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 char *arg_address = NULL;
38 static bool arg_unique = false;
39 static bool arg_acquired = false;
40 static bool arg_activatable = false;
41 static bool arg_show_machine = false;
42 static char **arg_matches = NULL;
43 static BusTransport arg_transport = BUS_TRANSPORT_LOCAL;
44 static char *arg_host = NULL;
45 static bool arg_user = false;
47 static void pager_open_if_enabled(void) {
49 /* Cache result before we open the pager */
56 static int list_bus_names(sd_bus *bus, char **argv) {
57 _cleanup_strv_free_ char **acquired = NULL, **activatable = NULL;
58 _cleanup_free_ char **merged = NULL;
59 _cleanup_hashmap_free_ Hashmap *names = NULL;
70 r = sd_bus_list_names(bus, (arg_acquired || arg_unique) ? &acquired : NULL, arg_activatable ? &activatable : NULL);
72 log_error("Failed to list names: %s", strerror(-r));
76 pager_open_if_enabled();
78 names = hashmap_new(string_hash_func, string_compare_func);
82 STRV_FOREACH(i, acquired) {
83 max_i = MAX(max_i, strlen(*i));
85 r = hashmap_put(names, *i, INT_TO_PTR(1));
87 log_error("Failed to add to hashmap: %s", strerror(-r));
92 STRV_FOREACH(i, activatable) {
93 max_i = MAX(max_i, strlen(*i));
95 r = hashmap_put(names, *i, INT_TO_PTR(2));
96 if (r < 0 && r != -EEXIST) {
97 log_error("Failed to add to hashmap: %s", strerror(-r));
102 merged = new(char*, hashmap_size(names) + 1);
103 HASHMAP_FOREACH_KEY(v, k, names, iterator)
109 printf("%-*s %*s %-*s %-*s %-*s %-*s %-*s",
110 (int) max_i, "NAME", 10, "PID", 15, "PROCESS", 16, "USER", 13, "CONNECTION", 25, "UNIT", 10, "SESSION");
112 if (arg_show_machine)
117 STRV_FOREACH(i, merged) {
118 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
121 if (hashmap_get(names, *i) == INT_TO_PTR(2)) {
124 printf("%-*s", (int) max_i, *i);
125 printf(" - - - (activatable) - - ");
126 if (arg_show_machine)
134 if (!arg_unique && (*i)[0] == ':')
137 if (!arg_acquired && (*i)[0] != ':')
140 printf("%-*s", (int) max_i, *i);
142 r = sd_bus_get_owner(bus, *i, SD_BUS_CREDS_UID|SD_BUS_CREDS_PID|SD_BUS_CREDS_COMM|SD_BUS_CREDS_UNIQUE_NAME|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_SESSION, &creds);
144 const char *unique, *session, *unit;
148 r = sd_bus_creds_get_pid(creds, &pid);
150 const char *comm = NULL;
152 sd_bus_creds_get_comm(creds, &comm);
154 printf(" %10lu %-15s", (unsigned long) pid, strna(comm));
156 fputs(" - - ", stdout);
158 r = sd_bus_creds_get_uid(creds, &uid);
160 _cleanup_free_ char *u = NULL;
162 u = uid_to_name(uid);
171 fputs(" - ", stdout);
173 r = sd_bus_creds_get_unique_name(creds, &unique);
175 printf(" %-13s", unique);
177 fputs(" - ", stdout);
179 r = sd_bus_creds_get_unit(creds, &unit);
181 _cleanup_free_ char *e;
183 e = ellipsize(unit, 25, 100);
189 fputs(" - ", stdout);
191 r = sd_bus_creds_get_session(creds, &session);
193 printf(" %-10s", session);
195 fputs(" - ", stdout);
198 printf(" - - - - - - ");
200 if (arg_show_machine) {
201 r = sd_bus_get_owner_machine_id(bus, *i, &mid);
203 char m[SD_ID128_STRING_MAX];
204 printf(" %s\n", sd_id128_to_string(mid, m));
214 static int monitor(sd_bus *bus, char *argv[]) {
215 bool added_something = false;
219 STRV_FOREACH(i, argv+1) {
220 _cleanup_free_ char *m = NULL;
222 if (!service_name_is_valid(*i)) {
223 log_error("Invalid service name '%s'", *i);
227 m = strjoin("sender='", *i, "'", NULL);
231 r = sd_bus_add_match(bus, m, NULL, NULL);
233 log_error("Failed to add match: %s", strerror(-r));
237 added_something = true;
240 STRV_FOREACH(i, arg_matches) {
241 r = sd_bus_add_match(bus, *i, NULL, NULL);
243 log_error("Failed to add match: %s", strerror(-r));
247 added_something = true;
250 if (!added_something) {
251 r = sd_bus_add_match(bus, "", NULL, NULL);
253 log_error("Failed to add match: %s", strerror(-r));
259 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
261 r = sd_bus_process(bus, &m);
263 log_error("Failed to process bus: %s", strerror(-r));
268 bus_message_dump(m, stdout, true);
275 r = sd_bus_wait(bus, (uint64_t) -1);
277 log_error("Failed to wait for bus: %s", strerror(-r));
283 static int status(sd_bus *bus, char *argv[]) {
284 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
290 if (strv_length(argv) != 2) {
291 log_error("Expects one argument.");
295 r = parse_pid(argv[1], &pid);
297 r = sd_bus_get_owner(bus, argv[1], _SD_BUS_CREDS_ALL, &creds);
299 r = sd_bus_creds_new_from_pid(pid, _SD_BUS_CREDS_ALL, &creds);
302 log_error("Failed to get credentials: %s", strerror(-r));
306 bus_creds_dump(creds, NULL);
310 static int help(void) {
312 printf("%s [OPTIONS...] {COMMAND} ...\n\n"
313 "Introspect the bus.\n\n"
314 " -h --help Show this help\n"
315 " --version Show package version\n"
316 " --no-pager Do not pipe output into a pager\n"
317 " --system Connect to system bus\n"
318 " --user Connect to user bus\n"
319 " -H --host=[USER@]HOST Operate on remote host\n"
320 " -M --machine=CONTAINER Operate on local container\n"
321 " --address=ADDRESS Connect to bus specified by address\n"
322 " --show-machine Show machine ID column in list\n"
323 " --unique Only show unique names\n"
324 " --acquired Only show acquired names\n"
325 " --activatable Only show activatable names\n"
326 " --match=MATCH Only show matching messages\n\n"
328 " list List bus names\n"
329 " monitor [SERVICE...] Show bus traffic\n"
330 " status NAME Show name status\n"
331 " help Show this help\n",
332 program_invocation_short_name);
337 static int parse_argv(int argc, char *argv[]) {
352 static const struct option options[] = {
353 { "help", no_argument, NULL, 'h' },
354 { "version", no_argument, NULL, ARG_VERSION },
355 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
356 { "system", no_argument, NULL, ARG_SYSTEM },
357 { "user", no_argument, NULL, ARG_USER },
358 { "address", required_argument, NULL, ARG_ADDRESS },
359 { "show-machine", no_argument, NULL, ARG_SHOW_MACHINE },
360 { "unique", no_argument, NULL, ARG_UNIQUE },
361 { "acquired", no_argument, NULL, ARG_ACQUIRED },
362 { "activatable", no_argument, NULL, ARG_ACTIVATABLE },
363 { "match", required_argument, NULL, ARG_MATCH },
364 { "host", required_argument, NULL, 'H' },
365 { "machine", required_argument, NULL, 'M' },
374 while ((c = getopt_long(argc, argv, "hH:M:", options, NULL)) >= 0) {
382 puts(PACKAGE_STRING);
383 puts(SYSTEMD_FEATURES);
399 arg_address = optarg;
402 case ARG_SHOW_MACHINE:
403 arg_show_machine = true;
414 case ARG_ACTIVATABLE:
415 arg_activatable = true;
419 if (strv_extend(&arg_matches, optarg) < 0)
424 arg_transport = BUS_TRANSPORT_REMOTE;
429 arg_transport = BUS_TRANSPORT_CONTAINER;
437 assert_not_reached("Unhandled option");
441 if (!arg_unique && !arg_acquired && !arg_activatable)
442 arg_unique = arg_acquired = arg_activatable = true;
447 static int busctl_main(sd_bus *bus, int argc, char *argv[]) {
450 if (optind >= argc ||
451 streq(argv[optind], "list"))
452 return list_bus_names(bus, argv + optind);
454 if (streq(argv[optind], "monitor"))
455 return monitor(bus, argv + optind);
457 if (streq(argv[optind], "status"))
458 return status(bus, argv + optind);
460 if (streq(argv[optind], "help"))
463 log_error("Unknown command '%s'", argv[optind]);
467 int main(int argc, char *argv[]) {
468 _cleanup_bus_unref_ sd_bus *bus = NULL;
471 log_parse_environment();
474 r = parse_argv(argc, argv);
479 r = sd_bus_new(&bus);
481 log_error("Failed to allocate bus: %s", strerror(-r));
485 r = sd_bus_set_address(bus, arg_address);
487 log_error("Failed to set address: %s", strerror(-r));
491 r = sd_bus_set_bus_client(bus, true);
493 log_error("Failed to set bus client: %s", strerror(-r));
497 r = sd_bus_start(bus);
499 r = bus_open_transport(arg_transport, arg_host, arg_user, &bus);
502 log_error("Failed to connect to bus: %s", strerror(-r));
506 r = busctl_main(bus, argc, argv);
511 strv_free(arg_matches);
513 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;