1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2014 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
25 #include "sd-network.h"
32 #include "rtnl-util.h"
33 #include "udev-util.h"
34 #include "arphrd-list.h"
35 #include "local-addresses.h"
37 static bool arg_no_pager = false;
38 static bool arg_legend = true;
40 static void pager_open_if_enabled(void) {
48 static int link_get_type_string(int iftype, struct udev_device *d, char **ret) {
52 if (iftype == ARPHRD_ETHER && d) {
53 const char *devtype, *id = NULL;
54 /* WLANs have iftype ARPHRD_ETHER, but we want
55 * to show a more useful type string for
58 devtype = udev_device_get_devtype(d);
59 if (streq_ptr(devtype, "wlan"))
61 else if (streq_ptr(devtype, "wwan"))
74 t = arphrd_to_name(iftype);
90 static int list_links(char **args, unsigned n) {
91 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
92 _cleanup_udev_unref_ struct udev *udev = NULL;
93 _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
98 pager_open_if_enabled();
100 r = sd_rtnl_open(&rtnl, 0);
102 log_error("Failed to connect to netlink: %s", strerror(-r));
108 log_error("Failed to connect to udev: %m");
112 r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, 0);
114 return rtnl_log_create_error(r);
116 r = sd_rtnl_message_request_dump(req, true);
118 return rtnl_log_create_error(r);
120 r = sd_rtnl_call(rtnl, req, 0, &reply);
122 log_error("Failed to enumerate links: %s", strerror(-r));
127 printf("%3s %-16s %-10s %-10s %-10s\n", "IDX", "LINK", "TYPE", "STATE", "OPERATIONAL");
129 for (i = reply; i; i = sd_rtnl_message_next(i)) {
130 _cleanup_free_ char *state = NULL, *operational_state = NULL;
131 _cleanup_udev_device_unref_ struct udev_device *d = NULL;
132 char devid[2 + DECIMAL_STR_MAX(int)];
133 _cleanup_free_ char *t = NULL;
139 r = sd_rtnl_message_get_type(i, &type);
141 return rtnl_log_parse_error(r);
143 if (type != RTM_NEWLINK)
146 r = sd_rtnl_message_link_get_ifindex(i, &ifindex);
148 return rtnl_log_parse_error(r);
150 r = sd_rtnl_message_read_string(i, IFLA_IFNAME, &name);
152 return rtnl_log_parse_error(r);
154 r = sd_rtnl_message_link_get_type(i, &iftype);
156 return rtnl_log_parse_error(r);
158 sd_network_get_link_state(ifindex, &state);
159 sd_network_get_link_operational_state(ifindex, &operational_state);
161 sprintf(devid, "n%i", ifindex);
162 d = udev_device_new_from_device_id(udev, devid);
164 link_get_type_string(iftype, d, &t);
166 printf("%3i %-16s %-10s %-10s %-10s\n", ifindex, name, strna(t), strna(state), strna(operational_state));
171 printf("\n%u links listed.\n", c);
176 static int dump_addresses(sd_rtnl *rtnl, const char *prefix, int ifindex) {
177 _cleanup_free_ struct local_address *local = NULL;
180 n = local_addresses(rtnl, ifindex, &local);
184 for (i = 0; i < n; i++) {
185 _cleanup_free_ char *pretty = NULL;
187 r = in_addr_to_string(local[i].family, &local[i].address, &pretty);
192 (int) strlen(prefix),
193 i == 0 ? prefix : "",
200 static void dump_list(const char *prefix, char **l) {
205 (int) strlen(prefix),
206 i == l ? prefix : "",
211 static int link_status(char **args, unsigned n) {
212 _cleanup_udev_unref_ struct udev *udev = NULL;
213 _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
218 _cleanup_free_ char *operational_state = NULL;
219 _cleanup_strv_free_ char **dns = NULL, **ntp = NULL;
221 sd_network_get_operational_state(&operational_state);
222 if (operational_state)
223 printf(" State: %s\n", operational_state);
225 sd_network_get_dns(&dns);
226 if (!strv_isempty(dns))
227 dump_list(" DNS: ", dns);
229 sd_network_get_dns(&ntp);
230 if (!strv_isempty(ntp))
231 dump_list(" NTP: ", ntp);
236 pager_open_if_enabled();
238 r = sd_rtnl_open(&rtnl, 0);
240 log_error("Failed to connect to netlink: %s", strerror(-r));
246 log_error("Failed to connect to udev: %m");
250 STRV_FOREACH(name, args + 1) {
251 _cleanup_strv_free_ char **dns = NULL, **ntp = NULL;
252 _cleanup_free_ char *state = NULL, *operational_state = NULL;
253 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
254 _cleanup_udev_device_unref_ struct udev_device *d = NULL;
255 const char *canonical_name = NULL;
256 char devid[2 + DECIMAL_STR_MAX(int)];
257 int ifindex, canonical_ifindex;
258 _cleanup_free_ char *t = NULL;
259 const char *driver = NULL, *path = NULL, *vendor = NULL, *model = NULL;
268 if (safe_atoi(*name, &ifindex) >= 0 && ifindex > 0)
269 r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, ifindex);
271 r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, 0);
273 return rtnl_log_create_error(r);
275 r = sd_rtnl_message_append_string(req, IFLA_IFNAME, *name);
279 return rtnl_log_create_error(r);
281 r = sd_rtnl_call(rtnl, req, 0, &reply);
283 log_error("Failed to query link: %s", strerror(-r));
287 r = sd_rtnl_message_link_get_ifindex(reply, &canonical_ifindex);
289 return rtnl_log_parse_error(r);
291 r = sd_rtnl_message_read_string(reply, IFLA_IFNAME, &canonical_name);
293 return rtnl_log_parse_error(r);
295 r = sd_rtnl_message_link_get_type(reply, &iftype);
297 return rtnl_log_parse_error(r);
299 have_mac = sd_rtnl_message_read_ether_addr(reply, IFLA_ADDRESS, &e) >= 0;
303 bool all_zeroes = true;
305 for (p = (uint8_t*) &e; p < (uint8_t*) &e + sizeof(e); p++)
315 sd_rtnl_message_read_u32(reply, IFLA_MTU, &mtu);
317 sd_network_get_link_state(canonical_ifindex, &state);
318 sd_network_get_link_operational_state(canonical_ifindex, &operational_state);
320 sd_network_get_link_dns(canonical_ifindex, &dns);
321 sd_network_get_link_ntp(canonical_ifindex, &ntp);
323 sprintf(devid, "n%i", canonical_ifindex);
324 d = udev_device_new_from_device_id(udev, devid);
326 link_get_type_string(iftype, d, &t);
329 driver = udev_device_get_property_value(d, "ID_NET_DRIVER");
330 path = udev_device_get_property_value(d, "ID_PATH");
332 vendor = udev_device_get_property_value(d, "ID_VENDOR_FROM_DATABASE");
334 vendor = udev_device_get_property_value(d, "ID_VENDOR");
336 model = udev_device_get_property_value(d, "ID_MODEL_FROM_DATABASE");
338 model = udev_device_get_property_value(d, "ID_MODEL");
341 printf("%i: %s\n", canonical_ifindex, canonical_name);
346 strna(operational_state),
350 printf(" Path: %s\n", path);
352 printf(" Driver: %s\n", driver);
354 printf(" Vendor: %s\n", vendor);
356 printf(" Model: %s\n", model);
359 _cleanup_free_ char *h = NULL;
361 h = hexmem(&e, sizeof(e));
365 printf(" HW Address: %s\n", h);
369 printf(" MTU: %u\n", mtu);
371 dump_addresses(rtnl, " Address: ", canonical_ifindex);
373 if (!strv_isempty(dns))
374 dump_list(" DNS: ", dns);
375 if (!strv_isempty(ntp))
376 dump_list(" NTP: ", ntp);
382 static void help(void) {
383 printf("%s [OPTIONS...]\n\n"
384 "Query and control the networking subsystem.\n\n"
385 " -h --help Show this help\n"
386 " --version Show package version\n\n"
389 " status LINK Show link status\n"
390 , program_invocation_short_name);
393 static int parse_argv(int argc, char *argv[]) {
401 static const struct option options[] = {
402 { "help", no_argument, NULL, 'h' },
403 { "version", no_argument, NULL, ARG_VERSION },
404 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
405 { "no-legend", no_argument, NULL, ARG_NO_LEGEND },
414 while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) {
423 puts(PACKAGE_STRING);
424 puts(SYSTEMD_FEATURES);
439 assert_not_reached("Unhandled option");
446 static int networkctl_main(int argc, char *argv[]) {
448 static const struct {
456 int (* const dispatch)(char **args, unsigned n);
458 { "list", LESS, 1, list_links },
459 { "status", MORE, 1, link_status },
468 left = argc - optind;
471 /* Special rule: no arguments means "list" */
474 if (streq(argv[optind], "help")) {
479 for (i = 0; i < ELEMENTSOF(verbs); i++)
480 if (streq(argv[optind], verbs[i].verb))
483 if (i >= ELEMENTSOF(verbs)) {
484 log_error("Unknown operation %s", argv[optind]);
489 switch (verbs[i].argc_cmp) {
492 if (left != verbs[i].argc) {
493 log_error("Invalid number of arguments.");
500 if (left < verbs[i].argc) {
501 log_error("Too few arguments.");
508 if (left > verbs[i].argc) {
509 log_error("Too many arguments.");
516 assert_not_reached("Unknown comparison operator.");
519 return verbs[i].dispatch(argv + optind, left);
522 int main(int argc, char* argv[]) {
525 log_parse_environment();
528 r = parse_argv(argc, argv);
532 r = networkctl_main(argc, argv);
537 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;