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_free_ char *owner = NULL;
83 if (arg_no_unique && (*i)[0] == ':')
86 printf("%-*s", (int) max_i, *i);
88 r = sd_bus_get_owner_pid(bus, *i, &pid);
90 _cleanup_free_ char *comm = NULL;
92 printf(" %10lu", (unsigned long) pid);
94 get_process_comm(pid, &comm);
95 printf(" %-15s", strna(comm));
99 r = sd_bus_get_owner_uid(bus, *i, &uid);
101 _cleanup_free_ char *u = NULL;
103 u = uid_to_name(uid);
114 r = sd_bus_get_owner(bus, *i, &owner);
116 printf(" %-20s", owner);
120 r = sd_bus_get_owner_machine_id(bus, *i, &mid);
122 char m[SD_ID128_STRING_MAX];
123 printf(" %s\n", sd_id128_to_string(mid, m));
131 static int monitor(sd_bus *bus, char *argv[]) {
132 bool added_something = false;
136 STRV_FOREACH(i, argv+1) {
137 _cleanup_free_ char *m = NULL;
139 if (!service_name_is_valid(*i)) {
140 log_error("Invalid service name '%s'", *i);
144 m = strjoin("sender='", *i, "'", NULL);
148 r = sd_bus_add_match(bus, m, NULL, NULL);
150 log_error("Failed to add match: %s", strerror(-r));
154 added_something = true;
157 STRV_FOREACH(i, arg_matches) {
158 r = sd_bus_add_match(bus, *i, NULL, NULL);
160 log_error("Failed to add match: %s", strerror(-r));
164 added_something = true;
167 if (!added_something) {
168 r = sd_bus_add_match(bus, "", NULL, NULL);
170 log_error("Failed to add match: %s", strerror(-r));
176 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
178 r = sd_bus_process(bus, &m);
180 log_error("Failed to process bus: %s", strerror(-r));
185 bus_message_dump(m, stdout, true);
192 r = sd_bus_wait(bus, (uint64_t) -1);
194 log_error("Failed to wait for bus: %s", strerror(-r));
202 static int help(void) {
204 printf("%s [OPTIONS...] {COMMAND} ...\n\n"
205 "Introspect the bus.\n\n"
206 " -h --help Show this help\n"
207 " --version Show package version\n"
208 " --no-pager Do not pipe output into a pager\n"
209 " --system Connect to system bus\n"
210 " --user Connect to user bus\n"
211 " -H --host=[USER@]HOST Operate on remote host\n"
212 " -M --machine=CONTAINER Operate on local container\n"
213 " --address=ADDRESS Connect to bus specified by address\n"
214 " --no-unique Only show well-known names\n"
215 " --match=MATCH Only show matching messages\n\n"
217 " list List bus names\n"
218 " monitor [SERVICE...] Show bus traffic\n",
219 program_invocation_short_name);
224 static int parse_argv(int argc, char *argv[]) {
236 static const struct option options[] = {
237 { "help", no_argument, NULL, 'h' },
238 { "version", no_argument, NULL, ARG_VERSION },
239 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
240 { "system", no_argument, NULL, ARG_SYSTEM },
241 { "user", no_argument, NULL, ARG_USER },
242 { "address", required_argument, NULL, ARG_ADDRESS },
243 { "no-unique", no_argument, NULL, ARG_NO_UNIQUE },
244 { "match", required_argument, NULL, ARG_MATCH },
245 { "host", required_argument, NULL, 'H' },
246 { "machine", required_argument, NULL, 'M' },
255 while ((c = getopt_long(argc, argv, "hH:M:", options, NULL)) >= 0) {
263 puts(PACKAGE_STRING);
264 puts(SYSTEMD_FEATURES);
280 arg_address = optarg;
284 arg_no_unique = true;
288 if (strv_extend(&arg_matches, optarg) < 0)
293 arg_transport = BUS_TRANSPORT_REMOTE;
298 arg_transport = BUS_TRANSPORT_CONTAINER;
306 assert_not_reached("Unhandled option");
313 static int busctl_main(sd_bus *bus, int argc, char *argv[]) {
316 if (optind >= argc ||
317 streq(argv[optind], "list"))
318 return list_bus_names(bus, argv + optind);
320 if (streq(argv[optind], "monitor"))
321 return monitor(bus, argv + optind);
323 if (streq(argv[optind], "help"))
326 log_error("Unknown command '%s'", argv[optind]);
330 int main(int argc, char *argv[]) {
331 _cleanup_bus_unref_ sd_bus *bus = NULL;
334 log_parse_environment();
337 r = parse_argv(argc, argv);
342 r = sd_bus_new(&bus);
344 log_error("Failed to allocate bus: %s", strerror(-r));
348 r = sd_bus_set_address(bus, arg_address);
350 log_error("Failed to set address: %s", strerror(-r));
354 r = sd_bus_set_bus_client(bus, true);
356 log_error("Failed to set bus client: %s", strerror(-r));
360 r = sd_bus_start(bus);
362 r = bus_open_transport(arg_transport, arg_host, arg_user, &bus);
365 log_error("Failed to connect to bus: %s", strerror(-r));
369 r = busctl_main(bus, argc, argv);
374 strv_free(arg_matches);
376 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;