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