chiark / gitweb /
rtnl: when querying local addresses and gateways, take address family into account
[elogind.git] / src / network / networkctl.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2014 Lennart Poettering
7
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.
12
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.
17
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/>.
20 ***/
21
22 #include <stdbool.h>
23 #include <getopt.h>
24
25 #include "sd-network.h"
26 #include "sd-rtnl.h"
27 #include "libudev.h"
28
29 #include "build.h"
30 #include "util.h"
31 #include "pager.h"
32 #include "rtnl-util.h"
33 #include "udev-util.h"
34 #include "arphrd-list.h"
35 #include "local-addresses.h"
36 #include "socket-util.h"
37 #include "ether-addr-util.h"
38
39 static bool arg_no_pager = false;
40 static bool arg_legend = true;
41 static bool arg_all = false;
42
43 static void pager_open_if_enabled(void) {
44
45         if (arg_no_pager)
46                 return;
47
48         pager_open(false);
49 }
50
51 static int link_get_type_string(int iftype, struct udev_device *d, char **ret) {
52         const char *t;
53         char *p;
54
55         if (iftype == ARPHRD_ETHER && d) {
56                 const char *devtype, *id = NULL;
57                 /* WLANs have iftype ARPHRD_ETHER, but we want
58                  * to show a more useful type string for
59                  * them */
60
61                 devtype = udev_device_get_devtype(d);
62                 if (streq_ptr(devtype, "wlan"))
63                         id = "wlan";
64                 else if (streq_ptr(devtype, "wwan"))
65                         id = "wwan";
66
67                 if (id) {
68                         p = strdup(id);
69                         if (!p)
70                                 return -ENOMEM;
71
72                         *ret = p;
73                         return 1;
74                 }
75         }
76
77         t = arphrd_to_name(iftype);
78         if (!t) {
79                 *ret = NULL;
80                 return 0;
81         }
82
83         p = strdup(t);
84         if (!p)
85                 return -ENOMEM;
86
87         ascii_strlower(p);
88         *ret = p;
89
90         return 0;
91 }
92
93 typedef struct LinkInfo {
94         const char *name;
95         int ifindex;
96         unsigned iftype;
97 } LinkInfo;
98
99 static int link_info_compare(const void *a, const void *b) {
100         const LinkInfo *x = a, *y = b;
101
102         return x->ifindex - y->ifindex;
103 }
104
105 static int decode_and_sort_links(sd_rtnl_message *m, LinkInfo **ret) {
106         _cleanup_free_ LinkInfo *links = NULL;
107         size_t size = 0, c = 0;
108         sd_rtnl_message *i;
109         int r;
110
111         for (i = m; i; i = sd_rtnl_message_next(i)) {
112                 const char *name;
113                 unsigned iftype;
114                 uint16_t type;
115                 int ifindex;
116
117                 r = sd_rtnl_message_get_type(i, &type);
118                 if (r < 0)
119                         return r;
120
121                 if (type != RTM_NEWLINK)
122                         continue;
123
124                 r = sd_rtnl_message_link_get_ifindex(i, &ifindex);
125                 if (r < 0)
126                         return r;
127
128                 r = sd_rtnl_message_read_string(i, IFLA_IFNAME, &name);
129                 if (r < 0)
130                         return r;
131
132                 r = sd_rtnl_message_link_get_type(i, &iftype);
133                 if (r < 0)
134                         return r;
135
136                 if (!GREEDY_REALLOC(links, size, c+1))
137                         return -ENOMEM;
138
139                 links[c].name = name;
140                 links[c].ifindex = ifindex;
141                 links[c].iftype = iftype;
142                 c++;
143         }
144
145         qsort_safe(links, c, sizeof(LinkInfo), link_info_compare);
146
147         *ret = links;
148         links = NULL;
149
150         return (int) c;
151 }
152
153 static void operational_state_to_color(const char *state, const char **on, const char **off) {
154         assert(on);
155         assert(off);
156
157         if (streq_ptr(state, "routable")) {
158                 *on = ansi_highlight_green();
159                 *off = ansi_highlight_off();
160         } else if (streq_ptr(state, "degraded")) {
161                 *on = ansi_highlight_yellow();
162                 *off = ansi_highlight_off();
163         } else
164                 *on = *off = "";
165 }
166
167 static void setup_state_to_color(const char *state, const char **on, const char **off) {
168         assert(on);
169         assert(off);
170
171         if (streq_ptr(state, "configured")) {
172                 *on = ansi_highlight_green();
173                 *off = ansi_highlight_off();
174         } else if (streq_ptr(state, "configuring")) {
175                 *on = ansi_highlight_yellow();
176                 *off = ansi_highlight_off();
177         } else if (streq_ptr(state, "failed") || streq_ptr(state, "linger")) {
178                 *on = ansi_highlight_red();
179                 *off = ansi_highlight_off();
180         } else
181                 *on = *off = "";
182 }
183
184 static int list_links(char **args, unsigned n) {
185         _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
186         _cleanup_udev_unref_ struct udev *udev = NULL;
187         _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
188         _cleanup_free_ LinkInfo *links = NULL;
189         int r, c, i;
190
191         pager_open_if_enabled();
192
193         r = sd_rtnl_open(&rtnl, 0);
194         if (r < 0)
195                 return log_error_errno(r, "Failed to connect to netlink: %m");
196
197         udev = udev_new();
198         if (!udev)
199                 return log_error_errno(errno, "Failed to connect to udev: %m");
200
201         r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, 0);
202         if (r < 0)
203                 return rtnl_log_create_error(r);
204
205         r = sd_rtnl_message_request_dump(req, true);
206         if (r < 0)
207                 return rtnl_log_create_error(r);
208
209         r = sd_rtnl_call(rtnl, req, 0, &reply);
210         if (r < 0)
211                 return log_error_errno(r, "Failed to enumerate links: %m");
212
213         if (arg_legend)
214                 printf("%3s %-16s %-18s %-11s %-10s\n", "IDX", "LINK", "TYPE", "OPERATIONAL", "SETUP");
215
216         c = decode_and_sort_links(reply, &links);
217         if (c < 0)
218                 return rtnl_log_parse_error(c);
219
220         for (i = 0; i < c; i++) {
221                 _cleanup_free_ char *setup_state = NULL, *operational_state = NULL;
222                 _cleanup_udev_device_unref_ struct udev_device *d = NULL;
223                 const char *on_color_operational, *off_color_operational,
224                            *on_color_setup, *off_color_setup;
225                  char devid[2 + DECIMAL_STR_MAX(int)];
226                 _cleanup_free_ char *t = NULL;
227
228                 sd_network_link_get_operational_state(links[i].ifindex, &operational_state);
229                 operational_state_to_color(operational_state, &on_color_operational, &off_color_operational);
230
231                 sd_network_link_get_setup_state(links[i].ifindex, &setup_state);
232                 setup_state_to_color(setup_state, &on_color_setup, &off_color_setup);
233
234                 sprintf(devid, "n%i", links[i].ifindex);
235                 d = udev_device_new_from_device_id(udev, devid);
236
237                 link_get_type_string(links[i].iftype, d, &t);
238
239                 printf("%3i %-16s %-18s %s%-11s%s %s%-10s%s\n",
240                        links[i].ifindex, links[i].name, strna(t),
241                        on_color_operational, strna(operational_state), off_color_operational,
242                        on_color_setup, strna(setup_state), off_color_setup);
243         }
244
245         if (arg_legend)
246                 printf("\n%i links listed.\n", c);
247
248         return 0;
249 }
250
251 /* IEEE Organizationally Unique Identifier vendor string */
252 static int ieee_oui(struct udev_hwdb *hwdb, struct ether_addr *mac, char **ret) {
253         struct udev_list_entry *entry;
254         char *description;
255         char str[strlen("OUI:XXYYXXYYXXYY") + 1];
256
257         /* skip commonly misused 00:00:00 (Xerox) prefix */
258         if (memcmp(mac, "\0\0\0", 3) == 0)
259                 return -EINVAL;
260
261         snprintf(str, sizeof(str), "OUI:" ETHER_ADDR_FORMAT_STR, ETHER_ADDR_FORMAT_VAL(*mac));
262
263         udev_list_entry_foreach(entry, udev_hwdb_get_properties_list_entry(hwdb, str, 0))
264                 if (strcmp(udev_list_entry_get_name(entry), "ID_OUI_FROM_DATABASE") == 0) {
265                         description = strdup(udev_list_entry_get_value(entry));
266                         if (!description)
267                                 return -ENOMEM;
268
269                         *ret = description;
270                         return 0;
271                 }
272
273         return -ENODATA;
274 }
275
276 static int get_gateway_description(sd_rtnl *rtnl, struct udev_hwdb *hwdb, int ifindex, int family,
277                                    union in_addr_union *gateway, char **gateway_description) {
278         _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
279         sd_rtnl_message *m;
280         int r;
281
282         assert(rtnl);
283         assert(ifindex >= 0);
284         assert(family == AF_INET || family == AF_INET6);
285         assert(gateway);
286         assert(gateway_description);
287
288         r = sd_rtnl_message_new_neigh(rtnl, &req, RTM_GETNEIGH, ifindex, family);
289         if (r < 0)
290                 return r;
291
292         r = sd_rtnl_message_request_dump(req, true);
293         if (r < 0)
294                 return r;
295
296         r = sd_rtnl_call(rtnl, req, 0, &reply);
297         if (r < 0)
298                 return r;
299
300         for (m = reply; m; m = sd_rtnl_message_next(m)) {
301                 union in_addr_union gw = {};
302                 struct ether_addr mac = {};
303                 uint16_t type;
304                 int ifi, fam;
305
306                 r = sd_rtnl_message_get_errno(m);
307                 if (r < 0) {
308                         log_error_errno(r, "got error: %m");
309                         continue;
310                 }
311
312                 r = sd_rtnl_message_get_type(m, &type);
313                 if (r < 0) {
314                         log_error_errno(r, "could not get type: %m");
315                         continue;
316                 }
317
318                 if (type != RTM_NEWNEIGH) {
319                         log_error("type is not RTM_NEWNEIGH");
320                         continue;
321                 }
322
323                 r = sd_rtnl_message_neigh_get_family(m, &fam);
324                 if (r < 0) {
325                         log_error_errno(r, "could not get family: %m");
326                         continue;
327                 }
328
329                 if (fam != family) {
330                         log_error("family is not correct");
331                         continue;
332                 }
333
334                 r = sd_rtnl_message_neigh_get_ifindex(m, &ifi);
335                 if (r < 0) {
336                         log_error_errno(r, "could not get ifindex: %m");
337                         continue;
338                 }
339
340                 if (ifindex > 0 && ifi != ifindex)
341                         continue;
342
343                 switch (fam) {
344                 case AF_INET:
345                         r = sd_rtnl_message_read_in_addr(m, NDA_DST, &gw.in);
346                         if (r < 0)
347                                 continue;
348
349                         break;
350                 case AF_INET6:
351                         r = sd_rtnl_message_read_in6_addr(m, NDA_DST, &gw.in6);
352                         if (r < 0)
353                                 continue;
354
355                         break;
356                 default:
357                         continue;
358                 }
359
360                 if (!in_addr_equal(fam, &gw, gateway))
361                         continue;
362
363                 r = sd_rtnl_message_read_ether_addr(m, NDA_LLADDR, &mac);
364                 if (r < 0)
365                         continue;
366
367                 r = ieee_oui(hwdb, &mac, gateway_description);
368                 if (r < 0)
369                         continue;
370
371                 return 0;
372         }
373
374         return -ENODATA;
375 }
376
377 static int dump_gateways(sd_rtnl *rtnl, struct udev_hwdb *hwdb, const char *prefix, int ifindex) {
378         _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
379         sd_rtnl_message *m;
380         bool first = true;
381         int r;
382
383         assert(rtnl);
384         assert(ifindex >= 0);
385
386         r = sd_rtnl_message_new_route(rtnl, &req, RTM_GETROUTE, AF_UNSPEC, RTPROT_UNSPEC);
387         if (r < 0)
388                 return r;
389
390         r = sd_rtnl_message_request_dump(req, true);
391         if (r < 0)
392                 return r;
393
394         r = sd_rtnl_call(rtnl, req, 0, &reply);
395         if (r < 0)
396                 return r;
397
398         for (m = reply; m; m = sd_rtnl_message_next(m)) {
399                 _cleanup_free_ char *gateway = NULL, *gateway_description = NULL;
400                 union in_addr_union gw = {};
401                 uint16_t type;
402                 uint32_t ifi;
403                 int family;
404
405                 r = sd_rtnl_message_get_errno(m);
406                 if (r < 0) {
407                         log_error_errno(r, "got error: %m");
408                         continue;
409                 }
410
411                 r = sd_rtnl_message_get_type(m, &type);
412                 if (r < 0) {
413                         log_error_errno(r, "could not get type: %m");
414                         continue;
415                 }
416
417                 if (type != RTM_NEWROUTE) {
418                         log_error("type is not RTM_NEWROUTE");
419                         continue;
420                 }
421
422                 r = sd_rtnl_message_route_get_family(m, &family);
423                 if (r < 0) {
424                         log_error_errno(r, "could not get family: %m");
425                         continue;
426                 }
427
428                 r = sd_rtnl_message_read_u32(m, RTA_OIF, &ifi);
429                 if (r < 0) {
430                         log_error_errno(r, "could not get RTA_OIF: %m");
431                         continue;
432                 }
433
434                 if (ifindex > 0 && ifi != (unsigned) ifindex)
435                         continue;
436
437                 switch (family) {
438                 case AF_INET:
439                         r = sd_rtnl_message_read_in_addr(m, RTA_GATEWAY, &gw.in);
440                         if (r < 0)
441                                 continue;
442
443                         r = sd_rtnl_message_read_in_addr(m, RTA_DST, NULL);
444                         if (r >= 0)
445                                 continue;
446
447                         r = sd_rtnl_message_read_in_addr(m, RTA_SRC, NULL);
448                         if (r >= 0)
449                                 continue;
450
451                         break;
452                 case AF_INET6:
453                         r = sd_rtnl_message_read_in6_addr(m, RTA_GATEWAY, &gw.in6);
454                         if (r < 0)
455                                 continue;
456
457                         r = sd_rtnl_message_read_in6_addr(m, RTA_DST, NULL);
458                         if (r >= 0)
459                                 continue;
460
461                         r = sd_rtnl_message_read_in6_addr(m, RTA_SRC, NULL);
462                         if (r >= 0)
463                                 continue;
464
465                         break;
466                 default:
467                         continue;
468                 }
469
470                 r = in_addr_to_string(family, &gw, &gateway);
471                 if (r < 0)
472                         continue;
473
474                 r = get_gateway_description(rtnl, hwdb, ifi, family, &gw, &gateway_description);
475                 if (r < 0)
476                         log_debug("could not get description of gateway: %s", strerror(-r));
477
478                 if (gateway_description)
479                         printf("%*s%s (%s)\n",
480                                (int) strlen(prefix),
481                                first ? prefix : "",
482                                gateway, gateway_description);
483                 else
484                         printf("%*s%s\n",
485                                (int) strlen(prefix),
486                                first ? prefix : "",
487                                gateway);
488
489                 first = false;
490         }
491
492         return 0;
493 }
494
495 static int dump_addresses(sd_rtnl *rtnl, const char *prefix, int ifindex) {
496         _cleanup_free_ struct local_address *local = NULL;
497         int r, n, i;
498
499         n = local_addresses(rtnl, ifindex, AF_UNSPEC, &local);
500         if (n < 0)
501                 return n;
502
503         for (i = 0; i < n; i++) {
504                 _cleanup_free_ char *pretty = NULL;
505
506                 r = in_addr_to_string(local[i].family, &local[i].address, &pretty);
507                 if (r < 0)
508                         return r;
509
510                 printf("%*s%s\n",
511                        (int) strlen(prefix),
512                        i == 0 ? prefix : "",
513                        pretty);
514         }
515
516         return 0;
517 }
518
519 static void dump_list(const char *prefix, char **l) {
520         char **i;
521
522         STRV_FOREACH(i, l) {
523                 printf("%*s%s\n",
524                        (int) strlen(prefix),
525                        i == l ? prefix : "",
526                        *i);
527         }
528 }
529
530 static int link_status_one(sd_rtnl *rtnl, struct udev *udev, const char *name) {
531         _cleanup_strv_free_ char **dns = NULL, **ntp = NULL, **domains = NULL;
532         _cleanup_free_ char *setup_state = NULL, *operational_state = NULL;
533         _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
534         _cleanup_udev_device_unref_ struct udev_device *d = NULL;
535         _cleanup_udev_hwdb_unref_ struct udev_hwdb *hwdb = NULL;
536         char devid[2 + DECIMAL_STR_MAX(int)];
537         _cleanup_free_ char *t = NULL, *network = NULL;
538         const char *driver = NULL, *path = NULL, *vendor = NULL, *model = NULL, *link = NULL;
539         const char *on_color_operational, *off_color_operational,
540                    *on_color_setup, *off_color_setup;
541         struct ether_addr e;
542         unsigned iftype;
543         int r, ifindex;
544         bool have_mac;
545         uint32_t mtu;
546
547         assert(rtnl);
548         assert(udev);
549         assert(name);
550
551         if (safe_atoi(name, &ifindex) >= 0 && ifindex > 0)
552                 r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, ifindex);
553         else {
554                 r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, 0);
555                 if (r < 0)
556                         return rtnl_log_create_error(r);
557
558                 r = sd_rtnl_message_append_string(req, IFLA_IFNAME, name);
559         }
560
561         if (r < 0)
562                 return rtnl_log_create_error(r);
563
564         r = sd_rtnl_call(rtnl, req, 0, &reply);
565         if (r < 0)
566                 return log_error_errno(r, "Failed to query link: %m");
567
568         r = sd_rtnl_message_link_get_ifindex(reply, &ifindex);
569         if (r < 0)
570                 return rtnl_log_parse_error(r);
571
572         r = sd_rtnl_message_read_string(reply, IFLA_IFNAME, &name);
573         if (r < 0)
574                 return rtnl_log_parse_error(r);
575
576         r = sd_rtnl_message_link_get_type(reply, &iftype);
577         if (r < 0)
578                 return rtnl_log_parse_error(r);
579
580         have_mac = sd_rtnl_message_read_ether_addr(reply, IFLA_ADDRESS, &e) >= 0;
581
582         if (have_mac) {
583                 const uint8_t *p;
584                 bool all_zeroes = true;
585
586                 for (p = (uint8_t*) &e; p < (uint8_t*) &e + sizeof(e); p++)
587                         if (*p != 0) {
588                                 all_zeroes = false;
589                                 break;
590                         }
591
592                 if (all_zeroes)
593                         have_mac = false;
594         }
595
596         sd_rtnl_message_read_u32(reply, IFLA_MTU, &mtu);
597
598         sd_network_link_get_operational_state(ifindex, &operational_state);
599         operational_state_to_color(operational_state, &on_color_operational, &off_color_operational);
600
601         sd_network_link_get_setup_state(ifindex, &setup_state);
602         setup_state_to_color(setup_state, &on_color_setup, &off_color_setup);
603
604         sd_network_link_get_dns(ifindex, &dns);
605         sd_network_link_get_ntp(ifindex, &ntp);
606         sd_network_link_get_domains(ifindex, &domains);
607         r = sd_network_link_get_wildcard_domain(ifindex);
608         if (r > 0) {
609                 char *wildcard;
610
611                 wildcard = strdup("*");
612                 if (!wildcard)
613                         return log_oom();
614
615                 if (strv_consume(&domains, wildcard) < 0)
616                         return log_oom();
617         }
618
619         sprintf(devid, "n%i", ifindex);
620         d = udev_device_new_from_device_id(udev, devid);
621
622         link_get_type_string(iftype, d, &t);
623
624         if (d) {
625                 link = udev_device_get_property_value(d, "ID_NET_LINK_FILE");
626                 driver = udev_device_get_property_value(d, "ID_NET_DRIVER");
627                 path = udev_device_get_property_value(d, "ID_PATH");
628
629                 vendor = udev_device_get_property_value(d, "ID_VENDOR_FROM_DATABASE");
630                 if (!vendor)
631                         vendor = udev_device_get_property_value(d, "ID_VENDOR");
632
633                 model = udev_device_get_property_value(d, "ID_MODEL_FROM_DATABASE");
634                 if (!model)
635                         model = udev_device_get_property_value(d, "ID_MODEL");
636         }
637
638         sd_network_link_get_network_file(ifindex, &network);
639
640         printf("%s%s%s %i: %s\n", on_color_operational, draw_special_char(DRAW_BLACK_CIRCLE), off_color_operational, ifindex, name);
641
642         printf("   Link File: %s\n"
643                "Network File: %s\n"
644                "        Type: %s\n"
645                "       State: %s%s%s (%s%s%s)\n",
646                strna(link),
647                strna(network),
648                strna(t),
649                on_color_operational, strna(operational_state), off_color_operational,
650                on_color_setup, strna(setup_state), off_color_setup);
651
652         if (path)
653                 printf("        Path: %s\n", path);
654         if (driver)
655                 printf("      Driver: %s\n", driver);
656         if (vendor)
657                 printf("      Vendor: %s\n", vendor);
658         if (model)
659                 printf("       Model: %s\n", model);
660
661         if (have_mac) {
662                 char ea[ETHER_ADDR_TO_STRING_MAX];
663                 printf("  HW Address: %s\n", ether_addr_to_string(&e, ea));
664         }
665
666         if (mtu > 0)
667                 printf("         MTU: %u\n", mtu);
668
669         hwdb = udev_hwdb_new(udev);
670
671         dump_gateways(rtnl, hwdb, "     Gateway: ", ifindex);
672
673         dump_addresses(rtnl, "     Address: ", ifindex);
674
675         if (!strv_isempty(dns))
676                 dump_list("         DNS: ", dns);
677         if (!strv_isempty(domains))
678                 dump_list("      Domain: ", domains);
679         if (!strv_isempty(ntp))
680                 dump_list("         NTP: ", ntp);
681
682         return 0;
683 }
684
685 static int link_status(char **args, unsigned n) {
686         _cleanup_udev_unref_ struct udev *udev = NULL;
687         _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
688         char **name;
689         int r;
690
691         r = sd_rtnl_open(&rtnl, 0);
692         if (r < 0)
693                 return log_error_errno(r, "Failed to connect to netlink: %m");
694
695         udev = udev_new();
696         if (!udev)
697                 return log_error_errno(errno, "Failed to connect to udev: %m");
698
699         if (n <= 1 && !arg_all) {
700                 _cleanup_free_ char *operational_state = NULL;
701                 _cleanup_strv_free_ char **dns = NULL, **ntp = NULL, **domains = NULL;
702                 _cleanup_free_ struct local_address *addresses = NULL;
703                 const char *on_color_operational, *off_color_operational;
704                 int i, c;
705
706                 sd_network_get_operational_state(&operational_state);
707                 operational_state_to_color(operational_state, &on_color_operational, &off_color_operational);
708
709                 printf("       State: %s%s%s\n", on_color_operational, strna(operational_state), off_color_operational);
710
711                 c = local_addresses(rtnl, 0, AF_UNSPEC, &addresses);
712                 for (i = 0; i < c; i++) {
713                         _cleanup_free_ char *pretty = NULL;
714
715                         r = in_addr_to_string(addresses[i].family, &addresses[i].address, &pretty);
716                         if (r < 0)
717                                 return log_oom();
718
719                         printf("%13s %s\n",
720                                i > 0 ? "" : "Address:", pretty);
721                 }
722
723                 sd_network_get_dns(&dns);
724                 if (!strv_isempty(dns))
725                         dump_list("         DNS: ", dns);
726
727                 sd_network_get_domains(&domains);
728                 if (!strv_isempty(domains))
729                         dump_list("      Domain: ", domains);
730
731                 sd_network_get_ntp(&ntp);
732                 if (!strv_isempty(ntp))
733                         dump_list("         NTP: ", ntp);
734
735                 return 0;
736         }
737
738         pager_open_if_enabled();
739
740         if (arg_all) {
741                 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
742                 _cleanup_free_ LinkInfo *links = NULL;
743                 int c, i;
744
745                 r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, 0);
746                 if (r < 0)
747                         return rtnl_log_create_error(r);
748
749                 r = sd_rtnl_message_request_dump(req, true);
750                 if (r < 0)
751                         return rtnl_log_create_error(r);
752
753                 r = sd_rtnl_call(rtnl, req, 0, &reply);
754                 if (r < 0)
755                         return log_error_errno(r, "Failed to enumerate links: %m");
756
757                 c = decode_and_sort_links(reply, &links);
758                 if (c < 0)
759                         return rtnl_log_parse_error(c);
760
761                 for (i = 0; i < c; i++) {
762                         if (i > 0)
763                                 fputc('\n', stdout);
764
765                         link_status_one(rtnl, udev, links[i].name);
766                 }
767         }
768
769         STRV_FOREACH(name, args + 1) {
770                 if (name != args+1)
771                         fputc('\n', stdout);
772
773                 link_status_one(rtnl, udev, *name);
774         }
775
776         return 0;
777 }
778
779 static void help(void) {
780         printf("%s [OPTIONS...]\n\n"
781                "Query and control the networking subsystem.\n\n"
782                "  -h --help             Show this help\n"
783                "     --version          Show package version\n"
784                "     --no-pager         Do not pipe output into a pager\n"
785                "     --no-legend        Do not show the headers and footers\n"
786                "  -a --all              Show status for all links\n\n"
787                "Commands:\n"
788                "  list                  List links\n"
789                "  status LINK           Show link status\n"
790                , program_invocation_short_name);
791 }
792
793 static int parse_argv(int argc, char *argv[]) {
794
795         enum {
796                 ARG_VERSION = 0x100,
797                 ARG_NO_PAGER,
798                 ARG_NO_LEGEND,
799         };
800
801         static const struct option options[] = {
802                 { "help",      no_argument,       NULL, 'h'           },
803                 { "version",   no_argument,       NULL, ARG_VERSION   },
804                 { "no-pager",  no_argument,       NULL, ARG_NO_PAGER  },
805                 { "no-legend", no_argument,       NULL, ARG_NO_LEGEND },
806                 { "all",       no_argument,       NULL, 'a'           },
807                 {}
808         };
809
810         int c;
811
812         assert(argc >= 0);
813         assert(argv);
814
815         while ((c = getopt_long(argc, argv, "ha", options, NULL)) >= 0) {
816
817                 switch (c) {
818
819                 case 'h':
820                         help();
821                         return 0;
822
823                 case ARG_VERSION:
824                         puts(PACKAGE_STRING);
825                         puts(SYSTEMD_FEATURES);
826                         return 0;
827
828                 case ARG_NO_PAGER:
829                         arg_no_pager = true;
830                         break;
831
832                 case ARG_NO_LEGEND:
833                         arg_legend = false;
834                         break;
835
836                 case 'a':
837                         arg_all = true;
838                         break;
839
840                 case '?':
841                         return -EINVAL;
842
843                 default:
844                         assert_not_reached("Unhandled option");
845                 }
846         }
847
848         return 1;
849 }
850
851 static int networkctl_main(int argc, char *argv[]) {
852
853         static const struct {
854                 const char* verb;
855                 const enum {
856                         MORE,
857                         LESS,
858                         EQUAL
859                 } argc_cmp;
860                 const int argc;
861                 int (* const dispatch)(char **args, unsigned n);
862         } verbs[] = {
863                 { "list",   LESS, 1, list_links  },
864                 { "status", MORE, 1, link_status },
865         };
866
867         int left;
868         unsigned i;
869
870         assert(argc >= 0);
871         assert(argv);
872
873         left = argc - optind;
874
875         if (left <= 0)
876                 /* Special rule: no arguments means "list" */
877                 i = 0;
878         else {
879                 if (streq(argv[optind], "help")) {
880                         help();
881                         return 0;
882                 }
883
884                 for (i = 0; i < ELEMENTSOF(verbs); i++)
885                         if (streq(argv[optind], verbs[i].verb))
886                                 break;
887
888                 if (i >= ELEMENTSOF(verbs)) {
889                         log_error("Unknown operation %s", argv[optind]);
890                         return -EINVAL;
891                 }
892         }
893
894         switch (verbs[i].argc_cmp) {
895
896         case EQUAL:
897                 if (left != verbs[i].argc) {
898                         log_error("Invalid number of arguments.");
899                         return -EINVAL;
900                 }
901
902                 break;
903
904         case MORE:
905                 if (left < verbs[i].argc) {
906                         log_error("Too few arguments.");
907                         return -EINVAL;
908                 }
909
910                 break;
911
912         case LESS:
913                 if (left > verbs[i].argc) {
914                         log_error("Too many arguments.");
915                         return -EINVAL;
916                 }
917
918                 break;
919
920         default:
921                 assert_not_reached("Unknown comparison operator.");
922         }
923
924         return verbs[i].dispatch(argv + optind, left);
925 }
926
927 int main(int argc, char* argv[]) {
928         int r;
929
930         log_parse_environment();
931         log_open();
932
933         r = parse_argv(argc, argv);
934         if (r <= 0)
935                 goto finish;
936
937         r = networkctl_main(argc, argv);
938
939 finish:
940         pager_close();
941
942         return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
943 }