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