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