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 char **arg_matches = NULL;
40 static BusTransport arg_transport = BUS_TRANSPORT_LOCAL;
41 static char *arg_host = NULL;
42 static bool arg_user = false;
44 static void pager_open_if_enabled(void) {
46 /* Cache result before we open the pager */
53 static int list_bus_names(sd_bus *bus, char **argv) {
54 _cleanup_strv_free_ char **l = NULL;
61 r = sd_bus_list_names(bus, &l);
63 log_error("Failed to list names: %s", strerror(-r));
67 pager_open_if_enabled();
72 max_i = MAX(max_i, strlen(*i));
74 printf("%-*s %*s %-*s %-*s %-*s MACHINE\n",
75 (int) max_i, "NAME", 10, "PID", 15, "PROCESS", 16, "USER", 20, "CONNECTION");
78 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
79 _cleanup_free_ char *owner = NULL;
82 if (arg_no_unique && (*i)[0] == ':')
85 printf("%-*s", (int) max_i, *i);
87 r = sd_bus_get_owner_creds(bus, *i, SD_BUS_CREDS_UID|SD_BUS_CREDS_PID|SD_BUS_CREDS_COMM, &creds);
92 r = sd_bus_creds_get_pid(creds, &pid);
94 const char *comm = NULL;
96 sd_bus_creds_get_comm(creds, &comm);
98 printf(" %10lu %-15s", (unsigned long) pid, strna(comm));
102 r = sd_bus_creds_get_uid(creds, &uid);
104 _cleanup_free_ char *u = NULL;
106 u = uid_to_name(uid);
120 r = sd_bus_get_owner(bus, *i, &owner);
122 printf(" %-20s", owner);
126 r = sd_bus_get_owner_machine_id(bus, *i, &mid);
128 char m[SD_ID128_STRING_MAX];
129 printf(" %s\n", sd_id128_to_string(mid, m));
137 static int monitor(sd_bus *bus, char *argv[]) {
138 bool added_something = false;
142 STRV_FOREACH(i, argv+1) {
143 _cleanup_free_ char *m = NULL;
145 if (!service_name_is_valid(*i)) {
146 log_error("Invalid service name '%s'", *i);
150 m = strjoin("sender='", *i, "'", NULL);
154 r = sd_bus_add_match(bus, m, NULL, NULL);
156 log_error("Failed to add match: %s", strerror(-r));
160 added_something = true;
163 STRV_FOREACH(i, arg_matches) {
164 r = sd_bus_add_match(bus, *i, NULL, NULL);
166 log_error("Failed to add match: %s", strerror(-r));
170 added_something = true;
173 if (!added_something) {
174 r = sd_bus_add_match(bus, "", NULL, NULL);
176 log_error("Failed to add match: %s", strerror(-r));
182 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
184 r = sd_bus_process(bus, &m);
186 log_error("Failed to process bus: %s", strerror(-r));
191 bus_message_dump(m, stdout, true);
198 r = sd_bus_wait(bus, (uint64_t) -1);
200 log_error("Failed to wait for bus: %s", strerror(-r));
208 static int help(void) {
210 printf("%s [OPTIONS...] {COMMAND} ...\n\n"
211 "Introspect the bus.\n\n"
212 " -h --help Show this help\n"
213 " --version Show package version\n"
214 " --no-pager Do not pipe output into a pager\n"
215 " --system Connect to system bus\n"
216 " --user Connect to user bus\n"
217 " -H --host=[USER@]HOST Operate on remote host\n"
218 " -M --machine=CONTAINER Operate on local container\n"
219 " --address=ADDRESS Connect to bus specified by address\n"
220 " --no-unique Only show well-known names\n"
221 " --match=MATCH Only show matching messages\n\n"
223 " list List bus names\n"
224 " monitor [SERVICE...] Show bus traffic\n",
225 program_invocation_short_name);
230 static int parse_argv(int argc, char *argv[]) {
242 static const struct option options[] = {
243 { "help", no_argument, NULL, 'h' },
244 { "version", no_argument, NULL, ARG_VERSION },
245 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
246 { "system", no_argument, NULL, ARG_SYSTEM },
247 { "user", no_argument, NULL, ARG_USER },
248 { "address", required_argument, NULL, ARG_ADDRESS },
249 { "no-unique", no_argument, NULL, ARG_NO_UNIQUE },
250 { "match", required_argument, NULL, ARG_MATCH },
251 { "host", required_argument, NULL, 'H' },
252 { "machine", required_argument, NULL, 'M' },
261 while ((c = getopt_long(argc, argv, "hH:M:", options, NULL)) >= 0) {
269 puts(PACKAGE_STRING);
270 puts(SYSTEMD_FEATURES);
286 arg_address = optarg;
290 arg_no_unique = true;
294 if (strv_extend(&arg_matches, optarg) < 0)
299 arg_transport = BUS_TRANSPORT_REMOTE;
304 arg_transport = BUS_TRANSPORT_CONTAINER;
312 assert_not_reached("Unhandled option");
319 static int busctl_main(sd_bus *bus, int argc, char *argv[]) {
322 if (optind >= argc ||
323 streq(argv[optind], "list"))
324 return list_bus_names(bus, argv + optind);
326 if (streq(argv[optind], "monitor"))
327 return monitor(bus, argv + optind);
329 if (streq(argv[optind], "help"))
332 log_error("Unknown command '%s'", argv[optind]);
336 int main(int argc, char *argv[]) {
337 _cleanup_bus_unref_ sd_bus *bus = NULL;
340 log_parse_environment();
343 r = parse_argv(argc, argv);
348 r = sd_bus_new(&bus);
350 log_error("Failed to allocate bus: %s", strerror(-r));
354 r = sd_bus_set_address(bus, arg_address);
356 log_error("Failed to set address: %s", strerror(-r));
360 r = sd_bus_set_bus_client(bus, true);
362 log_error("Failed to set bus client: %s", strerror(-r));
366 r = sd_bus_start(bus);
368 r = bus_open_transport(arg_transport, arg_host, arg_user, &bus);
371 log_error("Failed to connect to bus: %s", strerror(-r));
375 r = busctl_main(bus, argc, argv);
380 strv_free(arg_matches);
382 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;