]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd/sd-bus/bus-dump.c
shared: add terminal-util.[ch]
[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 "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 bool audit_sessionid_is_set = false, audit_loginuid_is_set = false;
335 const char *u = NULL, *uu = NULL, *s = NULL, *sl = NULL;
336 uid_t owner, audit_loginuid;
337 uint32_t audit_sessionid;
338 char **cmdline = NULL, **well_known = NULL;
339 const char *prefix, *color, *suffix;
340 int r;
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_highlight_off();
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
366 if (terse && ((c->mask & (SD_BUS_CREDS_PID|SD_BUS_CREDS_TID))))
367 fputs("\n", f);
368
369 if (c->mask & SD_BUS_CREDS_UID)
370 fprintf(f, "%sUID=%s"UID_FMT"%s", prefix, color, c->uid, suffix);
371 if (c->mask & SD_BUS_CREDS_EUID)
372 fprintf(f, "%sEUID=%s"UID_FMT"%s", prefix, color, c->euid, suffix);
373 if (c->mask & SD_BUS_CREDS_SUID)
374 fprintf(f, "%sSUID=%s"UID_FMT"%s", prefix, color, c->suid, suffix);
375 if (c->mask & SD_BUS_CREDS_FSUID)
376 fprintf(f, "%sFSUID=%s"UID_FMT"%s", prefix, color, c->fsuid, suffix);
377 r = sd_bus_creds_get_owner_uid(c, &owner);
378 if (r >= 0)
379 fprintf(f, "%sOwnerUID=%s"UID_FMT"%s", prefix, color, owner, suffix);
380 if (c->mask & SD_BUS_CREDS_GID)
381 fprintf(f, "%sGID=%s"GID_FMT"%s", prefix, color, c->gid, suffix);
382 if (c->mask & SD_BUS_CREDS_EGID)
383 fprintf(f, "%sEGID=%s"GID_FMT"%s", prefix, color, c->egid, suffix);
384 if (c->mask & SD_BUS_CREDS_SGID)
385 fprintf(f, "%sSGID=%s"GID_FMT"%s", prefix, color, c->sgid, suffix);
386 if (c->mask & SD_BUS_CREDS_FSGID)
387 fprintf(f, "%sFSGID=%s"GID_FMT"%s", prefix, color, c->fsgid, suffix);
388
389 if (c->mask & SD_BUS_CREDS_SUPPLEMENTARY_GIDS) {
390 unsigned i;
391
392 fprintf(f, "%sSupplementaryGIDs=%s", prefix, color);
393 for (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, 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 if (sd_bus_creds_get_cmdline(c, &cmdline) >= 0) {
414 char **i;
415
416 fprintf(f, "%sCommandLine=%s", prefix, color);
417 STRV_FOREACH(i, cmdline) {
418 if (i != cmdline)
419 fputc(' ', f);
420
421 fputs(*i, f);
422 }
423
424 fprintf(f, "%s", suffix);
425 }
426
427 if (c->mask & SD_BUS_CREDS_SELINUX_CONTEXT)
428 fprintf(f, "%sLabel=%s%s%s", prefix, color, c->label, suffix);
429 if (c->mask & SD_BUS_CREDS_DESCRIPTION)
430 fprintf(f, "%sDescription=%s%s%s", prefix, color, c->description, suffix);
431
432 if (terse && (c->mask & (SD_BUS_CREDS_SELINUX_CONTEXT|SD_BUS_CREDS_DESCRIPTION)))
433 fputs("\n", f);
434
435 if (c->mask & SD_BUS_CREDS_CGROUP)
436 fprintf(f, "%sCGroup=%s%s%s", prefix, color, c->cgroup, suffix);
437 (void) sd_bus_creds_get_unit(c, &u);
438 if (u)
439 fprintf(f, "%sUnit=%s%s%s", prefix, color, u, suffix);
440 (void) sd_bus_creds_get_user_unit(c, &uu);
441 if (uu)
442 fprintf(f, "%sUserUnit=%s%s%s", prefix, color, uu, suffix);
443 (void) sd_bus_creds_get_slice(c, &sl);
444 if (sl)
445 fprintf(f, "%sSlice=%s%s%s", prefix, color, sl, suffix);
446 (void) sd_bus_creds_get_session(c, &s);
447 if (s)
448 fprintf(f, "%sSession=%s%s%s", prefix, color, s, suffix);
449
450 if (terse && ((c->mask & SD_BUS_CREDS_CGROUP) || u || uu || sl || s))
451 fputs("\n", f);
452
453 if (sd_bus_creds_get_audit_login_uid(c, &audit_loginuid) >= 0) {
454 audit_loginuid_is_set = true;
455 fprintf(f, "%sAuditLoginUID=%s"UID_FMT"%s", prefix, color, audit_loginuid, suffix);
456 }
457 if (sd_bus_creds_get_audit_session_id(c, &audit_sessionid) >= 0) {
458 audit_sessionid_is_set = true;
459 fprintf(f, "%sAuditSessionID=%s%"PRIu32"%s", prefix, color, audit_sessionid, suffix);
460 }
461
462 if (terse && (audit_loginuid_is_set || audit_sessionid_is_set))
463 fputs("\n", f);
464
465 if (c->mask & SD_BUS_CREDS_UNIQUE_NAME)
466 fprintf(f, "%sUniqueName=%s%s%s", prefix, color, c->unique_name, suffix);
467
468 if (sd_bus_creds_get_well_known_names(c, &well_known) >= 0) {
469 char **i;
470
471 fprintf(f, "%sWellKnownNames=%s", prefix, color);
472 STRV_FOREACH(i, well_known) {
473 if (i != well_known)
474 fputc(' ', f);
475
476 fputs(*i, f);
477 }
478
479 fprintf(f, "%s", suffix);
480 }
481
482 if (terse && (c->mask & SD_BUS_CREDS_UNIQUE_NAME || well_known))
483 fputc('\n', f);
484
485 dump_capabilities(c, f, "EffectiveCapabilities", terse, sd_bus_creds_has_effective_cap);
486 dump_capabilities(c, f, "PermittedCapabilities", terse, sd_bus_creds_has_permitted_cap);
487 dump_capabilities(c, f, "InheritableCapabilities", terse, sd_bus_creds_has_inheritable_cap);
488 dump_capabilities(c, f, "BoundingCapabilities", terse, sd_bus_creds_has_bounding_cap);
489
490 return 0;
491 }
492
493 /*
494 * For details about the file format, see:
495 *
496 * http://wiki.wireshark.org/Development/LibpcapFileFormat
497 */
498
499 typedef struct _packed_ pcap_hdr_s {
500 uint32_t magic_number; /* magic number */
501 uint16_t version_major; /* major version number */
502 uint16_t version_minor; /* minor version number */
503 int32_t thiszone; /* GMT to local correction */
504 uint32_t sigfigs; /* accuracy of timestamps */
505 uint32_t snaplen; /* max length of captured packets, in octets */
506 uint32_t network; /* data link type */
507 } pcap_hdr_t ;
508
509 typedef struct _packed_ pcaprec_hdr_s {
510 uint32_t ts_sec; /* timestamp seconds */
511 uint32_t ts_usec; /* timestamp microseconds */
512 uint32_t incl_len; /* number of octets of packet saved in file */
513 uint32_t orig_len; /* actual length of packet */
514 } pcaprec_hdr_t;
515
516 int bus_pcap_header(size_t snaplen, FILE *f) {
517
518 pcap_hdr_t hdr = {
519 .magic_number = 0xa1b2c3d4U,
520 .version_major = 2,
521 .version_minor = 4,
522 .thiszone = 0, /* UTC */
523 .sigfigs = 0,
524 .network = 231, /* D-Bus */
525 };
526
527 if (!f)
528 f = stdout;
529
530 assert(snaplen > 0);
531 assert((size_t) (uint32_t) snaplen == snaplen);
532
533 hdr.snaplen = (uint32_t) snaplen;
534
535 fwrite(&hdr, 1, sizeof(hdr), f);
536 fflush(f);
537
538 return 0;
539 }
540
541 int bus_message_pcap_frame(sd_bus_message *m, size_t snaplen, FILE *f) {
542 struct bus_body_part *part;
543 pcaprec_hdr_t hdr = {};
544 struct timeval tv;
545 unsigned i;
546 size_t w;
547
548 if (!f)
549 f = stdout;
550
551 assert(m);
552 assert(snaplen > 0);
553 assert((size_t) (uint32_t) snaplen == snaplen);
554
555 if (m->realtime != 0)
556 timeval_store(&tv, m->realtime);
557 else
558 assert_se(gettimeofday(&tv, NULL) >= 0);
559
560 hdr.ts_sec = tv.tv_sec;
561 hdr.ts_usec = tv.tv_usec;
562 hdr.orig_len = BUS_MESSAGE_SIZE(m);
563 hdr.incl_len = MIN(hdr.orig_len, snaplen);
564
565 /* write the pcap header */
566 fwrite(&hdr, 1, sizeof(hdr), f);
567
568 /* write the dbus header */
569 w = MIN(BUS_MESSAGE_BODY_BEGIN(m), snaplen);
570 fwrite(m->header, 1, w, f);
571 snaplen -= w;
572
573 /* write the dbus body */
574 MESSAGE_FOREACH_PART(part, i, m) {
575 if (snaplen <= 0)
576 break;
577
578 w = MIN(part->size, snaplen);
579 fwrite(part->data, 1, w, f);
580 snaplen -= w;
581 }
582
583 fflush(f);
584
585 return 0;
586 }