1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2013 Lennart Poettering
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.
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.
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/>.
31 #include "bus-message.h"
32 #include "bus-internal.h"
36 static bool arg_no_pager = false;
37 static bool arg_legend = true;
38 static char *arg_address = NULL;
39 static bool arg_unique = false;
40 static bool arg_acquired = false;
41 static bool arg_activatable = false;
42 static bool arg_show_machine = false;
43 static char **arg_matches = NULL;
44 static BusTransport arg_transport = BUS_TRANSPORT_LOCAL;
45 static char *arg_host = NULL;
46 static bool arg_user = false;
47 static size_t arg_snaplen = 4096;
49 static void pager_open_if_enabled(void) {
51 /* Cache result before we open the pager */
58 static int list_bus_names(sd_bus *bus, char **argv) {
59 _cleanup_strv_free_ char **acquired = NULL, **activatable = NULL;
60 _cleanup_free_ char **merged = NULL;
61 _cleanup_hashmap_free_ Hashmap *names = NULL;
72 r = sd_bus_list_names(bus, (arg_acquired || arg_unique) ? &acquired : NULL, arg_activatable ? &activatable : NULL);
74 log_error("Failed to list names: %s", strerror(-r));
78 pager_open_if_enabled();
80 names = hashmap_new(&string_hash_ops);
84 STRV_FOREACH(i, acquired) {
85 max_i = MAX(max_i, strlen(*i));
87 r = hashmap_put(names, *i, INT_TO_PTR(1));
89 log_error("Failed to add to hashmap: %s", strerror(-r));
94 STRV_FOREACH(i, activatable) {
95 max_i = MAX(max_i, strlen(*i));
97 r = hashmap_put(names, *i, INT_TO_PTR(2));
98 if (r < 0 && r != -EEXIST) {
99 log_error("Failed to add to hashmap: %s", strerror(-r));
104 merged = new(char*, hashmap_size(names) + 1);
105 HASHMAP_FOREACH_KEY(v, k, names, iterator)
112 printf("%-*s %*s %-*s %-*s %-*s %-*s %-*s %-*s",
113 (int) max_i, "NAME", 10, "PID", 15, "PROCESS", 16, "USER", 13, "CONNECTION", 25, "UNIT", 10, "SESSION", 19, "CONNECTION-NAME");
115 if (arg_show_machine)
121 STRV_FOREACH(i, merged) {
122 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
125 if (hashmap_get(names, *i) == INT_TO_PTR(2)) {
128 printf("%-*s", (int) max_i, *i);
129 printf(" - - - (activatable) - - ");
130 if (arg_show_machine)
138 if (!arg_unique && (*i)[0] == ':')
141 if (!arg_acquired && (*i)[0] != ':')
144 printf("%-*s", (int) max_i, *i);
146 r = sd_bus_get_name_creds(bus, *i,
147 SD_BUS_CREDS_UID|SD_BUS_CREDS_PID|SD_BUS_CREDS_COMM|
148 SD_BUS_CREDS_UNIQUE_NAME|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_SESSION|
149 SD_BUS_CREDS_CONNECTION_NAME, &creds);
151 const char *unique, *session, *unit, *cn;
155 r = sd_bus_creds_get_pid(creds, &pid);
157 const char *comm = NULL;
159 sd_bus_creds_get_comm(creds, &comm);
161 printf(" %10lu %-15s", (unsigned long) pid, strna(comm));
163 fputs(" - - ", stdout);
165 r = sd_bus_creds_get_uid(creds, &uid);
167 _cleanup_free_ char *u = NULL;
169 u = uid_to_name(uid);
178 fputs(" - ", stdout);
180 r = sd_bus_creds_get_unique_name(creds, &unique);
182 printf(" %-13s", unique);
184 fputs(" - ", stdout);
186 r = sd_bus_creds_get_unit(creds, &unit);
188 _cleanup_free_ char *e;
190 e = ellipsize(unit, 25, 100);
196 fputs(" - ", stdout);
198 r = sd_bus_creds_get_session(creds, &session);
200 printf(" %-10s", session);
202 fputs(" - ", stdout);
204 r = sd_bus_creds_get_connection_name(creds, &cn);
206 printf(" %-19s", cn);
208 fputs(" - ", stdout);
211 printf(" - - - - - - - ");
213 if (arg_show_machine) {
214 r = sd_bus_get_name_machine_id(bus, *i, &mid);
216 char m[SD_ID128_STRING_MAX];
217 printf(" %s\n", sd_id128_to_string(mid, m));
227 static int message_dump(sd_bus_message *m, FILE *f) {
228 return bus_message_dump(m, f, true);
231 static int message_pcap(sd_bus_message *m, FILE *f) {
232 return bus_message_pcap_frame(m, arg_snaplen, f);
235 static int monitor(sd_bus *bus, char *argv[], int (*dump)(sd_bus_message *m, FILE *f)) {
236 bool added_something = false;
240 STRV_FOREACH(i, argv+1) {
241 _cleanup_free_ char *m = NULL;
243 if (!service_name_is_valid(*i)) {
244 log_error("Invalid service name '%s'", *i);
248 m = strjoin("sender='", *i, "'", NULL);
252 r = sd_bus_add_match(bus, NULL, m, NULL, NULL);
254 log_error("Failed to add match: %s", strerror(-r));
258 added_something = true;
261 STRV_FOREACH(i, arg_matches) {
262 r = sd_bus_add_match(bus, NULL, *i, NULL, NULL);
264 log_error("Failed to add match: %s", strerror(-r));
268 added_something = true;
271 if (!added_something) {
272 r = sd_bus_add_match(bus, NULL, "", NULL, NULL);
274 log_error("Failed to add match: %s", strerror(-r));
280 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
282 r = sd_bus_process(bus, &m);
284 log_error("Failed to process bus: %s", strerror(-r));
296 r = sd_bus_wait(bus, (uint64_t) -1);
298 log_error("Failed to wait for bus: %s", strerror(-r));
304 static int capture(sd_bus *bus, char *argv[]) {
307 if (isatty(fileno(stdout)) > 0) {
308 log_error("Refusing to write message data to console, please redirect output to a file.");
312 bus_pcap_header(arg_snaplen, stdout);
314 r = monitor(bus, argv, message_pcap);
318 if (ferror(stdout)) {
319 log_error("Couldn't write capture file.");
326 static int status(sd_bus *bus, char *argv[]) {
327 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
333 if (strv_length(argv) != 2) {
334 log_error("Expects one argument.");
338 r = parse_pid(argv[1], &pid);
340 r = sd_bus_get_name_creds(bus, argv[1], _SD_BUS_CREDS_ALL, &creds);
342 r = sd_bus_creds_new_from_pid(&creds, pid, _SD_BUS_CREDS_ALL);
345 log_error("Failed to get credentials: %s", strerror(-r));
349 bus_creds_dump(creds, NULL);
353 static int help(void) {
354 printf("%s [OPTIONS...] {COMMAND} ...\n\n"
355 "Introspect the bus.\n\n"
356 " -h --help Show this help\n"
357 " --version Show package version\n"
358 " --no-pager Do not pipe output into a pager\n"
359 " --no-legend Do not show the headers and footers\n"
360 " --system Connect to system bus\n"
361 " --user Connect to user bus\n"
362 " -H --host=[USER@]HOST Operate on remote host\n"
363 " -M --machine=CONTAINER Operate on local container\n"
364 " --address=ADDRESS Connect to bus specified by address\n"
365 " --show-machine Show machine ID column in list\n"
366 " --unique Only show unique names\n"
367 " --acquired Only show acquired names\n"
368 " --activatable Only show activatable names\n"
369 " --match=MATCH Only show matching messages\n\n"
371 " list List bus names\n"
372 " monitor [SERVICE...] Show bus traffic\n"
373 " capture [SERVICE...] Capture bus traffic as pcap\n"
374 " status NAME Show name status\n"
375 " help Show this help\n"
376 , program_invocation_short_name);
381 static int parse_argv(int argc, char *argv[]) {
398 static const struct option options[] = {
399 { "help", no_argument, NULL, 'h' },
400 { "version", no_argument, NULL, ARG_VERSION },
401 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
402 { "no-legend", no_argument, NULL, ARG_NO_LEGEND },
403 { "system", no_argument, NULL, ARG_SYSTEM },
404 { "user", no_argument, NULL, ARG_USER },
405 { "address", required_argument, NULL, ARG_ADDRESS },
406 { "show-machine", no_argument, NULL, ARG_SHOW_MACHINE },
407 { "unique", no_argument, NULL, ARG_UNIQUE },
408 { "acquired", no_argument, NULL, ARG_ACQUIRED },
409 { "activatable", no_argument, NULL, ARG_ACTIVATABLE },
410 { "match", required_argument, NULL, ARG_MATCH },
411 { "host", required_argument, NULL, 'H' },
412 { "machine", required_argument, NULL, 'M' },
413 { "size", required_argument, NULL, ARG_SIZE },
422 while ((c = getopt_long(argc, argv, "hH:M:", options, NULL)) >= 0)
430 puts(PACKAGE_STRING);
431 puts(SYSTEMD_FEATURES);
451 arg_address = optarg;
454 case ARG_SHOW_MACHINE:
455 arg_show_machine = true;
466 case ARG_ACTIVATABLE:
467 arg_activatable = true;
471 if (strv_extend(&arg_matches, optarg) < 0)
478 r = parse_size(optarg, 0, &o);
480 log_error("Failed to parse size: %s", optarg);
484 if ((off_t) (size_t) o != o) {
485 log_error("Size out of range.");
489 arg_snaplen = (size_t) o;
494 arg_transport = BUS_TRANSPORT_REMOTE;
499 arg_transport = BUS_TRANSPORT_CONTAINER;
507 assert_not_reached("Unhandled option");
510 if (!arg_unique && !arg_acquired && !arg_activatable)
511 arg_unique = arg_acquired = arg_activatable = true;
516 static int busctl_main(sd_bus *bus, int argc, char *argv[]) {
519 if (optind >= argc ||
520 streq(argv[optind], "list"))
521 return list_bus_names(bus, argv + optind);
523 if (streq(argv[optind], "monitor"))
524 return monitor(bus, argv + optind, message_dump);
526 if (streq(argv[optind], "capture"))
527 return capture(bus, argv + optind);
529 if (streq(argv[optind], "status"))
530 return status(bus, argv + optind);
532 if (streq(argv[optind], "help"))
535 log_error("Unknown command '%s'", argv[optind]);
539 int main(int argc, char *argv[]) {
540 _cleanup_bus_close_unref_ sd_bus *bus = NULL;
543 log_parse_environment();
546 r = parse_argv(argc, argv);
550 r = sd_bus_new(&bus);
552 log_error("Failed to allocate bus: %s", strerror(-r));
556 if (streq_ptr(argv[optind], "monitor") ||
557 streq_ptr(argv[optind], "capture")) {
559 r = sd_bus_set_monitor(bus, true);
561 log_error("Failed to set monitor mode: %s", strerror(-r));
565 r = sd_bus_negotiate_creds(bus, _SD_BUS_CREDS_ALL);
567 log_error("Failed to enable credentials: %s", strerror(-r));
571 r = sd_bus_negotiate_timestamp(bus, true);
573 log_error("Failed to enable timestamps: %s", strerror(-r));
577 r = sd_bus_negotiate_fds(bus, true);
579 log_error("Failed to enable fds: %s", strerror(-r));
585 r = sd_bus_set_address(bus, arg_address);
587 switch (arg_transport) {
589 case BUS_TRANSPORT_LOCAL:
591 r = bus_set_address_user(bus);
593 r = bus_set_address_system(bus);
596 case BUS_TRANSPORT_REMOTE:
597 r = bus_set_address_system_remote(bus, arg_host);
600 case BUS_TRANSPORT_CONTAINER:
601 r = bus_set_address_system_container(bus, arg_host);
605 assert_not_reached("Hmm, unknown transport type.");
609 log_error("Failed to set address: %s", strerror(-r));
613 r = sd_bus_set_bus_client(bus, true);
615 log_error("Failed to set bus client: %s", strerror(-r));
619 r = sd_bus_start(bus);
621 log_error("Failed to connect to bus: %s", strerror(-r));
625 r = busctl_main(bus, argc, argv);
630 strv_free(arg_matches);
632 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;