]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
busctl: use dispatch_verb()
authorYu Watanabe <watanabe.yu+github@gmail.com>
Tue, 13 Mar 2018 20:09:16 +0000 (05:09 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Mon, 19 Mar 2018 12:03:36 +0000 (21:03 +0900)
src/busctl/busctl.c

index f8c43b5079ca180432e5f5acf1f350a9295ff341..f4ef947c2118ddca4aca3dd32eddfa56ac836fcc 100644 (file)
@@ -42,6 +42,7 @@
 #include "terminal-util.h"
 #include "user-util.h"
 #include "util.h"
+#include "verbs.h"
 
 static bool arg_no_pager = false;
 static bool arg_legend = true;
@@ -68,7 +69,82 @@ static usec_t arg_timeout = 0;
 #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) {
+static int acquire_bus(bool set_monitor, sd_bus **ret) {
+        _cleanup_(sd_bus_unrefp) sd_bus *bus = NULL;
+        int r;
+
+        r = sd_bus_new(&bus);
+        if (r < 0)
+                return log_error_errno(r, "Failed to allocate bus: %m");
+
+        if (set_monitor) {
+                r = sd_bus_set_monitor(bus, true);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to set monitor mode: %m");
+
+                r = sd_bus_negotiate_creds(bus, true, _SD_BUS_CREDS_ALL);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to enable credentials: %m");
+
+                r = sd_bus_negotiate_timestamp(bus, true);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to enable timestamps: %m");
+
+                r = sd_bus_negotiate_fds(bus, true);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to enable fds: %m");
+        }
+
+        r = sd_bus_set_bus_client(bus, true);
+        if (r < 0)
+                return log_error_errno(r, "Failed to set bus client: %m");
+
+        r = sd_bus_set_watch_bind(bus, arg_watch_bind);
+        if (r < 0)
+                return log_error_errno(r, "Failed to set watch-bind setting to '%s': %m", yes_no(arg_watch_bind));
+
+        if (arg_address)
+                r = sd_bus_set_address(bus, arg_address);
+        else {
+                switch (arg_transport) {
+
+                case BUS_TRANSPORT_LOCAL:
+                        if (arg_user) {
+                                bus->is_user = true;
+                                r = bus_set_address_user(bus);
+                        } 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_MACHINE:
+                        r = bus_set_address_system_machine(bus, arg_host);
+                        break;
+
+                default:
+                        assert_not_reached("Hmm, unknown transport type.");
+                }
+        }
+        if (r < 0)
+                return log_error_errno(r, "Failed to set address: %m");
+
+        r = sd_bus_start(bus);
+        if (r < 0)
+                return log_error_errno(r, "Failed to connect to bus: %m");
+
+        *ret = bus;
+        bus = NULL;
+
+        return 0;
+}
+
+static int list_bus_names(int argc, char **argv, void *userdata) {
+        _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
         _cleanup_strv_free_ char **acquired = NULL, **activatable = NULL;
         _cleanup_free_ char **merged = NULL;
         _cleanup_hashmap_free_ Hashmap *names = NULL;
@@ -80,11 +156,13 @@ static int list_bus_names(sd_bus *bus, char **argv) {
         char *k;
         Iterator iterator;
 
-        assert(bus);
-
         if (!arg_unique && !arg_acquired && !arg_activatable)
                 arg_unique = arg_acquired = arg_activatable = true;
 
+        r = acquire_bus(false, &bus);
+        if (r < 0)
+                return r;
+
         r = sd_bus_list_names(bus, (arg_acquired || arg_unique) ? &acquired : NULL, arg_activatable ? &activatable : NULL);
         if (r < 0)
                 return log_error_errno(r, "Failed to list names: %m");
@@ -417,14 +495,19 @@ static int tree_one(sd_bus *bus, const char *service, const char *prefix, bool m
         return r;
 }
 
-static int tree(sd_bus *bus, char **argv) {
+static int tree(int argc, char **argv, void *userdata) {
+        _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
         char **i;
         int r = 0;
 
         if (!arg_unique && !arg_acquired)
                 arg_acquired = true;
 
-        if (strv_length(argv) <= 1) {
+        r = acquire_bus(false, &bus);
+        if (r < 0)
+                return r;
+
+        if (argc <= 1) {
                 _cleanup_strv_free_ char **names = NULL;
                 bool not_first = false;
 
@@ -848,7 +931,7 @@ static const char *strdash(const char *x) {
         return isempty(x) ? "-" : x;
 }
 
-static int introspect(sd_bus *bus, char **argv) {
+static int introspect(int argc, char **argv, void *userdata) {
         static const struct hash_ops member_hash_ops = {
                 .hash = member_hash_func,
                 .compare = member_compare_func,
@@ -861,27 +944,19 @@ static int introspect(sd_bus *bus, char **argv) {
                 .on_property = on_property,
         };
 
+        _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
         _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply_xml = NULL;
         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
         _cleanup_(member_set_freep) Set *members = NULL;
+        unsigned name_width, type_width, signature_width, result_width, j, k = 0;
+        Member *m, **sorted = NULL;
         Iterator i;
-        Member *m;
         const char *xml;
         int r;
-        unsigned name_width,  type_width, signature_width, result_width;
-        Member **sorted = NULL;
-        unsigned k = 0, j, n_args;
 
-        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;
-        }
+        r = acquire_bus(false, &bus);
+        if (r < 0)
+                return r;
 
         members = set_new(&member_hash_ops);
         if (!members)
@@ -1071,7 +1146,8 @@ static int message_pcap(sd_bus_message *m, FILE *f) {
         return bus_message_pcap_frame(m, arg_snaplen, f);
 }
 
-static int monitor(sd_bus *bus, char *argv[], int (*dump)(sd_bus_message *m, FILE *f)) {
+static int monitor(int argc, char **argv, int (*dump)(sd_bus_message *m, FILE *f)) {
+        _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
         _cleanup_(sd_bus_message_unrefp) sd_bus_message *message = NULL;
         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
         char **i;
@@ -1080,6 +1156,10 @@ static int monitor(sd_bus *bus, char *argv[], int (*dump)(sd_bus_message *m, FIL
         bool is_monitor = false;
         int r;
 
+        r = acquire_bus(true, &bus);
+        if (r < 0)
+                return r;
+
         /* upgrade connection; it's not used for anything else after this call */
         r = sd_bus_message_new_method_call(bus, &message, "org.freedesktop.DBus", "/org/freedesktop/DBus", "org.freedesktop.DBus.Monitoring", "BecomeMonitor");
         if (r < 0)
@@ -1186,7 +1266,11 @@ static int monitor(sd_bus *bus, char *argv[], int (*dump)(sd_bus_message *m, FIL
         }
 }
 
-static int capture(sd_bus *bus, char *argv[]) {
+static int verb_monitor(int argc, char **argv, void *userdata) {
+        return monitor(argc, argv, message_dump);
+}
+
+static int verb_capture(int argc, char **argv, void *userdata) {
         int r;
 
         if (isatty(fileno(stdout)) > 0) {
@@ -1196,7 +1280,7 @@ static int capture(sd_bus *bus, char *argv[]) {
 
         bus_pcap_header(arg_snaplen, stdout);
 
-        r = monitor(bus, argv, message_pcap);
+        r = monitor(argc, argv, message_pcap);
         if (r < 0)
                 return r;
 
@@ -1208,19 +1292,17 @@ static int capture(sd_bus *bus, char *argv[]) {
         return r;
 }
 
-static int status(sd_bus *bus, char *argv[]) {
+static int status(int argc, char **argv, void *userdata) {
+        _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
         _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
         pid_t pid;
         int r;
 
-        assert(bus);
-
-        if (strv_length(argv) > 2) {
-                log_error("Expects no or one argument.");
-                return -EINVAL;
-        }
+        r = acquire_bus(false, &bus);
+        if (r < 0)
+                return r;
 
-        if (argv[1]) {
+        if (!isempty(argv[1])) {
                 r = parse_pid(argv[1], &pid);
                 if (r < 0)
                         r = sd_bus_get_name_creds(
@@ -1515,17 +1597,15 @@ static int message_append_cmdline(sd_bus_message *m, const char *signature, char
         return 0;
 }
 
-static int call(sd_bus *bus, char *argv[]) {
+static int call(int argc, char **argv, void *userdata) {
+        _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
         _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *reply = NULL;
         int r;
 
-        assert(bus);
-
-        if (strv_length(argv) < 5) {
-                log_error("Expects at least four arguments.");
-                return -EINVAL;
-        }
+        r = acquire_bus(false, &bus);
+        if (r < 0)
+                return r;
 
         r = sd_bus_message_new_method_call(bus, &m, argv[1], argv[2], argv[3], argv[4]);
         if (r < 0)
@@ -1602,19 +1682,15 @@ static int call(sd_bus *bus, char *argv[]) {
         return 0;
 }
 
-static int get_property(sd_bus *bus, char *argv[]) {
+static int get_property(int argc, char **argv, void *userdata) {
+        _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
-        unsigned n;
         char **i;
         int r;
 
-        assert(bus);
-
-        n = strv_length(argv);
-        if (n < 5) {
-                log_error("Expects at least four arguments.");
-                return -EINVAL;
-        }
+        r = acquire_bus(false, &bus);
+        if (r < 0)
+                return r;
 
         STRV_FOREACH(i, argv + 4) {
                 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
@@ -1660,20 +1736,16 @@ static int get_property(sd_bus *bus, char *argv[]) {
         return 0;
 }
 
-static int set_property(sd_bus *bus, char *argv[]) {
+static int set_property(int argc, char **argv, void *userdata) {
+        _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
         _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
-        unsigned n;
         char **p;
         int r;
 
-        assert(bus);
-
-        n = strv_length(argv);
-        if (n < 6) {
-                log_error("Expects at least five arguments.");
-                return -EINVAL;
-        }
+        r = acquire_bus(false, &bus);
+        if (r < 0)
+                return r;
 
         r = sd_bus_message_new_method_call(bus, &m, argv[1], argv[2], "org.freedesktop.DBus.Properties", "Set");
         if (r < 0)
@@ -1687,7 +1759,7 @@ static int set_property(sd_bus *bus, char *argv[]) {
         if (r < 0)
                 return bus_log_create_error(r);
 
-        p = argv+6;
+        p = argv + 6;
         r = message_append_cmdline(m, argv[5], &p);
         if (r < 0)
                 return r;
@@ -1758,6 +1830,10 @@ static int help(void) {
         return 0;
 }
 
+static int verb_help(int argc, char **argv, void *userdata) {
+        return help();
+}
+
 static int parse_argv(int argc, char *argv[]) {
 
         enum {
@@ -1978,46 +2054,26 @@ static int parse_argv(int argc, char *argv[]) {
         return 1;
 }
 
-static int busctl_main(sd_bus *bus, int argc, char *argv[]) {
-        assert(bus);
-
-        if (optind >= argc ||
-            streq(argv[optind], "list"))
-                return list_bus_names(bus, argv + optind);
-
-        if (streq(argv[optind], "monitor"))
-                return monitor(bus, argv + optind, message_dump);
-
-        if (streq(argv[optind], "capture"))
-                return capture(bus, argv + optind);
-
-        if (streq(argv[optind], "status"))
-                return status(bus, argv + optind);
-
-        if (streq(argv[optind], "tree"))
-                return tree(bus, argv + optind);
-
-        if (streq(argv[optind], "introspect"))
-                return introspect(bus, argv + optind);
-
-        if (streq(argv[optind], "call"))
-                return call(bus, argv + optind);
-
-        if (streq(argv[optind], "get-property"))
-                return get_property(bus, argv + optind);
-
-        if (streq(argv[optind], "set-property"))
-                return set_property(bus, argv + optind);
-
-        if (streq(argv[optind], "help"))
-                return help();
+static int busctl_main(int argc, char *argv[]) {
+
+        static const Verb verbs[] = {
+                { "list",         VERB_ANY, 1,        VERB_DEFAULT, list_bus_names },
+                { "status",       VERB_ANY, 2,        0,            status         },
+                { "monitor",      VERB_ANY, VERB_ANY, 0,            verb_monitor   },
+                { "capture",      VERB_ANY, VERB_ANY, 0,            verb_capture   },
+                { "tree",         VERB_ANY, VERB_ANY, 0,            tree           },
+                { "introspect",   3,        4,        0,            introspect     },
+                { "call",         5,        VERB_ANY, 0,            call           },
+                { "get-property", 5,        VERB_ANY, 0,            get_property   },
+                { "set-property", 6,        VERB_ANY, 0,            set_property   },
+                { "help",         VERB_ANY, VERB_ANY, 0,            verb_help      },
+                {}
+        };
 
-        log_error("Unknown command '%s'", argv[optind]);
-        return -EINVAL;
+        return dispatch_verb(argc, argv, verbs, NULL);
 }
 
 int main(int argc, char *argv[]) {
-        sd_bus *bus = NULL;
         int r;
 
         log_parse_environment();
@@ -2027,98 +2083,14 @@ int main(int argc, char *argv[]) {
         if (r <= 0)
                 goto finish;
 
-        r = sd_bus_new(&bus);
-        if (r < 0) {
-                log_error_errno(r, "Failed to allocate bus: %m");
-                goto finish;
-        }
-
-        if (STRPTR_IN_SET(argv[optind], "monitor", "capture")) {
-
-                r = sd_bus_set_monitor(bus, true);
-                if (r < 0) {
-                        log_error_errno(r, "Failed to set monitor mode: %m");
-                        goto finish;
-                }
-
-                r = sd_bus_negotiate_creds(bus, true, _SD_BUS_CREDS_ALL);
-                if (r < 0) {
-                        log_error_errno(r, "Failed to enable credentials: %m");
-                        goto finish;
-                }
-
-                r = sd_bus_negotiate_timestamp(bus, true);
-                if (r < 0) {
-                        log_error_errno(r, "Failed to enable timestamps: %m");
-                        goto finish;
-                }
-
-                r = sd_bus_negotiate_fds(bus, true);
-                if (r < 0) {
-                        log_error_errno(r, "Failed to enable fds: %m");
-                        goto finish;
-                }
-        }
-
-        r = sd_bus_set_bus_client(bus, true);
-        if (r < 0) {
-                log_error_errno(r, "Failed to set bus client: %m");
-                goto finish;
-        }
-
-        r = sd_bus_set_watch_bind(bus, arg_watch_bind);
-        if (r < 0) {
-                log_error_errno(r, "Failed to set watch-bind setting to '%s': %m", yes_no(arg_watch_bind));
-                goto finish;
-        }
-
-        if (arg_address)
-                r = sd_bus_set_address(bus, arg_address);
-        else {
-                switch (arg_transport) {
-
-                case BUS_TRANSPORT_LOCAL:
-                        if (arg_user) {
-                                bus->is_user = true;
-                                r = bus_set_address_user(bus);
-                        } 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_MACHINE:
-                        r = bus_set_address_system_machine(bus, arg_host);
-                        break;
-
-                default:
-                        assert_not_reached("Hmm, unknown transport type.");
-                }
-        }
-        if (r < 0) {
-                log_error_errno(r, "Failed to set address: %m");
-                goto finish;
-        }
-
-        r = sd_bus_start(bus);
-        if (r < 0) {
-                log_error_errno(r, "Failed to connect to bus: %m");
-                goto finish;
-        }
-
-        r = busctl_main(bus, argc, argv);
+        r = busctl_main(argc, argv);
 
 finish:
         /* make sure we terminate the bus connection first, and then close the
          * pager, see issue #3543 for the details. */
-        sd_bus_flush_close_unref(bus);
         pager_close();
 
-        strv_free(arg_matches);
+        arg_matches = strv_free(arg_matches);
 
         return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
 }