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