Search for location of waf script
[Samba.git] / lib / util / tevent_req_profile.c
blob2d280f78f322a76be07bfd2fe6ea5a386504859f
1 /*
2 * Unix SMB/CIFS implementation.
4 * Helpers around tevent_req_profile
6 * Copyright (C) Volker Lendecke 2018
8 * ** NOTE! The following LGPL license applies to the tevent
9 * ** library. This does NOT imply that all of Samba is released
10 * ** under the LGPL
12 * This library is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public
14 * License as published by the Free Software Foundation; either
15 * version 3 of the License, or (at your option) any later version.
17 * This library is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
26 #include "replace.h"
27 #include <tevent.h>
28 #include "lib/util/tevent_req_profile.h"
29 #include "lib/util/time_basic.h"
30 #include "lib/util/memory.h"
32 static bool tevent_req_profile_string_internal(
33 const struct tevent_req_profile *profile,
34 unsigned indent,
35 unsigned max_indent,
36 char **string)
38 struct timeval start, stop, diff;
39 struct timeval_buf start_buf, stop_buf;
40 const char *req_name = NULL;
41 const char *start_location = NULL;
42 const char *stop_location = NULL;
43 pid_t pid;
44 enum tevent_req_state state;
45 const char *state_buf = NULL;
46 uint64_t user_error;
47 const struct tevent_req_profile *sub = NULL;
48 char *result;
50 tevent_req_profile_get_name(profile, &req_name);
52 tevent_req_profile_get_start(profile, &start_location, &start);
53 timeval_str_buf(&start, false, true, &start_buf);
55 tevent_req_profile_get_stop(profile, &stop_location, &stop);
56 timeval_str_buf(&stop, false, true, &stop_buf);
58 diff = tevent_timeval_until(&start, &stop);
60 tevent_req_profile_get_status(profile, &pid, &state, &user_error);
62 switch(state) {
63 case TEVENT_REQ_INIT:
64 state_buf = "TEVENT_REQ_INIT";
65 break;
66 case TEVENT_REQ_IN_PROGRESS:
67 state_buf = "TEVENT_REQ_IN_PROGRESS";
68 break;
69 case TEVENT_REQ_DONE:
70 state_buf = "TEVENT_REQ_DONE";
71 break;
72 case TEVENT_REQ_USER_ERROR:
73 state_buf = "TEVENT_REQ_USER_ERROR";
74 break;
75 case TEVENT_REQ_TIMED_OUT:
76 state_buf = "TEVENT_REQ_TIMED_OUT";
77 break;
78 case TEVENT_REQ_NO_MEMORY:
79 state_buf = "TEVENT_REQ_NO_MEMORY";
80 break;
81 case TEVENT_REQ_RECEIVED:
82 state_buf = "TEVENT_REQ_RECEIVED";
83 break;
84 default:
85 state_buf = "unknown";
86 break;
89 result = talloc_asprintf_append_buffer(
90 *string,
91 "%*s[%s] %s [%s] %s [%s] [%ju.%.6ju] -> %s (%d %"PRIu64"))\n",
92 indent,
93 "",
94 req_name,
95 start_location,
96 start_buf.buf,
97 stop_location,
98 stop_buf.buf,
99 (uintmax_t)diff.tv_sec,
100 (uintmax_t)diff.tv_usec,
101 state_buf,
102 (int)state,
103 user_error);
104 if (result == NULL) {
105 return false;
107 *string = result;
109 indent += 1;
111 if (indent >= max_indent) {
112 return true;
115 for (sub = tevent_req_profile_get_subprofiles(profile);
116 sub != NULL;
117 sub = tevent_req_profile_next(sub)) {
118 bool ret;
120 ret = tevent_req_profile_string_internal(
121 sub,
122 indent,
123 max_indent,
124 string);
125 if (!ret) {
126 return false;
130 return true;
133 char *tevent_req_profile_string(TALLOC_CTX *mem_ctx,
134 const struct tevent_req_profile *profile,
135 unsigned indent,
136 unsigned max_indent)
138 char *result;
139 bool ret;
141 result = talloc_strdup(mem_ctx, "");
142 if (result == NULL) {
143 return NULL;
146 ret = tevent_req_profile_string_internal(
147 profile,
148 indent,
149 max_indent,
150 &result);
151 if (!ret) {
152 TALLOC_FREE(result);
153 return NULL;
156 return result;
159 static ssize_t tevent_req_profile_pack_one(
160 const struct tevent_req_profile *profile,
161 uint8_t *buf,
162 size_t buflen)
164 const char *req_name = NULL;
165 const char *start_location = NULL;
166 const char *stop_location = NULL;
167 struct timeval start_time, stop_time;
168 pid_t pid;
169 enum tevent_req_state state;
170 uint64_t user_error;
171 size_t pack_len, len;
172 int ret;
174 tevent_req_profile_get_name(profile, &req_name);
175 tevent_req_profile_get_start(profile, &start_location, &start_time);
176 tevent_req_profile_get_stop(profile, &stop_location, &stop_time);
177 tevent_req_profile_get_status(profile, &pid, &state, &user_error);
179 len = strlen(req_name)+1;
180 if (buflen >= len) {
181 memcpy(buf, req_name, len);
182 buf += len;
183 buflen -= len;
186 pack_len = len;
188 len = strlen(start_location)+1;
189 pack_len += len;
190 if (pack_len < len) {
191 return -1; /* overflow */
194 if (buflen >= len) {
195 memcpy(buf, start_location, len);
196 buf += len;
197 buflen -= len;
200 len = strlen(stop_location)+1;
201 pack_len += len;
202 if (pack_len < len) {
203 return -1; /* overflow */
206 if (buflen >= len) {
207 memcpy(buf, stop_location, len);
208 buf += len;
209 buflen -= len;
212 ret = snprintf((char *)buf,
213 buflen,
214 "%ju %ju %ju %ju %d %d %"PRIu64"",
215 (uintmax_t)start_time.tv_sec,
216 (uintmax_t)start_time.tv_usec,
217 (uintmax_t)stop_time.tv_sec,
218 (uintmax_t)stop_time.tv_usec,
219 (int)pid,
220 (int)state,
221 user_error);
222 if (ret < 0) {
223 return -1;
227 * Take care of the trailing 0. No overflow check, this would
228 * be a VERY small number of bits for "int".
230 ret += 1;
232 pack_len += ret;
234 return pack_len;
237 ssize_t tevent_req_profile_pack(
238 const struct tevent_req_profile *profile,
239 uint8_t *buf,
240 size_t buflen)
242 const struct tevent_req_profile *sub = NULL;
243 size_t num_sub;
244 ssize_t pack_len, profile_len;
245 int ret;
247 num_sub = 0;
248 pack_len = 0;
250 for (sub = tevent_req_profile_get_subprofiles(profile);
251 sub != NULL;
252 sub = tevent_req_profile_next(sub)) {
253 num_sub += 1;
256 ret = snprintf((char *)buf, buflen, "%zu ", num_sub);
257 if (ret < 0) {
258 return -1;
261 if (buflen > (size_t)ret) {
262 buf += ret;
263 buflen -= ret;
266 pack_len = ret;
268 profile_len = tevent_req_profile_pack_one(profile, buf, buflen);
269 if (profile_len == -1) {
270 return -1;
273 if (buflen >= (size_t)profile_len) {
274 buf += profile_len;
275 buflen -= profile_len;
278 pack_len += profile_len;
279 if (pack_len < profile_len) {
280 return -1; /* overflow */
283 for (sub = tevent_req_profile_get_subprofiles(profile);
284 sub != NULL;
285 sub = tevent_req_profile_next(sub)) {
287 profile_len = tevent_req_profile_pack(sub, buf, buflen);
288 if (profile_len == -1) {
289 return -1;
292 if (buflen >= (size_t)profile_len) {
293 buf += profile_len;
294 buflen -= profile_len;
297 pack_len += profile_len;
298 if (pack_len < profile_len) {
299 return -1; /* overflow */
303 return pack_len;
306 static bool parse_uintmax(const char *buf,
307 char delimiter,
308 uintmax_t *presult,
309 char **p_endptr)
311 uintmax_t result;
312 char *endptr;
314 result = strtoumax(buf, &endptr, 10);
315 if ((result == UINTMAX_MAX) && (errno == ERANGE)) {
316 return false;
318 if (*endptr != delimiter) {
319 return false;
322 *presult = result;
323 *p_endptr = endptr+1;
325 return true;
328 static ssize_t tevent_req_profile_unpack_one(
329 const uint8_t *buf,
330 size_t buflen,
331 struct tevent_req_profile *profile)
333 const char *orig_buf = (const char *)buf;
334 const char *req_name = NULL;
335 const char *start_location = NULL;
336 const char *stop_location = NULL;
337 uintmax_t start_sec, start_usec, stop_sec, stop_usec, pid, state;
338 uintmax_t user_error;
339 char *next = NULL;
340 size_t len;
341 bool ok;
343 if (buflen == 0) {
344 return -1;
346 if (buf[buflen-1] != '\0') {
347 return -1;
350 req_name = (const char *)buf;
351 len = strlen(req_name)+1;
353 buf += len;
354 buflen -= len;
355 if (buflen == 0) {
356 return -1;
359 start_location = (const char *)buf;
360 len = strlen(start_location)+1;
362 buf += len;
363 buflen -= len;
364 if (buflen == 0) {
365 return -1;
368 stop_location = (const char *)buf;
369 len = strlen(stop_location)+1;
371 buf += len;
372 buflen -= len;
373 if (buflen == 0) {
374 return -1;
377 ok = parse_uintmax((const char *)buf, ' ', &start_sec, &next);
378 if (!ok) {
379 return -1;
382 ok = parse_uintmax(next, ' ', &start_usec, &next);
383 if (!ok) {
384 return -1;
387 ok = parse_uintmax(next, ' ', &stop_sec, &next);
388 if (!ok) {
389 return -1;
392 ok = parse_uintmax(next, ' ', &stop_usec, &next);
393 if (!ok) {
394 return -1;
397 ok = parse_uintmax(next, ' ', &pid, &next);
398 if (!ok) {
399 return -1;
402 ok = parse_uintmax(next, ' ', &state, &next);
403 if (!ok) {
404 return -1;
407 ok = parse_uintmax(next, '\0', &user_error, &next);
408 if (!ok) {
409 return -1;
412 ok = tevent_req_profile_set_name(profile, req_name);
413 if (!ok) {
414 return -1;
417 ok = tevent_req_profile_set_start(
418 profile,
419 start_location,
420 (struct timeval){ .tv_sec=start_sec, .tv_usec=start_usec });
421 if (!ok) {
422 return -1;
425 ok = tevent_req_profile_set_stop(
426 profile,
427 stop_location,
428 (struct timeval){ .tv_sec=stop_sec, .tv_usec=stop_usec });
429 if (!ok) {
430 return -1;
433 tevent_req_profile_set_status(
434 profile,
435 pid,
436 (enum tevent_req_state)state,
437 user_error);
439 return next - orig_buf;
442 ssize_t tevent_req_profile_unpack(
443 const uint8_t *buf,
444 size_t buflen,
445 TALLOC_CTX *mem_ctx,
446 struct tevent_req_profile **p_profile)
448 const uint8_t *orig_buf = buf;
449 struct tevent_req_profile *profile = NULL;
450 uintmax_t i, num_subprofiles;
451 char *next = NULL;
452 bool ok;
453 ssize_t len;
455 errno = 0;
457 if (buf[buflen-1] != '\0') {
458 return -1;
461 ok = parse_uintmax((const char *)buf, ' ', &num_subprofiles, &next);
462 if (!ok) {
463 return -1;
466 len = (next - (const char *)buf);
468 buf += len;
469 buflen -= len;
471 profile = tevent_req_profile_create(mem_ctx);
472 if (profile == NULL) {
473 return -1;
476 len = tevent_req_profile_unpack_one(buf, buflen, profile);
477 if (len == -1) {
478 TALLOC_FREE(profile);
479 return -1;
482 buf += len;
483 buflen -= len;
485 for (i=0; i<num_subprofiles; i++) {
486 struct tevent_req_profile *subprofile;
488 len = tevent_req_profile_unpack(
489 buf,
490 buflen,
491 profile,
492 &subprofile);
493 if (len == -1) {
494 TALLOC_FREE(profile);
495 return -1;
497 buf += len;
498 buflen -= len;
500 tevent_req_profile_append_sub(profile, &subprofile);
503 *p_profile = profile;
505 return buf - orig_buf;