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