Branch data Line data Source code
1 : : #include <unistd.h>
2 : : #include <sys/types.h>
3 : : #include <sys/stat.h>
4 : : #include <fcntl.h>
5 : : #include <stdlib.h>
6 : : #include <arpa/inet.h>
7 : : #include <ctype.h>
8 : :
9 : : #include <google/protobuf-c/protobuf-c.h>
10 : :
11 : : #include "image.h"
12 : : #include "servicefd.h"
13 : : #include "compiler.h"
14 : : #include "asm/types.h"
15 : : #include "log.h"
16 : : #include "util.h"
17 : : #include "string.h"
18 : : #include "sockets.h"
19 : : #include "cr_options.h"
20 : :
21 : : #include "protobuf.h"
22 : :
23 : : /*
24 : : * To speed up reading of packed objects
25 : : * by providing space on stack, this should
26 : : * be more than enough for most objects.
27 : : */
28 : : #define PB_PKOBJ_LOCAL_SIZE 1024
29 : :
30 : : #define INET_ADDR_LEN 40
31 : :
32 : : struct pb_pr_field_s {
33 : : void *data;
34 : : int number;
35 : : int depth;
36 : : int count;
37 : : char fmt[32];
38 : : };
39 : :
40 : : typedef struct pb_pr_field_s pb_pr_field_t;
41 : :
42 : : struct pb_pr_ctrl_s {
43 : : void *arg;
44 : : int single_entry;
45 : : const char *pretty_fmt;
46 : : pb_pr_field_t cur;
47 : : };
48 : :
49 : : typedef struct pb_pr_ctrl_s pb_pr_ctl_t;
50 : : typedef int (*pb_pr_show_t)(pb_pr_field_t *field);
51 : :
52 : 0 : static int pb_msg_int32x(pb_pr_field_t *field)
53 : : {
54 : 0 : pr_msg("%#x", *(int *)field->data);
55 : 0 : return 0;
56 : : }
57 : :
58 : 0 : static int pb_msg_int64x(pb_pr_field_t *field)
59 : : {
60 : 0 : pr_msg("%#016lx", *(long *)field->data);
61 : 0 : return 0;
62 : : }
63 : :
64 : 0 : static int pb_msg_int64x_r(pb_pr_field_t *field)
65 : : {
66 : 0 : long val = *(long *)field->data;
67 [ # # ]: 0 : if (val)
68 : 0 : pr_msg("%#016lx", val);
69 : : else
70 : 0 : pr_msg("0");
71 : 0 : return 0;
72 : : }
73 : :
74 : 0 : static int pb_msg_string(pb_pr_field_t *field)
75 : : {
76 : 0 : pr_msg("\"%s\"", *(char **)field->data);
77 : 0 : return 0;
78 : : }
79 : :
80 : 0 : static int pb_msg_unk(pb_pr_field_t *field)
81 : : {
82 : 0 : pr_msg("unknown object %p", field->data);
83 : 0 : return 0;
84 : : }
85 : :
86 : : static inline void print_tabs(pb_pr_ctl_t *ctl)
87 : : {
88 : : int counter = ctl->cur.depth;
89 : :
90 [ # # ][ # # ]: 0 : if (!ctl->single_entry)
91 : : return;
92 : :
93 [ # # ][ # # ]: 0 : while (counter--)
94 : 0 : pr_msg("\t");
95 : : }
96 : :
97 : 0 : static void print_nested_message_braces(pb_pr_ctl_t *ctl, int right_brace)
98 : : {
99 [ # # ]: 0 : if (right_brace)
100 : : print_tabs(ctl);
101 [ # # ][ # # ]: 0 : pr_msg("%s%s", (right_brace) ? "}" : "{", (ctl->single_entry) ? "\n" : " ");
102 : 0 : }
103 : :
104 : : static void pb_show_msg(const void *msg, pb_pr_ctl_t *ctl);
105 : :
106 : 0 : static int show_nested_message(pb_pr_field_t *field)
107 : : {
108 : 0 : pb_pr_ctl_t *ctl = container_of(field, pb_pr_ctl_t, cur);
109 : :
110 : 0 : print_nested_message_braces(ctl, 0);
111 : 0 : field->depth++;
112 : 0 : pb_show_msg(field->data, ctl);
113 : 0 : field->depth--;
114 : 0 : print_nested_message_braces(ctl, 1);
115 : 0 : return 0;
116 : : }
117 : :
118 : 0 : static int show_enum(pb_pr_field_t *field)
119 : : {
120 : : pb_pr_ctl_t *ctl = container_of(field, pb_pr_ctl_t, cur);
121 : 0 : ProtobufCEnumDescriptor *d = ctl->arg;
122 : : const char *val_name = NULL;
123 : : int val, i;
124 : :
125 : 0 : val = *(int *)field->data;
126 [ # # ]: 0 : for (i = 0; i < d->n_values; i++)
127 [ # # ]: 0 : if (d->values[i].value == val) {
128 : 0 : val_name = d->values[i].name;
129 : 0 : break;
130 : : }
131 : :
132 [ # # ]: 0 : if (val_name != NULL)
133 : 0 : pr_msg("%s", val_name);
134 : : else
135 : 0 : pr_msg("%d", val);
136 : 0 : return 0;
137 : : }
138 : :
139 : 0 : static int show_bool(pb_pr_field_t *field)
140 : : {
141 : 0 : protobuf_c_boolean val = *(protobuf_c_boolean *)field->data;
142 : :
143 [ # # ]: 0 : if (val)
144 : 0 : pr_msg("True");
145 : : else
146 : 0 : pr_msg("False");
147 : 0 : return 0;
148 : : }
149 : :
150 : 0 : static int show_bytes(pb_pr_field_t *field)
151 : : {
152 : 0 : ProtobufCBinaryData *bytes = (ProtobufCBinaryData *)field->data;
153 : : int i = 0;
154 : :
155 [ # # ]: 0 : while (i < bytes->len)
156 : 0 : pr_msg("%02x ", bytes->data[i++]);
157 : 0 : return 0;
158 : : }
159 : :
160 : 0 : static size_t pb_show_prepare_field_context(const ProtobufCFieldDescriptor *fd,
161 : : pb_pr_ctl_t *ctl)
162 : : {
163 : : size_t fsize = 0;
164 : :
165 [ # # # # : 0 : switch (fd->type) {
# # # # ]
166 : : case PROTOBUF_C_TYPE_ENUM:
167 : 0 : ctl->arg = (void *)fd->descriptor;
168 : : case PROTOBUF_C_TYPE_INT32:
169 : : case PROTOBUF_C_TYPE_SINT32:
170 : : case PROTOBUF_C_TYPE_UINT32:
171 : : case PROTOBUF_C_TYPE_SFIXED32:
172 : : case PROTOBUF_C_TYPE_FLOAT:
173 : : fsize = 4;
174 : : break;
175 : : case PROTOBUF_C_TYPE_INT64:
176 : : case PROTOBUF_C_TYPE_SINT64:
177 : : case PROTOBUF_C_TYPE_SFIXED64:
178 : : case PROTOBUF_C_TYPE_FIXED32:
179 : : case PROTOBUF_C_TYPE_UINT64:
180 : : case PROTOBUF_C_TYPE_FIXED64:
181 : : case PROTOBUF_C_TYPE_DOUBLE:
182 : : fsize = 8;
183 : : break;
184 : : case PROTOBUF_C_TYPE_MESSAGE:
185 : 0 : ctl->arg = (void *)fd->descriptor;
186 : : case PROTOBUF_C_TYPE_STRING:
187 : : fsize = sizeof (void *);
188 : : break;
189 : : case PROTOBUF_C_TYPE_BOOL:
190 : : fsize = sizeof (protobuf_c_boolean);
191 : : break;
192 : : case PROTOBUF_C_TYPE_BYTES:
193 : : fsize = sizeof (ProtobufCBinaryData);
194 : : break;
195 : : default:
196 : 0 : BUG();
197 : : }
198 : 0 : return fsize;
199 : : }
200 : :
201 : 0 : static int pb_show_pretty(pb_pr_field_t *field)
202 : : {
203 [ # # # # ]: 0 : switch (field->fmt[0]) {
204 : : case '%':
205 : 0 : pr_msg(field->fmt, *(long *)field->data);
206 : 0 : break;
207 : : case 'S':
208 : : {
209 : 0 : ProtobufCBinaryData *name = (ProtobufCBinaryData *)field->data;
210 : : int i;
211 : :
212 [ # # ]: 0 : for (i = 0; i < name->len; i++) {
213 : 0 : char c = (char)name->data[i];
214 : :
215 [ # # ]: 0 : if (isprint(c))
216 : 0 : pr_msg("%c", c);
217 [ # # ]: 0 : else if (c != 0)
218 : 0 : pr_msg(".");
219 : : }
220 : : break;
221 : : }
222 : : case 'A':
223 : : {
224 : 0 : char addr[INET_ADDR_LEN] = "<unknown>";
225 [ # # ]: 0 : int family = (field->count == 1) ? AF_INET : AF_INET6;
226 : :
227 [ # # ]: 0 : if (inet_ntop(family, (void *)field->data, addr,
228 : : INET_ADDR_LEN) == NULL)
229 : 0 : pr_msg("failed to translate");
230 : : else
231 : 0 : pr_msg("%s", addr);
232 : : }
233 : 0 : return 1;
234 : : }
235 : : return 0;
236 : : }
237 : :
238 : : static void pb_copy_fmt(const char *fmt, char *to)
239 : : {
240 [ # # ]: 0 : while (*fmt != ' ' && *fmt != '\0') {
241 : 0 : *to = *fmt;
242 : 0 : to++;
243 : 0 : fmt++;
244 : : }
245 : :
246 : 0 : *to = '\0';
247 : : }
248 : :
249 : 0 : static const char *pb_next_pretty(const char *pfmt)
250 : : {
251 : 0 : pfmt = strchr(pfmt, ' ');
252 [ # # ]: 0 : if (pfmt) {
253 [ # # ]: 0 : while (*pfmt == ' ')
254 : 0 : pfmt++;
255 : :
256 [ # # ]: 0 : if (*pfmt == '\0')
257 : : pfmt = NULL;
258 : : }
259 : :
260 : 0 : return pfmt;
261 : : }
262 : :
263 : 0 : static int pb_find_fmt(char *what, pb_pr_ctl_t *ctl)
264 : : {
265 : : int len;
266 : 0 : const char *pretty = ctl->pretty_fmt;
267 : :
268 : 0 : len = strlen(what);
269 : : while (1) {
270 [ # # ]: 0 : if (!strncmp(pretty, what, len)) {
271 : 0 : pb_copy_fmt(pretty + len, ctl->cur.fmt);
272 : 0 : return 1;
273 : : }
274 : :
275 : 0 : pretty = pb_next_pretty(pretty + len);
276 [ # # ]: 0 : if (!pretty)
277 : : return 0;
278 : : }
279 : : }
280 : :
281 : 0 : static int pb_field_show_pretty(const ProtobufCFieldDescriptor *fd, pb_pr_ctl_t *ctl)
282 : : {
283 : : char cookie[32];
284 : :
285 [ # # ]: 0 : if (!ctl->pretty_fmt)
286 : : return 0;
287 : :
288 : 0 : sprintf(cookie, "%s:", fd->name);
289 [ # # ]: 0 : if (pb_find_fmt(cookie, ctl))
290 : : return 1;
291 : :
292 [ # # ]: 0 : if (!ctl->cur.depth)
293 : 0 : sprintf(cookie, "%d:", ctl->cur.number);
294 : : else
295 : 0 : sprintf(cookie, "%d.%d:", ctl->cur.depth, ctl->cur.number);
296 : :
297 [ # # ]: 0 : if (pb_find_fmt(cookie, ctl))
298 : : return 1;
299 : :
300 : : sprintf(cookie, "*:");
301 [ # # ]: 0 : if (pb_find_fmt(cookie, ctl))
302 : : return 1;
303 : :
304 : : return 0;
305 : : }
306 : :
307 : 0 : static pb_pr_show_t get_pb_show_function(int type, int label)
308 : : {
309 [ # # # # : 0 : switch (type) {
# # # #
# ]
310 : : case PROTOBUF_C_TYPE_INT32:
311 : : case PROTOBUF_C_TYPE_SINT32:
312 : : case PROTOBUF_C_TYPE_UINT32:
313 : : case PROTOBUF_C_TYPE_SFIXED32:
314 : : return pb_msg_int32x;
315 : : case PROTOBUF_C_TYPE_INT64:
316 : : case PROTOBUF_C_TYPE_SINT64:
317 : : case PROTOBUF_C_TYPE_SFIXED64:
318 : : case PROTOBUF_C_TYPE_FIXED32:
319 : : case PROTOBUF_C_TYPE_UINT64:
320 : : case PROTOBUF_C_TYPE_FIXED64:
321 [ # # ]: 0 : return (label == PROTOBUF_C_LABEL_REPEATED ?
322 : : pb_msg_int64x_r : pb_msg_int64x);
323 : : case PROTOBUF_C_TYPE_STRING:
324 : 0 : return pb_msg_string;
325 : : case PROTOBUF_C_TYPE_MESSAGE:
326 : 0 : return show_nested_message;
327 : : case PROTOBUF_C_TYPE_ENUM:
328 : 0 : return show_enum;
329 : : case PROTOBUF_C_TYPE_BOOL:
330 : 0 : return show_bool;
331 : : case PROTOBUF_C_TYPE_BYTES:
332 : 0 : return show_bytes;
333 : : case PROTOBUF_C_TYPE_FLOAT:
334 : : case PROTOBUF_C_TYPE_DOUBLE:
335 : : break;
336 : : default:
337 : 0 : BUG();
338 : : }
339 : : return pb_msg_unk;
340 : : }
341 : :
342 : 0 : static pb_pr_show_t get_show_function(const ProtobufCFieldDescriptor *fd, pb_pr_ctl_t *ctl)
343 : : {
344 [ # # ]: 0 : if (pb_field_show_pretty(fd, ctl))
345 : : return pb_show_pretty;
346 : 0 : return get_pb_show_function(fd->type, fd->label);
347 : : }
348 : :
349 : 0 : static void pb_show_repeated(const ProtobufCFieldDescriptor *fd, pb_pr_ctl_t *ctl, int nr_fields, pb_pr_show_t show,
350 : : size_t fsize)
351 : : {
352 : 0 : pb_pr_field_t *field = &ctl->cur;
353 : : unsigned long counter;
354 : : int done;
355 : :
356 [ # # ]: 0 : if (nr_fields == 0) {
357 : 0 : pr_msg("<empty>");
358 : : return;
359 : : }
360 : :
361 [ # # ]: 0 : if (fd->type == PROTOBUF_C_TYPE_MESSAGE) {
362 : 0 : void *p = field->data;
363 : :
364 : 0 : field->count = nr_fields;
365 : 0 : field->data = (void *)(*(long *)p);
366 : 0 : done = show(field);
367 [ # # ]: 0 : if (done)
368 : : return;
369 : :
370 [ # # ]: 0 : for (p += fsize, counter = 0; counter < nr_fields - 1; counter++, p += fsize) {
371 : 0 : pr_msg(":");
372 : 0 : field->data = (void *)(*(long *)p);
373 : 0 : show(field);
374 : : }
375 : : return;
376 : : }
377 : :
378 : 0 : field->count = nr_fields;
379 : 0 : done = show(field);
380 [ # # ]: 0 : if (done)
381 : : return;
382 : :
383 : 0 : field->data += fsize;
384 : :
385 [ # # ]: 0 : for (counter = 0; counter < nr_fields - 1; counter++, field->data += fsize) {
386 : 0 : pr_msg(":");
387 : 0 : show(field);
388 : : }
389 : : }
390 : :
391 : 0 : static void pb_show_field(const ProtobufCFieldDescriptor *fd,
392 : 0 : int nr_fields, pb_pr_ctl_t *ctl)
393 : : {
394 : : pb_pr_show_t show;
395 : :
396 : : print_tabs(ctl);
397 : 0 : pr_msg("%s: ", fd->name);
398 : :
399 : 0 : show = get_show_function(fd, ctl);
400 : :
401 : 0 : pb_show_repeated(fd, ctl, nr_fields, show, pb_show_prepare_field_context(fd, ctl));
402 : :
403 [ # # ]: 0 : if (ctl->single_entry)
404 : 0 : pr_msg("\n");
405 : : else
406 : 0 : pr_msg(" ");
407 : 0 : }
408 : :
409 : 0 : static int pb_optional_field_present(const ProtobufCFieldDescriptor *field,
410 : : const void *msg)
411 : : {
412 [ # # ]: 0 : if ((field->type == PROTOBUF_C_TYPE_MESSAGE) ||
413 : : (field->type == PROTOBUF_C_TYPE_STRING)) {
414 : 0 : const void *opt_flag = * (const void * const *)(msg + field->offset);
415 : :
416 [ # # ][ # # ]: 0 : if ((opt_flag == NULL) || (opt_flag == field->default_value))
417 : : return 0;
418 : : } else {
419 : 0 : const protobuf_c_boolean *has = msg + field->quantifier_offset;
420 : :
421 [ # # ]: 0 : if (!*has)
422 : : return 0;
423 : : }
424 : 0 : return 1;
425 : : }
426 : :
427 : 0 : static bool should_show_field(const char *name)
428 : : {
429 : : char *s, *e;
430 : : int len;
431 : :
432 [ # # ]: 0 : if (!opts.show_fmt)
433 : : return true;
434 : :
435 : 0 : len = strlen(name);
436 : : s = opts.show_fmt;
437 : :
438 : : while (1) {
439 : 0 : e = strchrnul(s, ',');
440 [ # # ]: 0 : if (e - s == len) {
441 [ # # ]: 0 : if (!strncmp(name, s, len))
442 : : return true;
443 : : }
444 [ # # ]: 0 : if (*e == '\0')
445 : : return false;
446 : 0 : s = e + 1;
447 : 0 : }
448 : : }
449 : :
450 : 0 : static void pb_show_msg(const void *msg, pb_pr_ctl_t *ctl)
451 : : {
452 : : int i;
453 : 0 : const ProtobufCMessageDescriptor *md = ctl->arg;
454 : :
455 [ # # ]: 0 : BUG_ON(md == NULL);
456 : :
457 [ # # ]: 0 : for (i = 0; i < md->n_fields; i++) {
458 : 0 : const ProtobufCFieldDescriptor fd = md->fields[i];
459 : : unsigned long *data;
460 : : size_t nr_fields;
461 : :
462 : : nr_fields = 1;
463 : 0 : data = (unsigned long *)(msg + fd.offset);
464 : :
465 [ # # ]: 0 : if (fd.label == PROTOBUF_C_LABEL_OPTIONAL) {
466 [ # # ]: 0 : if (!pb_optional_field_present(&fd, msg))
467 : 0 : continue;
468 : : }
469 : :
470 [ # # ]: 0 : if (!should_show_field(fd.name))
471 : 0 : continue;
472 : :
473 [ # # ]: 0 : if (fd.label == PROTOBUF_C_LABEL_REPEATED) {
474 : 0 : nr_fields = *(size_t *)(msg + fd.quantifier_offset);
475 : 0 : data = (unsigned long *)*data;
476 : : }
477 : :
478 : 0 : ctl->cur.data = data;
479 : 0 : ctl->cur.number = i + 1;
480 : :
481 : 0 : pb_show_field(&fd, nr_fields, ctl);
482 : : }
483 : 0 : }
484 : :
485 : 0 : static inline void pb_no_payload(int fd, void *obj) { }
486 : :
487 : 0 : void do_pb_show_plain(int fd, int type, int single_entry,
488 : : void (*payload_hadler)(int fd, void *obj),
489 : : const char *pretty_fmt)
490 : : {
491 : 0 : pb_pr_ctl_t ctl = {NULL, single_entry, pretty_fmt};
492 : : void (*handle_payload)(int fd, void *obj);
493 : :
494 [ # # ]: 0 : if (!cr_pb_descs[type].pb_desc) {
495 : 0 : pr_err("Wrong object requested %d\n", type);
496 : 0 : return;
497 : : }
498 : :
499 [ # # ]: 0 : handle_payload = (payload_hadler) ? : pb_no_payload;
500 : :
501 : : while (1) {
502 : : void *obj;
503 : :
504 [ # # ]: 0 : if (pb_read_one_eof(fd, &obj, type) <= 0)
505 : : break;
506 : :
507 : 0 : ctl.arg = (void *)cr_pb_descs[type].pb_desc;
508 : 0 : pb_show_msg(obj, &ctl);
509 : 0 : handle_payload(fd, obj);
510 : 0 : cr_pb_descs[type].free(obj, NULL);
511 [ # # ]: 0 : if (single_entry)
512 : : break;
513 : 0 : pr_msg("\n");
514 : 0 : }
515 : : }
516 : :
517 : : static char *image_name(int fd)
518 : : {
519 : : static char image_path[PATH_MAX];
520 : :
521 [ # # ][ # # ]: 0 : if (read_fd_link(fd, image_path, sizeof(image_path)) > 0)
[ # # ][ # # ]
[ # # ][ # # ]
522 : : return image_path;
523 : : return NULL;
524 : : }
525 : :
526 : : /*
527 : : * Reads PB record (header + packed object) from file @fd and unpack
528 : : * it with @unpack procedure to the pointer @pobj
529 : : *
530 : : * 1 on success
531 : : * -1 on error (or EOF met and @eof set to false)
532 : : * 0 on EOF and @eof set to true
533 : : *
534 : : * Don't forget to free memory granted to unpacked object in calling code if needed
535 : : */
536 : :
537 : 387878 : int do_pb_read_one(int fd, void **pobj, int type, bool eof)
538 : : {
539 : : u8 local[PB_PKOBJ_LOCAL_SIZE];
540 : : void *buf = (void *)&local;
541 : : u32 size;
542 : : int ret;
543 : :
544 [ - + ]: 387878 : if (!cr_pb_descs[type].pb_desc) {
545 : 0 : pr_err("Wrong object requested %d on %s\n",
546 : : type, image_name(fd));
547 : 0 : return -1;
548 : : }
549 : :
550 : 387878 : *pobj = NULL;
551 : :
552 : 387878 : ret = read(fd, &size, sizeof(size));
553 [ + + ]: 387878 : if (ret == 0) {
554 [ - + ]: 14531 : if (eof) {
555 : : return 0;
556 : : } else {
557 : 0 : pr_err("Unexpected EOF on %s\n",
558 : : image_name(fd));
559 : 0 : return -1;
560 : : }
561 [ - + ]: 373347 : } else if (ret < sizeof(size)) {
562 : 0 : pr_perror("Read %d bytes while %d expected on %s",
563 : : ret, (int)sizeof(size),
564 : : image_name(fd));
565 : 0 : return -1;
566 : : }
567 : :
568 [ + + ]: 373347 : if (size > sizeof(local)) {
569 : : ret = -1;
570 [ - + ]: 88 : buf = xmalloc(size);
571 [ + - ]: 88 : if (!buf)
572 : : goto err;
573 : : }
574 : :
575 : 746694 : ret = read(fd, buf, size);
576 [ - + ]: 373347 : if (ret < 0) {
577 : 0 : pr_perror("Can't read %d bytes from file %s",
578 : : size, image_name(fd));
579 : 0 : goto err;
580 [ - + ]: 373347 : } else if (ret != size) {
581 : 0 : pr_perror("Read %d bytes while %d expected from %s",
582 : : ret, size, image_name(fd));
583 : : ret = -1;
584 : 0 : goto err;
585 : : }
586 : :
587 : 373347 : *pobj = cr_pb_descs[type].unpack(NULL, size, buf);
588 [ - + ]: 373347 : if (!*pobj) {
589 : : ret = -1;
590 : 0 : pr_err("Failed unpacking object %p from %s\n",
591 : : pobj, image_name(fd));
592 : 0 : goto err;
593 : : }
594 : :
595 : : ret = 1;
596 : : err:
597 [ + + ]: 373347 : if (buf != (void *)&local)
598 [ + - ]: 88 : xfree(buf);
599 : :
600 : 373347 : return ret;
601 : : }
602 : :
603 : : /*
604 : : * Writes PB record (header + packed object pointed by @obj)
605 : : * to file @fd, using @getpksize to get packed size and @pack
606 : : * to implement packing
607 : : *
608 : : * 0 on success
609 : : * -1 on error
610 : : */
611 : 233447 : int pb_write_one(int fd, void *obj, int type)
612 : : {
613 : : u8 local[PB_PKOBJ_LOCAL_SIZE];
614 : : void *buf = (void *)&local;
615 : : u32 size, packed;
616 : : int ret = -1;
617 : : struct iovec iov[2];
618 : :
619 [ - + ]: 233447 : if (!cr_pb_descs[type].pb_desc) {
620 : 0 : pr_err("Wrong object requested %d\n", type);
621 : 0 : return -1;
622 : : }
623 : :
624 : 233447 : size = cr_pb_descs[type].getpksize(obj);
625 [ + + ]: 233447 : if (size > (u32)sizeof(local)) {
626 [ - + ]: 78 : buf = xmalloc(size);
627 [ + - ]: 78 : if (!buf)
628 : : goto err;
629 : : }
630 : :
631 : 233447 : packed = cr_pb_descs[type].pack(obj, buf);
632 [ - + ]: 233447 : if (packed != size) {
633 : 0 : pr_err("Failed packing PB object %p\n", obj);
634 : 0 : goto err;
635 : : }
636 : :
637 : 233447 : iov[0].iov_base = &size;
638 : 233447 : iov[0].iov_len = sizeof(size);
639 : 233447 : iov[1].iov_base = buf;
640 : 233447 : iov[1].iov_len = size;
641 : :
642 : 233447 : ret = writev(fd, iov, 2);
643 [ - + ]: 233447 : if (ret != size + sizeof(size)) {
644 : 0 : pr_perror("Can't write %d bytes", (int)(size + sizeof(size)));
645 : 0 : goto err;
646 : : }
647 : :
648 : : ret = 0;
649 : : err:
650 [ + + ]: 233447 : if (buf != (void *)&local)
651 [ + - ]: 78 : xfree(buf);
652 : 233447 : return ret;
653 : : }
654 : :
655 : 8113 : int collect_image(struct collect_image_info *cinfo)
656 : : {
657 : 8113 : bool optional = !!(cinfo->flags & COLLECT_OPTIONAL);
658 : : int fd, ret;
659 : : void *(*o_alloc)(size_t size) = malloc;
660 : : void (*o_free)(void *ptr) = free;
661 : :
662 : 8113 : pr_info("Collecting %d/%d (flags %x)\n",
663 : : cinfo->fd_type, cinfo->pb_type, cinfo->flags);
664 : :
665 [ + + ]: 8113 : fd = open_image(cinfo->fd_type, O_RSTR | (optional ? O_OPT : 0));
666 [ - + ]: 8113 : if (fd < 0) {
667 [ # # ]: 0 : if (optional && fd == -ENOENT)
668 : : return 0;
669 : : else
670 : 0 : return -1;
671 : : }
672 : :
673 [ + + ]: 8113 : if (cinfo->flags & COLLECT_SHARED) {
674 : : o_alloc = shmalloc;
675 : : o_free = shfree_last;
676 : : }
677 : :
678 : : while (1) {
679 : : void *obj;
680 : : ProtobufCMessage *msg;
681 : :
682 [ + + ]: 11910 : if (cinfo->priv_size) {
683 : : ret = -1;
684 : 11529 : obj = o_alloc(cinfo->priv_size);
685 [ + - ]: 11529 : if (!obj)
686 : : break;
687 : : } else
688 : : obj = NULL;
689 : :
690 : 11910 : ret = pb_read_one_eof(fd, &msg, cinfo->pb_type);
691 [ + + ]: 11910 : if (ret <= 0) {
692 : 8113 : o_free(obj);
693 : 8113 : break;
694 : : }
695 : :
696 : 3797 : ret = cinfo->collect(obj, msg);
697 [ - + ]: 3797 : if (ret < 0) {
698 : 0 : o_free(obj);
699 : 0 : cr_pb_descs[cinfo->pb_type].free(msg, NULL);
700 : 0 : break;
701 : : }
702 : :
703 [ + + ]: 3797 : if (!cinfo->priv_size)
704 : 26 : cr_pb_descs[cinfo->pb_type].free(msg, NULL);
705 : 3797 : }
706 : :
707 : 8113 : close(fd);
708 : 8113 : pr_debug(" `- ... done\n");
709 : 8113 : return ret;
710 : : }
|