/* SPDX-License-Identifier: LGPL-2.1-or-later */ #include #include #include "ansi-color.h" #include "networkctl.h" #include "networkctl-util.h" #include "strv.h" #include "varlink-util.h" int varlink_connect_networkd(sd_varlink **ret_varlink) { _cleanup_(sd_varlink_flush_close_unrefp) sd_varlink *vl = NULL; sd_json_variant *reply; uint64_t id; int r; r = sd_varlink_connect_address(&vl, "/run/systemd/netif/io.systemd.Network"); if (r < 0) return log_error_errno(r, "Failed to connect to network service /run/systemd/netif/io.systemd.Network: %m"); (void) sd_varlink_set_description(vl, "varlink-network"); r = sd_varlink_set_allow_fd_passing_output(vl, true); if (r < 0) return log_error_errno(r, "Failed to allow passing file descriptor through varlink: %m"); r = varlink_call_and_log(vl, "io.systemd.Network.GetNamespaceId", /* parameters= */ NULL, &reply); if (r < 0) return r; static const sd_json_dispatch_field dispatch_table[] = { { "NamespaceId", SD_JSON_VARIANT_UNSIGNED, sd_json_dispatch_uint64, 0, SD_JSON_MANDATORY }, {}, }; r = sd_json_dispatch(reply, dispatch_table, SD_JSON_LOG|SD_JSON_ALLOW_EXTENSIONS, &id); if (r < 0) return r; if (id == 0) log_debug("systemd-networkd.service not running in a network namespace (?), skipping netns check."); else { struct stat st; if (stat("/proc/self/ns/net", &st) < 0) return log_error_errno(errno, "Failed to determine our own network namespace ID: %m"); if (id != st.st_ino) return log_error_errno(SYNTHETIC_ERRNO(EREMOTE), "networkctl must be invoked in same network namespace as systemd-networkd.service."); } if (ret_varlink) *ret_varlink = TAKE_PTR(vl); return 0; } bool networkd_is_running(void) { static int cached = -1; int r; if (cached < 0) { r = access("/run/systemd/netif/state", F_OK); if (r < 0) { if (errno != ENOENT) log_debug_errno(errno, "Failed to determine whether networkd is running, assuming it's not: %m"); cached = false; } else cached = true; } return cached; } int acquire_bus(sd_bus **ret) { _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; int r; assert(ret); r = sd_bus_open_system(&bus); if (r < 0) return log_error_errno(r, "Failed to connect to system bus: %m"); (void) sd_bus_set_allow_interactive_authorization(bus, arg_ask_password); if (networkd_is_running()) { r = varlink_connect_networkd(/* ret_varlink = */ NULL); if (r < 0) return r; } else log_warning("systemd-networkd is not running, output might be incomplete."); *ret = TAKE_PTR(bus); return 0; } int link_get_property( sd_bus *bus, int ifindex, sd_bus_error *error, sd_bus_message **reply, const char *iface, const char *propname, const char *type) { _cleanup_free_ char *path = NULL; char ifindex_str[DECIMAL_STR_MAX(int)]; int r; assert(bus); assert(ifindex >= 0); assert(error); assert(reply); assert(iface); assert(propname); assert(type); xsprintf(ifindex_str, "%i", ifindex); r = sd_bus_path_encode("/org/freedesktop/network1/link", ifindex_str, &path); if (r < 0) return r; return sd_bus_get_property(bus, "org.freedesktop.network1", path, iface, propname, error, reply, type); } void operational_state_to_color(const char *name, const char *state, const char **on, const char **off) { if (STRPTR_IN_SET(state, "routable", "enslaved") || (streq_ptr(name, "lo") && streq_ptr(state, "carrier"))) { if (on) *on = ansi_highlight_green(); if (off) *off = ansi_normal(); } else if (streq_ptr(state, "degraded")) { if (on) *on = ansi_highlight_yellow(); if (off) *off = ansi_normal(); } else { if (on) *on = ""; if (off) *off = ""; } } void setup_state_to_color(const char *state, const char **on, const char **off) { if (streq_ptr(state, "configured")) { if (on) *on = ansi_highlight_green(); if (off) *off = ansi_normal(); } else if (streq_ptr(state, "configuring")) { if (on) *on = ansi_highlight_yellow(); if (off) *off = ansi_normal(); } else if (STRPTR_IN_SET(state, "failed", "linger")) { if (on) *on = ansi_highlight_red(); if (off) *off = ansi_normal(); } else { if (on) *on = ""; if (off) *off = ""; } } void online_state_to_color(const char *state, const char **on, const char **off) { if (streq_ptr(state, "online")) { if (on) *on = ansi_highlight_green(); if (off) *off = ansi_normal(); } else if (streq_ptr(state, "partial")) { if (on) *on = ansi_highlight_yellow(); if (off) *off = ansi_normal(); } else { if (on) *on = ""; if (off) *off = ""; } }