]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd/sd-bus/busctl.c
nspawn: ignore EEXIST when creating mount point
[thirdparty/systemd.git] / src / libsystemd / sd-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 36static bool arg_no_pager = false;
17d47d8d 37static bool arg_legend = true;
1f849790 38static char *arg_address = NULL;
56e61788
LP
39static bool arg_unique = false;
40static bool arg_acquired = false;
41static bool arg_activatable = false;
42static bool arg_show_machine = false;
1f849790 43static char **arg_matches = NULL;
d75edbd6
LP
44static BusTransport arg_transport = BUS_TRANSPORT_LOCAL;
45static char *arg_host = NULL;
46static bool arg_user = false;
1f849790
LP
47
48static void pager_open_if_enabled(void) {
49
50 /* Cache result before we open the pager */
51 if (arg_no_pager)
52 return;
53
54 pager_open(false);
55}
56
57static int list_bus_names(sd_bus *bus, char **argv) {
71f2ab46 58 _cleanup_strv_free_ char **acquired = NULL, **activatable = NULL;
5e2f14e6
LP
59 _cleanup_free_ char **merged = NULL;
60 _cleanup_hashmap_free_ Hashmap *names = NULL;
de1c301e
LP
61 char **i;
62 int r;
89ffcd2a 63 size_t max_i = 0;
5e2f14e6
LP
64 unsigned n = 0;
65 void *v;
66 char *k;
67 Iterator iterator;
de1c301e 68
1f849790 69 assert(bus);
de1c301e 70
56e61788 71 r = sd_bus_list_names(bus, (arg_acquired || arg_unique) ? &acquired : NULL, arg_activatable ? &activatable : NULL);
de1c301e
LP
72 if (r < 0) {
73 log_error("Failed to list names: %s", strerror(-r));
1f849790 74 return r;
de1c301e
LP
75 }
76
1f849790
LP
77 pager_open_if_enabled();
78
d5099efc 79 names = hashmap_new(&string_hash_ops);
5e2f14e6
LP
80 if (!names)
81 return log_oom();
89ffcd2a 82
5e2f14e6 83 STRV_FOREACH(i, acquired) {
71f2ab46
LP
84 max_i = MAX(max_i, strlen(*i));
85
5e2f14e6
LP
86 r = hashmap_put(names, *i, INT_TO_PTR(1));
87 if (r < 0) {
88 log_error("Failed to add to hashmap: %s", strerror(-r));
89 return r;
90 }
91 }
92
93 STRV_FOREACH(i, activatable) {
89ffcd2a
LP
94 max_i = MAX(max_i, strlen(*i));
95
5e2f14e6
LP
96 r = hashmap_put(names, *i, INT_TO_PTR(2));
97 if (r < 0 && r != -EEXIST) {
98 log_error("Failed to add to hashmap: %s", strerror(-r));
99 return r;
100 }
101 }
102
103 merged = new(char*, hashmap_size(names) + 1);
104 HASHMAP_FOREACH_KEY(v, k, names, iterator)
105 merged[n++] = k;
106
107 merged[n] = NULL;
108 strv_sort(merged);
109
17d47d8d
TA
110 if (arg_legend) {
111 printf("%-*s %*s %-*s %-*s %-*s %-*s %-*s %-*s",
112 (int) max_i, "NAME", 10, "PID", 15, "PROCESS", 16, "USER", 13, "CONNECTION", 25, "UNIT", 10, "SESSION", 19, "CONNECTION-NAME");
89ffcd2a 113
17d47d8d
TA
114 if (arg_show_machine)
115 puts(" MACHINE");
116 else
117 putchar('\n');
118 }
a4297f08 119
5e2f14e6
LP
120 STRV_FOREACH(i, merged) {
121 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
122 sd_id128_t mid;
71f2ab46 123
5e2f14e6
LP
124 if (hashmap_get(names, *i) == INT_TO_PTR(2)) {
125 /* Activatable */
71f2ab46 126
5e2f14e6 127 printf("%-*s", (int) max_i, *i);
56e61788
LP
128 printf(" - - - (activatable) - - ");
129 if (arg_show_machine)
5e2f14e6 130 puts(" -");
56e61788
LP
131 else
132 putchar('\n');
71f2ab46
LP
133 continue;
134
5e2f14e6 135 }
de1c301e 136
56e61788
LP
137 if (!arg_unique && (*i)[0] == ':')
138 continue;
139
140 if (!arg_acquired && (*i)[0] != ':')
1f849790 141 continue;
89ffcd2a
LP
142
143 printf("%-*s", (int) max_i, *i);
de1c301e 144
056f95d0 145 r = sd_bus_get_name_creds(bus, *i,
14008e4e
LP
146 SD_BUS_CREDS_UID|SD_BUS_CREDS_PID|SD_BUS_CREDS_COMM|
147 SD_BUS_CREDS_UNIQUE_NAME|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_SESSION|
148 SD_BUS_CREDS_CONNECTION_NAME, &creds);
89ffcd2a 149 if (r >= 0) {
14008e4e 150 const char *unique, *session, *unit, *cn;
5b12334d
LP
151 pid_t pid;
152 uid_t uid;
de1c301e 153
5b12334d
LP
154 r = sd_bus_creds_get_pid(creds, &pid);
155 if (r >= 0) {
156 const char *comm = NULL;
de1c301e 157
5b12334d 158 sd_bus_creds_get_comm(creds, &comm);
89ffcd2a 159
5b12334d
LP
160 printf(" %10lu %-15s", (unsigned long) pid, strna(comm));
161 } else
a4297f08 162 fputs(" - - ", stdout);
89ffcd2a 163
5b12334d
LP
164 r = sd_bus_creds_get_uid(creds, &uid);
165 if (r >= 0) {
166 _cleanup_free_ char *u = NULL;
89ffcd2a 167
5b12334d
LP
168 u = uid_to_name(uid);
169 if (!u)
170 return log_oom();
89ffcd2a 171
5b12334d
LP
172 if (strlen(u) > 16)
173 u[16] = 0;
174
175 printf(" %-16s", u);
176 } else
a4297f08 177 fputs(" - ", stdout);
89ffcd2a 178
49b832c5
LP
179 r = sd_bus_creds_get_unique_name(creds, &unique);
180 if (r >= 0)
56e61788
LP
181 printf(" %-13s", unique);
182 else
183 fputs(" - ", stdout);
184
185 r = sd_bus_creds_get_unit(creds, &unit);
186 if (r >= 0) {
187 _cleanup_free_ char *e;
188
189 e = ellipsize(unit, 25, 100);
190 if (!e)
191 return log_oom();
192
193 printf(" %-25s", e);
194 } else
195 fputs(" - ", stdout);
196
197 r = sd_bus_creds_get_session(creds, &session);
198 if (r >= 0)
199 printf(" %-10s", session);
a4297f08 200 else
56e61788 201 fputs(" - ", stdout);
7b0b392f 202
14008e4e
LP
203 r = sd_bus_creds_get_connection_name(creds, &cn);
204 if (r >= 0)
205 printf(" %-19s", cn);
206 else
207 fputs(" - ", stdout);
208
7b0b392f 209 } else
14008e4e 210 printf(" - - - - - - - ");
a4297f08 211
56e61788 212 if (arg_show_machine) {
056f95d0 213 r = sd_bus_get_name_machine_id(bus, *i, &mid);
a4297f08
LP
214 if (r >= 0) {
215 char m[SD_ID128_STRING_MAX];
216 printf(" %s\n", sd_id128_to_string(mid, m));
217 } else
218 puts(" -");
56e61788
LP
219 } else
220 putchar('\n');
de1c301e
LP
221 }
222
1f849790
LP
223 return 0;
224}
225
226static int monitor(sd_bus *bus, char *argv[]) {
b51f299a 227 bool added_something = false;
1f849790
LP
228 char **i;
229 int r;
230
231 STRV_FOREACH(i, argv+1) {
232 _cleanup_free_ char *m = NULL;
233
234 if (!service_name_is_valid(*i)) {
235 log_error("Invalid service name '%s'", *i);
236 return -EINVAL;
237 }
238
239 m = strjoin("sender='", *i, "'", NULL);
240 if (!m)
241 return log_oom();
242
19befb2d 243 r = sd_bus_add_match(bus, NULL, m, NULL, NULL);
1f849790
LP
244 if (r < 0) {
245 log_error("Failed to add match: %s", strerror(-r));
246 return r;
247 }
b51f299a
LP
248
249 added_something = true;
1f849790
LP
250 }
251
252 STRV_FOREACH(i, arg_matches) {
19befb2d 253 r = sd_bus_add_match(bus, NULL, *i, NULL, NULL);
1f849790
LP
254 if (r < 0) {
255 log_error("Failed to add match: %s", strerror(-r));
256 return r;
257 }
b51f299a
LP
258
259 added_something = true;
260 }
261
262 if (!added_something) {
19befb2d 263 r = sd_bus_add_match(bus, NULL, "", NULL, NULL);
b51f299a
LP
264 if (r < 0) {
265 log_error("Failed to add match: %s", strerror(-r));
266 return r;
267 }
1f849790
LP
268 }
269
270 for (;;) {
271 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
272
273 r = sd_bus_process(bus, &m);
274 if (r < 0) {
275 log_error("Failed to process bus: %s", strerror(-r));
276 return r;
277 }
278
279 if (m) {
c430fee6 280 bus_message_dump(m, stdout, true);
1f849790
LP
281 continue;
282 }
283
284 if (r > 0)
285 continue;
286
287 r = sd_bus_wait(bus, (uint64_t) -1);
288 if (r < 0) {
289 log_error("Failed to wait for bus: %s", strerror(-r));
290 return r;
291 }
292 }
95c4fe82 293}
1f849790 294
95c4fe82
LP
295static int status(sd_bus *bus, char *argv[]) {
296 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
297 pid_t pid;
298 int r;
299
300 assert(bus);
301
302 if (strv_length(argv) != 2) {
303 log_error("Expects one argument.");
304 return -EINVAL;
305 }
306
307 r = parse_pid(argv[1], &pid);
308 if (r < 0)
056f95d0 309 r = sd_bus_get_name_creds(bus, argv[1], _SD_BUS_CREDS_ALL, &creds);
95c4fe82 310 else
151b9b96 311 r = sd_bus_creds_new_from_pid(&creds, pid, _SD_BUS_CREDS_ALL);
95c4fe82
LP
312
313 if (r < 0) {
314 log_error("Failed to get credentials: %s", strerror(-r));
315 return r;
316 }
317
318 bus_creds_dump(creds, NULL);
319 return 0;
1f849790
LP
320}
321
322static int help(void) {
1f849790
LP
323 printf("%s [OPTIONS...] {COMMAND} ...\n\n"
324 "Introspect the bus.\n\n"
d75edbd6
LP
325 " -h --help Show this help\n"
326 " --version Show package version\n"
a86a47ce 327 " --no-pager Do not pipe output into a pager\n"
17d47d8d 328 " --no-legend Do not show the headers and footers\n"
d75edbd6
LP
329 " --system Connect to system bus\n"
330 " --user Connect to user bus\n"
331 " -H --host=[USER@]HOST Operate on remote host\n"
332 " -M --machine=CONTAINER Operate on local container\n"
333 " --address=ADDRESS Connect to bus specified by address\n"
56e61788
LP
334 " --show-machine Show machine ID column in list\n"
335 " --unique Only show unique names\n"
336 " --acquired Only show acquired names\n"
337 " --activatable Only show activatable names\n"
b5dda4d8 338 " --match=MATCH Only show matching messages\n\n"
1f849790 339 "Commands:\n"
d75edbd6 340 " list List bus names\n"
d94fe1f1 341 " monitor [SERVICE...] Show bus traffic\n"
56e61788 342 " status NAME Show name status\n"
601185b4
ZJS
343 " help Show this help\n"
344 , program_invocation_short_name);
1f849790
LP
345
346 return 0;
347}
348
349static int parse_argv(int argc, char *argv[]) {
350
351 enum {
352 ARG_VERSION = 0x100,
353 ARG_NO_PAGER,
17d47d8d 354 ARG_NO_LEGEND,
1f849790
LP
355 ARG_SYSTEM,
356 ARG_USER,
357 ARG_ADDRESS,
358 ARG_MATCH,
56e61788
LP
359 ARG_SHOW_MACHINE,
360 ARG_UNIQUE,
361 ARG_ACQUIRED,
362 ARG_ACTIVATABLE
1f849790
LP
363 };
364
365 static const struct option options[] = {
56e61788
LP
366 { "help", no_argument, NULL, 'h' },
367 { "version", no_argument, NULL, ARG_VERSION },
368 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
17d47d8d 369 { "no-legend", no_argument, NULL, ARG_NO_LEGEND },
56e61788
LP
370 { "system", no_argument, NULL, ARG_SYSTEM },
371 { "user", no_argument, NULL, ARG_USER },
372 { "address", required_argument, NULL, ARG_ADDRESS },
373 { "show-machine", no_argument, NULL, ARG_SHOW_MACHINE },
374 { "unique", no_argument, NULL, ARG_UNIQUE },
375 { "acquired", no_argument, NULL, ARG_ACQUIRED },
376 { "activatable", no_argument, NULL, ARG_ACTIVATABLE },
377 { "match", required_argument, NULL, ARG_MATCH },
378 { "host", required_argument, NULL, 'H' },
379 { "machine", required_argument, NULL, 'M' },
eb9da376 380 {},
1f849790
LP
381 };
382
383 int c;
384
385 assert(argc >= 0);
386 assert(argv);
387
601185b4 388 while ((c = getopt_long(argc, argv, "hH:M:", options, NULL)) >= 0)
1f849790
LP
389
390 switch (c) {
391
392 case 'h':
393 return help();
394
395 case ARG_VERSION:
396 puts(PACKAGE_STRING);
397 puts(SYSTEMD_FEATURES);
398 return 0;
399
400 case ARG_NO_PAGER:
401 arg_no_pager = true;
402 break;
403
17d47d8d
TA
404 case ARG_NO_LEGEND:
405 arg_legend = false;
406 break;
407
1f849790
LP
408 case ARG_USER:
409 arg_user = true;
410 break;
411
412 case ARG_SYSTEM:
413 arg_user = false;
414 break;
415
416 case ARG_ADDRESS:
417 arg_address = optarg;
418 break;
419
56e61788
LP
420 case ARG_SHOW_MACHINE:
421 arg_show_machine = true;
422 break;
423
424 case ARG_UNIQUE:
425 arg_unique = true;
1f849790
LP
426 break;
427
56e61788
LP
428 case ARG_ACQUIRED:
429 arg_acquired = true;
430 break;
431
432 case ARG_ACTIVATABLE:
433 arg_activatable = true;
a4297f08
LP
434 break;
435
1f849790
LP
436 case ARG_MATCH:
437 if (strv_extend(&arg_matches, optarg) < 0)
438 return log_oom();
439 break;
440
d75edbd6
LP
441 case 'H':
442 arg_transport = BUS_TRANSPORT_REMOTE;
443 arg_host = optarg;
444 break;
445
446 case 'M':
447 arg_transport = BUS_TRANSPORT_CONTAINER;
448 arg_host = optarg;
449 break;
450
1f849790
LP
451 case '?':
452 return -EINVAL;
453
454 default:
eb9da376 455 assert_not_reached("Unhandled option");
1f849790 456 }
1f849790 457
56e61788
LP
458 if (!arg_unique && !arg_acquired && !arg_activatable)
459 arg_unique = arg_acquired = arg_activatable = true;
460
1f849790
LP
461 return 1;
462}
463
464static int busctl_main(sd_bus *bus, int argc, char *argv[]) {
465 assert(bus);
466
467 if (optind >= argc ||
468 streq(argv[optind], "list"))
469 return list_bus_names(bus, argv + optind);
470
471 if (streq(argv[optind], "monitor"))
472 return monitor(bus, argv + optind);
473
95c4fe82
LP
474 if (streq(argv[optind], "status"))
475 return status(bus, argv + optind);
476
1f849790
LP
477 if (streq(argv[optind], "help"))
478 return help();
479
480 log_error("Unknown command '%s'", argv[optind]);
481 return -EINVAL;
482}
483
484int main(int argc, char *argv[]) {
24996861 485 _cleanup_bus_close_unref_ sd_bus *bus = NULL;
1f849790
LP
486 int r;
487
488 log_parse_environment();
489 log_open();
490
491 r = parse_argv(argc, argv);
492 if (r <= 0)
493 goto finish;
494
09365592
LP
495 r = sd_bus_new(&bus);
496 if (r < 0) {
497 log_error("Failed to allocate bus: %s", strerror(-r));
498 goto finish;
499 }
500
501 if (streq_ptr(argv[optind], "monitor")) {
502
503 r = sd_bus_set_monitor(bus, true);
1f849790 504 if (r < 0) {
09365592 505 log_error("Failed to set monitor mode: %s", strerror(-r));
1f849790
LP
506 goto finish;
507 }
d0ce7734
LP
508
509 r = sd_bus_negotiate_creds(bus, _SD_BUS_CREDS_ALL);
510 if (r < 0) {
511 log_error("Failed to enable credentials: %s", strerror(-r));
512 goto finish;
513 }
514
515 r = sd_bus_negotiate_timestamp(bus, true);
516 if (r < 0) {
517 log_error("Failed to enable timestamps: %s", strerror(-r));
518 goto finish;
519 }
520
521 r = sd_bus_negotiate_fds(bus, true);
522 if (r < 0) {
523 log_error("Failed to enable fds: %s", strerror(-r));
524 goto finish;
525 }
09365592 526 }
1f849790 527
09365592 528 if (arg_address)
1f849790 529 r = sd_bus_set_address(bus, arg_address);
09365592
LP
530 else {
531 switch (arg_transport) {
1f849790 532
09365592
LP
533 case BUS_TRANSPORT_LOCAL:
534 if (arg_user)
535 r = bus_set_address_user(bus);
536 else
537 r = bus_set_address_system(bus);
538 break;
539
540 case BUS_TRANSPORT_REMOTE:
541 r = bus_set_address_system_remote(bus, arg_host);
542 break;
543
544 case BUS_TRANSPORT_CONTAINER:
545 r = bus_set_address_system_container(bus, arg_host);
546 break;
547
548 default:
549 assert_not_reached("Hmm, unknown transport type.");
1f849790 550 }
09365592
LP
551 }
552 if (r < 0) {
553 log_error("Failed to set address: %s", strerror(-r));
554 goto finish;
555 }
1f849790 556
09365592
LP
557 r = sd_bus_set_bus_client(bus, true);
558 if (r < 0) {
559 log_error("Failed to set bus client: %s", strerror(-r));
560 goto finish;
561 }
1f849790 562
09365592 563 r = sd_bus_start(bus);
1f849790
LP
564 if (r < 0) {
565 log_error("Failed to connect to bus: %s", strerror(-r));
566 goto finish;
567 }
568
569 r = busctl_main(bus, argc, argv);
570
571finish:
572 pager_close();
d75edbd6 573
1f849790 574 strv_free(arg_matches);
de1c301e 575
de1c301e
LP
576 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
577}