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 typedef struct LinkInfo {
97 static int link_info_compare(const void *a, const void *b) {
98 const LinkInfo *x = a, *y = b;
100 return x->ifindex - y->ifindex;
103 static int decode_and_sort_links(sd_rtnl_message *m, LinkInfo **ret) {
104 _cleanup_free_ LinkInfo *links = NULL;
105 size_t size = 0, c = 0;
109 for (i = m; i; i = sd_rtnl_message_next(i)) {
115 r = sd_rtnl_message_get_type(i, &type);
119 if (type != RTM_NEWLINK)
122 r = sd_rtnl_message_link_get_ifindex(i, &ifindex);
126 r = sd_rtnl_message_read_string(i, IFLA_IFNAME, &name);
130 r = sd_rtnl_message_link_get_type(i, &iftype);
134 if (!GREEDY_REALLOC(links, size, c+1))
137 links[c].name = name;
138 links[c].ifindex = ifindex;
139 links[c].iftype = iftype;
143 qsort(links, c, sizeof(LinkInfo), link_info_compare);
151 static void operational_state_to_color(const char *state, const char **on, const char **off) {
155 if (streq_ptr(state, "routable")) {
156 *on = ansi_highlight_green();
157 *off = ansi_highlight_off();
158 } else if (streq_ptr(state, "degraded")) {
159 *on = ansi_highlight_yellow();
160 *off = ansi_highlight_off();
165 static void setup_state_to_color(const char *state, const char **on, const char **off) {
169 if (streq_ptr(state, "configured")) {
170 *on = ansi_highlight_green();
171 *off = ansi_highlight_off();
172 } else if (streq_ptr(state, "configuring")) {
173 *on = ansi_highlight_yellow();
174 *off = ansi_highlight_off();
175 } else if (streq_ptr(state, "failed") || streq_ptr(state, "linger")) {
176 *on = ansi_highlight_red();
177 *off = ansi_highlight_off();
182 static int list_links(char **args, unsigned n) {
183 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
184 _cleanup_udev_unref_ struct udev *udev = NULL;
185 _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
186 _cleanup_free_ LinkInfo *links = NULL;
189 pager_open_if_enabled();
191 r = sd_rtnl_open(&rtnl, 0);
193 log_error("Failed to connect to netlink: %s", strerror(-r));
199 log_error("Failed to connect to udev: %m");
203 r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, 0);
205 return rtnl_log_create_error(r);
207 r = sd_rtnl_message_request_dump(req, true);
209 return rtnl_log_create_error(r);
211 r = sd_rtnl_call(rtnl, req, 0, &reply);
213 log_error("Failed to enumerate links: %s", strerror(-r));
218 printf("%3s %-16s %-10s %-11s %-10s\n", "IDX", "LINK", "TYPE", "OPERATIONAL", "SETUP");
220 c = decode_and_sort_links(reply, &links);
222 return rtnl_log_parse_error(c);
224 for (i = 0; i < c; i++) {
225 _cleanup_free_ char *setup_state = NULL, *operational_state = NULL;
226 _cleanup_udev_device_unref_ struct udev_device *d = NULL;
227 const char *on_color_operational, *off_color_operational,
228 *on_color_setup, *off_color_setup;
229 char devid[2 + DECIMAL_STR_MAX(int)];
230 _cleanup_free_ char *t = NULL;
232 sd_network_link_get_operational_state(links[i].ifindex, &operational_state);
233 operational_state_to_color(operational_state, &on_color_operational, &off_color_operational);
235 sd_network_link_get_setup_state(links[i].ifindex, &setup_state);
236 setup_state_to_color(setup_state, &on_color_setup, &off_color_setup);
238 sprintf(devid, "n%i", links[i].ifindex);
239 d = udev_device_new_from_device_id(udev, devid);
241 link_get_type_string(links[i].iftype, d, &t);
243 printf("%3i %-16s %-10s %s%-11s%s %s%-10s%s\n",
244 links[i].ifindex, links[i].name, strna(t),
245 on_color_operational, strna(operational_state), off_color_operational,
246 on_color_setup, strna(setup_state), off_color_setup);
250 printf("\n%i links listed.\n", c);
255 static int dump_addresses(sd_rtnl *rtnl, const char *prefix, int ifindex) {
256 _cleanup_free_ struct local_address *local = NULL;
259 n = local_addresses(rtnl, ifindex, &local);
263 for (i = 0; i < n; i++) {
264 _cleanup_free_ char *pretty = NULL;
266 r = in_addr_to_string(local[i].family, &local[i].address, &pretty);
271 (int) strlen(prefix),
272 i == 0 ? prefix : "",
279 static void dump_list(const char *prefix, char **l) {
284 (int) strlen(prefix),
285 i == l ? prefix : "",
290 static int link_status_one(sd_rtnl *rtnl, struct udev *udev, const char *name) {
291 _cleanup_strv_free_ char **dns = NULL, **ntp = NULL, **domains = NULL;
292 _cleanup_free_ char *setup_state = NULL, *operational_state = NULL;
293 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
294 _cleanup_udev_device_unref_ struct udev_device *d = NULL;
295 char devid[2 + DECIMAL_STR_MAX(int)];
296 _cleanup_free_ char *t = NULL;
297 const char *driver = NULL, *path = NULL, *vendor = NULL, *model = NULL;
298 const char *on_color_operational, *off_color_operational,
299 *on_color_setup, *off_color_setup;
310 if (safe_atoi(name, &ifindex) >= 0 && ifindex > 0)
311 r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, ifindex);
313 r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, 0);
315 return rtnl_log_create_error(r);
317 r = sd_rtnl_message_append_string(req, IFLA_IFNAME, name);
321 return rtnl_log_create_error(r);
323 r = sd_rtnl_call(rtnl, req, 0, &reply);
325 log_error("Failed to query link: %s", strerror(-r));
329 r = sd_rtnl_message_link_get_ifindex(reply, &ifindex);
331 return rtnl_log_parse_error(r);
333 r = sd_rtnl_message_read_string(reply, IFLA_IFNAME, &name);
335 return rtnl_log_parse_error(r);
337 r = sd_rtnl_message_link_get_type(reply, &iftype);
339 return rtnl_log_parse_error(r);
341 have_mac = sd_rtnl_message_read_ether_addr(reply, IFLA_ADDRESS, &e) >= 0;
345 bool all_zeroes = true;
347 for (p = (uint8_t*) &e; p < (uint8_t*) &e + sizeof(e); p++)
357 sd_rtnl_message_read_u32(reply, IFLA_MTU, &mtu);
359 sd_network_link_get_operational_state(ifindex, &operational_state);
360 operational_state_to_color(operational_state, &on_color_operational, &off_color_operational);
362 sd_network_link_get_setup_state(ifindex, &setup_state);
363 setup_state_to_color(setup_state, &on_color_setup, &off_color_setup);
365 sd_network_link_get_dns(ifindex, &dns);
366 sd_network_link_get_ntp(ifindex, &ntp);
367 sd_network_link_get_domains(ifindex, &domains);
369 sprintf(devid, "n%i", ifindex);
370 d = udev_device_new_from_device_id(udev, devid);
372 link_get_type_string(iftype, d, &t);
375 driver = udev_device_get_property_value(d, "ID_NET_DRIVER");
376 path = udev_device_get_property_value(d, "ID_PATH");
378 vendor = udev_device_get_property_value(d, "ID_VENDOR_FROM_DATABASE");
380 vendor = udev_device_get_property_value(d, "ID_VENDOR");
382 model = udev_device_get_property_value(d, "ID_MODEL_FROM_DATABASE");
384 model = udev_device_get_property_value(d, "ID_MODEL");
388 printf("%s%s%s %i: %s\n", on_color_operational, draw_special_char(DRAW_BLACK_CIRCLE), off_color_operational, ifindex, name);
391 " State: %s%s%s (%s%s%s)\n",
393 on_color_operational, strna(operational_state), off_color_operational,
394 on_color_setup, strna(setup_state), off_color_setup);
397 printf(" Path: %s\n", path);
399 printf(" Driver: %s\n", driver);
401 printf(" Vendor: %s\n", vendor);
403 printf(" Model: %s\n", model);
406 printf(" HW Address: %s\n", ether_ntoa(&e));
409 printf(" MTU: %u\n", mtu);
411 dump_addresses(rtnl, " Address: ", ifindex);
413 if (!strv_isempty(dns))
414 dump_list(" DNS: ", dns);
415 if (!strv_isempty(domains))
416 dump_list(" Domains: ", domains);
417 if (!strv_isempty(ntp))
418 dump_list(" NTP: ", ntp);
423 static int link_status(char **args, unsigned n) {
424 _cleanup_udev_unref_ struct udev *udev = NULL;
425 _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
429 r = sd_rtnl_open(&rtnl, 0);
431 log_error("Failed to connect to netlink: %s", strerror(-r));
437 log_error("Failed to connect to udev: %m");
441 if (n <= 1 && !arg_all) {
442 _cleanup_free_ char *operational_state = NULL;
443 _cleanup_strv_free_ char **dns = NULL, **ntp = NULL;
444 _cleanup_free_ struct local_address *addresses = NULL;
445 const char *on_color_operational, *off_color_operational;
448 sd_network_get_operational_state(&operational_state);
449 operational_state_to_color(operational_state, &on_color_operational, &off_color_operational);
451 printf(" State: %s%s%s\n", on_color_operational, strna(operational_state), off_color_operational);
453 c = local_addresses(rtnl, 0, &addresses);
454 for (i = 0; i < c; i++) {
455 _cleanup_free_ char *pretty = NULL;
457 r = in_addr_to_string(addresses[i].family, &addresses[i].address, &pretty);
462 i > 0 ? "" : "Address:", pretty);
465 sd_network_get_dns(&dns);
466 if (!strv_isempty(dns))
467 dump_list(" DNS: ", dns);
469 sd_network_get_dns(&ntp);
470 if (!strv_isempty(ntp))
471 dump_list(" NTP: ", ntp);
476 pager_open_if_enabled();
479 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
480 _cleanup_free_ LinkInfo *links = NULL;
483 r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, 0);
485 return rtnl_log_create_error(r);
487 r = sd_rtnl_message_request_dump(req, true);
489 return rtnl_log_create_error(r);
491 r = sd_rtnl_call(rtnl, req, 0, &reply);
493 log_error("Failed to enumerate links: %s", strerror(-r));
497 c = decode_and_sort_links(reply, &links);
499 return rtnl_log_parse_error(c);
501 for (i = 0; i < c; i++) {
505 link_status_one(rtnl, udev, links[i].name);
509 STRV_FOREACH(name, args + 1) {
513 link_status_one(rtnl, udev, *name);
519 static void help(void) {
520 printf("%s [OPTIONS...]\n\n"
521 "Query and control the networking subsystem.\n\n"
522 " -h --help Show this help\n"
523 " --version Show package version\n"
524 " --no-pager Do not pipe output into a pager\n"
525 " --no-legend Do not show the headers and footers\n"
526 " -a --all Show status for all links\n\n"
529 " status LINK Show link status\n"
530 , program_invocation_short_name);
533 static int parse_argv(int argc, char *argv[]) {
541 static const struct option options[] = {
542 { "help", no_argument, NULL, 'h' },
543 { "version", no_argument, NULL, ARG_VERSION },
544 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
545 { "no-legend", no_argument, NULL, ARG_NO_LEGEND },
546 { "all", no_argument, NULL, 'a' },
555 while ((c = getopt_long(argc, argv, "ha", options, NULL)) >= 0) {
564 puts(PACKAGE_STRING);
565 puts(SYSTEMD_FEATURES);
584 assert_not_reached("Unhandled option");
591 static int networkctl_main(int argc, char *argv[]) {
593 static const struct {
601 int (* const dispatch)(char **args, unsigned n);
603 { "list", LESS, 1, list_links },
604 { "status", MORE, 1, link_status },
613 left = argc - optind;
616 /* Special rule: no arguments means "list" */
619 if (streq(argv[optind], "help")) {
624 for (i = 0; i < ELEMENTSOF(verbs); i++)
625 if (streq(argv[optind], verbs[i].verb))
628 if (i >= ELEMENTSOF(verbs)) {
629 log_error("Unknown operation %s", argv[optind]);
634 switch (verbs[i].argc_cmp) {
637 if (left != verbs[i].argc) {
638 log_error("Invalid number of arguments.");
645 if (left < verbs[i].argc) {
646 log_error("Too few arguments.");
653 if (left > verbs[i].argc) {
654 log_error("Too many arguments.");
661 assert_not_reached("Unknown comparison operator.");
664 return verbs[i].dispatch(argv + optind, left);
667 int main(int argc, char* argv[]) {
670 log_parse_environment();
673 r = parse_argv(argc, argv);
677 r = networkctl_main(argc, argv);
682 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;