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 "crtools.h"
12 : : #include "compiler.h"
13 : : #include "types.h"
14 : : #include "log.h"
15 : : #include "util.h"
16 : : #include "string.h"
17 : : #include "sockets.h"
18 : :
19 : : #include "protobuf.h"
20 : : #include "protobuf/inventory.pb-c.h"
21 : : #include "protobuf/regfile.pb-c.h"
22 : : #include "protobuf/eventfd.pb-c.h"
23 : : #include "protobuf/eventpoll.pb-c.h"
24 : : #include "protobuf/signalfd.pb-c.h"
25 : : #include "protobuf/inotify.pb-c.h"
26 : : #include "protobuf/core.pb-c.h"
27 : : #include "protobuf/mm.pb-c.h"
28 : : #include "protobuf/pipe.pb-c.h"
29 : : #include "protobuf/fifo.pb-c.h"
30 : : #include "protobuf/fdinfo.pb-c.h"
31 : : #include "protobuf/pipe-data.pb-c.h"
32 : : #include "protobuf/pstree.pb-c.h"
33 : : #include "protobuf/sa.pb-c.h"
34 : : #include "protobuf/sk-unix.pb-c.h"
35 : : #include "protobuf/sk-inet.pb-c.h"
36 : : #include "protobuf/packet-sock.pb-c.h"
37 : : #include "protobuf/sk-packet.pb-c.h"
38 : : #include "protobuf/creds.pb-c.h"
39 : : #include "protobuf/itimer.pb-c.h"
40 : : #include "protobuf/utsns.pb-c.h"
41 : : #include "protobuf/ipc-var.pb-c.h"
42 : : #include "protobuf/ipc-shm.pb-c.h"
43 : : #include "protobuf/ipc-msg.pb-c.h"
44 : : #include "protobuf/ipc-sem.pb-c.h"
45 : : #include "protobuf/fs.pb-c.h"
46 : : #include "protobuf/remap-file-path.pb-c.h"
47 : : #include "protobuf/ghost-file.pb-c.h"
48 : : #include "protobuf/mnt.pb-c.h"
49 : : #include "protobuf/netdev.pb-c.h"
50 : : #include "protobuf/tcp-stream.pb-c.h"
51 : : #include "protobuf/tty.pb-c.h"
52 : :
53 : : typedef size_t (*pb_getpksize_t)(void *obj);
54 : : typedef size_t (*pb_pack_t)(void *obj, void *where);
55 : : typedef void *(*pb_unpack_t)(void *allocator, size_t size, void *from);
56 : : typedef void (*pb_free_t)(void *obj, void *allocator);
57 : :
58 : : struct cr_pb_message_desc {
59 : : pb_getpksize_t getpksize;
60 : : pb_pack_t pack;
61 : : pb_unpack_t unpack;
62 : : pb_free_t free;
63 : : const ProtobufCMessageDescriptor *pb_desc;
64 : : };
65 : :
66 : : #define PB_PACK_TYPECHECK(__o, __fn) ({ if (0) __fn##__pack(__o, NULL); (pb_pack_t)&__fn##__pack; })
67 : : #define PB_GPS_TYPECHECK(__o, __fn) ({ if (0) __fn##__get_packed_size(__o); (pb_getpksize_t)&__fn##__get_packed_size; })
68 : : #define PB_UNPACK_TYPECHECK(__op, __fn) ({ if (0) *__op = __fn##__unpack(NULL, 0, NULL); (pb_unpack_t)&__fn##__unpack; })
69 : : #define PB_FREE_TYPECHECK(__o, __fn) ({ if (0) __fn##__free_unpacked(__o, NULL); (pb_free_t)&__fn##__free_unpacked; })
70 : :
71 : : /*
72 : : * This should be explicitly "called" to do type-checking
73 : : */
74 : :
75 : : #define CR_PB_MDESC_INIT(__var, __type, __name) do { \
76 : : __var.getpksize = PB_GPS_TYPECHECK((__type *)NULL, __name); \
77 : : __var.pack = PB_PACK_TYPECHECK((__type *)NULL, __name); \
78 : : __var.unpack = PB_UNPACK_TYPECHECK((__type **)NULL, __name); \
79 : : __var.free = PB_FREE_TYPECHECK((__type *)NULL, __name); \
80 : : __var.pb_desc = &__name##__descriptor; \
81 : : } while (0)
82 : :
83 : : static struct cr_pb_message_desc cr_pb_descs[PB_MAX];
84 : :
85 : : #define CR_PB_DESC(__type, __vtype, __ftype) \
86 : : CR_PB_MDESC_INIT(cr_pb_descs[PB_##__type], __vtype##Entry, __ftype##_entry)
87 : :
88 : 547 : void cr_pb_init(void)
89 : : {
90 : 547 : CR_PB_DESC(INVENTORY, Inventory, inventory);
91 : 547 : CR_PB_DESC(FDINFO, Fdinfo, fdinfo);
92 : 547 : CR_PB_DESC(REG_FILES, RegFile, reg_file);
93 : 547 : CR_PB_DESC(EVENTFD, EventfdFile, eventfd_file);
94 : 547 : CR_PB_DESC(EVENTPOLL, EventpollFile, eventpoll_file);
95 : 547 : CR_PB_DESC(EVENTPOLL_TFD, EventpollTfd, eventpoll_tfd);
96 : 547 : CR_PB_DESC(SIGNALFD, Signalfd, signalfd);
97 : 547 : CR_PB_DESC(INOTIFY, InotifyFile, inotify_file);
98 : 547 : CR_PB_DESC(INOTIFY_WD, InotifyWd, inotify_wd);
99 : 547 : CR_PB_DESC(CORE, Core, core);
100 : 547 : CR_PB_DESC(MM, Mm, mm);
101 : 547 : CR_PB_DESC(VMAS, Vma, vma);
102 : 547 : CR_PB_DESC(PIPES, Pipe, pipe);
103 : 547 : CR_PB_DESC(PIPES_DATA, PipeData, pipe_data);
104 : 547 : CR_PB_DESC(FIFO, Fifo, fifo);
105 : 547 : CR_PB_DESC(PSTREE, Pstree, pstree);
106 : 547 : CR_PB_DESC(SIGACT, Sa, sa);
107 : 547 : CR_PB_DESC(UNIXSK, UnixSk, unix_sk);
108 : 547 : CR_PB_DESC(INETSK, InetSk, inet_sk);
109 : 547 : CR_PB_DESC(SK_QUEUES, SkPacket, sk_packet);
110 : 547 : CR_PB_DESC(ITIMERS, Itimer, itimer);
111 : 547 : CR_PB_DESC(CREDS, Creds, creds);
112 : 547 : CR_PB_DESC(UTSNS, Utsns, utsns);
113 : 547 : CR_PB_DESC(IPCNS_VAR, IpcVar, ipc_var);
114 : 547 : CR_PB_DESC(IPCNS_SHM, IpcShm, ipc_shm);
115 : : /* There's no _entry suffix in this one :( */
116 : 547 : CR_PB_MDESC_INIT(cr_pb_descs[PB_IPCNS_MSG], IpcMsg, ipc_msg);
117 : 547 : CR_PB_DESC(IPCNS_MSG_ENT, IpcMsg, ipc_msg);
118 : 547 : CR_PB_DESC(IPCNS_SEM, IpcSem, ipc_sem);
119 : 547 : CR_PB_DESC(FS, Fs, fs);
120 : 547 : CR_PB_DESC(REMAP_FPATH, RemapFilePath, remap_file_path);
121 : 547 : CR_PB_DESC(GHOST_FILE, GhostFile, ghost_file);
122 : 547 : CR_PB_DESC(TCP_STREAM, TcpStream, tcp_stream);
123 : 547 : CR_PB_DESC(MOUNTPOINTS, Mnt, mnt);
124 : 547 : CR_PB_DESC(NETDEV, NetDevice, net_device);
125 : 547 : CR_PB_DESC(PACKETSK, PacketSock, packet_sock);
126 : 547 : CR_PB_DESC(TTY, TtyFile, tty_file);
127 : 547 : CR_PB_DESC(TTY_INFO, TtyInfo, tty_info);
128 : 547 : }
129 : :
130 : : /*
131 : : * To speed up reading of packed objects
132 : : * by providing space on stack, this should
133 : : * be more than enough for most objects.
134 : : */
135 : : #define PB_PKOBJ_LOCAL_SIZE 1024
136 : :
137 : : #define INET_ADDR_LEN 40
138 : :
139 : : struct pb_pr_field_s {
140 : : void *data;
141 : : int number;
142 : : int depth;
143 : : int count;
144 : : char fmt[32];
145 : : };
146 : :
147 : : typedef struct pb_pr_field_s pb_pr_field_t;
148 : :
149 : : struct pb_pr_ctrl_s {
150 : : void *arg;
151 : : int single_entry;
152 : : const char *pretty_fmt;
153 : : pb_pr_field_t cur;
154 : : };
155 : :
156 : : typedef struct pb_pr_ctrl_s pb_pr_ctl_t;
157 : : typedef int (*pb_pr_show_t)(pb_pr_field_t *field);
158 : :
159 : 0 : static int pb_msg_int32x(pb_pr_field_t *field)
160 : : {
161 : 0 : pr_msg("%#x", *(int *)field->data);
162 : 0 : return 0;
163 : : }
164 : :
165 : 0 : static int pb_msg_int64x(pb_pr_field_t *field)
166 : : {
167 : 0 : pr_msg("%#016lx", *(long *)field->data);
168 : 0 : return 0;
169 : : }
170 : :
171 : 0 : static int pb_msg_string(pb_pr_field_t *field)
172 : : {
173 : 0 : pr_msg("\"%s\"", *(char **)field->data);
174 : 0 : return 0;
175 : : }
176 : :
177 : 0 : static int pb_msg_unk(pb_pr_field_t *field)
178 : : {
179 : 0 : pr_msg("unknown object %p", field->data);
180 : 0 : return 0;
181 : : }
182 : :
183 : 0 : static inline void print_tabs(pb_pr_ctl_t *ctl)
184 : : {
185 : 0 : int counter = ctl->cur.depth;
186 : :
187 [ # # ]: 0 : if (!ctl->single_entry)
188 : 0 : return;
189 : :
190 [ # # ]: 0 : while (counter--)
191 : 0 : pr_msg("\t");
192 : : }
193 : :
194 : 0 : static void print_nested_message_braces(pb_pr_ctl_t *ctl, int right_brace)
195 : : {
196 [ # # ]: 0 : if (right_brace)
197 : 0 : print_tabs(ctl);
198 [ # # ][ # # ]: 0 : pr_msg("%s%s", (right_brace) ? "}" : "{", (ctl->single_entry) ? "\n" : " ");
199 : 0 : }
200 : :
201 : : static void pb_show_msg(const void *msg, pb_pr_ctl_t *ctl);
202 : :
203 : 0 : static int show_nested_message(pb_pr_field_t *field)
204 : : {
205 : 0 : pb_pr_ctl_t *ctl = container_of(field, pb_pr_ctl_t, cur);
206 : :
207 : 0 : print_nested_message_braces(ctl, 0);
208 : 0 : field->depth++;
209 : 0 : pb_show_msg(field->data, ctl);
210 : 0 : field->depth--;
211 : 0 : print_nested_message_braces(ctl, 1);
212 : 0 : return 0;
213 : : }
214 : :
215 : 0 : static int show_enum(pb_pr_field_t *field)
216 : : {
217 : 0 : pb_pr_ctl_t *ctl = container_of(field, pb_pr_ctl_t, cur);
218 : 0 : ProtobufCEnumDescriptor *d = ctl->arg;
219 : 0 : const char *val_name = NULL;
220 : : int val, i;
221 : :
222 : 0 : val = *(int *)field->data;
223 [ # # ]: 0 : for (i = 0; i < d->n_values; i++)
224 [ # # ]: 0 : if (d->values[i].value == val) {
225 : 0 : val_name = d->values[i].name;
226 : 0 : break;
227 : : }
228 : :
229 [ # # ]: 0 : if (val_name != NULL)
230 : 0 : pr_msg("%s", val_name);
231 : : else
232 : 0 : pr_msg("%d", val);
233 : 0 : return 0;
234 : : }
235 : :
236 : 0 : static int show_bool(pb_pr_field_t *field)
237 : : {
238 : 0 : protobuf_c_boolean val = *(protobuf_c_boolean *)field->data;
239 : :
240 [ # # ]: 0 : if (val)
241 : 0 : pr_msg("True");
242 : : else
243 : 0 : pr_msg("False");
244 : 0 : return 0;
245 : : }
246 : :
247 : 0 : static int show_bytes(pb_pr_field_t *field)
248 : : {
249 : 0 : ProtobufCBinaryData *bytes = (ProtobufCBinaryData *)field->data;
250 : 0 : int i = 0;
251 : :
252 [ # # ]: 0 : while (i < bytes->len)
253 : 0 : pr_msg("%02x ", bytes->data[i++]);
254 : 0 : return 0;
255 : : }
256 : :
257 : 0 : static size_t pb_show_prepare_field_context(const ProtobufCFieldDescriptor *fd,
258 : : pb_pr_ctl_t *ctl)
259 : : {
260 : 0 : pb_pr_field_t *field = &ctl->cur;
261 : 0 : size_t fsize = 0;
262 : :
263 [ # # # # : 0 : switch (fd->type) {
# # # # ]
264 : : case PROTOBUF_C_TYPE_ENUM:
265 : 0 : ctl->arg = (void *)fd->descriptor;
266 : : case PROTOBUF_C_TYPE_INT32:
267 : : case PROTOBUF_C_TYPE_SINT32:
268 : : case PROTOBUF_C_TYPE_UINT32:
269 : : case PROTOBUF_C_TYPE_SFIXED32:
270 : : case PROTOBUF_C_TYPE_FLOAT:
271 : : fsize = 4;
272 : : break;
273 : : case PROTOBUF_C_TYPE_INT64:
274 : : case PROTOBUF_C_TYPE_SINT64:
275 : : case PROTOBUF_C_TYPE_SFIXED64:
276 : : case PROTOBUF_C_TYPE_FIXED32:
277 : : case PROTOBUF_C_TYPE_UINT64:
278 : : case PROTOBUF_C_TYPE_FIXED64:
279 : : case PROTOBUF_C_TYPE_DOUBLE:
280 : : fsize = 8;
281 : : break;
282 : : case PROTOBUF_C_TYPE_MESSAGE:
283 : 0 : ctl->arg = (void *)fd->descriptor;
284 : 0 : field->data = (void *)(*(long *)field->data);
285 : : case PROTOBUF_C_TYPE_STRING:
286 : : fsize = sizeof (void *);
287 : : break;
288 : : case PROTOBUF_C_TYPE_BOOL:
289 : 0 : fsize = sizeof (protobuf_c_boolean);
290 : : break;
291 : : case PROTOBUF_C_TYPE_BYTES:
292 : 0 : fsize = sizeof (ProtobufCBinaryData);
293 : : break;
294 : : default:
295 : 0 : BUG();
296 : : }
297 : 0 : return fsize;
298 : : }
299 : :
300 : 0 : static int pb_show_pretty(pb_pr_field_t *field)
301 : : {
302 [ # # # # ]: 0 : switch (field->fmt[0]) {
303 : : case '%':
304 : 0 : pr_msg(field->fmt, *(long *)field->data);
305 : 0 : break;
306 : : case 'S':
307 : : {
308 : 0 : ProtobufCBinaryData *name = (ProtobufCBinaryData *)field->data;
309 : : int i;
310 : :
311 [ # # ]: 0 : for (i = 0; i < name->len; i++) {
312 : 0 : char c = (char)name->data[i];
313 : :
314 [ # # ]: 0 : if (isprint(c))
315 : 0 : pr_msg("%c", c);
316 [ # # ]: 0 : else if (c != 0)
317 : 0 : pr_msg(".");
318 : : }
319 : : break;
320 : : }
321 : : case 'A':
322 : : {
323 : 0 : char addr[INET_ADDR_LEN] = "<unknown>";
324 [ # # ]: 0 : int family = (field->count == 1) ? AF_INET : AF_INET6;
325 : :
326 [ # # ]: 0 : if (inet_ntop(family, (void *)field->data, addr,
327 : : INET_ADDR_LEN) == NULL)
328 : 0 : pr_msg("failed to translate");
329 : : else
330 : 0 : pr_msg("%s", addr);
331 : : }
332 : 0 : return 1;
333 : : }
334 : : return 0;
335 : : }
336 : :
337 : 0 : static int pb_field_show_pretty(pb_pr_ctl_t *ctl)
338 : : {
339 : 0 : pb_pr_field_t *field = &ctl->cur;
340 : : int found;
341 : : char cookie[32];
342 : : const char *ptr;
343 : :
344 [ # # ][ # # ]: 0 : if (!ctl->pretty_fmt || field->depth)
345 : : return 0;
346 : :
347 : 0 : sprintf(cookie, " %d:", field->number);
348 [ # # ]: 0 : if (!strncmp(ctl->pretty_fmt, &cookie[1], strlen(&cookie[1])))
349 : : ptr = ctl->pretty_fmt;
350 : : else {
351 : 0 : ptr = strstr(ctl->pretty_fmt, cookie);
352 [ # # ]: 0 : if (!ptr)
353 : : return 0;
354 : : }
355 : 0 : found = sscanf(ptr, "%*[ 1-9:]%s", field->fmt);
356 [ # # ]: 0 : BUG_ON(found > 1);
357 : : return found;
358 : : }
359 : :
360 : 0 : static pb_pr_show_t get_pb_show_function(int type)
361 : : {
362 [ # # # # : 0 : switch (type) {
# # # #
# ]
363 : : case PROTOBUF_C_TYPE_INT32:
364 : : case PROTOBUF_C_TYPE_SINT32:
365 : : case PROTOBUF_C_TYPE_UINT32:
366 : : case PROTOBUF_C_TYPE_SFIXED32:
367 : : return pb_msg_int32x;
368 : : case PROTOBUF_C_TYPE_INT64:
369 : : case PROTOBUF_C_TYPE_SINT64:
370 : : case PROTOBUF_C_TYPE_SFIXED64:
371 : : case PROTOBUF_C_TYPE_FIXED32:
372 : : case PROTOBUF_C_TYPE_UINT64:
373 : : case PROTOBUF_C_TYPE_FIXED64:
374 : 0 : return pb_msg_int64x;
375 : : case PROTOBUF_C_TYPE_STRING:
376 : 0 : return pb_msg_string;
377 : : case PROTOBUF_C_TYPE_MESSAGE:
378 : 0 : return show_nested_message;
379 : : case PROTOBUF_C_TYPE_ENUM:
380 : 0 : return show_enum;
381 : : case PROTOBUF_C_TYPE_BOOL:
382 : 0 : return show_bool;
383 : : case PROTOBUF_C_TYPE_BYTES:
384 : 0 : return show_bytes;
385 : : case PROTOBUF_C_TYPE_FLOAT:
386 : : case PROTOBUF_C_TYPE_DOUBLE:
387 : : break;
388 : : default:
389 : 0 : BUG();
390 : : }
391 : : return pb_msg_unk;
392 : : }
393 : :
394 : 0 : static pb_pr_show_t get_show_function(int type, pb_pr_ctl_t *ctl)
395 : : {
396 [ # # ]: 0 : if (pb_field_show_pretty(ctl))
397 : : return pb_show_pretty;
398 : 0 : return get_pb_show_function(type);
399 : : }
400 : :
401 : 0 : static void pb_show_repeated(pb_pr_ctl_t *ctl, int nr_fields, pb_pr_show_t show,
402 : : size_t fsize)
403 : : {
404 : 0 : pb_pr_field_t *field = &ctl->cur;
405 : : unsigned long counter;
406 : : int done;
407 : :
408 [ # # ]: 0 : if (nr_fields == 0) {
409 : 0 : pr_msg("<empty>");
410 : 0 : return;
411 : : }
412 : :
413 : 0 : field->count = nr_fields;
414 : 0 : done = show(field);
415 [ # # ]: 0 : if (done)
416 : : return;
417 : :
418 : 0 : field->data += fsize;
419 : :
420 [ # # ]: 0 : for (counter = 0; counter < nr_fields - 1; counter++, field->data += fsize) {
421 : 0 : pr_msg(":");
422 : 0 : show(field);
423 : : }
424 : : }
425 : :
426 : 0 : static void pb_show_field(const ProtobufCFieldDescriptor *fd,
427 : : int nr_fields, pb_pr_ctl_t *ctl)
428 : : {
429 : : pb_pr_show_t show;
430 : :
431 : 0 : print_tabs(ctl);
432 : 0 : pr_msg("%s: ", fd->name);
433 : :
434 : 0 : show = get_show_function(fd->type, ctl);
435 : :
436 : 0 : pb_show_repeated(ctl, nr_fields, show, pb_show_prepare_field_context(fd, ctl));
437 : :
438 [ # # ]: 0 : if (ctl->single_entry)
439 : 0 : pr_msg("\n");
440 : : else
441 : 0 : pr_msg(" ");
442 : 0 : }
443 : :
444 : 0 : static int pb_optional_field_present(const ProtobufCFieldDescriptor *field,
445 : : const void *msg)
446 : : {
447 [ # # ]: 0 : if ((field->type == PROTOBUF_C_TYPE_MESSAGE) ||
448 : : (field->type == PROTOBUF_C_TYPE_STRING)) {
449 : 0 : const void *opt_flag = * (const void * const *)(msg + field->offset);
450 : :
451 [ # # ][ # # ]: 0 : if ((opt_flag == NULL) || (opt_flag == field->default_value))
452 : : return 0;
453 : : } else {
454 : 0 : const protobuf_c_boolean *has = msg + field->quantifier_offset;
455 : :
456 [ # # ]: 0 : if (!*has)
457 : : return 0;
458 : : }
459 : 0 : return 1;
460 : : }
461 : :
462 : 0 : static void pb_show_msg(const void *msg, pb_pr_ctl_t *ctl)
463 : : {
464 : : int i;
465 : 0 : const ProtobufCMessageDescriptor *md = ctl->arg;
466 : :
467 [ # # ]: 0 : BUG_ON(md == NULL);
468 : :
469 [ # # ]: 0 : for (i = 0; i < md->n_fields; i++) {
470 : 0 : const ProtobufCFieldDescriptor fd = md->fields[i];
471 : : unsigned long *data;
472 : : size_t nr_fields;
473 : :
474 : 0 : nr_fields = 1;
475 : 0 : data = (unsigned long *)(msg + fd.offset);
476 : :
477 [ # # ]: 0 : if (fd.label == PROTOBUF_C_LABEL_OPTIONAL) {
478 [ # # ]: 0 : if (!pb_optional_field_present(&fd, msg))
479 : 0 : continue;
480 : : }
481 : :
482 [ # # ]: 0 : if (fd.label == PROTOBUF_C_LABEL_REPEATED) {
483 : 0 : nr_fields = *(size_t *)(msg + fd.quantifier_offset);
484 : 0 : data = (unsigned long *)*data;
485 : : }
486 : :
487 : 0 : ctl->cur.data = data;
488 : 0 : ctl->cur.number = i + 1;
489 : :
490 : 0 : pb_show_field(&fd, nr_fields, ctl);
491 : : }
492 : 0 : }
493 : :
494 : 0 : static inline void pb_no_payload(int fd, void *obj, int flags) { }
495 : :
496 : 0 : void do_pb_show_plain(int fd, int type, int single_entry,
497 : : void (*payload_hadler)(int fd, void *obj, int flags),
498 : : int flags, const char *pretty_fmt)
499 : : {
500 : 0 : pb_pr_ctl_t ctl = {NULL, single_entry, pretty_fmt};
501 : : void (*handle_payload)(int fd, void *obj, int flags);
502 : :
503 [ # # ]: 0 : if (!cr_pb_descs[type].pb_desc) {
504 : 0 : pr_err("Wrong object requested %d\n", type);
505 : 0 : return;
506 : : }
507 : :
508 [ # # ]: 0 : handle_payload = (payload_hadler) ? : pb_no_payload;
509 : :
510 : : while (1) {
511 : : void *obj;
512 : :
513 [ # # ]: 0 : if (pb_read_one_eof(fd, &obj, type) <= 0)
514 : : break;
515 : :
516 : 0 : ctl.arg = (void *)cr_pb_descs[type].pb_desc;
517 : 0 : pb_show_msg(obj, &ctl);
518 : 0 : handle_payload(fd, obj, flags);
519 : 0 : cr_pb_descs[type].free(obj, NULL);
520 [ # # ]: 0 : if (single_entry)
521 : : break;
522 : 0 : pr_msg("\n");
523 : 0 : }
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 : 98619 : int do_pb_read_one(int fd, void **pobj, int type, bool eof)
538 : : {
539 : : u8 local[PB_PKOBJ_LOCAL_SIZE];
540 : 98619 : void *buf = (void *)&local;
541 : : u32 size;
542 : : int ret;
543 : :
544 [ - + ]: 98619 : if (!cr_pb_descs[type].pb_desc) {
545 : 0 : pr_err("Wrong object requested %d\n", type);
546 : : return -1;
547 : : }
548 : :
549 : 98619 : *pobj = NULL;
550 : :
551 : 98619 : ret = read(fd, &size, sizeof(size));
552 [ + + ]: 98619 : if (ret == 0) {
553 [ - + ]: 11230 : if (eof) {
554 : : return 0;
555 : : } else {
556 : 0 : pr_err("Unexpected EOF\n");
557 : : return -1;
558 : : }
559 [ - + ]: 87389 : } else if (ret < sizeof(size)) {
560 : 0 : pr_perror("Read %d bytes while %d expected",
561 : : ret, (int)sizeof(size));
562 : : return -1;
563 : : }
564 : :
565 [ - + ]: 87389 : if (size > sizeof(local)) {
566 : 0 : ret = -1;
567 [ # # ]: 0 : buf = xmalloc(size);
568 [ # # ]: 0 : if (!buf)
569 : : goto err;
570 : : }
571 : :
572 : 87389 : ret = read(fd, buf, size);
573 [ - + ]: 87389 : if (ret < 0) {
574 : 0 : pr_perror("Can't read %d bytes from file", size);
575 : 0 : goto err;
576 [ - + ]: 87389 : } else if (ret != size) {
577 : 0 : pr_perror("Read %d bytes while %d expected", ret, size);
578 : 0 : ret = -1;
579 : 0 : goto err;
580 : : }
581 : :
582 : 87389 : *pobj = cr_pb_descs[type].unpack(NULL, size, buf);
583 [ - + ]: 87389 : if (!*pobj) {
584 : 0 : ret = -1;
585 : 0 : pr_err("Failed unpacking object %p\n", pobj);
586 : 0 : goto err;
587 : : }
588 : :
589 : : ret = 1;
590 : : err:
591 [ - + ]: 87389 : if (buf != (void *)&local)
592 [ # # ]: 98619 : xfree(buf);
593 : :
594 : : return ret;
595 : : }
596 : :
597 : : /*
598 : : * Writes PB record (header + packed object pointed by @obj)
599 : : * to file @fd, using @getpksize to get packed size and @pack
600 : : * to implement packing
601 : : *
602 : : * 0 on success
603 : : * -1 on error
604 : : */
605 : 37929 : int pb_write_one(int fd, void *obj, int type)
606 : : {
607 : : u8 local[PB_PKOBJ_LOCAL_SIZE];
608 : 37929 : void *buf = (void *)&local;
609 : : u32 size, packed;
610 : 37929 : int ret = -1;
611 : :
612 [ - + ]: 37929 : if (!cr_pb_descs[type].pb_desc) {
613 : 0 : pr_err("Wrong object requested %d\n", type);
614 : : return -1;
615 : : }
616 : :
617 : 37929 : size = cr_pb_descs[type].getpksize(obj);
618 [ - + ]: 37929 : if (size > (u32)sizeof(local)) {
619 [ # # ]: 0 : buf = xmalloc(size);
620 [ # # ]: 0 : if (!buf)
621 : : goto err;
622 : : }
623 : :
624 : 37929 : packed = cr_pb_descs[type].pack(obj, buf);
625 [ - + ]: 37929 : if (packed != size) {
626 : 0 : pr_err("Failed packing PB object %p\n", obj);
627 : 0 : goto err;
628 : : }
629 : :
630 : 37929 : ret = write(fd, &size, sizeof(size));
631 [ - + ]: 37929 : if (ret != sizeof(size)) {
632 : 0 : ret = -1;
633 : 0 : pr_perror("Can't write %d bytes", (int)sizeof(size));
634 : 0 : goto err;
635 : : }
636 : :
637 : 37929 : ret = write(fd, buf, size);
638 [ - + ]: 37929 : if (ret != size) {
639 : 0 : ret = -1;
640 : 0 : pr_perror("Can't write %d bytes", size);
641 : 0 : goto err;
642 : : }
643 : :
644 : : ret = 0;
645 : : err:
646 [ - + ]: 37929 : if (buf != (void *)&local)
647 [ # # ]: 37929 : xfree(buf);
648 : : return ret;
649 : : }
650 : :
651 : 4995 : static int __collect_image(int fd_t, int obj_t, unsigned size,
652 : : int (*collect)(void *obj, ProtobufCMessage *msg),
653 : : void * (*alloc)(size_t size),
654 : : void (*free)(void *ptr))
655 : : {
656 : : int fd, ret;
657 : :
658 : 4995 : fd = open_image_ro(fd_t);
659 [ + - ]: 4995 : if (fd < 0)
660 : : return -1;
661 : :
662 : : while (1) {
663 : : void *obj;
664 : : ProtobufCMessage *msg;
665 : :
666 [ + - ]: 24777 : if (size) {
667 : 24777 : ret = -1;
668 : 24777 : obj = alloc(size);
669 [ + - ]: 24777 : if (!obj)
670 : : break;
671 : : } else
672 : : obj = NULL;
673 : :
674 : 24777 : ret = pb_read_one_eof(fd, &msg, obj_t);
675 [ + + ]: 24777 : if (ret <= 0) {
676 : 4995 : free(obj);
677 : : break;
678 : : }
679 : :
680 : 19782 : ret = collect(obj, msg);
681 [ - + ]: 19782 : if (ret < 0) {
682 : 0 : free(obj);
683 : 0 : cr_pb_descs[obj_t].free(msg, NULL);
684 : : break;
685 : : }
686 : 19782 : }
687 : :
688 : 4995 : close(fd);
689 : 4995 : return ret;
690 : : }
691 : :
692 : 4640 : int collect_image(int fd_t, int obj_t, unsigned size,
693 : : int (*collect)(void *obj, ProtobufCMessage *msg))
694 : : {
695 : 4640 : return __collect_image(fd_t, obj_t, size, collect, malloc, free);
696 : : }
697 : :
698 : 355 : int collect_image_sh(int fd_t, int obj_t, unsigned size,
699 : : int (*collect)(void *obj, ProtobufCMessage *msg))
700 : : {
701 : 355 : return __collect_image(fd_t, obj_t, size, collect, shmalloc, shfree_last);
702 : 0 : }
|