]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd-bus/busctl.c
nspawn: fix buggy mount_binds, now works for bind-mounted files
[thirdparty/systemd.git] / src / libsystemd-bus / busctl.c
CommitLineData
de1c301e
LP
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
1f849790
LP
22#include <getopt.h>
23
89ffcd2a
LP
24#include "strv.h"
25#include "util.h"
26#include "log.h"
1f849790
LP
27#include "build.h"
28#include "pager.h"
89ffcd2a 29
de1c301e 30#include "sd-bus.h"
89ffcd2a
LP
31#include "bus-message.h"
32#include "bus-internal.h"
40ca29a1 33#include "bus-util.h"
2b5c5383 34#include "bus-dump.h"
de1c301e 35
1f849790
LP
36static bool arg_no_pager = false;
37static char *arg_address = NULL;
1f849790 38static bool arg_no_unique = false;
a4297f08 39static bool arg_no_machine = false;
1f849790 40static char **arg_matches = NULL;
d75edbd6
LP
41static BusTransport arg_transport = BUS_TRANSPORT_LOCAL;
42static char *arg_host = NULL;
43static bool arg_user = false;
1f849790
LP
44
45static void pager_open_if_enabled(void) {
46
47 /* Cache result before we open the pager */
48 if (arg_no_pager)
49 return;
50
51 pager_open(false);
52}
53
54static int list_bus_names(sd_bus *bus, char **argv) {
71f2ab46 55 _cleanup_strv_free_ char **acquired = NULL, **activatable = NULL;
de1c301e
LP
56 char **i;
57 int r;
89ffcd2a 58 size_t max_i = 0;
de1c301e 59
1f849790 60 assert(bus);
de1c301e 61
71f2ab46 62 r = sd_bus_list_names(bus, &acquired, &activatable);
de1c301e
LP
63 if (r < 0) {
64 log_error("Failed to list names: %s", strerror(-r));
1f849790 65 return r;
de1c301e
LP
66 }
67
1f849790
LP
68 pager_open_if_enabled();
69
71f2ab46
LP
70 strv_sort(acquired);
71 strv_sort(activatable);
89ffcd2a 72
71f2ab46
LP
73 STRV_FOREACH(i, acquired)
74 max_i = MAX(max_i, strlen(*i));
75
76 STRV_FOREACH(i, activatable)
89ffcd2a
LP
77 max_i = MAX(max_i, strlen(*i));
78
a4297f08 79 printf("%-*s %*s %-*s %-*s %-*s",
7b0b392f 80 (int) max_i, "NAME", 10, "PID", 15, "PROCESS", 16, "USER", 20, "CONNECTION");
89ffcd2a 81
a4297f08
LP
82 if (!arg_no_machine)
83 puts(" MACHINE");
84 else
85 putchar('\n');
86
71f2ab46
LP
87 STRV_FOREACH(i, activatable) {
88
89 /* Skip the bus driver */
90 if (streq(*i, "org.freedesktop.DBus"))
91 continue;
92
93 if (strv_contains(acquired, *i))
94 continue;
95
96 printf("%-*s", (int) max_i, *i);
97 printf(" - - - (activation) ");
98 if (arg_no_machine)
99 putchar('\n');
100 else
101 puts(" -");
102 }
103
104 STRV_FOREACH(i, acquired) {
5b12334d 105 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
7b0b392f 106 sd_id128_t mid;
de1c301e 107
1f849790
LP
108 if (arg_no_unique && (*i)[0] == ':')
109 continue;
89ffcd2a 110
7f4cec69
LP
111 /* Skip the bus driver */
112 if (streq(*i, "org.freedesktop.DBus"))
113 continue;
114
89ffcd2a 115 printf("%-*s", (int) max_i, *i);
de1c301e 116
49b832c5 117 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);
89ffcd2a 118 if (r >= 0) {
49b832c5 119 const char *unique;
5b12334d
LP
120 pid_t pid;
121 uid_t uid;
de1c301e 122
5b12334d
LP
123 r = sd_bus_creds_get_pid(creds, &pid);
124 if (r >= 0) {
125 const char *comm = NULL;
de1c301e 126
5b12334d 127 sd_bus_creds_get_comm(creds, &comm);
89ffcd2a 128
5b12334d
LP
129 printf(" %10lu %-15s", (unsigned long) pid, strna(comm));
130 } else
a4297f08 131 fputs(" - - ", stdout);
89ffcd2a 132
5b12334d
LP
133 r = sd_bus_creds_get_uid(creds, &uid);
134 if (r >= 0) {
135 _cleanup_free_ char *u = NULL;
89ffcd2a 136
5b12334d
LP
137 u = uid_to_name(uid);
138 if (!u)
139 return log_oom();
89ffcd2a 140
5b12334d
LP
141 if (strlen(u) > 16)
142 u[16] = 0;
143
144 printf(" %-16s", u);
145 } else
a4297f08 146 fputs(" - ", stdout);
89ffcd2a 147
49b832c5
LP
148 r = sd_bus_creds_get_unique_name(creds, &unique);
149 if (r >= 0)
150 printf(" %-20s", unique);
a4297f08
LP
151 else
152 fputs(" - ", stdout);
7b0b392f 153
7b0b392f 154 } else
a4297f08
LP
155 printf(" - - - - ");
156
157 if (arg_no_machine)
158 putchar('\n');
159 else {
160 r = sd_bus_get_owner_machine_id(bus, *i, &mid);
161 if (r >= 0) {
162 char m[SD_ID128_STRING_MAX];
163 printf(" %s\n", sd_id128_to_string(mid, m));
164 } else
165 puts(" -");
166 }
de1c301e
LP
167 }
168
1f849790
LP
169 return 0;
170}
171
172static int monitor(sd_bus *bus, char *argv[]) {
b51f299a 173 bool added_something = false;
1f849790
LP
174 char **i;
175 int r;
176
177 STRV_FOREACH(i, argv+1) {
178 _cleanup_free_ char *m = NULL;
179
180 if (!service_name_is_valid(*i)) {
181 log_error("Invalid service name '%s'", *i);
182 return -EINVAL;
183 }
184
185 m = strjoin("sender='", *i, "'", NULL);
186 if (!m)
187 return log_oom();
188
189 r = sd_bus_add_match(bus, m, NULL, NULL);
190 if (r < 0) {
191 log_error("Failed to add match: %s", strerror(-r));
192 return r;
193 }
b51f299a
LP
194
195 added_something = true;
1f849790
LP
196 }
197
198 STRV_FOREACH(i, arg_matches) {
199 r = sd_bus_add_match(bus, *i, NULL, NULL);
200 if (r < 0) {
201 log_error("Failed to add match: %s", strerror(-r));
202 return r;
203 }
b51f299a
LP
204
205 added_something = true;
206 }
207
208 if (!added_something) {
209 r = sd_bus_add_match(bus, "", NULL, NULL);
210 if (r < 0) {
211 log_error("Failed to add match: %s", strerror(-r));
212 return r;
213 }
1f849790
LP
214 }
215
216 for (;;) {
217 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
218
219 r = sd_bus_process(bus, &m);
220 if (r < 0) {
221 log_error("Failed to process bus: %s", strerror(-r));
222 return r;
223 }
224
225 if (m) {
c430fee6 226 bus_message_dump(m, stdout, true);
1f849790
LP
227 continue;
228 }
229
230 if (r > 0)
231 continue;
232
233 r = sd_bus_wait(bus, (uint64_t) -1);
234 if (r < 0) {
235 log_error("Failed to wait for bus: %s", strerror(-r));
236 return r;
237 }
238 }
95c4fe82 239}
1f849790 240
95c4fe82
LP
241static int status(sd_bus *bus, char *argv[]) {
242 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
243 pid_t pid;
244 int r;
245
246 assert(bus);
247
248 if (strv_length(argv) != 2) {
249 log_error("Expects one argument.");
250 return -EINVAL;
251 }
252
253 r = parse_pid(argv[1], &pid);
254 if (r < 0)
255 r = sd_bus_get_owner(bus, argv[1], _SD_BUS_CREDS_ALL, &creds);
256 else
257 r = sd_bus_creds_new_from_pid(pid, _SD_BUS_CREDS_ALL, &creds);
258
259 if (r < 0) {
260 log_error("Failed to get credentials: %s", strerror(-r));
261 return r;
262 }
263
264 bus_creds_dump(creds, NULL);
265 return 0;
1f849790
LP
266}
267
268static int help(void) {
269
270 printf("%s [OPTIONS...] {COMMAND} ...\n\n"
271 "Introspect the bus.\n\n"
d75edbd6
LP
272 " -h --help Show this help\n"
273 " --version Show package version\n"
a86a47ce 274 " --no-pager Do not pipe output into a pager\n"
d75edbd6
LP
275 " --system Connect to system bus\n"
276 " --user Connect to user bus\n"
277 " -H --host=[USER@]HOST Operate on remote host\n"
278 " -M --machine=CONTAINER Operate on local container\n"
279 " --address=ADDRESS Connect to bus specified by address\n"
280 " --no-unique Only show well-known names\n"
b5dda4d8
LP
281 " --no-machine Don't show machine ID column in list\n"
282 " --match=MATCH Only show matching messages\n\n"
1f849790 283 "Commands:\n"
d75edbd6
LP
284 " list List bus names\n"
285 " monitor [SERVICE...] Show bus traffic\n",
86cb0691
ZJS
286 " status ENDPOINT Show endpoint status\n",
287 " help Show this help\n",
1f849790
LP
288 program_invocation_short_name);
289
290 return 0;
291}
292
293static int parse_argv(int argc, char *argv[]) {
294
295 enum {
296 ARG_VERSION = 0x100,
297 ARG_NO_PAGER,
298 ARG_SYSTEM,
299 ARG_USER,
300 ARG_ADDRESS,
301 ARG_MATCH,
a4297f08
LP
302 ARG_NO_UNIQUE,
303 ARG_NO_MACHINE,
1f849790
LP
304 };
305
306 static const struct option options[] = {
a4297f08
LP
307 { "help", no_argument, NULL, 'h' },
308 { "version", no_argument, NULL, ARG_VERSION },
309 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
310 { "system", no_argument, NULL, ARG_SYSTEM },
311 { "user", no_argument, NULL, ARG_USER },
312 { "address", required_argument, NULL, ARG_ADDRESS },
313 { "no-unique", no_argument, NULL, ARG_NO_UNIQUE },
314 { "no-machine", no_argument, NULL, ARG_NO_MACHINE },
315 { "match", required_argument, NULL, ARG_MATCH },
316 { "host", required_argument, NULL, 'H' },
317 { "machine", required_argument, NULL, 'M' },
eb9da376 318 {},
1f849790
LP
319 };
320
321 int c;
322
323 assert(argc >= 0);
324 assert(argv);
325
d75edbd6 326 while ((c = getopt_long(argc, argv, "hH:M:", options, NULL)) >= 0) {
1f849790
LP
327
328 switch (c) {
329
330 case 'h':
331 return help();
332
333 case ARG_VERSION:
334 puts(PACKAGE_STRING);
335 puts(SYSTEMD_FEATURES);
336 return 0;
337
338 case ARG_NO_PAGER:
339 arg_no_pager = true;
340 break;
341
342 case ARG_USER:
343 arg_user = true;
344 break;
345
346 case ARG_SYSTEM:
347 arg_user = false;
348 break;
349
350 case ARG_ADDRESS:
351 arg_address = optarg;
352 break;
353
354 case ARG_NO_UNIQUE:
355 arg_no_unique = true;
356 break;
357
a4297f08
LP
358 case ARG_NO_MACHINE:
359 arg_no_machine = true;
360 break;
361
1f849790
LP
362 case ARG_MATCH:
363 if (strv_extend(&arg_matches, optarg) < 0)
364 return log_oom();
365 break;
366
d75edbd6
LP
367 case 'H':
368 arg_transport = BUS_TRANSPORT_REMOTE;
369 arg_host = optarg;
370 break;
371
372 case 'M':
373 arg_transport = BUS_TRANSPORT_CONTAINER;
374 arg_host = optarg;
375 break;
376
1f849790
LP
377 case '?':
378 return -EINVAL;
379
380 default:
eb9da376 381 assert_not_reached("Unhandled option");
1f849790
LP
382 }
383 }
384
385 return 1;
386}
387
388static int busctl_main(sd_bus *bus, int argc, char *argv[]) {
389 assert(bus);
390
391 if (optind >= argc ||
392 streq(argv[optind], "list"))
393 return list_bus_names(bus, argv + optind);
394
395 if (streq(argv[optind], "monitor"))
396 return monitor(bus, argv + optind);
397
95c4fe82
LP
398 if (streq(argv[optind], "status"))
399 return status(bus, argv + optind);
400
1f849790
LP
401 if (streq(argv[optind], "help"))
402 return help();
403
404 log_error("Unknown command '%s'", argv[optind]);
405 return -EINVAL;
406}
407
408int main(int argc, char *argv[]) {
409 _cleanup_bus_unref_ sd_bus *bus = NULL;
410 int r;
411
412 log_parse_environment();
413 log_open();
414
415 r = parse_argv(argc, argv);
416 if (r <= 0)
417 goto finish;
418
419 if (arg_address) {
420 r = sd_bus_new(&bus);
421 if (r < 0) {
422 log_error("Failed to allocate bus: %s", strerror(-r));
423 goto finish;
424 }
425
426 r = sd_bus_set_address(bus, arg_address);
427 if (r < 0) {
428 log_error("Failed to set address: %s", strerror(-r));
429 goto finish;
430 }
431
432 r = sd_bus_set_bus_client(bus, true);
433 if (r < 0) {
434 log_error("Failed to set bus client: %s", strerror(-r));
435 goto finish;
436 }
437
438 r = sd_bus_start(bus);
d75edbd6
LP
439 } else
440 r = bus_open_transport(arg_transport, arg_host, arg_user, &bus);
1f849790
LP
441
442 if (r < 0) {
443 log_error("Failed to connect to bus: %s", strerror(-r));
444 goto finish;
445 }
446
447 r = busctl_main(bus, argc, argv);
448
449finish:
450 pager_close();
d75edbd6 451
1f849790 452 strv_free(arg_matches);
de1c301e 453
de1c301e
LP
454 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
455}