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 printf("%-*s", (int) max_i, *i);
113 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);
119 r = sd_bus_creds_get_pid(creds, &pid);
121 const char *comm = NULL;
123 sd_bus_creds_get_comm(creds, &comm);
125 printf(" %10lu %-15s", (unsigned long) pid, strna(comm));
127 fputs(" - - ", stdout);
129 r = sd_bus_creds_get_uid(creds, &uid);
131 _cleanup_free_ char *u = NULL;
133 u = uid_to_name(uid);
142 fputs(" - ", stdout);
144 r = sd_bus_creds_get_unique_name(creds, &unique);
146 printf(" %-20s", unique);
148 fputs(" - ", stdout);
156 r = sd_bus_get_owner_machine_id(bus, *i, &mid);
158 char m[SD_ID128_STRING_MAX];
159 printf(" %s\n", sd_id128_to_string(mid, m));
168 static int monitor(sd_bus *bus, char *argv[]) {
169 bool added_something = false;
173 STRV_FOREACH(i, argv+1) {
174 _cleanup_free_ char *m = NULL;
176 if (!service_name_is_valid(*i)) {
177 log_error("Invalid service name '%s'", *i);
181 m = strjoin("sender='", *i, "'", NULL);
185 r = sd_bus_add_match(bus, m, NULL, NULL);
187 log_error("Failed to add match: %s", strerror(-r));
191 added_something = true;
194 STRV_FOREACH(i, arg_matches) {
195 r = sd_bus_add_match(bus, *i, NULL, NULL);
197 log_error("Failed to add match: %s", strerror(-r));
201 added_something = true;
204 if (!added_something) {
205 r = sd_bus_add_match(bus, "", NULL, NULL);
207 log_error("Failed to add match: %s", strerror(-r));
213 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
215 r = sd_bus_process(bus, &m);
217 log_error("Failed to process bus: %s", strerror(-r));
222 bus_message_dump(m, stdout, true);
229 r = sd_bus_wait(bus, (uint64_t) -1);
231 log_error("Failed to wait for bus: %s", strerror(-r));
237 static int status(sd_bus *bus, char *argv[]) {
238 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
244 if (strv_length(argv) != 2) {
245 log_error("Expects one argument.");
249 r = parse_pid(argv[1], &pid);
251 r = sd_bus_get_owner(bus, argv[1], _SD_BUS_CREDS_ALL, &creds);
253 r = sd_bus_creds_new_from_pid(pid, _SD_BUS_CREDS_ALL, &creds);
256 log_error("Failed to get credentials: %s", strerror(-r));
260 bus_creds_dump(creds, NULL);
264 static int help(void) {
266 printf("%s [OPTIONS...] {COMMAND} ...\n\n"
267 "Introspect the bus.\n\n"
268 " -h --help Show this help\n"
269 " --version Show package version\n"
270 " --no-pager Do not pipe output into a pager\n"
271 " --system Connect to system bus\n"
272 " --user Connect to user bus\n"
273 " -H --host=[USER@]HOST Operate on remote host\n"
274 " -M --machine=CONTAINER Operate on local container\n"
275 " --address=ADDRESS Connect to bus specified by address\n"
276 " --no-unique Only show well-known names\n"
277 " --no-machine Don't show machine ID column in list\n"
278 " --match=MATCH Only show matching messages\n\n"
280 " list List bus names\n"
281 " monitor [SERVICE...] Show bus traffic\n"
282 " status ENDPOINT Show endpoint status\n"
283 " help Show this help\n",
284 program_invocation_short_name);
289 static int parse_argv(int argc, char *argv[]) {
302 static const struct option options[] = {
303 { "help", no_argument, NULL, 'h' },
304 { "version", no_argument, NULL, ARG_VERSION },
305 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
306 { "system", no_argument, NULL, ARG_SYSTEM },
307 { "user", no_argument, NULL, ARG_USER },
308 { "address", required_argument, NULL, ARG_ADDRESS },
309 { "no-unique", no_argument, NULL, ARG_NO_UNIQUE },
310 { "no-machine", no_argument, NULL, ARG_NO_MACHINE },
311 { "match", required_argument, NULL, ARG_MATCH },
312 { "host", required_argument, NULL, 'H' },
313 { "machine", required_argument, NULL, 'M' },
322 while ((c = getopt_long(argc, argv, "hH:M:", options, NULL)) >= 0) {
330 puts(PACKAGE_STRING);
331 puts(SYSTEMD_FEATURES);
347 arg_address = optarg;
351 arg_no_unique = true;
355 arg_no_machine = true;
359 if (strv_extend(&arg_matches, optarg) < 0)
364 arg_transport = BUS_TRANSPORT_REMOTE;
369 arg_transport = BUS_TRANSPORT_CONTAINER;
377 assert_not_reached("Unhandled option");
384 static int busctl_main(sd_bus *bus, int argc, char *argv[]) {
387 if (optind >= argc ||
388 streq(argv[optind], "list"))
389 return list_bus_names(bus, argv + optind);
391 if (streq(argv[optind], "monitor"))
392 return monitor(bus, argv + optind);
394 if (streq(argv[optind], "status"))
395 return status(bus, argv + optind);
397 if (streq(argv[optind], "help"))
400 log_error("Unknown command '%s'", argv[optind]);
404 int main(int argc, char *argv[]) {
405 _cleanup_bus_unref_ sd_bus *bus = NULL;
408 log_parse_environment();
411 r = parse_argv(argc, argv);
416 r = sd_bus_new(&bus);
418 log_error("Failed to allocate bus: %s", strerror(-r));
422 r = sd_bus_set_address(bus, arg_address);
424 log_error("Failed to set address: %s", strerror(-r));
428 r = sd_bus_set_bus_client(bus, true);
430 log_error("Failed to set bus client: %s", strerror(-r));
434 r = sd_bus_start(bus);
436 r = bus_open_transport(arg_transport, arg_host, arg_user, &bus);
439 log_error("Failed to connect to bus: %s", strerror(-r));
443 r = busctl_main(bus, argc, argv);
448 strv_free(arg_matches);
450 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;