spoolss-iremotewinspool-tests: Use more recent client OS version
[Samba.git] / lib / util / tevent_req_profile.c
blob522741c5ede8a8647bb053620a817bd3975f9555
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 int tevent_req_profile_print(const struct tevent_req_profile *profile,
33 FILE *fp,
34 unsigned indent,
35 unsigned max_indent)
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;
42 pid_t pid;
43 enum tevent_req_state state;
44 const char *state_buf = NULL;
45 uint64_t user_error;
46 const struct tevent_req_profile *sub = NULL;
47 int ret;
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);
61 switch(state) {
62 case TEVENT_REQ_INIT:
63 state_buf = "TEVENT_REQ_INIT";
64 break;
65 case TEVENT_REQ_IN_PROGRESS:
66 state_buf = "TEVENT_REQ_IN_PROGRESS";
67 break;
68 case TEVENT_REQ_DONE:
69 state_buf = "TEVENT_REQ_DONE";
70 break;
71 case TEVENT_REQ_USER_ERROR:
72 state_buf = "TEVENT_REQ_USER_ERROR";
73 break;
74 case TEVENT_REQ_TIMED_OUT:
75 state_buf = "TEVENT_REQ_TIMED_OUT";
76 break;
77 case TEVENT_REQ_NO_MEMORY:
78 state_buf = "TEVENT_REQ_NO_MEMORY";
79 break;
80 case TEVENT_REQ_RECEIVED:
81 state_buf = "TEVENT_REQ_RECEIVED";
82 break;
83 default:
84 state_buf = "unknown";
85 break;
88 ret = fprintf(
89 fp,
90 "%*s[%s] %s [%s] %s [%s] [%ju.%.6ju] -> %s (%d %"PRIu64"))\n",
91 indent,
92 "",
93 req_name,
94 start_location,
95 start_buf.buf,
96 stop_location,
97 stop_buf.buf,
98 (uintmax_t)diff.tv_sec,
99 (uintmax_t)diff.tv_usec,
100 state_buf,
101 (int)state,
102 user_error);
104 if (ret < 0) {
105 return ret;
108 indent += 1;
110 if (indent >= max_indent) {
111 return ret;
114 for (sub = tevent_req_profile_get_subprofiles(profile);
115 sub != NULL;
116 sub = tevent_req_profile_next(sub)) {
117 int subret;
119 subret = tevent_req_profile_print(sub, fp, indent, max_indent);
120 if (subret < 0) {
121 return subret;
124 ret += subret;
126 if (ret < subret) {
127 /* overflow */
128 return -1;
132 return ret;
135 char *tevent_req_profile_string(const struct tevent_req_profile *profile,
136 TALLOC_CTX *mem_ctx,
137 unsigned indent,
138 unsigned max_indent)
140 FILE *fp = NULL;
141 char *buf = NULL;
142 size_t buflen = 0;
143 char *result = NULL;
144 int ret;
146 fp = open_memstream(&buf, &buflen);
147 if (fp == NULL) {
148 return NULL;
151 ret = tevent_req_profile_print(profile, fp, 0, max_indent);
152 if (ret < 0) {
153 goto done;
156 ret = fclose(fp);
157 if (ret != 0) {
158 goto done;
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);
167 done:
168 SAFE_FREE(buf);
169 return result;
172 static ssize_t tevent_req_profile_pack_one(
173 const struct tevent_req_profile *profile,
174 uint8_t *buf,
175 size_t buflen)
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;
181 pid_t pid;
182 enum tevent_req_state state;
183 uint64_t user_error;
184 size_t pack_len, len;
185 int ret;
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;
193 if (buflen >= len) {
194 memcpy(buf, req_name, len);
195 buf += len;
196 buflen -= len;
199 pack_len = len;
201 len = strlen(start_location)+1;
202 pack_len += len;
203 if (pack_len < len) {
204 return -1; /* overflow */
207 if (buflen >= len) {
208 memcpy(buf, start_location, len);
209 buf += len;
210 buflen -= len;
213 len = strlen(stop_location)+1;
214 pack_len += len;
215 if (pack_len < len) {
216 return -1; /* overflow */
219 if (buflen >= len) {
220 memcpy(buf, stop_location, len);
221 buf += len;
222 buflen -= len;
225 ret = snprintf((char *)buf,
226 buflen,
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,
232 (int)pid,
233 (int)state,
234 user_error);
235 if (ret < 0) {
236 return -1;
240 * Take care of the trailing 0. No overflow check, this would
241 * be a VERY small number of bits for "int".
243 ret += 1;
245 pack_len += ret;
247 return pack_len;
250 ssize_t tevent_req_profile_pack(
251 const struct tevent_req_profile *profile,
252 uint8_t *buf,
253 size_t buflen)
255 const struct tevent_req_profile *sub = NULL;
256 size_t num_sub;
257 ssize_t pack_len, profile_len;
258 int ret;
260 num_sub = 0;
261 pack_len = 0;
263 for (sub = tevent_req_profile_get_subprofiles(profile);
264 sub != NULL;
265 sub = tevent_req_profile_next(sub)) {
266 num_sub += 1;
269 ret = snprintf((char *)buf, buflen, "%zu ", num_sub);
270 if (ret < 0) {
271 return -1;
274 if (buflen > (size_t)ret) {
275 buf += ret;
276 buflen -= ret;
279 pack_len = ret;
281 profile_len = tevent_req_profile_pack_one(profile, buf, buflen);
282 if (profile_len == -1) {
283 return -1;
286 if (buflen >= (size_t)profile_len) {
287 buf += 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);
297 sub != NULL;
298 sub = tevent_req_profile_next(sub)) {
300 profile_len = tevent_req_profile_pack(sub, buf, buflen);
301 if (profile_len == -1) {
302 return -1;
305 if (buflen >= (size_t)profile_len) {
306 buf += profile_len;
307 buflen -= profile_len;
310 pack_len += profile_len;
311 if (pack_len < profile_len) {
312 return -1; /* overflow */
316 return pack_len;
319 static bool parse_uintmax(const char *buf,
320 char delimiter,
321 uintmax_t *presult,
322 char **p_endptr)
324 uintmax_t result;
325 char *endptr;
327 result = strtoumax(buf, &endptr, 10);
328 if ((result == UINTMAX_MAX) && (errno == ERANGE)) {
329 return false;
331 if (*endptr != delimiter) {
332 return false;
335 *presult = result;
336 *p_endptr = endptr+1;
338 return true;
341 static ssize_t tevent_req_profile_unpack_one(
342 const uint8_t *buf,
343 size_t buflen,
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;
352 char *next = NULL;
353 size_t len;
354 bool ok;
356 if (buflen == 0) {
357 return -1;
359 if (buf[buflen-1] != '\0') {
360 return -1;
363 req_name = (const char *)buf;
364 len = strlen(req_name)+1;
366 buf += len;
367 buflen -= len;
368 if (buflen == 0) {
369 return -1;
372 start_location = (const char *)buf;
373 len = strlen(start_location)+1;
375 buf += len;
376 buflen -= len;
377 if (buflen == 0) {
378 return -1;
381 stop_location = (const char *)buf;
382 len = strlen(stop_location)+1;
384 buf += len;
385 buflen -= len;
386 if (buflen == 0) {
387 return -1;
390 ok = parse_uintmax((const char *)buf, ' ', &start_sec, &next);
391 if (!ok) {
392 return -1;
395 ok = parse_uintmax(next, ' ', &start_usec, &next);
396 if (!ok) {
397 return -1;
400 ok = parse_uintmax(next, ' ', &stop_sec, &next);
401 if (!ok) {
402 return -1;
405 ok = parse_uintmax(next, ' ', &stop_usec, &next);
406 if (!ok) {
407 return -1;
410 ok = parse_uintmax(next, ' ', &pid, &next);
411 if (!ok) {
412 return -1;
415 ok = parse_uintmax(next, ' ', &state, &next);
416 if (!ok) {
417 return -1;
420 ok = parse_uintmax(next, '\0', &user_error, &next);
421 if (!ok) {
422 return -1;
425 ok = tevent_req_profile_set_name(profile, req_name);
426 if (!ok) {
427 return -1;
430 ok = tevent_req_profile_set_start(
431 profile,
432 start_location,
433 (struct timeval){ .tv_sec=start_sec, .tv_usec=start_usec });
434 if (!ok) {
435 return -1;
438 ok = tevent_req_profile_set_stop(
439 profile,
440 stop_location,
441 (struct timeval){ .tv_sec=stop_sec, .tv_usec=stop_usec });
442 if (!ok) {
443 return -1;
446 tevent_req_profile_set_status(
447 profile,
448 pid,
449 (enum tevent_req_state)state,
450 user_error);
452 return next - orig_buf;
455 ssize_t tevent_req_profile_unpack(
456 const uint8_t *buf,
457 size_t buflen,
458 TALLOC_CTX *mem_ctx,
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;
464 char *next = NULL;
465 bool ok;
466 ssize_t len;
468 errno = 0;
470 if (buf[buflen-1] != '\0') {
471 return -1;
474 ok = parse_uintmax((const char *)buf, ' ', &num_subprofiles, &next);
475 if (!ok) {
476 return -1;
479 len = (next - (const char *)buf);
481 buf += len;
482 buflen -= len;
484 profile = tevent_req_profile_create(mem_ctx);
485 if (profile == NULL) {
486 return -1;
489 len = tevent_req_profile_unpack_one(buf, buflen, profile);
490 if (len == -1) {
491 TALLOC_FREE(profile);
492 return -1;
495 buf += len;
496 buflen -= len;
498 for (i=0; i<num_subprofiles; i++) {
499 struct tevent_req_profile *subprofile;
501 len = tevent_req_profile_unpack(
502 buf,
503 buflen,
504 profile,
505 &subprofile);
506 if (len == -1) {
507 TALLOC_FREE(profile);
508 return -1;
510 buf += len;
511 buflen -= len;
513 tevent_req_profile_append_sub(profile, &subprofile);
516 *p_profile = profile;
518 return buf - orig_buf;