chiark / gitweb /
bus: properly return an error when we detect a method call timeout
[elogind.git] / src / libsystemd-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 <sys/capability.h>
23
24 #include "util.h"
25 #include "capability.h"
26 #include "strv.h"
27 #include "audit.h"
28
29 #include "bus-message.h"
30 #include "bus-internal.h"
31 #include "bus-type.h"
32 #include "bus-dump.h"
33
34 static char *indent(unsigned level) {
35         char *p;
36
37         p = new(char, 2 + level + 1);
38         if (!p)
39                 return NULL;
40
41         p[0] = p[1] = ' ';
42         memset(p + 2, '\t', level);
43         p[2 + level] = 0;
44
45         return p;
46 }
47
48 int bus_message_dump(sd_bus_message *m, FILE *f, bool with_header) {
49         unsigned level = 1;
50         int r;
51
52         assert(m);
53
54         if (!f)
55                 f = stdout;
56
57         if (with_header) {
58                 fprintf(f,
59                         "%s%s%sType=%s%s%s  Endian=%c  Flags=%u  Version=%u",
60                         m->header->type == SD_BUS_MESSAGE_METHOD_ERROR ? ansi_highlight_red() :
61                         m->header->type == SD_BUS_MESSAGE_METHOD_RETURN ? ansi_highlight_green() :
62                         m->header->type != SD_BUS_MESSAGE_SIGNAL ? ansi_highlight() : "", draw_special_char(DRAW_TRIANGULAR_BULLET), ansi_highlight_off(),
63                         ansi_highlight(), bus_message_type_to_string(m->header->type), ansi_highlight_off(),
64                         m->header->endian,
65                         m->header->flags,
66                         m->header->version);
67
68                 /* Display synthetic message serial number in a more readable
69                  * format than (uint32_t) -1 */
70                 if (BUS_MESSAGE_SERIAL(m) == 0xFFFFFFFFULL)
71                         fprintf(f, " Serial=-1");
72                 else
73                         fprintf(f, " Serial=%u", BUS_MESSAGE_SERIAL(m));
74
75                 if (m->reply_serial != 0)
76                         fprintf(f, "  ReplySerial=%u", m->reply_serial);
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=%llu", (unsigned long long) m->monotonic);
103                 if (m->realtime != 0)
104                         fprintf(f, "  Realtime=%llu", (unsigned long long) m->realtime);
105
106                 if (m->monotonic != 0 || m->realtime != 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(), yes_no(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                         if (n > 0)
285                                 fputc(' ', f);
286                         if (n % 4 == 3)
287                                 fputs("\n          ", f);
288
289                         fputs(cap_to_name(i), f);
290                         n++;
291                 }
292
293                 i++;
294
295                 if (i > last_cap)
296                         break;
297
298                 r = has(c, i);
299         }
300
301         fputs("\n", f);
302 }
303
304 int bus_creds_dump(sd_bus_creds *c, FILE *f) {
305         bool audit_sessionid_is_set = false, audit_loginuid_is_set = false;
306         const char *u = NULL, *uu = NULL, *s = NULL, *sl = NULL;
307         uid_t owner, audit_loginuid;
308         uint32_t audit_sessionid;
309         char **cmdline = NULL, **well_known = NULL;
310         int r;
311
312         assert(c);
313
314         if (!f)
315                 f = stdout;
316
317         if (c->mask & SD_BUS_CREDS_PID)
318                 fprintf(f, "  PID=%lu", (unsigned long) c->pid);
319         if (c->mask & SD_BUS_CREDS_PID_STARTTIME)
320                 fprintf(f, "  PIDStartTime=%llu", (unsigned long long) c->pid_starttime);
321         if (c->mask & SD_BUS_CREDS_TID)
322                 fprintf(f, "  TID=%lu", (unsigned long) c->tid);
323         if (c->mask & SD_BUS_CREDS_UID)
324                 fprintf(f, "  UID=%lu", (unsigned long) c->uid);
325         r = sd_bus_creds_get_owner_uid(c, &owner);
326         if (r >= 0)
327                 fprintf(f, "  OwnerUID=%lu", (unsigned long) owner);
328         if (c->mask & SD_BUS_CREDS_GID)
329                 fprintf(f, "  GID=%lu", (unsigned long) c->gid);
330
331         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)
332                 fputs("\n", f);
333
334         if (c->mask & SD_BUS_CREDS_EXE)
335                 fprintf(f, "  Exe=%s", c->exe);
336         if (c->mask & SD_BUS_CREDS_COMM)
337                 fprintf(f, "  Comm=%s", c->comm);
338         if (c->mask & SD_BUS_CREDS_TID_COMM)
339                 fprintf(f, "  TIDComm=%s", c->tid_comm);
340         if (c->mask & SD_BUS_CREDS_SELINUX_CONTEXT)
341                 fprintf(f, "  Label=%s", c->label);
342
343         if (c->mask & (SD_BUS_CREDS_EXE|SD_BUS_CREDS_COMM|SD_BUS_CREDS_TID_COMM|SD_BUS_CREDS_SELINUX_CONTEXT))
344                 fputs("\n", f);
345
346         if (sd_bus_creds_get_cmdline(c, &cmdline) >= 0) {
347                 char **i;
348
349                 fputs("  CommandLine={", f);
350                 STRV_FOREACH(i, cmdline) {
351                         if (i != cmdline)
352                                 fputc(' ', f);
353
354                         fputs(*i, f);
355                 }
356
357                 fputs("}\n", f);
358         }
359
360         if (c->mask & SD_BUS_CREDS_CGROUP)
361                 fprintf(f, "  CGroup=%s", c->cgroup);
362         sd_bus_creds_get_unit(c, &u);
363         if (u)
364                 fprintf(f, "  Unit=%s", u);
365         sd_bus_creds_get_user_unit(c, &uu);
366         if (uu)
367                 fprintf(f, "  UserUnit=%s", uu);
368         sd_bus_creds_get_slice(c, &sl);
369         if (sl)
370                 fprintf(f, "  Slice=%s", sl);
371         sd_bus_creds_get_session(c, &s);
372         if (s)
373                 fprintf(f, "  Session=%s", s);
374
375         if ((c->mask & SD_BUS_CREDS_CGROUP) || u || uu || sl || s)
376                 fputs("\n", f);
377
378         if (sd_bus_creds_get_audit_login_uid(c, &audit_loginuid) >= 0) {
379                 audit_loginuid_is_set = true;
380                 fprintf(f, "  AuditLoginUID=%lu", (unsigned long) audit_loginuid);
381         }
382         if (sd_bus_creds_get_audit_session_id(c, &audit_sessionid) >= 0) {
383                 audit_sessionid_is_set = true;
384                 fprintf(f, "  AuditSessionID=%lu", (unsigned long) audit_sessionid);
385         }
386
387         if (audit_loginuid_is_set || audit_sessionid_is_set)
388                 fputs("\n", f);
389
390         if (c->mask & SD_BUS_CREDS_UNIQUE_NAME)
391                 fprintf(f, "  UniqueName=%s", c->unique_name);
392
393         if (sd_bus_creds_get_well_known_names(c, &well_known) >= 0) {
394                 char **i;
395
396                 fputs("  WellKnownNames={", f);
397                 STRV_FOREACH(i, well_known) {
398                         if (i != well_known)
399                                 fputc(' ', f);
400
401                         fputs(*i, f);
402                 }
403
404                 fputc('}', f);
405         }
406
407         if (c->mask & SD_BUS_CREDS_UNIQUE_NAME || well_known)
408                 fputc('\n', f);
409
410         dump_capabilities(c, f, "EffectiveCapabilities", sd_bus_creds_has_effective_cap);
411         dump_capabilities(c, f, "PermittedCapabilities", sd_bus_creds_has_permitted_cap);
412         dump_capabilities(c, f, "InheritableCapabilities", sd_bus_creds_has_inheritable_cap);
413         dump_capabilities(c, f, "BoundingCapabilities", sd_bus_creds_has_bounding_cap);
414
415         return 0;
416 }