]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd-bus/busctl.c
machinectl: show list headers even if we pipe, since that appears to be the usual way
[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"
de1c301e 34
1f849790
LP
35static bool arg_no_pager = false;
36static char *arg_address = NULL;
1f849790
LP
37static bool arg_no_unique = false;
38static char **arg_matches = NULL;
d75edbd6
LP
39static BusTransport arg_transport = BUS_TRANSPORT_LOCAL;
40static char *arg_host = NULL;
41static bool arg_user = false;
1f849790
LP
42
43static 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
52static int list_bus_names(sd_bus *bus, char **argv) {
de1c301e
LP
53 _cleanup_strv_free_ char **l = NULL;
54 char **i;
55 int r;
89ffcd2a 56 size_t max_i = 0;
de1c301e 57
1f849790 58 assert(bus);
de1c301e
LP
59
60 r = sd_bus_list_names(bus, &l);
61 if (r < 0) {
62 log_error("Failed to list names: %s", strerror(-r));
1f849790 63 return r;
de1c301e
LP
64 }
65
1f849790
LP
66 pager_open_if_enabled();
67
89ffcd2a
LP
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
de1c301e
LP
76 STRV_FOREACH(i, l) {
77 _cleanup_free_ char *owner = NULL;
89ffcd2a 78 pid_t pid;
de1c301e 79 uid_t uid;
de1c301e 80
1f849790
LP
81 if (arg_no_unique && (*i)[0] == ':')
82 continue;
89ffcd2a
LP
83
84 printf("%-*s", (int) max_i, *i);
de1c301e 85
89ffcd2a
LP
86 r = sd_bus_get_owner_pid(bus, *i, &pid);
87 if (r >= 0) {
88 _cleanup_free_ char *comm = NULL;
de1c301e 89
89ffcd2a 90 printf(" %10lu", (unsigned long) pid);
de1c301e 91
89ffcd2a
LP
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);
1f849790
LP
102 if (!u)
103 return log_oom();
89ffcd2a
LP
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");
de1c301e
LP
117 }
118
1f849790
LP
119 return 0;
120}
121
122static 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) {
c430fee6 163 bus_message_dump(m, stdout, true);
1f849790
LP
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
180static int help(void) {
181
182 printf("%s [OPTIONS...] {COMMAND} ...\n\n"
183 "Introspect the bus.\n\n"
d75edbd6
LP
184 " -h --help Show this help\n"
185 " --version Show package version\n"
186 " --system Connect to system bus\n"
187 " --user Connect to user bus\n"
188 " -H --host=[USER@]HOST Operate on remote host\n"
189 " -M --machine=CONTAINER Operate on local container\n"
190 " --address=ADDRESS Connect to bus specified by address\n"
191 " --no-unique Only show well-known names\n"
192 " --match=MATCH Only show matching messages\n"
193 " --no-pager Do not pipe output into a pager\n\n"
1f849790 194 "Commands:\n"
d75edbd6
LP
195 " list List bus names\n"
196 " monitor [SERVICE...] Show bus traffic\n",
1f849790
LP
197 program_invocation_short_name);
198
199 return 0;
200}
201
202static 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 },
eb9da376 223 {},
1f849790
LP
224 };
225
226 int c;
227
228 assert(argc >= 0);
229 assert(argv);
230
d75edbd6 231 while ((c = getopt_long(argc, argv, "hH:M:", options, NULL)) >= 0) {
1f849790
LP
232
233 switch (c) {
234
235 case 'h':
236 return help();
237
238 case ARG_VERSION:
239 puts(PACKAGE_STRING);
240 puts(SYSTEMD_FEATURES);
241 return 0;
242
243 case ARG_NO_PAGER:
244 arg_no_pager = true;
245 break;
246
247 case ARG_USER:
248 arg_user = true;
249 break;
250
251 case ARG_SYSTEM:
252 arg_user = false;
253 break;
254
255 case ARG_ADDRESS:
256 arg_address = optarg;
257 break;
258
259 case ARG_NO_UNIQUE:
260 arg_no_unique = true;
261 break;
262
263 case ARG_MATCH:
264 if (strv_extend(&arg_matches, optarg) < 0)
265 return log_oom();
266 break;
267
d75edbd6
LP
268 case 'H':
269 arg_transport = BUS_TRANSPORT_REMOTE;
270 arg_host = optarg;
271 break;
272
273 case 'M':
274 arg_transport = BUS_TRANSPORT_CONTAINER;
275 arg_host = optarg;
276 break;
277
1f849790
LP
278 case '?':
279 return -EINVAL;
280
281 default:
eb9da376 282 assert_not_reached("Unhandled option");
1f849790
LP
283 }
284 }
285
286 return 1;
287}
288
289static int busctl_main(sd_bus *bus, int argc, char *argv[]) {
290 assert(bus);
291
292 if (optind >= argc ||
293 streq(argv[optind], "list"))
294 return list_bus_names(bus, argv + optind);
295
296 if (streq(argv[optind], "monitor"))
297 return monitor(bus, argv + optind);
298
299 if (streq(argv[optind], "help"))
300 return help();
301
302 log_error("Unknown command '%s'", argv[optind]);
303 return -EINVAL;
304}
305
306int main(int argc, char *argv[]) {
307 _cleanup_bus_unref_ sd_bus *bus = NULL;
308 int r;
309
310 log_parse_environment();
311 log_open();
312
313 r = parse_argv(argc, argv);
314 if (r <= 0)
315 goto finish;
316
317 if (arg_address) {
318 r = sd_bus_new(&bus);
319 if (r < 0) {
320 log_error("Failed to allocate bus: %s", strerror(-r));
321 goto finish;
322 }
323
324 r = sd_bus_set_address(bus, arg_address);
325 if (r < 0) {
326 log_error("Failed to set address: %s", strerror(-r));
327 goto finish;
328 }
329
330 r = sd_bus_set_bus_client(bus, true);
331 if (r < 0) {
332 log_error("Failed to set bus client: %s", strerror(-r));
333 goto finish;
334 }
335
336 r = sd_bus_start(bus);
d75edbd6
LP
337 } else
338 r = bus_open_transport(arg_transport, arg_host, arg_user, &bus);
1f849790
LP
339
340 if (r < 0) {
341 log_error("Failed to connect to bus: %s", strerror(-r));
342 goto finish;
343 }
344
345 r = busctl_main(bus, argc, argv);
346
347finish:
348 pager_close();
d75edbd6 349
1f849790 350 strv_free(arg_matches);
de1c301e 351
de1c301e
LP
352 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
353}