]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd/sd-bus/bus-dump.c
util-lib: split our string related calls from util.[ch] into its own file string...
[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 "bus-internal.h"
23 #include "bus-message.h"
24 #include "bus-type.h"
25 #include "cap-list.h"
26 #include "capability.h"
27 #include "formats-util.h"
28 #include "macro.h"
29 #include "string-util.h"
30 #include "strv.h"
31 #include "terminal-util.h"
32 #include "util.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_normal(),
77 ansi_highlight(), bus_message_type_to_string(m->header->type), ansi_normal(),
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_normal());
97 if (m->destination)
98 fprintf(f, " Destination=%s%s%s", ansi_highlight(), m->destination, ansi_normal());
99 if (m->path)
100 fprintf(f, " Path=%s%s%s", ansi_highlight(), m->path, ansi_normal());
101 if (m->interface)
102 fprintf(f, " Interface=%s%s%s", ansi_highlight(), m->interface, ansi_normal());
103 if (m->member)
104 fprintf(f, " Member=%s%s%s", ansi_highlight(), m->member, ansi_normal());
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_normal(),
114 ansi_highlight_red(), strna(m->error.message), ansi_normal());
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_normal());
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_normal());
219 break;
220
221 case SD_BUS_TYPE_INT16:
222 fprintf(f, "%sINT16 %s%i%s;\n", prefix, ansi_highlight(), basic.s16, ansi_normal());
223 break;
224
225 case SD_BUS_TYPE_UINT16:
226 fprintf(f, "%sUINT16 %s%u%s;\n", prefix, ansi_highlight(), basic.u16, ansi_normal());
227 break;
228
229 case SD_BUS_TYPE_INT32:
230 fprintf(f, "%sINT32 %s%i%s;\n", prefix, ansi_highlight(), basic.s32, ansi_normal());
231 break;
232
233 case SD_BUS_TYPE_UINT32:
234 fprintf(f, "%sUINT32 %s%u%s;\n", prefix, ansi_highlight(), basic.u32, ansi_normal());
235 break;
236
237 case SD_BUS_TYPE_INT64:
238 fprintf(f, "%sINT64 %s%"PRIi64"%s;\n", prefix, ansi_highlight(), basic.s64, ansi_normal());
239 break;
240
241 case SD_BUS_TYPE_UINT64:
242 fprintf(f, "%sUINT64 %s%"PRIu64"%s;\n", prefix, ansi_highlight(), basic.u64, ansi_normal());
243 break;
244
245 case SD_BUS_TYPE_DOUBLE:
246 fprintf(f, "%sDOUBLE %s%g%s;\n", prefix, ansi_highlight(), basic.d64, ansi_normal());
247 break;
248
249 case SD_BUS_TYPE_STRING:
250 fprintf(f, "%sSTRING \"%s%s%s\";\n", prefix, ansi_highlight(), basic.string, ansi_normal());
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_normal());
255 break;
256
257 case SD_BUS_TYPE_SIGNATURE:
258 fprintf(f, "%sSIGNATURE \"%s%s%s\";\n", prefix, ansi_highlight(), basic.string, ansi_normal());
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_normal());
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_normal(), f);
331 }
332
333 int bus_creds_dump(sd_bus_creds *c, FILE *f, bool terse) {
334 uid_t owner, audit_loginuid;
335 uint32_t audit_sessionid;
336 char **cmdline = NULL, **well_known = NULL;
337 const char *prefix, *color, *suffix, *s;
338 int r, q, v, w, z;
339
340 assert(c);
341
342 if (!f)
343 f = stdout;
344
345 if (terse) {
346 prefix = " ";
347 suffix = "";
348 color = "";
349 } else {
350 const char *off;
351
352 prefix = "";
353 color = ansi_highlight();
354
355 off = ansi_normal();
356 suffix = strjoina(off, "\n");
357 }
358
359 if (c->mask & SD_BUS_CREDS_PID)
360 fprintf(f, "%sPID=%s"PID_FMT"%s", prefix, color, c->pid, suffix);
361 if (c->mask & SD_BUS_CREDS_TID)
362 fprintf(f, "%sTID=%s"PID_FMT"%s", prefix, color, c->tid, suffix);
363 if (c->mask & SD_BUS_CREDS_PPID) {
364 if (c->ppid == 0)
365 fprintf(f, "%sPPID=%sn/a%s", prefix, color, suffix);
366 else
367 fprintf(f, "%sPPID=%s"PID_FMT"%s", prefix, color, c->ppid, suffix);
368 }
369 if (c->mask & SD_BUS_CREDS_TTY)
370 fprintf(f, "%sTTY=%s%s%s", prefix, color, strna(c->tty), suffix);
371
372 if (terse && ((c->mask & (SD_BUS_CREDS_PID|SD_BUS_CREDS_TID|SD_BUS_CREDS_PPID|SD_BUS_CREDS_TTY))))
373 fputs("\n", f);
374
375 if (c->mask & SD_BUS_CREDS_UID)
376 fprintf(f, "%sUID=%s"UID_FMT"%s", prefix, color, c->uid, suffix);
377 if (c->mask & SD_BUS_CREDS_EUID)
378 fprintf(f, "%sEUID=%s"UID_FMT"%s", prefix, color, c->euid, suffix);
379 if (c->mask & SD_BUS_CREDS_SUID)
380 fprintf(f, "%sSUID=%s"UID_FMT"%s", prefix, color, c->suid, suffix);
381 if (c->mask & SD_BUS_CREDS_FSUID)
382 fprintf(f, "%sFSUID=%s"UID_FMT"%s", prefix, color, c->fsuid, suffix);
383 r = sd_bus_creds_get_owner_uid(c, &owner);
384 if (r >= 0)
385 fprintf(f, "%sOwnerUID=%s"UID_FMT"%s", prefix, color, owner, suffix);
386 if (c->mask & SD_BUS_CREDS_GID)
387 fprintf(f, "%sGID=%s"GID_FMT"%s", prefix, color, c->gid, suffix);
388 if (c->mask & SD_BUS_CREDS_EGID)
389 fprintf(f, "%sEGID=%s"GID_FMT"%s", prefix, color, c->egid, suffix);
390 if (c->mask & SD_BUS_CREDS_SGID)
391 fprintf(f, "%sSGID=%s"GID_FMT"%s", prefix, color, c->sgid, suffix);
392 if (c->mask & SD_BUS_CREDS_FSGID)
393 fprintf(f, "%sFSGID=%s"GID_FMT"%s", prefix, color, c->fsgid, suffix);
394
395 if (c->mask & SD_BUS_CREDS_SUPPLEMENTARY_GIDS) {
396 unsigned i;
397
398 fprintf(f, "%sSupplementaryGIDs=%s", prefix, color);
399 for (i = 0; i < c->n_supplementary_gids; i++)
400 fprintf(f, "%s" GID_FMT, i > 0 ? " " : "", c->supplementary_gids[i]);
401 fprintf(f, "%s", suffix);
402 }
403
404 if (terse && ((c->mask & (SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID|
405 SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID|
406 SD_BUS_CREDS_SUPPLEMENTARY_GIDS)) || r >= 0))
407 fputs("\n", f);
408
409 if (c->mask & SD_BUS_CREDS_COMM)
410 fprintf(f, "%sComm=%s%s%s", prefix, color, c->comm, suffix);
411 if (c->mask & SD_BUS_CREDS_TID_COMM)
412 fprintf(f, "%sTIDComm=%s%s%s", prefix, color, c->tid_comm, suffix);
413 if (c->mask & SD_BUS_CREDS_EXE)
414 fprintf(f, "%sExe=%s%s%s", prefix, color, strna(c->exe), suffix);
415
416 if (terse && (c->mask & (SD_BUS_CREDS_EXE|SD_BUS_CREDS_COMM|SD_BUS_CREDS_TID_COMM)))
417 fputs("\n", f);
418
419 r = sd_bus_creds_get_cmdline(c, &cmdline);
420 if (r >= 0) {
421 char **i;
422
423 fprintf(f, "%sCommandLine=%s", prefix, color);
424 STRV_FOREACH(i, cmdline) {
425 if (i != cmdline)
426 fputc(' ', f);
427
428 fputs(*i, f);
429 }
430
431 fprintf(f, "%s", suffix);
432 } else if (r != -ENODATA)
433 fprintf(f, "%sCommandLine=%sn/a%s", prefix, color, suffix);
434
435 if (c->mask & SD_BUS_CREDS_SELINUX_CONTEXT)
436 fprintf(f, "%sLabel=%s%s%s", prefix, color, c->label, suffix);
437 if (c->mask & SD_BUS_CREDS_DESCRIPTION)
438 fprintf(f, "%sDescription=%s%s%s", prefix, color, c->description, suffix);
439
440 if (terse && (c->mask & (SD_BUS_CREDS_SELINUX_CONTEXT|SD_BUS_CREDS_DESCRIPTION)))
441 fputs("\n", f);
442
443 if (c->mask & SD_BUS_CREDS_CGROUP)
444 fprintf(f, "%sCGroup=%s%s%s", prefix, color, c->cgroup, suffix);
445 s = NULL;
446 r = sd_bus_creds_get_unit(c, &s);
447 if (r != -ENODATA)
448 fprintf(f, "%sUnit=%s%s%s", prefix, color, strna(s), suffix);
449 s = NULL;
450 v = sd_bus_creds_get_slice(c, &s);
451 if (v != -ENODATA)
452 fprintf(f, "%sSlice=%s%s%s", prefix, color, strna(s), suffix);
453 s = NULL;
454 q = sd_bus_creds_get_user_unit(c, &s);
455 if (q != -ENODATA)
456 fprintf(f, "%sUserUnit=%s%s%s", prefix, color, strna(s), suffix);
457 s = NULL;
458 w = sd_bus_creds_get_user_slice(c, &s);
459 if (w != -ENODATA)
460 fprintf(f, "%sUserSlice=%s%s%s", prefix, color, strna(s), suffix);
461 s = NULL;
462 z = sd_bus_creds_get_session(c, &s);
463 if (z != -ENODATA)
464 fprintf(f, "%sSession=%s%s%s", prefix, color, strna(s), suffix);
465
466 if (terse && ((c->mask & SD_BUS_CREDS_CGROUP) || r != -ENODATA || q != -ENODATA || v != -ENODATA || w != -ENODATA || z != -ENODATA))
467 fputs("\n", f);
468
469 r = sd_bus_creds_get_audit_login_uid(c, &audit_loginuid);
470 if (r >= 0)
471 fprintf(f, "%sAuditLoginUID=%s"UID_FMT"%s", prefix, color, audit_loginuid, suffix);
472 else if (r != -ENODATA)
473 fprintf(f, "%sAuditLoginUID=%sn/a%s", prefix, color, suffix);
474 q = sd_bus_creds_get_audit_session_id(c, &audit_sessionid);
475 if (q >= 0)
476 fprintf(f, "%sAuditSessionID=%s%"PRIu32"%s", prefix, color, audit_sessionid, suffix);
477 else if (q != -ENODATA)
478 fprintf(f, "%sAuditSessionID=%sn/a%s", prefix, color, suffix);
479
480 if (terse && (r != -ENODATA || q != -ENODATA))
481 fputs("\n", f);
482
483 if (c->mask & SD_BUS_CREDS_UNIQUE_NAME)
484 fprintf(f, "%sUniqueName=%s%s%s", prefix, color, c->unique_name, suffix);
485
486 if (sd_bus_creds_get_well_known_names(c, &well_known) >= 0) {
487 char **i;
488
489 fprintf(f, "%sWellKnownNames=%s", prefix, color);
490 STRV_FOREACH(i, well_known) {
491 if (i != well_known)
492 fputc(' ', f);
493
494 fputs(*i, f);
495 }
496
497 fprintf(f, "%s", suffix);
498 }
499
500 if (terse && (c->mask & SD_BUS_CREDS_UNIQUE_NAME || well_known))
501 fputc('\n', f);
502
503 dump_capabilities(c, f, "EffectiveCapabilities", terse, sd_bus_creds_has_effective_cap);
504 dump_capabilities(c, f, "PermittedCapabilities", terse, sd_bus_creds_has_permitted_cap);
505 dump_capabilities(c, f, "InheritableCapabilities", terse, sd_bus_creds_has_inheritable_cap);
506 dump_capabilities(c, f, "BoundingCapabilities", terse, sd_bus_creds_has_bounding_cap);
507
508 return 0;
509 }
510
511 /*
512 * For details about the file format, see:
513 *
514 * http://wiki.wireshark.org/Development/LibpcapFileFormat
515 */
516
517 typedef struct _packed_ pcap_hdr_s {
518 uint32_t magic_number; /* magic number */
519 uint16_t version_major; /* major version number */
520 uint16_t version_minor; /* minor version number */
521 int32_t thiszone; /* GMT to local correction */
522 uint32_t sigfigs; /* accuracy of timestamps */
523 uint32_t snaplen; /* max length of captured packets, in octets */
524 uint32_t network; /* data link type */
525 } pcap_hdr_t ;
526
527 typedef struct _packed_ pcaprec_hdr_s {
528 uint32_t ts_sec; /* timestamp seconds */
529 uint32_t ts_usec; /* timestamp microseconds */
530 uint32_t incl_len; /* number of octets of packet saved in file */
531 uint32_t orig_len; /* actual length of packet */
532 } pcaprec_hdr_t;
533
534 int bus_pcap_header(size_t snaplen, FILE *f) {
535
536 pcap_hdr_t hdr = {
537 .magic_number = 0xa1b2c3d4U,
538 .version_major = 2,
539 .version_minor = 4,
540 .thiszone = 0, /* UTC */
541 .sigfigs = 0,
542 .network = 231, /* D-Bus */
543 };
544
545 if (!f)
546 f = stdout;
547
548 assert(snaplen > 0);
549 assert((size_t) (uint32_t) snaplen == snaplen);
550
551 hdr.snaplen = (uint32_t) snaplen;
552
553 fwrite(&hdr, 1, sizeof(hdr), f);
554
555 return fflush_and_check(f);
556 }
557
558 int bus_message_pcap_frame(sd_bus_message *m, size_t snaplen, FILE *f) {
559 struct bus_body_part *part;
560 pcaprec_hdr_t hdr = {};
561 struct timeval tv;
562 unsigned i;
563 size_t w;
564
565 if (!f)
566 f = stdout;
567
568 assert(m);
569 assert(snaplen > 0);
570 assert((size_t) (uint32_t) snaplen == snaplen);
571
572 if (m->realtime != 0)
573 timeval_store(&tv, m->realtime);
574 else
575 assert_se(gettimeofday(&tv, NULL) >= 0);
576
577 hdr.ts_sec = tv.tv_sec;
578 hdr.ts_usec = tv.tv_usec;
579 hdr.orig_len = BUS_MESSAGE_SIZE(m);
580 hdr.incl_len = MIN(hdr.orig_len, snaplen);
581
582 /* write the pcap header */
583 fwrite(&hdr, 1, sizeof(hdr), f);
584
585 /* write the dbus header */
586 w = MIN(BUS_MESSAGE_BODY_BEGIN(m), snaplen);
587 fwrite(m->header, 1, w, f);
588 snaplen -= w;
589
590 /* write the dbus body */
591 MESSAGE_FOREACH_PART(part, i, m) {
592 if (snaplen <= 0)
593 break;
594
595 w = MIN(part->size, snaplen);
596 fwrite(part->data, 1, w, f);
597 snaplen -= w;
598 }
599
600 return fflush_and_check(f);
601 }