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