networkctl.c revision 1d050e1e0a7082e23ee9b31fa0b819cb332b3444
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering/***
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering This file is part of systemd.
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering Copyright 2014 Lennart Poettering
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering systemd is free software; you can redistribute it and/or modify it
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering under the terms of the GNU Lesser General Public License as published by
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering the Free Software Foundation; either version 2.1 of the License, or
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering (at your option) any later version.
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering systemd is distributed in the hope that it will be useful, but
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering Lesser General Public License for more details.
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering You should have received a copy of the GNU Lesser General Public License
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering***/
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering#include <stdbool.h>
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering#include <getopt.h>
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering#include "sd-network.h"
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering#include "sd-rtnl.h"
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering#include "libudev.h"
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering#include "build.h"
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering#include "util.h"
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering#include "pager.h"
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering#include "rtnl-util.h"
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering#include "udev-util.h"
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering#include "arphrd-list.h"
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering#include "local-addresses.h"
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering#include "socket-util.h"
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering#include "ether-addr-util.h"
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poetteringstatic bool arg_no_pager = false;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poetteringstatic bool arg_legend = true;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poetteringstatic bool arg_all = false;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poetteringstatic void pager_open_if_enabled(void) {
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering if (arg_no_pager)
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering return;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering pager_open(false);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering}
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poetteringstatic int link_get_type_string(int iftype, struct udev_device *d, char **ret) {
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering const char *t;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering char *p;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering if (iftype == ARPHRD_ETHER && d) {
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering const char *devtype, *id = NULL;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering /* WLANs have iftype ARPHRD_ETHER, but we want
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering * to show a more useful type string for
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering * them */
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering devtype = udev_device_get_devtype(d);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering if (streq_ptr(devtype, "wlan"))
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering id = "wlan";
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering else if (streq_ptr(devtype, "wwan"))
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering id = "wwan";
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering if (id) {
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering p = strdup(id);
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering if (!p)
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering return -ENOMEM;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering *ret = p;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering return 1;
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering }
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering }
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering t = arphrd_to_name(iftype);
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering if (!t) {
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering *ret = NULL;
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering return 0;
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering }
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering p = strdup(t);
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering if (!p)
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering return -ENOMEM;
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering ascii_strlower(p);
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering *ret = p;
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering return 0;
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering}
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poetteringtypedef struct LinkInfo {
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering const char *name;
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering int ifindex;
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering unsigned iftype;
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering} LinkInfo;
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poetteringstatic int link_info_compare(const void *a, const void *b) {
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering const LinkInfo *x = a, *y = b;
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering return x->ifindex - y->ifindex;
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering}
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poetteringstatic int decode_and_sort_links(sd_rtnl_message *m, LinkInfo **ret) {
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering _cleanup_free_ LinkInfo *links = NULL;
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering size_t size = 0, c = 0;
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering sd_rtnl_message *i;
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering int r;
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering for (i = m; i; i = sd_rtnl_message_next(i)) {
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering const char *name;
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering unsigned iftype;
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering uint16_t type;
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering int ifindex;
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering r = sd_rtnl_message_get_type(i, &type);
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering if (r < 0)
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering return r;
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering if (type != RTM_NEWLINK)
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering continue;
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering r = sd_rtnl_message_link_get_ifindex(i, &ifindex);
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering if (r < 0)
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering return r;
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering r = sd_rtnl_message_read_string(i, IFLA_IFNAME, &name);
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering if (r < 0)
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering return r;
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering r = sd_rtnl_message_link_get_type(i, &iftype);
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering if (r < 0)
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering return r;
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering if (!GREEDY_REALLOC(links, size, c+1))
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering return -ENOMEM;
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering links[c].name = name;
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering links[c].ifindex = ifindex;
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering links[c].iftype = iftype;
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering c++;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering }
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering qsort_safe(links, c, sizeof(LinkInfo), link_info_compare);
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering *ret = links;
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering links = NULL;
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering return (int) c;
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering}
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poetteringstatic void operational_state_to_color(const char *state, const char **on, const char **off) {
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering assert(on);
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering assert(off);
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering if (streq_ptr(state, "routable")) {
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering *on = ansi_highlight_green();
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering *off = ansi_highlight_off();
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering } else if (streq_ptr(state, "degraded")) {
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering *on = ansi_highlight_yellow();
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering *off = ansi_highlight_off();
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering } else
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering *on = *off = "";
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering}
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poetteringstatic void setup_state_to_color(const char *state, const char **on, const char **off) {
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering assert(on);
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering assert(off);
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering if (streq_ptr(state, "configured")) {
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering *on = ansi_highlight_green();
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering *off = ansi_highlight_off();
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering } else if (streq_ptr(state, "configuring")) {
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering *on = ansi_highlight_yellow();
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering *off = ansi_highlight_off();
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering } else if (streq_ptr(state, "failed") || streq_ptr(state, "linger")) {
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering *on = ansi_highlight_red();
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering *off = ansi_highlight_off();
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering } else
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering *on = *off = "";
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering}
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poetteringstatic int list_links(char **args, unsigned n) {
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering _cleanup_udev_unref_ struct udev *udev = NULL;
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering _cleanup_free_ LinkInfo *links = NULL;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering int r, c, i;
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering pager_open_if_enabled();
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering r = sd_rtnl_open(&rtnl, 0);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering if (r < 0)
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering return log_error_errno(r, "Failed to connect to netlink: %m");
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering udev = udev_new();
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering if (!udev)
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering return log_error_errno(errno, "Failed to connect to udev: %m");
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, 0);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering if (r < 0)
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering return rtnl_log_create_error(r);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering r = sd_rtnl_message_request_dump(req, true);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering if (r < 0)
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering return rtnl_log_create_error(r);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering r = sd_rtnl_call(rtnl, req, 0, &reply);
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering if (r < 0)
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering return log_error_errno(r, "Failed to enumerate links: %m");
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering if (arg_legend)
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering printf("%3s %-16s %-18s %-11s %-10s\n", "IDX", "LINK", "TYPE", "OPERATIONAL", "SETUP");
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering c = decode_and_sort_links(reply, &links);
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering if (c < 0)
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering return rtnl_log_parse_error(c);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering for (i = 0; i < c; i++) {
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering _cleanup_free_ char *setup_state = NULL, *operational_state = NULL;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering _cleanup_udev_device_unref_ struct udev_device *d = NULL;
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering const char *on_color_operational, *off_color_operational,
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering *on_color_setup, *off_color_setup;
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering char devid[2 + DECIMAL_STR_MAX(int)];
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering _cleanup_free_ char *t = NULL;
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering sd_network_link_get_operational_state(links[i].ifindex, &operational_state);
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering operational_state_to_color(operational_state, &on_color_operational, &off_color_operational);
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering sd_network_link_get_setup_state(links[i].ifindex, &setup_state);
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering setup_state_to_color(setup_state, &on_color_setup, &off_color_setup);
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering sprintf(devid, "n%i", links[i].ifindex);
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering d = udev_device_new_from_device_id(udev, devid);
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering link_get_type_string(links[i].iftype, d, &t);
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering printf("%3i %-16s %-18s %s%-11s%s %s%-10s%s\n",
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering links[i].ifindex, links[i].name, strna(t),
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering on_color_operational, strna(operational_state), off_color_operational,
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering on_color_setup, strna(setup_state), off_color_setup);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering }
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering if (arg_legend)
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering printf("\n%i links listed.\n", c);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering return 0;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering}
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering/* IEEE Organizationally Unique Identifier vendor string */
04d39279245834494baccfdb9349db8bf80abd13Lennart Poetteringstatic int ieee_oui(struct udev_hwdb *hwdb, struct ether_addr *mac, char **ret) {
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering struct udev_list_entry *entry;
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering char *description;
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering char str[strlen("OUI:XXYYXXYYXXYY") + 1];
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering /* skip commonly misused 00:00:00 (Xerox) prefix */
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering if (memcmp(mac, "\0\0\0", 3) == 0)
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering return -EINVAL;
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering snprintf(str, sizeof(str), "OUI:" ETHER_ADDR_FORMAT_STR, ETHER_ADDR_FORMAT_VAL(*mac));
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering udev_list_entry_foreach(entry, udev_hwdb_get_properties_list_entry(hwdb, str, 0))
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering if (strcmp(udev_list_entry_get_name(entry), "ID_OUI_FROM_DATABASE") == 0) {
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering description = strdup(udev_list_entry_get_value(entry));
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering if (!description)
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering return -ENOMEM;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering *ret = description;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering return 0;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering }
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering return -ENODATA;
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering}
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poetteringstatic int get_gateway_description(sd_rtnl *rtnl, struct udev_hwdb *hwdb, int ifindex, int family,
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering union in_addr_union *gateway, char **gateway_description) {
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering sd_rtnl_message *m;
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering int r;
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering assert(rtnl);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering assert(ifindex >= 0);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering assert(family == AF_INET || family == AF_INET6);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering assert(gateway);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering assert(gateway_description);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering r = sd_rtnl_message_new_neigh(rtnl, &req, RTM_GETNEIGH, ifindex, family);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering if (r < 0)
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering return r;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering r = sd_rtnl_message_request_dump(req, true);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering if (r < 0)
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering return r;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering r = sd_rtnl_call(rtnl, req, 0, &reply);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering if (r < 0)
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering return r;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering for (m = reply; m; m = sd_rtnl_message_next(m)) {
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering union in_addr_union gw = {};
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering struct ether_addr mac = {};
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering uint16_t type;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering int ifi, fam;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering r = sd_rtnl_message_get_errno(m);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering if (r < 0) {
eaf73b061604c028aa28f960870a9b46aab2f76aLuke Shumaker log_error_errno(r, "got error: %m");
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering continue;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering }
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering r = sd_rtnl_message_get_type(m, &type);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering if (r < 0) {
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering log_error_errno(r, "could not get type: %m");
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering continue;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering }
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering if (type != RTM_NEWNEIGH) {
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering log_error("type is not RTM_NEWNEIGH");
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering continue;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering }
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering r = sd_rtnl_message_neigh_get_family(m, &fam);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering if (r < 0) {
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering log_error_errno(r, "could not get family: %m");
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering continue;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering }
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering if (fam != family) {
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering log_error("family is not correct");
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering continue;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering }
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering r = sd_rtnl_message_neigh_get_ifindex(m, &ifi);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering if (r < 0) {
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering log_error_errno(r, "could not get ifindex: %m");
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering continue;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering }
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering if (ifindex > 0 && ifi != ifindex)
4ba93280223ceb5de1bcedb196c38252f334521aLennart Poettering continue;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering switch (fam) {
90d14d2015dda79c7b465b74dd3aaf2dfc25d43cLuke Shumaker case AF_INET:
90d14d2015dda79c7b465b74dd3aaf2dfc25d43cLuke Shumaker r = sd_rtnl_message_read_in_addr(m, NDA_DST, &gw.in);
90d14d2015dda79c7b465b74dd3aaf2dfc25d43cLuke Shumaker if (r < 0)
90d14d2015dda79c7b465b74dd3aaf2dfc25d43cLuke Shumaker continue;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering break;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering case AF_INET6:
eaf73b061604c028aa28f960870a9b46aab2f76aLuke Shumaker r = sd_rtnl_message_read_in6_addr(m, NDA_DST, &gw.in6);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering if (r < 0)
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering continue;
90d14d2015dda79c7b465b74dd3aaf2dfc25d43cLuke Shumaker
90d14d2015dda79c7b465b74dd3aaf2dfc25d43cLuke Shumaker break;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering default:
90d14d2015dda79c7b465b74dd3aaf2dfc25d43cLuke Shumaker continue;
90d14d2015dda79c7b465b74dd3aaf2dfc25d43cLuke Shumaker }
90d14d2015dda79c7b465b74dd3aaf2dfc25d43cLuke Shumaker
90d14d2015dda79c7b465b74dd3aaf2dfc25d43cLuke Shumaker if (!in_addr_equal(fam, &gw, gateway))
90d14d2015dda79c7b465b74dd3aaf2dfc25d43cLuke Shumaker continue;
90d14d2015dda79c7b465b74dd3aaf2dfc25d43cLuke Shumaker
90d14d2015dda79c7b465b74dd3aaf2dfc25d43cLuke Shumaker r = sd_rtnl_message_read_ether_addr(m, NDA_LLADDR, &mac);
90d14d2015dda79c7b465b74dd3aaf2dfc25d43cLuke Shumaker if (r < 0)
90d14d2015dda79c7b465b74dd3aaf2dfc25d43cLuke Shumaker continue;
90d14d2015dda79c7b465b74dd3aaf2dfc25d43cLuke Shumaker
90d14d2015dda79c7b465b74dd3aaf2dfc25d43cLuke Shumaker r = ieee_oui(hwdb, &mac, gateway_description);
90d14d2015dda79c7b465b74dd3aaf2dfc25d43cLuke Shumaker if (r < 0)
90d14d2015dda79c7b465b74dd3aaf2dfc25d43cLuke Shumaker continue;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering return 0;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering }
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
90d14d2015dda79c7b465b74dd3aaf2dfc25d43cLuke Shumaker return -ENODATA;
90d14d2015dda79c7b465b74dd3aaf2dfc25d43cLuke Shumaker}
90d14d2015dda79c7b465b74dd3aaf2dfc25d43cLuke Shumaker
90d14d2015dda79c7b465b74dd3aaf2dfc25d43cLuke Shumakerstatic int dump_gateways(sd_rtnl *rtnl, struct udev_hwdb *hwdb, const char *prefix, int ifindex) {
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering sd_rtnl_message *m;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering bool first = true;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering int r;
assert(rtnl);
assert(ifindex >= 0);
r = sd_rtnl_message_new_route(rtnl, &req, RTM_GETROUTE, AF_UNSPEC, RTPROT_UNSPEC);
if (r < 0)
return r;
r = sd_rtnl_message_request_dump(req, true);
if (r < 0)
return r;
r = sd_rtnl_call(rtnl, req, 0, &reply);
if (r < 0)
return r;
for (m = reply; m; m = sd_rtnl_message_next(m)) {
_cleanup_free_ char *gateway = NULL, *gateway_description = NULL;
union in_addr_union gw = {};
uint16_t type;
uint32_t ifi;
int family;
r = sd_rtnl_message_get_errno(m);
if (r < 0) {
log_error_errno(r, "got error: %m");
continue;
}
r = sd_rtnl_message_get_type(m, &type);
if (r < 0) {
log_error_errno(r, "could not get type: %m");
continue;
}
if (type != RTM_NEWROUTE) {
log_error("type is not RTM_NEWROUTE");
continue;
}
r = sd_rtnl_message_route_get_family(m, &family);
if (r < 0) {
log_error_errno(r, "could not get family: %m");
continue;
}
r = sd_rtnl_message_read_u32(m, RTA_OIF, &ifi);
if (r < 0) {
log_error_errno(r, "could not get RTA_OIF: %m");
continue;
}
if (ifindex > 0 && ifi != (unsigned) ifindex)
continue;
switch (family) {
case AF_INET:
r = sd_rtnl_message_read_in_addr(m, RTA_GATEWAY, &gw.in);
if (r < 0)
continue;
r = sd_rtnl_message_read_in_addr(m, RTA_DST, NULL);
if (r >= 0)
continue;
r = sd_rtnl_message_read_in_addr(m, RTA_SRC, NULL);
if (r >= 0)
continue;
break;
case AF_INET6:
r = sd_rtnl_message_read_in6_addr(m, RTA_GATEWAY, &gw.in6);
if (r < 0)
continue;
r = sd_rtnl_message_read_in6_addr(m, RTA_DST, NULL);
if (r >= 0)
continue;
r = sd_rtnl_message_read_in6_addr(m, RTA_SRC, NULL);
if (r >= 0)
continue;
break;
default:
continue;
}
r = in_addr_to_string(family, &gw, &gateway);
if (r < 0)
continue;
r = get_gateway_description(rtnl, hwdb, ifi, family, &gw, &gateway_description);
if (r < 0)
log_debug("could not get description of gateway: %s", strerror(-r));
if (gateway_description)
printf("%*s%s (%s)\n",
(int) strlen(prefix),
first ? prefix : "",
gateway, gateway_description);
else
printf("%*s%s\n",
(int) strlen(prefix),
first ? prefix : "",
gateway);
first = false;
}
return 0;
}
static int dump_addresses(sd_rtnl *rtnl, const char *prefix, int ifindex) {
_cleanup_free_ struct local_address *local = NULL;
int r, n, i;
n = local_addresses(rtnl, ifindex, AF_UNSPEC, &local);
if (n < 0)
return n;
for (i = 0; i < n; i++) {
_cleanup_free_ char *pretty = NULL;
r = in_addr_to_string(local[i].family, &local[i].address, &pretty);
if (r < 0)
return r;
printf("%*s%s\n",
(int) strlen(prefix),
i == 0 ? prefix : "",
pretty);
}
return 0;
}
static void dump_list(const char *prefix, char **l) {
char **i;
STRV_FOREACH(i, l) {
printf("%*s%s\n",
(int) strlen(prefix),
i == l ? prefix : "",
*i);
}
}
static int link_status_one(sd_rtnl *rtnl, struct udev *udev, const char *name) {
_cleanup_strv_free_ char **dns = NULL, **ntp = NULL, **domains = NULL;
_cleanup_free_ char *setup_state = NULL, *operational_state = NULL;
_cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
_cleanup_udev_device_unref_ struct udev_device *d = NULL;
_cleanup_udev_hwdb_unref_ struct udev_hwdb *hwdb = NULL;
char devid[2 + DECIMAL_STR_MAX(int)];
_cleanup_free_ char *t = NULL, *network = NULL;
const char *driver = NULL, *path = NULL, *vendor = NULL, *model = NULL, *link = NULL;
const char *on_color_operational, *off_color_operational,
*on_color_setup, *off_color_setup;
struct ether_addr e;
unsigned iftype;
int r, ifindex;
bool have_mac;
uint32_t mtu;
assert(rtnl);
assert(udev);
assert(name);
if (safe_atoi(name, &ifindex) >= 0 && ifindex > 0)
r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, ifindex);
else {
r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, 0);
if (r < 0)
return rtnl_log_create_error(r);
r = sd_rtnl_message_append_string(req, IFLA_IFNAME, name);
}
if (r < 0)
return rtnl_log_create_error(r);
r = sd_rtnl_call(rtnl, req, 0, &reply);
if (r < 0)
return log_error_errno(r, "Failed to query link: %m");
r = sd_rtnl_message_link_get_ifindex(reply, &ifindex);
if (r < 0)
return rtnl_log_parse_error(r);
r = sd_rtnl_message_read_string(reply, IFLA_IFNAME, &name);
if (r < 0)
return rtnl_log_parse_error(r);
r = sd_rtnl_message_link_get_type(reply, &iftype);
if (r < 0)
return rtnl_log_parse_error(r);
have_mac = sd_rtnl_message_read_ether_addr(reply, IFLA_ADDRESS, &e) >= 0;
if (have_mac) {
const uint8_t *p;
bool all_zeroes = true;
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_link_get_operational_state(ifindex, &operational_state);
operational_state_to_color(operational_state, &on_color_operational, &off_color_operational);
sd_network_link_get_setup_state(ifindex, &setup_state);
setup_state_to_color(setup_state, &on_color_setup, &off_color_setup);
sd_network_link_get_dns(ifindex, &dns);
sd_network_link_get_ntp(ifindex, &ntp);
sd_network_link_get_domains(ifindex, &domains);
r = sd_network_link_get_wildcard_domain(ifindex);
if (r > 0) {
char *wildcard;
wildcard = strdup("*");
if (!wildcard)
return log_oom();
if (strv_consume(&domains, wildcard) < 0)
return log_oom();
}
sprintf(devid, "n%i", ifindex);
d = udev_device_new_from_device_id(udev, devid);
link_get_type_string(iftype, d, &t);
if (d) {
link = udev_device_get_property_value(d, "ID_NET_LINK_FILE");
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");
}
sd_network_link_get_network_file(ifindex, &network);
printf("%s%s%s %i: %s\n", on_color_operational, draw_special_char(DRAW_BLACK_CIRCLE), off_color_operational, ifindex, name);
printf(" Link File: %s\n"
"Network File: %s\n"
" Type: %s\n"
" State: %s%s%s (%s%s%s)\n",
strna(link),
strna(network),
strna(t),
on_color_operational, strna(operational_state), off_color_operational,
on_color_setup, strna(setup_state), off_color_setup);
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) {
char ea[ETHER_ADDR_TO_STRING_MAX];
printf(" HW Address: %s\n", ether_addr_to_string(&e, ea));
}
if (mtu > 0)
printf(" MTU: %u\n", mtu);
hwdb = udev_hwdb_new(udev);
dump_gateways(rtnl, hwdb, " Gateway: ", ifindex);
dump_addresses(rtnl, " Address: ", ifindex);
if (!strv_isempty(dns))
dump_list(" DNS: ", dns);
if (!strv_isempty(domains))
dump_list(" Domain: ", domains);
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)
return log_error_errno(r, "Failed to connect to netlink: %m");
udev = udev_new();
if (!udev)
return log_error_errno(errno, "Failed to connect to udev: %m");
if (n <= 1 && !arg_all) {
_cleanup_free_ char *operational_state = NULL;
_cleanup_strv_free_ char **dns = NULL, **ntp = NULL, **domains = NULL;
_cleanup_free_ struct local_address *addresses = NULL;
const char *on_color_operational, *off_color_operational;
int i, c;
sd_network_get_operational_state(&operational_state);
operational_state_to_color(operational_state, &on_color_operational, &off_color_operational);
printf(" State: %s%s%s\n", on_color_operational, strna(operational_state), off_color_operational);
c = local_addresses(rtnl, 0, AF_UNSPEC, &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_domains(&domains);
if (!strv_isempty(domains))
dump_list(" Domain: ", domains);
sd_network_get_ntp(&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)
return log_error_errno(r, "Failed to enumerate links: %m");
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;
}