]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd-bus/busctl.c
bus: beautify bus_message_dump() output a bit
[thirdparty/systemd.git] / src / libsystemd-bus / busctl.c
CommitLineData
de1c301e
LP
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
1f849790
LP
22#include <getopt.h>
23
89ffcd2a
LP
24#include "strv.h"
25#include "util.h"
26#include "log.h"
1f849790
LP
27#include "build.h"
28#include "pager.h"
89ffcd2a 29
de1c301e 30#include "sd-bus.h"
89ffcd2a
LP
31#include "bus-message.h"
32#include "bus-internal.h"
40ca29a1 33#include "bus-util.h"
2b5c5383 34#include "bus-dump.h"
de1c301e 35
1f849790
LP
36static bool arg_no_pager = false;
37static char *arg_address = NULL;
1f849790
LP
38static bool arg_no_unique = false;
39static char **arg_matches = NULL;
d75edbd6
LP
40static BusTransport arg_transport = BUS_TRANSPORT_LOCAL;
41static char *arg_host = NULL;
42static bool arg_user = false;
1f849790
LP
43
44static void pager_open_if_enabled(void) {
45
46 /* Cache result before we open the pager */
47 if (arg_no_pager)
48 return;
49
50 pager_open(false);
51}
52
53static int list_bus_names(sd_bus *bus, char **argv) {
de1c301e
LP
54 _cleanup_strv_free_ char **l = NULL;
55 char **i;
56 int r;
89ffcd2a 57 size_t max_i = 0;
de1c301e 58
1f849790 59 assert(bus);
de1c301e
LP
60
61 r = sd_bus_list_names(bus, &l);
62 if (r < 0) {
63 log_error("Failed to list names: %s", strerror(-r));
1f849790 64 return r;
de1c301e
LP
65 }
66
1f849790
LP
67 pager_open_if_enabled();
68
89ffcd2a
LP
69 strv_sort(l);
70
71 STRV_FOREACH(i, l)
72 max_i = MAX(max_i, strlen(*i));
73
7b0b392f
LP
74 printf("%-*s %*s %-*s %-*s %-*s MACHINE\n",
75 (int) max_i, "NAME", 10, "PID", 15, "PROCESS", 16, "USER", 20, "CONNECTION");
89ffcd2a 76
de1c301e
LP
77 STRV_FOREACH(i, l) {
78 _cleanup_free_ char *owner = NULL;
7b0b392f 79 sd_id128_t mid;
89ffcd2a 80 pid_t pid;
de1c301e 81 uid_t uid;
de1c301e 82
1f849790
LP
83 if (arg_no_unique && (*i)[0] == ':')
84 continue;
89ffcd2a
LP
85
86 printf("%-*s", (int) max_i, *i);
de1c301e 87
89ffcd2a
LP
88 r = sd_bus_get_owner_pid(bus, *i, &pid);
89 if (r >= 0) {
90 _cleanup_free_ char *comm = NULL;
de1c301e 91
89ffcd2a 92 printf(" %10lu", (unsigned long) pid);
de1c301e 93
89ffcd2a
LP
94 get_process_comm(pid, &comm);
95 printf(" %-15s", strna(comm));
96 } else
97 printf(" - - ");
98
99 r = sd_bus_get_owner_uid(bus, *i, &uid);
100 if (r >= 0) {
101 _cleanup_free_ char *u = NULL;
102
103 u = uid_to_name(uid);
1f849790
LP
104 if (!u)
105 return log_oom();
89ffcd2a
LP
106
107 if (strlen(u) > 16)
108 u[16] = 0;
109
110 printf(" %-16s", u);
111 } else
112 printf(" - ");
113
114 r = sd_bus_get_owner(bus, *i, &owner);
115 if (r >= 0)
7b0b392f 116 printf(" %-20s", owner);
89ffcd2a 117 else
7b0b392f
LP
118 printf(" - ");
119
120 r = sd_bus_get_owner_machine_id(bus, *i, &mid);
121 if (r >= 0) {
122 char m[SD_ID128_STRING_MAX];
123 printf(" %s\n", sd_id128_to_string(mid, m));
124 } else
89ffcd2a 125 printf(" -\n");
de1c301e
LP
126 }
127
1f849790
LP
128 return 0;
129}
130
131static int monitor(sd_bus *bus, char *argv[]) {
132 char **i;
133 int r;
134
135 STRV_FOREACH(i, argv+1) {
136 _cleanup_free_ char *m = NULL;
137
138 if (!service_name_is_valid(*i)) {
139 log_error("Invalid service name '%s'", *i);
140 return -EINVAL;
141 }
142
143 m = strjoin("sender='", *i, "'", NULL);
144 if (!m)
145 return log_oom();
146
147 r = sd_bus_add_match(bus, m, NULL, NULL);
148 if (r < 0) {
149 log_error("Failed to add match: %s", strerror(-r));
150 return r;
151 }
152 }
153
154 STRV_FOREACH(i, arg_matches) {
155 r = sd_bus_add_match(bus, *i, NULL, NULL);
156 if (r < 0) {
157 log_error("Failed to add match: %s", strerror(-r));
158 return r;
159 }
160 }
161
162 for (;;) {
163 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
164
165 r = sd_bus_process(bus, &m);
166 if (r < 0) {
167 log_error("Failed to process bus: %s", strerror(-r));
168 return r;
169 }
170
171 if (m) {
c430fee6 172 bus_message_dump(m, stdout, true);
1f849790
LP
173 continue;
174 }
175
176 if (r > 0)
177 continue;
178
179 r = sd_bus_wait(bus, (uint64_t) -1);
180 if (r < 0) {
181 log_error("Failed to wait for bus: %s", strerror(-r));
182 return r;
183 }
184 }
185
186 return -EINVAL;
187}
188
189static int help(void) {
190
191 printf("%s [OPTIONS...] {COMMAND} ...\n\n"
192 "Introspect the bus.\n\n"
d75edbd6
LP
193 " -h --help Show this help\n"
194 " --version Show package version\n"
a86a47ce 195 " --no-pager Do not pipe output into a pager\n"
d75edbd6
LP
196 " --system Connect to system bus\n"
197 " --user Connect to user bus\n"
198 " -H --host=[USER@]HOST Operate on remote host\n"
199 " -M --machine=CONTAINER Operate on local container\n"
200 " --address=ADDRESS Connect to bus specified by address\n"
201 " --no-unique Only show well-known names\n"
a86a47ce 202 " --match=MATCH Only show matching messages\n\n"
1f849790 203 "Commands:\n"
d75edbd6
LP
204 " list List bus names\n"
205 " monitor [SERVICE...] Show bus traffic\n",
1f849790
LP
206 program_invocation_short_name);
207
208 return 0;
209}
210
211static int parse_argv(int argc, char *argv[]) {
212
213 enum {
214 ARG_VERSION = 0x100,
215 ARG_NO_PAGER,
216 ARG_SYSTEM,
217 ARG_USER,
218 ARG_ADDRESS,
219 ARG_MATCH,
220 ARG_NO_UNIQUE
221 };
222
223 static const struct option options[] = {
224 { "help", no_argument, NULL, 'h' },
225 { "version", no_argument, NULL, ARG_VERSION },
226 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
227 { "system", no_argument, NULL, ARG_SYSTEM },
228 { "user", no_argument, NULL, ARG_USER },
229 { "address", required_argument, NULL, ARG_ADDRESS },
230 { "no-unique", no_argument, NULL, ARG_NO_UNIQUE },
231 { "match", required_argument, NULL, ARG_MATCH },
8fe12d88
LP
232 { "host", required_argument, NULL, 'H' },
233 { "machine", required_argument, NULL, 'M' },
eb9da376 234 {},
1f849790
LP
235 };
236
237 int c;
238
239 assert(argc >= 0);
240 assert(argv);
241
d75edbd6 242 while ((c = getopt_long(argc, argv, "hH:M:", options, NULL)) >= 0) {
1f849790
LP
243
244 switch (c) {
245
246 case 'h':
247 return help();
248
249 case ARG_VERSION:
250 puts(PACKAGE_STRING);
251 puts(SYSTEMD_FEATURES);
252 return 0;
253
254 case ARG_NO_PAGER:
255 arg_no_pager = true;
256 break;
257
258 case ARG_USER:
259 arg_user = true;
260 break;
261
262 case ARG_SYSTEM:
263 arg_user = false;
264 break;
265
266 case ARG_ADDRESS:
267 arg_address = optarg;
268 break;
269
270 case ARG_NO_UNIQUE:
271 arg_no_unique = true;
272 break;
273
274 case ARG_MATCH:
275 if (strv_extend(&arg_matches, optarg) < 0)
276 return log_oom();
277 break;
278
d75edbd6
LP
279 case 'H':
280 arg_transport = BUS_TRANSPORT_REMOTE;
281 arg_host = optarg;
282 break;
283
284 case 'M':
285 arg_transport = BUS_TRANSPORT_CONTAINER;
286 arg_host = optarg;
287 break;
288
1f849790
LP
289 case '?':
290 return -EINVAL;
291
292 default:
eb9da376 293 assert_not_reached("Unhandled option");
1f849790
LP
294 }
295 }
296
297 return 1;
298}
299
300static int busctl_main(sd_bus *bus, int argc, char *argv[]) {
301 assert(bus);
302
303 if (optind >= argc ||
304 streq(argv[optind], "list"))
305 return list_bus_names(bus, argv + optind);
306
307 if (streq(argv[optind], "monitor"))
308 return monitor(bus, argv + optind);
309
310 if (streq(argv[optind], "help"))
311 return help();
312
313 log_error("Unknown command '%s'", argv[optind]);
314 return -EINVAL;
315}
316
317int main(int argc, char *argv[]) {
318 _cleanup_bus_unref_ sd_bus *bus = NULL;
319 int r;
320
321 log_parse_environment();
322 log_open();
323
324 r = parse_argv(argc, argv);
325 if (r <= 0)
326 goto finish;
327
328 if (arg_address) {
329 r = sd_bus_new(&bus);
330 if (r < 0) {
331 log_error("Failed to allocate bus: %s", strerror(-r));
332 goto finish;
333 }
334
335 r = sd_bus_set_address(bus, arg_address);
336 if (r < 0) {
337 log_error("Failed to set address: %s", strerror(-r));
338 goto finish;
339 }
340
341 r = sd_bus_set_bus_client(bus, true);
342 if (r < 0) {
343 log_error("Failed to set bus client: %s", strerror(-r));
344 goto finish;
345 }
346
347 r = sd_bus_start(bus);
d75edbd6
LP
348 } else
349 r = bus_open_transport(arg_transport, arg_host, arg_user, &bus);
1f849790
LP
350
351 if (r < 0) {
352 log_error("Failed to connect to bus: %s", strerror(-r));
353 goto finish;
354 }
355
356 r = busctl_main(bus, argc, argv);
357
358finish:
359 pager_close();
d75edbd6 360
1f849790 361 strv_free(arg_matches);
de1c301e 362
de1c301e
LP
363 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
364}