chiark / gitweb /
bus: set no_auto_start flag for GetMachineId calls, so that we don't auto-start if...
[elogind.git] / src / libsystemd-bus / busctl.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2013 Lennart Poettering
7
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.
12
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.
17
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/>.
20 ***/
21
22 #include <getopt.h>
23
24 #include "strv.h"
25 #include "util.h"
26 #include "log.h"
27 #include "build.h"
28 #include "pager.h"
29
30 #include "sd-bus.h"
31 #include "bus-message.h"
32 #include "bus-internal.h"
33 #include "bus-util.h"
34
35 static bool arg_no_pager = false;
36 static char *arg_address = NULL;
37 static bool arg_no_unique = false;
38 static char **arg_matches = NULL;
39 static BusTransport arg_transport = BUS_TRANSPORT_LOCAL;
40 static char *arg_host = NULL;
41 static bool arg_user = false;
42
43 static void pager_open_if_enabled(void) {
44
45         /* Cache result before we open the pager */
46         if (arg_no_pager)
47                 return;
48
49         pager_open(false);
50 }
51
52 static int list_bus_names(sd_bus *bus, char **argv) {
53         _cleanup_strv_free_ char **l = NULL;
54         char **i;
55         int r;
56         size_t max_i = 0;
57
58         assert(bus);
59
60         r = sd_bus_list_names(bus, &l);
61         if (r < 0) {
62                 log_error("Failed to list names: %s", strerror(-r));
63                 return r;
64         }
65
66         pager_open_if_enabled();
67
68         strv_sort(l);
69
70         STRV_FOREACH(i, l)
71                 max_i = MAX(max_i, strlen(*i));
72
73         printf("%-*s %*s %-*s %-*s CONNECTION\n",
74                (int) max_i, "NAME", 10, "PID", 15, "PROCESS", 16, "USER");
75
76         STRV_FOREACH(i, l) {
77                 _cleanup_free_ char *owner = NULL;
78                 pid_t pid;
79                 uid_t uid;
80
81                 if (arg_no_unique && (*i)[0] == ':')
82                         continue;
83
84                 printf("%-*s", (int) max_i, *i);
85
86                 r = sd_bus_get_owner_pid(bus, *i, &pid);
87                 if (r >= 0) {
88                         _cleanup_free_ char *comm = NULL;
89
90                         printf(" %10lu", (unsigned long) pid);
91
92                         get_process_comm(pid, &comm);
93                         printf(" %-15s", strna(comm));
94                 } else
95                         printf("          - -              ");
96
97                 r = sd_bus_get_owner_uid(bus, *i, &uid);
98                 if (r >= 0) {
99                         _cleanup_free_ char *u = NULL;
100
101                         u = uid_to_name(uid);
102                         if (!u)
103                                 return log_oom();
104
105                         if (strlen(u) > 16)
106                                 u[16] = 0;
107
108                         printf(" %-16s", u);
109                 } else
110                         printf(" -               ");
111
112                 r = sd_bus_get_owner(bus, *i, &owner);
113                 if (r >= 0)
114                         printf(" %s\n", owner);
115                 else
116                         printf(" -\n");
117         }
118
119         return 0;
120 }
121
122 static int monitor(sd_bus *bus, char *argv[]) {
123         char **i;
124         int r;
125
126         STRV_FOREACH(i, argv+1) {
127                 _cleanup_free_ char *m = NULL;
128
129                 if (!service_name_is_valid(*i)) {
130                         log_error("Invalid service name '%s'", *i);
131                         return -EINVAL;
132                 }
133
134                 m = strjoin("sender='", *i, "'", NULL);
135                 if (!m)
136                         return log_oom();
137
138                 r = sd_bus_add_match(bus, m, NULL, NULL);
139                 if (r < 0) {
140                         log_error("Failed to add match: %s", strerror(-r));
141                         return r;
142                 }
143         }
144
145         STRV_FOREACH(i, arg_matches) {
146                 r = sd_bus_add_match(bus, *i, NULL, NULL);
147                 if (r < 0) {
148                         log_error("Failed to add match: %s", strerror(-r));
149                         return r;
150                 }
151         }
152
153         for (;;) {
154                 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
155
156                 r = sd_bus_process(bus, &m);
157                 if (r < 0) {
158                         log_error("Failed to process bus: %s", strerror(-r));
159                         return r;
160                 }
161
162                 if (m) {
163                         bus_message_dump(m, stdout, true);
164                         continue;
165                 }
166
167                 if (r > 0)
168                         continue;
169
170                 r = sd_bus_wait(bus, (uint64_t) -1);
171                 if (r < 0) {
172                         log_error("Failed to wait for bus: %s", strerror(-r));
173                         return r;
174                 }
175         }
176
177         return -EINVAL;
178 }
179
180 static int help(void) {
181
182         printf("%s [OPTIONS...] {COMMAND} ...\n\n"
183                "Introspect the bus.\n\n"
184                "  -h --help               Show this help\n"
185                "     --version            Show package version\n"
186                "     --no-pager           Do not pipe output into a pager\n"
187                "     --system             Connect to system bus\n"
188                "     --user               Connect to user bus\n"
189                "  -H --host=[USER@]HOST   Operate on remote host\n"
190                "  -M --machine=CONTAINER  Operate on local container\n"
191                "     --address=ADDRESS    Connect to bus specified by address\n"
192                "     --no-unique          Only show well-known names\n"
193                "     --match=MATCH        Only show matching messages\n\n"
194                "Commands:\n"
195                "  list                    List bus names\n"
196                "  monitor [SERVICE...]    Show bus traffic\n",
197                program_invocation_short_name);
198
199         return 0;
200 }
201
202 static int parse_argv(int argc, char *argv[]) {
203
204         enum {
205                 ARG_VERSION = 0x100,
206                 ARG_NO_PAGER,
207                 ARG_SYSTEM,
208                 ARG_USER,
209                 ARG_ADDRESS,
210                 ARG_MATCH,
211                 ARG_NO_UNIQUE
212         };
213
214         static const struct option options[] = {
215                 { "help",      no_argument,       NULL, 'h'           },
216                 { "version",   no_argument,       NULL, ARG_VERSION   },
217                 { "no-pager",  no_argument,       NULL, ARG_NO_PAGER  },
218                 { "system",    no_argument,       NULL, ARG_SYSTEM    },
219                 { "user",      no_argument,       NULL, ARG_USER      },
220                 { "address",   required_argument, NULL, ARG_ADDRESS   },
221                 { "no-unique", no_argument,       NULL, ARG_NO_UNIQUE },
222                 { "match",     required_argument, NULL, ARG_MATCH     },
223                 { "host",      required_argument, NULL, 'H'           },
224                 { "machine",   required_argument, NULL, 'M'           },
225                 {},
226         };
227
228         int c;
229
230         assert(argc >= 0);
231         assert(argv);
232
233         while ((c = getopt_long(argc, argv, "hH:M:", options, NULL)) >= 0) {
234
235                 switch (c) {
236
237                 case 'h':
238                         return help();
239
240                 case ARG_VERSION:
241                         puts(PACKAGE_STRING);
242                         puts(SYSTEMD_FEATURES);
243                         return 0;
244
245                 case ARG_NO_PAGER:
246                         arg_no_pager = true;
247                         break;
248
249                 case ARG_USER:
250                         arg_user = true;
251                         break;
252
253                 case ARG_SYSTEM:
254                         arg_user = false;
255                         break;
256
257                 case ARG_ADDRESS:
258                         arg_address = optarg;
259                         break;
260
261                 case ARG_NO_UNIQUE:
262                         arg_no_unique = true;
263                         break;
264
265                 case ARG_MATCH:
266                         if (strv_extend(&arg_matches, optarg) < 0)
267                                 return log_oom();
268                         break;
269
270                 case 'H':
271                         arg_transport = BUS_TRANSPORT_REMOTE;
272                         arg_host = optarg;
273                         break;
274
275                 case 'M':
276                         arg_transport = BUS_TRANSPORT_CONTAINER;
277                         arg_host = optarg;
278                         break;
279
280                 case '?':
281                         return -EINVAL;
282
283                 default:
284                         assert_not_reached("Unhandled option");
285                 }
286         }
287
288         return 1;
289 }
290
291 static int busctl_main(sd_bus *bus, int argc, char *argv[]) {
292         assert(bus);
293
294         if (optind >= argc ||
295             streq(argv[optind], "list"))
296                 return list_bus_names(bus, argv + optind);
297
298         if (streq(argv[optind], "monitor"))
299                 return monitor(bus, argv + optind);
300
301         if (streq(argv[optind], "help"))
302                 return help();
303
304         log_error("Unknown command '%s'", argv[optind]);
305         return -EINVAL;
306 }
307
308 int main(int argc, char *argv[]) {
309         _cleanup_bus_unref_ sd_bus *bus = NULL;
310         int r;
311
312         log_parse_environment();
313         log_open();
314
315         r = parse_argv(argc, argv);
316         if (r <= 0)
317                 goto finish;
318
319         if (arg_address) {
320                 r = sd_bus_new(&bus);
321                 if (r < 0) {
322                         log_error("Failed to allocate bus: %s", strerror(-r));
323                         goto finish;
324                 }
325
326                 r = sd_bus_set_address(bus, arg_address);
327                 if (r < 0) {
328                         log_error("Failed to set address: %s", strerror(-r));
329                         goto finish;
330                 }
331
332                 r = sd_bus_set_bus_client(bus, true);
333                 if (r < 0) {
334                         log_error("Failed to set bus client: %s", strerror(-r));
335                         goto finish;
336                 }
337
338                 r = sd_bus_start(bus);
339         } else
340                 r = bus_open_transport(arg_transport, arg_host, arg_user, &bus);
341
342         if (r < 0) {
343                 log_error("Failed to connect to bus: %s", strerror(-r));
344                 goto finish;
345         }
346
347         r = busctl_main(bus, argc, argv);
348
349 finish:
350         pager_close();
351
352         strv_free(arg_matches);
353
354         return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
355 }