]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd/sd-bus/bus-dump.c
treewide: more log_*_errno + return simplifications
[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 return log_error_errno(r, "Failed to rewind: %m");
130
131 if (!(flags & BUS_MESSAGE_DUMP_SUBTREE_ONLY))
132 fprintf(f, "%sMESSAGE \"%s\" {\n", indent(0, flags), strempty(m->root_container.signature));
133
134 for (;;) {
135 _cleanup_free_ char *prefix = NULL;
136 const char *contents = NULL;
137 char type;
138 union {
139 uint8_t u8;
140 uint16_t u16;
141 int16_t s16;
142 uint32_t u32;
143 int32_t s32;
144 uint64_t u64;
145 int64_t s64;
146 double d64;
147 const char *string;
148 int i;
149 } basic;
150
151 r = sd_bus_message_peek_type(m, &type, &contents);
152 if (r < 0)
153 return log_error_errno(r, "Failed to peek type: %m");
154
155 if (r == 0) {
156 if (level <= 1)
157 break;
158
159 r = sd_bus_message_exit_container(m);
160 if (r < 0)
161 return log_error_errno(r, "Failed to exit container: %m");
162
163 level--;
164
165 prefix = indent(level, flags);
166 if (!prefix)
167 return log_oom();
168
169 fprintf(f, "%s};\n", prefix);
170 continue;
171 }
172
173 prefix = indent(level, flags);
174 if (!prefix)
175 return log_oom();
176
177 if (bus_type_is_container(type) > 0) {
178 r = sd_bus_message_enter_container(m, type, contents);
179 if (r < 0)
180 return log_error_errno(r, "Failed to enter container: %m");
181
182 if (type == SD_BUS_TYPE_ARRAY)
183 fprintf(f, "%sARRAY \"%s\" {\n", prefix, contents);
184 else if (type == SD_BUS_TYPE_VARIANT)
185 fprintf(f, "%sVARIANT \"%s\" {\n", prefix, contents);
186 else if (type == SD_BUS_TYPE_STRUCT)
187 fprintf(f, "%sSTRUCT \"%s\" {\n", prefix, contents);
188 else if (type == SD_BUS_TYPE_DICT_ENTRY)
189 fprintf(f, "%sDICT_ENTRY \"%s\" {\n", prefix, contents);
190
191 level ++;
192
193 continue;
194 }
195
196 r = sd_bus_message_read_basic(m, type, &basic);
197 if (r < 0)
198 return log_error_errno(r, "Failed to get basic: %m");
199
200 assert(r > 0);
201
202 switch (type) {
203
204 case SD_BUS_TYPE_BYTE:
205 fprintf(f, "%sBYTE %s%u%s;\n", prefix, ansi_highlight(), basic.u8, ansi_highlight_off());
206 break;
207
208 case SD_BUS_TYPE_BOOLEAN:
209 fprintf(f, "%sBOOLEAN %s%s%s;\n", prefix, ansi_highlight(), true_false(basic.i), ansi_highlight_off());
210 break;
211
212 case SD_BUS_TYPE_INT16:
213 fprintf(f, "%sINT16 %s%i%s;\n", prefix, ansi_highlight(), basic.s16, ansi_highlight_off());
214 break;
215
216 case SD_BUS_TYPE_UINT16:
217 fprintf(f, "%sUINT16 %s%u%s;\n", prefix, ansi_highlight(), basic.u16, ansi_highlight_off());
218 break;
219
220 case SD_BUS_TYPE_INT32:
221 fprintf(f, "%sINT32 %s%i%s;\n", prefix, ansi_highlight(), basic.s32, ansi_highlight_off());
222 break;
223
224 case SD_BUS_TYPE_UINT32:
225 fprintf(f, "%sUINT32 %s%u%s;\n", prefix, ansi_highlight(), basic.u32, ansi_highlight_off());
226 break;
227
228 case SD_BUS_TYPE_INT64:
229 fprintf(f, "%sINT64 %s%"PRIi64"%s;\n", prefix, ansi_highlight(), basic.s64, ansi_highlight_off());
230 break;
231
232 case SD_BUS_TYPE_UINT64:
233 fprintf(f, "%sUINT64 %s%"PRIu64"%s;\n", prefix, ansi_highlight(), basic.u64, ansi_highlight_off());
234 break;
235
236 case SD_BUS_TYPE_DOUBLE:
237 fprintf(f, "%sDOUBLE %s%g%s;\n", prefix, ansi_highlight(), basic.d64, ansi_highlight_off());
238 break;
239
240 case SD_BUS_TYPE_STRING:
241 fprintf(f, "%sSTRING \"%s%s%s\";\n", prefix, ansi_highlight(), basic.string, ansi_highlight_off());
242 break;
243
244 case SD_BUS_TYPE_OBJECT_PATH:
245 fprintf(f, "%sOBJECT_PATH \"%s%s%s\";\n", prefix, ansi_highlight(), basic.string, ansi_highlight_off());
246 break;
247
248 case SD_BUS_TYPE_SIGNATURE:
249 fprintf(f, "%sSIGNATURE \"%s%s%s\";\n", prefix, ansi_highlight(), basic.string, ansi_highlight_off());
250 break;
251
252 case SD_BUS_TYPE_UNIX_FD:
253 fprintf(f, "%sUNIX_FD %s%i%s;\n", prefix, ansi_highlight(), basic.i, ansi_highlight_off());
254 break;
255
256 default:
257 assert_not_reached("Unknown basic type.");
258 }
259 }
260
261 if (!(flags & BUS_MESSAGE_DUMP_SUBTREE_ONLY))
262 fprintf(f, "%s};\n\n", indent(0, flags));
263
264 return 0;
265 }
266
267 static void dump_capabilities(
268 sd_bus_creds *c,
269 FILE *f,
270 const char *name,
271 bool terse,
272 int (*has)(sd_bus_creds *c, int capability)) {
273
274 unsigned long i, last_cap;
275 unsigned n = 0;
276 int r;
277
278 assert(c);
279 assert(f);
280 assert(name);
281 assert(has);
282
283 i = 0;
284 r = has(c, i);
285 if (r < 0)
286 return;
287
288 fprintf(f, "%s%s=%s", terse ? " " : "", name, terse ? "" : ansi_highlight());
289 last_cap = cap_last_cap();
290
291 for (;;) {
292 if (r > 0) {
293 _cleanup_cap_free_charp_ char *t;
294
295 if (n > 0)
296 fputc(' ', f);
297 if (n % 4 == 3)
298 fprintf(f, terse ? "\n " : "\n ");
299
300 t = cap_to_name(i);
301 fprintf(f, "%s", t);
302 n++;
303 }
304
305 i++;
306
307 if (i > last_cap)
308 break;
309
310 r = has(c, i);
311 }
312
313 fputs("\n", f);
314
315 if (!terse)
316 fputs(ansi_highlight_off(), f);
317 }
318
319 int bus_creds_dump(sd_bus_creds *c, FILE *f, bool terse) {
320 bool audit_sessionid_is_set = false, audit_loginuid_is_set = false;
321 const char *u = NULL, *uu = NULL, *s = NULL, *sl = NULL;
322 uid_t owner, audit_loginuid;
323 uint32_t audit_sessionid;
324 char **cmdline = NULL, **well_known = NULL;
325 const char *prefix, *color, *suffix;
326 int r;
327
328 assert(c);
329
330 if (!f)
331 f = stdout;
332
333 if (terse) {
334 prefix = " ";
335 suffix = "";
336 color = "";
337 } else {
338 const char *off;
339
340 prefix = "";
341 color = ansi_highlight();
342
343 off = ansi_highlight_off();
344 suffix = strappenda(off, "\n");
345 }
346
347 if (c->mask & SD_BUS_CREDS_PID)
348 fprintf(f, "%sPID=%s"PID_FMT"%s", prefix, color, c->pid, suffix);
349 if (c->mask & SD_BUS_CREDS_PID_STARTTIME)
350 fprintf(f, "%sPIDStartTime=%s"USEC_FMT"%s", prefix, color, c->pid_starttime, suffix);
351 if (c->mask & SD_BUS_CREDS_TID)
352 fprintf(f, "%sTID=%s"PID_FMT"%s", prefix, color, c->tid, suffix);
353
354 if (terse && ((c->mask & (SD_BUS_CREDS_PID|SD_BUS_CREDS_PID_STARTTIME|SD_BUS_CREDS_TID))))
355 fputs("\n", f);
356
357 if (c->mask & SD_BUS_CREDS_UID)
358 fprintf(f, "%sUID=%s"UID_FMT"%s", prefix, color, c->uid, suffix);
359 if (c->mask & SD_BUS_CREDS_EUID)
360 fprintf(f, "%sEUID=%s"UID_FMT"%s", prefix, color, c->euid, suffix);
361 if (c->mask & SD_BUS_CREDS_SUID)
362 fprintf(f, "%sSUID=%s"UID_FMT"%s", prefix, color, c->suid, suffix);
363 if (c->mask & SD_BUS_CREDS_FSUID)
364 fprintf(f, "%sFSUID=%s"UID_FMT"%s", prefix, color, c->fsuid, suffix);
365 r = sd_bus_creds_get_owner_uid(c, &owner);
366 if (r >= 0)
367 fprintf(f, "%sOwnerUID=%s"UID_FMT"%s", prefix, color, owner, suffix);
368 if (c->mask & SD_BUS_CREDS_GID)
369 fprintf(f, "%sGID=%s"GID_FMT"%s", prefix, color, c->gid, suffix);
370 if (c->mask & SD_BUS_CREDS_EGID)
371 fprintf(f, "%sEGID=%s"GID_FMT"%s", prefix, color, c->egid, suffix);
372 if (c->mask & SD_BUS_CREDS_SGID)
373 fprintf(f, "%sSGID=%s"GID_FMT"%s", prefix, color, c->sgid, suffix);
374 if (c->mask & SD_BUS_CREDS_FSGID)
375 fprintf(f, "%sFSGID=%s"GID_FMT"%s", prefix, color, c->fsgid, suffix);
376
377 if (c->mask & SD_BUS_CREDS_SUPPLEMENTARY_GIDS) {
378 unsigned i;
379
380 fprintf(f, "%sSupplementaryGIDs=%s", prefix, color);
381 for (i = 0; i < c->n_supplementary_gids; i++)
382 fprintf(f, "%s" GID_FMT, i > 0 ? " " : "", c->supplementary_gids[i]);
383 fprintf(f, "%s", suffix);
384 }
385
386 if (terse && ((c->mask & (SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID|
387 SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID|
388 SD_BUS_CREDS_SUPPLEMENTARY_GIDS)) || r >= 0))
389 fputs("\n", f);
390
391 if (c->mask & SD_BUS_CREDS_COMM)
392 fprintf(f, "%sComm=%s%s%s", prefix, color, c->comm, suffix);
393 if (c->mask & SD_BUS_CREDS_TID_COMM)
394 fprintf(f, "%sTIDComm=%s%s%s", prefix, color, c->tid_comm, suffix);
395 if (c->mask & SD_BUS_CREDS_EXE)
396 fprintf(f, "%sExe=%s%s%s", prefix, color, c->exe, suffix);
397
398 if (terse && (c->mask & (SD_BUS_CREDS_EXE|SD_BUS_CREDS_COMM|SD_BUS_CREDS_TID_COMM)))
399 fputs("\n", f);
400
401 if (sd_bus_creds_get_cmdline(c, &cmdline) >= 0) {
402 char **i;
403
404 fprintf(f, "%sCommandLine=%s", prefix, color);
405 STRV_FOREACH(i, cmdline) {
406 if (i != cmdline)
407 fputc(' ', f);
408
409 fputs(*i, f);
410 }
411
412 fprintf(f, "%s", suffix);
413 }
414
415 if (c->mask & SD_BUS_CREDS_SELINUX_CONTEXT)
416 fprintf(f, "%sLabel=%s%s%s", prefix, color, c->label, suffix);
417 if (c->mask & SD_BUS_CREDS_DESCRIPTION)
418 fprintf(f, "%sDescription=%s%s%s", prefix, color, c->description, suffix);
419
420 if (terse && (c->mask & (SD_BUS_CREDS_SELINUX_CONTEXT|SD_BUS_CREDS_DESCRIPTION)))
421 fputs("\n", f);
422
423 if (c->mask & SD_BUS_CREDS_CGROUP)
424 fprintf(f, "%sCGroup=%s%s%s", prefix, color, c->cgroup, suffix);
425 sd_bus_creds_get_unit(c, &u);
426 if (u)
427 fprintf(f, "%sUnit=%s%s%s", prefix, color, u, suffix);
428 sd_bus_creds_get_user_unit(c, &uu);
429 if (uu)
430 fprintf(f, "%sUserUnit=%s%s%s", prefix, color, uu, suffix);
431 sd_bus_creds_get_slice(c, &sl);
432 if (sl)
433 fprintf(f, "%sSlice=%s%s%s", prefix, color, sl, suffix);
434 sd_bus_creds_get_session(c, &s);
435 if (s)
436 fprintf(f, "%sSession=%s%s%s", prefix, color, s, suffix);
437
438 if (terse && ((c->mask & SD_BUS_CREDS_CGROUP) || u || uu || sl || s))
439 fputs("\n", f);
440
441 if (sd_bus_creds_get_audit_login_uid(c, &audit_loginuid) >= 0) {
442 audit_loginuid_is_set = true;
443 fprintf(f, "%sAuditLoginUID=%s"UID_FMT"%s", prefix, color, audit_loginuid, suffix);
444 }
445 if (sd_bus_creds_get_audit_session_id(c, &audit_sessionid) >= 0) {
446 audit_sessionid_is_set = true;
447 fprintf(f, "%sAuditSessionID=%s%"PRIu32"%s", prefix, color, audit_sessionid, suffix);
448 }
449
450 if (terse && (audit_loginuid_is_set || audit_sessionid_is_set))
451 fputs("\n", f);
452
453 if (c->mask & SD_BUS_CREDS_UNIQUE_NAME)
454 fprintf(f, "%sUniqueName=%s%s%s", prefix, color, c->unique_name, suffix);
455
456 if (sd_bus_creds_get_well_known_names(c, &well_known) >= 0) {
457 char **i;
458
459 fprintf(f, "%sWellKnownNames=%s", prefix, color);
460 STRV_FOREACH(i, well_known) {
461 if (i != well_known)
462 fputc(' ', f);
463
464 fputs(*i, f);
465 }
466
467 fprintf(f, "%s", suffix);
468 }
469
470 if (terse && (c->mask & SD_BUS_CREDS_UNIQUE_NAME || well_known))
471 fputc('\n', f);
472
473 dump_capabilities(c, f, "EffectiveCapabilities", terse, sd_bus_creds_has_effective_cap);
474 dump_capabilities(c, f, "PermittedCapabilities", terse, sd_bus_creds_has_permitted_cap);
475 dump_capabilities(c, f, "InheritableCapabilities", terse, sd_bus_creds_has_inheritable_cap);
476 dump_capabilities(c, f, "BoundingCapabilities", terse, sd_bus_creds_has_bounding_cap);
477
478 return 0;
479 }
480
481 /*
482 * For details about the file format, see:
483 *
484 * http://wiki.wireshark.org/Development/LibpcapFileFormat
485 */
486
487 typedef struct _packed_ pcap_hdr_s {
488 uint32_t magic_number; /* magic number */
489 uint16_t version_major; /* major version number */
490 uint16_t version_minor; /* minor version number */
491 int32_t thiszone; /* GMT to local correction */
492 uint32_t sigfigs; /* accuracy of timestamps */
493 uint32_t snaplen; /* max length of captured packets, in octets */
494 uint32_t network; /* data link type */
495 } pcap_hdr_t ;
496
497 typedef struct _packed_ pcaprec_hdr_s {
498 uint32_t ts_sec; /* timestamp seconds */
499 uint32_t ts_usec; /* timestamp microseconds */
500 uint32_t incl_len; /* number of octets of packet saved in file */
501 uint32_t orig_len; /* actual length of packet */
502 } pcaprec_hdr_t;
503
504 int bus_pcap_header(size_t snaplen, FILE *f) {
505
506 pcap_hdr_t hdr = {
507 .magic_number = 0xa1b2c3d4U,
508 .version_major = 2,
509 .version_minor = 4,
510 .thiszone = 0, /* UTC */
511 .sigfigs = 0,
512 .network = 231, /* D-Bus */
513 };
514
515 if (!f)
516 f = stdout;
517
518 assert(snaplen > 0);
519 assert((size_t) (uint32_t) snaplen == snaplen);
520
521 hdr.snaplen = (uint32_t) snaplen;
522
523 fwrite(&hdr, 1, sizeof(hdr), f);
524 fflush(f);
525
526 return 0;
527 }
528
529 int bus_message_pcap_frame(sd_bus_message *m, size_t snaplen, FILE *f) {
530 struct bus_body_part *part;
531 pcaprec_hdr_t hdr = {};
532 struct timeval tv;
533 unsigned i;
534 size_t w;
535
536 if (!f)
537 f = stdout;
538
539 assert(m);
540 assert(snaplen > 0);
541 assert((size_t) (uint32_t) snaplen == snaplen);
542
543 if (m->realtime != 0)
544 timeval_store(&tv, m->realtime);
545 else
546 assert_se(gettimeofday(&tv, NULL) >= 0);
547
548 hdr.ts_sec = tv.tv_sec;
549 hdr.ts_usec = tv.tv_usec;
550 hdr.orig_len = BUS_MESSAGE_SIZE(m);
551 hdr.incl_len = MIN(hdr.orig_len, snaplen);
552
553 /* write the pcap header */
554 fwrite(&hdr, 1, sizeof(hdr), f);
555
556 /* write the dbus header */
557 w = MIN(BUS_MESSAGE_BODY_BEGIN(m), snaplen);
558 fwrite(m->header, 1, w, f);
559 snaplen -= w;
560
561 /* write the dbus body */
562 MESSAGE_FOREACH_PART(part, i, m) {
563 if (snaplen <= 0)
564 break;
565
566 w = MIN(part->size, snaplen);
567 fwrite(part->data, 1, w, f);
568 snaplen -= w;
569 }
570
571 fflush(f);
572
573 return 0;
574 }