2014-08-12 01:41:42 +02:00
|
|
|
/***
|
|
|
|
This file is part of systemd.
|
|
|
|
|
|
|
|
Copyright 2014 Lennart Poettering
|
|
|
|
|
|
|
|
systemd is free software; you can redistribute it and/or modify it
|
|
|
|
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>
|
2014-12-12 19:07:26 +01:00
|
|
|
#include <net/if.h>
|
2015-09-23 03:01:06 +02:00
|
|
|
#include <stdbool.h>
|
2014-08-12 01:41:42 +02:00
|
|
|
|
2014-12-05 01:16:05 +01:00
|
|
|
#include "sd-device.h"
|
2015-09-23 03:01:06 +02:00
|
|
|
#include "sd-hwdb.h"
|
|
|
|
#include "sd-netlink.h"
|
|
|
|
#include "sd-network.h"
|
2014-08-12 01:41:42 +02:00
|
|
|
|
2015-10-27 03:01:06 +01:00
|
|
|
#include "alloc-util.h"
|
2015-09-23 03:01:06 +02:00
|
|
|
#include "arphrd-list.h"
|
2014-12-05 01:16:05 +01:00
|
|
|
#include "device-util.h"
|
2015-09-23 03:01:06 +02:00
|
|
|
#include "ether-addr-util.h"
|
2014-12-15 20:07:34 +01:00
|
|
|
#include "hwdb-util.h"
|
2015-09-23 03:01:06 +02:00
|
|
|
#include "lldp.h"
|
2014-08-12 01:41:42 +02:00
|
|
|
#include "local-addresses.h"
|
2015-10-26 23:01:30 +01:00
|
|
|
#include "locale-util.h"
|
2015-09-23 03:01:06 +02:00
|
|
|
#include "netlink-util.h"
|
|
|
|
#include "pager.h"
|
2015-10-26 16:18:16 +01:00
|
|
|
#include "parse-util.h"
|
2014-08-15 13:18:50 +02:00
|
|
|
#include "socket-util.h"
|
2016-01-12 15:34:20 +01:00
|
|
|
#include "stdio-util.h"
|
2015-10-26 22:31:05 +01:00
|
|
|
#include "string-table.h"
|
2015-10-26 23:01:30 +01:00
|
|
|
#include "string-util.h"
|
2015-09-23 03:01:06 +02:00
|
|
|
#include "strv.h"
|
2015-04-10 23:15:59 +02:00
|
|
|
#include "terminal-util.h"
|
2015-09-23 03:01:06 +02:00
|
|
|
#include "util.h"
|
|
|
|
#include "verbs.h"
|
2014-08-12 01:41:42 +02:00
|
|
|
|
|
|
|
static bool arg_no_pager = false;
|
|
|
|
static bool arg_legend = true;
|
2014-08-12 15:19:30 +02:00
|
|
|
static bool arg_all = false;
|
2014-08-12 01:41:42 +02:00
|
|
|
|
|
|
|
static void pager_open_if_enabled(void) {
|
|
|
|
|
|
|
|
if (arg_no_pager)
|
|
|
|
return;
|
|
|
|
|
|
|
|
pager_open(false);
|
|
|
|
}
|
|
|
|
|
2016-02-18 22:47:34 +01:00
|
|
|
static int link_get_type_string(unsigned short iftype, sd_device *d, char **ret) {
|
2014-08-12 01:41:42 +02:00
|
|
|
const char *t;
|
|
|
|
char *p;
|
|
|
|
|
2014-12-05 01:16:05 +01:00
|
|
|
assert(ret);
|
|
|
|
|
2014-08-12 01:41:42 +02:00
|
|
|
if (iftype == ARPHRD_ETHER && d) {
|
2015-05-30 10:51:41 +02:00
|
|
|
const char *devtype = NULL, *id = NULL;
|
2014-08-12 01:41:42 +02:00
|
|
|
/* WLANs have iftype ARPHRD_ETHER, but we want
|
|
|
|
* to show a more useful type string for
|
|
|
|
* them */
|
|
|
|
|
2014-12-05 01:16:05 +01:00
|
|
|
(void)sd_device_get_devtype(d, &devtype);
|
|
|
|
|
2014-08-12 01:41:42 +02:00
|
|
|
if (streq_ptr(devtype, "wlan"))
|
|
|
|
id = "wlan";
|
|
|
|
else if (streq_ptr(devtype, "wwan"))
|
|
|
|
id = "wwan";
|
|
|
|
|
|
|
|
if (id) {
|
|
|
|
p = strdup(id);
|
|
|
|
if (!p)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
*ret = p;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
t = arphrd_to_name(iftype);
|
|
|
|
if (!t) {
|
|
|
|
*ret = NULL;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
p = strdup(t);
|
|
|
|
if (!p)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
ascii_strlower(p);
|
|
|
|
*ret = p;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-08-12 16:03:45 +02:00
|
|
|
typedef struct LinkInfo {
|
|
|
|
const char *name;
|
|
|
|
int ifindex;
|
2016-02-18 22:47:34 +01:00
|
|
|
unsigned short iftype;
|
2014-08-12 16:03:45 +02:00
|
|
|
} LinkInfo;
|
|
|
|
|
|
|
|
static int link_info_compare(const void *a, const void *b) {
|
|
|
|
const LinkInfo *x = a, *y = b;
|
|
|
|
|
|
|
|
return x->ifindex - y->ifindex;
|
|
|
|
}
|
|
|
|
|
2015-06-12 16:31:33 +02:00
|
|
|
static int decode_and_sort_links(sd_netlink_message *m, LinkInfo **ret) {
|
2014-08-12 16:03:45 +02:00
|
|
|
_cleanup_free_ LinkInfo *links = NULL;
|
|
|
|
size_t size = 0, c = 0;
|
2015-06-12 16:31:33 +02:00
|
|
|
sd_netlink_message *i;
|
2014-08-12 16:03:45 +02:00
|
|
|
int r;
|
|
|
|
|
2015-06-12 16:31:33 +02:00
|
|
|
for (i = m; i; i = sd_netlink_message_next(i)) {
|
2014-08-12 16:03:45 +02:00
|
|
|
const char *name;
|
2016-02-18 22:47:34 +01:00
|
|
|
unsigned short iftype;
|
2014-08-12 16:03:45 +02:00
|
|
|
uint16_t type;
|
|
|
|
int ifindex;
|
|
|
|
|
2015-06-12 16:31:33 +02:00
|
|
|
r = sd_netlink_message_get_type(i, &type);
|
2014-08-12 16:03:45 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
if (type != RTM_NEWLINK)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
r = sd_rtnl_message_link_get_ifindex(i, &ifindex);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2015-06-12 16:31:33 +02:00
|
|
|
r = sd_netlink_message_read_string(i, IFLA_IFNAME, &name);
|
2014-08-12 16:03:45 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
r = sd_rtnl_message_link_get_type(i, &iftype);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
if (!GREEDY_REALLOC(links, size, c+1))
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
links[c].name = name;
|
|
|
|
links[c].ifindex = ifindex;
|
|
|
|
links[c].iftype = iftype;
|
|
|
|
c++;
|
|
|
|
}
|
|
|
|
|
2014-08-16 23:18:32 +02:00
|
|
|
qsort_safe(links, c, sizeof(LinkInfo), link_info_compare);
|
2014-08-12 16:03:45 +02:00
|
|
|
|
|
|
|
*ret = links;
|
|
|
|
links = NULL;
|
|
|
|
|
|
|
|
return (int) c;
|
|
|
|
}
|
|
|
|
|
2014-08-14 01:18:37 +02:00
|
|
|
static void operational_state_to_color(const char *state, const char **on, const char **off) {
|
|
|
|
assert(on);
|
|
|
|
assert(off);
|
|
|
|
|
|
|
|
if (streq_ptr(state, "routable")) {
|
|
|
|
*on = ansi_highlight_green();
|
2015-09-19 00:45:05 +02:00
|
|
|
*off = ansi_normal();
|
2014-08-14 01:18:37 +02:00
|
|
|
} else if (streq_ptr(state, "degraded")) {
|
|
|
|
*on = ansi_highlight_yellow();
|
2015-09-19 00:45:05 +02:00
|
|
|
*off = ansi_normal();
|
2014-08-14 01:18:37 +02:00
|
|
|
} else
|
|
|
|
*on = *off = "";
|
|
|
|
}
|
|
|
|
|
|
|
|
static void setup_state_to_color(const char *state, const char **on, const char **off) {
|
|
|
|
assert(on);
|
|
|
|
assert(off);
|
|
|
|
|
|
|
|
if (streq_ptr(state, "configured")) {
|
|
|
|
*on = ansi_highlight_green();
|
2015-09-19 00:45:05 +02:00
|
|
|
*off = ansi_normal();
|
2014-08-14 01:18:37 +02:00
|
|
|
} else if (streq_ptr(state, "configuring")) {
|
|
|
|
*on = ansi_highlight_yellow();
|
2015-09-19 00:45:05 +02:00
|
|
|
*off = ansi_normal();
|
2014-08-14 01:18:37 +02:00
|
|
|
} else if (streq_ptr(state, "failed") || streq_ptr(state, "linger")) {
|
|
|
|
*on = ansi_highlight_red();
|
2015-09-19 00:45:05 +02:00
|
|
|
*off = ansi_normal();
|
2014-08-14 01:18:37 +02:00
|
|
|
} else
|
|
|
|
*on = *off = "";
|
|
|
|
}
|
|
|
|
|
2014-12-19 03:16:45 +01:00
|
|
|
static int list_links(int argc, char *argv[], void *userdata) {
|
tree-wide: expose "p"-suffix unref calls in public APIs to make gcc cleanup easy
GLIB has recently started to officially support the gcc cleanup
attribute in its public API, hence let's do the same for our APIs.
With this patch we'll define an xyz_unrefp() call for each public
xyz_unref() call, to make it easy to use inside a
__attribute__((cleanup())) expression. Then, all code is ported over to
make use of this.
The new calls are also documented in the man pages, with examples how to
use them (well, I only added docs where the _unref() call itself already
had docs, and the examples, only cover sd_bus_unrefp() and
sd_event_unrefp()).
This also renames sd_lldp_free() to sd_lldp_unref(), since that's how we
tend to call our destructors these days.
Note that this defines no public macro that wraps gcc's attribute and
makes it easier to use. While I think it's our duty in the library to
make our stuff easy to use, I figure it's not our duty to make gcc's own
features easy to use on its own. Most likely, client code which wants to
make use of this should define its own:
#define _cleanup_(function) __attribute__((cleanup(function)))
Or similar, to make the gcc feature easier to use.
Making this logic public has the benefit that we can remove three header
files whose only purpose was to define these functions internally.
See #2008.
2015-11-27 19:13:45 +01:00
|
|
|
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL;
|
|
|
|
_cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
|
2014-08-12 16:03:45 +02:00
|
|
|
_cleanup_free_ LinkInfo *links = NULL;
|
|
|
|
int r, c, i;
|
2014-08-12 01:41:42 +02:00
|
|
|
|
|
|
|
pager_open_if_enabled();
|
|
|
|
|
2015-06-12 16:31:33 +02:00
|
|
|
r = sd_netlink_open(&rtnl);
|
2014-11-28 18:50:43 +01:00
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to connect to netlink: %m");
|
2014-08-12 01:41:42 +02:00
|
|
|
|
|
|
|
r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, 0);
|
|
|
|
if (r < 0)
|
|
|
|
return rtnl_log_create_error(r);
|
|
|
|
|
2015-06-12 16:31:33 +02:00
|
|
|
r = sd_netlink_message_request_dump(req, true);
|
2014-08-12 01:41:42 +02:00
|
|
|
if (r < 0)
|
|
|
|
return rtnl_log_create_error(r);
|
|
|
|
|
2015-06-12 16:31:33 +02:00
|
|
|
r = sd_netlink_call(rtnl, req, 0, &reply);
|
2014-11-28 18:50:43 +01:00
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to enumerate links: %m");
|
2014-08-12 01:41:42 +02:00
|
|
|
|
|
|
|
if (arg_legend)
|
2014-08-15 12:57:33 +02:00
|
|
|
printf("%3s %-16s %-18s %-11s %-10s\n", "IDX", "LINK", "TYPE", "OPERATIONAL", "SETUP");
|
2014-08-12 01:41:42 +02:00
|
|
|
|
2014-08-12 16:03:45 +02:00
|
|
|
c = decode_and_sort_links(reply, &links);
|
|
|
|
if (c < 0)
|
|
|
|
return rtnl_log_parse_error(c);
|
|
|
|
|
|
|
|
for (i = 0; i < c; i++) {
|
2014-08-14 01:10:08 +02:00
|
|
|
_cleanup_free_ char *setup_state = NULL, *operational_state = NULL;
|
tree-wide: expose "p"-suffix unref calls in public APIs to make gcc cleanup easy
GLIB has recently started to officially support the gcc cleanup
attribute in its public API, hence let's do the same for our APIs.
With this patch we'll define an xyz_unrefp() call for each public
xyz_unref() call, to make it easy to use inside a
__attribute__((cleanup())) expression. Then, all code is ported over to
make use of this.
The new calls are also documented in the man pages, with examples how to
use them (well, I only added docs where the _unref() call itself already
had docs, and the examples, only cover sd_bus_unrefp() and
sd_event_unrefp()).
This also renames sd_lldp_free() to sd_lldp_unref(), since that's how we
tend to call our destructors these days.
Note that this defines no public macro that wraps gcc's attribute and
makes it easier to use. While I think it's our duty in the library to
make our stuff easy to use, I figure it's not our duty to make gcc's own
features easy to use on its own. Most likely, client code which wants to
make use of this should define its own:
#define _cleanup_(function) __attribute__((cleanup(function)))
Or similar, to make the gcc feature easier to use.
Making this logic public has the benefit that we can remove three header
files whose only purpose was to define these functions internally.
See #2008.
2015-11-27 19:13:45 +01:00
|
|
|
_cleanup_(sd_device_unrefp) sd_device *d = NULL;
|
2014-08-14 01:18:37 +02:00
|
|
|
const char *on_color_operational, *off_color_operational,
|
|
|
|
*on_color_setup, *off_color_setup;
|
2015-08-06 00:31:09 +02:00
|
|
|
char devid[2 + DECIMAL_STR_MAX(int)];
|
2014-08-12 01:41:42 +02:00
|
|
|
_cleanup_free_ char *t = NULL;
|
|
|
|
|
2014-08-13 22:37:45 +02:00
|
|
|
sd_network_link_get_operational_state(links[i].ifindex, &operational_state);
|
2014-08-14 01:18:37 +02:00
|
|
|
operational_state_to_color(operational_state, &on_color_operational, &off_color_operational);
|
|
|
|
|
|
|
|
sd_network_link_get_setup_state(links[i].ifindex, &setup_state);
|
|
|
|
setup_state_to_color(setup_state, &on_color_setup, &off_color_setup);
|
2014-08-12 01:41:42 +02:00
|
|
|
|
2014-08-12 16:03:45 +02:00
|
|
|
sprintf(devid, "n%i", links[i].ifindex);
|
2014-12-05 01:16:05 +01:00
|
|
|
(void)sd_device_new_from_device_id(&d, devid);
|
2014-08-12 01:41:42 +02:00
|
|
|
|
2014-08-12 16:03:45 +02:00
|
|
|
link_get_type_string(links[i].iftype, d, &t);
|
2014-08-12 01:41:42 +02:00
|
|
|
|
2014-08-15 12:57:33 +02:00
|
|
|
printf("%3i %-16s %-18s %s%-11s%s %s%-10s%s\n",
|
2014-08-14 01:18:37 +02:00
|
|
|
links[i].ifindex, links[i].name, strna(t),
|
|
|
|
on_color_operational, strna(operational_state), off_color_operational,
|
|
|
|
on_color_setup, strna(setup_state), off_color_setup);
|
2014-08-12 01:41:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (arg_legend)
|
2014-08-12 16:03:45 +02:00
|
|
|
printf("\n%i links listed.\n", c);
|
2014-08-12 01:41:42 +02:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-12-02 01:05:52 +01:00
|
|
|
/* IEEE Organizationally Unique Identifier vendor string */
|
2014-12-15 20:07:34 +01:00
|
|
|
static int ieee_oui(sd_hwdb *hwdb, struct ether_addr *mac, char **ret) {
|
|
|
|
const char *description;
|
|
|
|
char modalias[strlen("OUI:XXYYXXYYXXYY") + 1], *desc;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(ret);
|
2014-12-02 01:05:52 +01:00
|
|
|
|
2014-12-12 18:50:06 +01:00
|
|
|
if (!hwdb)
|
|
|
|
return -EINVAL;
|
|
|
|
|
2014-12-15 20:07:34 +01:00
|
|
|
if (!mac)
|
|
|
|
return -EINVAL;
|
|
|
|
|
2014-12-02 01:05:52 +01:00
|
|
|
/* skip commonly misused 00:00:00 (Xerox) prefix */
|
|
|
|
if (memcmp(mac, "\0\0\0", 3) == 0)
|
|
|
|
return -EINVAL;
|
|
|
|
|
2016-01-12 15:34:20 +01:00
|
|
|
xsprintf(modalias, "OUI:" ETHER_ADDR_FORMAT_STR,
|
|
|
|
ETHER_ADDR_FORMAT_VAL(*mac));
|
2014-12-02 01:05:52 +01:00
|
|
|
|
2014-12-15 20:07:34 +01:00
|
|
|
r = sd_hwdb_get(hwdb, modalias, "ID_OUI_FROM_DATABASE", &description);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2014-12-02 01:05:52 +01:00
|
|
|
|
2014-12-15 20:07:34 +01:00
|
|
|
desc = strdup(description);
|
|
|
|
if (!desc)
|
|
|
|
return -ENOMEM;
|
2014-12-02 01:05:52 +01:00
|
|
|
|
2014-12-15 20:07:34 +01:00
|
|
|
*ret = desc;
|
|
|
|
|
|
|
|
return 0;
|
2014-12-02 01:05:52 +01:00
|
|
|
}
|
|
|
|
|
2014-12-12 18:57:15 +01:00
|
|
|
static int get_gateway_description(
|
2015-06-12 16:31:33 +02:00
|
|
|
sd_netlink *rtnl,
|
2014-12-15 20:07:34 +01:00
|
|
|
sd_hwdb *hwdb,
|
2014-12-12 18:57:15 +01:00
|
|
|
int ifindex,
|
|
|
|
int family,
|
|
|
|
union in_addr_union *gateway,
|
|
|
|
char **gateway_description) {
|
tree-wide: expose "p"-suffix unref calls in public APIs to make gcc cleanup easy
GLIB has recently started to officially support the gcc cleanup
attribute in its public API, hence let's do the same for our APIs.
With this patch we'll define an xyz_unrefp() call for each public
xyz_unref() call, to make it easy to use inside a
__attribute__((cleanup())) expression. Then, all code is ported over to
make use of this.
The new calls are also documented in the man pages, with examples how to
use them (well, I only added docs where the _unref() call itself already
had docs, and the examples, only cover sd_bus_unrefp() and
sd_event_unrefp()).
This also renames sd_lldp_free() to sd_lldp_unref(), since that's how we
tend to call our destructors these days.
Note that this defines no public macro that wraps gcc's attribute and
makes it easier to use. While I think it's our duty in the library to
make our stuff easy to use, I figure it's not our duty to make gcc's own
features easy to use on its own. Most likely, client code which wants to
make use of this should define its own:
#define _cleanup_(function) __attribute__((cleanup(function)))
Or similar, to make the gcc feature easier to use.
Making this logic public has the benefit that we can remove three header
files whose only purpose was to define these functions internally.
See #2008.
2015-11-27 19:13:45 +01:00
|
|
|
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL;
|
2015-06-12 16:31:33 +02:00
|
|
|
sd_netlink_message *m;
|
2014-12-02 01:05:52 +01:00
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(rtnl);
|
|
|
|
assert(ifindex >= 0);
|
|
|
|
assert(family == AF_INET || family == AF_INET6);
|
|
|
|
assert(gateway);
|
|
|
|
assert(gateway_description);
|
|
|
|
|
|
|
|
r = sd_rtnl_message_new_neigh(rtnl, &req, RTM_GETNEIGH, ifindex, family);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2015-06-12 16:31:33 +02:00
|
|
|
r = sd_netlink_message_request_dump(req, true);
|
2014-12-02 01:05:52 +01:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2015-06-12 16:31:33 +02:00
|
|
|
r = sd_netlink_call(rtnl, req, 0, &reply);
|
2014-12-02 01:05:52 +01:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2015-06-12 16:31:33 +02:00
|
|
|
for (m = reply; m; m = sd_netlink_message_next(m)) {
|
2014-12-02 01:05:52 +01:00
|
|
|
union in_addr_union gw = {};
|
|
|
|
struct ether_addr mac = {};
|
|
|
|
uint16_t type;
|
|
|
|
int ifi, fam;
|
|
|
|
|
2015-06-12 16:31:33 +02:00
|
|
|
r = sd_netlink_message_get_errno(m);
|
2014-12-02 01:05:52 +01:00
|
|
|
if (r < 0) {
|
|
|
|
log_error_errno(r, "got error: %m");
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2015-06-12 16:31:33 +02:00
|
|
|
r = sd_netlink_message_get_type(m, &type);
|
2014-12-02 01:05:52 +01:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fam != family) {
|
|
|
|
log_error("family is not correct");
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = sd_rtnl_message_neigh_get_ifindex(m, &ifi);
|
|
|
|
if (r < 0) {
|
2014-12-03 20:59:00 +01:00
|
|
|
log_error_errno(r, "could not get ifindex: %m");
|
2014-12-02 01:05:52 +01:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ifindex > 0 && ifi != ifindex)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
switch (fam) {
|
|
|
|
case AF_INET:
|
2015-06-12 16:31:33 +02:00
|
|
|
r = sd_netlink_message_read_in_addr(m, NDA_DST, &gw.in);
|
2014-12-02 01:05:52 +01:00
|
|
|
if (r < 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
break;
|
|
|
|
case AF_INET6:
|
2015-06-12 16:31:33 +02:00
|
|
|
r = sd_netlink_message_read_in6_addr(m, NDA_DST, &gw.in6);
|
2014-12-02 01:05:52 +01:00
|
|
|
if (r < 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!in_addr_equal(fam, &gw, gateway))
|
|
|
|
continue;
|
|
|
|
|
2015-06-12 16:31:33 +02:00
|
|
|
r = sd_netlink_message_read_ether_addr(m, NDA_LLADDR, &mac);
|
2014-12-02 01:05:52 +01:00
|
|
|
if (r < 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
r = ieee_oui(hwdb, &mac, gateway_description);
|
|
|
|
if (r < 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return -ENODATA;
|
|
|
|
}
|
|
|
|
|
2014-12-12 18:57:15 +01:00
|
|
|
static int dump_gateways(
|
2015-06-12 16:31:33 +02:00
|
|
|
sd_netlink *rtnl,
|
2014-12-15 20:07:34 +01:00
|
|
|
sd_hwdb *hwdb,
|
2014-12-12 18:57:15 +01:00
|
|
|
const char *prefix,
|
|
|
|
int ifindex) {
|
2014-12-04 12:19:27 +01:00
|
|
|
_cleanup_free_ struct local_address *local = NULL;
|
|
|
|
int r, n, i;
|
2014-12-02 01:05:52 +01:00
|
|
|
|
2014-12-04 12:19:27 +01:00
|
|
|
n = local_gateways(rtnl, ifindex, AF_UNSPEC, &local);
|
|
|
|
if (n < 0)
|
|
|
|
return n;
|
2014-12-02 01:05:52 +01:00
|
|
|
|
2014-12-04 12:19:27 +01:00
|
|
|
for (i = 0; i < n; i++) {
|
|
|
|
_cleanup_free_ char *gateway = NULL, *description = NULL;
|
2014-12-02 01:05:52 +01:00
|
|
|
|
2014-12-04 12:19:27 +01:00
|
|
|
r = in_addr_to_string(local[i].family, &local[i].address, &gateway);
|
2014-12-02 01:05:52 +01:00
|
|
|
if (r < 0)
|
2014-12-04 12:19:27 +01:00
|
|
|
return r;
|
2014-12-02 01:05:52 +01:00
|
|
|
|
2014-12-12 18:57:15 +01:00
|
|
|
r = get_gateway_description(rtnl, hwdb, local[i].ifindex, local[i].family, &local[i].address, &description);
|
2014-12-02 01:05:52 +01:00
|
|
|
if (r < 0)
|
2014-12-04 12:19:27 +01:00
|
|
|
log_debug_errno(r, "Could not get description of gateway: %m");
|
2014-12-02 01:05:52 +01:00
|
|
|
|
2014-12-12 19:07:26 +01:00
|
|
|
printf("%*s%s",
|
|
|
|
(int) strlen(prefix),
|
|
|
|
i == 0 ? prefix : "",
|
|
|
|
gateway);
|
|
|
|
|
2014-12-04 12:19:27 +01:00
|
|
|
if (description)
|
2014-12-12 19:07:26 +01:00
|
|
|
printf(" (%s)", description);
|
|
|
|
|
|
|
|
/* Show interface name for the entry if we show
|
|
|
|
* entries for all interfaces */
|
|
|
|
if (ifindex <= 0) {
|
|
|
|
char name[IF_NAMESIZE+1];
|
|
|
|
|
|
|
|
if (if_indextoname(local[i].ifindex, name)) {
|
|
|
|
fputs(" on ", stdout);
|
|
|
|
fputs(name, stdout);
|
|
|
|
} else
|
|
|
|
printf(" on %%%i", local[i].ifindex);
|
|
|
|
}
|
|
|
|
|
|
|
|
fputc('\n', stdout);
|
2014-12-02 01:05:52 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-12-12 18:57:15 +01:00
|
|
|
static int dump_addresses(
|
2015-06-12 16:31:33 +02:00
|
|
|
sd_netlink *rtnl,
|
2014-12-12 18:57:15 +01:00
|
|
|
const char *prefix,
|
|
|
|
int ifindex) {
|
|
|
|
|
2014-08-12 01:41:42 +02:00
|
|
|
_cleanup_free_ struct local_address *local = NULL;
|
|
|
|
int r, n, i;
|
|
|
|
|
2014-12-04 01:41:12 +01:00
|
|
|
n = local_addresses(rtnl, ifindex, AF_UNSPEC, &local);
|
2014-08-12 01:41:42 +02:00
|
|
|
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;
|
|
|
|
|
2014-12-12 19:07:26 +01:00
|
|
|
printf("%*s%s",
|
2014-08-12 01:41:42 +02:00
|
|
|
(int) strlen(prefix),
|
|
|
|
i == 0 ? prefix : "",
|
|
|
|
pretty);
|
2014-12-12 19:07:26 +01:00
|
|
|
|
|
|
|
if (ifindex <= 0) {
|
|
|
|
char name[IF_NAMESIZE+1];
|
|
|
|
|
|
|
|
if (if_indextoname(local[i].ifindex, name)) {
|
|
|
|
fputs(" on ", stdout);
|
|
|
|
fputs(name, stdout);
|
|
|
|
} else
|
|
|
|
printf(" on %%%i", local[i].ifindex);
|
|
|
|
}
|
|
|
|
|
|
|
|
fputc('\n', stdout);
|
2014-08-12 01:41:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void dump_list(const char *prefix, char **l) {
|
|
|
|
char **i;
|
|
|
|
|
2016-01-25 20:14:58 +01:00
|
|
|
if (strv_isempty(l))
|
|
|
|
return;
|
|
|
|
|
2014-08-12 01:41:42 +02:00
|
|
|
STRV_FOREACH(i, l) {
|
|
|
|
printf("%*s%s\n",
|
|
|
|
(int) strlen(prefix),
|
|
|
|
i == l ? prefix : "",
|
|
|
|
*i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-12-12 18:57:15 +01:00
|
|
|
static int link_status_one(
|
2015-06-12 16:31:33 +02:00
|
|
|
sd_netlink *rtnl,
|
2014-12-15 20:07:34 +01:00
|
|
|
sd_hwdb *hwdb,
|
2014-12-12 18:57:15 +01:00
|
|
|
const char *name) {
|
networkd: rework Domains= setting
Previously, .network files only knew a vaguely defined "Domains=" concept, for which the documentation declared it was
the "DNS domain" for the network connection, without specifying what that means.
With this the Domains setting is reworked, so that there are now "routing" domains and "search" domains. The former are
to be used by resolved to route DNS request to specific network interfaces, the latter is to be used for searching
single-label hostnames with (in addition to being used for routing). Both settings are configured in the "Domains="
setting. Normal domain names listed in it are now considered search domains (for compatibility with existing setups),
while those prefixed with "~" are considered routing domains only. To route all lookups to a specific interface the
routing domain "." may be used, referring to the root domain. An alternative syntax for this is the "*", as was already
implemented before using the "wildcard" domain concept.
This commit adds proper parsers for this new logic, and exposes this via the sd-network API. This information is not
used by resolved yet, this will be added in a later commit.
2016-01-25 19:46:00 +01:00
|
|
|
_cleanup_strv_free_ char **dns = NULL, **ntp = NULL, **search_domains = NULL, **route_domains = NULL;
|
2015-08-30 03:18:33 +02:00
|
|
|
_cleanup_free_ char *setup_state = NULL, *operational_state = NULL, *tz = NULL;
|
tree-wide: expose "p"-suffix unref calls in public APIs to make gcc cleanup easy
GLIB has recently started to officially support the gcc cleanup
attribute in its public API, hence let's do the same for our APIs.
With this patch we'll define an xyz_unrefp() call for each public
xyz_unref() call, to make it easy to use inside a
__attribute__((cleanup())) expression. Then, all code is ported over to
make use of this.
The new calls are also documented in the man pages, with examples how to
use them (well, I only added docs where the _unref() call itself already
had docs, and the examples, only cover sd_bus_unrefp() and
sd_event_unrefp()).
This also renames sd_lldp_free() to sd_lldp_unref(), since that's how we
tend to call our destructors these days.
Note that this defines no public macro that wraps gcc's attribute and
makes it easier to use. While I think it's our duty in the library to
make our stuff easy to use, I figure it's not our duty to make gcc's own
features easy to use on its own. Most likely, client code which wants to
make use of this should define its own:
#define _cleanup_(function) __attribute__((cleanup(function)))
Or similar, to make the gcc feature easier to use.
Making this logic public has the benefit that we can remove three header
files whose only purpose was to define these functions internally.
See #2008.
2015-11-27 19:13:45 +01:00
|
|
|
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL;
|
|
|
|
_cleanup_(sd_device_unrefp) sd_device *d = NULL;
|
2014-08-12 15:19:30 +02:00
|
|
|
char devid[2 + DECIMAL_STR_MAX(int)];
|
2014-09-08 14:00:34 +02:00
|
|
|
_cleanup_free_ char *t = NULL, *network = NULL;
|
2014-09-08 14:18:32 +02:00
|
|
|
const char *driver = NULL, *path = NULL, *vendor = NULL, *model = NULL, *link = NULL;
|
2014-08-14 01:18:37 +02:00
|
|
|
const char *on_color_operational, *off_color_operational,
|
|
|
|
*on_color_setup, *off_color_setup;
|
2015-02-17 13:06:57 +01:00
|
|
|
_cleanup_strv_free_ char **carrier_bound_to = NULL;
|
|
|
|
_cleanup_strv_free_ char **carrier_bound_by = NULL;
|
2014-08-12 15:19:30 +02:00
|
|
|
struct ether_addr e;
|
2016-02-18 22:47:34 +01:00
|
|
|
unsigned short iftype;
|
2014-08-12 15:19:30 +02:00
|
|
|
int r, ifindex;
|
|
|
|
bool have_mac;
|
|
|
|
uint32_t mtu;
|
|
|
|
|
|
|
|
assert(rtnl);
|
|
|
|
assert(name);
|
|
|
|
|
2015-11-02 23:57:21 +01:00
|
|
|
if (parse_ifindex(name, &ifindex) >= 0)
|
2014-08-12 15:19:30 +02:00
|
|
|
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);
|
|
|
|
|
2015-06-12 16:31:33 +02:00
|
|
|
r = sd_netlink_message_append_string(req, IFLA_IFNAME, name);
|
2014-08-12 15:19:30 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (r < 0)
|
|
|
|
return rtnl_log_create_error(r);
|
|
|
|
|
2015-06-12 16:31:33 +02:00
|
|
|
r = sd_netlink_call(rtnl, req, 0, &reply);
|
2014-11-28 18:50:43 +01:00
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to query link: %m");
|
2014-08-12 15:19:30 +02:00
|
|
|
|
|
|
|
r = sd_rtnl_message_link_get_ifindex(reply, &ifindex);
|
|
|
|
if (r < 0)
|
|
|
|
return rtnl_log_parse_error(r);
|
|
|
|
|
2015-06-12 16:31:33 +02:00
|
|
|
r = sd_netlink_message_read_string(reply, IFLA_IFNAME, &name);
|
2014-08-12 15:19:30 +02:00
|
|
|
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);
|
|
|
|
|
2015-06-12 16:31:33 +02:00
|
|
|
have_mac = sd_netlink_message_read_ether_addr(reply, IFLA_ADDRESS, &e) >= 0;
|
2014-08-12 15:19:30 +02:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2016-01-25 20:14:58 +01:00
|
|
|
(void) sd_netlink_message_read_u32(reply, IFLA_MTU, &mtu);
|
2014-08-12 15:19:30 +02:00
|
|
|
|
2016-01-25 20:14:58 +01:00
|
|
|
(void) sd_network_link_get_operational_state(ifindex, &operational_state);
|
2014-08-14 01:18:37 +02:00
|
|
|
operational_state_to_color(operational_state, &on_color_operational, &off_color_operational);
|
|
|
|
|
2016-01-25 20:14:58 +01:00
|
|
|
(void) sd_network_link_get_setup_state(ifindex, &setup_state);
|
2014-08-14 01:18:37 +02:00
|
|
|
setup_state_to_color(setup_state, &on_color_setup, &off_color_setup);
|
2014-08-12 15:19:30 +02:00
|
|
|
|
2016-01-25 20:14:58 +01:00
|
|
|
(void) sd_network_link_get_dns(ifindex, &dns);
|
|
|
|
(void) sd_network_link_get_search_domains(ifindex, &search_domains);
|
|
|
|
(void) sd_network_link_get_route_domains(ifindex, &route_domains);
|
|
|
|
(void) sd_network_link_get_ntp(ifindex, &ntp);
|
2014-08-12 15:19:30 +02:00
|
|
|
|
|
|
|
sprintf(devid, "n%i", ifindex);
|
2014-12-05 01:16:05 +01:00
|
|
|
|
2016-01-25 20:14:58 +01:00
|
|
|
(void) sd_device_new_from_device_id(&d, devid);
|
2014-12-05 01:16:05 +01:00
|
|
|
|
2014-08-12 15:19:30 +02:00
|
|
|
if (d) {
|
2016-01-25 20:14:58 +01:00
|
|
|
(void) sd_device_get_property_value(d, "ID_NET_LINK_FILE", &link);
|
|
|
|
(void) sd_device_get_property_value(d, "ID_NET_DRIVER", &driver);
|
|
|
|
(void) sd_device_get_property_value(d, "ID_PATH", &path);
|
2014-08-12 15:19:30 +02:00
|
|
|
|
2014-12-05 01:16:05 +01:00
|
|
|
r = sd_device_get_property_value(d, "ID_VENDOR_FROM_DATABASE", &vendor);
|
|
|
|
if (r < 0)
|
2016-01-25 20:14:58 +01:00
|
|
|
(void) sd_device_get_property_value(d, "ID_VENDOR", &vendor);
|
2014-08-12 15:19:30 +02:00
|
|
|
|
2014-12-05 01:16:05 +01:00
|
|
|
r = sd_device_get_property_value(d, "ID_MODEL_FROM_DATABASE", &model);
|
|
|
|
if (r < 0)
|
2016-01-25 20:14:58 +01:00
|
|
|
(void) sd_device_get_property_value(d, "ID_MODEL", &model);
|
2014-08-12 15:19:30 +02:00
|
|
|
}
|
|
|
|
|
2014-12-12 19:11:35 +01:00
|
|
|
link_get_type_string(iftype, d, &t);
|
|
|
|
|
2014-09-08 14:00:34 +02:00
|
|
|
sd_network_link_get_network_file(ifindex, &network);
|
2014-08-12 15:41:01 +02:00
|
|
|
|
2015-02-17 13:06:57 +01:00
|
|
|
sd_network_link_get_carrier_bound_to(ifindex, &carrier_bound_to);
|
|
|
|
sd_network_link_get_carrier_bound_by(ifindex, &carrier_bound_by);
|
|
|
|
|
2014-08-14 01:18:37 +02:00
|
|
|
printf("%s%s%s %i: %s\n", on_color_operational, draw_special_char(DRAW_BLACK_CIRCLE), off_color_operational, ifindex, name);
|
2014-08-12 15:19:30 +02:00
|
|
|
|
2015-02-17 13:06:57 +01:00
|
|
|
printf(" Link File: %s\n"
|
|
|
|
" Network File: %s\n"
|
|
|
|
" Type: %s\n"
|
|
|
|
" State: %s%s%s (%s%s%s)\n",
|
2014-09-08 14:18:32 +02:00
|
|
|
strna(link),
|
2014-09-08 14:00:34 +02:00
|
|
|
strna(network),
|
2014-08-12 15:19:30 +02:00
|
|
|
strna(t),
|
2014-08-14 01:18:37 +02:00
|
|
|
on_color_operational, strna(operational_state), off_color_operational,
|
|
|
|
on_color_setup, strna(setup_state), off_color_setup);
|
2014-08-12 15:19:30 +02:00
|
|
|
|
|
|
|
if (path)
|
2015-02-17 13:06:57 +01:00
|
|
|
printf(" Path: %s\n", path);
|
2014-08-12 15:19:30 +02:00
|
|
|
if (driver)
|
2015-02-17 13:06:57 +01:00
|
|
|
printf(" Driver: %s\n", driver);
|
2014-08-12 15:19:30 +02:00
|
|
|
if (vendor)
|
2015-02-17 13:06:57 +01:00
|
|
|
printf(" Vendor: %s\n", vendor);
|
2014-08-12 15:19:30 +02:00
|
|
|
if (model)
|
2015-02-17 13:06:57 +01:00
|
|
|
printf(" Model: %s\n", model);
|
2014-08-12 15:19:30 +02:00
|
|
|
|
2014-08-15 13:18:50 +02:00
|
|
|
if (have_mac) {
|
2014-12-12 18:50:06 +01:00
|
|
|
_cleanup_free_ char *description = NULL;
|
2014-08-15 13:18:50 +02:00
|
|
|
char ea[ETHER_ADDR_TO_STRING_MAX];
|
2014-12-12 18:50:06 +01:00
|
|
|
|
|
|
|
ieee_oui(hwdb, &e, &description);
|
|
|
|
|
|
|
|
if (description)
|
2015-02-17 13:06:57 +01:00
|
|
|
printf(" HW Address: %s (%s)\n", ether_addr_to_string(&e, ea), description);
|
2014-12-12 18:50:06 +01:00
|
|
|
else
|
2015-02-17 13:06:57 +01:00
|
|
|
printf(" HW Address: %s\n", ether_addr_to_string(&e, ea));
|
2014-08-15 13:18:50 +02:00
|
|
|
}
|
2014-08-12 15:19:30 +02:00
|
|
|
|
|
|
|
if (mtu > 0)
|
2015-02-17 13:06:57 +01:00
|
|
|
printf(" MTU: %u\n", mtu);
|
2014-08-12 15:19:30 +02:00
|
|
|
|
2015-02-17 13:06:57 +01:00
|
|
|
dump_addresses(rtnl, " Address: ", ifindex);
|
|
|
|
dump_gateways(rtnl, hwdb, " Gateway: ", ifindex);
|
2014-08-12 15:19:30 +02:00
|
|
|
|
2016-01-25 20:14:58 +01:00
|
|
|
dump_list(" DNS: ", dns);
|
|
|
|
dump_list(" Search Domains: ", search_domains);
|
|
|
|
dump_list(" Route Domains: ", route_domains);
|
2015-08-26 19:19:32 +02:00
|
|
|
|
2016-01-25 20:14:58 +01:00
|
|
|
dump_list(" NTP: ", ntp);
|
2015-02-17 13:06:57 +01:00
|
|
|
|
2016-01-25 20:14:58 +01:00
|
|
|
dump_list("Carrier Bound To: ", carrier_bound_to);
|
|
|
|
dump_list("Carrier Bound By: ", carrier_bound_by);
|
2014-08-12 15:19:30 +02:00
|
|
|
|
2015-08-30 03:18:33 +02:00
|
|
|
(void) sd_network_link_get_timezone(ifindex, &tz);
|
|
|
|
if (tz)
|
|
|
|
printf(" Time Zone: %s", tz);
|
2015-08-26 19:19:32 +02:00
|
|
|
|
2014-08-12 15:19:30 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-12-19 03:16:45 +01:00
|
|
|
static int link_status(int argc, char *argv[], void *userdata) {
|
tree-wide: expose "p"-suffix unref calls in public APIs to make gcc cleanup easy
GLIB has recently started to officially support the gcc cleanup
attribute in its public API, hence let's do the same for our APIs.
With this patch we'll define an xyz_unrefp() call for each public
xyz_unref() call, to make it easy to use inside a
__attribute__((cleanup())) expression. Then, all code is ported over to
make use of this.
The new calls are also documented in the man pages, with examples how to
use them (well, I only added docs where the _unref() call itself already
had docs, and the examples, only cover sd_bus_unrefp() and
sd_event_unrefp()).
This also renames sd_lldp_free() to sd_lldp_unref(), since that's how we
tend to call our destructors these days.
Note that this defines no public macro that wraps gcc's attribute and
makes it easier to use. While I think it's our duty in the library to
make our stuff easy to use, I figure it's not our duty to make gcc's own
features easy to use on its own. Most likely, client code which wants to
make use of this should define its own:
#define _cleanup_(function) __attribute__((cleanup(function)))
Or similar, to make the gcc feature easier to use.
Making this logic public has the benefit that we can remove three header
files whose only purpose was to define these functions internally.
See #2008.
2015-11-27 19:13:45 +01:00
|
|
|
_cleanup_(sd_hwdb_unrefp) sd_hwdb *hwdb = NULL;
|
|
|
|
_cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
|
2014-08-12 01:41:42 +02:00
|
|
|
char **name;
|
|
|
|
int r;
|
|
|
|
|
2015-06-12 16:31:33 +02:00
|
|
|
r = sd_netlink_open(&rtnl);
|
2014-11-28 18:50:43 +01:00
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to connect to netlink: %m");
|
2014-08-12 16:19:37 +02:00
|
|
|
|
2014-12-15 20:07:34 +01:00
|
|
|
r = sd_hwdb_new(&hwdb);
|
|
|
|
if (r < 0)
|
|
|
|
log_debug_errno(r, "Failed to open hardware database: %m");
|
2014-12-12 18:57:15 +01:00
|
|
|
|
2014-12-19 03:16:45 +01:00
|
|
|
if (argc <= 1 && !arg_all) {
|
2014-08-12 01:41:42 +02:00
|
|
|
_cleanup_free_ char *operational_state = NULL;
|
networkd: rework Domains= setting
Previously, .network files only knew a vaguely defined "Domains=" concept, for which the documentation declared it was
the "DNS domain" for the network connection, without specifying what that means.
With this the Domains setting is reworked, so that there are now "routing" domains and "search" domains. The former are
to be used by resolved to route DNS request to specific network interfaces, the latter is to be used for searching
single-label hostnames with (in addition to being used for routing). Both settings are configured in the "Domains="
setting. Normal domain names listed in it are now considered search domains (for compatibility with existing setups),
while those prefixed with "~" are considered routing domains only. To route all lookups to a specific interface the
routing domain "." may be used, referring to the root domain. An alternative syntax for this is the "*", as was already
implemented before using the "wildcard" domain concept.
This commit adds proper parsers for this new logic, and exposes this via the sd-network API. This information is not
used by resolved yet, this will be added in a later commit.
2016-01-25 19:46:00 +01:00
|
|
|
_cleanup_strv_free_ char **dns = NULL, **ntp = NULL, **search_domains = NULL, **route_domains;
|
2014-08-14 01:23:20 +02:00
|
|
|
const char *on_color_operational, *off_color_operational;
|
2014-08-12 01:41:42 +02:00
|
|
|
|
2014-08-12 15:05:21 +02:00
|
|
|
sd_network_get_operational_state(&operational_state);
|
2014-08-14 01:23:20 +02:00
|
|
|
operational_state_to_color(operational_state, &on_color_operational, &off_color_operational);
|
2014-08-13 22:02:27 +02:00
|
|
|
|
networkd: rework Domains= setting
Previously, .network files only knew a vaguely defined "Domains=" concept, for which the documentation declared it was
the "DNS domain" for the network connection, without specifying what that means.
With this the Domains setting is reworked, so that there are now "routing" domains and "search" domains. The former are
to be used by resolved to route DNS request to specific network interfaces, the latter is to be used for searching
single-label hostnames with (in addition to being used for routing). Both settings are configured in the "Domains="
setting. Normal domain names listed in it are now considered search domains (for compatibility with existing setups),
while those prefixed with "~" are considered routing domains only. To route all lookups to a specific interface the
routing domain "." may be used, referring to the root domain. An alternative syntax for this is the "*", as was already
implemented before using the "wildcard" domain concept.
This commit adds proper parsers for this new logic, and exposes this via the sd-network API. This information is not
used by resolved yet, this will be added in a later commit.
2016-01-25 19:46:00 +01:00
|
|
|
printf("%s%s%s State: %s%s%s\n",
|
2014-12-12 19:11:35 +01:00
|
|
|
on_color_operational, draw_special_char(DRAW_BLACK_CIRCLE), off_color_operational,
|
|
|
|
on_color_operational, strna(operational_state), off_color_operational);
|
2014-08-12 15:05:21 +02:00
|
|
|
|
networkd: rework Domains= setting
Previously, .network files only knew a vaguely defined "Domains=" concept, for which the documentation declared it was
the "DNS domain" for the network connection, without specifying what that means.
With this the Domains setting is reworked, so that there are now "routing" domains and "search" domains. The former are
to be used by resolved to route DNS request to specific network interfaces, the latter is to be used for searching
single-label hostnames with (in addition to being used for routing). Both settings are configured in the "Domains="
setting. Normal domain names listed in it are now considered search domains (for compatibility with existing setups),
while those prefixed with "~" are considered routing domains only. To route all lookups to a specific interface the
routing domain "." may be used, referring to the root domain. An alternative syntax for this is the "*", as was already
implemented before using the "wildcard" domain concept.
This commit adds proper parsers for this new logic, and exposes this via the sd-network API. This information is not
used by resolved yet, this will be added in a later commit.
2016-01-25 19:46:00 +01:00
|
|
|
dump_addresses(rtnl, " Address: ", 0);
|
|
|
|
dump_gateways(rtnl, hwdb, " Gateway: ", 0);
|
2014-12-12 18:57:15 +01:00
|
|
|
|
2014-08-12 15:05:21 +02:00
|
|
|
sd_network_get_dns(&dns);
|
2016-01-25 20:14:58 +01:00
|
|
|
dump_list(" DNS: ", dns);
|
networkd: rework Domains= setting
Previously, .network files only knew a vaguely defined "Domains=" concept, for which the documentation declared it was
the "DNS domain" for the network connection, without specifying what that means.
With this the Domains setting is reworked, so that there are now "routing" domains and "search" domains. The former are
to be used by resolved to route DNS request to specific network interfaces, the latter is to be used for searching
single-label hostnames with (in addition to being used for routing). Both settings are configured in the "Domains="
setting. Normal domain names listed in it are now considered search domains (for compatibility with existing setups),
while those prefixed with "~" are considered routing domains only. To route all lookups to a specific interface the
routing domain "." may be used, referring to the root domain. An alternative syntax for this is the "*", as was already
implemented before using the "wildcard" domain concept.
This commit adds proper parsers for this new logic, and exposes this via the sd-network API. This information is not
used by resolved yet, this will be added in a later commit.
2016-01-25 19:46:00 +01:00
|
|
|
|
|
|
|
sd_network_get_search_domains(&search_domains);
|
2016-01-25 20:14:58 +01:00
|
|
|
dump_list("Search Domains: ", search_domains);
|
networkd: rework Domains= setting
Previously, .network files only knew a vaguely defined "Domains=" concept, for which the documentation declared it was
the "DNS domain" for the network connection, without specifying what that means.
With this the Domains setting is reworked, so that there are now "routing" domains and "search" domains. The former are
to be used by resolved to route DNS request to specific network interfaces, the latter is to be used for searching
single-label hostnames with (in addition to being used for routing). Both settings are configured in the "Domains="
setting. Normal domain names listed in it are now considered search domains (for compatibility with existing setups),
while those prefixed with "~" are considered routing domains only. To route all lookups to a specific interface the
routing domain "." may be used, referring to the root domain. An alternative syntax for this is the "*", as was already
implemented before using the "wildcard" domain concept.
This commit adds proper parsers for this new logic, and exposes this via the sd-network API. This information is not
used by resolved yet, this will be added in a later commit.
2016-01-25 19:46:00 +01:00
|
|
|
|
|
|
|
sd_network_get_route_domains(&route_domains);
|
2016-01-25 20:14:58 +01:00
|
|
|
dump_list(" Route Domains: ", route_domains);
|
2014-08-15 16:02:29 +02:00
|
|
|
|
2014-08-18 23:22:26 +02:00
|
|
|
sd_network_get_ntp(&ntp);
|
2016-01-25 20:14:58 +01:00
|
|
|
dump_list(" NTP: ", ntp);
|
2014-08-12 01:41:42 +02:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
pager_open_if_enabled();
|
|
|
|
|
2014-08-12 15:19:30 +02:00
|
|
|
if (arg_all) {
|
tree-wide: expose "p"-suffix unref calls in public APIs to make gcc cleanup easy
GLIB has recently started to officially support the gcc cleanup
attribute in its public API, hence let's do the same for our APIs.
With this patch we'll define an xyz_unrefp() call for each public
xyz_unref() call, to make it easy to use inside a
__attribute__((cleanup())) expression. Then, all code is ported over to
make use of this.
The new calls are also documented in the man pages, with examples how to
use them (well, I only added docs where the _unref() call itself already
had docs, and the examples, only cover sd_bus_unrefp() and
sd_event_unrefp()).
This also renames sd_lldp_free() to sd_lldp_unref(), since that's how we
tend to call our destructors these days.
Note that this defines no public macro that wraps gcc's attribute and
makes it easier to use. While I think it's our duty in the library to
make our stuff easy to use, I figure it's not our duty to make gcc's own
features easy to use on its own. Most likely, client code which wants to
make use of this should define its own:
#define _cleanup_(function) __attribute__((cleanup(function)))
Or similar, to make the gcc feature easier to use.
Making this logic public has the benefit that we can remove three header
files whose only purpose was to define these functions internally.
See #2008.
2015-11-27 19:13:45 +01:00
|
|
|
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL;
|
2014-08-12 16:03:45 +02:00
|
|
|
_cleanup_free_ LinkInfo *links = NULL;
|
|
|
|
int c, i;
|
2014-08-12 01:41:42 +02:00
|
|
|
|
2014-08-12 15:19:30 +02:00
|
|
|
r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, 0);
|
|
|
|
if (r < 0)
|
|
|
|
return rtnl_log_create_error(r);
|
2014-08-12 01:41:42 +02:00
|
|
|
|
2015-06-12 16:31:33 +02:00
|
|
|
r = sd_netlink_message_request_dump(req, true);
|
2014-08-12 01:41:42 +02:00
|
|
|
if (r < 0)
|
|
|
|
return rtnl_log_create_error(r);
|
|
|
|
|
2015-06-12 16:31:33 +02:00
|
|
|
r = sd_netlink_call(rtnl, req, 0, &reply);
|
2014-11-28 18:50:43 +01:00
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to enumerate links: %m");
|
2014-08-12 01:41:42 +02:00
|
|
|
|
2014-08-12 16:03:45 +02:00
|
|
|
c = decode_and_sort_links(reply, &links);
|
|
|
|
if (c < 0)
|
|
|
|
return rtnl_log_parse_error(c);
|
2014-08-12 01:41:42 +02:00
|
|
|
|
2014-08-12 16:03:45 +02:00
|
|
|
for (i = 0; i < c; i++) {
|
|
|
|
if (i > 0)
|
2014-08-12 15:19:30 +02:00
|
|
|
fputc('\n', stdout);
|
2014-08-12 01:41:42 +02:00
|
|
|
|
2014-12-05 01:16:05 +01:00
|
|
|
link_status_one(rtnl, hwdb, links[i].name);
|
2014-08-12 01:41:42 +02:00
|
|
|
}
|
2014-12-12 18:57:15 +01:00
|
|
|
} else {
|
2014-12-19 03:16:45 +01:00
|
|
|
STRV_FOREACH(name, argv + 1) {
|
|
|
|
if (name != argv + 1)
|
2014-12-12 18:57:15 +01:00
|
|
|
fputc('\n', stdout);
|
2014-08-12 01:41:42 +02:00
|
|
|
|
2014-12-05 01:16:05 +01:00
|
|
|
link_status_one(rtnl, hwdb, *name);
|
2014-12-12 18:57:15 +01:00
|
|
|
}
|
2014-08-12 01:41:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-12-11 05:29:55 +01:00
|
|
|
const char *lldp_system_capability_to_string(LLDPSystemCapabilities d) _const_;
|
|
|
|
LLDPSystemCapabilities lldp_system_capability_from_string(const char *d) _pure_;
|
|
|
|
|
|
|
|
static const char* const lldp_system_capability_table[_LLDP_SYSTEM_CAPABILITIES_MAX + 1] = {
|
|
|
|
[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",
|
|
|
|
};
|
|
|
|
|
|
|
|
DEFINE_STRING_TABLE_LOOKUP(lldp_system_capability, LLDPSystemCapabilities);
|
|
|
|
|
|
|
|
static char *lldp_system_caps(uint16_t cap) {
|
|
|
|
_cleanup_free_ char *s = NULL, *t = NULL;
|
|
|
|
char *capability;
|
|
|
|
|
|
|
|
t = strdup("[ ");
|
|
|
|
if (!t)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
if (cap & LLDP_SYSTEM_CAPABILITIES_OTHER) {
|
|
|
|
s = strjoin(t, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_OTHER), " ", NULL);
|
|
|
|
if (!s)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
free(t);
|
|
|
|
t = s;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (cap & LLDP_SYSTEM_CAPABILITIES_REPEATER) {
|
|
|
|
s = strjoin(t, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_REPEATER), " ", NULL);
|
|
|
|
if (!s)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
free(t);
|
|
|
|
t = s;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (cap & LLDP_SYSTEM_CAPABILITIES_BRIDGE) {
|
|
|
|
s = strjoin(t, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_BRIDGE), " ", NULL);
|
|
|
|
if (!s)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
free(t);
|
|
|
|
t = s;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (cap & LLDP_SYSTEM_CAPABILITIES_WLAN_AP) {
|
|
|
|
s = strjoin(t, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_WLAN_AP), " ", NULL);
|
|
|
|
if (!s)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
free(t);
|
|
|
|
t = s;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (cap & LLDP_SYSTEM_CAPABILITIES_ROUTER) {
|
2015-06-08 20:53:16 +02:00
|
|
|
s = strjoin(t, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_ROUTER), " ", NULL);
|
2014-12-11 05:29:55 +01:00
|
|
|
if (!s)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
free(t);
|
|
|
|
t = s;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (cap & LLDP_SYSTEM_CAPABILITIES_PHONE) {
|
|
|
|
s = strjoin(t, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_PHONE), " ", NULL);
|
|
|
|
if (!s)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
free(t);
|
|
|
|
t = s;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (cap & LLDP_SYSTEM_CAPABILITIES_DOCSIS) {
|
|
|
|
s = strjoin(t, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_DOCSIS), " ", NULL);
|
|
|
|
if (!s)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
free(t);
|
|
|
|
t = s;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (cap & LLDP_SYSTEM_CAPABILITIES_STATION) {
|
|
|
|
s = strjoin(t, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_STATION), " ", NULL);
|
|
|
|
if (!s)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
free(t);
|
|
|
|
t = s;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (cap & LLDP_SYSTEM_CAPABILITIES_CVLAN) {
|
|
|
|
s = strjoin(t, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_CVLAN), " ", NULL);
|
|
|
|
if (!s)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
free(t);
|
|
|
|
t = s;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (cap & LLDP_SYSTEM_CAPABILITIES_SVLAN) {
|
|
|
|
s = strjoin(t, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_SVLAN), " ", NULL);
|
|
|
|
if (!s)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
free(t);
|
|
|
|
t = s;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (cap & LLDP_SYSTEM_CAPABILITIES_TPMR) {
|
|
|
|
s = strappend(t, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_TPMR));
|
|
|
|
if (!s)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
free(t);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!s) {
|
|
|
|
s = strappend(t, lldp_system_capability_to_string(_LLDP_SYSTEM_CAPABILITIES_MAX));
|
|
|
|
if (!s)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
free(t);
|
|
|
|
}
|
|
|
|
|
|
|
|
t = strappend(s, "]");
|
2014-12-31 15:56:11 +01:00
|
|
|
if (!t)
|
2014-12-11 05:29:55 +01:00
|
|
|
return NULL;
|
|
|
|
|
|
|
|
free(s);
|
|
|
|
capability = t;
|
|
|
|
|
|
|
|
s = NULL;
|
|
|
|
t = NULL;
|
|
|
|
|
|
|
|
return capability;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int link_lldp_status(int argc, char *argv[], void *userdata) {
|
tree-wide: expose "p"-suffix unref calls in public APIs to make gcc cleanup easy
GLIB has recently started to officially support the gcc cleanup
attribute in its public API, hence let's do the same for our APIs.
With this patch we'll define an xyz_unrefp() call for each public
xyz_unref() call, to make it easy to use inside a
__attribute__((cleanup())) expression. Then, all code is ported over to
make use of this.
The new calls are also documented in the man pages, with examples how to
use them (well, I only added docs where the _unref() call itself already
had docs, and the examples, only cover sd_bus_unrefp() and
sd_event_unrefp()).
This also renames sd_lldp_free() to sd_lldp_unref(), since that's how we
tend to call our destructors these days.
Note that this defines no public macro that wraps gcc's attribute and
makes it easier to use. While I think it's our duty in the library to
make our stuff easy to use, I figure it's not our duty to make gcc's own
features easy to use on its own. Most likely, client code which wants to
make use of this should define its own:
#define _cleanup_(function) __attribute__((cleanup(function)))
Or similar, to make the gcc feature easier to use.
Making this logic public has the benefit that we can remove three header
files whose only purpose was to define these functions internally.
See #2008.
2015-11-27 19:13:45 +01:00
|
|
|
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL;
|
|
|
|
_cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
|
2014-12-11 05:29:55 +01:00
|
|
|
_cleanup_free_ LinkInfo *links = NULL;
|
2015-01-01 18:00:59 +01:00
|
|
|
double ttl = -1;
|
2014-12-11 05:29:55 +01:00
|
|
|
uint32_t capability;
|
|
|
|
int i, r, c, j;
|
2015-10-26 05:27:38 +01:00
|
|
|
const char *p;
|
2014-12-11 05:29:55 +01:00
|
|
|
char **s;
|
|
|
|
|
|
|
|
pager_open_if_enabled();
|
|
|
|
|
2015-06-12 16:31:33 +02:00
|
|
|
r = sd_netlink_open(&rtnl);
|
2014-12-11 05:29:55 +01:00
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to connect to netlink: %m");
|
|
|
|
|
|
|
|
r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, 0);
|
|
|
|
if (r < 0)
|
|
|
|
return rtnl_log_create_error(r);
|
|
|
|
|
2015-06-12 16:31:33 +02:00
|
|
|
r = sd_netlink_message_request_dump(req, true);
|
2014-12-11 05:29:55 +01:00
|
|
|
if (r < 0)
|
|
|
|
return rtnl_log_create_error(r);
|
|
|
|
|
2015-06-12 16:31:33 +02:00
|
|
|
r = sd_netlink_call(rtnl, req, 0, &reply);
|
2014-12-11 05:29:55 +01:00
|
|
|
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);
|
|
|
|
|
2014-12-19 08:33:46 +01:00
|
|
|
if (arg_legend)
|
|
|
|
printf("%s %16s %24s %16s %16s\n", "Local Intf", "Device ID", "Port ID", "TTL", "Capability");
|
2014-12-11 05:29:55 +01:00
|
|
|
|
|
|
|
for (i = j = 0; i < c; i++) {
|
|
|
|
_cleanup_free_ char *chassis = NULL, *port = NULL, *cap = NULL, *lldp = NULL;
|
|
|
|
_cleanup_strv_free_ char **l = NULL;
|
|
|
|
|
|
|
|
r = sd_network_link_get_lldp(links[i].ifindex, &lldp);
|
|
|
|
if (r < 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
l = strv_split_newlines(lldp);
|
|
|
|
if (!l)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
STRV_FOREACH(s, l) {
|
|
|
|
|
2015-10-26 05:27:38 +01:00
|
|
|
p = *s;
|
|
|
|
for (;;) {
|
|
|
|
_cleanup_free_ char *a = NULL, *b = NULL, *word = NULL;
|
|
|
|
|
|
|
|
r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to parse LLDP syntax \"%s\": %m", *s);
|
|
|
|
|
|
|
|
if (r == 0)
|
|
|
|
break;
|
2014-12-11 05:29:55 +01:00
|
|
|
|
2015-10-26 05:27:38 +01:00
|
|
|
r = split_pair(word, "=", &a, &b);
|
2014-12-11 05:29:55 +01:00
|
|
|
if (r < 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (streq(a, "_Chassis")) {
|
2015-03-07 20:06:35 +01:00
|
|
|
r = free_and_strdup(&chassis, b);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2014-12-11 05:29:55 +01:00
|
|
|
|
|
|
|
} else if (streq(a, "_Port")) {
|
2015-03-07 20:06:35 +01:00
|
|
|
r = free_and_strdup(&port, b);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2014-12-11 05:29:55 +01:00
|
|
|
|
|
|
|
} else if (streq(a, "_TTL")) {
|
2015-03-27 12:02:49 +01:00
|
|
|
long long unsigned x = 0;
|
2015-01-01 18:00:59 +01:00
|
|
|
usec_t time;
|
2014-12-11 05:29:55 +01:00
|
|
|
|
2015-01-01 18:00:59 +01:00
|
|
|
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);
|
2014-12-11 05:29:55 +01:00
|
|
|
|
2015-08-03 16:43:29 +02:00
|
|
|
time = now(clock_boottime_or_monotonic());
|
2015-01-01 18:00:59 +01:00
|
|
|
if (x < time)
|
|
|
|
continue;
|
2014-12-11 05:29:55 +01:00
|
|
|
|
2015-01-01 18:00:59 +01:00
|
|
|
ttl = (double) (x - time) / USEC_PER_SEC;
|
2014-12-11 05:29:55 +01:00
|
|
|
|
|
|
|
} else if (streq(a, "_CAP")) {
|
|
|
|
sscanf(b, "%x", &capability);
|
|
|
|
|
|
|
|
cap = lldp_system_caps(capability);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2015-01-01 18:00:59 +01:00
|
|
|
if (ttl >= 0) {
|
|
|
|
printf("%10s %24s %16s %16f %16s\n",
|
|
|
|
links[i].name,
|
|
|
|
strna(chassis), strna(port),
|
|
|
|
ttl, cap);
|
2014-12-11 05:29:55 +01:00
|
|
|
j++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-12-19 08:33:46 +01:00
|
|
|
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);
|
|
|
|
}
|
2014-12-11 05:29:55 +01:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-08-12 01:41:42 +02:00
|
|
|
static void help(void) {
|
|
|
|
printf("%s [OPTIONS...]\n\n"
|
|
|
|
"Query and control the networking subsystem.\n\n"
|
|
|
|
" -h --help Show this help\n"
|
2014-08-12 15:19:30 +02:00
|
|
|
" --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"
|
2014-08-12 01:41:42 +02:00
|
|
|
"Commands:\n"
|
|
|
|
" list List links\n"
|
2015-01-20 03:44:16 +01:00
|
|
|
" status [LINK...] Show link status\n"
|
2014-12-11 05:29:55 +01:00
|
|
|
" lldp Show lldp information\n"
|
2014-08-12 01:41:42 +02:00
|
|
|
, 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 },
|
2014-08-12 15:19:30 +02:00
|
|
|
{ "all", no_argument, NULL, 'a' },
|
2014-08-12 01:41:42 +02:00
|
|
|
{}
|
|
|
|
};
|
|
|
|
|
|
|
|
int c;
|
|
|
|
|
|
|
|
assert(argc >= 0);
|
|
|
|
assert(argv);
|
|
|
|
|
2014-08-12 15:19:30 +02:00
|
|
|
while ((c = getopt_long(argc, argv, "ha", options, NULL)) >= 0) {
|
2014-08-12 01:41:42 +02:00
|
|
|
|
|
|
|
switch (c) {
|
|
|
|
|
|
|
|
case 'h':
|
|
|
|
help();
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
case ARG_VERSION:
|
2015-09-23 03:01:06 +02:00
|
|
|
return version();
|
2014-08-12 01:41:42 +02:00
|
|
|
|
|
|
|
case ARG_NO_PAGER:
|
|
|
|
arg_no_pager = true;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case ARG_NO_LEGEND:
|
|
|
|
arg_legend = false;
|
|
|
|
break;
|
|
|
|
|
2014-08-12 15:19:30 +02:00
|
|
|
case 'a':
|
|
|
|
arg_all = true;
|
|
|
|
break;
|
|
|
|
|
2014-08-12 01:41:42 +02:00
|
|
|
case '?':
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
default:
|
|
|
|
assert_not_reached("Unhandled option");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int networkctl_main(int argc, char *argv[]) {
|
2014-12-19 03:16:45 +01:00
|
|
|
const Verb verbs[] = {
|
|
|
|
{ "list", VERB_ANY, 1, VERB_DEFAULT, list_links },
|
|
|
|
{ "status", 1, VERB_ANY, 0, link_status },
|
2014-12-11 05:29:55 +01:00
|
|
|
{ "lldp", VERB_ANY, 1, VERB_DEFAULT, link_lldp_status },
|
2014-12-19 03:16:45 +01:00
|
|
|
{}
|
2014-08-12 01:41:42 +02:00
|
|
|
};
|
|
|
|
|
2014-12-19 03:16:45 +01:00
|
|
|
return dispatch_verb(argc, argv, verbs, NULL);
|
2014-08-12 01:41:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|