networkctl.c revision 5323ead145304785121b72dcbc1c244303de7575
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering/***
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering This file is part of systemd.
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering Copyright 2014 Lennart Poettering
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering systemd is free software; you can redistribute it and/or modify it
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering under the terms of the GNU Lesser General Public License as published by
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering the Free Software Foundation; either version 2.1 of the License, or
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering (at your option) any later version.
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering systemd is distributed in the hope that it will be useful, but
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering Lesser General Public License for more details.
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering You should have received a copy of the GNU Lesser General Public License
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering***/
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering#include <stdbool.h>
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering#include <getopt.h>
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering#include "sd-network.h"
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering#include "sd-rtnl.h"
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering#include "libudev.h"
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering#include "build.h"
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering#include "util.h"
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering#include "pager.h"
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering#include "rtnl-util.h"
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering#include "udev-util.h"
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering#include "arphrd-list.h"
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering#include "local-addresses.h"
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poetteringstatic bool arg_no_pager = false;
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poetteringstatic bool arg_legend = true;
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poetteringstatic bool arg_all = false;
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poetteringstatic void pager_open_if_enabled(void) {
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering if (arg_no_pager)
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering return;
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering pager_open(false);
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering}
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poetteringstatic int link_get_type_string(int iftype, struct udev_device *d, char **ret) {
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering const char *t;
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering char *p;
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering if (iftype == ARPHRD_ETHER && d) {
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering const char *devtype, *id = NULL;
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering /* WLANs have iftype ARPHRD_ETHER, but we want
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering * to show a more useful type string for
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering * them */
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering devtype = udev_device_get_devtype(d);
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering if (streq_ptr(devtype, "wlan"))
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering id = "wlan";
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering else if (streq_ptr(devtype, "wwan"))
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering id = "wwan";
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering if (id) {
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering p = strdup(id);
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering if (!p)
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering return -ENOMEM;
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering *ret = p;
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering return 1;
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering }
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering }
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering t = arphrd_to_name(iftype);
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering if (!t) {
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering *ret = NULL;
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering return 0;
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering }
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering p = strdup(t);
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering if (!p)
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering return -ENOMEM;
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering ascii_strlower(p);
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering *ret = p;
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering return 0;
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering}
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poetteringtypedef struct LinkInfo {
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering const char *name;
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering int ifindex;
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering unsigned iftype;
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering} LinkInfo;
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poetteringstatic int link_info_compare(const void *a, const void *b) {
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering const LinkInfo *x = a, *y = b;
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering return x->ifindex - y->ifindex;
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering}
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poetteringstatic int decode_and_sort_links(sd_rtnl_message *m, LinkInfo **ret) {
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering _cleanup_free_ LinkInfo *links = NULL;
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering size_t size = 0, c = 0;
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering sd_rtnl_message *i;
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering int r;
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering for (i = m; i; i = sd_rtnl_message_next(i)) {
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering const char *name;
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering unsigned iftype;
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering uint16_t type;
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering int ifindex;
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering r = sd_rtnl_message_get_type(i, &type);
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering if (r < 0)
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering return r;
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering if (type != RTM_NEWLINK)
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering continue;
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering r = sd_rtnl_message_link_get_ifindex(i, &ifindex);
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering if (r < 0)
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering return r;
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering r = sd_rtnl_message_read_string(i, IFLA_IFNAME, &name);
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering if (r < 0)
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering return r;
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering r = sd_rtnl_message_link_get_type(i, &iftype);
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering if (r < 0)
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering return r;
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering if (!GREEDY_REALLOC(links, size, c+1))
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering return -ENOMEM;
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering links[c].name = name;
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering links[c].ifindex = ifindex;
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering links[c].iftype = iftype;
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering c++;
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering }
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering qsort(links, c, sizeof(LinkInfo), link_info_compare);
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering *ret = links;
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering links = NULL;
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering return (int) c;
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering}
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poetteringstatic int list_links(char **args, unsigned n) {
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering _cleanup_udev_unref_ struct udev *udev = NULL;
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
6de0e0e500d9d534c6e4baab242fc2a146f021faLennart Poettering _cleanup_free_ LinkInfo *links = NULL;
6de0e0e500d9d534c6e4baab242fc2a146f021faLennart Poettering int r, c, i;
6de0e0e500d9d534c6e4baab242fc2a146f021faLennart Poettering
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering pager_open_if_enabled();
6de0e0e500d9d534c6e4baab242fc2a146f021faLennart Poettering
6de0e0e500d9d534c6e4baab242fc2a146f021faLennart Poettering r = sd_rtnl_open(&rtnl, 0);
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering if (r < 0) {
6de0e0e500d9d534c6e4baab242fc2a146f021faLennart Poettering log_error("Failed to connect to netlink: %s", strerror(-r));
6de0e0e500d9d534c6e4baab242fc2a146f021faLennart Poettering return r;
6de0e0e500d9d534c6e4baab242fc2a146f021faLennart Poettering }
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering
6de0e0e500d9d534c6e4baab242fc2a146f021faLennart Poettering udev = udev_new();
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering if (!udev) {
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering log_error("Failed to connect to udev: %m");
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering return -errno;
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering }
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, 0);
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering if (r < 0)
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering return rtnl_log_create_error(r);
6de0e0e500d9d534c6e4baab242fc2a146f021faLennart Poettering
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering r = sd_rtnl_message_request_dump(req, true);
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering if (r < 0)
6de0e0e500d9d534c6e4baab242fc2a146f021faLennart Poettering return rtnl_log_create_error(r);
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering r = sd_rtnl_call(rtnl, req, 0, &reply);
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering if (r < 0) {
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering log_error("Failed to enumerate links: %s", strerror(-r));
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering return r;
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering }
6de0e0e500d9d534c6e4baab242fc2a146f021faLennart Poettering
6de0e0e500d9d534c6e4baab242fc2a146f021faLennart Poettering if (arg_legend)
6de0e0e500d9d534c6e4baab242fc2a146f021faLennart Poettering printf("%3s %-16s %-10s %-11s %-10s\n", "IDX", "LINK", "TYPE", "ADMIN", "OPERATIONAL");
6de0e0e500d9d534c6e4baab242fc2a146f021faLennart Poettering
6de0e0e500d9d534c6e4baab242fc2a146f021faLennart Poettering c = decode_and_sort_links(reply, &links);
6de0e0e500d9d534c6e4baab242fc2a146f021faLennart Poettering if (c < 0)
6de0e0e500d9d534c6e4baab242fc2a146f021faLennart Poettering return rtnl_log_parse_error(c);
6de0e0e500d9d534c6e4baab242fc2a146f021faLennart Poettering
6de0e0e500d9d534c6e4baab242fc2a146f021faLennart Poettering for (i = 0; i < c; i++) {
6de0e0e500d9d534c6e4baab242fc2a146f021faLennart Poettering _cleanup_free_ char *state = NULL, *operational_state = NULL;
6de0e0e500d9d534c6e4baab242fc2a146f021faLennart Poettering _cleanup_udev_device_unref_ struct udev_device *d = NULL;
6de0e0e500d9d534c6e4baab242fc2a146f021faLennart Poettering const char *on_color_oper = "", *off_color_oper = "",
6de0e0e500d9d534c6e4baab242fc2a146f021faLennart Poettering *on_color = "", *off_color = "";
6de0e0e500d9d534c6e4baab242fc2a146f021faLennart Poettering char devid[2 + DECIMAL_STR_MAX(int)];
6de0e0e500d9d534c6e4baab242fc2a146f021faLennart Poettering _cleanup_free_ char *t = NULL;
6de0e0e500d9d534c6e4baab242fc2a146f021faLennart Poettering
6de0e0e500d9d534c6e4baab242fc2a146f021faLennart Poettering sd_network_get_link_state(links[i].ifindex, &state);
6de0e0e500d9d534c6e4baab242fc2a146f021faLennart Poettering sd_network_get_link_operational_state(links[i].ifindex, &operational_state);
6de0e0e500d9d534c6e4baab242fc2a146f021faLennart Poettering
6de0e0e500d9d534c6e4baab242fc2a146f021faLennart Poettering sprintf(devid, "n%i", links[i].ifindex);
6de0e0e500d9d534c6e4baab242fc2a146f021faLennart Poettering d = udev_device_new_from_device_id(udev, devid);
6de0e0e500d9d534c6e4baab242fc2a146f021faLennart Poettering
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering link_get_type_string(links[i].iftype, d, &t);
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering if (streq_ptr(operational_state, "routable")) {
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering on_color_oper = ansi_highlight_green();
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering off_color_oper = ansi_highlight_off();
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering } else if (streq_ptr(operational_state, "degraded")) {
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering on_color_oper = ansi_highlight_yellow();
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering off_color_oper = ansi_highlight_off();
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering }
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering if (streq_ptr(state, "configured")) {
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering on_color = ansi_highlight_green();
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering off_color = ansi_highlight_off();
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering } else if (streq_ptr(state, "configuring")) {
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering on_color = ansi_highlight_yellow();
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering off_color = ansi_highlight_off();
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering } else if (streq_ptr(state, "failed") ||
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering streq_ptr(state, "linger")) {
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering on_color = ansi_highlight_red();
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering off_color = ansi_highlight_off();
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering }
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering printf("%3i %-16s %-10s %s%-11s%s %s%-10s%s\n", links[i].ifindex,
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering links[i].name, strna(t), on_color, strna(state), off_color,
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering on_color_oper, strna(operational_state), off_color_oper);
6de0e0e500d9d534c6e4baab242fc2a146f021faLennart Poettering }
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering if (arg_legend)
6de0e0e500d9d534c6e4baab242fc2a146f021faLennart Poettering printf("\n%i links listed.\n", c);
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering return 0;
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering}
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poetteringstatic int dump_addresses(sd_rtnl *rtnl, const char *prefix, int ifindex) {
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering _cleanup_free_ struct local_address *local = NULL;
6de0e0e500d9d534c6e4baab242fc2a146f021faLennart Poettering int r, n, i;
6de0e0e500d9d534c6e4baab242fc2a146f021faLennart Poettering
6de0e0e500d9d534c6e4baab242fc2a146f021faLennart Poettering n = local_addresses(rtnl, ifindex, &local);
6de0e0e500d9d534c6e4baab242fc2a146f021faLennart Poettering if (n < 0)
6de0e0e500d9d534c6e4baab242fc2a146f021faLennart Poettering return n;
6de0e0e500d9d534c6e4baab242fc2a146f021faLennart Poettering
6de0e0e500d9d534c6e4baab242fc2a146f021faLennart Poettering for (i = 0; i < n; i++) {
6de0e0e500d9d534c6e4baab242fc2a146f021faLennart Poettering _cleanup_free_ char *pretty = NULL;
6de0e0e500d9d534c6e4baab242fc2a146f021faLennart Poettering
6de0e0e500d9d534c6e4baab242fc2a146f021faLennart Poettering r = in_addr_to_string(local[i].family, &local[i].address, &pretty);
6de0e0e500d9d534c6e4baab242fc2a146f021faLennart Poettering if (r < 0)
6de0e0e500d9d534c6e4baab242fc2a146f021faLennart Poettering return r;
6de0e0e500d9d534c6e4baab242fc2a146f021faLennart Poettering
6de0e0e500d9d534c6e4baab242fc2a146f021faLennart Poettering printf("%*s%s\n",
6de0e0e500d9d534c6e4baab242fc2a146f021faLennart Poettering (int) strlen(prefix),
6de0e0e500d9d534c6e4baab242fc2a146f021faLennart Poettering i == 0 ? prefix : "",
6de0e0e500d9d534c6e4baab242fc2a146f021faLennart Poettering pretty);
6de0e0e500d9d534c6e4baab242fc2a146f021faLennart Poettering }
6de0e0e500d9d534c6e4baab242fc2a146f021faLennart Poettering
6de0e0e500d9d534c6e4baab242fc2a146f021faLennart Poettering return 0;
6de0e0e500d9d534c6e4baab242fc2a146f021faLennart Poettering}
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poetteringstatic void dump_list(const char *prefix, char **l) {
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering char **i;
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering STRV_FOREACH(i, l) {
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering printf("%*s%s\n",
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering (int) strlen(prefix),
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering i == l ? prefix : "",
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering *i);
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering }
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering}
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poetteringstatic int link_status_one(sd_rtnl *rtnl, struct udev *udev, const char *name) {
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering _cleanup_strv_free_ char **dns = NULL, **ntp = NULL;
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering _cleanup_free_ char *state = NULL, *operational_state = NULL;
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering _cleanup_udev_device_unref_ struct udev_device *d = NULL;
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering char devid[2 + DECIMAL_STR_MAX(int)];
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering _cleanup_free_ char *t = NULL;
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering const char *driver = NULL, *path = NULL, *vendor = NULL, *model = NULL;
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering const char *on_color = "", *off_color = "";
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering struct ether_addr e;
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering unsigned iftype;
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering int r, ifindex;
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering bool have_mac;
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering uint32_t mtu;
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering assert(rtnl);
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering assert(udev);
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering assert(name);
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering if (safe_atoi(name, &ifindex) >= 0 && ifindex > 0)
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, ifindex);
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering else {
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, 0);
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering if (r < 0)
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering return rtnl_log_create_error(r);
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering r = sd_rtnl_message_append_string(req, IFLA_IFNAME, name);
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering }
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering if (r < 0)
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering return rtnl_log_create_error(r);
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering r = sd_rtnl_call(rtnl, req, 0, &reply);
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering if (r < 0) {
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering log_error("Failed to query link: %s", strerror(-r));
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering return r;
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering }
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering r = sd_rtnl_message_link_get_ifindex(reply, &ifindex);
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering if (r < 0)
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering return rtnl_log_parse_error(r);
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering r = sd_rtnl_message_read_string(reply, IFLA_IFNAME, &name);
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering if (r < 0)
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering return rtnl_log_parse_error(r);
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering r = sd_rtnl_message_link_get_type(reply, &iftype);
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering if (r < 0)
6de0e0e500d9d534c6e4baab242fc2a146f021faLennart Poettering return rtnl_log_parse_error(r);
6de0e0e500d9d534c6e4baab242fc2a146f021faLennart Poettering
6de0e0e500d9d534c6e4baab242fc2a146f021faLennart Poettering have_mac = sd_rtnl_message_read_ether_addr(reply, IFLA_ADDRESS, &e) >= 0;
6de0e0e500d9d534c6e4baab242fc2a146f021faLennart Poettering
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering if (have_mac) {
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering const uint8_t *p;
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering bool all_zeroes = true;
e9d21f240704f87c6bb5f7fca1c5e6d0f31c84cdLennart Poettering
for (p = (uint8_t*) &e; p < (uint8_t*) &e + sizeof(e); p++)
if (*p != 0) {
all_zeroes = false;
break;
}
if (all_zeroes)
have_mac = false;
}
sd_rtnl_message_read_u32(reply, IFLA_MTU, &mtu);
sd_network_get_link_state(ifindex, &state);
sd_network_get_link_operational_state(ifindex, &operational_state);
sd_network_get_link_dns(ifindex, &dns);
sd_network_get_link_ntp(ifindex, &ntp);
sprintf(devid, "n%i", ifindex);
d = udev_device_new_from_device_id(udev, devid);
link_get_type_string(iftype, d, &t);
if (d) {
driver = udev_device_get_property_value(d, "ID_NET_DRIVER");
path = udev_device_get_property_value(d, "ID_PATH");
vendor = udev_device_get_property_value(d, "ID_VENDOR_FROM_DATABASE");
if (!vendor)
vendor = udev_device_get_property_value(d, "ID_VENDOR");
model = udev_device_get_property_value(d, "ID_MODEL_FROM_DATABASE");
if (!model)
model = udev_device_get_property_value(d, "ID_MODEL");
}
if (streq_ptr(operational_state, "routable")) {
on_color = ansi_highlight_green();
off_color = ansi_highlight_off();
} else if (streq_ptr(operational_state, "degraded")) {
on_color = ansi_highlight_yellow();
off_color = ansi_highlight_off();
}
printf("%s%s%s %i: %s\n", on_color, draw_special_char(DRAW_BLACK_CIRCLE), off_color, ifindex, name);
printf(" Type: %s\n"
" State: %s%s%s (%s)\n",
strna(t),
on_color, strna(operational_state), off_color,
strna(state));
if (path)
printf(" Path: %s\n", path);
if (driver)
printf(" Driver: %s\n", driver);
if (vendor)
printf(" Vendor: %s\n", vendor);
if (model)
printf(" Model: %s\n", model);
if (have_mac)
printf(" HW Address: %s\n", ether_ntoa(&e));
if (mtu > 0)
printf(" MTU: %u\n", mtu);
dump_addresses(rtnl, " Address: ", ifindex);
if (!strv_isempty(dns))
dump_list(" DNS: ", dns);
if (!strv_isempty(ntp))
dump_list(" NTP: ", ntp);
return 0;
}
static int link_status(char **args, unsigned n) {
_cleanup_udev_unref_ struct udev *udev = NULL;
_cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
char **name;
int r;
r = sd_rtnl_open(&rtnl, 0);
if (r < 0) {
log_error("Failed to connect to netlink: %s", strerror(-r));
return r;
}
udev = udev_new();
if (!udev) {
log_error("Failed to connect to udev: %m");
return -errno;
}
if (n <= 1 && !arg_all) {
_cleanup_free_ char *operational_state = NULL;
_cleanup_strv_free_ char **dns = NULL, **ntp = NULL;
_cleanup_free_ struct local_address *addresses = NULL;
const char *on_color_oper = "", *off_color_oper = "";
int i, c;
sd_network_get_operational_state(&operational_state);
if (streq_ptr(operational_state, "routable")) {
on_color_oper = ansi_highlight_green();
off_color_oper = ansi_highlight_off();
} else if (streq_ptr(operational_state, "degraded")) {
on_color_oper = ansi_highlight_yellow();
off_color_oper = ansi_highlight_off();
}
printf(" State: %s%s%s\n", on_color_oper, strna(operational_state), off_color_oper);
c = local_addresses(rtnl, 0, &addresses);
for (i = 0; i < c; i++) {
_cleanup_free_ char *pretty = NULL;
r = in_addr_to_string(addresses[i].family, &addresses[i].address, &pretty);
if (r < 0)
return log_oom();
printf("%13s %s\n",
i > 0 ? "" : "Address:", pretty);
}
sd_network_get_dns(&dns);
if (!strv_isempty(dns))
dump_list(" DNS: ", dns);
sd_network_get_dns(&ntp);
if (!strv_isempty(ntp))
dump_list(" NTP: ", ntp);
return 0;
}
pager_open_if_enabled();
if (arg_all) {
_cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
_cleanup_free_ LinkInfo *links = NULL;
int c, i;
r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, 0);
if (r < 0)
return rtnl_log_create_error(r);
r = sd_rtnl_message_request_dump(req, true);
if (r < 0)
return rtnl_log_create_error(r);
r = sd_rtnl_call(rtnl, req, 0, &reply);
if (r < 0) {
log_error("Failed to enumerate links: %s", strerror(-r));
return r;
}
c = decode_and_sort_links(reply, &links);
if (c < 0)
return rtnl_log_parse_error(c);
for (i = 0; i < c; i++) {
if (i > 0)
fputc('\n', stdout);
link_status_one(rtnl, udev, links[i].name);
}
}
STRV_FOREACH(name, args + 1) {
if (name != args+1)
fputc('\n', stdout);
link_status_one(rtnl, udev, *name);
}
return 0;
}
static void help(void) {
printf("%s [OPTIONS...]\n\n"
"Query and control the networking subsystem.\n\n"
" -h --help Show this help\n"
" --version Show package version\n"
" --no-pager Do not pipe output into a pager\n"
" --no-legend Do not show the headers and footers\n"
" -a --all Show status for all links\n\n"
"Commands:\n"
" list List links\n"
" status LINK Show link status\n"
, program_invocation_short_name);
}
static int parse_argv(int argc, char *argv[]) {
enum {
ARG_VERSION = 0x100,
ARG_NO_PAGER,
ARG_NO_LEGEND,
};
static const struct option options[] = {
{ "help", no_argument, NULL, 'h' },
{ "version", no_argument, NULL, ARG_VERSION },
{ "no-pager", no_argument, NULL, ARG_NO_PAGER },
{ "no-legend", no_argument, NULL, ARG_NO_LEGEND },
{ "all", no_argument, NULL, 'a' },
{}
};
int c;
assert(argc >= 0);
assert(argv);
while ((c = getopt_long(argc, argv, "ha", options, NULL)) >= 0) {
switch (c) {
case 'h':
help();
return 0;
case ARG_VERSION:
puts(PACKAGE_STRING);
puts(SYSTEMD_FEATURES);
return 0;
case ARG_NO_PAGER:
arg_no_pager = true;
break;
case ARG_NO_LEGEND:
arg_legend = false;
break;
case 'a':
arg_all = true;
break;
case '?':
return -EINVAL;
default:
assert_not_reached("Unhandled option");
}
}
return 1;
}
static int networkctl_main(int argc, char *argv[]) {
static const struct {
const char* verb;
const enum {
MORE,
LESS,
EQUAL
} argc_cmp;
const int argc;
int (* const dispatch)(char **args, unsigned n);
} verbs[] = {
{ "list", LESS, 1, list_links },
{ "status", MORE, 1, link_status },
};
int left;
unsigned i;
assert(argc >= 0);
assert(argv);
left = argc - optind;
if (left <= 0)
/* Special rule: no arguments means "list" */
i = 0;
else {
if (streq(argv[optind], "help")) {
help();
return 0;
}
for (i = 0; i < ELEMENTSOF(verbs); i++)
if (streq(argv[optind], verbs[i].verb))
break;
if (i >= ELEMENTSOF(verbs)) {
log_error("Unknown operation %s", argv[optind]);
return -EINVAL;
}
}
switch (verbs[i].argc_cmp) {
case EQUAL:
if (left != verbs[i].argc) {
log_error("Invalid number of arguments.");
return -EINVAL;
}
break;
case MORE:
if (left < verbs[i].argc) {
log_error("Too few arguments.");
return -EINVAL;
}
break;
case LESS:
if (left > verbs[i].argc) {
log_error("Too many arguments.");
return -EINVAL;
}
break;
default:
assert_not_reached("Unknown comparison operator.");
}
return verbs[i].dispatch(argv + optind, left);
}
int main(int argc, char* argv[]) {
int r;
log_parse_environment();
log_open();
r = parse_argv(argc, argv);
if (r <= 0)
goto finish;
r = networkctl_main(argc, argv);
finish:
pager_close();
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}