From: Tom Gundersen Date: Thu, 8 May 2014 15:21:37 +0000 (+0200) Subject: sd-network: expose global operational state X-Git-Tag: v213~216 X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=commitdiff_plain;h=bbf7c04821a71fec67eaf0e7a34d17afc5913c13 sd-network: expose global operational state --- diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index 04b226561..ab3158356 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -1117,7 +1117,7 @@ static int link_acquire_conf(Link *link) { return 0; } -static bool link_has_carrier(unsigned flags, uint8_t operstate) { +bool link_has_carrier(unsigned flags, uint8_t operstate) { /* see Documentation/networking/operstates.txt in the kernel sources */ if (operstate == IF_OPER_UP) @@ -1689,6 +1689,11 @@ int link_save(Link *link) { assert(link); assert(link->state_file); + assert(link->manager); + + r = manager_save(link->manager); + if (r < 0) + return r; admin_state = link_state_to_string(link->state); assert(admin_state); @@ -1735,7 +1740,7 @@ int link_save(Link *link) { finish: if (r < 0) - log_error("Failed to save link data %s: %s", link->state_file, strerror(-r)); + log_error("Failed to save link data to %s: %s", link->state_file, strerror(-r)); return r; } diff --git a/src/network/networkd-manager.c b/src/network/networkd-manager.c index 28de7919d..4b2955333 100644 --- a/src/network/networkd-manager.c +++ b/src/network/networkd-manager.c @@ -20,6 +20,7 @@ ***/ #include +#include #include "path-util.h" #include "networkd.h" @@ -80,6 +81,10 @@ int manager_new(Manager **ret) { if (!m) return -ENOMEM; + m->state_file = strdup("/run/systemd/network/state"); + if (!m->state_file) + return -ENOMEM; + r = sd_event_default(&m->event); if (r < 0) return r; @@ -135,6 +140,8 @@ void manager_free(Manager *m) { if (!m) return; + free(m->state_file); + udev_monitor_unref(m->udev_monitor); udev_unref(m->udev); sd_bus_unref(m->bus); @@ -457,3 +464,55 @@ int manager_update_resolv_conf(Manager *m) { return 0; } + +int manager_save(Manager *m) { + Link *link; + Iterator i; + _cleanup_free_ char *temp_path = NULL; + _cleanup_fclose_ FILE *f = NULL; + const char *oper_state = "unknown"; + bool dormant, carrier; + int r; + + assert(m); + assert(m->state_file); + + HASHMAP_FOREACH(link, m->links, i) { + if (link->flags & IFF_LOOPBACK) + continue; + + if (link_has_carrier(link->flags, link->operstate)) + carrier = true; + else if (link->operstate == IF_OPER_DORMANT) + dormant = true; + } + + if (carrier) + oper_state = "carrier"; + else if (dormant) + oper_state = "dormant"; + + r = fopen_temporary(m->state_file, &f, &temp_path); + if (r < 0) + goto finish; + + fchmod(fileno(f), 0644); + + fprintf(f, + "# This is private data. Do not parse.\n" + "OPER_STATE=%s\n", oper_state); + + fflush(f); + + if (ferror(f) || rename(temp_path, m->state_file) < 0) { + r = -errno; + unlink(m->state_file); + unlink(temp_path); + } + +finish: + if (r < 0) + log_error("Failed to save network state to %s: %s", m->state_file, strerror(-r)); + + return r; +} diff --git a/src/network/networkd.h b/src/network/networkd.h index d31844aef..aebb28592 100644 --- a/src/network/networkd.h +++ b/src/network/networkd.h @@ -232,6 +232,8 @@ struct Manager { sd_event_source *sigterm_event_source; sd_event_source *sigint_event_source; + char *state_file; + Hashmap *links; Hashmap *netdevs; LIST_HEAD(Network, networks); @@ -256,6 +258,7 @@ int manager_udev_listen(Manager *m); int manager_bus_listen(Manager *m); int manager_update_resolv_conf(Manager *m); +int manager_save(Manager *m); DEFINE_TRIVIAL_CLEANUP_FUNC(Manager*, manager_free); #define _cleanup_manager_free_ _cleanup_(manager_freep) @@ -377,6 +380,8 @@ int link_initialized(Link *link, struct udev_device *device); int link_save(Link *link); +bool link_has_carrier(unsigned flags, uint8_t operstate); + const char* link_state_to_string(LinkState s) _const_; LinkState link_state_from_string(const char *s) _pure_; diff --git a/src/network/sd-network.c b/src/network/sd-network.c index c86781220..492e97c73 100644 --- a/src/network/sd-network.c +++ b/src/network/sd-network.c @@ -95,6 +95,27 @@ _public_ int sd_network_get_link_state(unsigned index, char **state) { return 0; } +_public_ int sd_network_get_operational_state(char **state) { + _cleanup_free_ char *s = NULL; + int r; + + assert_return(state, -EINVAL); + + r = parse_env_file("/run/systemd/network/state", NEWLINE, "OPER_STATE", + &s, NULL); + if (r == -ENOENT) + return -ENODATA; + else if (r < 0) + return r; + else if (!s) + return -EIO; + + *state = s; + s = NULL; + + return 0; +} + _public_ int sd_network_get_link_operational_state(unsigned index, char **state) { _cleanup_free_ char *s = NULL, *p = NULL; int r; diff --git a/src/systemd/sd-network.h b/src/systemd/sd-network.h index 40bd75a23..d0b2ea357 100644 --- a/src/systemd/sd-network.h +++ b/src/systemd/sd-network.h @@ -67,6 +67,13 @@ int sd_network_get_link_state(unsigned index, char **state); */ int sd_network_get_link_operational_state(unsigned index, char **state); +/* Get overall opeartional state + * Possible states: unknown, dormant, carrier + * Possible return codes: + * -ENODATA: networkd is not aware of any links + */ +int sd_network_get_operational_state(char **state); + /* Returns true if link exists and is loopback, and false otherwise */ int sd_network_link_is_loopback(unsigned index);