Line data Source code
1 : /*
2 : * Unix SMB/CIFS implementation.
3 : *
4 : * Helpers around tevent_req_profile
5 : *
6 : * Copyright (C) Volker Lendecke 2018
7 : *
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
11 : *
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.
16 : *
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.
21 : *
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/>.
24 : */
25 :
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"
31 :
32 0 : static bool tevent_req_profile_string_internal(
33 : const struct tevent_req_profile *profile,
34 : unsigned indent,
35 : unsigned max_indent,
36 : char **string)
37 : {
38 : struct timeval start, stop, diff;
39 : struct timeval_buf start_buf, stop_buf;
40 0 : const char *req_name = NULL;
41 0 : const char *start_location = NULL;
42 0 : const char *stop_location = NULL;
43 : pid_t pid;
44 : enum tevent_req_state state;
45 0 : const char *state_buf = NULL;
46 : uint64_t user_error;
47 0 : const struct tevent_req_profile *sub = NULL;
48 : char *result;
49 :
50 0 : tevent_req_profile_get_name(profile, &req_name);
51 :
52 0 : tevent_req_profile_get_start(profile, &start_location, &start);
53 0 : timeval_str_buf(&start, false, true, &start_buf);
54 :
55 0 : tevent_req_profile_get_stop(profile, &stop_location, &stop);
56 0 : timeval_str_buf(&stop, false, true, &stop_buf);
57 :
58 0 : diff = tevent_timeval_until(&start, &stop);
59 :
60 0 : tevent_req_profile_get_status(profile, &pid, &state, &user_error);
61 :
62 0 : switch(state) {
63 0 : case TEVENT_REQ_INIT:
64 0 : state_buf = "TEVENT_REQ_INIT";
65 0 : break;
66 0 : case TEVENT_REQ_IN_PROGRESS:
67 0 : state_buf = "TEVENT_REQ_IN_PROGRESS";
68 0 : break;
69 0 : case TEVENT_REQ_DONE:
70 0 : state_buf = "TEVENT_REQ_DONE";
71 0 : break;
72 0 : case TEVENT_REQ_USER_ERROR:
73 0 : state_buf = "TEVENT_REQ_USER_ERROR";
74 0 : break;
75 0 : case TEVENT_REQ_TIMED_OUT:
76 0 : state_buf = "TEVENT_REQ_TIMED_OUT";
77 0 : break;
78 0 : case TEVENT_REQ_NO_MEMORY:
79 0 : state_buf = "TEVENT_REQ_NO_MEMORY";
80 0 : break;
81 0 : case TEVENT_REQ_RECEIVED:
82 0 : state_buf = "TEVENT_REQ_RECEIVED";
83 0 : break;
84 0 : default:
85 0 : state_buf = "unknown";
86 0 : break;
87 : }
88 :
89 0 : 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 0 : (uintmax_t)diff.tv_sec,
100 0 : (uintmax_t)diff.tv_usec,
101 : state_buf,
102 : (int)state,
103 : user_error);
104 0 : if (result == NULL) {
105 0 : return false;
106 : }
107 0 : *string = result;
108 :
109 0 : indent += 1;
110 :
111 0 : if (indent >= max_indent) {
112 0 : return true;
113 : }
114 :
115 0 : for (sub = tevent_req_profile_get_subprofiles(profile);
116 0 : sub != NULL;
117 0 : sub = tevent_req_profile_next(sub)) {
118 : bool ret;
119 :
120 0 : ret = tevent_req_profile_string_internal(
121 : sub,
122 : indent,
123 : max_indent,
124 : string);
125 0 : if (!ret) {
126 0 : return false;
127 : }
128 : }
129 :
130 0 : return true;
131 : }
132 :
133 0 : char *tevent_req_profile_string(TALLOC_CTX *mem_ctx,
134 : const struct tevent_req_profile *profile,
135 : unsigned indent,
136 : unsigned max_indent)
137 : {
138 : char *result;
139 : bool ret;
140 :
141 0 : result = talloc_strdup(mem_ctx, "");
142 0 : if (result == NULL) {
143 0 : return NULL;
144 : }
145 :
146 0 : ret = tevent_req_profile_string_internal(
147 : profile,
148 : indent,
149 : max_indent,
150 : &result);
151 0 : if (!ret) {
152 0 : TALLOC_FREE(result);
153 0 : return NULL;
154 : }
155 :
156 0 : return result;
157 : }
158 :
159 0 : static ssize_t tevent_req_profile_pack_one(
160 : const struct tevent_req_profile *profile,
161 : uint8_t *buf,
162 : size_t buflen)
163 : {
164 0 : const char *req_name = NULL;
165 0 : const char *start_location = NULL;
166 0 : 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;
173 :
174 0 : tevent_req_profile_get_name(profile, &req_name);
175 0 : tevent_req_profile_get_start(profile, &start_location, &start_time);
176 0 : tevent_req_profile_get_stop(profile, &stop_location, &stop_time);
177 0 : tevent_req_profile_get_status(profile, &pid, &state, &user_error);
178 :
179 0 : len = strlen(req_name)+1;
180 0 : if (buflen >= len) {
181 0 : memcpy(buf, req_name, len);
182 0 : buf += len;
183 0 : buflen -= len;
184 : }
185 :
186 0 : pack_len = len;
187 :
188 0 : len = strlen(start_location)+1;
189 0 : pack_len += len;
190 0 : if (pack_len < len) {
191 0 : return -1; /* overflow */
192 : }
193 :
194 0 : if (buflen >= len) {
195 0 : memcpy(buf, start_location, len);
196 0 : buf += len;
197 0 : buflen -= len;
198 : }
199 :
200 0 : len = strlen(stop_location)+1;
201 0 : pack_len += len;
202 0 : if (pack_len < len) {
203 0 : return -1; /* overflow */
204 : }
205 :
206 0 : if (buflen >= len) {
207 0 : memcpy(buf, stop_location, len);
208 0 : buf += len;
209 0 : buflen -= len;
210 : }
211 :
212 0 : ret = snprintf((char *)buf,
213 : buflen,
214 : "%ju %ju %ju %ju %d %d %"PRIu64"",
215 0 : (uintmax_t)start_time.tv_sec,
216 0 : (uintmax_t)start_time.tv_usec,
217 0 : (uintmax_t)stop_time.tv_sec,
218 0 : (uintmax_t)stop_time.tv_usec,
219 : (int)pid,
220 : (int)state,
221 : user_error);
222 0 : if (ret < 0) {
223 0 : return -1;
224 : }
225 :
226 : /*
227 : * Take care of the trailing 0. No overflow check, this would
228 : * be a VERY small number of bits for "int".
229 : */
230 0 : ret += 1;
231 :
232 0 : pack_len += ret;
233 :
234 0 : return pack_len;
235 : }
236 :
237 0 : ssize_t tevent_req_profile_pack(
238 : const struct tevent_req_profile *profile,
239 : uint8_t *buf,
240 : size_t buflen)
241 : {
242 0 : const struct tevent_req_profile *sub = NULL;
243 : size_t num_sub;
244 : ssize_t pack_len, profile_len;
245 : int ret;
246 :
247 0 : num_sub = 0;
248 0 : pack_len = 0;
249 :
250 0 : for (sub = tevent_req_profile_get_subprofiles(profile);
251 0 : sub != NULL;
252 0 : sub = tevent_req_profile_next(sub)) {
253 0 : num_sub += 1;
254 : }
255 :
256 0 : ret = snprintf((char *)buf, buflen, "%zu ", num_sub);
257 0 : if (ret < 0) {
258 0 : return -1;
259 : }
260 :
261 0 : if (buflen > (size_t)ret) {
262 0 : buf += ret;
263 0 : buflen -= ret;
264 : }
265 :
266 0 : pack_len = ret;
267 :
268 0 : profile_len = tevent_req_profile_pack_one(profile, buf, buflen);
269 0 : if (profile_len == -1) {
270 0 : return -1;
271 : }
272 :
273 0 : if (buflen >= (size_t)profile_len) {
274 0 : buf += profile_len;
275 0 : buflen -= profile_len;
276 : }
277 :
278 0 : pack_len += profile_len;
279 0 : if (pack_len < profile_len) {
280 0 : return -1; /* overflow */
281 : }
282 :
283 0 : for (sub = tevent_req_profile_get_subprofiles(profile);
284 0 : sub != NULL;
285 0 : sub = tevent_req_profile_next(sub)) {
286 :
287 0 : profile_len = tevent_req_profile_pack(sub, buf, buflen);
288 0 : if (profile_len == -1) {
289 0 : return -1;
290 : }
291 :
292 0 : if (buflen >= (size_t)profile_len) {
293 0 : buf += profile_len;
294 0 : buflen -= profile_len;
295 : }
296 :
297 0 : pack_len += profile_len;
298 0 : if (pack_len < profile_len) {
299 0 : return -1; /* overflow */
300 : }
301 : }
302 :
303 0 : return pack_len;
304 : }
305 :
306 0 : static bool parse_uintmax(const char *buf,
307 : char delimiter,
308 : uintmax_t *presult,
309 : char **p_endptr)
310 : {
311 : uintmax_t result;
312 : char *endptr;
313 :
314 0 : result = strtoumax(buf, &endptr, 10);
315 0 : if ((result == UINTMAX_MAX) && (errno == ERANGE)) {
316 0 : return false;
317 : }
318 0 : if (*endptr != delimiter) {
319 0 : return false;
320 : }
321 :
322 0 : *presult = result;
323 0 : *p_endptr = endptr+1;
324 :
325 0 : return true;
326 : }
327 :
328 0 : static ssize_t tevent_req_profile_unpack_one(
329 : const uint8_t *buf,
330 : size_t buflen,
331 : struct tevent_req_profile *profile)
332 : {
333 0 : const char *orig_buf = (const char *)buf;
334 0 : const char *req_name = NULL;
335 0 : const char *start_location = NULL;
336 0 : const char *stop_location = NULL;
337 : uintmax_t start_sec, start_usec, stop_sec, stop_usec, pid, state;
338 : uintmax_t user_error;
339 0 : char *next = NULL;
340 : size_t len;
341 : bool ok;
342 :
343 0 : if (buflen == 0) {
344 0 : return -1;
345 : }
346 0 : if (buf[buflen-1] != '\0') {
347 0 : return -1;
348 : }
349 :
350 0 : req_name = (const char *)buf;
351 0 : len = strlen(req_name)+1;
352 :
353 0 : buf += len;
354 0 : buflen -= len;
355 0 : if (buflen == 0) {
356 0 : return -1;
357 : }
358 :
359 0 : start_location = (const char *)buf;
360 0 : len = strlen(start_location)+1;
361 :
362 0 : buf += len;
363 0 : buflen -= len;
364 0 : if (buflen == 0) {
365 0 : return -1;
366 : }
367 :
368 0 : stop_location = (const char *)buf;
369 0 : len = strlen(stop_location)+1;
370 :
371 0 : buf += len;
372 0 : buflen -= len;
373 0 : if (buflen == 0) {
374 0 : return -1;
375 : }
376 :
377 0 : ok = parse_uintmax((const char *)buf, ' ', &start_sec, &next);
378 0 : if (!ok) {
379 0 : return -1;
380 : }
381 :
382 0 : ok = parse_uintmax(next, ' ', &start_usec, &next);
383 0 : if (!ok) {
384 0 : return -1;
385 : }
386 :
387 0 : ok = parse_uintmax(next, ' ', &stop_sec, &next);
388 0 : if (!ok) {
389 0 : return -1;
390 : }
391 :
392 0 : ok = parse_uintmax(next, ' ', &stop_usec, &next);
393 0 : if (!ok) {
394 0 : return -1;
395 : }
396 :
397 0 : ok = parse_uintmax(next, ' ', &pid, &next);
398 0 : if (!ok) {
399 0 : return -1;
400 : }
401 :
402 0 : ok = parse_uintmax(next, ' ', &state, &next);
403 0 : if (!ok) {
404 0 : return -1;
405 : }
406 :
407 0 : ok = parse_uintmax(next, '\0', &user_error, &next);
408 0 : if (!ok) {
409 0 : return -1;
410 : }
411 :
412 0 : ok = tevent_req_profile_set_name(profile, req_name);
413 0 : if (!ok) {
414 0 : return -1;
415 : }
416 :
417 0 : ok = tevent_req_profile_set_start(
418 : profile,
419 : start_location,
420 0 : (struct timeval){ .tv_sec=start_sec, .tv_usec=start_usec });
421 0 : if (!ok) {
422 0 : return -1;
423 : }
424 :
425 0 : ok = tevent_req_profile_set_stop(
426 : profile,
427 : stop_location,
428 0 : (struct timeval){ .tv_sec=stop_sec, .tv_usec=stop_usec });
429 0 : if (!ok) {
430 0 : return -1;
431 : }
432 :
433 0 : tevent_req_profile_set_status(
434 : profile,
435 : pid,
436 : (enum tevent_req_state)state,
437 : user_error);
438 :
439 0 : return next - orig_buf;
440 : }
441 :
442 0 : 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)
447 : {
448 0 : const uint8_t *orig_buf = buf;
449 0 : struct tevent_req_profile *profile = NULL;
450 : uintmax_t i, num_subprofiles;
451 0 : char *next = NULL;
452 : bool ok;
453 : ssize_t len;
454 :
455 0 : errno = 0;
456 :
457 0 : if (buf[buflen-1] != '\0') {
458 0 : return -1;
459 : }
460 :
461 0 : ok = parse_uintmax((const char *)buf, ' ', &num_subprofiles, &next);
462 0 : if (!ok) {
463 0 : return -1;
464 : }
465 :
466 0 : len = (next - (const char *)buf);
467 :
468 0 : buf += len;
469 0 : buflen -= len;
470 :
471 0 : profile = tevent_req_profile_create(mem_ctx);
472 0 : if (profile == NULL) {
473 0 : return -1;
474 : }
475 :
476 0 : len = tevent_req_profile_unpack_one(buf, buflen, profile);
477 0 : if (len == -1) {
478 0 : TALLOC_FREE(profile);
479 0 : return -1;
480 : }
481 :
482 0 : buf += len;
483 0 : buflen -= len;
484 :
485 0 : for (i=0; i<num_subprofiles; i++) {
486 : struct tevent_req_profile *subprofile;
487 :
488 0 : len = tevent_req_profile_unpack(
489 : buf,
490 : buflen,
491 : profile,
492 : &subprofile);
493 0 : if (len == -1) {
494 0 : TALLOC_FREE(profile);
495 0 : return -1;
496 : }
497 0 : buf += len;
498 0 : buflen -= len;
499 :
500 0 : tevent_req_profile_append_sub(profile, &subprofile);
501 : }
502 :
503 0 : *p_profile = profile;
504 :
505 0 : return buf - orig_buf;
506 : }
|