chiark / gitweb /
9db86adb7f4320ca8d62ad4c6aa9060af5f68f05
[elogind.git] / src / libelogind / sd-bus / bus-dump.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2013 Lennart Poettering
7
8   systemd is free software; you can redistribute it and/or modify it
9   under the terms of the GNU Lesser General Public License as published by
10   the Free Software Foundation; either version 2.1 of the License, or
11   (at your option) any later version.
12
13   systemd is distributed in the hope that it will be useful, but
14   WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16   Lesser General Public License for more details.
17
18   You should have received a copy of the GNU Lesser General Public License
19   along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include "util.h"
23 #include "capability.h"
24 #include "strv.h"
25 #include "macro.h"
26 #include "cap-list.h"
27 #include "formats-util.h"
28 #include "terminal-util.h"
29
30 #include "bus-message.h"
31 #include "bus-internal.h"
32 #include "bus-type.h"
33 #include "bus-dump.h"
34
35 static char *indent(unsigned level, unsigned flags) {
36         char *p;
37         unsigned n, i = 0;
38
39         n = 0;
40
41         if (flags & BUS_MESSAGE_DUMP_SUBTREE_ONLY && level > 0)
42                 level -= 1;
43
44         if (flags & BUS_MESSAGE_DUMP_WITH_HEADER)
45                 n += 2;
46
47         p = new(char, n + level*8 + 1);
48         if (!p)
49                 return NULL;
50
51         if (flags & BUS_MESSAGE_DUMP_WITH_HEADER) {
52                 p[i++] = ' ';
53                 p[i++] = ' ';
54         }
55
56         memset(p + i, ' ', level*8);
57         p[i + level*8] = 0;
58
59         return p;
60 }
61
62 int bus_message_dump(sd_bus_message *m, FILE *f, unsigned flags) {
63         unsigned level = 1;
64         int r;
65
66         assert(m);
67
68         if (!f)
69                 f = stdout;
70
71         if (flags & BUS_MESSAGE_DUMP_WITH_HEADER) {
72                 fprintf(f,
73                         "%s%s%s Type=%s%s%s  Endian=%c  Flags=%u  Version=%u  Priority=%"PRIi64,
74                         m->header->type == SD_BUS_MESSAGE_METHOD_ERROR ? ansi_highlight_red() :
75                         m->header->type == SD_BUS_MESSAGE_METHOD_RETURN ? ansi_highlight_green() :
76                         m->header->type != SD_BUS_MESSAGE_SIGNAL ? ansi_highlight() : "", draw_special_char(DRAW_TRIANGULAR_BULLET), ansi_highlight_off(),
77                         ansi_highlight(), bus_message_type_to_string(m->header->type), ansi_highlight_off(),
78                         m->header->endian,
79                         m->header->flags,
80                         m->header->version,
81                         m->priority);
82
83                 /* Display synthetic message serial number in a more readable
84                  * format than (uint32_t) -1 */
85                 if (BUS_MESSAGE_COOKIE(m) == 0xFFFFFFFFULL)
86                         fprintf(f, " Cookie=-1");
87                 else
88                         fprintf(f, " Cookie=%" PRIu64, BUS_MESSAGE_COOKIE(m));
89
90                 if (m->reply_cookie != 0)
91                         fprintf(f, "  ReplyCookie=%" PRIu64, m->reply_cookie);
92
93                 fputs("\n", f);
94
95                 if (m->sender)
96                         fprintf(f, "  Sender=%s%s%s", ansi_highlight(), m->sender, ansi_highlight_off());
97                 if (m->destination)
98                         fprintf(f, "  Destination=%s%s%s", ansi_highlight(), m->destination, ansi_highlight_off());
99                 if (m->path)
100                         fprintf(f, "  Path=%s%s%s", ansi_highlight(), m->path, ansi_highlight_off());
101                 if (m->interface)
102                         fprintf(f, "  Interface=%s%s%s", ansi_highlight(), m->interface, ansi_highlight_off());
103                 if (m->member)
104                         fprintf(f, "  Member=%s%s%s", ansi_highlight(), m->member, ansi_highlight_off());
105
106                 if (m->sender || m->destination || m->path || m->interface || m->member)
107                         fputs("\n", f);
108
109                 if (sd_bus_error_is_set(&m->error))
110                         fprintf(f,
111                                 "  ErrorName=%s%s%s"
112                                 "  ErrorMessage=%s\"%s\"%s\n",
113                                 ansi_highlight_red(), strna(m->error.name), ansi_highlight_off(),
114                                 ansi_highlight_red(), strna(m->error.message), ansi_highlight_off());
115
116                 if (m->monotonic != 0)
117                         fprintf(f, "  Monotonic="USEC_FMT, m->monotonic);
118                 if (m->realtime != 0)
119                         fprintf(f, "  Realtime="USEC_FMT, m->realtime);
120                 if (m->seqnum != 0)
121                         fprintf(f, "  SequenceNumber=%"PRIu64, m->seqnum);
122
123                 if (m->monotonic != 0 || m->realtime != 0 || m->seqnum != 0)
124                         fputs("\n", f);
125
126                 bus_creds_dump(&m->creds, f, true);
127         }
128
129         r = sd_bus_message_rewind(m, !(flags & BUS_MESSAGE_DUMP_SUBTREE_ONLY));
130         if (r < 0)
131                 return log_error_errno(r, "Failed to rewind: %m");
132
133         if (!(flags & BUS_MESSAGE_DUMP_SUBTREE_ONLY)) {
134                 _cleanup_free_ char *prefix = NULL;
135
136                 prefix = indent(0, flags);
137                 if (!prefix)
138                         return log_oom();
139
140                 fprintf(f, "%sMESSAGE \"%s\" {\n", prefix, strempty(m->root_container.signature));
141         }
142
143         for (;;) {
144                 _cleanup_free_ char *prefix = NULL;
145                 const char *contents = NULL;
146                 char type;
147                 union {
148                         uint8_t u8;
149                         uint16_t u16;
150                         int16_t s16;
151                         uint32_t u32;
152                         int32_t s32;
153                         uint64_t u64;
154                         int64_t s64;
155                         double d64;
156                         const char *string;
157                         int i;
158                 } basic;
159
160                 r = sd_bus_message_peek_type(m, &type, &contents);
161                 if (r < 0)
162                         return log_error_errno(r, "Failed to peek type: %m");
163
164                 if (r == 0) {
165                         if (level <= 1)
166                                 break;
167
168                         r = sd_bus_message_exit_container(m);
169                         if (r < 0)
170                                 return log_error_errno(r, "Failed to exit container: %m");
171
172                         level--;
173
174                         prefix = indent(level, flags);
175                         if (!prefix)
176                                 return log_oom();
177
178                         fprintf(f, "%s};\n", prefix);
179                         continue;
180                 }
181
182                 prefix = indent(level, flags);
183                 if (!prefix)
184                         return log_oom();
185
186                 if (bus_type_is_container(type) > 0) {
187                         r = sd_bus_message_enter_container(m, type, contents);
188                         if (r < 0)
189                                 return log_error_errno(r, "Failed to enter container: %m");
190
191                         if (type == SD_BUS_TYPE_ARRAY)
192                                 fprintf(f, "%sARRAY \"%s\" {\n", prefix, contents);
193                         else if (type == SD_BUS_TYPE_VARIANT)
194                                 fprintf(f, "%sVARIANT \"%s\" {\n", prefix, contents);
195                         else if (type == SD_BUS_TYPE_STRUCT)
196                                 fprintf(f, "%sSTRUCT \"%s\" {\n", prefix, contents);
197                         else if (type == SD_BUS_TYPE_DICT_ENTRY)
198                                 fprintf(f, "%sDICT_ENTRY \"%s\" {\n", prefix, contents);
199
200                         level ++;
201
202                         continue;
203                 }
204
205                 r = sd_bus_message_read_basic(m, type, &basic);
206                 if (r < 0)
207                         return log_error_errno(r, "Failed to get basic: %m");
208
209                 assert(r > 0);
210
211                 switch (type) {
212
213                 case SD_BUS_TYPE_BYTE:
214                         fprintf(f, "%sBYTE %s%u%s;\n", prefix, ansi_highlight(), basic.u8, ansi_highlight_off());
215                         break;
216
217                 case SD_BUS_TYPE_BOOLEAN:
218                         fprintf(f, "%sBOOLEAN %s%s%s;\n", prefix, ansi_highlight(), true_false(basic.i), ansi_highlight_off());
219                         break;
220
221                 case SD_BUS_TYPE_INT16:
222                         fprintf(f, "%sINT16 %s%i%s;\n", prefix, ansi_highlight(), basic.s16, ansi_highlight_off());
223                         break;
224
225                 case SD_BUS_TYPE_UINT16:
226                         fprintf(f, "%sUINT16 %s%u%s;\n", prefix, ansi_highlight(), basic.u16, ansi_highlight_off());
227                         break;
228
229                 case SD_BUS_TYPE_INT32:
230                         fprintf(f, "%sINT32 %s%i%s;\n", prefix, ansi_highlight(), basic.s32, ansi_highlight_off());
231                         break;
232
233                 case SD_BUS_TYPE_UINT32:
234                         fprintf(f, "%sUINT32 %s%u%s;\n", prefix, ansi_highlight(), basic.u32, ansi_highlight_off());
235                         break;
236
237                 case SD_BUS_TYPE_INT64:
238                         fprintf(f, "%sINT64 %s%"PRIi64"%s;\n", prefix, ansi_highlight(), basic.s64, ansi_highlight_off());
239                         break;
240
241                 case SD_BUS_TYPE_UINT64:
242                         fprintf(f, "%sUINT64 %s%"PRIu64"%s;\n", prefix, ansi_highlight(), basic.u64, ansi_highlight_off());
243                         break;
244
245                 case SD_BUS_TYPE_DOUBLE:
246                         fprintf(f, "%sDOUBLE %s%g%s;\n", prefix, ansi_highlight(), basic.d64, ansi_highlight_off());
247                         break;
248
249                 case SD_BUS_TYPE_STRING:
250                         fprintf(f, "%sSTRING \"%s%s%s\";\n", prefix, ansi_highlight(), basic.string, ansi_highlight_off());
251                         break;
252
253                 case SD_BUS_TYPE_OBJECT_PATH:
254                         fprintf(f, "%sOBJECT_PATH \"%s%s%s\";\n", prefix, ansi_highlight(), basic.string, ansi_highlight_off());
255                         break;
256
257                 case SD_BUS_TYPE_SIGNATURE:
258                         fprintf(f, "%sSIGNATURE \"%s%s%s\";\n", prefix, ansi_highlight(), basic.string, ansi_highlight_off());
259                         break;
260
261                 case SD_BUS_TYPE_UNIX_FD:
262                         fprintf(f, "%sUNIX_FD %s%i%s;\n", prefix, ansi_highlight(), basic.i, ansi_highlight_off());
263                         break;
264
265                 default:
266                         assert_not_reached("Unknown basic type.");
267                 }
268         }
269
270         if (!(flags & BUS_MESSAGE_DUMP_SUBTREE_ONLY)) {
271                 _cleanup_free_ char *prefix = NULL;
272
273                 prefix = indent(0, flags);
274                 if (!prefix)
275                         return log_oom();
276
277                 fprintf(f, "%s};\n\n", prefix);
278         }
279
280         return 0;
281 }
282
283 static void dump_capabilities(
284                 sd_bus_creds *c,
285                 FILE *f,
286                 const char *name,
287                 bool terse,
288                 int (*has)(sd_bus_creds *c, int capability)) {
289
290         unsigned long i, last_cap;
291         unsigned n = 0;
292         int r;
293
294         assert(c);
295         assert(f);
296         assert(name);
297         assert(has);
298
299         i = 0;
300         r = has(c, i);
301         if (r < 0)
302                 return;
303
304         fprintf(f, "%s%s=%s", terse ? "  " : "", name, terse ? "" : ansi_highlight());
305         last_cap = cap_last_cap();
306
307         for (;;) {
308                 if (r > 0) {
309
310                         if (n > 0)
311                                 fputc(' ', f);
312                         if (n % 4 == 3)
313                                 fprintf(f, terse ? "\n          " : "\n        ");
314
315                         fprintf(f, "%s", strna(capability_to_name(i)));
316                         n++;
317                 }
318
319                 i++;
320
321                 if (i > last_cap)
322                         break;
323
324                 r = has(c, i);
325         }
326
327         fputs("\n", f);
328
329         if (!terse)
330                 fputs(ansi_highlight_off(), f);
331 }
332
333 int bus_creds_dump(sd_bus_creds *c, FILE *f, bool terse) {
334         uid_t owner, audit_loginuid;
335         uint32_t audit_sessionid;
336         char **cmdline = NULL, **well_known = NULL;
337         const char *prefix, *color, *suffix, *s;
338         int r, q, v, w, z;
339
340         assert(c);
341
342         if (!f)
343                 f = stdout;
344
345         if (terse) {
346                 prefix = "  ";
347                 suffix = "";
348                 color = "";
349         } else {
350                 const char *off;
351
352                 prefix = "";
353                 color = ansi_highlight();
354
355                 off = ansi_highlight_off();
356                 suffix = strjoina(off, "\n");
357         }
358
359         if (c->mask & SD_BUS_CREDS_PID)
360                 fprintf(f, "%sPID=%s"PID_FMT"%s", prefix, color, c->pid, suffix);
361         if (c->mask & SD_BUS_CREDS_TID)
362                 fprintf(f, "%sTID=%s"PID_FMT"%s", prefix, color, c->tid, suffix);
363         if (c->mask & SD_BUS_CREDS_PPID) {
364                 if (c->ppid == 0)
365                         fprintf(f, "%sPPID=%sn/a%s", prefix, color, suffix);
366                 else
367                         fprintf(f, "%sPPID=%s"PID_FMT"%s", prefix, color, c->ppid, suffix);
368         }
369         if (c->mask & SD_BUS_CREDS_TTY)
370                 fprintf(f, "%sTTY=%s%s%s", prefix, color, strna(c->tty), suffix);
371
372         if (terse && ((c->mask & (SD_BUS_CREDS_PID|SD_BUS_CREDS_TID|SD_BUS_CREDS_PPID|SD_BUS_CREDS_TTY))))
373                 fputs("\n", f);
374
375         if (c->mask & SD_BUS_CREDS_UID)
376                 fprintf(f, "%sUID=%s"UID_FMT"%s", prefix, color, c->uid, suffix);
377         if (c->mask & SD_BUS_CREDS_EUID)
378                 fprintf(f, "%sEUID=%s"UID_FMT"%s", prefix, color, c->euid, suffix);
379         if (c->mask & SD_BUS_CREDS_SUID)
380                 fprintf(f, "%sSUID=%s"UID_FMT"%s", prefix, color, c->suid, suffix);
381         if (c->mask & SD_BUS_CREDS_FSUID)
382                 fprintf(f, "%sFSUID=%s"UID_FMT"%s", prefix, color, c->fsuid, suffix);
383         r = sd_bus_creds_get_owner_uid(c, &owner);
384         if (r >= 0)
385                 fprintf(f, "%sOwnerUID=%s"UID_FMT"%s", prefix, color, owner, suffix);
386         if (c->mask & SD_BUS_CREDS_GID)
387                 fprintf(f, "%sGID=%s"GID_FMT"%s", prefix, color, c->gid, suffix);
388         if (c->mask & SD_BUS_CREDS_EGID)
389                 fprintf(f, "%sEGID=%s"GID_FMT"%s", prefix, color, c->egid, suffix);
390         if (c->mask & SD_BUS_CREDS_SGID)
391                 fprintf(f, "%sSGID=%s"GID_FMT"%s", prefix, color, c->sgid, suffix);
392         if (c->mask & SD_BUS_CREDS_FSGID)
393                 fprintf(f, "%sFSGID=%s"GID_FMT"%s", prefix, color, c->fsgid, suffix);
394
395         if (c->mask & SD_BUS_CREDS_SUPPLEMENTARY_GIDS) {
396                 unsigned i;
397
398                 fprintf(f, "%sSupplementaryGIDs=%s", prefix, color);
399                 for (i = 0; i < c->n_supplementary_gids; i++)
400                         fprintf(f, "%s" GID_FMT, i > 0 ? " " : "", c->supplementary_gids[i]);
401                 fprintf(f, "%s", suffix);
402         }
403
404         if (terse && ((c->mask & (SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID|
405                                   SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID|
406                                   SD_BUS_CREDS_SUPPLEMENTARY_GIDS)) || r >= 0))
407                 fputs("\n", f);
408
409         if (c->mask & SD_BUS_CREDS_COMM)
410                 fprintf(f, "%sComm=%s%s%s", prefix, color, c->comm, suffix);
411         if (c->mask & SD_BUS_CREDS_TID_COMM)
412                 fprintf(f, "%sTIDComm=%s%s%s", prefix, color, c->tid_comm, suffix);
413         if (c->mask & SD_BUS_CREDS_EXE)
414                 fprintf(f, "%sExe=%s%s%s", prefix, color, strna(c->exe), suffix);
415
416         if (terse && (c->mask & (SD_BUS_CREDS_EXE|SD_BUS_CREDS_COMM|SD_BUS_CREDS_TID_COMM)))
417                 fputs("\n", f);
418
419         r = sd_bus_creds_get_cmdline(c, &cmdline);
420         if (r >= 0) {
421                 char **i;
422
423                 fprintf(f, "%sCommandLine=%s", prefix, color);
424                 STRV_FOREACH(i, cmdline) {
425                         if (i != cmdline)
426                                 fputc(' ', f);
427
428                         fputs(*i, f);
429                 }
430
431                 fprintf(f, "%s", suffix);
432         } else if (r != -ENODATA)
433                 fprintf(f, "%sCommandLine=%sn/a%s", prefix, color, suffix);
434
435         if (c->mask & SD_BUS_CREDS_SELINUX_CONTEXT)
436                 fprintf(f, "%sLabel=%s%s%s", prefix, color, c->label, suffix);
437         if (c->mask & SD_BUS_CREDS_DESCRIPTION)
438                 fprintf(f, "%sDescription=%s%s%s", prefix, color, c->description, suffix);
439
440         if (terse && (c->mask & (SD_BUS_CREDS_SELINUX_CONTEXT|SD_BUS_CREDS_DESCRIPTION)))
441                 fputs("\n", f);
442
443         if (c->mask & SD_BUS_CREDS_CGROUP)
444                 fprintf(f, "%sCGroup=%s%s%s", prefix, color, c->cgroup, suffix);
445         s = NULL;
446         r = sd_bus_creds_get_unit(c, &s);
447         if (r != -ENODATA)
448                 fprintf(f, "%sUnit=%s%s%s", prefix, color, strna(s), suffix);
449         s = NULL;
450         v = sd_bus_creds_get_slice(c, &s);
451         if (v != -ENODATA)
452                 fprintf(f, "%sSlice=%s%s%s", prefix, color, strna(s), suffix);
453         s = NULL;
454         q = sd_bus_creds_get_user_unit(c, &s);
455         if (q != -ENODATA)
456                 fprintf(f, "%sUserUnit=%s%s%s", prefix, color, strna(s), suffix);
457         s = NULL;
458         w = sd_bus_creds_get_user_slice(c, &s);
459         if (w != -ENODATA)
460                 fprintf(f, "%sUserSlice=%s%s%s", prefix, color, strna(s), suffix);
461         s = NULL;
462         z = sd_bus_creds_get_session(c, &s);
463         if (z != -ENODATA)
464                 fprintf(f, "%sSession=%s%s%s", prefix, color, strna(s), suffix);
465
466         if (terse && ((c->mask & SD_BUS_CREDS_CGROUP) || r != -ENODATA || q != -ENODATA || v != -ENODATA || w != -ENODATA || z != -ENODATA))
467                 fputs("\n", f);
468
469         r = sd_bus_creds_get_audit_login_uid(c, &audit_loginuid);
470         if (r >= 0)
471                 fprintf(f, "%sAuditLoginUID=%s"UID_FMT"%s", prefix, color, audit_loginuid, suffix);
472         else if (r != -ENODATA)
473                 fprintf(f, "%sAuditLoginUID=%sn/a%s", prefix, color, suffix);
474         q = sd_bus_creds_get_audit_session_id(c, &audit_sessionid);
475         if (q >= 0)
476                 fprintf(f, "%sAuditSessionID=%s%"PRIu32"%s", prefix, color, audit_sessionid, suffix);
477         else if (q != -ENODATA)
478                 fprintf(f, "%sAuditSessionID=%sn/a%s", prefix, color, suffix);
479
480         if (terse && (r != -ENODATA || q != -ENODATA))
481                 fputs("\n", f);
482
483         if (c->mask & SD_BUS_CREDS_UNIQUE_NAME)
484                 fprintf(f, "%sUniqueName=%s%s%s", prefix, color, c->unique_name, suffix);
485
486         if (sd_bus_creds_get_well_known_names(c, &well_known) >= 0) {
487                 char **i;
488
489                 fprintf(f, "%sWellKnownNames=%s", prefix, color);
490                 STRV_FOREACH(i, well_known) {
491                         if (i != well_known)
492                                 fputc(' ', f);
493
494                         fputs(*i, f);
495                 }
496
497                 fprintf(f, "%s", suffix);
498         }
499
500         if (terse && (c->mask & SD_BUS_CREDS_UNIQUE_NAME || well_known))
501                 fputc('\n', f);
502
503         dump_capabilities(c, f, "EffectiveCapabilities", terse, sd_bus_creds_has_effective_cap);
504         dump_capabilities(c, f, "PermittedCapabilities", terse, sd_bus_creds_has_permitted_cap);
505         dump_capabilities(c, f, "InheritableCapabilities", terse, sd_bus_creds_has_inheritable_cap);
506         dump_capabilities(c, f, "BoundingCapabilities", terse, sd_bus_creds_has_bounding_cap);
507
508         return 0;
509 }
510
511 /*
512  * For details about the file format, see:
513  *
514  * http://wiki.wireshark.org/Development/LibpcapFileFormat
515  */
516
517 typedef struct _packed_ pcap_hdr_s {
518         uint32_t magic_number;   /* magic number */
519         uint16_t version_major;  /* major version number */
520         uint16_t version_minor;  /* minor version number */
521         int32_t  thiszone;       /* GMT to local correction */
522         uint32_t sigfigs;        /* accuracy of timestamps */
523         uint32_t snaplen;        /* max length of captured packets, in octets */
524         uint32_t network;        /* data link type */
525 } pcap_hdr_t ;
526
527 typedef struct  _packed_ pcaprec_hdr_s {
528         uint32_t ts_sec;         /* timestamp seconds */
529         uint32_t ts_usec;        /* timestamp microseconds */
530         uint32_t incl_len;       /* number of octets of packet saved in file */
531         uint32_t orig_len;       /* actual length of packet */
532 } pcaprec_hdr_t;
533
534 int bus_pcap_header(size_t snaplen, FILE *f) {
535
536         pcap_hdr_t hdr = {
537                 .magic_number = 0xa1b2c3d4U,
538                 .version_major = 2,
539                 .version_minor = 4,
540                 .thiszone = 0, /* UTC */
541                 .sigfigs = 0,
542                 .network = 231, /* D-Bus */
543         };
544
545         if (!f)
546                 f = stdout;
547
548         assert(snaplen > 0);
549         assert((size_t) (uint32_t) snaplen == snaplen);
550
551         hdr.snaplen = (uint32_t) snaplen;
552
553         fwrite(&hdr, 1, sizeof(hdr), f);
554         fflush(f);
555
556         return 0;
557 }
558
559 int bus_message_pcap_frame(sd_bus_message *m, size_t snaplen, FILE *f) {
560         struct bus_body_part *part;
561         pcaprec_hdr_t hdr = {};
562         struct timeval tv;
563         unsigned i;
564         size_t w;
565
566         if (!f)
567                 f = stdout;
568
569         assert(m);
570         assert(snaplen > 0);
571         assert((size_t) (uint32_t) snaplen == snaplen);
572
573         if (m->realtime != 0)
574                 timeval_store(&tv, m->realtime);
575         else
576                 assert_se(gettimeofday(&tv, NULL) >= 0);
577
578         hdr.ts_sec = tv.tv_sec;
579         hdr.ts_usec = tv.tv_usec;
580         hdr.orig_len = BUS_MESSAGE_SIZE(m);
581         hdr.incl_len = MIN(hdr.orig_len, snaplen);
582
583         /* write the pcap header */
584         fwrite(&hdr, 1, sizeof(hdr), f);
585
586         /* write the dbus header */
587         w = MIN(BUS_MESSAGE_BODY_BEGIN(m), snaplen);
588         fwrite(m->header, 1, w, f);
589         snaplen -= w;
590
591         /* write the dbus body */
592         MESSAGE_FOREACH_PART(part, i, m) {
593                 if (snaplen <= 0)
594                         break;
595
596                 w = MIN(part->size, snaplen);
597                 fwrite(part->data, 1, w, f);
598                 snaplen -= w;
599         }
600
601         fflush(f);
602
603         return 0;
604 }