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