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