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