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;
220 r = sd_network_get_operational_state(&operational_state);
222 log_error("Failed to get operational state: %s", strerror(-r));
226 printf("State: %s\n", operational_state);
230 pager_open_if_enabled();
232 r = sd_rtnl_open(&rtnl, 0);
234 log_error("Failed to connect to netlink: %s", strerror(-r));
240 log_error("Failed to connect to udev: %m");
244 STRV_FOREACH(name, args + 1) {
245 _cleanup_strv_free_ char **dns = NULL, **ntp = NULL;
246 _cleanup_free_ char *state = NULL, *operational_state = NULL;
247 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
248 _cleanup_udev_device_unref_ struct udev_device *d = NULL;
249 const char *canonical_name = NULL;
250 char devid[2 + DECIMAL_STR_MAX(int)];
251 int ifindex, canonical_ifindex;
252 _cleanup_free_ char *t = NULL;
253 const char *driver = NULL, *path = NULL, *vendor = NULL, *model = NULL;
262 if (safe_atoi(*name, &ifindex) >= 0 && ifindex > 0)
263 r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, ifindex);
265 r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, 0);
267 return rtnl_log_create_error(r);
269 r = sd_rtnl_message_append_string(req, IFLA_IFNAME, *name);
273 return rtnl_log_create_error(r);
275 r = sd_rtnl_call(rtnl, req, 0, &reply);
277 log_error("Failed to query link: %s", strerror(-r));
281 r = sd_rtnl_message_link_get_ifindex(reply, &canonical_ifindex);
283 return rtnl_log_parse_error(r);
285 r = sd_rtnl_message_read_string(reply, IFLA_IFNAME, &canonical_name);
287 return rtnl_log_parse_error(r);
289 r = sd_rtnl_message_link_get_type(reply, &iftype);
291 return rtnl_log_parse_error(r);
293 have_mac = sd_rtnl_message_read_ether_addr(reply, IFLA_ADDRESS, &e) >= 0;
297 bool all_zeroes = true;
299 for (p = (uint8_t*) &e; p < (uint8_t*) &e + sizeof(e); p++)
309 sd_rtnl_message_read_u32(reply, IFLA_MTU, &mtu);
311 sd_network_get_link_state(canonical_ifindex, &state);
312 sd_network_get_link_operational_state(canonical_ifindex, &operational_state);
314 sd_network_get_link_dns(canonical_ifindex, &dns);
315 sd_network_get_link_dns(canonical_ifindex, &ntp);
317 sprintf(devid, "n%i", canonical_ifindex);
318 d = udev_device_new_from_device_id(udev, devid);
320 link_get_type_string(iftype, d, &t);
323 driver = udev_device_get_property_value(d, "ID_NET_DRIVER");
324 path = udev_device_get_property_value(d, "ID_PATH");
326 vendor = udev_device_get_property_value(d, "ID_VENDOR_FROM_DATABASE");
328 vendor = udev_device_get_property_value(d, "ID_VENDOR");
330 model = udev_device_get_property_value(d, "ID_MODEL_FROM_DATABASE");
332 model = udev_device_get_property_value(d, "ID_MODEL");
335 printf("%i: %s\n", canonical_ifindex, canonical_name);
340 strna(operational_state),
344 printf(" Path: %s\n", path);
346 printf(" Driver: %s\n", driver);
348 printf(" Vendor: %s\n", vendor);
350 printf(" Model: %s\n", model);
353 _cleanup_free_ char *h = NULL;
355 h = hexmem(&e, sizeof(e));
359 printf(" HW Address: %s\n", h);
363 printf(" MTU: %u\n", mtu);
365 dump_addresses(rtnl, " Address: ", canonical_ifindex);
367 if (!strv_isempty(dns))
368 dump_list(" DNS: ", dns);
369 if (!strv_isempty(ntp))
370 dump_list(" NTP: ", ntp);
376 static void help(void) {
377 printf("%s [OPTIONS...]\n\n"
378 "Query and control the networking subsystem.\n\n"
379 " -h --help Show this help\n"
380 " --version Show package version\n\n"
383 " status LINK Show link status\n"
384 , program_invocation_short_name);
387 static int parse_argv(int argc, char *argv[]) {
395 static const struct option options[] = {
396 { "help", no_argument, NULL, 'h' },
397 { "version", no_argument, NULL, ARG_VERSION },
398 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
399 { "no-legend", no_argument, NULL, ARG_NO_LEGEND },
408 while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) {
417 puts(PACKAGE_STRING);
418 puts(SYSTEMD_FEATURES);
433 assert_not_reached("Unhandled option");
440 static int networkctl_main(int argc, char *argv[]) {
442 static const struct {
450 int (* const dispatch)(char **args, unsigned n);
452 { "list", LESS, 1, list_links },
453 { "status", MORE, 1, link_status },
462 left = argc - optind;
465 /* Special rule: no arguments means "list" */
468 if (streq(argv[optind], "help")) {
473 for (i = 0; i < ELEMENTSOF(verbs); i++)
474 if (streq(argv[optind], verbs[i].verb))
477 if (i >= ELEMENTSOF(verbs)) {
478 log_error("Unknown operation %s", argv[optind]);
483 switch (verbs[i].argc_cmp) {
486 if (left != verbs[i].argc) {
487 log_error("Invalid number of arguments.");
494 if (left < verbs[i].argc) {
495 log_error("Too few arguments.");
502 if (left > verbs[i].argc) {
503 log_error("Too many arguments.");
510 assert_not_reached("Unknown comparison operator.");
513 return verbs[i].dispatch(argv + optind, left);
516 int main(int argc, char* argv[]) {
519 log_parse_environment();
522 r = parse_argv(argc, argv);
526 r = networkctl_main(argc, argv);
531 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;