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
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/>.
28 #include "lib/util/tevent_req_profile.h"
29 #include "lib/util/time_basic.h"
30 #include "lib/util/memory.h"
32 int tevent_req_profile_print(const struct tevent_req_profile
*profile
,
37 struct timeval start
, stop
, diff
;
38 struct timeval_buf start_buf
, stop_buf
;
39 const char *req_name
= NULL
;
40 const char *start_location
= NULL
;
41 const char *stop_location
= NULL
;
43 enum tevent_req_state state
;
44 const char *state_buf
= NULL
;
46 const struct tevent_req_profile
*sub
= NULL
;
49 tevent_req_profile_get_name(profile
, &req_name
);
51 tevent_req_profile_get_start(profile
, &start_location
, &start
);
52 timeval_str_buf(&start
, false, true, &start_buf
);
54 tevent_req_profile_get_stop(profile
, &stop_location
, &stop
);
55 timeval_str_buf(&stop
, false, true, &stop_buf
);
57 diff
= tevent_timeval_until(&start
, &stop
);
59 tevent_req_profile_get_status(profile
, &pid
, &state
, &user_error
);
63 state_buf
= "TEVENT_REQ_INIT";
65 case TEVENT_REQ_IN_PROGRESS
:
66 state_buf
= "TEVENT_REQ_IN_PROGRESS";
69 state_buf
= "TEVENT_REQ_DONE";
71 case TEVENT_REQ_USER_ERROR
:
72 state_buf
= "TEVENT_REQ_USER_ERROR";
74 case TEVENT_REQ_TIMED_OUT
:
75 state_buf
= "TEVENT_REQ_TIMED_OUT";
77 case TEVENT_REQ_NO_MEMORY
:
78 state_buf
= "TEVENT_REQ_NO_MEMORY";
80 case TEVENT_REQ_RECEIVED
:
81 state_buf
= "TEVENT_REQ_RECEIVED";
84 state_buf
= "unknown";
90 "%*s[%s] %s [%s] %s [%s] [%ju.%.6ju] -> %s (%d %"PRIu64
"))\n",
98 (uintmax_t)diff
.tv_sec
,
99 (uintmax_t)diff
.tv_usec
,
110 if (indent
>= max_indent
) {
114 for (sub
= tevent_req_profile_get_subprofiles(profile
);
116 sub
= tevent_req_profile_next(sub
)) {
119 subret
= tevent_req_profile_print(sub
, fp
, indent
, max_indent
);
135 char *tevent_req_profile_string(const struct tevent_req_profile
*profile
,
146 fp
= open_memstream(&buf
, &buflen
);
151 ret
= tevent_req_profile_print(profile
, fp
, 0, max_indent
);
162 * A FILE* from open_memstream maintains the 0-byte at the end
163 * beyond the reported length.
165 result
= talloc_memdup(mem_ctx
, buf
, buflen
+1);
172 static ssize_t
tevent_req_profile_pack_one(
173 const struct tevent_req_profile
*profile
,
177 const char *req_name
= NULL
;
178 const char *start_location
= NULL
;
179 const char *stop_location
= NULL
;
180 struct timeval start_time
, stop_time
;
182 enum tevent_req_state state
;
184 size_t pack_len
, len
;
187 tevent_req_profile_get_name(profile
, &req_name
);
188 tevent_req_profile_get_start(profile
, &start_location
, &start_time
);
189 tevent_req_profile_get_stop(profile
, &stop_location
, &stop_time
);
190 tevent_req_profile_get_status(profile
, &pid
, &state
, &user_error
);
192 len
= strlen(req_name
)+1;
194 memcpy(buf
, req_name
, len
);
201 len
= strlen(start_location
)+1;
203 if (pack_len
< len
) {
204 return -1; /* overflow */
208 memcpy(buf
, start_location
, len
);
213 len
= strlen(stop_location
)+1;
215 if (pack_len
< len
) {
216 return -1; /* overflow */
220 memcpy(buf
, stop_location
, len
);
225 ret
= snprintf((char *)buf
,
227 "%ju %ju %ju %ju %d %d %"PRIu64
"",
228 (uintmax_t)start_time
.tv_sec
,
229 (uintmax_t)start_time
.tv_usec
,
230 (uintmax_t)stop_time
.tv_sec
,
231 (uintmax_t)stop_time
.tv_usec
,
240 * Take care of the trailing 0. No overflow check, this would
241 * be a VERY small number of bits for "int".
250 ssize_t
tevent_req_profile_pack(
251 const struct tevent_req_profile
*profile
,
255 const struct tevent_req_profile
*sub
= NULL
;
257 ssize_t pack_len
, profile_len
;
263 for (sub
= tevent_req_profile_get_subprofiles(profile
);
265 sub
= tevent_req_profile_next(sub
)) {
269 ret
= snprintf((char *)buf
, buflen
, "%zu ", num_sub
);
274 if (buflen
> (size_t)ret
) {
281 profile_len
= tevent_req_profile_pack_one(profile
, buf
, buflen
);
282 if (profile_len
== -1) {
286 if (buflen
>= (size_t)profile_len
) {
288 buflen
-= profile_len
;
291 pack_len
+= profile_len
;
292 if (pack_len
< profile_len
) {
293 return -1; /* overflow */
296 for (sub
= tevent_req_profile_get_subprofiles(profile
);
298 sub
= tevent_req_profile_next(sub
)) {
300 profile_len
= tevent_req_profile_pack(sub
, buf
, buflen
);
301 if (profile_len
== -1) {
305 if (buflen
>= (size_t)profile_len
) {
307 buflen
-= profile_len
;
310 pack_len
+= profile_len
;
311 if (pack_len
< profile_len
) {
312 return -1; /* overflow */
319 static bool parse_uintmax(const char *buf
,
327 result
= strtoumax(buf
, &endptr
, 10);
328 if ((result
== UINTMAX_MAX
) && (errno
== ERANGE
)) {
331 if (*endptr
!= delimiter
) {
336 *p_endptr
= endptr
+1;
341 static ssize_t
tevent_req_profile_unpack_one(
344 struct tevent_req_profile
*profile
)
346 const char *orig_buf
= (const char *)buf
;
347 const char *req_name
= NULL
;
348 const char *start_location
= NULL
;
349 const char *stop_location
= NULL
;
350 uintmax_t start_sec
, start_usec
, stop_sec
, stop_usec
, pid
, state
;
351 uintmax_t user_error
;
359 if (buf
[buflen
-1] != '\0') {
363 req_name
= (const char *)buf
;
364 len
= strlen(req_name
)+1;
372 start_location
= (const char *)buf
;
373 len
= strlen(start_location
)+1;
381 stop_location
= (const char *)buf
;
382 len
= strlen(stop_location
)+1;
390 ok
= parse_uintmax((const char *)buf
, ' ', &start_sec
, &next
);
395 ok
= parse_uintmax(next
, ' ', &start_usec
, &next
);
400 ok
= parse_uintmax(next
, ' ', &stop_sec
, &next
);
405 ok
= parse_uintmax(next
, ' ', &stop_usec
, &next
);
410 ok
= parse_uintmax(next
, ' ', &pid
, &next
);
415 ok
= parse_uintmax(next
, ' ', &state
, &next
);
420 ok
= parse_uintmax(next
, '\0', &user_error
, &next
);
425 ok
= tevent_req_profile_set_name(profile
, req_name
);
430 ok
= tevent_req_profile_set_start(
433 (struct timeval
){ .tv_sec
=start_sec
, .tv_usec
=start_usec
});
438 ok
= tevent_req_profile_set_stop(
441 (struct timeval
){ .tv_sec
=stop_sec
, .tv_usec
=stop_usec
});
446 tevent_req_profile_set_status(
449 (enum tevent_req_state
)state
,
452 return next
- orig_buf
;
455 ssize_t
tevent_req_profile_unpack(
459 struct tevent_req_profile
**p_profile
)
461 const uint8_t *orig_buf
= buf
;
462 struct tevent_req_profile
*profile
= NULL
;
463 uintmax_t i
, num_subprofiles
;
470 if (buf
[buflen
-1] != '\0') {
474 ok
= parse_uintmax((const char *)buf
, ' ', &num_subprofiles
, &next
);
479 len
= (next
- (const char *)buf
);
484 profile
= tevent_req_profile_create(mem_ctx
);
485 if (profile
== NULL
) {
489 len
= tevent_req_profile_unpack_one(buf
, buflen
, profile
);
491 TALLOC_FREE(profile
);
498 for (i
=0; i
<num_subprofiles
; i
++) {
499 struct tevent_req_profile
*subprofile
;
501 len
= tevent_req_profile_unpack(
507 TALLOC_FREE(profile
);
513 tevent_req_profile_append_sub(profile
, &subprofile
);
516 *p_profile
= profile
;
518 return buf
- orig_buf
;