]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd/sd-bus/bus-dump.c
f1d00a952b0f9611c16038e3805aef132e9ae310
[thirdparty/systemd.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 }