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 static bool tevent_req_profile_string_internal(
33 const struct tevent_req_profile
*profile
,
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
;
44 enum tevent_req_state state
;
45 const char *state_buf
= NULL
;
47 const struct tevent_req_profile
*sub
= NULL
;
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
);
64 state_buf
= "TEVENT_REQ_INIT";
66 case TEVENT_REQ_IN_PROGRESS
:
67 state_buf
= "TEVENT_REQ_IN_PROGRESS";
70 state_buf
= "TEVENT_REQ_DONE";
72 case TEVENT_REQ_USER_ERROR
:
73 state_buf
= "TEVENT_REQ_USER_ERROR";
75 case TEVENT_REQ_TIMED_OUT
:
76 state_buf
= "TEVENT_REQ_TIMED_OUT";
78 case TEVENT_REQ_NO_MEMORY
:
79 state_buf
= "TEVENT_REQ_NO_MEMORY";
81 case TEVENT_REQ_RECEIVED
:
82 state_buf
= "TEVENT_REQ_RECEIVED";
85 state_buf
= "unknown";
89 result
= talloc_asprintf_append_buffer(
91 "%*s[%s] %s [%s] %s [%s] [%ju.%.6ju] -> %s (%d %"PRIu64
"))\n",
99 (uintmax_t)diff
.tv_sec
,
100 (uintmax_t)diff
.tv_usec
,
104 if (result
== NULL
) {
111 if (indent
>= max_indent
) {
115 for (sub
= tevent_req_profile_get_subprofiles(profile
);
117 sub
= tevent_req_profile_next(sub
)) {
120 ret
= tevent_req_profile_string_internal(
133 char *tevent_req_profile_string(TALLOC_CTX
*mem_ctx
,
134 const struct tevent_req_profile
*profile
,
141 result
= talloc_strdup(mem_ctx
, "");
142 if (result
== NULL
) {
146 ret
= tevent_req_profile_string_internal(
159 static ssize_t
tevent_req_profile_pack_one(
160 const struct tevent_req_profile
*profile
,
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
;
169 enum tevent_req_state state
;
171 size_t pack_len
, len
;
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;
181 memcpy(buf
, req_name
, len
);
188 len
= strlen(start_location
)+1;
190 if (pack_len
< len
) {
191 return -1; /* overflow */
195 memcpy(buf
, start_location
, len
);
200 len
= strlen(stop_location
)+1;
202 if (pack_len
< len
) {
203 return -1; /* overflow */
207 memcpy(buf
, stop_location
, len
);
212 ret
= snprintf((char *)buf
,
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
,
227 * Take care of the trailing 0. No overflow check, this would
228 * be a VERY small number of bits for "int".
237 ssize_t
tevent_req_profile_pack(
238 const struct tevent_req_profile
*profile
,
242 const struct tevent_req_profile
*sub
= NULL
;
244 ssize_t pack_len
, profile_len
;
250 for (sub
= tevent_req_profile_get_subprofiles(profile
);
252 sub
= tevent_req_profile_next(sub
)) {
256 ret
= snprintf((char *)buf
, buflen
, "%zu ", num_sub
);
261 if (buflen
> (size_t)ret
) {
268 profile_len
= tevent_req_profile_pack_one(profile
, buf
, buflen
);
269 if (profile_len
== -1) {
273 if (buflen
>= (size_t)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
);
285 sub
= tevent_req_profile_next(sub
)) {
287 profile_len
= tevent_req_profile_pack(sub
, buf
, buflen
);
288 if (profile_len
== -1) {
292 if (buflen
>= (size_t)profile_len
) {
294 buflen
-= profile_len
;
297 pack_len
+= profile_len
;
298 if (pack_len
< profile_len
) {
299 return -1; /* overflow */
306 static bool parse_uintmax(const char *buf
,
314 result
= strtoumax(buf
, &endptr
, 10);
315 if ((result
== UINTMAX_MAX
) && (errno
== ERANGE
)) {
318 if (*endptr
!= delimiter
) {
323 *p_endptr
= endptr
+1;
328 static ssize_t
tevent_req_profile_unpack_one(
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
;
346 if (buf
[buflen
-1] != '\0') {
350 req_name
= (const char *)buf
;
351 len
= strlen(req_name
)+1;
359 start_location
= (const char *)buf
;
360 len
= strlen(start_location
)+1;
368 stop_location
= (const char *)buf
;
369 len
= strlen(stop_location
)+1;
377 ok
= parse_uintmax((const char *)buf
, ' ', &start_sec
, &next
);
382 ok
= parse_uintmax(next
, ' ', &start_usec
, &next
);
387 ok
= parse_uintmax(next
, ' ', &stop_sec
, &next
);
392 ok
= parse_uintmax(next
, ' ', &stop_usec
, &next
);
397 ok
= parse_uintmax(next
, ' ', &pid
, &next
);
402 ok
= parse_uintmax(next
, ' ', &state
, &next
);
407 ok
= parse_uintmax(next
, '\0', &user_error
, &next
);
412 ok
= tevent_req_profile_set_name(profile
, req_name
);
417 ok
= tevent_req_profile_set_start(
420 (struct timeval
){ .tv_sec
=start_sec
, .tv_usec
=start_usec
});
425 ok
= tevent_req_profile_set_stop(
428 (struct timeval
){ .tv_sec
=stop_sec
, .tv_usec
=stop_usec
});
433 tevent_req_profile_set_status(
436 (enum tevent_req_state
)state
,
439 return next
- orig_buf
;
442 ssize_t
tevent_req_profile_unpack(
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
;
457 if (buf
[buflen
-1] != '\0') {
461 ok
= parse_uintmax((const char *)buf
, ' ', &num_subprofiles
, &next
);
466 len
= (next
- (const char *)buf
);
471 profile
= tevent_req_profile_create(mem_ctx
);
472 if (profile
== NULL
) {
476 len
= tevent_req_profile_unpack_one(buf
, buflen
, profile
);
478 TALLOC_FREE(profile
);
485 for (i
=0; i
<num_subprofiles
; i
++) {
486 struct tevent_req_profile
*subprofile
;
488 len
= tevent_req_profile_unpack(
494 TALLOC_FREE(profile
);
500 tevent_req_profile_append_sub(profile
, &subprofile
);
503 *p_profile
= profile
;
505 return buf
- orig_buf
;