chiark / gitweb /
sd-bus: when we get ENOTTY on the HELLO ioctl assume incompatible API version
[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;
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         q = sd_bus_creds_get_user_unit(c, &s);
451         if (q != -ENODATA)
452                 fprintf(f, "%sUserUnit=%s%s%s", prefix, color, strna(s), suffix);
453         s = NULL;
454         v = sd_bus_creds_get_slice(c, &s);
455         if (v != -ENODATA)
456                 fprintf(f, "%sSlice=%s%s%s", prefix, color, strna(s), suffix);
457         s = NULL;
458         w = sd_bus_creds_get_session(c, &s);
459         if (w != -ENODATA)
460                 fprintf(f, "%sSession=%s%s%s", prefix, color, strna(s), suffix);
461
462         if (terse && ((c->mask & SD_BUS_CREDS_CGROUP) || r != -ENODATA || q != -ENODATA || v != -ENODATA || w != -ENODATA))
463                 fputs("\n", f);
464
465         r = sd_bus_creds_get_audit_login_uid(c, &audit_loginuid);
466         if (r >= 0)
467                 fprintf(f, "%sAuditLoginUID=%s"UID_FMT"%s", prefix, color, audit_loginuid, suffix);
468         else if (r != -ENODATA)
469                 fprintf(f, "%sAuditLoginUID=%sn/a%s", prefix, color, suffix);
470         q = sd_bus_creds_get_audit_session_id(c, &audit_sessionid);
471         if (q >= 0)
472                 fprintf(f, "%sAuditSessionID=%s%"PRIu32"%s", prefix, color, audit_sessionid, suffix);
473         else if (q != -ENODATA)
474                 fprintf(f, "%sAuditSessionID=%sn/a%s", prefix, color, suffix);
475
476         if (terse && (r != -ENODATA || q != -ENODATA))
477                 fputs("\n", f);
478
479         if (c->mask & SD_BUS_CREDS_UNIQUE_NAME)
480                 fprintf(f, "%sUniqueName=%s%s%s", prefix, color, c->unique_name, suffix);
481
482         if (sd_bus_creds_get_well_known_names(c, &well_known) >= 0) {
483                 char **i;
484
485                 fprintf(f, "%sWellKnownNames=%s", prefix, color);
486                 STRV_FOREACH(i, well_known) {
487                         if (i != well_known)
488                                 fputc(' ', f);
489
490                         fputs(*i, f);
491                 }
492
493                 fprintf(f, "%s", suffix);
494         }
495
496         if (terse && (c->mask & SD_BUS_CREDS_UNIQUE_NAME || well_known))
497                 fputc('\n', f);
498
499         dump_capabilities(c, f, "EffectiveCapabilities", terse, sd_bus_creds_has_effective_cap);
500         dump_capabilities(c, f, "PermittedCapabilities", terse, sd_bus_creds_has_permitted_cap);
501         dump_capabilities(c, f, "InheritableCapabilities", terse, sd_bus_creds_has_inheritable_cap);
502         dump_capabilities(c, f, "BoundingCapabilities", terse, sd_bus_creds_has_bounding_cap);
503
504         return 0;
505 }
506
507 /*
508  * For details about the file format, see:
509  *
510  * http://wiki.wireshark.org/Development/LibpcapFileFormat
511  */
512
513 typedef struct _packed_ pcap_hdr_s {
514         uint32_t magic_number;   /* magic number */
515         uint16_t version_major;  /* major version number */
516         uint16_t version_minor;  /* minor version number */
517         int32_t  thiszone;       /* GMT to local correction */
518         uint32_t sigfigs;        /* accuracy of timestamps */
519         uint32_t snaplen;        /* max length of captured packets, in octets */
520         uint32_t network;        /* data link type */
521 } pcap_hdr_t ;
522
523 typedef struct  _packed_ pcaprec_hdr_s {
524         uint32_t ts_sec;         /* timestamp seconds */
525         uint32_t ts_usec;        /* timestamp microseconds */
526         uint32_t incl_len;       /* number of octets of packet saved in file */
527         uint32_t orig_len;       /* actual length of packet */
528 } pcaprec_hdr_t;
529
530 int bus_pcap_header(size_t snaplen, FILE *f) {
531
532         pcap_hdr_t hdr = {
533                 .magic_number = 0xa1b2c3d4U,
534                 .version_major = 2,
535                 .version_minor = 4,
536                 .thiszone = 0, /* UTC */
537                 .sigfigs = 0,
538                 .network = 231, /* D-Bus */
539         };
540
541         if (!f)
542                 f = stdout;
543
544         assert(snaplen > 0);
545         assert((size_t) (uint32_t) snaplen == snaplen);
546
547         hdr.snaplen = (uint32_t) snaplen;
548
549         fwrite(&hdr, 1, sizeof(hdr), f);
550         fflush(f);
551
552         return 0;
553 }
554
555 int bus_message_pcap_frame(sd_bus_message *m, size_t snaplen, FILE *f) {
556         struct bus_body_part *part;
557         pcaprec_hdr_t hdr = {};
558         struct timeval tv;
559         unsigned i;
560         size_t w;
561
562         if (!f)
563                 f = stdout;
564
565         assert(m);
566         assert(snaplen > 0);
567         assert((size_t) (uint32_t) snaplen == snaplen);
568
569         if (m->realtime != 0)
570                 timeval_store(&tv, m->realtime);
571         else
572                 assert_se(gettimeofday(&tv, NULL) >= 0);
573
574         hdr.ts_sec = tv.tv_sec;
575         hdr.ts_usec = tv.tv_usec;
576         hdr.orig_len = BUS_MESSAGE_SIZE(m);
577         hdr.incl_len = MIN(hdr.orig_len, snaplen);
578
579         /* write the pcap header */
580         fwrite(&hdr, 1, sizeof(hdr), f);
581
582         /* write the dbus header */
583         w = MIN(BUS_MESSAGE_BODY_BEGIN(m), snaplen);
584         fwrite(m->header, 1, w, f);
585         snaplen -= w;
586
587         /* write the dbus body */
588         MESSAGE_FOREACH_PART(part, i, m) {
589                 if (snaplen <= 0)
590                         break;
591
592                 w = MIN(part->size, snaplen);
593                 fwrite(part->data, 1, w, f);
594                 snaplen -= w;
595         }
596
597         fflush(f);
598
599         return 0;
600 }