From 44574b1d813183abce2ec32b2d43198ca177d67e Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Mon, 10 Feb 2014 18:29:06 +0100 Subject: [PATCH] miraclectl: add scan commands Three new commands that control scans on a given link are added: 1) start-scan: Starts scanning in background for a given link 2) stop-scan: Stops scanning in background for a given link 3) scan: Does interactive scanning for a given link The interactive scanning basically calls start-scan and stop-scan. In between, it listens for dbus-signals for new peers and displays them if they are assigned to the given link. This should be used for basic p2p-device scanning on a link. Signed-off-by: David Herrmann --- src/miraclectl.c | 476 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 476 insertions(+) diff --git a/src/miraclectl.c b/src/miraclectl.c index c73174d..c7ffe14 100644 --- a/src/miraclectl.c +++ b/src/miraclectl.c @@ -26,16 +26,120 @@ #include #include #include +#include #include #include #include #include +#include #include #include "miracle.h" #include "shl_log.h" #include "shl_macro.h" #include "shl_util.h" +/* + * Helpers for interactive commands + */ + +static sd_bus *cli_bus; +static sd_event *cli_event; +static sd_event_source *cli_sigs[_NSIG]; + +static int cli_signal_fn(sd_event_source *source, + const struct signalfd_siginfo *ssi, + void *data) +{ + if (ssi->ssi_signo == SIGCHLD) { + log_debug("caught SIGCHLD for %d", (int)ssi->ssi_pid); + return 0; + } + + log_notice("caught signal %d, exiting..", (int)ssi->ssi_signo); + sd_event_exit(cli_event, 0); + + return 0; +} + +static void cli_destroy(void) +{ + unsigned int i; + + if (!cli_bus) + return; + + for (i = 0; cli_sigs[i]; ++i) { + sd_event_source_unref(cli_sigs[i]); + cli_sigs[i] = NULL; + } + + sd_event_unref(cli_event); + cli_event = NULL; + sd_bus_unref(cli_bus); + cli_bus = NULL; +} + +static int cli_init(sd_bus *bus) +{ + static const int sigs[] = { + SIGINT, SIGTERM, SIGQUIT, SIGHUP, SIGPIPE, SIGCHLD, 0 + }; + unsigned int i; + sigset_t mask; + int r; + + if (cli_bus || !bus) + return log_EINVAL(); + + cli_bus = sd_bus_ref(bus); + + r = sd_event_default(&cli_event); + if (r < 0) { + log_vERR(r); + goto error; + } + + r = sd_bus_attach_event(cli_bus, cli_event, 0); + if (r < 0) { + log_vERR(r); + goto error; + } + + for (i = 0; sigs[i]; ++i) { + sigemptyset(&mask); + sigaddset(&mask, sigs[i]); + sigprocmask(SIG_BLOCK, &mask, NULL); + + r = sd_event_add_signal(cli_event, + sigs[i], + cli_signal_fn, + NULL, + &cli_sigs[i]); + if (r < 0) { + log_vERR(r); + goto error; + } + } + + return 0; + +error: + cli_destroy(); + return r; +} + +static int cli_run(void) +{ + if (!cli_bus) + return log_EINVAL(); + + return sd_event_loop(cli_event); +} + +/* + * verb: list + */ + static int verb_list_links(sd_bus *bus, sd_bus_message *m) { char *link; @@ -280,6 +384,10 @@ static int verb_list(sd_bus *bus, char **args, unsigned int n) return 0; } +/* + * verb: show-link + */ + static int verb_show_link(sd_bus *bus, char **args, unsigned int n) { _cleanup_sd_bus_error_ sd_bus_error err = SD_BUS_ERROR_NULL; @@ -375,6 +483,10 @@ static int verb_show_link(sd_bus *bus, char **args, unsigned int n) return 0; } +/* + * verb: show-peer + */ + static int verb_show_peer(sd_bus *bus, char **args, unsigned int n) { _cleanup_sd_bus_error_ sd_bus_error err = SD_BUS_ERROR_NULL; @@ -503,6 +615,10 @@ static int verb_show_peer(sd_bus *bus, char **args, unsigned int n) return 0; } +/* + * verb: add-link + */ + static int verb_add_link(sd_bus *bus, char **args, unsigned int n) { _cleanup_sd_bus_error_ sd_bus_error err = SD_BUS_ERROR_NULL; @@ -537,6 +653,10 @@ static int verb_add_link(sd_bus *bus, char **args, unsigned int n) return 0; } +/* + * verb: remove-link + */ + static int verb_remove_link(sd_bus *bus, char **args, unsigned int n) { _cleanup_sd_bus_error_ sd_bus_error err = SD_BUS_ERROR_NULL; @@ -560,6 +680,10 @@ static int verb_remove_link(sd_bus *bus, char **args, unsigned int n) return 0; } +/* + * verb: set-link-name + */ + static int verb_set_link_name(sd_bus *bus, char **args, unsigned int n) { _cleanup_sd_bus_error_ sd_bus_error err = SD_BUS_ERROR_NULL; @@ -612,6 +736,352 @@ static int verb_set_link_name(sd_bus *bus, char **args, unsigned int n) return 0; } +/* + * verb: start-scan + */ + +static int verb_start_scan(sd_bus *bus, char **args, unsigned int n) +{ + _cleanup_sd_bus_error_ sd_bus_error err = SD_BUS_ERROR_NULL; + _cleanup_free_ char *path = NULL, *name = NULL; + int r; + + name = sd_bus_label_escape(args[1]); + if (!name) + return log_ENOMEM(); + + path = shl_strcat("/org/freedesktop/miracle/link/", name); + if (!path) + return log_ENOMEM(); + + r = sd_bus_call_method(bus, + "org.freedesktop.miracle", + path, + "org.freedesktop.miracle.Link", + "StartScan", + &err, + NULL, + NULL); + if (r < 0) { + log_error("cannot start scan on link %s: %s", + args[1], bus_error_message(&err, r)); + return r; + } + + printf("Scan on link %s started\n", args[1]); + return 0; +} + +/* + * verb: stop-scan + */ + +static int verb_stop_scan(sd_bus *bus, char **args, unsigned int n) +{ + _cleanup_sd_bus_error_ sd_bus_error err = SD_BUS_ERROR_NULL; + _cleanup_free_ char *path = NULL, *name = NULL; + int r; + + name = sd_bus_label_escape(args[1]); + if (!name) + return log_ENOMEM(); + + path = shl_strcat("/org/freedesktop/miracle/link/", name); + if (!path) + return log_ENOMEM(); + + r = sd_bus_call_method(bus, + "org.freedesktop.miracle", + path, + "org.freedesktop.miracle.Link", + "StopScan", + &err, + NULL, + NULL); + if (r < 0) { + log_error("cannot stop scan on link %s: %s", + args[1], bus_error_message(&err, r)); + return r; + } + + printf("Scan on link %s stopped\n", args[1]); + return 0; +} + +/* + * verb: scan + */ + +static int verb_scan_list_peer(sd_bus *bus, + sd_bus_message *m, + const char *link_filter, + const char *peer) +{ + const char *obj, *link = NULL, *name = NULL; + int r, connected = false; + + r = sd_bus_message_enter_container(m, 'a', "{sa{sv}}"); + if (r < 0) + return log_bus_parser(r); + + while ((r = sd_bus_message_enter_container(m, + 'e', + "sa{sv}")) > 0) { + r = sd_bus_message_read(m, "s", &obj); + if (r < 0) + return log_bus_parser(r); + + if (strcmp(obj, "org.freedesktop.miracle.Peer")) { + r = sd_bus_message_skip(m, "a{sv}"); + if (r < 0) + return log_bus_parser(r); + r = sd_bus_message_exit_container(m); + if (r < 0) + return log_bus_parser(r); + continue; + } + + r = sd_bus_message_enter_container(m, 'a', "{sv}"); + if (r < 0) + return log_bus_parser(r); + + while ((r = sd_bus_message_enter_container(m, + 'e', + "sv")) > 0) { + r = sd_bus_message_read(m, "s", &obj); + if (r < 0) + return log_bus_parser(r); + + if (!strcmp(obj, "Link")) { + r = bus_message_read_basic_variant(m, "o", + &obj); + if (r < 0) + return log_bus_parser(r); + + obj = shl_startswith(obj, + "/org/freedesktop/miracle/link/"); + if (obj) + link = obj; + } else if (!strcmp(obj, "Name")) { + r = bus_message_read_basic_variant(m, "s", + &name); + if (r < 0) + return log_bus_parser(r); + } else if (!strcmp(obj, "Connected")) { + r = bus_message_read_basic_variant(m, "b", + &connected); + if (r < 0) + return log_bus_parser(r); + } else { + sd_bus_message_skip(m, "v"); + } + + r = sd_bus_message_exit_container(m); + if (r < 0) + return log_bus_parser(r); + } + if (r < 0) + return log_bus_parser(r); + + r = sd_bus_message_exit_container(m); + if (r < 0) + return log_bus_parser(r); + + r = sd_bus_message_exit_container(m); + if (r < 0) + return log_bus_parser(r); + } + if (r < 0) + return log_bus_parser(r); + + r = sd_bus_message_exit_container(m); + if (r < 0) + return log_bus_parser(r); + + if (!strcmp(link, link_filter)) + printf("%4s %-24s %-4s\n", + peer, name, connected ? "yes" : "no"); + + return 0; +} + +static int verb_scan_list(sd_bus *bus, const char *link) +{ + _cleanup_sd_bus_message_ sd_bus_message *m = NULL; + _cleanup_sd_bus_error_ sd_bus_error err = SD_BUS_ERROR_NULL; + _cleanup_free_ char *peer = NULL; + const char *obj; + int r; + + r = sd_bus_call_method(bus, + "org.freedesktop.miracle", + "/org/freedesktop/miracle", + "org.freedesktop.DBus.ObjectManager", + "GetManagedObjects", + &err, + &m, + ""); + if (r < 0) { + log_error("cannot retrieve objects: %s", + bus_error_message(&err, r)); + return r; + } + + r = sd_bus_message_enter_container(m, 'a', "{oa{sa{sv}}}"); + if (r < 0) + return log_bus_parser(r); + + while ((r = sd_bus_message_enter_container(m, + 'e', + "oa{sa{sv}}")) > 0) { + r = sd_bus_message_read(m, "o", &obj); + if (r < 0) + return log_bus_parser(r); + + obj = shl_startswith(obj, "/org/freedesktop/miracle/peer/"); + if (!obj) { + r = sd_bus_message_skip(m, "a{sa{sv}}"); + if (r < 0) + return log_bus_parser(r); + r = sd_bus_message_exit_container(m); + if (r < 0) + return log_bus_parser(r); + continue; + } + + free(peer); + peer = sd_bus_label_unescape(obj); + if (!peer) + return log_ENOMEM(); + + r = verb_scan_list_peer(bus, m, link, peer); + if (r < 0) + return r; + + r = sd_bus_message_exit_container(m); + if (r < 0) + return log_bus_parser(r); + } + if (r < 0) + return log_bus_parser(r); + + r = sd_bus_message_exit_container(m); + if (r < 0) + return log_bus_parser(r); + + return 0; +} + +static int verb_scan_match_fn(sd_bus *bus, + sd_bus_message *m, + void *data, + sd_bus_error *err) +{ + _cleanup_free_ char *peer = NULL; + const char *obj, *link = data; + int r; + + r = sd_bus_message_read(m, "o", &obj); + if (r < 0) + return log_bus_parser(r); + + obj = shl_startswith(obj, "/org/freedesktop/miracle/peer/"); + if (!obj) + return 0; + + peer = sd_bus_label_unescape(obj); + if (!peer) + return log_ENOMEM(); + + r = verb_scan_list_peer(bus, m, link, peer); + if (r < 0) + return r; + + return 0; +} + +static void verb_scan_listen(sd_bus *bus, const char *link) +{ + int r; + + r = sd_bus_add_match(bus, + "type='signal'," + "sender='org.freedesktop.miracle'," + "interface='org.freedesktop.DBus.ObjectManager'," + "member='InterfacesAdded'", + verb_scan_match_fn, + (void*)link); + if (r < 0) + return log_error("cannot add dbus match: %d", r); + + r = cli_init(bus); + if (r < 0) + goto error; + + verb_scan_list(bus, link); + cli_run(); + +error: + cli_destroy(); + sd_bus_remove_match(bus, + "type='signal'," + "sender='org.freedesktop.miracle'," + "interface='org.freedesktop.DBus.ObjectManager'", + verb_scan_match_fn, + NULL); +} + +static int verb_scan(sd_bus *bus, char **args, unsigned int n) +{ + _cleanup_sd_bus_error_ sd_bus_error err = SD_BUS_ERROR_NULL; + _cleanup_free_ char *path = NULL, *name = NULL; + int r; + + name = sd_bus_label_escape(args[1]); + if (!name) + return log_ENOMEM(); + + path = shl_strcat("/org/freedesktop/miracle/link/", name); + if (!path) + return log_ENOMEM(); + + r = sd_bus_call_method(bus, + "org.freedesktop.miracle", + path, + "org.freedesktop.miracle.Link", + "StartScan", + &err, + NULL, + NULL); + if (r < 0) + log_warning("cannot start scan on link %s (already running?): %s", + args[1], bus_error_message(&err, r)); + + printf("Scan on link %s started, listing peers..\n", args[1]); + printf("%4s %-24s %-4s\n", "ID", "NAME", "CONNECTED"); + verb_scan_listen(bus, name); + + r = sd_bus_call_method(bus, + "org.freedesktop.miracle", + path, + "org.freedesktop.miracle.Link", + "StopScan", + &err, + NULL, + NULL); + if (r < 0) + log_error("cannot stop scan on link %s: %s", + args[1], bus_error_message(&err, r)); + else + printf("Scan on link %s stopped\n", args[1]); + + return 0; +} + +/* + * main + */ + static int help(void) { /* @@ -632,6 +1102,9 @@ static int help(void) " add-link LINK... Start managing the given link\n" " remove-link LINK... Stop managing the given link\n" " set-link-name LINK NAME Set friendly-name of given link\n" + " start-scan LINK... Start peer discovery on given link\n" + " stop-scan LINK... Stop peer discovery on given link\n" + " scan LINK... Interactive scan on given link\n" , program_invocation_short_name); /* * 80-char barrier: @@ -696,6 +1169,9 @@ static int miraclectl_main(sd_bus *bus, int argc, char *argv[]) { "add-link", EQUAL, 3, verb_add_link }, { "remove-link", EQUAL, 2, verb_remove_link }, { "set-link-name", EQUAL, 3, verb_set_link_name }, + { "start-scan", EQUAL, 2, verb_start_scan }, + { "stop-scan", EQUAL, 2, verb_stop_scan }, + { "scan", EQUAL, 2, verb_scan }, }; int left; unsigned int i;