]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd-bus/busctl.c
path-util: paths_check_timestamp() opimizations
[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 },
223 { NULL, 0, NULL, 0 },
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:
282 log_error("Unknown option code %c", c);
283 return -EINVAL;
284 }
285 }
286
287 return 1;
288}
289
290static int busctl_main(sd_bus *bus, int argc, char *argv[]) {
291 assert(bus);
292
293 if (optind >= argc ||
294 streq(argv[optind], "list"))
295 return list_bus_names(bus, argv + optind);
296
297 if (streq(argv[optind], "monitor"))
298 return monitor(bus, argv + optind);
299
300 if (streq(argv[optind], "help"))
301 return help();
302
303 log_error("Unknown command '%s'", argv[optind]);
304 return -EINVAL;
305}
306
307int main(int argc, char *argv[]) {
308 _cleanup_bus_unref_ sd_bus *bus = NULL;
309 int r;
310
311 log_parse_environment();
312 log_open();
313
314 r = parse_argv(argc, argv);
315 if (r <= 0)
316 goto finish;
317
318 if (arg_address) {
319 r = sd_bus_new(&bus);
320 if (r < 0) {
321 log_error("Failed to allocate bus: %s", strerror(-r));
322 goto finish;
323 }
324
325 r = sd_bus_set_address(bus, arg_address);
326 if (r < 0) {
327 log_error("Failed to set address: %s", strerror(-r));
328 goto finish;
329 }
330
331 r = sd_bus_set_bus_client(bus, true);
332 if (r < 0) {
333 log_error("Failed to set bus client: %s", strerror(-r));
334 goto finish;
335 }
336
337 r = sd_bus_start(bus);
d75edbd6
LP
338 } else
339 r = bus_open_transport(arg_transport, arg_host, arg_user, &bus);
1f849790
LP
340
341 if (r < 0) {
342 log_error("Failed to connect to bus: %s", strerror(-r));
343 goto finish;
344 }
345
346 r = busctl_main(bus, argc, argv);
347
348finish:
349 pager_close();
d75edbd6 350
1f849790 351 strv_free(arg_matches);
de1c301e 352
de1c301e
LP
353 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
354}