X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Flibsystemd%2Fsd-bus%2Fbusctl.c;h=d3c1772019c901eed3f7dbf61b028bce2b9923cb;hb=63c372cb9df3bee01e3bf8cd7f96f336bddda846;hp=7f5124f800813fa8a3f4def9897ee9f6ca8d74fb;hpb=1fc5560911a7e9e8cf2993e17e1f0a001e148809;p=elogind.git diff --git a/src/libsystemd/sd-bus/busctl.c b/src/libsystemd/sd-bus/busctl.c index 7f5124f80..d3c177201 100644 --- a/src/libsystemd/sd-bus/busctl.c +++ b/src/libsystemd/sd-bus/busctl.c @@ -28,6 +28,7 @@ #include "pager.h" #include "xml.h" #include "path-util.h" +#include "set.h" #include "sd-bus.h" #include "bus-message.h" @@ -53,6 +54,11 @@ static size_t arg_snaplen = 4096; static bool arg_list = false; static bool arg_quiet = false; static bool arg_verbose = false; +static bool arg_expect_reply = true; +static bool arg_auto_start = true; +static bool arg_allow_interactive_authorization = true; +static bool arg_augment_creds = true; +static usec_t arg_timeout = 0; static void pager_open_if_enabled(void) { @@ -63,6 +69,9 @@ static void pager_open_if_enabled(void) { pager_open(false); } +#define NAME_IS_ACQUIRED INT_TO_PTR(1) +#define NAME_IS_ACTIVATABLE INT_TO_PTR(2) + static int list_bus_names(sd_bus *bus, char **argv) { _cleanup_strv_free_ char **acquired = NULL, **activatable = NULL; _cleanup_free_ char **merged = NULL; @@ -81,10 +90,8 @@ static int list_bus_names(sd_bus *bus, char **argv) { arg_unique = arg_acquired = arg_activatable = true; r = sd_bus_list_names(bus, (arg_acquired || arg_unique) ? &acquired : NULL, arg_activatable ? &activatable : NULL); - if (r < 0) { - log_error("Failed to list names: %s", strerror(-r)); - return r; - } + if (r < 0) + return log_error_errno(r, "Failed to list names: %m"); pager_open_if_enabled(); @@ -95,21 +102,17 @@ static int list_bus_names(sd_bus *bus, char **argv) { STRV_FOREACH(i, acquired) { max_i = MAX(max_i, strlen(*i)); - r = hashmap_put(names, *i, INT_TO_PTR(1)); - if (r < 0) { - log_error("Failed to add to hashmap: %s", strerror(-r)); - return r; - } + r = hashmap_put(names, *i, NAME_IS_ACQUIRED); + if (r < 0) + return log_error_errno(r, "Failed to add to hashmap: %m"); } STRV_FOREACH(i, activatable) { max_i = MAX(max_i, strlen(*i)); - r = hashmap_put(names, *i, INT_TO_PTR(2)); - if (r < 0 && r != -EEXIST) { - log_error("Failed to add to hashmap: %s", strerror(-r)); - return r; - } + r = hashmap_put(names, *i, NAME_IS_ACTIVATABLE); + if (r < 0 && r != -EEXIST) + return log_error_errno(r, "Failed to add to hashmap: %m"); } merged = new(char*, hashmap_size(names) + 1); @@ -133,7 +136,7 @@ static int list_bus_names(sd_bus *bus, char **argv) { _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL; sd_id128_t mid; - if (hashmap_get(names, *i) == INT_TO_PTR(2)) { + if (hashmap_get(names, *i) == NAME_IS_ACTIVATABLE) { /* Activatable */ printf("%-*s", (int) max_i, *i); @@ -154,10 +157,12 @@ static int list_bus_names(sd_bus *bus, char **argv) { printf("%-*s", (int) max_i, *i); - r = sd_bus_get_name_creds(bus, *i, - SD_BUS_CREDS_UID|SD_BUS_CREDS_PID|SD_BUS_CREDS_COMM| - SD_BUS_CREDS_UNIQUE_NAME|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_SESSION| - SD_BUS_CREDS_DESCRIPTION, &creds); + r = sd_bus_get_name_creds( + bus, *i, + (arg_augment_creds ? SD_BUS_CREDS_AUGMENT : 0) | + SD_BUS_CREDS_EUID|SD_BUS_CREDS_PID|SD_BUS_CREDS_COMM| + SD_BUS_CREDS_UNIQUE_NAME|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_SESSION| + SD_BUS_CREDS_DESCRIPTION, &creds); if (r >= 0) { const char *unique, *session, *unit, *cn; pid_t pid; @@ -173,7 +178,7 @@ static int list_bus_names(sd_bus *bus, char **argv) { } else fputs(" - - ", stdout); - r = sd_bus_creds_get_uid(creds, &uid); + r = sd_bus_creds_get_euid(creds, &uid); if (r >= 0) { _cleanup_free_ char *u = NULL; @@ -251,8 +256,8 @@ static void print_subtree(const char *prefix, const char *path, char **l) { l++; } - vertical = strappenda(prefix, draw_special_char(DRAW_TREE_VERTICAL)); - space = strappenda(prefix, draw_special_char(DRAW_TREE_SPACE)); + vertical = strjoina(prefix, draw_special_char(DRAW_TREE_VERTICAL)); + space = strjoina(prefix, draw_special_char(DRAW_TREE_SPACE)); for (;;) { bool has_more = false; @@ -428,10 +433,8 @@ static int tree(sd_bus *bus, char **argv) { bool not_first = false; r = sd_bus_list_names(bus, &names, NULL); - if (r < 0) { - log_error("Failed to get name list: %s", strerror(-r)); - return r; - } + if (r < 0) + return log_error_errno(r, "Failed to get name list: %m"); pager_open_if_enabled(); @@ -536,7 +539,7 @@ static int format_cmdline(sd_bus_message *m, FILE *f, bool needs_space) { fprintf(f, "%s", contents); } - r = format_cmdline(m, f, true); + r = format_cmdline(m, f, needs_space || IN_SET(type, SD_BUS_TYPE_ARRAY, SD_BUS_TYPE_VARIANT)); if (r < 0) return r; @@ -612,6 +615,7 @@ static int format_cmdline(sd_bus_message *m, FILE *f, bool needs_space) { assert_not_reached("Unknown basic type."); } + needs_space = true; } } @@ -879,13 +883,19 @@ static int introspect(sd_bus *bus, char **argv) { int r; unsigned name_width, type_width, signature_width, result_width; Member **sorted = NULL; - unsigned k = 0, j; + unsigned k = 0, j, n_args; - if (strv_length(argv) != 3) { + n_args = strv_length(argv); + if (n_args < 3) { log_error("Requires service and object path argument."); return -EINVAL; } + if (n_args > 4) { + log_error("Too many arguments."); + return -EINVAL; + } + members = set_new(&member_hash_ops); if (!members) return log_oom(); @@ -914,6 +924,9 @@ static int introspect(sd_bus *bus, char **argv) { if (m->value) continue; + if (argv[3] && !streq(argv[3], m->interface)) + continue; + r = sd_bus_call_method(bus, argv[1], argv[2], "org.freedesktop.DBus.Properties", "GetAll", &error, &reply, "s", m->interface); if (r < 0) { log_error("%s", bus_error_message(&error, r)); @@ -991,6 +1004,10 @@ static int introspect(sd_bus *bus, char **argv) { sorted = newa(Member*, set_size(members)); SET_FOREACH(m, members, i) { + + if (argv[3] && !streq(argv[3], m->interface)) + continue; + if (m->interface) name_width = MAX(name_width, strlen(m->interface)); if (m->name) @@ -1010,7 +1027,6 @@ static int introspect(sd_bus *bus, char **argv) { if (result_width > 40) result_width = 40; - assert(k == set_size(members)); qsort(sorted, k, sizeof(Member*), member_compare_funcp); if (arg_legend) { @@ -1029,8 +1045,14 @@ static int introspect(sd_bus *bus, char **argv) { m = sorted[j]; + if (argv[3] && !streq(argv[3], m->interface)) + continue; + is_interface = streq(m->type, "interface"); + if (argv[3] && is_interface) + continue; + if (m->value) { ellipsized = ellipsize(m->value, result_width, 100); if (!ellipsized) @@ -1085,43 +1107,43 @@ static int monitor(sd_bus *bus, char *argv[], int (*dump)(sd_bus_message *m, FIL return log_oom(); r = sd_bus_add_match(bus, NULL, m, NULL, NULL); - if (r < 0) { - log_error("Failed to add match: %s", strerror(-r)); - return r; - } + if (r < 0) + return log_error_errno(r, "Failed to add match: %m"); added_something = true; } STRV_FOREACH(i, arg_matches) { r = sd_bus_add_match(bus, NULL, *i, NULL, NULL); - if (r < 0) { - log_error("Failed to add match: %s", strerror(-r)); - return r; - } + if (r < 0) + return log_error_errno(r, "Failed to add match: %m"); added_something = true; } if (!added_something) { r = sd_bus_add_match(bus, NULL, "", NULL, NULL); - if (r < 0) { - log_error("Failed to add match: %s", strerror(-r)); - return r; - } + if (r < 0) + return log_error_errno(r, "Failed to add match: %m"); } + log_info("Monitoring bus message stream."); + for (;;) { _cleanup_bus_message_unref_ sd_bus_message *m = NULL; r = sd_bus_process(bus, &m); - if (r < 0) { - log_error("Failed to process bus: %s", strerror(-r)); - return r; - } + if (r < 0) + return log_error_errno(r, "Failed to process bus: %m"); if (m) { dump(m, stdout); + + if (sd_bus_message_is_signal(m, "org.freedesktop.DBus.Local", "Disconnected") > 0) { + log_info("Connection terminated, exiting."); + return 0; + } + continue; } @@ -1129,10 +1151,8 @@ static int monitor(sd_bus *bus, char *argv[], int (*dump)(sd_bus_message *m, FIL continue; r = sd_bus_wait(bus, (uint64_t) -1); - if (r < 0) { - log_error("Failed to wait for bus: %s", strerror(-r)); - return r; - } + if (r < 0) + return log_error_errno(r, "Failed to wait for bus: %m"); } } @@ -1165,22 +1185,49 @@ static int status(sd_bus *bus, char *argv[]) { assert(bus); - if (strv_length(argv) != 2) { - log_error("Expects one argument."); + if (strv_length(argv) > 2) { + log_error("Expects no or one argument."); return -EINVAL; } - r = parse_pid(argv[1], &pid); - if (r < 0) - r = sd_bus_get_name_creds(bus, argv[1], _SD_BUS_CREDS_ALL, &creds); - else - r = sd_bus_creds_new_from_pid(&creds, pid, _SD_BUS_CREDS_ALL); + if (argv[1]) { + r = parse_pid(argv[1], &pid); + if (r < 0) + r = sd_bus_get_name_creds( + bus, + argv[1], + (arg_augment_creds ? SD_BUS_CREDS_AUGMENT : 0) | _SD_BUS_CREDS_ALL, + &creds); + else + r = sd_bus_creds_new_from_pid( + &creds, + pid, + _SD_BUS_CREDS_ALL); + } else { + const char *scope, *address; + sd_id128_t bus_id; - if (r < 0) { - log_error("Failed to get credentials: %s", strerror(-r)); - return r; + r = sd_bus_get_address(bus, &address); + if (r >= 0) + printf("BusAddress=%s%s%s\n", ansi_highlight(), address, ansi_highlight_off()); + + r = sd_bus_get_scope(bus, &scope); + if (r >= 0) + printf("BusScope=%s%s%s\n", ansi_highlight(), scope, ansi_highlight_off()); + + r = sd_bus_get_bus_id(bus, &bus_id); + if (r >= 0) + printf("BusID=%s" SD_ID128_FORMAT_STR "%s\n", ansi_highlight(), SD_ID128_FORMAT_VAL(bus_id), ansi_highlight_off()); + + r = sd_bus_get_owner_creds( + bus, + (arg_augment_creds ? SD_BUS_CREDS_AUGMENT : 0) | _SD_BUS_CREDS_ALL, + &creds); } + if (r < 0) + return log_error_errno(r, "Failed to get credentials: %m"); + bus_creds_dump(creds, NULL, false); return 0; } @@ -1454,6 +1501,18 @@ static int call(sd_bus *bus, char *argv[]) { if (r < 0) return bus_log_create_error(r); + r = sd_bus_message_set_expect_reply(m, arg_expect_reply); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_set_auto_start(m, arg_auto_start); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_set_allow_interactive_authorization(m, arg_allow_interactive_authorization); + if (r < 0) + return bus_log_create_error(r); + if (!isempty(argv[5])) { char **p; @@ -1469,7 +1528,17 @@ static int call(sd_bus *bus, char *argv[]) { } } - r = sd_bus_call(bus, m, 0, &error, &reply); + if (!arg_expect_reply) { + r = sd_bus_send(bus, m, NULL); + if (r < 0) { + log_error("Failed to send message."); + return r; + } + + return 0; + } + + r = sd_bus_call(bus, m, arg_timeout, &error, &reply); if (r < 0) { log_error("%s", bus_error_message(&error, r)); return r; @@ -1602,7 +1671,7 @@ static int set_property(sd_bus *bus, char *argv[]) { return -EINVAL; } - r = sd_bus_call(bus, m, 0, &error, NULL); + r = sd_bus_call(bus, m, arg_timeout, &error, NULL); if (r < 0) { log_error("%s", bus_error_message(&error, r)); return r; @@ -1630,14 +1699,20 @@ static int help(void) { " --match=MATCH Only show matching messages\n" " --list Don't show tree, but simple object path list\n" " --quiet Don't show method call reply\n" - " --verbose Show result values in long format\n\n" + " --verbose Show result values in long format\n" + " --expect-reply=BOOL Expect a method call reply\n" + " --auto-start=BOOL Auto-start destination service\n" + " --allow-interactive-authorization=BOOL\n" + " Allow interactive authorization for operation\n" + " --timeout=SECS Maximum time to wait for method call completion\n" + " --augment-creds=BOOL Extend credential data with data read from /proc/$PID\n\n" "Commands:\n" " list List bus names\n" - " status SERVICE Show service name status\n" + " status [SERVICE] Show bus service, process or bus owner credentials\n" " monitor [SERVICE...] Show bus traffic\n" " capture [SERVICE...] Capture bus traffic as pcap\n" " tree [SERVICE...] Show object tree of service\n" - " introspect SERVICE OBJECT\n" + " introspect SERVICE OBJECT [INTERFACE]\n" " call SERVICE OBJECT INTERFACE METHOD [SIGNATURE [ARGUMENT...]]\n" " Call a method\n" " get-property SERVICE OBJECT INTERFACE PROPERTY...\n" @@ -1667,6 +1742,11 @@ static int parse_argv(int argc, char *argv[]) { ARG_SIZE, ARG_LIST, ARG_VERBOSE, + ARG_EXPECT_REPLY, + ARG_AUTO_START, + ARG_ALLOW_INTERACTIVE_AUTHORIZATION, + ARG_TIMEOUT, + ARG_AUGMENT_CREDS, }; static const struct option options[] = { @@ -1688,6 +1768,11 @@ static int parse_argv(int argc, char *argv[]) { { "list", no_argument, NULL, ARG_LIST }, { "quiet", no_argument, NULL, 'q' }, { "verbose", no_argument, NULL, ARG_VERBOSE }, + { "expect-reply", required_argument, NULL, ARG_EXPECT_REPLY }, + { "auto-start", required_argument, NULL, ARG_AUTO_START }, + { "allow-interactive-authorization", required_argument, NULL, ARG_ALLOW_INTERACTIVE_AUTHORIZATION }, + { "timeout", required_argument, NULL, ARG_TIMEOUT }, + { "augment-creds",required_argument, NULL, ARG_AUGMENT_CREDS}, {}, }; @@ -1777,7 +1862,7 @@ static int parse_argv(int argc, char *argv[]) { break; case 'M': - arg_transport = BUS_TRANSPORT_CONTAINER; + arg_transport = BUS_TRANSPORT_MACHINE; arg_host = optarg; break; @@ -1789,6 +1874,57 @@ static int parse_argv(int argc, char *argv[]) { arg_verbose = true; break; + case ARG_EXPECT_REPLY: + r = parse_boolean(optarg); + if (r < 0) { + log_error("Failed to parse --expect-reply= parameter."); + return r; + } + + arg_expect_reply = !!r; + break; + + + case ARG_AUTO_START: + r = parse_boolean(optarg); + if (r < 0) { + log_error("Failed to parse --auto-start= parameter."); + return r; + } + + arg_auto_start = !!r; + break; + + + case ARG_ALLOW_INTERACTIVE_AUTHORIZATION: + r = parse_boolean(optarg); + if (r < 0) { + log_error("Failed to parse --allow-interactive-authorization= parameter."); + return r; + } + + arg_allow_interactive_authorization = !!r; + break; + + case ARG_TIMEOUT: + r = parse_sec(optarg, &arg_timeout); + if (r < 0) { + log_error("Failed to parse --timeout= parameter."); + return r; + } + + break; + + case ARG_AUGMENT_CREDS: + r = parse_boolean(optarg); + if (r < 0) { + log_error("Failed to parse --augment-creds= parameter."); + return r; + } + + arg_augment_creds = !!r; + break; + case '?': return -EINVAL; @@ -1850,7 +1986,7 @@ int main(int argc, char *argv[]) { r = sd_bus_new(&bus); if (r < 0) { - log_error("Failed to allocate bus: %s", strerror(-r)); + log_error_errno(r, "Failed to allocate bus: %m"); goto finish; } @@ -1859,25 +1995,25 @@ int main(int argc, char *argv[]) { r = sd_bus_set_monitor(bus, true); if (r < 0) { - log_error("Failed to set monitor mode: %s", strerror(-r)); + log_error_errno(r, "Failed to set monitor mode: %m"); goto finish; } - r = sd_bus_negotiate_creds(bus, _SD_BUS_CREDS_ALL); + r = sd_bus_negotiate_creds(bus, true, _SD_BUS_CREDS_ALL); if (r < 0) { - log_error("Failed to enable credentials: %s", strerror(-r)); + log_error_errno(r, "Failed to enable credentials: %m"); goto finish; } r = sd_bus_negotiate_timestamp(bus, true); if (r < 0) { - log_error("Failed to enable timestamps: %s", strerror(-r)); + log_error_errno(r, "Failed to enable timestamps: %m"); goto finish; } r = sd_bus_negotiate_fds(bus, true); if (r < 0) { - log_error("Failed to enable fds: %s", strerror(-r)); + log_error_errno(r, "Failed to enable fds: %m"); goto finish; } } @@ -1887,25 +2023,28 @@ int main(int argc, char *argv[]) { else { r = sd_bus_set_bus_client(bus, true); if (r < 0) { - log_error("Failed to set bus client: %s", strerror(-r)); + log_error_errno(r, "Failed to set bus client: %m"); goto finish; } switch (arg_transport) { case BUS_TRANSPORT_LOCAL: - if (arg_user) + if (arg_user) { + bus->is_user = true; r = bus_set_address_user(bus); - else + } else { + bus->is_system = true; r = bus_set_address_system(bus); + } break; case BUS_TRANSPORT_REMOTE: r = bus_set_address_system_remote(bus, arg_host); break; - case BUS_TRANSPORT_CONTAINER: - r = bus_set_address_system_container(bus, arg_host); + case BUS_TRANSPORT_MACHINE: + r = bus_set_address_system_machine(bus, arg_host); break; default: @@ -1913,13 +2052,13 @@ int main(int argc, char *argv[]) { } } if (r < 0) { - log_error("Failed to set address: %s", strerror(-r)); + log_error_errno(r, "Failed to set address: %m"); goto finish; } r = sd_bus_start(bus); if (r < 0) { - log_error("Failed to connect to bus: %s", strerror(-r)); + log_error_errno(r, "Failed to connect to bus: %m"); goto finish; }