summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--Makefile.am36
-rw-r--r--src/libsystemd/sd-bus/bus-util.c4
-rw-r--r--src/libsystemd/sd-rtnl/local-addresses.c26
-rw-r--r--src/libsystemd/sd-rtnl/local-addresses.h3
-rw-r--r--src/libsystemd/sd-rtnl/rtnl-message.c15
-rw-r--r--src/libsystemd/sd-rtnl/rtnl-util.c10
-rw-r--r--src/libsystemd/sd-rtnl/rtnl-util.h3
-rw-r--r--src/machine/machine-dbus.c2
-rw-r--r--src/network/networkctl.c532
-rw-r--r--src/notify/notify.c3
-rw-r--r--src/nss-myhostname/nss-myhostname.c6
-rw-r--r--src/shared/.gitignore4
-rw-r--r--src/shared/arphrd-list.c59
-rw-r--r--src/shared/arphrd-list.h27
-rw-r--r--src/systemd/sd-rtnl.h1
16 files changed, 713 insertions, 19 deletions
diff --git a/.gitignore b/.gitignore
index 73e8b6b44..6f905247f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -43,6 +43,7 @@
/loginctl
/machinectl
/mtd_probe
+/networkctl
/scsi_id
/systemadm
/systemctl
diff --git a/Makefile.am b/Makefile.am
index ce8f2472e..2d00fcec4 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -833,6 +833,8 @@ libsystemd_shared_la_SOURCES = \
src/shared/errno-list.h \
src/shared/af-list.c \
src/shared/af-list.h \
+ src/shared/arphrd-list.c \
+ src/shared/arphrd-list.h \
src/shared/audit.c \
src/shared/audit.h \
src/shared/xml.c \
@@ -864,7 +866,9 @@ nodist_libsystemd_shared_la_SOURCES = \
src/shared/errno-from-name.h \
src/shared/errno-to-name.h \
src/shared/af-from-name.h \
- src/shared/af-to-name.h
+ src/shared/af-to-name.h \
+ src/shared/arphrd-from-name.h \
+ src/shared/arphrd-to-name.h
libsystemd_shared_la_CFLAGS = \
$(AM_CFLAGS) \
@@ -1150,6 +1154,8 @@ CLEANFILES += \
src/shared/errno-from-name.gperf \
src/shared/af-list.txt \
src/shared/af-from-name.gperf \
+ src/shared/arphrd-list.txt \
+ src/shared/arphrd-from-name.gperf \
src/shared/dns_type-list.txt \
src/shared/dns_type-from-name.gperf
@@ -1158,6 +1164,8 @@ BUILT_SOURCES += \
src/shared/errno-to-name.h \
src/shared/af-from-name.h \
src/shared/af-to-name.h \
+ src/shared/arphrd-from-name.h \
+ src/shared/arphrd-to-name.h \
src/resolve/dns_type-from-name.h \
src/resolve/dns_type-to-name.h
@@ -1170,7 +1178,7 @@ BUILT_SOURCES += \
src/shared/errno-list.txt:
$(AM_V_at)$(MKDIR_P) $(dir $@)
- $(AM_V_GEN)$(CPP) $(CFLAGS) $(AM_CPPFLAGS) $(CPPFLAGS) -dM -include errno.h - </dev/null | $(AWK) '/^#define[ \t]+E[^ _]+[ \t]+/ { print $$2; }' >$@
+ $(AM_V_GEN)$(CPP) $(CFLAGS) $(AM_CPPFLAGS) $(CPPFLAGS) -dM -include errno.h - </dev/null | $(AWK) '/^#define[ \t]+E[^ _]+[ \t]+/ { print $$2; }' >$@
src/shared/errno-to-name.h: src/shared/errno-list.txt
$(AM_V_GEN)$(AWK) 'BEGIN{ print "static const char* const errno_names[] = { "} !/EDEADLOCK/ && !/EWOULDBLOCK/ && !/ENOTSUP/ { printf "[%s] = \"%s\",\n", $$1, $$1 } END{print "};"}' <$< >$@
@@ -1178,11 +1186,21 @@ src/shared/errno-to-name.h: src/shared/errno-list.txt
src/shared/af-list.txt:
$(AM_V_at)$(MKDIR_P) $(dir $@)
- $(AM_V_GEN)$(CPP) $(CFLAGS) $(AM_CPPFLAGS) $(CPPFLAGS) -dM -include sys/socket.h - </dev/null | grep -v AF_UNSPEC | grep -v AF_MAX | $(AWK) '/^#define[ \t]+AF_[^ \t]+[ \t]+PF_[^ \t]/ { print $$2; }' >$@
+ $(AM_V_GEN)$(CPP) $(CFLAGS) $(AM_CPPFLAGS) $(CPPFLAGS) -dM -include sys/socket.h - </dev/null | grep -v AF_UNSPEC | grep -v AF_MAX | $(AWK) '/^#define[ \t]+AF_[^ \t]+[ \t]+PF_[^ \t]/ { print $$2; }' >$@
src/shared/af-to-name.h: src/shared/af-list.txt
$(AM_V_GEN)$(AWK) 'BEGIN{ print "static const char* const af_names[] = { "} !/AF_FILE/ && !/AF_ROUTE/ && !/AF_LOCAL/ { printf "[%s] = \"%s\",\n", $$1, $$1 } END{print "};"}' <$< >$@
+src/shared/arphrd-list.txt:
+ $(AM_V_at)$(MKDIR_P) $(dir $@)
+ $(AM_V_GEN)$(CPP) $(CFLAGS) $(AM_CPPFLAGS) $(CPPFLAGS) -dM -include net/if_arp.h - </dev/null | $(AWK) '/^#define[ \t]+ARPHRD_[^ \t]+[ \t]+[^ \t]/ { print $$2; }' | sed -e 's/ARPHRD_//' >$@
+
+src/shared/arphrd-to-name.h: src/shared/arphrd-list.txt
+ $(AM_V_GEN)$(AWK) 'BEGIN{ print "static const char* const arphrd_names[] = { "} !/CISCO/ { printf "[ARPHRD_%s] = \"%s\",\n", $$1, $$1 } END{print "};"}' <$< >$@
+
+src/shared/arphrd-from-name.gperf: src/shared/arphrd-list.txt
+ $(AM_V_GEN)$(AWK) 'BEGIN{ print "struct arphrd_name { const char* name; int id; };"; print "%null-strings"; print "%%";} { printf "%s, ARPHRD_%s\n", $$1, $$1 }' <$< >$@
+
src/resolve/dns_type-list.txt: src/resolve/dns-type.h
$(AM_V_at)$(MKDIR_P) $(dir $@)
@@ -4974,6 +4992,18 @@ systemd_networkd_wait_online_LDADD = \
libsystemd-internal.la \
libsystemd-shared.la
+rootbin_PROGRAMS += \
+ networkctl
+
+networkctl_SOURCES = \
+ src/network/networkctl.c
+
+networkctl_LDADD = \
+ libsystemd-internal.la \
+ libudev-internal.la \
+ libsystemd-shared.la \
+ libsystemd-network.la
+
test_network_SOURCES = \
src/network/test-network.c
diff --git a/src/libsystemd/sd-bus/bus-util.c b/src/libsystemd/sd-bus/bus-util.c
index d41e53753..32c536813 100644
--- a/src/libsystemd/sd-bus/bus-util.c
+++ b/src/libsystemd/sd-bus/bus-util.c
@@ -1186,12 +1186,12 @@ int bus_property_get_ulong(
#endif
int bus_log_parse_error(int r) {
- log_error("Failed to parse message: %s", strerror(-r));
+ log_error("Failed to parse bus message: %s", strerror(-r));
return r;
}
int bus_log_create_error(int r) {
- log_error("Failed to create message: %s", strerror(-r));
+ log_error("Failed to create bus message: %s", strerror(-r));
return r;
}
diff --git a/src/libsystemd/sd-rtnl/local-addresses.c b/src/libsystemd/sd-rtnl/local-addresses.c
index dd5ccedc9..c5508856c 100644
--- a/src/libsystemd/sd-rtnl/local-addresses.c
+++ b/src/libsystemd/sd-rtnl/local-addresses.c
@@ -48,7 +48,7 @@ static int address_compare(const void *_a, const void *_b) {
return 0;
}
-int local_addresses(struct local_address **ret) {
+int local_addresses(sd_rtnl *context, int ifindex, struct local_address **ret) {
_cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
_cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
_cleanup_free_ struct local_address *list = NULL;
@@ -58,9 +58,13 @@ int local_addresses(struct local_address **ret) {
assert(ret);
- r = sd_rtnl_open(&rtnl, 0);
- if (r < 0)
- return r;
+ if (context)
+ rtnl = sd_rtnl_ref(context);
+ else {
+ r = sd_rtnl_open(&rtnl, 0);
+ if (r < 0)
+ return r;
+ }
r = sd_rtnl_message_new_addr(rtnl, &req, RTM_GETADDR, 0, AF_UNSPEC);
if (r < 0)
@@ -74,6 +78,7 @@ int local_addresses(struct local_address **ret) {
struct local_address *a;
unsigned char flags;
uint16_t type;
+ int ifi;
r = sd_rtnl_message_get_errno(m);
if (r < 0)
@@ -86,6 +91,13 @@ int local_addresses(struct local_address **ret) {
if (type != RTM_NEWADDR)
continue;
+ r = sd_rtnl_message_addr_get_ifindex(m, &ifi);
+ if (r < 0)
+ return r;
+
+ if (ifindex != 0 && ifi != ifindex)
+ continue;
+
r = sd_rtnl_message_addr_get_flags(m, &flags);
if (r < 0)
return r;
@@ -102,7 +114,7 @@ int local_addresses(struct local_address **ret) {
if (r < 0)
return r;
- if (a->scope == RT_SCOPE_HOST || a->scope == RT_SCOPE_NOWHERE)
+ if (ifindex == 0 && (a->scope == RT_SCOPE_HOST || a->scope == RT_SCOPE_NOWHERE))
continue;
r = sd_rtnl_message_addr_get_family(m, &a->family);
@@ -133,9 +145,7 @@ int local_addresses(struct local_address **ret) {
continue;
}
- r = sd_rtnl_message_addr_get_ifindex(m, &a->ifindex);
- if (r < 0)
- return r;
+ a->ifindex = ifi;
n_list++;
};
diff --git a/src/libsystemd/sd-rtnl/local-addresses.h b/src/libsystemd/sd-rtnl/local-addresses.h
index c6e3559bf..b1ed6341f 100644
--- a/src/libsystemd/sd-rtnl/local-addresses.h
+++ b/src/libsystemd/sd-rtnl/local-addresses.h
@@ -26,6 +26,7 @@
#include <assert.h>
#include <sys/socket.h>
+#include "sd-rtnl.h"
#include "in-addr-util.h"
struct local_address {
@@ -34,4 +35,4 @@ struct local_address {
union in_addr_union address;
};
-int local_addresses(struct local_address **ret);
+int local_addresses(sd_rtnl *rtnl, int ifindex, struct local_address **ret);
diff --git a/src/libsystemd/sd-rtnl/rtnl-message.c b/src/libsystemd/sd-rtnl/rtnl-message.c
index c50d0ea98..1f596ca10 100644
--- a/src/libsystemd/sd-rtnl/rtnl-message.c
+++ b/src/libsystemd/sd-rtnl/rtnl-message.c
@@ -465,6 +465,21 @@ int sd_rtnl_message_link_get_flags(sd_rtnl_message *m, unsigned *flags) {
return 0;
}
+int sd_rtnl_message_link_get_type(sd_rtnl_message *m, unsigned *type) {
+ struct ifinfomsg *ifi;
+
+ assert_return(m, -EINVAL);
+ assert_return(m->hdr, -EINVAL);
+ assert_return(rtnl_message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
+ assert_return(type, -EINVAL);
+
+ ifi = NLMSG_DATA(m->hdr);
+
+ *type = ifi->ifi_type;
+
+ return 0;
+}
+
/* If successful the updated message will be correctly aligned, if
unsuccessful the old message is untouched. */
static int add_rtattr(sd_rtnl_message *m, unsigned short type, const void *data, size_t data_length) {
diff --git a/src/libsystemd/sd-rtnl/rtnl-util.c b/src/libsystemd/sd-rtnl/rtnl-util.c
index c8b20d109..0bc2c9b1f 100644
--- a/src/libsystemd/sd-rtnl/rtnl-util.c
+++ b/src/libsystemd/sd-rtnl/rtnl-util.c
@@ -153,3 +153,13 @@ bool rtnl_message_type_is_addr(uint16_t type) {
return false;
}
}
+
+int rtnl_log_parse_error(int r) {
+ log_error("Failed to parse netlink message: %s", strerror(-r));
+ return r;
+}
+
+int rtnl_log_create_error(int r) {
+ log_error("Failed to create netlink message: %s", strerror(-r));
+ return r;
+}
diff --git a/src/libsystemd/sd-rtnl/rtnl-util.h b/src/libsystemd/sd-rtnl/rtnl-util.h
index 06d5699c3..2963f02d3 100644
--- a/src/libsystemd/sd-rtnl/rtnl-util.h
+++ b/src/libsystemd/sd-rtnl/rtnl-util.h
@@ -37,6 +37,9 @@ bool rtnl_message_type_is_route(uint16_t type);
int rtnl_set_link_name(sd_rtnl *rtnl, int ifindex, const char *name);
int rtnl_set_link_properties(sd_rtnl *rtnl, int ifindex, const char *alias, const struct ether_addr *mac, unsigned mtu);
+int rtnl_log_parse_error(int r);
+int rtnl_log_create_error(int r);
+
DEFINE_TRIVIAL_CLEANUP_FUNC(sd_rtnl*, sd_rtnl_unref);
DEFINE_TRIVIAL_CLEANUP_FUNC(sd_rtnl_message*, sd_rtnl_message_unref);
diff --git a/src/machine/machine-dbus.c b/src/machine/machine-dbus.c
index 89c93779d..f12ce98a8 100644
--- a/src/machine/machine-dbus.c
+++ b/src/machine/machine-dbus.c
@@ -207,7 +207,7 @@ int bus_machine_method_get_addresses(sd_bus *bus, sd_bus_message *message, void
if (r < 0)
_exit(EXIT_FAILURE);
- n = local_addresses(&addresses);
+ n = local_addresses(NULL, 0, &addresses);
if (n < 0)
_exit(EXIT_FAILURE);
diff --git a/src/network/networkctl.c b/src/network/networkctl.c
new file mode 100644
index 000000000..93b129345
--- /dev/null
+++ b/src/network/networkctl.c
@@ -0,0 +1,532 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ 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 <stdbool.h>
+#include <getopt.h>
+
+#include "sd-network.h"
+#include "sd-rtnl.h"
+#include "libudev.h"
+
+#include "build.h"
+#include "util.h"
+#include "pager.h"
+#include "rtnl-util.h"
+#include "udev-util.h"
+#include "arphrd-list.h"
+#include "local-addresses.h"
+
+static bool arg_no_pager = false;
+static bool arg_legend = true;
+
+static void pager_open_if_enabled(void) {
+
+ if (arg_no_pager)
+ return;
+
+ pager_open(false);
+}
+
+static int link_get_type_string(int iftype, struct udev_device *d, char **ret) {
+ const char *t;
+ char *p;
+
+ if (iftype == ARPHRD_ETHER && d) {
+ const char *devtype, *id = NULL;
+ /* WLANs have iftype ARPHRD_ETHER, but we want
+ * to show a more useful type string for
+ * them */
+
+ devtype = udev_device_get_devtype(d);
+ 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;
+}
+
+static int list_links(char **args, unsigned n) {
+ _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
+ _cleanup_udev_unref_ struct udev *udev = NULL;
+ _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
+ sd_rtnl_message *i;
+ unsigned c = 0;
+ int r;
+
+ pager_open_if_enabled();
+
+ r = sd_rtnl_open(&rtnl, 0);
+ if (r < 0) {
+ log_error("Failed to connect to netlink: %s", strerror(-r));
+ return r;
+ }
+
+ udev = udev_new();
+ if (!udev) {
+ log_error("Failed to connect to udev: %m");
+ return -errno;
+ }
+
+ r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, 0);
+ if (r < 0)
+ return rtnl_log_create_error(r);
+
+ r = sd_rtnl_message_request_dump(req, true);
+ if (r < 0)
+ return rtnl_log_create_error(r);
+
+ r = sd_rtnl_call(rtnl, req, 0, &reply);
+ if (r < 0) {
+ log_error("Failed to enumerate links: %s", strerror(-r));
+ return r;
+ }
+
+ if (arg_legend)
+ printf("%3s %-16s %-10s %-10s %-10s\n", "IDX", "LINK", "TYPE", "STATE", "OPERATIONAL");
+
+ for (i = reply; i; i = sd_rtnl_message_next(i)) {
+ _cleanup_free_ char *state = NULL, *operational_state = NULL;
+ _cleanup_udev_device_unref_ struct udev_device *d = NULL;
+ char devid[2 + DECIMAL_STR_MAX(int)];
+ _cleanup_free_ char *t = NULL;
+ const char *name;
+ unsigned iftype;
+ uint16_t type;
+ int ifindex;
+
+ r = sd_rtnl_message_get_type(i, &type);
+ if (r < 0)
+ return rtnl_log_parse_error(r);
+
+ if (type != RTM_NEWLINK)
+ continue;
+
+ r = sd_rtnl_message_link_get_ifindex(i, &ifindex);
+ if (r < 0)
+ return rtnl_log_parse_error(r);
+
+ r = sd_rtnl_message_read_string(i, IFLA_IFNAME, &name);
+ if (r < 0)
+ return rtnl_log_parse_error(r);
+
+ r = sd_rtnl_message_link_get_type(i, &iftype);
+ if (r < 0)
+ return rtnl_log_parse_error(r);
+
+ sd_network_get_link_state(ifindex, &state);
+ sd_network_get_link_operational_state(ifindex, &operational_state);
+
+ sprintf(devid, "n%i", ifindex);
+ d = udev_device_new_from_device_id(udev, devid);
+
+ link_get_type_string(iftype, d, &t);
+
+ printf("%3i %-16s %-10s %-10s %-10s\n", ifindex, name, strna(t), strna(state), strna(operational_state));
+ c++;
+ }
+
+ if (arg_legend)
+ printf("\n%u links listed.\n", c);
+
+ 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, &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(char **args, unsigned n) {
+ _cleanup_udev_unref_ struct udev *udev = NULL;
+ _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
+ char **name;
+ int r;
+
+ if (n <= 1) {
+ _cleanup_free_ char *operational_state = NULL;
+
+ r = sd_network_get_operational_state(&operational_state);
+ if (r < 0) {
+ log_error("Failed to get operational state: %s", strerror(-r));
+ return r;
+ }
+
+ printf("State: %s\n", operational_state);
+ return 0;
+ }
+
+ pager_open_if_enabled();
+
+ r = sd_rtnl_open(&rtnl, 0);
+ if (r < 0) {
+ log_error("Failed to connect to netlink: %s", strerror(-r));
+ return r;
+ }
+
+ udev = udev_new();
+ if (!udev) {
+ log_error("Failed to connect to udev: %m");
+ return -errno;
+ }
+
+ STRV_FOREACH(name, args + 1) {
+ _cleanup_strv_free_ char **dns = NULL, **ntp = NULL;
+ _cleanup_free_ char *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;
+ const char *canonical_name = NULL;
+ char devid[2 + DECIMAL_STR_MAX(int)];
+ int ifindex, canonical_ifindex;
+ _cleanup_free_ char *t = NULL;
+ const char *driver = NULL, *path = NULL, *vendor = NULL, *model = NULL;
+ struct ether_addr e;
+ unsigned iftype;
+ bool have_mac;
+ uint32_t mtu;
+
+ if (name != args+1)
+ printf("\n");
+
+ 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) {
+ log_error("Failed to query link: %s", strerror(-r));
+ continue;
+ }
+
+ r = sd_rtnl_message_link_get_ifindex(reply, &canonical_ifindex);
+ if (r < 0)
+ return rtnl_log_parse_error(r);
+
+ r = sd_rtnl_message_read_string(reply, IFLA_IFNAME, &canonical_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_get_link_state(canonical_ifindex, &state);
+ sd_network_get_link_operational_state(canonical_ifindex, &operational_state);
+
+ sd_network_get_link_dns(canonical_ifindex, &dns);
+ sd_network_get_link_dns(canonical_ifindex, &ntp);
+
+ sprintf(devid, "n%i", canonical_ifindex);
+ d = udev_device_new_from_device_id(udev, devid);
+
+ link_get_type_string(iftype, d, &t);
+
+ if (d) {
+ driver = udev_device_get_property_value(d, "ID_NET_DRIVER");
+ path = udev_device_get_property_value(d, "ID_PATH");
+
+ vendor = udev_device_get_property_value(d, "ID_VENDOR_FROM_DATABASE");
+ if (!vendor)
+ vendor = udev_device_get_property_value(d, "ID_VENDOR");
+
+ model = udev_device_get_property_value(d, "ID_MODEL_FROM_DATABASE");
+ if (!model)
+ model = udev_device_get_property_value(d, "ID_MODEL");
+ }
+
+ printf("%i: %s\n", canonical_ifindex, canonical_name);
+
+ printf(" Type: %s\n"
+ " State: %s (%s)\n",
+ strna(t),
+ strna(operational_state),
+ strna(state));
+
+ if (path)
+ printf(" Path: %s\n", path);
+ if (driver)
+ printf(" Driver: %s\n", driver);
+ if (vendor)
+ printf(" Vendor: %s\n", vendor);
+ if (model)
+ printf(" Model: %s\n", model);
+
+ if (have_mac) {
+ _cleanup_free_ char *h = NULL;
+
+ h = hexmem(&e, sizeof(e));
+ if (!h)
+ return log_oom();
+
+ printf(" HW Address: %s\n", h);
+ }
+
+ if (mtu > 0)
+ printf(" MTU: %u\n", mtu);
+
+ dump_addresses(rtnl, " Address: ", canonical_ifindex);
+
+ if (!strv_isempty(dns))
+ dump_list(" DNS: ", dns);
+ if (!strv_isempty(ntp))
+ dump_list(" NTP: ", ntp);
+ }
+
+ 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\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 },
+ {}
+ };
+
+ int c;
+
+ assert(argc >= 0);
+ assert(argv);
+
+ while ((c = getopt_long(argc, argv, "h", 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 '?':
+ 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;
+}
diff --git a/src/notify/notify.c b/src/notify/notify.c
index 2148ae0df..6f1c52e3f 100644
--- a/src/notify/notify.c
+++ b/src/notify/notify.c
@@ -82,7 +82,7 @@ static int parse_argv(int argc, char *argv[]) {
assert(argc >= 0);
assert(argv);
- while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
+ while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) {
switch (c) {
@@ -129,6 +129,7 @@ static int parse_argv(int argc, char *argv[]) {
default:
assert_not_reached("Unhandled option");
}
+ }
if (optind >= argc &&
!arg_ready &&
diff --git a/src/nss-myhostname/nss-myhostname.c b/src/nss-myhostname/nss-myhostname.c
index 08d70f6c0..86e7be2aa 100644
--- a/src/nss-myhostname/nss-myhostname.c
+++ b/src/nss-myhostname/nss-myhostname.c
@@ -92,7 +92,7 @@ enum nss_status _nss_myhostname_gethostbyname4_r(
return NSS_STATUS_NOTFOUND;
}
- n_addresses = local_addresses(&addresses);
+ n_addresses = local_addresses(NULL, 0, &addresses);
if (n_addresses < 0)
n_addresses = 0;
@@ -349,7 +349,7 @@ enum nss_status _nss_myhostname_gethostbyname3_r(
return NSS_STATUS_NOTFOUND;
}
- n_addresses = local_addresses(&addresses);
+ n_addresses = local_addresses(NULL, 0, &addresses);
if (n_addresses < 0)
n_addresses = 0;
@@ -425,7 +425,7 @@ enum nss_status _nss_myhostname_gethostbyaddr2_r(
}
- n_addresses = local_addresses(&addresses);
+ n_addresses = local_addresses(NULL, 0, &addresses);
if (n_addresses < 0)
n_addresses = 0;
diff --git a/src/shared/.gitignore b/src/shared/.gitignore
index 9f4ec9f9c..61709e8da 100644
--- a/src/shared/.gitignore
+++ b/src/shared/.gitignore
@@ -6,3 +6,7 @@
/af-from-name.h
/af-list.txt
/af-to-name.h
+/arphrd-from-name.gperf
+/arphrd-from-name.h
+/arphrd-list.txt
+/arphrd-to-name.h
diff --git a/src/shared/arphrd-list.c b/src/shared/arphrd-list.c
new file mode 100644
index 000000000..6e113eff7
--- /dev/null
+++ b/src/shared/arphrd-list.c
@@ -0,0 +1,59 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ 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 <net/if_arp.h>
+#include <sys/socket.h>
+#include <string.h>
+
+#include "util.h"
+#include "arphrd-list.h"
+
+static const struct arphrd_name* lookup_arphrd(register const char *str, register unsigned int len);
+
+#include "arphrd-to-name.h"
+#include "arphrd-from-name.h"
+
+const char *arphrd_to_name(int id) {
+
+ if (id <= 0)
+ return NULL;
+
+ if (id >= (int) ELEMENTSOF(arphrd_names))
+ return NULL;
+
+ return arphrd_names[id];
+}
+
+int arphrd_from_name(const char *name) {
+ const struct arphrd_name *sc;
+
+ assert(name);
+
+ sc = lookup_arphrd(name, strlen(name));
+ if (!sc)
+ return 0;
+
+ return sc->id;
+}
+
+int arphrd_max(void) {
+ return ELEMENTSOF(arphrd_names);
+}
diff --git a/src/shared/arphrd-list.h b/src/shared/arphrd-list.h
new file mode 100644
index 000000000..5ca182c9e
--- /dev/null
+++ b/src/shared/arphrd-list.h
@@ -0,0 +1,27 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#pragma once
+
+/***
+ 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/>.
+***/
+
+const char *arphrd_to_name(int id);
+int arphrd_from_name(const char *name);
+
+int arphrd_max(void);
diff --git a/src/systemd/sd-rtnl.h b/src/systemd/sd-rtnl.h
index 47bb232ff..1e7eb811d 100644
--- a/src/systemd/sd-rtnl.h
+++ b/src/systemd/sd-rtnl.h
@@ -95,6 +95,7 @@ int sd_rtnl_message_link_set_flags(sd_rtnl_message *m, unsigned flags, unsigned
int sd_rtnl_message_link_set_type(sd_rtnl_message *m, unsigned type);
int sd_rtnl_message_link_get_ifindex(sd_rtnl_message *m, int *ifindex);
int sd_rtnl_message_link_get_flags(sd_rtnl_message *m, unsigned *flags);
+int sd_rtnl_message_link_get_type(sd_rtnl_message *m, unsigned *type);
int sd_rtnl_message_route_set_dst_prefixlen(sd_rtnl_message *m, unsigned char prefixlen);
int sd_rtnl_message_route_set_scope(sd_rtnl_message *m, unsigned char scope);