chiark / gitweb /
remove unused variables
[elogind.git] / src / libsystemd / sd-bus / busctl.c
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
36 static bool arg_no_pager = false;
37 static bool arg_legend = true;
38 static char *arg_address = NULL;
39 static bool arg_unique = false;
40 static bool arg_acquired = false;
41 static bool arg_activatable = false;
42 static bool arg_show_machine = false;
43 static char **arg_matches = NULL;
44 static BusTransport arg_transport = BUS_TRANSPORT_LOCAL;
45 static char *arg_host = NULL;
46 static bool arg_user = false;
47
48 static 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
57 static int list_bus_names(sd_bus *bus, char **argv) {
58         _cleanup_strv_free_ char **acquired = NULL, **activatable = NULL;
59         _cleanup_free_ char **merged = NULL;
60         _cleanup_hashmap_free_ Hashmap *names = NULL;
61         char **i;
62         int r;
63         size_t max_i = 0;
64         unsigned n = 0;
65         void *v;
66         char *k;
67         Iterator iterator;
68
69         assert(bus);
70
71         r = sd_bus_list_names(bus, (arg_acquired || arg_unique) ? &acquired : NULL, arg_activatable ? &activatable : NULL);
72         if (r < 0) {
73                 log_error("Failed to list names: %s", strerror(-r));
74                 return r;
75         }
76
77         pager_open_if_enabled();
78
79         names = hashmap_new(string_hash_func, string_compare_func);
80         if (!names)
81                 return log_oom();
82
83         STRV_FOREACH(i, acquired) {
84                 max_i = MAX(max_i, strlen(*i));
85
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) {
94                 max_i = MAX(max_i, strlen(*i));
95
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
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");
113
114                 if (arg_show_machine)
115                         puts(" MACHINE");
116                 else
117                         putchar('\n');
118         }
119
120         STRV_FOREACH(i, merged) {
121                 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
122                 sd_id128_t mid;
123
124                 if (hashmap_get(names, *i) == INT_TO_PTR(2)) {
125                         /* Activatable */
126
127                         printf("%-*s", (int) max_i, *i);
128                         printf("          - -               -                (activatable) -                         -         ");
129                         if (arg_show_machine)
130                                 puts(" -");
131                         else
132                                 putchar('\n');
133                         continue;
134
135                 }
136
137                 if (!arg_unique && (*i)[0] == ':')
138                         continue;
139
140                 if (!arg_acquired && (*i)[0] != ':')
141                         continue;
142
143                 printf("%-*s", (int) max_i, *i);
144
145                 r = sd_bus_get_owner(bus, *i,
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);
149                 if (r >= 0) {
150                         const char *unique, *session, *unit, *cn;
151                         pid_t pid;
152                         uid_t uid;
153
154                         r = sd_bus_creds_get_pid(creds, &pid);
155                         if (r >= 0) {
156                                 const char *comm = NULL;
157
158                                 sd_bus_creds_get_comm(creds, &comm);
159
160                                 printf(" %10lu %-15s", (unsigned long) pid, strna(comm));
161                         } else
162                                 fputs("          - -              ", stdout);
163
164                         r = sd_bus_creds_get_uid(creds, &uid);
165                         if (r >= 0) {
166                                 _cleanup_free_ char *u = NULL;
167
168                                 u = uid_to_name(uid);
169                                 if (!u)
170                                         return log_oom();
171
172                                 if (strlen(u) > 16)
173                                         u[16] = 0;
174
175                                 printf(" %-16s", u);
176                         } else
177                                 fputs(" -               ", stdout);
178
179                         r = sd_bus_creds_get_unique_name(creds, &unique);
180                         if (r >= 0)
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);
200                         else
201                                 fputs(" -         ", stdout);
202
203                         r = sd_bus_creds_get_connection_name(creds, &cn);
204                         if (r >= 0)
205                                 printf(" %-19s", cn);
206                         else
207                                 fputs(" -                  ", stdout);
208
209                 } else
210                         printf("          - -               -                -             -                         -          -                  ");
211
212                 if (arg_show_machine) {
213                         r = sd_bus_get_owner_machine_id(bus, *i, &mid);
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(" -");
219                 } else
220                         putchar('\n');
221         }
222
223         return 0;
224 }
225
226 static int monitor(sd_bus *bus, char *argv[]) {
227         bool added_something = false;
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
243                 r = sd_bus_add_match(bus, NULL, m, NULL, NULL);
244                 if (r < 0) {
245                         log_error("Failed to add match: %s", strerror(-r));
246                         return r;
247                 }
248
249                 added_something = true;
250         }
251
252         STRV_FOREACH(i, arg_matches) {
253                 r = sd_bus_add_match(bus, NULL, *i, NULL, NULL);
254                 if (r < 0) {
255                         log_error("Failed to add match: %s", strerror(-r));
256                         return r;
257                 }
258
259                 added_something = true;
260         }
261
262         if (!added_something) {
263                 r = sd_bus_add_match(bus, NULL, "", NULL, NULL);
264                 if (r < 0) {
265                         log_error("Failed to add match: %s", strerror(-r));
266                         return r;
267                 }
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) {
280                         bus_message_dump(m, stdout, true);
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         }
293 }
294
295 static 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)
309                 r = sd_bus_get_owner(bus, argv[1], _SD_BUS_CREDS_ALL, &creds);
310         else
311                 r = sd_bus_creds_new_from_pid(&creds, pid, _SD_BUS_CREDS_ALL);
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;
320 }
321
322 static int help(void) {
323         printf("%s [OPTIONS...] {COMMAND} ...\n\n"
324                "Introspect the bus.\n\n"
325                "  -h --help               Show this help\n"
326                "     --version            Show package version\n"
327                "     --no-pager           Do not pipe output into a pager\n"
328                "     --no-legend          Do not show the headers and footers\n"
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"
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"
338                "     --match=MATCH        Only show matching messages\n\n"
339                "Commands:\n"
340                "  list                    List bus names\n"
341                "  monitor [SERVICE...]    Show bus traffic\n"
342                "  status NAME             Show name status\n"
343                "  help                    Show this help\n"
344                , program_invocation_short_name);
345
346         return 0;
347 }
348
349 static int parse_argv(int argc, char *argv[]) {
350
351         enum {
352                 ARG_VERSION = 0x100,
353                 ARG_NO_PAGER,
354                 ARG_NO_LEGEND,
355                 ARG_SYSTEM,
356                 ARG_USER,
357                 ARG_ADDRESS,
358                 ARG_MATCH,
359                 ARG_SHOW_MACHINE,
360                 ARG_UNIQUE,
361                 ARG_ACQUIRED,
362                 ARG_ACTIVATABLE
363         };
364
365         static const struct option options[] = {
366                 { "help",         no_argument,       NULL, 'h'              },
367                 { "version",      no_argument,       NULL, ARG_VERSION      },
368                 { "no-pager",     no_argument,       NULL, ARG_NO_PAGER     },
369                 { "no-legend",    no_argument,       NULL, ARG_NO_LEGEND    },
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'              },
380                 {},
381         };
382
383         int c;
384
385         assert(argc >= 0);
386         assert(argv);
387
388         while ((c = getopt_long(argc, argv, "hH:M:", options, NULL)) >= 0)
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
404                 case ARG_NO_LEGEND:
405                         arg_legend = false;
406                         break;
407
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
420                 case ARG_SHOW_MACHINE:
421                         arg_show_machine = true;
422                         break;
423
424                 case ARG_UNIQUE:
425                         arg_unique = true;
426                         break;
427
428                 case ARG_ACQUIRED:
429                         arg_acquired = true;
430                         break;
431
432                 case ARG_ACTIVATABLE:
433                         arg_activatable = true;
434                         break;
435
436                 case ARG_MATCH:
437                         if (strv_extend(&arg_matches, optarg) < 0)
438                                 return log_oom();
439                         break;
440
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
451                 case '?':
452                         return -EINVAL;
453
454                 default:
455                         assert_not_reached("Unhandled option");
456                 }
457
458         if (!arg_unique && !arg_acquired && !arg_activatable)
459                 arg_unique = arg_acquired = arg_activatable = true;
460
461         return 1;
462 }
463
464 static 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
474         if (streq(argv[optind], "status"))
475                 return status(bus, argv + optind);
476
477         if (streq(argv[optind], "help"))
478                 return help();
479
480         log_error("Unknown command '%s'", argv[optind]);
481         return -EINVAL;
482 }
483
484 int main(int argc, char *argv[]) {
485         _cleanup_bus_close_unref_ sd_bus *bus = NULL;
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
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);
504                 if (r < 0) {
505                         log_error("Failed to set monitor mode: %s", strerror(-r));
506                         goto finish;
507                 }
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                 }
526         }
527
528         if (arg_address)
529                 r = sd_bus_set_address(bus, arg_address);
530         else {
531                 switch (arg_transport) {
532
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.");
550                 }
551         }
552         if (r < 0) {
553                 log_error("Failed to set address: %s", strerror(-r));
554                 goto finish;
555         }
556
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         }
562
563         r = sd_bus_start(bus);
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
571 finish:
572         pager_close();
573
574         strv_free(arg_matches);
575
576         return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
577 }