chiark / gitweb /
bus: add color and indentation to bus_message_dump()
[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
28 #include "bus-message.h"
29 #include "bus-internal.h"
30 #include "bus-type.h"
31 #include "bus-dump.h"
32
33 static char *indent(unsigned level) {
34         char *p;
35
36         p = new(char, 2 + level + 1);
37         if (!p)
38                 return NULL;
39
40         p[0] = p[1] = ' ';
41         memset(p + 2, '\t', level);
42         p[2 + level] = 0;
43
44         return p;
45 }
46
47 int bus_message_dump(sd_bus_message *m, FILE *f, bool with_header) {
48         const char *u = NULL, *uu = NULL, *s = NULL;
49         char **cmdline = NULL;
50         unsigned level = 1;
51         int r;
52         uid_t owner, audit_loginuid;
53         uint32_t audit_sessionid;
54         bool audit_sessionid_is_set = false, audit_loginuid_is_set = false;
55
56         assert(m);
57
58         if (!f)
59                 f = stdout;
60
61         if (with_header) {
62                 fprintf(f,
63                         "%s%s%sType=%s%s%s  Endian=%c  Flags=%u  Version=%u  Serial=%u ",
64                         m->header->type == SD_BUS_MESSAGE_METHOD_ERROR ? ansi_highlight_red() :
65                         m->header->type == SD_BUS_MESSAGE_METHOD_RETURN ? ansi_highlight_green() :
66                         m->header->type != SD_BUS_MESSAGE_SIGNAL ? ansi_highlight() : "", draw_special_char(DRAW_TRIANGULAR_BULLET), ansi_highlight_off(),
67                         ansi_highlight(), bus_message_type_to_string(m->header->type), ansi_highlight_off(),
68                         m->header->endian,
69                         m->header->flags,
70                         m->header->version,
71                         BUS_MESSAGE_SERIAL(m));
72
73                 if (m->reply_serial != 0)
74                         fprintf(f, "  ReplySerial=%u", m->reply_serial);
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->pid != 0)
100                         fprintf(f, "  PID=%lu", (unsigned long) m->pid);
101                 if (m->pid_starttime != 0)
102                         fprintf(f, "  PIDStartTime=%llu", (unsigned long long) m->pid_starttime);
103                 if (m->tid != 0)
104                         fprintf(f, "  TID=%lu", (unsigned long) m->tid);
105                 if (m->uid_valid)
106                         fprintf(f, "  UID=%lu", (unsigned long) m->uid);
107                 r = sd_bus_message_get_owner_uid(m, &owner);
108                 if (r >= 0)
109                         fprintf(f, "  OwnerUID=%lu", (unsigned long) owner);
110                 if (m->gid_valid)
111                         fprintf(f, "  GID=%lu", (unsigned long) m->gid);
112
113                 if (m->pid != 0 || m->pid_starttime != 0 || m->tid != 0 || m->uid_valid || r >= 0 || m->gid_valid)
114                         fputs("\n", f);
115
116                 if (m->monotonic != 0)
117                         fprintf(f, "  Monotonic=%llu", (unsigned long long) m->monotonic);
118                 if (m->realtime != 0)
119                         fprintf(f, "  Realtime=%llu", (unsigned long long) m->realtime);
120
121                 if (m->monotonic != 0 || m->realtime != 0)
122                         fputs("\n", f);
123
124                 if (m->exe)
125                         fprintf(f, "  Exe=%s", m->exe);
126                 if (m->comm)
127                         fprintf(f, "  Comm=%s", m->comm);
128                 if (m->tid_comm)
129                         fprintf(f, "  TIDComm=%s", m->tid_comm);
130                 if (m->label)
131                         fprintf(f, "  Label=%s", m->label);
132
133                 if (m->exe || m->comm || m->tid_comm || m->label)
134                         fputs("\n", f);
135
136                 if (sd_bus_message_get_cmdline(m, &cmdline) >= 0) {
137                         char **c;
138
139                         fputs("  CommandLine=[", f);
140                         STRV_FOREACH(c, cmdline) {
141                                 if (c != cmdline)
142                                         fputc(' ', f);
143
144                                 fputs(*c, f);
145                         }
146
147                         fputs("]\n", f);
148                 }
149
150                 if (m->cgroup)
151                         fprintf(f, "  CGroup=%s\n", m->cgroup);
152
153                 sd_bus_message_get_unit(m, &u);
154                 if (u)
155                         fprintf(f, "  Unit=%s", u);
156                 sd_bus_message_get_user_unit(m, &uu);
157                 if (uu)
158                         fprintf(f, "  UserUnit=%s", uu);
159                 sd_bus_message_get_session(m, &s);
160                 if (s)
161                         fprintf(f, "  Session=%s", s);
162                 if (sd_bus_message_get_audit_loginuid(m, &audit_loginuid) >= 0) {
163                         audit_loginuid_is_set = true;
164                         fprintf(f, "  AuditLoginUID=%lu", (unsigned long) audit_loginuid);
165                 }
166                 if (sd_bus_message_get_audit_sessionid(m, &audit_sessionid) >= 0) {
167                         audit_sessionid_is_set = true;
168                         fprintf(f, "  AuditSessionID=%lu", (unsigned long) audit_sessionid);
169                 }
170
171                 if (u || uu || s || audit_loginuid_is_set || audit_sessionid_is_set)
172                         fputs("\n", f);
173
174                 r = sd_bus_message_has_effective_cap(m, 0);
175                 if (r >= 0) {
176                         unsigned long c, last_cap;
177
178                         fprintf(f, "  Capabilities=%s", r ? cap_to_name(0) : "");
179
180                         last_cap = cap_last_cap();
181                         for (c = 0; c < last_cap; c++) {
182                                 r = sd_bus_message_has_effective_cap(m, c);
183                                 if (r > 0)
184                                         fprintf(f, "|%s", cap_to_name(c));
185                         }
186                         fputs("\n", f);
187                 }
188         }
189
190         r = sd_bus_message_rewind(m, true);
191         if (r < 0) {
192                 log_error("Failed to rewind: %s", strerror(-r));
193                 return r;
194         }
195
196         fprintf(f, "  MESSAGE \"%s\" {\n", strempty(m->root_container.signature));
197
198         for(;;) {
199                 _cleanup_free_ char *prefix = NULL;
200                 const char *contents = NULL;
201                 char type;
202                 union {
203                         uint8_t u8;
204                         uint16_t u16;
205                         int16_t s16;
206                         uint32_t u32;
207                         int32_t s32;
208                         uint64_t u64;
209                         int64_t s64;
210                         double d64;
211                         const char *string;
212                         int i;
213                 } basic;
214
215                 r = sd_bus_message_peek_type(m, &type, &contents);
216                 if (r < 0) {
217                         log_error("Failed to peek type: %s", strerror(-r));
218                         return r;
219                 }
220
221                 if (r == 0) {
222                         if (level <= 1)
223                                 break;
224
225                         r = sd_bus_message_exit_container(m);
226                         if (r < 0) {
227                                 log_error("Failed to exit container: %s", strerror(-r));
228                                 return r;
229                         }
230
231                         level--;
232
233                         prefix = indent(level);
234                         if (!prefix)
235                                 return log_oom();
236
237                         fprintf(f, "%s};\n", prefix);
238                         continue;
239                 }
240
241                 prefix = indent(level);
242                 if (!prefix)
243                         return log_oom();
244
245                 if (bus_type_is_container(type) > 0) {
246                         r = sd_bus_message_enter_container(m, type, contents);
247                         if (r < 0) {
248                                 log_error("Failed to enter container: %s", strerror(-r));
249                                 return r;
250                         }
251
252                         if (type == SD_BUS_TYPE_ARRAY)
253                                 fprintf(f, "%sARRAY \"%s\" {\n", prefix, contents);
254                         else if (type == SD_BUS_TYPE_VARIANT)
255                                 fprintf(f, "%sVARIANT \"%s\" {\n", prefix, contents);
256                         else if (type == SD_BUS_TYPE_STRUCT)
257                                 fprintf(f, "%sSTRUCT \"%s\" {\n", prefix, contents);
258                         else if (type == SD_BUS_TYPE_DICT_ENTRY)
259                                 fprintf(f, "%sDICT_ENTRY \"%s\" {\n", prefix, contents);
260
261                         level ++;
262
263                         continue;
264                 }
265
266                 r = sd_bus_message_read_basic(m, type, &basic);
267                 if (r < 0) {
268                         log_error("Failed to get basic: %s", strerror(-r));
269                         return r;
270                 }
271
272                 assert(r > 0);
273
274                 switch (type) {
275
276                 case SD_BUS_TYPE_BYTE:
277                         fprintf(f, "%sBYTE %s%u%s;\n", prefix, ansi_highlight(), basic.u8, ansi_highlight_off());
278                         break;
279
280                 case SD_BUS_TYPE_BOOLEAN:
281                         fprintf(f, "%sBOOLEAN %s%s%s;\n", prefix, ansi_highlight(), yes_no(basic.i), ansi_highlight_off());
282                         break;
283
284                 case SD_BUS_TYPE_INT16:
285                         fprintf(f, "%sINT16 %s%i%s;\n", prefix, ansi_highlight(), basic.s16, ansi_highlight_off());
286                         break;
287
288                 case SD_BUS_TYPE_UINT16:
289                         fprintf(f, "%sUINT16 %s%u%s;\n", prefix, ansi_highlight(), basic.u16, ansi_highlight_off());
290                         break;
291
292                 case SD_BUS_TYPE_INT32:
293                         fprintf(f, "%sINT32 %s%i%s;\n", prefix, ansi_highlight(), basic.s32, ansi_highlight_off());
294                         break;
295
296                 case SD_BUS_TYPE_UINT32:
297                         fprintf(f, "%sUINT32 %s%u%s;\n", prefix, ansi_highlight(), basic.u32, ansi_highlight_off());
298                         break;
299
300                 case SD_BUS_TYPE_INT64:
301                         fprintf(f, "%sINT64 %s%lli%s;\n", prefix, ansi_highlight(), (long long) basic.s64, ansi_highlight_off());
302                         break;
303
304                 case SD_BUS_TYPE_UINT64:
305                         fprintf(f, "%sUINT64 %s%llu%s;\n", prefix, ansi_highlight(), (unsigned long long) basic.u64, ansi_highlight_off());
306                         break;
307
308                 case SD_BUS_TYPE_DOUBLE:
309                         fprintf(f, "%sDOUBLE %s%g%s;\n", prefix, ansi_highlight(), basic.d64, ansi_highlight_off());
310                         break;
311
312                 case SD_BUS_TYPE_STRING:
313                         fprintf(f, "%sSTRING \"%s%s%s\";\n", prefix, ansi_highlight(), basic.string, ansi_highlight_off());
314                         break;
315
316                 case SD_BUS_TYPE_OBJECT_PATH:
317                         fprintf(f, "%sOBJECT_PATH \"%s%s%s\";\n", prefix, ansi_highlight(), basic.string, ansi_highlight_off());
318                         break;
319
320                 case SD_BUS_TYPE_SIGNATURE:
321                         fprintf(f, "%sSIGNATURE \"%s%s%s\";\n", prefix, ansi_highlight(), basic.string, ansi_highlight_off());
322                         break;
323
324                 case SD_BUS_TYPE_UNIX_FD:
325                         fprintf(f, "%sUNIX_FD %s%i%s;\n", prefix, ansi_highlight(), basic.i, ansi_highlight_off());
326                         break;
327
328                 default:
329                         assert_not_reached("Unknown basic type.");
330                 }
331         }
332
333         fprintf(f, "  };\n\n");
334         return 0;
335 }