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