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 **l = NULL;
62 r = sd_bus_list_names(bus, &l);
64 log_error("Failed to list names: %s", strerror(-r));
68 pager_open_if_enabled();
73 max_i = MAX(max_i, strlen(*i));
75 printf("%-*s %*s %-*s %-*s %-*s",
76 (int) max_i, "NAME", 10, "PID", 15, "PROCESS", 16, "USER", 20, "CONNECTION");
84 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
87 if (arg_no_unique && (*i)[0] == ':')
90 /* Skip the bus driver */
91 if (streq(*i, "org.freedesktop.DBus"))
94 printf("%-*s", (int) max_i, *i);
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);
102 r = sd_bus_creds_get_pid(creds, &pid);
104 const char *comm = NULL;
106 sd_bus_creds_get_comm(creds, &comm);
108 printf(" %10lu %-15s", (unsigned long) pid, strna(comm));
110 fputs(" - - ", stdout);
112 r = sd_bus_creds_get_uid(creds, &uid);
114 _cleanup_free_ char *u = NULL;
116 u = uid_to_name(uid);
125 fputs(" - ", stdout);
127 r = sd_bus_creds_get_unique_name(creds, &unique);
129 printf(" %-20s", unique);
131 fputs(" - ", stdout);
139 r = sd_bus_get_owner_machine_id(bus, *i, &mid);
141 char m[SD_ID128_STRING_MAX];
142 printf(" %s\n", sd_id128_to_string(mid, m));
151 static int monitor(sd_bus *bus, char *argv[]) {
152 bool added_something = false;
156 STRV_FOREACH(i, argv+1) {
157 _cleanup_free_ char *m = NULL;
159 if (!service_name_is_valid(*i)) {
160 log_error("Invalid service name '%s'", *i);
164 m = strjoin("sender='", *i, "'", NULL);
168 r = sd_bus_add_match(bus, m, NULL, NULL);
170 log_error("Failed to add match: %s", strerror(-r));
174 added_something = true;
177 STRV_FOREACH(i, arg_matches) {
178 r = sd_bus_add_match(bus, *i, NULL, NULL);
180 log_error("Failed to add match: %s", strerror(-r));
184 added_something = true;
187 if (!added_something) {
188 r = sd_bus_add_match(bus, "", NULL, NULL);
190 log_error("Failed to add match: %s", strerror(-r));
196 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
198 r = sd_bus_process(bus, &m);
200 log_error("Failed to process bus: %s", strerror(-r));
205 bus_message_dump(m, stdout, true);
212 r = sd_bus_wait(bus, (uint64_t) -1);
214 log_error("Failed to wait for bus: %s", strerror(-r));
222 static int help(void) {
224 printf("%s [OPTIONS...] {COMMAND} ...\n\n"
225 "Introspect the bus.\n\n"
226 " -h --help Show this help\n"
227 " --version Show package version\n"
228 " --no-pager Do not pipe output into a pager\n"
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"
235 " --no-machine Don't show machine ID column in list\n"
236 " --match=MATCH Only show matching messages\n\n"
238 " list List bus names\n"
239 " monitor [SERVICE...] Show bus traffic\n",
240 program_invocation_short_name);
245 static int parse_argv(int argc, char *argv[]) {
258 static const struct option options[] = {
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' },
278 while ((c = getopt_long(argc, argv, "hH:M:", options, NULL)) >= 0) {
286 puts(PACKAGE_STRING);
287 puts(SYSTEMD_FEATURES);
303 arg_address = optarg;
307 arg_no_unique = true;
311 arg_no_machine = true;
315 if (strv_extend(&arg_matches, optarg) < 0)
320 arg_transport = BUS_TRANSPORT_REMOTE;
325 arg_transport = BUS_TRANSPORT_CONTAINER;
333 assert_not_reached("Unhandled option");
340 static int busctl_main(sd_bus *bus, int argc, char *argv[]) {
343 if (optind >= argc ||
344 streq(argv[optind], "list"))
345 return list_bus_names(bus, argv + optind);
347 if (streq(argv[optind], "monitor"))
348 return monitor(bus, argv + optind);
350 if (streq(argv[optind], "help"))
353 log_error("Unknown command '%s'", argv[optind]);
357 int main(int argc, char *argv[]) {
358 _cleanup_bus_unref_ sd_bus *bus = NULL;
361 log_parse_environment();
364 r = parse_argv(argc, argv);
369 r = sd_bus_new(&bus);
371 log_error("Failed to allocate bus: %s", strerror(-r));
375 r = sd_bus_set_address(bus, arg_address);
377 log_error("Failed to set address: %s", strerror(-r));
381 r = sd_bus_set_bus_client(bus, true);
383 log_error("Failed to set bus client: %s", strerror(-r));
387 r = sd_bus_start(bus);
389 r = bus_open_transport(arg_transport, arg_host, arg_user, &bus);
392 log_error("Failed to connect to bus: %s", strerror(-r));
396 r = busctl_main(bus, argc, argv);
401 strv_free(arg_matches);
403 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;