chiark / gitweb /
sd-bus: rename "connection name" to "description" for the sd-bus API too
[elogind.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) {
34         char *p;
35
36         p = new(char, 2 + level + 1);
37         if (!p)
38                 return NULL;
39
40         p[0] = p[1] = ' ';
41         memset(p + 2, '\t', level);
42         p[2 + level] = 0;
43
44         return p;
45 }
46
47 int bus_message_dump(sd_bus_message *m, FILE *f, bool with_header) {
48         unsigned level = 1;
49         int r;
50
51         assert(m);
52
53         if (!f)
54                 f = stdout;
55
56         if (with_header) {
57                 fprintf(f,
58                         "%s%s%s Type=%s%s%s  Endian=%c  Flags=%u  Version=%u  Priority=%lli",
59                         m->header->type == SD_BUS_MESSAGE_METHOD_ERROR ? ansi_highlight_red() :
60                         m->header->type == SD_BUS_MESSAGE_METHOD_RETURN ? ansi_highlight_green() :
61                         m->header->type != SD_BUS_MESSAGE_SIGNAL ? ansi_highlight() : "", draw_special_char(DRAW_TRIANGULAR_BULLET), ansi_highlight_off(),
62                         ansi_highlight(), bus_message_type_to_string(m->header->type), ansi_highlight_off(),
63                         m->header->endian,
64                         m->header->flags,
65                         m->header->version,
66                         (long long) m->priority);
67
68                 /* Display synthetic message serial number in a more readable
69                  * format than (uint32_t) -1 */
70                 if (BUS_MESSAGE_COOKIE(m) == 0xFFFFFFFFULL)
71                         fprintf(f, " Cookie=-1");
72                 else
73                         fprintf(f, " Cookie=%" PRIu64, BUS_MESSAGE_COOKIE(m));
74
75                 if (m->reply_cookie != 0)
76                         fprintf(f, "  ReplyCookie=%" PRIu64, m->reply_cookie);
77
78                 fputs("\n", f);
79
80                 if (m->sender)
81                         fprintf(f, "  Sender=%s%s%s", ansi_highlight(), m->sender, ansi_highlight_off());
82                 if (m->destination)
83                         fprintf(f, "  Destination=%s%s%s", ansi_highlight(), m->destination, ansi_highlight_off());
84                 if (m->path)
85                         fprintf(f, "  Path=%s%s%s", ansi_highlight(), m->path, ansi_highlight_off());
86                 if (m->interface)
87                         fprintf(f, "  Interface=%s%s%s", ansi_highlight(), m->interface, ansi_highlight_off());
88                 if (m->member)
89                         fprintf(f, "  Member=%s%s%s", ansi_highlight(), m->member, ansi_highlight_off());
90
91                 if (m->sender || m->destination || m->path || m->interface || m->member)
92                         fputs("\n", f);
93
94                 if (sd_bus_error_is_set(&m->error))
95                         fprintf(f,
96                                 "  ErrorName=%s%s%s"
97                                 "  ErrorMessage=%s\"%s\"%s\n",
98                                 ansi_highlight_red(), strna(m->error.name), ansi_highlight_off(),
99                                 ansi_highlight_red(), strna(m->error.message), ansi_highlight_off());
100
101                 if (m->monotonic != 0)
102                         fprintf(f, "  Monotonic="USEC_FMT, m->monotonic);
103                 if (m->realtime != 0)
104                         fprintf(f, "  Realtime="USEC_FMT, m->realtime);
105                 if (m->seqnum != 0)
106                         fprintf(f, "  SequenceNumber=%"PRIu64, m->seqnum);
107
108                 if (m->monotonic != 0 || m->realtime != 0 || m->seqnum != 0)
109                         fputs("\n", f);
110
111                 bus_creds_dump(&m->creds, f);
112         }
113
114         r = sd_bus_message_rewind(m, true);
115         if (r < 0) {
116                 log_error("Failed to rewind: %s", strerror(-r));
117                 return r;
118         }
119
120         fprintf(f, "  MESSAGE \"%s\" {\n", strempty(m->root_container.signature));
121
122         for (;;) {
123                 _cleanup_free_ char *prefix = NULL;
124                 const char *contents = NULL;
125                 char type;
126                 union {
127                         uint8_t u8;
128                         uint16_t u16;
129                         int16_t s16;
130                         uint32_t u32;
131                         int32_t s32;
132                         uint64_t u64;
133                         int64_t s64;
134                         double d64;
135                         const char *string;
136                         int i;
137                 } basic;
138
139                 r = sd_bus_message_peek_type(m, &type, &contents);
140                 if (r < 0) {
141                         log_error("Failed to peek type: %s", strerror(-r));
142                         return r;
143                 }
144
145                 if (r == 0) {
146                         if (level <= 1)
147                                 break;
148
149                         r = sd_bus_message_exit_container(m);
150                         if (r < 0) {
151                                 log_error("Failed to exit container: %s", strerror(-r));
152                                 return r;
153                         }
154
155                         level--;
156
157                         prefix = indent(level);
158                         if (!prefix)
159                                 return log_oom();
160
161                         fprintf(f, "%s};\n", prefix);
162                         continue;
163                 }
164
165                 prefix = indent(level);
166                 if (!prefix)
167                         return log_oom();
168
169                 if (bus_type_is_container(type) > 0) {
170                         r = sd_bus_message_enter_container(m, type, contents);
171                         if (r < 0) {
172                                 log_error("Failed to enter container: %s", strerror(-r));
173                                 return r;
174                         }
175
176                         if (type == SD_BUS_TYPE_ARRAY)
177                                 fprintf(f, "%sARRAY \"%s\" {\n", prefix, contents);
178                         else if (type == SD_BUS_TYPE_VARIANT)
179                                 fprintf(f, "%sVARIANT \"%s\" {\n", prefix, contents);
180                         else if (type == SD_BUS_TYPE_STRUCT)
181                                 fprintf(f, "%sSTRUCT \"%s\" {\n", prefix, contents);
182                         else if (type == SD_BUS_TYPE_DICT_ENTRY)
183                                 fprintf(f, "%sDICT_ENTRY \"%s\" {\n", prefix, contents);
184
185                         level ++;
186
187                         continue;
188                 }
189
190                 r = sd_bus_message_read_basic(m, type, &basic);
191                 if (r < 0) {
192                         log_error("Failed to get basic: %s", strerror(-r));
193                         return r;
194                 }
195
196                 assert(r > 0);
197
198                 switch (type) {
199
200                 case SD_BUS_TYPE_BYTE:
201                         fprintf(f, "%sBYTE %s%u%s;\n", prefix, ansi_highlight(), basic.u8, ansi_highlight_off());
202                         break;
203
204                 case SD_BUS_TYPE_BOOLEAN:
205                         fprintf(f, "%sBOOLEAN %s%s%s;\n", prefix, ansi_highlight(), true_false(basic.i), ansi_highlight_off());
206                         break;
207
208                 case SD_BUS_TYPE_INT16:
209                         fprintf(f, "%sINT16 %s%i%s;\n", prefix, ansi_highlight(), basic.s16, ansi_highlight_off());
210                         break;
211
212                 case SD_BUS_TYPE_UINT16:
213                         fprintf(f, "%sUINT16 %s%u%s;\n", prefix, ansi_highlight(), basic.u16, ansi_highlight_off());
214                         break;
215
216                 case SD_BUS_TYPE_INT32:
217                         fprintf(f, "%sINT32 %s%i%s;\n", prefix, ansi_highlight(), basic.s32, ansi_highlight_off());
218                         break;
219
220                 case SD_BUS_TYPE_UINT32:
221                         fprintf(f, "%sUINT32 %s%u%s;\n", prefix, ansi_highlight(), basic.u32, ansi_highlight_off());
222                         break;
223
224                 case SD_BUS_TYPE_INT64:
225                         fprintf(f, "%sINT64 %s%"PRIi64"%s;\n", prefix, ansi_highlight(), basic.s64, ansi_highlight_off());
226                         break;
227
228                 case SD_BUS_TYPE_UINT64:
229                         fprintf(f, "%sUINT64 %s%"PRIu64"%s;\n", prefix, ansi_highlight(), basic.u64, ansi_highlight_off());
230                         break;
231
232                 case SD_BUS_TYPE_DOUBLE:
233                         fprintf(f, "%sDOUBLE %s%g%s;\n", prefix, ansi_highlight(), basic.d64, ansi_highlight_off());
234                         break;
235
236                 case SD_BUS_TYPE_STRING:
237                         fprintf(f, "%sSTRING \"%s%s%s\";\n", prefix, ansi_highlight(), basic.string, ansi_highlight_off());
238                         break;
239
240                 case SD_BUS_TYPE_OBJECT_PATH:
241                         fprintf(f, "%sOBJECT_PATH \"%s%s%s\";\n", prefix, ansi_highlight(), basic.string, ansi_highlight_off());
242                         break;
243
244                 case SD_BUS_TYPE_SIGNATURE:
245                         fprintf(f, "%sSIGNATURE \"%s%s%s\";\n", prefix, ansi_highlight(), basic.string, ansi_highlight_off());
246                         break;
247
248                 case SD_BUS_TYPE_UNIX_FD:
249                         fprintf(f, "%sUNIX_FD %s%i%s;\n", prefix, ansi_highlight(), basic.i, ansi_highlight_off());
250                         break;
251
252                 default:
253                         assert_not_reached("Unknown basic type.");
254                 }
255         }
256
257         fprintf(f, "  };\n\n");
258         return 0;
259 }
260
261 static void dump_capabilities(
262                 sd_bus_creds *c,
263                 FILE *f,
264                 const char *name,
265                 int (*has)(sd_bus_creds *c, int capability)) {
266
267         unsigned long i, last_cap;
268         unsigned n = 0;
269         int r;
270
271         assert(c);
272         assert(f);
273         assert(name);
274         assert(has);
275
276         i = 0;
277         r = has(c, i);
278         if (r < 0)
279                 return;
280
281         fprintf(f, "  %s=", name);
282         last_cap = cap_last_cap();
283
284         for (;;) {
285                 if (r > 0) {
286                         _cleanup_cap_free_charp_ char *t;
287
288                         if (n > 0)
289                                 fputc(' ', f);
290                         if (n % 4 == 3)
291                                 fputs("\n          ", f);
292
293                         t = cap_to_name(i);
294                         fprintf(f, "%s", t);
295                         n++;
296                 }
297
298                 i++;
299
300                 if (i > last_cap)
301                         break;
302
303                 r = has(c, i);
304         }
305
306         fputs("\n", f);
307 }
308
309 int bus_creds_dump(sd_bus_creds *c, FILE *f) {
310         bool audit_sessionid_is_set = false, audit_loginuid_is_set = false;
311         const char *u = NULL, *uu = NULL, *s = NULL, *sl = NULL;
312         uid_t owner, audit_loginuid;
313         uint32_t audit_sessionid;
314         char **cmdline = NULL, **well_known = NULL;
315         int r;
316
317         assert(c);
318
319         if (!f)
320                 f = stdout;
321
322         if (c->mask & SD_BUS_CREDS_PID)
323                 fprintf(f, "  PID="PID_FMT, c->pid);
324         if (c->mask & SD_BUS_CREDS_PID_STARTTIME)
325                 fprintf(f, "  PIDStartTime="USEC_FMT, c->pid_starttime);
326         if (c->mask & SD_BUS_CREDS_TID)
327                 fprintf(f, "  TID="PID_FMT, c->tid);
328         if (c->mask & SD_BUS_CREDS_UID)
329                 fprintf(f, "  UID="UID_FMT, c->uid);
330         r = sd_bus_creds_get_owner_uid(c, &owner);
331         if (r >= 0)
332                 fprintf(f, "  OwnerUID="UID_FMT, owner);
333         if (c->mask & SD_BUS_CREDS_GID)
334                 fprintf(f, "  GID="GID_FMT, c->gid);
335
336         if ((c->mask & (SD_BUS_CREDS_PID|SD_BUS_CREDS_PID_STARTTIME|SD_BUS_CREDS_TID|SD_BUS_CREDS_UID|SD_BUS_CREDS_GID)) || r >= 0)
337                 fputs("\n", f);
338
339         if (c->mask & SD_BUS_CREDS_EXE)
340                 fprintf(f, "  Exe=%s", c->exe);
341         if (c->mask & SD_BUS_CREDS_COMM)
342                 fprintf(f, "  Comm=%s", c->comm);
343         if (c->mask & SD_BUS_CREDS_TID_COMM)
344                 fprintf(f, "  TIDComm=%s", c->tid_comm);
345
346         if (c->mask & (SD_BUS_CREDS_EXE|SD_BUS_CREDS_COMM|SD_BUS_CREDS_TID_COMM))
347                 fputs("\n", f);
348
349         if (c->mask & SD_BUS_CREDS_SELINUX_CONTEXT)
350                 fprintf(f, "  Label=%s", c->label);
351         if (c->mask & SD_BUS_CREDS_DESCRIPTION)
352                 fprintf(f, "  Description=%s", c->description);
353
354         if (c->mask & (SD_BUS_CREDS_SELINUX_CONTEXT|SD_BUS_CREDS_DESCRIPTION))
355                 fputs("\n", f);
356
357         if (sd_bus_creds_get_cmdline(c, &cmdline) >= 0) {
358                 char **i;
359
360                 fputs("  CommandLine={", f);
361                 STRV_FOREACH(i, cmdline) {
362                         if (i != cmdline)
363                                 fputc(' ', f);
364
365                         fputs(*i, f);
366                 }
367
368                 fputs("}\n", f);
369         }
370
371         if (c->mask & SD_BUS_CREDS_CGROUP)
372                 fprintf(f, "  CGroup=%s", c->cgroup);
373         sd_bus_creds_get_unit(c, &u);
374         if (u)
375                 fprintf(f, "  Unit=%s", u);
376         sd_bus_creds_get_user_unit(c, &uu);
377         if (uu)
378                 fprintf(f, "  UserUnit=%s", uu);
379         sd_bus_creds_get_slice(c, &sl);
380         if (sl)
381                 fprintf(f, "  Slice=%s", sl);
382         sd_bus_creds_get_session(c, &s);
383         if (s)
384                 fprintf(f, "  Session=%s", s);
385
386         if ((c->mask & SD_BUS_CREDS_CGROUP) || u || uu || sl || s)
387                 fputs("\n", f);
388
389         if (sd_bus_creds_get_audit_login_uid(c, &audit_loginuid) >= 0) {
390                 audit_loginuid_is_set = true;
391                 fprintf(f, "  AuditLoginUID="UID_FMT, audit_loginuid);
392         }
393         if (sd_bus_creds_get_audit_session_id(c, &audit_sessionid) >= 0) {
394                 audit_sessionid_is_set = true;
395                 fprintf(f, "  AuditSessionID=%"PRIu32, audit_sessionid);
396         }
397
398         if (audit_loginuid_is_set || audit_sessionid_is_set)
399                 fputs("\n", f);
400
401         if (c->mask & SD_BUS_CREDS_UNIQUE_NAME)
402                 fprintf(f, "  UniqueName=%s", c->unique_name);
403
404         if (sd_bus_creds_get_well_known_names(c, &well_known) >= 0) {
405                 char **i;
406
407                 fputs("  WellKnownNames={", f);
408                 STRV_FOREACH(i, well_known) {
409                         if (i != well_known)
410                                 fputc(' ', f);
411
412                         fputs(*i, f);
413                 }
414
415                 fputc('}', f);
416         }
417
418         if (c->mask & SD_BUS_CREDS_UNIQUE_NAME || well_known)
419                 fputc('\n', f);
420
421         dump_capabilities(c, f, "EffectiveCapabilities", sd_bus_creds_has_effective_cap);
422         dump_capabilities(c, f, "PermittedCapabilities", sd_bus_creds_has_permitted_cap);
423         dump_capabilities(c, f, "InheritableCapabilities", sd_bus_creds_has_inheritable_cap);
424         dump_capabilities(c, f, "BoundingCapabilities", sd_bus_creds_has_bounding_cap);
425
426         return 0;
427 }
428
429 /*
430  * For details about the file format, see:
431  *
432  * http://wiki.wireshark.org/Development/LibpcapFileFormat
433  */
434
435 typedef struct _packed_ pcap_hdr_s {
436         uint32_t magic_number;   /* magic number */
437         uint16_t version_major;  /* major version number */
438         uint16_t version_minor;  /* minor version number */
439         int32_t  thiszone;       /* GMT to local correction */
440         uint32_t sigfigs;        /* accuracy of timestamps */
441         uint32_t snaplen;        /* max length of captured packets, in octets */
442         uint32_t network;        /* data link type */
443 } pcap_hdr_t ;
444
445 typedef struct  _packed_ pcaprec_hdr_s {
446         uint32_t ts_sec;         /* timestamp seconds */
447         uint32_t ts_usec;        /* timestamp microseconds */
448         uint32_t incl_len;       /* number of octets of packet saved in file */
449         uint32_t orig_len;       /* actual length of packet */
450 } pcaprec_hdr_t;
451
452 int bus_pcap_header(size_t snaplen, FILE *f) {
453
454         pcap_hdr_t hdr = {
455                 .magic_number = 0xa1b2c3d4U,
456                 .version_major = 2,
457                 .version_minor = 4,
458                 .thiszone = 0, /* UTC */
459                 .sigfigs = 0,
460                 .network = 231, /* D-Bus */
461         };
462
463         if (!f)
464                 f = stdout;
465
466         assert(snaplen > 0);
467         assert((size_t) (uint32_t) snaplen == snaplen);
468
469         hdr.snaplen = (uint32_t) snaplen;
470
471         fwrite(&hdr, 1, sizeof(hdr), f);
472         fflush(f);
473
474         return 0;
475 }
476
477 int bus_message_pcap_frame(sd_bus_message *m, size_t snaplen, FILE *f) {
478         struct bus_body_part *part;
479         pcaprec_hdr_t hdr = {};
480         struct timeval tv;
481         unsigned i;
482         size_t w;
483
484         if (!f)
485                 f = stdout;
486
487         assert(m);
488         assert(snaplen > 0);
489         assert((size_t) (uint32_t) snaplen == snaplen);
490
491         if (m->realtime != 0)
492                 timeval_store(&tv, m->realtime);
493         else
494                 assert_se(gettimeofday(&tv, NULL) >= 0);
495
496         hdr.ts_sec = tv.tv_sec;
497         hdr.ts_usec = tv.tv_usec;
498         hdr.orig_len = BUS_MESSAGE_SIZE(m);
499         hdr.incl_len = MIN(hdr.orig_len, snaplen);
500
501         /* write the pcap header */
502         fwrite(&hdr, 1, sizeof(hdr), f);
503
504         /* write the dbus header */
505         w = MIN(BUS_MESSAGE_BODY_BEGIN(m), snaplen);
506         fwrite(m->header, 1, w, f);
507         snaplen -= w;
508
509         /* write the dbus body */
510         MESSAGE_FOREACH_PART(part, i, m) {
511                 if (snaplen <= 0)
512                         break;
513
514                 w = MIN(part->size, snaplen);
515                 fwrite(part->data, 1, w, f);
516                 snaplen -= w;
517         }
518
519         fflush(f);
520
521         return 0;
522 }