]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd/sd-bus/bus-dump.c
050eec3a7cd07322b30ac6971c2ac811cc8e609b
[thirdparty/systemd.git] / src / libsystemd / sd-bus / bus-dump.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include <sys/time.h>
4
5 #include "alloc-util.h"
6 #include "bus-dump.h"
7 #include "bus-internal.h"
8 #include "bus-message.h"
9 #include "bus-type.h"
10 #include "cap-list.h"
11 #include "capability-util.h"
12 #include "fileio.h"
13 #include "format-util.h"
14 #include "glyph-util.h"
15 #include "macro.h"
16 #include "pcapng.h"
17 #include "string-util.h"
18 #include "strv.h"
19 #include "terminal-util.h"
20 #include "util.h"
21
22 static char *indent(unsigned level, uint64_t flags) {
23 char *p;
24 unsigned n, i = 0;
25
26 n = 0;
27
28 if (flags & SD_BUS_MESSAGE_DUMP_SUBTREE_ONLY && level > 0)
29 level -= 1;
30
31 if (flags & SD_BUS_MESSAGE_DUMP_WITH_HEADER)
32 n += 2;
33
34 p = new(char, n + level*8 + 1);
35 if (!p)
36 return NULL;
37
38 if (flags & SD_BUS_MESSAGE_DUMP_WITH_HEADER) {
39 p[i++] = ' ';
40 p[i++] = ' ';
41 }
42
43 memset(p + i, ' ', level*8);
44 p[i + level*8] = 0;
45
46 return p;
47 }
48
49 _public_ int sd_bus_message_dump(sd_bus_message *m, FILE *f, uint64_t flags) {
50 unsigned level = 1;
51 int r;
52
53 assert(m);
54
55 if (!f)
56 f = stdout;
57
58 if (flags & SD_BUS_MESSAGE_DUMP_WITH_HEADER) {
59 usec_t ts = m->realtime;
60
61 if (ts == 0)
62 ts = now(CLOCK_REALTIME);
63
64 fprintf(f,
65 "%s%s%s Type=%s%s%s Endian=%c Flags=%u Version=%u",
66 m->header->type == SD_BUS_MESSAGE_METHOD_ERROR ? ansi_highlight_red() :
67 m->header->type == SD_BUS_MESSAGE_METHOD_RETURN ? ansi_highlight_green() :
68 m->header->type != SD_BUS_MESSAGE_SIGNAL ? ansi_highlight() : "",
69 special_glyph(SPECIAL_GLYPH_TRIANGULAR_BULLET),
70 ansi_normal(),
71
72 ansi_highlight(),
73 bus_message_type_to_string(m->header->type) ?: "(unknown)",
74 ansi_normal(),
75
76 m->header->endian,
77 m->header->flags,
78 m->header->version);
79
80 /* Display synthetic message serial number in a more readable
81 * format than UINT32_MAX */
82 if (BUS_MESSAGE_COOKIE(m) == 0xFFFFFFFFULL)
83 fprintf(f, " Cookie=-1");
84 else
85 fprintf(f, " Cookie=%" PRIu64, BUS_MESSAGE_COOKIE(m));
86
87 if (m->reply_cookie != 0)
88 fprintf(f, " ReplyCookie=%" PRIu64, m->reply_cookie);
89
90 fprintf(f, " Timestamp=\"%s\"\n", strna(FORMAT_TIMESTAMP_STYLE(ts, TIMESTAMP_US_UTC)));
91
92 if (m->sender)
93 fprintf(f, " Sender=%s%s%s", ansi_highlight(), m->sender, ansi_normal());
94 if (m->destination)
95 fprintf(f, " Destination=%s%s%s", ansi_highlight(), m->destination, ansi_normal());
96 if (m->path)
97 fprintf(f, " Path=%s%s%s", ansi_highlight(), m->path, ansi_normal());
98 if (m->interface)
99 fprintf(f, " Interface=%s%s%s", ansi_highlight(), m->interface, ansi_normal());
100 if (m->member)
101 fprintf(f, " Member=%s%s%s", ansi_highlight(), m->member, ansi_normal());
102
103 if (m->sender || m->destination || m->path || m->interface || m->member)
104 fputs("\n", f);
105
106 if (sd_bus_error_is_set(&m->error))
107 fprintf(f,
108 " ErrorName=%s%s%s"
109 " ErrorMessage=%s\"%s\"%s\n",
110 ansi_highlight_red(), strna(m->error.name), ansi_normal(),
111 ansi_highlight_red(), strna(m->error.message), ansi_normal());
112
113 if (m->monotonic != 0)
114 fprintf(f, " Monotonic="USEC_FMT, m->monotonic);
115 if (m->realtime != 0)
116 fprintf(f, " Realtime="USEC_FMT, m->realtime);
117 if (m->seqnum != 0)
118 fprintf(f, " SequenceNumber=%"PRIu64, m->seqnum);
119
120 if (m->monotonic != 0 || m->realtime != 0 || m->seqnum != 0)
121 fputs("\n", f);
122
123 bus_creds_dump(&m->creds, f, true);
124 }
125
126 r = sd_bus_message_rewind(m, !(flags & SD_BUS_MESSAGE_DUMP_SUBTREE_ONLY));
127 if (r < 0)
128 return log_error_errno(r, "Failed to rewind: %m");
129
130 if (!(flags & SD_BUS_MESSAGE_DUMP_SUBTREE_ONLY)) {
131 _cleanup_free_ char *prefix = NULL;
132
133 prefix = indent(0, flags);
134 if (!prefix)
135 return log_oom();
136
137 fprintf(f, "%sMESSAGE \"%s\" {\n", prefix, strempty(m->root_container.signature));
138 }
139
140 for (;;) {
141 _cleanup_free_ char *prefix = NULL;
142 const char *contents = NULL;
143 char type;
144 union {
145 uint8_t u8;
146 uint16_t u16;
147 int16_t s16;
148 uint32_t u32;
149 int32_t s32;
150 uint64_t u64;
151 int64_t s64;
152 double d64;
153 const char *string;
154 int i;
155 } basic;
156
157 r = sd_bus_message_peek_type(m, &type, &contents);
158 if (r < 0)
159 return log_error_errno(r, "Failed to peek type: %m");
160
161 if (r == 0) {
162 if (level <= 1)
163 break;
164
165 r = sd_bus_message_exit_container(m);
166 if (r < 0)
167 return log_error_errno(r, "Failed to exit container: %m");
168
169 level--;
170
171 prefix = indent(level, flags);
172 if (!prefix)
173 return log_oom();
174
175 fprintf(f, "%s};\n", prefix);
176 continue;
177 }
178
179 prefix = indent(level, flags);
180 if (!prefix)
181 return log_oom();
182
183 if (bus_type_is_container(type) > 0) {
184 r = sd_bus_message_enter_container(m, type, contents);
185 if (r < 0)
186 return log_error_errno(r, "Failed to enter container: %m");
187
188 if (type == SD_BUS_TYPE_ARRAY)
189 fprintf(f, "%sARRAY \"%s\" {\n", prefix, contents);
190 else if (type == SD_BUS_TYPE_VARIANT)
191 fprintf(f, "%sVARIANT \"%s\" {\n", prefix, contents);
192 else if (type == SD_BUS_TYPE_STRUCT)
193 fprintf(f, "%sSTRUCT \"%s\" {\n", prefix, contents);
194 else if (type == SD_BUS_TYPE_DICT_ENTRY)
195 fprintf(f, "%sDICT_ENTRY \"%s\" {\n", prefix, contents);
196
197 level++;
198
199 continue;
200 }
201
202 r = sd_bus_message_read_basic(m, type, &basic);
203 if (r < 0)
204 return log_error_errno(r, "Failed to get basic: %m");
205
206 assert(r > 0);
207
208 switch (type) {
209
210 case SD_BUS_TYPE_BYTE:
211 fprintf(f, "%sBYTE %s%u%s;\n", prefix, ansi_highlight(), basic.u8, ansi_normal());
212 break;
213
214 case SD_BUS_TYPE_BOOLEAN:
215 fprintf(f, "%sBOOLEAN %s%s%s;\n", prefix, ansi_highlight(), true_false(basic.i), ansi_normal());
216 break;
217
218 case SD_BUS_TYPE_INT16:
219 fprintf(f, "%sINT16 %s%i%s;\n", prefix, ansi_highlight(), basic.s16, ansi_normal());
220 break;
221
222 case SD_BUS_TYPE_UINT16:
223 fprintf(f, "%sUINT16 %s%u%s;\n", prefix, ansi_highlight(), basic.u16, ansi_normal());
224 break;
225
226 case SD_BUS_TYPE_INT32:
227 fprintf(f, "%sINT32 %s%i%s;\n", prefix, ansi_highlight(), basic.s32, ansi_normal());
228 break;
229
230 case SD_BUS_TYPE_UINT32:
231 fprintf(f, "%sUINT32 %s%u%s;\n", prefix, ansi_highlight(), basic.u32, ansi_normal());
232 break;
233
234 case SD_BUS_TYPE_INT64:
235 fprintf(f, "%sINT64 %s%"PRIi64"%s;\n", prefix, ansi_highlight(), basic.s64, ansi_normal());
236 break;
237
238 case SD_BUS_TYPE_UINT64:
239 fprintf(f, "%sUINT64 %s%"PRIu64"%s;\n", prefix, ansi_highlight(), basic.u64, ansi_normal());
240 break;
241
242 case SD_BUS_TYPE_DOUBLE:
243 fprintf(f, "%sDOUBLE %s%g%s;\n", prefix, ansi_highlight(), basic.d64, ansi_normal());
244 break;
245
246 case SD_BUS_TYPE_STRING:
247 fprintf(f, "%sSTRING \"%s%s%s\";\n", prefix, ansi_highlight(), basic.string, ansi_normal());
248 break;
249
250 case SD_BUS_TYPE_OBJECT_PATH:
251 fprintf(f, "%sOBJECT_PATH \"%s%s%s\";\n", prefix, ansi_highlight(), basic.string, ansi_normal());
252 break;
253
254 case SD_BUS_TYPE_SIGNATURE:
255 fprintf(f, "%sSIGNATURE \"%s%s%s\";\n", prefix, ansi_highlight(), basic.string, ansi_normal());
256 break;
257
258 case SD_BUS_TYPE_UNIX_FD:
259 fprintf(f, "%sUNIX_FD %s%i%s;\n", prefix, ansi_highlight(), basic.i, ansi_normal());
260 break;
261
262 default:
263 assert_not_reached();
264 }
265 }
266
267 if (!(flags & SD_BUS_MESSAGE_DUMP_SUBTREE_ONLY)) {
268 _cleanup_free_ char *prefix = NULL;
269
270 prefix = indent(0, flags);
271 if (!prefix)
272 return log_oom();
273
274 fprintf(f, "%s};\n\n", prefix);
275 }
276
277 return 0;
278 }
279
280 static void dump_capabilities(
281 sd_bus_creds *c,
282 FILE *f,
283 const char *name,
284 bool terse,
285 int (*has)(sd_bus_creds *c, int capability)) {
286
287 unsigned long i, last_cap;
288 unsigned n = 0;
289 int r;
290
291 assert(c);
292 assert(f);
293 assert(name);
294 assert(has);
295
296 i = 0;
297 r = has(c, i);
298 if (r < 0)
299 return;
300
301 fprintf(f, "%s%s=%s", terse ? " " : "", name, terse ? "" : ansi_highlight());
302 last_cap = cap_last_cap();
303
304 for (;;) {
305 if (r > 0) {
306
307 if (n > 0)
308 fputc(' ', f);
309 if (n % 4 == 3)
310 fprintf(f, terse ? "\n " : "\n ");
311
312 fprintf(f, "%s", strna(capability_to_name(i)));
313 n++;
314 }
315
316 i++;
317
318 if (i > last_cap)
319 break;
320
321 r = has(c, i);
322 }
323
324 fputs("\n", f);
325
326 if (!terse)
327 fputs(ansi_normal(), f);
328 }
329
330 int bus_creds_dump(sd_bus_creds *c, FILE *f, bool terse) {
331 uid_t owner, audit_loginuid;
332 uint32_t audit_sessionid;
333 char **cmdline = NULL, **well_known = NULL;
334 const char *prefix, *color, *suffix, *s;
335 int r, q, v, w, z;
336
337 assert(c);
338
339 if (!f)
340 f = stdout;
341
342 if (terse) {
343 prefix = " ";
344 suffix = "";
345 color = "";
346 } else {
347 const char *off;
348
349 prefix = "";
350 color = ansi_highlight();
351
352 off = ansi_normal();
353 suffix = strjoina(off, "\n");
354 }
355
356 if (c->mask & SD_BUS_CREDS_PID)
357 fprintf(f, "%sPID=%s"PID_FMT"%s", prefix, color, c->pid, suffix);
358 if (c->mask & SD_BUS_CREDS_TID)
359 fprintf(f, "%sTID=%s"PID_FMT"%s", prefix, color, c->tid, suffix);
360 if (c->mask & SD_BUS_CREDS_PPID) {
361 if (c->ppid == 0)
362 fprintf(f, "%sPPID=%sn/a%s", prefix, color, suffix);
363 else
364 fprintf(f, "%sPPID=%s"PID_FMT"%s", prefix, color, c->ppid, suffix);
365 }
366 if (c->mask & SD_BUS_CREDS_TTY)
367 fprintf(f, "%sTTY=%s%s%s", prefix, color, strna(c->tty), suffix);
368
369 if (terse && ((c->mask & (SD_BUS_CREDS_PID|SD_BUS_CREDS_TID|SD_BUS_CREDS_PPID|SD_BUS_CREDS_TTY))))
370 fputs("\n", f);
371
372 if (c->mask & SD_BUS_CREDS_UID)
373 fprintf(f, "%sUID=%s"UID_FMT"%s", prefix, color, c->uid, suffix);
374 if (c->mask & SD_BUS_CREDS_EUID)
375 fprintf(f, "%sEUID=%s"UID_FMT"%s", prefix, color, c->euid, suffix);
376 if (c->mask & SD_BUS_CREDS_SUID)
377 fprintf(f, "%sSUID=%s"UID_FMT"%s", prefix, color, c->suid, suffix);
378 if (c->mask & SD_BUS_CREDS_FSUID)
379 fprintf(f, "%sFSUID=%s"UID_FMT"%s", prefix, color, c->fsuid, suffix);
380 r = sd_bus_creds_get_owner_uid(c, &owner);
381 if (r >= 0)
382 fprintf(f, "%sOwnerUID=%s"UID_FMT"%s", prefix, color, owner, suffix);
383 if (c->mask & SD_BUS_CREDS_GID)
384 fprintf(f, "%sGID=%s"GID_FMT"%s", prefix, color, c->gid, suffix);
385 if (c->mask & SD_BUS_CREDS_EGID)
386 fprintf(f, "%sEGID=%s"GID_FMT"%s", prefix, color, c->egid, suffix);
387 if (c->mask & SD_BUS_CREDS_SGID)
388 fprintf(f, "%sSGID=%s"GID_FMT"%s", prefix, color, c->sgid, suffix);
389 if (c->mask & SD_BUS_CREDS_FSGID)
390 fprintf(f, "%sFSGID=%s"GID_FMT"%s", prefix, color, c->fsgid, suffix);
391
392 if (c->mask & SD_BUS_CREDS_SUPPLEMENTARY_GIDS) {
393 fprintf(f, "%sSupplementaryGIDs=%s", prefix, color);
394 for (unsigned i = 0; i < c->n_supplementary_gids; i++)
395 fprintf(f, "%s" GID_FMT, i > 0 ? " " : "", c->supplementary_gids[i]);
396 fprintf(f, "%s", suffix);
397 }
398
399 if (terse && ((c->mask & (SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID|
400 SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID|
401 SD_BUS_CREDS_SUPPLEMENTARY_GIDS)) || r >= 0))
402 fputs("\n", f);
403
404 if (c->mask & SD_BUS_CREDS_COMM)
405 fprintf(f, "%sComm=%s%s%s", prefix, color, c->comm, suffix);
406 if (c->mask & SD_BUS_CREDS_TID_COMM)
407 fprintf(f, "%sTIDComm=%s%s%s", prefix, color, c->tid_comm, suffix);
408 if (c->mask & SD_BUS_CREDS_EXE)
409 fprintf(f, "%sExe=%s%s%s", prefix, color, strna(c->exe), suffix);
410
411 if (terse && (c->mask & (SD_BUS_CREDS_EXE|SD_BUS_CREDS_COMM|SD_BUS_CREDS_TID_COMM)))
412 fputs("\n", f);
413
414 r = sd_bus_creds_get_cmdline(c, &cmdline);
415 if (r >= 0) {
416 fprintf(f, "%sCommandLine=%s", prefix, color);
417 STRV_FOREACH(i, cmdline) {
418 if (i != cmdline)
419 fputc(' ', f);
420
421 fputs(*i, f);
422 }
423
424 fprintf(f, "%s", suffix);
425 } else if (r != -ENODATA)
426 fprintf(f, "%sCommandLine=%sn/a%s", prefix, color, suffix);
427
428 if (c->mask & SD_BUS_CREDS_SELINUX_CONTEXT)
429 fprintf(f, "%sLabel=%s%s%s", prefix, color, c->label, suffix);
430 if (c->mask & SD_BUS_CREDS_DESCRIPTION)
431 fprintf(f, "%sDescription=%s%s%s", prefix, color, c->description, suffix);
432
433 if (terse && (c->mask & (SD_BUS_CREDS_SELINUX_CONTEXT|SD_BUS_CREDS_DESCRIPTION)))
434 fputs("\n", f);
435
436 if (c->mask & SD_BUS_CREDS_CGROUP)
437 fprintf(f, "%sCGroup=%s%s%s", prefix, color, c->cgroup, suffix);
438 s = NULL;
439 r = sd_bus_creds_get_unit(c, &s);
440 if (r != -ENODATA)
441 fprintf(f, "%sUnit=%s%s%s", prefix, color, strna(s), suffix);
442 s = NULL;
443 v = sd_bus_creds_get_slice(c, &s);
444 if (v != -ENODATA)
445 fprintf(f, "%sSlice=%s%s%s", prefix, color, strna(s), suffix);
446 s = NULL;
447 q = sd_bus_creds_get_user_unit(c, &s);
448 if (q != -ENODATA)
449 fprintf(f, "%sUserUnit=%s%s%s", prefix, color, strna(s), suffix);
450 s = NULL;
451 w = sd_bus_creds_get_user_slice(c, &s);
452 if (w != -ENODATA)
453 fprintf(f, "%sUserSlice=%s%s%s", prefix, color, strna(s), suffix);
454 s = NULL;
455 z = sd_bus_creds_get_session(c, &s);
456 if (z != -ENODATA)
457 fprintf(f, "%sSession=%s%s%s", prefix, color, strna(s), suffix);
458
459 if (terse && ((c->mask & SD_BUS_CREDS_CGROUP) || r != -ENODATA || q != -ENODATA || v != -ENODATA || w != -ENODATA || z != -ENODATA))
460 fputs("\n", f);
461
462 r = sd_bus_creds_get_audit_login_uid(c, &audit_loginuid);
463 if (r >= 0)
464 fprintf(f, "%sAuditLoginUID=%s"UID_FMT"%s", prefix, color, audit_loginuid, suffix);
465 else if (r != -ENODATA)
466 fprintf(f, "%sAuditLoginUID=%sn/a%s", prefix, color, suffix);
467 q = sd_bus_creds_get_audit_session_id(c, &audit_sessionid);
468 if (q >= 0)
469 fprintf(f, "%sAuditSessionID=%s%"PRIu32"%s", prefix, color, audit_sessionid, suffix);
470 else if (q != -ENODATA)
471 fprintf(f, "%sAuditSessionID=%sn/a%s", prefix, color, suffix);
472
473 if (terse && (r != -ENODATA || q != -ENODATA))
474 fputs("\n", f);
475
476 if (c->mask & SD_BUS_CREDS_UNIQUE_NAME)
477 fprintf(f, "%sUniqueName=%s%s%s", prefix, color, c->unique_name, suffix);
478
479 if (sd_bus_creds_get_well_known_names(c, &well_known) >= 0) {
480 fprintf(f, "%sWellKnownNames=%s", prefix, color);
481 STRV_FOREACH(i, well_known) {
482 if (i != well_known)
483 fputc(' ', f);
484
485 fputs(*i, f);
486 }
487
488 fprintf(f, "%s", suffix);
489 }
490
491 if (terse && (c->mask & SD_BUS_CREDS_UNIQUE_NAME || well_known))
492 fputc('\n', f);
493
494 dump_capabilities(c, f, "EffectiveCapabilities", terse, sd_bus_creds_has_effective_cap);
495 dump_capabilities(c, f, "PermittedCapabilities", terse, sd_bus_creds_has_permitted_cap);
496 dump_capabilities(c, f, "InheritableCapabilities", terse, sd_bus_creds_has_inheritable_cap);
497 dump_capabilities(c, f, "BoundingCapabilities", terse, sd_bus_creds_has_bounding_cap);
498
499 return 0;
500 }
501
502 static uint16_t pcapng_optlen(size_t len) {
503 return ALIGN4(len + sizeof(struct pcapng_option));
504 }
505
506 static void pcapng_putopt(FILE *f, uint16_t code, const void *data, size_t len) {
507 struct pcapng_option opt = {
508 .code = code,
509 .length = len,
510 };
511
512 assert(f);
513 assert((uint16_t) len == len);
514 assert(data || len == 0);
515
516 fwrite(&opt, 1, sizeof(opt), f);
517 if (len > 0) {
518 size_t pad = ALIGN4(len) - len;
519
520 fwrite(data, 1, len, f);
521
522 assert(pad < sizeof(uint32_t));
523 while (pad-- > 0)
524 fputc('\0', f);
525 }
526 }
527
528 static void pcapng_section_header(FILE *f, const char *os, const char *app) {
529 uint32_t len;
530
531 assert(f);
532
533 /* determine length of section header and options */
534 len = sizeof(struct pcapng_section);
535 if (os)
536 len += pcapng_optlen(strlen(os));
537 if (app)
538 len += pcapng_optlen(strlen(app));
539 len += pcapng_optlen(0); /* OPT_END */
540 len += sizeof(uint32_t); /* trailer length */
541
542 struct pcapng_section hdr = {
543 .block_type = PCAPNG_SECTION_BLOCK,
544 .block_length = len,
545 .byte_order_magic = PCAPNG_BYTE_ORDER_MAGIC,
546 .major_version = PCAPNG_MAJOR_VERS,
547 .minor_version = PCAPNG_MINOR_VERS,
548 .section_length = UINT64_MAX,
549 };
550
551 fwrite(&hdr, 1, sizeof(hdr), f);
552 if (os)
553 pcapng_putopt(f, PCAPNG_SHB_OS, os, strlen(os));
554 if (app)
555 pcapng_putopt(f, PCAPNG_SHB_USERAPPL, app, strlen(app));
556 pcapng_putopt(f, PCAPNG_OPT_END, NULL, 0);
557 fwrite(&len, 1, sizeof(uint32_t), f);
558 }
559
560 /* Only have a single instance of dbus pseudo interface */
561 static void pcapng_interface_header(FILE *f, size_t snaplen) {
562 uint32_t len;
563
564 assert(f);
565 assert(snaplen > 0);
566 assert((size_t) (uint32_t) snaplen == snaplen);
567
568 /* no options (yet) */
569 len = sizeof(struct pcapng_interface_block) + sizeof(uint32_t);
570 struct pcapng_interface_block hdr = {
571 .block_type = PCAPNG_INTERFACE_BLOCK,
572 .block_length = len,
573 .link_type = 231, /* D-Bus */
574 .snap_len = snaplen,
575 };
576
577 fwrite(&hdr, 1, sizeof(hdr), f);
578 fwrite(&len, 1, sizeof(uint32_t), f);
579 }
580
581 int bus_pcap_header(size_t snaplen, const char *os, const char *info, FILE *f) {
582 if (!f)
583 f = stdout;
584
585 pcapng_section_header(f, os, info);
586 pcapng_interface_header(f, snaplen);
587 return fflush_and_check(f);
588 }
589
590 int bus_message_pcap_frame(sd_bus_message *m, size_t snaplen, FILE *f) {
591 struct bus_body_part *part;
592 size_t msglen, caplen, pad;
593 uint32_t length;
594 uint64_t ts;
595 unsigned i;
596 size_t w;
597
598 if (!f)
599 f = stdout;
600
601 assert(m);
602 assert(snaplen > 0);
603 assert((size_t) (uint32_t) snaplen == snaplen);
604
605 ts = m->realtime ?: now(CLOCK_REALTIME);
606 msglen = BUS_MESSAGE_SIZE(m);
607 caplen = MIN(msglen, snaplen);
608 pad = ALIGN4(caplen) - caplen;
609
610 /* packet block has no options */
611 length = sizeof(struct pcapng_enhance_packet_block)
612 + caplen + pad + sizeof(uint32_t);
613
614 struct pcapng_enhance_packet_block epb = {
615 .block_type = PCAPNG_ENHANCED_PACKET_BLOCK,
616 .block_length = length,
617 .interface_id = 0,
618 .timestamp_hi = (uint32_t)(ts >> 32),
619 .timestamp_lo = (uint32_t)ts,
620 .original_length = msglen,
621 .capture_length = caplen,
622 };
623
624 /* write the pcapng enhanced packet block header */
625 fwrite(&epb, 1, sizeof(epb), f);
626
627 /* write the dbus header */
628 w = MIN(BUS_MESSAGE_BODY_BEGIN(m), snaplen);
629 fwrite(m->header, 1, w, f);
630 snaplen -= w;
631
632 /* write the dbus body */
633 MESSAGE_FOREACH_PART(part, i, m) {
634 if (snaplen <= 0)
635 break;
636
637 w = MIN(part->size, snaplen);
638 fwrite(part->data, 1, w, f);
639 snaplen -= w;
640 }
641
642 while (pad-- > 0)
643 fputc('\0', f);
644
645 /* trailing block length */
646 fwrite(&length, 1, sizeof(uint32_t), f);
647
648 return fflush_and_check(f);
649 }