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