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_no_unique = false;
39 static bool arg_no_machine = false;
40 static char **arg_matches = NULL;
41 static BusTransport arg_transport = BUS_TRANSPORT_LOCAL;
42 static char *arg_host = NULL;
43 static bool arg_user = false;
45 static void pager_open_if_enabled(void) {
47 /* Cache result before we open the pager */
54 static int list_bus_names(sd_bus *bus, char **argv) {
55 _cleanup_strv_free_ char **acquired = NULL, **activatable = NULL;
62 r = sd_bus_list_names(bus, &acquired, &activatable);
64 log_error("Failed to list names: %s", strerror(-r));
68 pager_open_if_enabled();
71 strv_sort(activatable);
73 STRV_FOREACH(i, acquired)
74 max_i = MAX(max_i, strlen(*i));
76 STRV_FOREACH(i, activatable)
77 max_i = MAX(max_i, strlen(*i));
79 printf("%-*s %*s %-*s %-*s %-*s",
80 (int) max_i, "NAME", 10, "PID", 15, "PROCESS", 16, "USER", 20, "CONNECTION");
87 STRV_FOREACH(i, activatable) {
89 /* Skip the bus driver */
90 if (streq(*i, "org.freedesktop.DBus"))
93 if (strv_contains(acquired, *i))
96 printf("%-*s", (int) max_i, *i);
97 printf(" - - - (activation) ");
104 STRV_FOREACH(i, acquired) {
105 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
108 if (arg_no_unique && (*i)[0] == ':')
111 /* Skip the bus driver */
112 if (streq(*i, "org.freedesktop.DBus"))
115 printf("%-*s", (int) max_i, *i);
117 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);
123 r = sd_bus_creds_get_pid(creds, &pid);
125 const char *comm = NULL;
127 sd_bus_creds_get_comm(creds, &comm);
129 printf(" %10lu %-15s", (unsigned long) pid, strna(comm));
131 fputs(" - - ", stdout);
133 r = sd_bus_creds_get_uid(creds, &uid);
135 _cleanup_free_ char *u = NULL;
137 u = uid_to_name(uid);
146 fputs(" - ", stdout);
148 r = sd_bus_creds_get_unique_name(creds, &unique);
150 printf(" %-20s", unique);
152 fputs(" - ", stdout);
160 r = sd_bus_get_owner_machine_id(bus, *i, &mid);
162 char m[SD_ID128_STRING_MAX];
163 printf(" %s\n", sd_id128_to_string(mid, m));
172 static int monitor(sd_bus *bus, char *argv[]) {
173 bool added_something = false;
177 STRV_FOREACH(i, argv+1) {
178 _cleanup_free_ char *m = NULL;
180 if (!service_name_is_valid(*i)) {
181 log_error("Invalid service name '%s'", *i);
185 m = strjoin("sender='", *i, "'", NULL);
189 r = sd_bus_add_match(bus, m, NULL, NULL);
191 log_error("Failed to add match: %s", strerror(-r));
195 added_something = true;
198 STRV_FOREACH(i, arg_matches) {
199 r = sd_bus_add_match(bus, *i, NULL, NULL);
201 log_error("Failed to add match: %s", strerror(-r));
205 added_something = true;
208 if (!added_something) {
209 r = sd_bus_add_match(bus, "", NULL, NULL);
211 log_error("Failed to add match: %s", strerror(-r));
217 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
219 r = sd_bus_process(bus, &m);
221 log_error("Failed to process bus: %s", strerror(-r));
226 bus_message_dump(m, stdout, true);
233 r = sd_bus_wait(bus, (uint64_t) -1);
235 log_error("Failed to wait for bus: %s", strerror(-r));
241 static int status(sd_bus *bus, char *argv[]) {
242 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
248 if (strv_length(argv) != 2) {
249 log_error("Expects one argument.");
253 r = parse_pid(argv[1], &pid);
255 r = sd_bus_get_owner(bus, argv[1], _SD_BUS_CREDS_ALL, &creds);
257 r = sd_bus_creds_new_from_pid(pid, _SD_BUS_CREDS_ALL, &creds);
260 log_error("Failed to get credentials: %s", strerror(-r));
264 bus_creds_dump(creds, NULL);
268 static int help(void) {
270 printf("%s [OPTIONS...] {COMMAND} ...\n\n"
271 "Introspect the bus.\n\n"
272 " -h --help Show this help\n"
273 " --version Show package version\n"
274 " --no-pager Do not pipe output into a pager\n"
275 " --system Connect to system bus\n"
276 " --user Connect to user bus\n"
277 " -H --host=[USER@]HOST Operate on remote host\n"
278 " -M --machine=CONTAINER Operate on local container\n"
279 " --address=ADDRESS Connect to bus specified by address\n"
280 " --no-unique Only show well-known names\n"
281 " --no-machine Don't show machine ID column in list\n"
282 " --match=MATCH Only show matching messages\n\n"
284 " list List bus names\n"
285 " monitor [SERVICE...] Show bus traffic\n"
286 " status ENDPOINT Show endpoint status\n"
287 " help Show this help\n",
288 program_invocation_short_name);
293 static int parse_argv(int argc, char *argv[]) {
306 static const struct option options[] = {
307 { "help", no_argument, NULL, 'h' },
308 { "version", no_argument, NULL, ARG_VERSION },
309 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
310 { "system", no_argument, NULL, ARG_SYSTEM },
311 { "user", no_argument, NULL, ARG_USER },
312 { "address", required_argument, NULL, ARG_ADDRESS },
313 { "no-unique", no_argument, NULL, ARG_NO_UNIQUE },
314 { "no-machine", no_argument, NULL, ARG_NO_MACHINE },
315 { "match", required_argument, NULL, ARG_MATCH },
316 { "host", required_argument, NULL, 'H' },
317 { "machine", required_argument, NULL, 'M' },
326 while ((c = getopt_long(argc, argv, "hH:M:", options, NULL)) >= 0) {
334 puts(PACKAGE_STRING);
335 puts(SYSTEMD_FEATURES);
351 arg_address = optarg;
355 arg_no_unique = true;
359 arg_no_machine = true;
363 if (strv_extend(&arg_matches, optarg) < 0)
368 arg_transport = BUS_TRANSPORT_REMOTE;
373 arg_transport = BUS_TRANSPORT_CONTAINER;
381 assert_not_reached("Unhandled option");
388 static int busctl_main(sd_bus *bus, int argc, char *argv[]) {
391 if (optind >= argc ||
392 streq(argv[optind], "list"))
393 return list_bus_names(bus, argv + optind);
395 if (streq(argv[optind], "monitor"))
396 return monitor(bus, argv + optind);
398 if (streq(argv[optind], "status"))
399 return status(bus, argv + optind);
401 if (streq(argv[optind], "help"))
404 log_error("Unknown command '%s'", argv[optind]);
408 int main(int argc, char *argv[]) {
409 _cleanup_bus_unref_ sd_bus *bus = NULL;
412 log_parse_environment();
415 r = parse_argv(argc, argv);
420 r = sd_bus_new(&bus);
422 log_error("Failed to allocate bus: %s", strerror(-r));
426 r = sd_bus_set_address(bus, arg_address);
428 log_error("Failed to set address: %s", strerror(-r));
432 r = sd_bus_set_bus_client(bus, true);
434 log_error("Failed to set bus client: %s", strerror(-r));
438 r = sd_bus_start(bus);
440 r = bus_open_transport(arg_transport, arg_host, arg_user, &bus);
443 log_error("Failed to connect to bus: %s", strerror(-r));
447 r = busctl_main(bus, argc, argv);
452 strv_free(arg_matches);
454 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;