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;
85 _cleanup_free_ char *owner = NULL;
88 if (arg_no_unique && (*i)[0] == ':')
91 printf("%-*s", (int) max_i, *i);
93 r = sd_bus_get_owner(bus, *i, SD_BUS_CREDS_UID|SD_BUS_CREDS_PID|SD_BUS_CREDS_COMM, &owner, &creds);
98 r = sd_bus_creds_get_pid(creds, &pid);
100 const char *comm = NULL;
102 sd_bus_creds_get_comm(creds, &comm);
104 printf(" %10lu %-15s", (unsigned long) pid, strna(comm));
106 fputs(" - - ", stdout);
108 r = sd_bus_creds_get_uid(creds, &uid);
110 _cleanup_free_ char *u = NULL;
112 u = uid_to_name(uid);
121 fputs(" - ", stdout);
124 printf(" %-20s", owner);
126 fputs(" - ", stdout);
134 r = sd_bus_get_owner_machine_id(bus, *i, &mid);
136 char m[SD_ID128_STRING_MAX];
137 printf(" %s\n", sd_id128_to_string(mid, m));
146 static int monitor(sd_bus *bus, char *argv[]) {
147 bool added_something = false;
151 STRV_FOREACH(i, argv+1) {
152 _cleanup_free_ char *m = NULL;
154 if (!service_name_is_valid(*i)) {
155 log_error("Invalid service name '%s'", *i);
159 m = strjoin("sender='", *i, "'", NULL);
163 r = sd_bus_add_match(bus, m, NULL, NULL);
165 log_error("Failed to add match: %s", strerror(-r));
169 added_something = true;
172 STRV_FOREACH(i, arg_matches) {
173 r = sd_bus_add_match(bus, *i, NULL, NULL);
175 log_error("Failed to add match: %s", strerror(-r));
179 added_something = true;
182 if (!added_something) {
183 r = sd_bus_add_match(bus, "", NULL, NULL);
185 log_error("Failed to add match: %s", strerror(-r));
191 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
193 r = sd_bus_process(bus, &m);
195 log_error("Failed to process bus: %s", strerror(-r));
200 bus_message_dump(m, stdout, true);
207 r = sd_bus_wait(bus, (uint64_t) -1);
209 log_error("Failed to wait for bus: %s", strerror(-r));
217 static int help(void) {
219 printf("%s [OPTIONS...] {COMMAND} ...\n\n"
220 "Introspect the bus.\n\n"
221 " -h --help Show this help\n"
222 " --version Show package version\n"
223 " --no-pager Do not pipe output into a pager\n"
224 " --system Connect to system bus\n"
225 " --user Connect to user bus\n"
226 " -H --host=[USER@]HOST Operate on remote host\n"
227 " -M --machine=CONTAINER Operate on local container\n"
228 " --address=ADDRESS Connect to bus specified by address\n"
229 " --no-unique Only show well-known names\n"
230 " --no-machine Don't show machine ID column in list\n\n"
231 " --match=MATCH Only show matching messages\n"
233 " list List bus names\n"
234 " monitor [SERVICE...] Show bus traffic\n",
235 program_invocation_short_name);
240 static int parse_argv(int argc, char *argv[]) {
253 static const struct option options[] = {
254 { "help", no_argument, NULL, 'h' },
255 { "version", no_argument, NULL, ARG_VERSION },
256 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
257 { "system", no_argument, NULL, ARG_SYSTEM },
258 { "user", no_argument, NULL, ARG_USER },
259 { "address", required_argument, NULL, ARG_ADDRESS },
260 { "no-unique", no_argument, NULL, ARG_NO_UNIQUE },
261 { "no-machine", no_argument, NULL, ARG_NO_MACHINE },
262 { "match", required_argument, NULL, ARG_MATCH },
263 { "host", required_argument, NULL, 'H' },
264 { "machine", required_argument, NULL, 'M' },
273 while ((c = getopt_long(argc, argv, "hH:M:", options, NULL)) >= 0) {
281 puts(PACKAGE_STRING);
282 puts(SYSTEMD_FEATURES);
298 arg_address = optarg;
302 arg_no_unique = true;
306 arg_no_machine = true;
310 if (strv_extend(&arg_matches, optarg) < 0)
315 arg_transport = BUS_TRANSPORT_REMOTE;
320 arg_transport = BUS_TRANSPORT_CONTAINER;
328 assert_not_reached("Unhandled option");
335 static int busctl_main(sd_bus *bus, int argc, char *argv[]) {
338 if (optind >= argc ||
339 streq(argv[optind], "list"))
340 return list_bus_names(bus, argv + optind);
342 if (streq(argv[optind], "monitor"))
343 return monitor(bus, argv + optind);
345 if (streq(argv[optind], "help"))
348 log_error("Unknown command '%s'", argv[optind]);
352 int main(int argc, char *argv[]) {
353 _cleanup_bus_unref_ sd_bus *bus = NULL;
356 log_parse_environment();
359 r = parse_argv(argc, argv);
364 r = sd_bus_new(&bus);
366 log_error("Failed to allocate bus: %s", strerror(-r));
370 r = sd_bus_set_address(bus, arg_address);
372 log_error("Failed to set address: %s", strerror(-r));
376 r = sd_bus_set_bus_client(bus, true);
378 log_error("Failed to set bus client: %s", strerror(-r));
382 r = sd_bus_start(bus);
384 r = bus_open_transport(arg_transport, arg_host, arg_user, &bus);
387 log_error("Failed to connect to bus: %s", strerror(-r));
391 r = busctl_main(bus, argc, argv);
396 strv_free(arg_matches);
398 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;