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