networkctl.c revision 8b43440b7ef4b81c69c31de7ff820dc07a780254
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
/***
This file is part of systemd.
Copyright 2014 Lennart Poettering
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
systemd is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#include <getopt.h>
#include <stdbool.h>
#include "sd-device.h"
#include "sd-hwdb.h"
#include "sd-netlink.h"
#include "sd-network.h"
#include "arphrd-list.h"
#include "device-util.h"
#include "ether-addr-util.h"
#include "hwdb-util.h"
#include "lldp.h"
#include "local-addresses.h"
#include "netlink-util.h"
#include "pager.h"
#include "parse-util.h"
#include "socket-util.h"
#include "string-util.h"
#include "string-table.h"
#include "strv.h"
#include "terminal-util.h"
#include "util.h"
#include "verbs.h"
static bool arg_no_pager = false;
static bool arg_legend = true;
static bool arg_all = false;
static void pager_open_if_enabled(void) {
if (arg_no_pager)
return;
pager_open(false);
}
const char *t;
char *p;
if (iftype == ARPHRD_ETHER && d) {
/* WLANs have iftype ARPHRD_ETHER, but we want
* to show a more useful type string for
* them */
(void)sd_device_get_devtype(d, &devtype);
id = "wlan";
id = "wwan";
if (id) {
if (!p)
return -ENOMEM;
*ret = p;
return 1;
}
}
t = arphrd_to_name(iftype);
if (!t) {
return 0;
}
p = strdup(t);
if (!p)
return -ENOMEM;
ascii_strlower(p);
*ret = p;
return 0;
}
typedef struct LinkInfo {
const char *name;
int ifindex;
unsigned iftype;
} LinkInfo;
static int link_info_compare(const void *a, const void *b) {
const LinkInfo *x = a, *y = b;
}
int r;
for (i = m; i; i = sd_netlink_message_next(i)) {
const char *name;
unsigned iftype;
int ifindex;
r = sd_netlink_message_get_type(i, &type);
if (r < 0)
return r;
if (type != RTM_NEWLINK)
continue;
r = sd_rtnl_message_link_get_ifindex(i, &ifindex);
if (r < 0)
return r;
if (r < 0)
return r;
r = sd_rtnl_message_link_get_type(i, &iftype);
if (r < 0)
return r;
return -ENOMEM;
c++;
}
return (int) c;
}
*on = ansi_highlight_green();
*off = ansi_normal();
*on = ansi_highlight_yellow();
*off = ansi_normal();
} else
}
*on = ansi_highlight_green();
*off = ansi_normal();
*on = ansi_highlight_yellow();
*off = ansi_normal();
*on = ansi_highlight_red();
*off = ansi_normal();
} else
}
int r, c, i;
r = sd_netlink_open(&rtnl);
if (r < 0)
return log_error_errno(r, "Failed to connect to netlink: %m");
if (r < 0)
return rtnl_log_create_error(r);
r = sd_netlink_message_request_dump(req, true);
if (r < 0)
return rtnl_log_create_error(r);
if (r < 0)
return log_error_errno(r, "Failed to enumerate links: %m");
if (arg_legend)
if (c < 0)
return rtnl_log_parse_error(c);
for (i = 0; i < c; i++) {
const char *on_color_operational, *off_color_operational,
_cleanup_free_ char *t = NULL;
(void)sd_device_new_from_device_id(&d, devid);
printf("%3i %-16s %-18s %s%-11s%s %s%-10s%s\n",
}
if (arg_legend)
printf("\n%i links listed.\n", c);
return 0;
}
/* IEEE Organizationally Unique Identifier vendor string */
const char *description;
int r;
if (!hwdb)
return -EINVAL;
if (!mac)
return -EINVAL;
/* skip commonly misused 00:00:00 (Xerox) prefix */
return -EINVAL;
if (r < 0)
return r;
if (!desc)
return -ENOMEM;
return 0;
}
static int get_gateway_description(
int ifindex,
int family,
union in_addr_union *gateway,
char **gateway_description) {
int r;
if (r < 0)
return r;
r = sd_netlink_message_request_dump(req, true);
if (r < 0)
return r;
if (r < 0)
return r;
for (m = reply; m; m = sd_netlink_message_next(m)) {
union in_addr_union gw = {};
struct ether_addr mac = {};
r = sd_netlink_message_get_errno(m);
if (r < 0) {
log_error_errno(r, "got error: %m");
continue;
}
r = sd_netlink_message_get_type(m, &type);
if (r < 0) {
log_error_errno(r, "could not get type: %m");
continue;
}
if (type != RTM_NEWNEIGH) {
log_error("type is not RTM_NEWNEIGH");
continue;
}
r = sd_rtnl_message_neigh_get_family(m, &fam);
if (r < 0) {
log_error_errno(r, "could not get family: %m");
continue;
}
log_error("family is not correct");
continue;
}
r = sd_rtnl_message_neigh_get_ifindex(m, &ifi);
if (r < 0) {
log_error_errno(r, "could not get ifindex: %m");
continue;
}
continue;
switch (fam) {
case AF_INET:
if (r < 0)
continue;
break;
case AF_INET6:
if (r < 0)
continue;
break;
default:
continue;
}
continue;
if (r < 0)
continue;
if (r < 0)
continue;
return 0;
}
return -ENODATA;
}
static int dump_gateways(
const char *prefix,
int ifindex) {
int r, n, i;
if (n < 0)
return n;
for (i = 0; i < n; i++) {
if (r < 0)
return r;
r = get_gateway_description(rtnl, hwdb, local[i].ifindex, local[i].family, &local[i].address, &description);
if (r < 0)
log_debug_errno(r, "Could not get description of gateway: %m");
printf("%*s%s",
i == 0 ? prefix : "",
gateway);
if (description)
/* Show interface name for the entry if we show
* entries for all interfaces */
if (ifindex <= 0) {
} else
}
}
return 0;
}
static int dump_addresses(
const char *prefix,
int ifindex) {
int r, n, i;
if (n < 0)
return n;
for (i = 0; i < n; i++) {
if (r < 0)
return r;
printf("%*s%s",
i == 0 ? prefix : "",
pretty);
if (ifindex <= 0) {
} else
}
}
return 0;
}
char **i;
STRV_FOREACH(i, l) {
printf("%*s%s\n",
i == l ? prefix : "",
*i);
}
}
static int link_status_one(
const char *name) {
const char *on_color_operational, *off_color_operational,
struct ether_addr e;
unsigned iftype;
int r, ifindex;
bool have_mac;
else {
if (r < 0)
return rtnl_log_create_error(r);
}
if (r < 0)
return rtnl_log_create_error(r);
if (r < 0)
return log_error_errno(r, "Failed to query link: %m");
if (r < 0)
return rtnl_log_parse_error(r);
if (r < 0)
return rtnl_log_parse_error(r);
if (r < 0)
return rtnl_log_parse_error(r);
if (have_mac) {
const uint8_t *p;
bool all_zeroes = true;
if (*p != 0) {
all_zeroes = false;
break;
}
if (all_zeroes)
have_mac = false;
}
if (r > 0) {
char *wildcard;
if (!wildcard)
return log_oom();
return log_oom();
}
(void)sd_device_new_from_device_id(&d, devid);
if (d) {
if (r < 0)
if (r < 0)
}
link_get_type_string(iftype, d, &t);
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(t),
if (path)
if (driver)
if (vendor)
if (model)
if (have_mac) {
char ea[ETHER_ADDR_TO_STRING_MAX];
if (description)
else
}
if (mtu > 0)
if (!strv_isempty(dns))
if (!strv_isempty(domains))
if (!strv_isempty(ntp))
if (!strv_isempty(carrier_bound_to))
if (!strv_isempty(carrier_bound_by))
if (tz)
return 0;
}
char **name;
int r;
r = sd_netlink_open(&rtnl);
if (r < 0)
return log_error_errno(r, "Failed to connect to netlink: %m");
r = sd_hwdb_new(&hwdb);
if (r < 0)
log_debug_errno(r, "Failed to open hardware database: %m");
const char *on_color_operational, *off_color_operational;
printf("%s%s%s State: %s%s%s\n",
if (!strv_isempty(dns))
if (!strv_isempty(domains))
if (!strv_isempty(ntp))
return 0;
}
if (arg_all) {
int c, i;
if (r < 0)
return rtnl_log_create_error(r);
r = sd_netlink_message_request_dump(req, true);
if (r < 0)
return rtnl_log_create_error(r);
if (r < 0)
return log_error_errno(r, "Failed to enumerate links: %m");
if (c < 0)
return rtnl_log_parse_error(c);
for (i = 0; i < c; i++) {
if (i > 0)
}
} else {
}
}
return 0;
}
[LLDP_SYSTEM_CAPABILITIES_OTHER] = "O",
[LLDP_SYSTEM_CAPABILITIES_REPEATER] = "P",
[LLDP_SYSTEM_CAPABILITIES_BRIDGE] = "B",
[LLDP_SYSTEM_CAPABILITIES_WLAN_AP] = "W",
[LLDP_SYSTEM_CAPABILITIES_ROUTER] = "R",
[LLDP_SYSTEM_CAPABILITIES_PHONE] = "T",
[LLDP_SYSTEM_CAPABILITIES_DOCSIS] = "D",
[LLDP_SYSTEM_CAPABILITIES_STATION] = "A",
[LLDP_SYSTEM_CAPABILITIES_CVLAN] = "C",
[LLDP_SYSTEM_CAPABILITIES_SVLAN] = "S",
[LLDP_SYSTEM_CAPABILITIES_TPMR] = "M",
[_LLDP_SYSTEM_CAPABILITIES_MAX] = "N/A",
};
char *capability;
t = strdup("[ ");
if (!t)
return NULL;
if (cap & LLDP_SYSTEM_CAPABILITIES_OTHER) {
if (!s)
return NULL;
free(t);
t = s;
}
if (cap & LLDP_SYSTEM_CAPABILITIES_REPEATER) {
if (!s)
return NULL;
free(t);
t = s;
}
if (cap & LLDP_SYSTEM_CAPABILITIES_BRIDGE) {
if (!s)
return NULL;
free(t);
t = s;
}
if (cap & LLDP_SYSTEM_CAPABILITIES_WLAN_AP) {
if (!s)
return NULL;
free(t);
t = s;
}
if (cap & LLDP_SYSTEM_CAPABILITIES_ROUTER) {
if (!s)
return NULL;
free(t);
t = s;
}
if (cap & LLDP_SYSTEM_CAPABILITIES_PHONE) {
if (!s)
return NULL;
free(t);
t = s;
}
if (cap & LLDP_SYSTEM_CAPABILITIES_DOCSIS) {
if (!s)
return NULL;
free(t);
t = s;
}
if (cap & LLDP_SYSTEM_CAPABILITIES_STATION) {
if (!s)
return NULL;
free(t);
t = s;
}
if (cap & LLDP_SYSTEM_CAPABILITIES_CVLAN) {
if (!s)
return NULL;
free(t);
t = s;
}
if (cap & LLDP_SYSTEM_CAPABILITIES_SVLAN) {
if (!s)
return NULL;
free(t);
t = s;
}
if (cap & LLDP_SYSTEM_CAPABILITIES_TPMR) {
if (!s)
return NULL;
free(t);
}
if (!s) {
if (!s)
return NULL;
free(t);
}
t = strappend(s, "]");
if (!t)
return NULL;
free(s);
capability = t;
s = NULL;
t = NULL;
return capability;
}
double ttl = -1;
int i, r, c, j;
char **s;
r = sd_netlink_open(&rtnl);
if (r < 0)
return log_error_errno(r, "Failed to connect to netlink: %m");
if (r < 0)
return rtnl_log_create_error(r);
r = sd_netlink_message_request_dump(req, true);
if (r < 0)
return rtnl_log_create_error(r);
if (r < 0)
return log_error_errno(r, "Failed to enumerate links: %m");
if (c < 0)
return rtnl_log_parse_error(c);
if (arg_legend)
for (i = j = 0; i < c; i++) {
_cleanup_strv_free_ char **l = NULL;
if (r < 0)
continue;
l = strv_split_newlines(lldp);
if (!l)
return -ENOMEM;
STRV_FOREACH(s, l) {
if (!t)
return -ENOMEM;
r = split_pair(t, "=", &a, &b);
if (r < 0)
continue;
if (streq(a, "_Chassis")) {
r = free_and_strdup(&chassis, b);
if (r < 0)
return r;
} else if (streq(a, "_Port")) {
r = free_and_strdup(&port, b);
if (r < 0)
return r;
} else if (streq(a, "_TTL")) {
long long unsigned x = 0;
r = safe_atollu(b, &x);
if (r < 0 || (usec_t) x != x)
return log_warning_errno(r < 0 ? r : ERANGE,
"Failed to parse TTL \"%s\": %m", b);
if (x < time)
continue;
} else if (streq(a, "_CAP")) {
}
}
if (ttl >= 0) {
printf("%10s %24s %16s %16f %16s\n",
j++;
}
}
}
if (arg_legend) {
printf("\nCapability Codes:\n"
"(O) - Other, (P) - Repeater, (B) - Bridge , (W) - WLAN Access Point, (R) = Router,\n"
"(T) - Telephone, (D) - Data Over Cable Service Interface Specifications, (A) - Station,\n"
"(C) - Customer VLAN, (S) - Service VLAN, (M) - Two-port MAC Relay (TPMR)\n\n");
printf("Total entries displayed: %d\n", j);
}
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"
" lldp Show lldp information\n"
}
enum {
ARG_VERSION = 0x100,
};
{}
};
int c;
switch (c) {
case 'h':
help();
return 0;
case ARG_VERSION:
return version();
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;
}
{}
};
}
int r;
log_open();
if (r <= 0)
goto finish;
pager_close();
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}