chiark / gitweb /
delta: draw arrows with draw_special_char()
[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
27 #include "bus-message.h"
28 #include "bus-internal.h"
29 #include "bus-type.h"
30 #include "bus-dump.h"
31
32 static char *indent(unsigned level) {
33         char *p;
34
35         p = new(char, 2 + level + 1);
36         if (!p)
37                 return NULL;
38
39         p[0] = p[1] = ' ';
40         memset(p + 2, '\t', level);
41         p[2 + level] = 0;
42
43         return p;
44 }
45
46 int bus_message_dump(sd_bus_message *m, FILE *f, bool with_header) {
47         unsigned level = 1;
48         int r;
49
50         assert(m);
51
52         if (!f)
53                 f = stdout;
54
55         if (with_header) {
56                 fprintf(f,
57                         "%s%s%s Type=%s%s%s  Endian=%c  Flags=%u  Version=%u  Priority=%lli",
58                         m->header->type == SD_BUS_MESSAGE_METHOD_ERROR ? ansi_highlight_red() :
59                         m->header->type == SD_BUS_MESSAGE_METHOD_RETURN ? ansi_highlight_green() :
60                         m->header->type != SD_BUS_MESSAGE_SIGNAL ? ansi_highlight() : "", draw_special_char(DRAW_TRIANGULAR_BULLET), ansi_highlight_off(),
61                         ansi_highlight(), bus_message_type_to_string(m->header->type), ansi_highlight_off(),
62                         m->header->endian,
63                         m->header->flags,
64                         m->header->version,
65                         (long long) m->priority);
66
67                 /* Display synthetic message serial number in a more readable
68                  * format than (uint32_t) -1 */
69                 if (BUS_MESSAGE_COOKIE(m) == 0xFFFFFFFFULL)
70                         fprintf(f, " Cookie=-1");
71                 else
72                         fprintf(f, " Cookie=%" PRIu64, BUS_MESSAGE_COOKIE(m));
73
74                 if (m->reply_cookie != 0)
75                         fprintf(f, "  ReplyCookie=%" PRIu64, m->reply_cookie);
76
77                 fputs("\n", f);
78
79                 if (m->sender)
80                         fprintf(f, "  Sender=%s%s%s", ansi_highlight(), m->sender, ansi_highlight_off());
81                 if (m->destination)
82                         fprintf(f, "  Destination=%s%s%s", ansi_highlight(), m->destination, ansi_highlight_off());
83                 if (m->path)
84                         fprintf(f, "  Path=%s%s%s", ansi_highlight(), m->path, ansi_highlight_off());
85                 if (m->interface)
86                         fprintf(f, "  Interface=%s%s%s", ansi_highlight(), m->interface, ansi_highlight_off());
87                 if (m->member)
88                         fprintf(f, "  Member=%s%s%s", ansi_highlight(), m->member, ansi_highlight_off());
89
90                 if (m->sender || m->destination || m->path || m->interface || m->member)
91                         fputs("\n", f);
92
93                 if (sd_bus_error_is_set(&m->error))
94                         fprintf(f,
95                                 "  ErrorName=%s%s%s"
96                                 "  ErrorMessage=%s\"%s\"%s\n",
97                                 ansi_highlight_red(), strna(m->error.name), ansi_highlight_off(),
98                                 ansi_highlight_red(), strna(m->error.message), ansi_highlight_off());
99
100                 if (m->monotonic != 0)
101                         fprintf(f, "  Monotonic=%llu", (unsigned long long) m->monotonic);
102                 if (m->realtime != 0)
103                         fprintf(f, "  Realtime=%llu", (unsigned long long) m->realtime);
104                 if (m->seqnum != 0)
105                         fprintf(f, "  SequenceNumber=%llu", (unsigned long long) m->seqnum);
106
107                 if (m->monotonic != 0 || m->realtime != 0 || m->seqnum != 0)
108                         fputs("\n", f);
109
110                 bus_creds_dump(&m->creds, f);
111         }
112
113         r = sd_bus_message_rewind(m, true);
114         if (r < 0) {
115                 log_error("Failed to rewind: %s", strerror(-r));
116                 return r;
117         }
118
119         fprintf(f, "  MESSAGE \"%s\" {\n", strempty(m->root_container.signature));
120
121         for (;;) {
122                 _cleanup_free_ char *prefix = NULL;
123                 const char *contents = NULL;
124                 char type;
125                 union {
126                         uint8_t u8;
127                         uint16_t u16;
128                         int16_t s16;
129                         uint32_t u32;
130                         int32_t s32;
131                         uint64_t u64;
132                         int64_t s64;
133                         double d64;
134                         const char *string;
135                         int i;
136                 } basic;
137
138                 r = sd_bus_message_peek_type(m, &type, &contents);
139                 if (r < 0) {
140                         log_error("Failed to peek type: %s", strerror(-r));
141                         return r;
142                 }
143
144                 if (r == 0) {
145                         if (level <= 1)
146                                 break;
147
148                         r = sd_bus_message_exit_container(m);
149                         if (r < 0) {
150                                 log_error("Failed to exit container: %s", strerror(-r));
151                                 return r;
152                         }
153
154                         level--;
155
156                         prefix = indent(level);
157                         if (!prefix)
158                                 return log_oom();
159
160                         fprintf(f, "%s};\n", prefix);
161                         continue;
162                 }
163
164                 prefix = indent(level);
165                 if (!prefix)
166                         return log_oom();
167
168                 if (bus_type_is_container(type) > 0) {
169                         r = sd_bus_message_enter_container(m, type, contents);
170                         if (r < 0) {
171                                 log_error("Failed to enter container: %s", strerror(-r));
172                                 return r;
173                         }
174
175                         if (type == SD_BUS_TYPE_ARRAY)
176                                 fprintf(f, "%sARRAY \"%s\" {\n", prefix, contents);
177                         else if (type == SD_BUS_TYPE_VARIANT)
178                                 fprintf(f, "%sVARIANT \"%s\" {\n", prefix, contents);
179                         else if (type == SD_BUS_TYPE_STRUCT)
180                                 fprintf(f, "%sSTRUCT \"%s\" {\n", prefix, contents);
181                         else if (type == SD_BUS_TYPE_DICT_ENTRY)
182                                 fprintf(f, "%sDICT_ENTRY \"%s\" {\n", prefix, contents);
183
184                         level ++;
185
186                         continue;
187                 }
188
189                 r = sd_bus_message_read_basic(m, type, &basic);
190                 if (r < 0) {
191                         log_error("Failed to get basic: %s", strerror(-r));
192                         return r;
193                 }
194
195                 assert(r > 0);
196
197                 switch (type) {
198
199                 case SD_BUS_TYPE_BYTE:
200                         fprintf(f, "%sBYTE %s%u%s;\n", prefix, ansi_highlight(), basic.u8, ansi_highlight_off());
201                         break;
202
203                 case SD_BUS_TYPE_BOOLEAN:
204                         fprintf(f, "%sBOOLEAN %s%s%s;\n", prefix, ansi_highlight(), true_false(basic.i), ansi_highlight_off());
205                         break;
206
207                 case SD_BUS_TYPE_INT16:
208                         fprintf(f, "%sINT16 %s%i%s;\n", prefix, ansi_highlight(), basic.s16, ansi_highlight_off());
209                         break;
210
211                 case SD_BUS_TYPE_UINT16:
212                         fprintf(f, "%sUINT16 %s%u%s;\n", prefix, ansi_highlight(), basic.u16, ansi_highlight_off());
213                         break;
214
215                 case SD_BUS_TYPE_INT32:
216                         fprintf(f, "%sINT32 %s%i%s;\n", prefix, ansi_highlight(), basic.s32, ansi_highlight_off());
217                         break;
218
219                 case SD_BUS_TYPE_UINT32:
220                         fprintf(f, "%sUINT32 %s%u%s;\n", prefix, ansi_highlight(), basic.u32, ansi_highlight_off());
221                         break;
222
223                 case SD_BUS_TYPE_INT64:
224                         fprintf(f, "%sINT64 %s%lli%s;\n", prefix, ansi_highlight(), (long long) basic.s64, ansi_highlight_off());
225                         break;
226
227                 case SD_BUS_TYPE_UINT64:
228                         fprintf(f, "%sUINT64 %s%llu%s;\n", prefix, ansi_highlight(), (unsigned long long) basic.u64, ansi_highlight_off());
229                         break;
230
231                 case SD_BUS_TYPE_DOUBLE:
232                         fprintf(f, "%sDOUBLE %s%g%s;\n", prefix, ansi_highlight(), basic.d64, ansi_highlight_off());
233                         break;
234
235                 case SD_BUS_TYPE_STRING:
236                         fprintf(f, "%sSTRING \"%s%s%s\";\n", prefix, ansi_highlight(), basic.string, ansi_highlight_off());
237                         break;
238
239                 case SD_BUS_TYPE_OBJECT_PATH:
240                         fprintf(f, "%sOBJECT_PATH \"%s%s%s\";\n", prefix, ansi_highlight(), basic.string, ansi_highlight_off());
241                         break;
242
243                 case SD_BUS_TYPE_SIGNATURE:
244                         fprintf(f, "%sSIGNATURE \"%s%s%s\";\n", prefix, ansi_highlight(), basic.string, ansi_highlight_off());
245                         break;
246
247                 case SD_BUS_TYPE_UNIX_FD:
248                         fprintf(f, "%sUNIX_FD %s%i%s;\n", prefix, ansi_highlight(), basic.i, ansi_highlight_off());
249                         break;
250
251                 default:
252                         assert_not_reached("Unknown basic type.");
253                 }
254         }
255
256         fprintf(f, "  };\n\n");
257         return 0;
258 }
259
260 static void dump_capabilities(
261                 sd_bus_creds *c,
262                 FILE *f,
263                 const char *name,
264                 int (*has)(sd_bus_creds *c, int capability)) {
265
266         unsigned long i, last_cap;
267         unsigned n = 0;
268         int r;
269
270         assert(c);
271         assert(f);
272         assert(name);
273         assert(has);
274
275         i = 0;
276         r = has(c, i);
277         if (r < 0)
278                 return;
279
280         fprintf(f, "  %s=", name);
281         last_cap = cap_last_cap();
282
283         for (;;) {
284                 if (r > 0) {
285                         _cleanup_cap_free_charp_ char *t;
286
287                         if (n > 0)
288                                 fputc(' ', f);
289                         if (n % 4 == 3)
290                                 fputs("\n          ", f);
291
292                         t = cap_to_name(i);
293                         fprintf(f, "%s", t);
294                         n++;
295                 }
296
297                 i++;
298
299                 if (i > last_cap)
300                         break;
301
302                 r = has(c, i);
303         }
304
305         fputs("\n", f);
306 }
307
308 int bus_creds_dump(sd_bus_creds *c, FILE *f) {
309         bool audit_sessionid_is_set = false, audit_loginuid_is_set = false;
310         const char *u = NULL, *uu = NULL, *s = NULL, *sl = NULL;
311         uid_t owner, audit_loginuid;
312         uint32_t audit_sessionid;
313         char **cmdline = NULL, **well_known = NULL;
314         int r;
315
316         assert(c);
317
318         if (!f)
319                 f = stdout;
320
321         if (c->mask & SD_BUS_CREDS_PID)
322                 fprintf(f, "  PID=%lu", (unsigned long) c->pid);
323         if (c->mask & SD_BUS_CREDS_PID_STARTTIME)
324                 fprintf(f, "  PIDStartTime=%llu", (unsigned long long) c->pid_starttime);
325         if (c->mask & SD_BUS_CREDS_TID)
326                 fprintf(f, "  TID=%lu", (unsigned long) c->tid);
327         if (c->mask & SD_BUS_CREDS_UID)
328                 fprintf(f, "  UID=%lu", (unsigned long) c->uid);
329         r = sd_bus_creds_get_owner_uid(c, &owner);
330         if (r >= 0)
331                 fprintf(f, "  OwnerUID=%lu", (unsigned long) owner);
332         if (c->mask & SD_BUS_CREDS_GID)
333                 fprintf(f, "  GID=%lu", (unsigned long) c->gid);
334
335         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)
336                 fputs("\n", f);
337
338         if (c->mask & SD_BUS_CREDS_EXE)
339                 fprintf(f, "  Exe=%s", c->exe);
340         if (c->mask & SD_BUS_CREDS_COMM)
341                 fprintf(f, "  Comm=%s", c->comm);
342         if (c->mask & SD_BUS_CREDS_TID_COMM)
343                 fprintf(f, "  TIDComm=%s", c->tid_comm);
344
345         if (c->mask & (SD_BUS_CREDS_EXE|SD_BUS_CREDS_COMM|SD_BUS_CREDS_TID_COMM))
346                 fputs("\n", f);
347
348         if (c->mask & SD_BUS_CREDS_SELINUX_CONTEXT)
349                 fprintf(f, "  Label=%s", c->label);
350         if (c->mask & SD_BUS_CREDS_CONNECTION_NAME)
351                 fprintf(f, "  ConnectionName=%s", c->conn_name);
352
353         if (c->mask & (SD_BUS_CREDS_SELINUX_CONTEXT|SD_BUS_CREDS_CONNECTION_NAME))
354                 fputs("\n", f);
355
356         if (sd_bus_creds_get_cmdline(c, &cmdline) >= 0) {
357                 char **i;
358
359                 fputs("  CommandLine={", f);
360                 STRV_FOREACH(i, cmdline) {
361                         if (i != cmdline)
362                                 fputc(' ', f);
363
364                         fputs(*i, f);
365                 }
366
367                 fputs("}\n", f);
368         }
369
370         if (c->mask & SD_BUS_CREDS_CGROUP)
371                 fprintf(f, "  CGroup=%s", c->cgroup);
372         sd_bus_creds_get_unit(c, &u);
373         if (u)
374                 fprintf(f, "  Unit=%s", u);
375         sd_bus_creds_get_user_unit(c, &uu);
376         if (uu)
377                 fprintf(f, "  UserUnit=%s", uu);
378         sd_bus_creds_get_slice(c, &sl);
379         if (sl)
380                 fprintf(f, "  Slice=%s", sl);
381         sd_bus_creds_get_session(c, &s);
382         if (s)
383                 fprintf(f, "  Session=%s", s);
384
385         if ((c->mask & SD_BUS_CREDS_CGROUP) || u || uu || sl || s)
386                 fputs("\n", f);
387
388         if (sd_bus_creds_get_audit_login_uid(c, &audit_loginuid) >= 0) {
389                 audit_loginuid_is_set = true;
390                 fprintf(f, "  AuditLoginUID=%lu", (unsigned long) audit_loginuid);
391         }
392         if (sd_bus_creds_get_audit_session_id(c, &audit_sessionid) >= 0) {
393                 audit_sessionid_is_set = true;
394                 fprintf(f, "  AuditSessionID=%lu", (unsigned long) audit_sessionid);
395         }
396
397         if (audit_loginuid_is_set || audit_sessionid_is_set)
398                 fputs("\n", f);
399
400         if (c->mask & SD_BUS_CREDS_UNIQUE_NAME)
401                 fprintf(f, "  UniqueName=%s", c->unique_name);
402
403         if (sd_bus_creds_get_well_known_names(c, &well_known) >= 0) {
404                 char **i;
405
406                 fputs("  WellKnownNames={", f);
407                 STRV_FOREACH(i, well_known) {
408                         if (i != well_known)
409                                 fputc(' ', f);
410
411                         fputs(*i, f);
412                 }
413
414                 fputc('}', f);
415         }
416
417         if (c->mask & SD_BUS_CREDS_UNIQUE_NAME || well_known)
418                 fputc('\n', f);
419
420         dump_capabilities(c, f, "EffectiveCapabilities", sd_bus_creds_has_effective_cap);
421         dump_capabilities(c, f, "PermittedCapabilities", sd_bus_creds_has_permitted_cap);
422         dump_capabilities(c, f, "InheritableCapabilities", sd_bus_creds_has_inheritable_cap);
423         dump_capabilities(c, f, "BoundingCapabilities", sd_bus_creds_has_bounding_cap);
424
425         return 0;
426 }