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