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