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;
39 static bool arg_all = false;
41 static void pager_open_if_enabled(void) {
49 static int link_get_type_string(int iftype, struct udev_device *d, char **ret) {
53 if (iftype == ARPHRD_ETHER && d) {
54 const char *devtype, *id = NULL;
55 /* WLANs have iftype ARPHRD_ETHER, but we want
56 * to show a more useful type string for
59 devtype = udev_device_get_devtype(d);
60 if (streq_ptr(devtype, "wlan"))
62 else if (streq_ptr(devtype, "wwan"))
75 t = arphrd_to_name(iftype);
91 static int list_links(char **args, unsigned n) {
92 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
93 _cleanup_udev_unref_ struct udev *udev = NULL;
94 _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
99 pager_open_if_enabled();
101 r = sd_rtnl_open(&rtnl, 0);
103 log_error("Failed to connect to netlink: %s", strerror(-r));
109 log_error("Failed to connect to udev: %m");
113 r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, 0);
115 return rtnl_log_create_error(r);
117 r = sd_rtnl_message_request_dump(req, true);
119 return rtnl_log_create_error(r);
121 r = sd_rtnl_call(rtnl, req, 0, &reply);
123 log_error("Failed to enumerate links: %s", strerror(-r));
128 printf("%3s %-16s %-10s %-10s %-10s\n", "IDX", "LINK", "TYPE", "STATE", "OPERATIONAL");
130 for (i = reply; i; i = sd_rtnl_message_next(i)) {
131 _cleanup_free_ char *state = NULL, *operational_state = NULL;
132 _cleanup_udev_device_unref_ struct udev_device *d = NULL;
133 char devid[2 + DECIMAL_STR_MAX(int)];
134 _cleanup_free_ char *t = NULL;
140 r = sd_rtnl_message_get_type(i, &type);
142 return rtnl_log_parse_error(r);
144 if (type != RTM_NEWLINK)
147 r = sd_rtnl_message_link_get_ifindex(i, &ifindex);
149 return rtnl_log_parse_error(r);
151 r = sd_rtnl_message_read_string(i, IFLA_IFNAME, &name);
153 return rtnl_log_parse_error(r);
155 r = sd_rtnl_message_link_get_type(i, &iftype);
157 return rtnl_log_parse_error(r);
159 sd_network_get_link_state(ifindex, &state);
160 sd_network_get_link_operational_state(ifindex, &operational_state);
162 sprintf(devid, "n%i", ifindex);
163 d = udev_device_new_from_device_id(udev, devid);
165 link_get_type_string(iftype, d, &t);
167 printf("%3i %-16s %-10s %-10s %-10s\n", ifindex, name, strna(t), strna(state), strna(operational_state));
172 printf("\n%u links listed.\n", c);
177 static int dump_addresses(sd_rtnl *rtnl, const char *prefix, int ifindex) {
178 _cleanup_free_ struct local_address *local = NULL;
181 n = local_addresses(rtnl, ifindex, &local);
185 for (i = 0; i < n; i++) {
186 _cleanup_free_ char *pretty = NULL;
188 r = in_addr_to_string(local[i].family, &local[i].address, &pretty);
193 (int) strlen(prefix),
194 i == 0 ? prefix : "",
201 static void dump_list(const char *prefix, char **l) {
206 (int) strlen(prefix),
207 i == l ? prefix : "",
212 static int link_status_one(sd_rtnl *rtnl, struct udev *udev, const char *name) {
213 _cleanup_strv_free_ char **dns = NULL, **ntp = NULL;
214 _cleanup_free_ char *state = NULL, *operational_state = NULL;
215 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
216 _cleanup_udev_device_unref_ struct udev_device *d = NULL;
217 char devid[2 + DECIMAL_STR_MAX(int)];
218 _cleanup_free_ char *t = NULL;
219 const char *driver = NULL, *path = NULL, *vendor = NULL, *model = NULL;
230 if (safe_atoi(name, &ifindex) >= 0 && ifindex > 0)
231 r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, ifindex);
233 r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, 0);
235 return rtnl_log_create_error(r);
237 r = sd_rtnl_message_append_string(req, IFLA_IFNAME, name);
241 return rtnl_log_create_error(r);
243 r = sd_rtnl_call(rtnl, req, 0, &reply);
245 log_error("Failed to query link: %s", strerror(-r));
249 r = sd_rtnl_message_link_get_ifindex(reply, &ifindex);
251 return rtnl_log_parse_error(r);
253 r = sd_rtnl_message_read_string(reply, IFLA_IFNAME, &name);
255 return rtnl_log_parse_error(r);
257 r = sd_rtnl_message_link_get_type(reply, &iftype);
259 return rtnl_log_parse_error(r);
261 have_mac = sd_rtnl_message_read_ether_addr(reply, IFLA_ADDRESS, &e) >= 0;
265 bool all_zeroes = true;
267 for (p = (uint8_t*) &e; p < (uint8_t*) &e + sizeof(e); p++)
277 sd_rtnl_message_read_u32(reply, IFLA_MTU, &mtu);
279 sd_network_get_link_state(ifindex, &state);
280 sd_network_get_link_operational_state(ifindex, &operational_state);
282 sd_network_get_link_dns(ifindex, &dns);
283 sd_network_get_link_ntp(ifindex, &ntp);
285 sprintf(devid, "n%i", ifindex);
286 d = udev_device_new_from_device_id(udev, devid);
288 link_get_type_string(iftype, d, &t);
291 driver = udev_device_get_property_value(d, "ID_NET_DRIVER");
292 path = udev_device_get_property_value(d, "ID_PATH");
294 vendor = udev_device_get_property_value(d, "ID_VENDOR_FROM_DATABASE");
296 vendor = udev_device_get_property_value(d, "ID_VENDOR");
298 model = udev_device_get_property_value(d, "ID_MODEL_FROM_DATABASE");
300 model = udev_device_get_property_value(d, "ID_MODEL");
303 printf("%i: %s\n", ifindex, name);
308 strna(operational_state),
312 printf(" Path: %s\n", path);
314 printf(" Driver: %s\n", driver);
316 printf(" Vendor: %s\n", vendor);
318 printf(" Model: %s\n", model);
321 printf(" HW Address: %s\n", ether_ntoa(&e));
324 printf(" MTU: %u\n", mtu);
326 dump_addresses(rtnl, " Address: ", ifindex);
328 if (!strv_isempty(dns))
329 dump_list(" DNS: ", dns);
330 if (!strv_isempty(ntp))
331 dump_list(" NTP: ", ntp);
336 static int link_status(char **args, unsigned n) {
337 _cleanup_udev_unref_ struct udev *udev = NULL;
338 _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
342 if (n <= 1 && !arg_all) {
343 _cleanup_free_ char *operational_state = NULL;
344 _cleanup_strv_free_ char **dns = NULL, **ntp = NULL;
346 sd_network_get_operational_state(&operational_state);
347 if (operational_state)
348 printf(" State: %s\n", operational_state);
350 sd_network_get_dns(&dns);
351 if (!strv_isempty(dns))
352 dump_list(" DNS: ", dns);
354 sd_network_get_dns(&ntp);
355 if (!strv_isempty(ntp))
356 dump_list(" NTP: ", ntp);
361 pager_open_if_enabled();
363 r = sd_rtnl_open(&rtnl, 0);
365 log_error("Failed to connect to netlink: %s", strerror(-r));
371 log_error("Failed to connect to udev: %m");
376 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
381 r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, 0);
383 return rtnl_log_create_error(r);
385 r = sd_rtnl_message_request_dump(req, true);
387 return rtnl_log_create_error(r);
389 r = sd_rtnl_call(rtnl, req, 0, &reply);
391 log_error("Failed to enumerate links: %s", strerror(-r));
395 for (i = reply; i; i = sd_rtnl_message_next(i)) {
398 r = sd_rtnl_message_get_type(i, &type);
400 return rtnl_log_parse_error(r);
402 if (type != RTM_NEWLINK)
405 r = sd_rtnl_message_read_string(i, IFLA_IFNAME, &nn);
407 return rtnl_log_parse_error(r);
412 link_status_one(rtnl, udev, nn);
417 STRV_FOREACH(name, args + 1) {
421 link_status_one(rtnl, udev, *name);
427 static void help(void) {
428 printf("%s [OPTIONS...]\n\n"
429 "Query and control the networking subsystem.\n\n"
430 " -h --help Show this help\n"
431 " --version Show package version\n"
432 " --no-pager Do not pipe output into a pager\n"
433 " --no-legend Do not show the headers and footers\n"
434 " -a --all Show status for all links\n\n"
437 " status LINK Show link status\n"
438 , program_invocation_short_name);
441 static int parse_argv(int argc, char *argv[]) {
449 static const struct option options[] = {
450 { "help", no_argument, NULL, 'h' },
451 { "version", no_argument, NULL, ARG_VERSION },
452 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
453 { "no-legend", no_argument, NULL, ARG_NO_LEGEND },
454 { "all", no_argument, NULL, 'a' },
463 while ((c = getopt_long(argc, argv, "ha", options, NULL)) >= 0) {
472 puts(PACKAGE_STRING);
473 puts(SYSTEMD_FEATURES);
492 assert_not_reached("Unhandled option");
499 static int networkctl_main(int argc, char *argv[]) {
501 static const struct {
509 int (* const dispatch)(char **args, unsigned n);
511 { "list", LESS, 1, list_links },
512 { "status", MORE, 1, link_status },
521 left = argc - optind;
524 /* Special rule: no arguments means "list" */
527 if (streq(argv[optind], "help")) {
532 for (i = 0; i < ELEMENTSOF(verbs); i++)
533 if (streq(argv[optind], verbs[i].verb))
536 if (i >= ELEMENTSOF(verbs)) {
537 log_error("Unknown operation %s", argv[optind]);
542 switch (verbs[i].argc_cmp) {
545 if (left != verbs[i].argc) {
546 log_error("Invalid number of arguments.");
553 if (left < verbs[i].argc) {
554 log_error("Too few arguments.");
561 if (left > verbs[i].argc) {
562 log_error("Too many arguments.");
569 assert_not_reached("Unknown comparison operator.");
572 return verbs[i].dispatch(argv + optind, left);
575 int main(int argc, char* argv[]) {
578 log_parse_environment();
581 r = parse_argv(argc, argv);
585 r = networkctl_main(argc, argv);
590 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;