networkctl.c revision 5323ead145304785121b72dcbc1c244303de7575
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder This file is part of systemd.
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder Copyright 2014 Lennart Poettering
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder systemd is free software; you can redistribute it and/or modify it
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder under the terms of the GNU Lesser General Public License as published by
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder the Free Software Foundation; either version 2.1 of the License, or
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder (at your option) any later version.
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder systemd is distributed in the hope that it will be useful, but
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder WITHOUT ANY WARRANTY; without even the implied warranty of
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder Lesser General Public License for more details.
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder You should have received a copy of the GNU Lesser General Public License
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder along with systemd; If not, see <http://www.gnu.org/licenses/>.
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroederstatic bool arg_no_pager = false;
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroederstatic bool arg_legend = true;
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroederstatic bool arg_all = false;
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroederstatic void pager_open_if_enabled(void) {
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroederstatic int link_get_type_string(int iftype, struct udev_device *d, char **ret) {
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder /* WLANs have iftype ARPHRD_ETHER, but we want
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder * to show a more useful type string for
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder devtype = udev_device_get_devtype(d);
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroederstatic int link_info_compare(const void *a, const void *b) {
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder const LinkInfo *x = a, *y = b;
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroederstatic int decode_and_sort_links(sd_rtnl_message *m, LinkInfo **ret) {
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder _cleanup_free_ LinkInfo *links = NULL;
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder for (i = m; i; i = sd_rtnl_message_next(i)) {
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder r = sd_rtnl_message_get_type(i, &type);
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder r = sd_rtnl_message_link_get_ifindex(i, &ifindex);
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder r = sd_rtnl_message_read_string(i, IFLA_IFNAME, &name);
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder r = sd_rtnl_message_link_get_type(i, &iftype);
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder if (!GREEDY_REALLOC(links, size, c+1))
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder qsort(links, c, sizeof(LinkInfo), link_info_compare);
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder return (int) c;
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroederstatic int list_links(char **args, unsigned n) {
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder _cleanup_udev_unref_ struct udev *udev = NULL;
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder _cleanup_free_ LinkInfo *links = NULL;
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder log_error("Failed to connect to netlink: %s", strerror(-r));
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder log_error("Failed to connect to udev: %m");
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, 0);
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder r = sd_rtnl_message_request_dump(req, true);
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder r = sd_rtnl_call(rtnl, req, 0, &reply);
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder log_error("Failed to enumerate links: %s", strerror(-r));
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder printf("%3s %-16s %-10s %-11s %-10s\n", "IDX", "LINK", "TYPE", "ADMIN", "OPERATIONAL");
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder c = decode_and_sort_links(reply, &links);
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder for (i = 0; i < c; i++) {
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder _cleanup_free_ char *state = NULL, *operational_state = NULL;
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder _cleanup_udev_device_unref_ struct udev_device *d = NULL;
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder const char *on_color_oper = "", *off_color_oper = "",
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder char devid[2 + DECIMAL_STR_MAX(int)];
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder sd_network_get_link_state(links[i].ifindex, &state);
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder sd_network_get_link_operational_state(links[i].ifindex, &operational_state);
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder sprintf(devid, "n%i", links[i].ifindex);
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder d = udev_device_new_from_device_id(udev, devid);
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder link_get_type_string(links[i].iftype, d, &t);
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder if (streq_ptr(operational_state, "routable")) {
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder on_color_oper = ansi_highlight_green();
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder off_color_oper = ansi_highlight_off();
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder } else if (streq_ptr(operational_state, "degraded")) {
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder on_color_oper = ansi_highlight_yellow();
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder off_color_oper = ansi_highlight_off();
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder if (streq_ptr(state, "configured")) {
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder } else if (streq_ptr(state, "configuring")) {
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder } else if (streq_ptr(state, "failed") ||
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder printf("%3i %-16s %-10s %s%-11s%s %s%-10s%s\n", links[i].ifindex,
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder links[i].name, strna(t), on_color, strna(state), off_color,
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder on_color_oper, strna(operational_state), off_color_oper);
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroederstatic int dump_addresses(sd_rtnl *rtnl, const char *prefix, int ifindex) {
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder _cleanup_free_ struct local_address *local = NULL;
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder n = local_addresses(rtnl, ifindex, &local);
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder for (i = 0; i < n; i++) {
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder r = in_addr_to_string(local[i].family, &local[i].address, &pretty);
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroederstatic void dump_list(const char *prefix, char **l) {
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroederstatic int link_status_one(sd_rtnl *rtnl, struct udev *udev, const char *name) {
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder _cleanup_strv_free_ char **dns = NULL, **ntp = NULL;
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder _cleanup_free_ char *state = NULL, *operational_state = NULL;
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder _cleanup_udev_device_unref_ struct udev_device *d = NULL;
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder char devid[2 + DECIMAL_STR_MAX(int)];
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder const char *driver = NULL, *path = NULL, *vendor = NULL, *model = NULL;
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder const char *on_color = "", *off_color = "";
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder if (safe_atoi(name, &ifindex) >= 0 && ifindex > 0)
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, ifindex);
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, 0);
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder r = sd_rtnl_message_append_string(req, IFLA_IFNAME, name);
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder r = sd_rtnl_call(rtnl, req, 0, &reply);
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder log_error("Failed to query link: %s", strerror(-r));
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder r = sd_rtnl_message_link_get_ifindex(reply, &ifindex);
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder r = sd_rtnl_message_read_string(reply, IFLA_IFNAME, &name);
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder r = sd_rtnl_message_link_get_type(reply, &iftype);
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder have_mac = sd_rtnl_message_read_ether_addr(reply, IFLA_ADDRESS, &e) >= 0;
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder for (p = (uint8_t*) &e; p < (uint8_t*) &e + sizeof(e); p++)
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder sd_rtnl_message_read_u32(reply, IFLA_MTU, &mtu);
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder sd_network_get_link_state(ifindex, &state);
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder sd_network_get_link_operational_state(ifindex, &operational_state);
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder sd_network_get_link_dns(ifindex, &dns);
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder sd_network_get_link_ntp(ifindex, &ntp);
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder d = udev_device_new_from_device_id(udev, devid);
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder driver = udev_device_get_property_value(d, "ID_NET_DRIVER");
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder path = udev_device_get_property_value(d, "ID_PATH");
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder vendor = udev_device_get_property_value(d, "ID_VENDOR_FROM_DATABASE");
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder vendor = udev_device_get_property_value(d, "ID_VENDOR");
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder model = udev_device_get_property_value(d, "ID_MODEL_FROM_DATABASE");
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder model = udev_device_get_property_value(d, "ID_MODEL");
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder if (streq_ptr(operational_state, "routable")) {
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder } else if (streq_ptr(operational_state, "degraded")) {
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder printf("%s%s%s %i: %s\n", on_color, draw_special_char(DRAW_BLACK_CIRCLE), off_color, ifindex, name);
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder " State: %s%s%s (%s)\n",
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder on_color, strna(operational_state), off_color,
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder printf(" HW Address: %s\n", ether_ntoa(&e));
81f49ee02aaa3bc870401f8883bf52742eb3ea7aJonathan von Schroeder dump_addresses(rtnl, " Address: ", ifindex);
char **name;
if (!udev) {
return -errno;
return log_oom();
if (arg_all) {
return rtnl_log_create_error(r);
return rtnl_log_create_error(r);
return rtnl_log_parse_error(c);
static void help(void) {
help();
case ARG_VERSION:
case ARG_NO_PAGER:
arg_no_pager = true;
case ARG_NO_LEGEND:
arg_legend = false;
arg_all = true;
return -EINVAL;
const char* verb;
MORE,
LESS,
} argc_cmp;
const int argc;
} verbs[] = {
int left;
if (left <= 0)
help();
return -EINVAL;
case EQUAL:
return -EINVAL;
case MORE:
return -EINVAL;
case LESS:
return -EINVAL;
log_open();
goto finish;
pager_close();