chiark / gitweb /
journal: bump RLIMIT_NOFILE when journal files to 16K (if possible)
[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 #include <net/if.h>
25
26 #include "sd-network.h"
27 #include "sd-rtnl.h"
28 #include "sd-hwdb.h"
29 #include "libudev.h"
30
31 #include "strv.h"
32 #include "build.h"
33 #include "util.h"
34 #include "pager.h"
35 #include "lldp.h"
36 #include "rtnl-util.h"
37 #include "udev-util.h"
38 #include "hwdb-util.h"
39 #include "arphrd-list.h"
40 #include "local-addresses.h"
41 #include "socket-util.h"
42 #include "ether-addr-util.h"
43 #include "verbs.h"
44
45 static bool arg_no_pager = false;
46 static bool arg_legend = true;
47 static bool arg_all = false;
48
49 static void pager_open_if_enabled(void) {
50
51         if (arg_no_pager)
52                 return;
53
54         pager_open(false);
55 }
56
57 static int link_get_type_string(int iftype, struct udev_device *d, char **ret) {
58         const char *t;
59         char *p;
60
61         if (iftype == ARPHRD_ETHER && d) {
62                 const char *devtype, *id = NULL;
63                 /* WLANs have iftype ARPHRD_ETHER, but we want
64                  * to show a more useful type string for
65                  * them */
66
67                 devtype = udev_device_get_devtype(d);
68                 if (streq_ptr(devtype, "wlan"))
69                         id = "wlan";
70                 else if (streq_ptr(devtype, "wwan"))
71                         id = "wwan";
72
73                 if (id) {
74                         p = strdup(id);
75                         if (!p)
76                                 return -ENOMEM;
77
78                         *ret = p;
79                         return 1;
80                 }
81         }
82
83         t = arphrd_to_name(iftype);
84         if (!t) {
85                 *ret = NULL;
86                 return 0;
87         }
88
89         p = strdup(t);
90         if (!p)
91                 return -ENOMEM;
92
93         ascii_strlower(p);
94         *ret = p;
95
96         return 0;
97 }
98
99 typedef struct LinkInfo {
100         const char *name;
101         int ifindex;
102         unsigned iftype;
103 } LinkInfo;
104
105 static int link_info_compare(const void *a, const void *b) {
106         const LinkInfo *x = a, *y = b;
107
108         return x->ifindex - y->ifindex;
109 }
110
111 static int decode_and_sort_links(sd_rtnl_message *m, LinkInfo **ret) {
112         _cleanup_free_ LinkInfo *links = NULL;
113         size_t size = 0, c = 0;
114         sd_rtnl_message *i;
115         int r;
116
117         for (i = m; i; i = sd_rtnl_message_next(i)) {
118                 const char *name;
119                 unsigned iftype;
120                 uint16_t type;
121                 int ifindex;
122
123                 r = sd_rtnl_message_get_type(i, &type);
124                 if (r < 0)
125                         return r;
126
127                 if (type != RTM_NEWLINK)
128                         continue;
129
130                 r = sd_rtnl_message_link_get_ifindex(i, &ifindex);
131                 if (r < 0)
132                         return r;
133
134                 r = sd_rtnl_message_read_string(i, IFLA_IFNAME, &name);
135                 if (r < 0)
136                         return r;
137
138                 r = sd_rtnl_message_link_get_type(i, &iftype);
139                 if (r < 0)
140                         return r;
141
142                 if (!GREEDY_REALLOC(links, size, c+1))
143                         return -ENOMEM;
144
145                 links[c].name = name;
146                 links[c].ifindex = ifindex;
147                 links[c].iftype = iftype;
148                 c++;
149         }
150
151         qsort_safe(links, c, sizeof(LinkInfo), link_info_compare);
152
153         *ret = links;
154         links = NULL;
155
156         return (int) c;
157 }
158
159 static void operational_state_to_color(const char *state, const char **on, const char **off) {
160         assert(on);
161         assert(off);
162
163         if (streq_ptr(state, "routable")) {
164                 *on = ansi_highlight_green();
165                 *off = ansi_highlight_off();
166         } else if (streq_ptr(state, "degraded")) {
167                 *on = ansi_highlight_yellow();
168                 *off = ansi_highlight_off();
169         } else
170                 *on = *off = "";
171 }
172
173 static void setup_state_to_color(const char *state, const char **on, const char **off) {
174         assert(on);
175         assert(off);
176
177         if (streq_ptr(state, "configured")) {
178                 *on = ansi_highlight_green();
179                 *off = ansi_highlight_off();
180         } else if (streq_ptr(state, "configuring")) {
181                 *on = ansi_highlight_yellow();
182                 *off = ansi_highlight_off();
183         } else if (streq_ptr(state, "failed") || streq_ptr(state, "linger")) {
184                 *on = ansi_highlight_red();
185                 *off = ansi_highlight_off();
186         } else
187                 *on = *off = "";
188 }
189
190 static int list_links(int argc, char *argv[], void *userdata) {
191         _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
192         _cleanup_udev_unref_ struct udev *udev = NULL;
193         _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
194         _cleanup_free_ LinkInfo *links = NULL;
195         int r, c, i;
196
197         pager_open_if_enabled();
198
199         r = sd_rtnl_open(&rtnl, 0);
200         if (r < 0)
201                 return log_error_errno(r, "Failed to connect to netlink: %m");
202
203         udev = udev_new();
204         if (!udev)
205                 return log_error_errno(errno, "Failed to connect to udev: %m");
206
207         r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, 0);
208         if (r < 0)
209                 return rtnl_log_create_error(r);
210
211         r = sd_rtnl_message_request_dump(req, true);
212         if (r < 0)
213                 return rtnl_log_create_error(r);
214
215         r = sd_rtnl_call(rtnl, req, 0, &reply);
216         if (r < 0)
217                 return log_error_errno(r, "Failed to enumerate links: %m");
218
219         if (arg_legend)
220                 printf("%3s %-16s %-18s %-11s %-10s\n", "IDX", "LINK", "TYPE", "OPERATIONAL", "SETUP");
221
222         c = decode_and_sort_links(reply, &links);
223         if (c < 0)
224                 return rtnl_log_parse_error(c);
225
226         for (i = 0; i < c; i++) {
227                 _cleanup_free_ char *setup_state = NULL, *operational_state = NULL;
228                 _cleanup_udev_device_unref_ struct udev_device *d = NULL;
229                 const char *on_color_operational, *off_color_operational,
230                            *on_color_setup, *off_color_setup;
231                  char devid[2 + DECIMAL_STR_MAX(int)];
232                 _cleanup_free_ char *t = NULL;
233
234                 sd_network_link_get_operational_state(links[i].ifindex, &operational_state);
235                 operational_state_to_color(operational_state, &on_color_operational, &off_color_operational);
236
237                 sd_network_link_get_setup_state(links[i].ifindex, &setup_state);
238                 setup_state_to_color(setup_state, &on_color_setup, &off_color_setup);
239
240                 sprintf(devid, "n%i", links[i].ifindex);
241                 d = udev_device_new_from_device_id(udev, devid);
242
243                 link_get_type_string(links[i].iftype, d, &t);
244
245                 printf("%3i %-16s %-18s %s%-11s%s %s%-10s%s\n",
246                        links[i].ifindex, links[i].name, strna(t),
247                        on_color_operational, strna(operational_state), off_color_operational,
248                        on_color_setup, strna(setup_state), off_color_setup);
249         }
250
251         if (arg_legend)
252                 printf("\n%i links listed.\n", c);
253
254         return 0;
255 }
256
257 /* IEEE Organizationally Unique Identifier vendor string */
258 static int ieee_oui(sd_hwdb *hwdb, struct ether_addr *mac, char **ret) {
259         const char *description;
260         char modalias[strlen("OUI:XXYYXXYYXXYY") + 1], *desc;
261         int r;
262
263         assert(ret);
264
265         if (!hwdb)
266                 return -EINVAL;
267
268         if (!mac)
269                 return -EINVAL;
270
271         /* skip commonly misused 00:00:00 (Xerox) prefix */
272         if (memcmp(mac, "\0\0\0", 3) == 0)
273                 return -EINVAL;
274
275         snprintf(modalias, sizeof(modalias), "OUI:" ETHER_ADDR_FORMAT_STR, ETHER_ADDR_FORMAT_VAL(*mac));
276
277         r = sd_hwdb_get(hwdb, modalias, "ID_OUI_FROM_DATABASE", &description);
278         if (r < 0)
279                 return r;
280
281         desc = strdup(description);
282         if (!desc)
283                 return -ENOMEM;
284
285         *ret = desc;
286
287         return 0;
288 }
289
290 static int get_gateway_description(
291                 sd_rtnl *rtnl,
292                 sd_hwdb *hwdb,
293                 int ifindex,
294                 int family,
295                 union in_addr_union *gateway,
296                 char **gateway_description) {
297         _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
298         sd_rtnl_message *m;
299         int r;
300
301         assert(rtnl);
302         assert(ifindex >= 0);
303         assert(family == AF_INET || family == AF_INET6);
304         assert(gateway);
305         assert(gateway_description);
306
307         r = sd_rtnl_message_new_neigh(rtnl, &req, RTM_GETNEIGH, ifindex, family);
308         if (r < 0)
309                 return r;
310
311         r = sd_rtnl_message_request_dump(req, true);
312         if (r < 0)
313                 return r;
314
315         r = sd_rtnl_call(rtnl, req, 0, &reply);
316         if (r < 0)
317                 return r;
318
319         for (m = reply; m; m = sd_rtnl_message_next(m)) {
320                 union in_addr_union gw = {};
321                 struct ether_addr mac = {};
322                 uint16_t type;
323                 int ifi, fam;
324
325                 r = sd_rtnl_message_get_errno(m);
326                 if (r < 0) {
327                         log_error_errno(r, "got error: %m");
328                         continue;
329                 }
330
331                 r = sd_rtnl_message_get_type(m, &type);
332                 if (r < 0) {
333                         log_error_errno(r, "could not get type: %m");
334                         continue;
335                 }
336
337                 if (type != RTM_NEWNEIGH) {
338                         log_error("type is not RTM_NEWNEIGH");
339                         continue;
340                 }
341
342                 r = sd_rtnl_message_neigh_get_family(m, &fam);
343                 if (r < 0) {
344                         log_error_errno(r, "could not get family: %m");
345                         continue;
346                 }
347
348                 if (fam != family) {
349                         log_error("family is not correct");
350                         continue;
351                 }
352
353                 r = sd_rtnl_message_neigh_get_ifindex(m, &ifi);
354                 if (r < 0) {
355                         log_error_errno(r, "could not get ifindex: %m");
356                         continue;
357                 }
358
359                 if (ifindex > 0 && ifi != ifindex)
360                         continue;
361
362                 switch (fam) {
363                 case AF_INET:
364                         r = sd_rtnl_message_read_in_addr(m, NDA_DST, &gw.in);
365                         if (r < 0)
366                                 continue;
367
368                         break;
369                 case AF_INET6:
370                         r = sd_rtnl_message_read_in6_addr(m, NDA_DST, &gw.in6);
371                         if (r < 0)
372                                 continue;
373
374                         break;
375                 default:
376                         continue;
377                 }
378
379                 if (!in_addr_equal(fam, &gw, gateway))
380                         continue;
381
382                 r = sd_rtnl_message_read_ether_addr(m, NDA_LLADDR, &mac);
383                 if (r < 0)
384                         continue;
385
386                 r = ieee_oui(hwdb, &mac, gateway_description);
387                 if (r < 0)
388                         continue;
389
390                 return 0;
391         }
392
393         return -ENODATA;
394 }
395
396 static int dump_gateways(
397                 sd_rtnl *rtnl,
398                 sd_hwdb *hwdb,
399                 const char *prefix,
400                 int ifindex) {
401         _cleanup_free_ struct local_address *local = NULL;
402         int r, n, i;
403
404         n = local_gateways(rtnl, ifindex, AF_UNSPEC, &local);
405         if (n < 0)
406                 return n;
407
408         for (i = 0; i < n; i++) {
409                 _cleanup_free_ char *gateway = NULL, *description = NULL;
410
411                 r = in_addr_to_string(local[i].family, &local[i].address, &gateway);
412                 if (r < 0)
413                         return r;
414
415                 r = get_gateway_description(rtnl, hwdb, local[i].ifindex, local[i].family, &local[i].address, &description);
416                 if (r < 0)
417                         log_debug_errno(r, "Could not get description of gateway: %m");
418
419                 printf("%*s%s",
420                        (int) strlen(prefix),
421                        i == 0 ? prefix : "",
422                        gateway);
423
424                 if (description)
425                         printf(" (%s)", description);
426
427                 /* Show interface name for the entry if we show
428                  * entries for all interfaces */
429                 if (ifindex <= 0) {
430                         char name[IF_NAMESIZE+1];
431
432                         if (if_indextoname(local[i].ifindex, name)) {
433                                 fputs(" on ", stdout);
434                                 fputs(name, stdout);
435                         } else
436                                 printf(" on %%%i", local[i].ifindex);
437                 }
438
439                 fputc('\n', stdout);
440         }
441
442         return 0;
443 }
444
445 static int dump_addresses(
446                 sd_rtnl *rtnl,
447                 const char *prefix,
448                 int ifindex) {
449
450         _cleanup_free_ struct local_address *local = NULL;
451         int r, n, i;
452
453         n = local_addresses(rtnl, ifindex, AF_UNSPEC, &local);
454         if (n < 0)
455                 return n;
456
457         for (i = 0; i < n; i++) {
458                 _cleanup_free_ char *pretty = NULL;
459
460                 r = in_addr_to_string(local[i].family, &local[i].address, &pretty);
461                 if (r < 0)
462                         return r;
463
464                 printf("%*s%s",
465                        (int) strlen(prefix),
466                        i == 0 ? prefix : "",
467                        pretty);
468
469                 if (ifindex <= 0) {
470                         char name[IF_NAMESIZE+1];
471
472                         if (if_indextoname(local[i].ifindex, name)) {
473                                 fputs(" on ", stdout);
474                                 fputs(name, stdout);
475                         } else
476                                 printf(" on %%%i", local[i].ifindex);
477                 }
478
479                 fputc('\n', stdout);
480         }
481
482         return 0;
483 }
484
485 static void dump_list(const char *prefix, char **l) {
486         char **i;
487
488         STRV_FOREACH(i, l) {
489                 printf("%*s%s\n",
490                        (int) strlen(prefix),
491                        i == l ? prefix : "",
492                        *i);
493         }
494 }
495
496 static int link_status_one(
497                 sd_rtnl *rtnl,
498                 struct udev *udev,
499                 sd_hwdb *hwdb,
500                 const char *name) {
501
502         _cleanup_strv_free_ char **dns = NULL, **ntp = NULL, **domains = NULL;
503         _cleanup_free_ char *setup_state = NULL, *operational_state = NULL;
504         _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
505         _cleanup_udev_device_unref_ struct udev_device *d = NULL;
506         char devid[2 + DECIMAL_STR_MAX(int)];
507         _cleanup_free_ char *t = NULL, *network = NULL;
508         const char *driver = NULL, *path = NULL, *vendor = NULL, *model = NULL, *link = NULL;
509         const char *on_color_operational, *off_color_operational,
510                    *on_color_setup, *off_color_setup;
511         struct ether_addr e;
512         unsigned iftype;
513         int r, ifindex;
514         bool have_mac;
515         uint32_t mtu;
516
517         assert(rtnl);
518         assert(udev);
519         assert(name);
520
521         if (safe_atoi(name, &ifindex) >= 0 && ifindex > 0)
522                 r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, ifindex);
523         else {
524                 r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, 0);
525                 if (r < 0)
526                         return rtnl_log_create_error(r);
527
528                 r = sd_rtnl_message_append_string(req, IFLA_IFNAME, name);
529         }
530
531         if (r < 0)
532                 return rtnl_log_create_error(r);
533
534         r = sd_rtnl_call(rtnl, req, 0, &reply);
535         if (r < 0)
536                 return log_error_errno(r, "Failed to query link: %m");
537
538         r = sd_rtnl_message_link_get_ifindex(reply, &ifindex);
539         if (r < 0)
540                 return rtnl_log_parse_error(r);
541
542         r = sd_rtnl_message_read_string(reply, IFLA_IFNAME, &name);
543         if (r < 0)
544                 return rtnl_log_parse_error(r);
545
546         r = sd_rtnl_message_link_get_type(reply, &iftype);
547         if (r < 0)
548                 return rtnl_log_parse_error(r);
549
550         have_mac = sd_rtnl_message_read_ether_addr(reply, IFLA_ADDRESS, &e) >= 0;
551
552         if (have_mac) {
553                 const uint8_t *p;
554                 bool all_zeroes = true;
555
556                 for (p = (uint8_t*) &e; p < (uint8_t*) &e + sizeof(e); p++)
557                         if (*p != 0) {
558                                 all_zeroes = false;
559                                 break;
560                         }
561
562                 if (all_zeroes)
563                         have_mac = false;
564         }
565
566         sd_rtnl_message_read_u32(reply, IFLA_MTU, &mtu);
567
568         sd_network_link_get_operational_state(ifindex, &operational_state);
569         operational_state_to_color(operational_state, &on_color_operational, &off_color_operational);
570
571         sd_network_link_get_setup_state(ifindex, &setup_state);
572         setup_state_to_color(setup_state, &on_color_setup, &off_color_setup);
573
574         sd_network_link_get_dns(ifindex, &dns);
575         sd_network_link_get_ntp(ifindex, &ntp);
576         sd_network_link_get_domains(ifindex, &domains);
577         r = sd_network_link_get_wildcard_domain(ifindex);
578         if (r > 0) {
579                 char *wildcard;
580
581                 wildcard = strdup("*");
582                 if (!wildcard)
583                         return log_oom();
584
585                 if (strv_consume(&domains, wildcard) < 0)
586                         return log_oom();
587         }
588
589         sprintf(devid, "n%i", ifindex);
590         d = udev_device_new_from_device_id(udev, devid);
591         if (d) {
592                 link = udev_device_get_property_value(d, "ID_NET_LINK_FILE");
593                 driver = udev_device_get_property_value(d, "ID_NET_DRIVER");
594                 path = udev_device_get_property_value(d, "ID_PATH");
595
596                 vendor = udev_device_get_property_value(d, "ID_VENDOR_FROM_DATABASE");
597                 if (!vendor)
598                         vendor = udev_device_get_property_value(d, "ID_VENDOR");
599
600                 model = udev_device_get_property_value(d, "ID_MODEL_FROM_DATABASE");
601                 if (!model)
602                         model = udev_device_get_property_value(d, "ID_MODEL");
603         }
604
605         link_get_type_string(iftype, d, &t);
606
607         sd_network_link_get_network_file(ifindex, &network);
608
609         printf("%s%s%s %i: %s\n", on_color_operational, draw_special_char(DRAW_BLACK_CIRCLE), off_color_operational, ifindex, name);
610
611         printf("   Link File: %s\n"
612                "Network File: %s\n"
613                "        Type: %s\n"
614                "       State: %s%s%s (%s%s%s)\n",
615                strna(link),
616                strna(network),
617                strna(t),
618                on_color_operational, strna(operational_state), off_color_operational,
619                on_color_setup, strna(setup_state), off_color_setup);
620
621         if (path)
622                 printf("        Path: %s\n", path);
623         if (driver)
624                 printf("      Driver: %s\n", driver);
625         if (vendor)
626                 printf("      Vendor: %s\n", vendor);
627         if (model)
628                 printf("       Model: %s\n", model);
629
630         if (have_mac) {
631                 _cleanup_free_ char *description = NULL;
632                 char ea[ETHER_ADDR_TO_STRING_MAX];
633
634                 ieee_oui(hwdb, &e, &description);
635
636                 if (description)
637                         printf("  HW Address: %s (%s)\n", ether_addr_to_string(&e, ea), description);
638                 else
639                         printf("  HW Address: %s\n", ether_addr_to_string(&e, ea));
640         }
641
642         if (mtu > 0)
643                 printf("         MTU: %u\n", mtu);
644
645         dump_addresses(rtnl, "     Address: ", ifindex);
646         dump_gateways(rtnl, hwdb, "     Gateway: ", ifindex);
647
648         if (!strv_isempty(dns))
649                 dump_list("         DNS: ", dns);
650         if (!strv_isempty(domains))
651                 dump_list("      Domain: ", domains);
652         if (!strv_isempty(ntp))
653                 dump_list("         NTP: ", ntp);
654
655         return 0;
656 }
657
658 static int link_status(int argc, char *argv[], void *userdata) {
659         _cleanup_hwdb_unref_ sd_hwdb *hwdb = NULL;
660         _cleanup_udev_unref_ struct udev *udev = NULL;
661         _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
662         char **name;
663         int r;
664
665         r = sd_rtnl_open(&rtnl, 0);
666         if (r < 0)
667                 return log_error_errno(r, "Failed to connect to netlink: %m");
668
669         udev = udev_new();
670         if (!udev)
671                 return log_error_errno(errno, "Failed to connect to udev: %m");
672
673         r = sd_hwdb_new(&hwdb);
674         if (r < 0)
675                 log_debug_errno(r, "Failed to open hardware database: %m");
676
677         if (argc <= 1 && !arg_all) {
678                 _cleanup_free_ char *operational_state = NULL;
679                 _cleanup_strv_free_ char **dns = NULL, **ntp = NULL, **domains = NULL;
680                 const char *on_color_operational, *off_color_operational;
681
682                 sd_network_get_operational_state(&operational_state);
683                 operational_state_to_color(operational_state, &on_color_operational, &off_color_operational);
684
685                 printf("%s%s%s      State: %s%s%s\n",
686                        on_color_operational, draw_special_char(DRAW_BLACK_CIRCLE), off_color_operational,
687                        on_color_operational, strna(operational_state), off_color_operational);
688
689                 dump_addresses(rtnl, "     Address: ", 0);
690                 dump_gateways(rtnl, hwdb, "     Gateway: ", 0);
691
692                 sd_network_get_dns(&dns);
693                 if (!strv_isempty(dns))
694                         dump_list("         DNS: ", dns);
695
696                 sd_network_get_domains(&domains);
697                 if (!strv_isempty(domains))
698                         dump_list("      Domain: ", domains);
699
700                 sd_network_get_ntp(&ntp);
701                 if (!strv_isempty(ntp))
702                         dump_list("         NTP: ", ntp);
703
704                 return 0;
705         }
706
707         pager_open_if_enabled();
708
709         if (arg_all) {
710                 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
711                 _cleanup_free_ LinkInfo *links = NULL;
712                 int c, i;
713
714                 r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, 0);
715                 if (r < 0)
716                         return rtnl_log_create_error(r);
717
718                 r = sd_rtnl_message_request_dump(req, true);
719                 if (r < 0)
720                         return rtnl_log_create_error(r);
721
722                 r = sd_rtnl_call(rtnl, req, 0, &reply);
723                 if (r < 0)
724                         return log_error_errno(r, "Failed to enumerate links: %m");
725
726                 c = decode_and_sort_links(reply, &links);
727                 if (c < 0)
728                         return rtnl_log_parse_error(c);
729
730                 for (i = 0; i < c; i++) {
731                         if (i > 0)
732                                 fputc('\n', stdout);
733
734                         link_status_one(rtnl, udev, hwdb, links[i].name);
735                 }
736         } else {
737                 STRV_FOREACH(name, argv + 1) {
738                         if (name != argv + 1)
739                                 fputc('\n', stdout);
740
741                         link_status_one(rtnl, udev, hwdb, *name);
742                 }
743         }
744
745         return 0;
746 }
747
748 const char *lldp_system_capability_to_string(LLDPSystemCapabilities d) _const_;
749 LLDPSystemCapabilities lldp_system_capability_from_string(const char *d) _pure_;
750
751 static const char* const lldp_system_capability_table[_LLDP_SYSTEM_CAPABILITIES_MAX + 1] = {
752         [LLDP_SYSTEM_CAPABILITIES_OTHER] = "O",
753         [LLDP_SYSTEM_CAPABILITIES_REPEATER] = "P",
754         [LLDP_SYSTEM_CAPABILITIES_BRIDGE] = "B",
755         [LLDP_SYSTEM_CAPABILITIES_WLAN_AP] = "W",
756         [LLDP_SYSTEM_CAPABILITIES_ROUTER] = "R",
757         [LLDP_SYSTEM_CAPABILITIES_PHONE] = "T",
758         [LLDP_SYSTEM_CAPABILITIES_DOCSIS] = "D",
759         [LLDP_SYSTEM_CAPABILITIES_STATION] = "A",
760         [LLDP_SYSTEM_CAPABILITIES_CVLAN] = "C",
761         [LLDP_SYSTEM_CAPABILITIES_SVLAN] = "S",
762         [LLDP_SYSTEM_CAPABILITIES_TPMR] = "M",
763         [_LLDP_SYSTEM_CAPABILITIES_MAX] = "N/A",
764 };
765
766 DEFINE_STRING_TABLE_LOOKUP(lldp_system_capability, LLDPSystemCapabilities);
767
768 static char *lldp_system_caps(uint16_t cap) {
769         _cleanup_free_ char *s = NULL, *t = NULL;
770         char *capability;
771
772         t = strdup("[ ");
773         if (!t)
774                 return NULL;
775
776         if (cap & LLDP_SYSTEM_CAPABILITIES_OTHER) {
777                 s = strjoin(t, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_OTHER), " ", NULL);
778                 if (!s)
779                         return NULL;
780
781                 free(t);
782                 t = s;
783         }
784
785         if (cap & LLDP_SYSTEM_CAPABILITIES_REPEATER) {
786                 s = strjoin(t, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_REPEATER), " ", NULL);
787                 if (!s)
788                         return NULL;
789
790                 free(t);
791                 t = s;
792         }
793
794         if (cap & LLDP_SYSTEM_CAPABILITIES_BRIDGE) {
795                 s = strjoin(t, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_BRIDGE), " ", NULL);
796                 if (!s)
797                         return NULL;
798
799                 free(t);
800                 t = s;
801         }
802
803         if (cap & LLDP_SYSTEM_CAPABILITIES_WLAN_AP) {
804                 s = strjoin(t, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_WLAN_AP), " ", NULL);
805                 if (!s)
806                         return NULL;
807
808                 free(t);
809                 t = s;
810         }
811
812         if (cap & LLDP_SYSTEM_CAPABILITIES_ROUTER) {
813                 s =  strjoin(t, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_ROUTER), " ", NULL);
814                 if (!s)
815                         return NULL;
816
817                 free(t);
818                 t = s;
819         }
820
821         if (cap & LLDP_SYSTEM_CAPABILITIES_PHONE) {
822                 s = strjoin(t, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_PHONE), " ", NULL);
823                 if (!s)
824                         return NULL;
825
826                 free(t);
827                 t = s;
828         }
829
830         if (cap & LLDP_SYSTEM_CAPABILITIES_DOCSIS) {
831                 s = strjoin(t, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_DOCSIS), " ", NULL);
832                 if (!s)
833                         return NULL;
834
835                 free(t);
836                 t = s;
837         }
838
839         if (cap & LLDP_SYSTEM_CAPABILITIES_STATION) {
840                 s = strjoin(t, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_STATION), " ", NULL);
841                 if (!s)
842                         return NULL;
843
844                 free(t);
845                 t = s;
846         }
847
848         if (cap & LLDP_SYSTEM_CAPABILITIES_CVLAN) {
849                 s = strjoin(t, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_CVLAN), " ", NULL);
850                 if (!s)
851                         return NULL;
852
853                 free(t);
854                 t = s;
855         }
856
857         if (cap & LLDP_SYSTEM_CAPABILITIES_SVLAN) {
858                 s = strjoin(t, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_SVLAN), " ", NULL);
859                 if (!s)
860                         return NULL;
861
862                 free(t);
863                 t = s;
864         }
865
866         if (cap & LLDP_SYSTEM_CAPABILITIES_TPMR) {
867                 s = strappend(t, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_TPMR));
868                 if (!s)
869                         return NULL;
870
871                 free(t);
872         }
873
874         if (!s) {
875                 s = strappend(t, lldp_system_capability_to_string(_LLDP_SYSTEM_CAPABILITIES_MAX));
876                 if (!s)
877                         return NULL;
878
879                 free(t);
880         }
881
882         t = strappend(s, "]");
883         if (!t)
884                 return NULL;
885
886         free(s);
887         capability = t;
888
889         s = NULL;
890         t = NULL;
891
892         return capability;
893 }
894
895 static int link_lldp_status(int argc, char *argv[], void *userdata) {
896         _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
897         _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
898         _cleanup_free_ LinkInfo *links = NULL;
899         const char *state, *word;
900
901         double ttl = -1;
902         uint32_t capability;
903         int i, r, c, j;
904         size_t ll;
905         char **s;
906
907         pager_open_if_enabled();
908
909         r = sd_rtnl_open(&rtnl, 0);
910         if (r < 0)
911                 return log_error_errno(r, "Failed to connect to netlink: %m");
912
913         r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, 0);
914         if (r < 0)
915                 return rtnl_log_create_error(r);
916
917         r = sd_rtnl_message_request_dump(req, true);
918         if (r < 0)
919                 return rtnl_log_create_error(r);
920
921         r = sd_rtnl_call(rtnl, req, 0, &reply);
922         if (r < 0)
923                 return log_error_errno(r, "Failed to enumerate links: %m");
924
925         c = decode_and_sort_links(reply, &links);
926         if (c < 0)
927                 return rtnl_log_parse_error(c);
928
929         if (arg_legend)
930                 printf("%s %16s %24s %16s %16s\n", "Local Intf", "Device ID", "Port ID", "TTL", "Capability");
931
932         for (i = j = 0; i < c; i++) {
933                 _cleanup_free_ char *chassis = NULL, *port = NULL, *cap = NULL, *lldp = NULL;
934                 _cleanup_strv_free_ char **l = NULL;
935
936                 r = sd_network_link_get_lldp(links[i].ifindex, &lldp);
937                 if (r < 0)
938                         continue;
939
940                 l = strv_split_newlines(lldp);
941                 if (!l)
942                         return -ENOMEM;
943
944                 STRV_FOREACH(s, l) {
945                         FOREACH_WORD_QUOTED(word, ll, *s, state) {
946                                 _cleanup_free_ char *t = NULL, *a = NULL, *b = NULL;
947
948                                 t = strndup(word, ll);
949                                 if (!t)
950                                         return -ENOMEM;
951
952                                 r = split_pair(t, "=", &a, &b);
953                                 if (r < 0)
954                                         continue;
955
956                                 if (streq(a, "_Chassis")) {
957                                         chassis = strdup(b);
958                                         if (!chassis)
959                                                 return -ENOMEM;
960
961                                 } else if (streq(a, "_Port")) {
962                                         port = strdup(b);
963                                         if (!port)
964                                                 return -ENOMEM;
965
966                                 } else if (streq(a, "_TTL")) {
967                                         long long unsigned x;
968                                         usec_t time;
969
970                                         r = safe_atollu(b, &x);
971                                         if (r < 0 || (usec_t) x != x)
972                                                 return log_warning_errno(r < 0 ? r : ERANGE,
973                                                                          "Failed to parse TTL \"%s\": %m", b);
974
975                                         time = now(CLOCK_BOOTTIME);
976                                         if (x < time)
977                                                 continue;
978
979                                         ttl = (double) (x - time) / USEC_PER_SEC;
980
981                                 } else if (streq(a, "_CAP")) {
982                                         sscanf(b, "%x", &capability);
983
984                                         cap = lldp_system_caps(capability);
985                                 }
986
987                         }
988
989                         if (ttl >= 0) {
990                                 printf("%10s %24s %16s %16f %16s\n",
991                                        links[i].name,
992                                        strna(chassis), strna(port),
993                                        ttl, cap);
994                                 j++;
995                         }
996                 }
997         }
998
999         if (arg_legend) {
1000                 printf("\nCapability Codes:\n"
1001                        "(O) - Other, (P) - Repeater,  (B) - Bridge , (W) - WLAN Access Point, (R) = Router,\n"
1002                        "(T) - Telephone, (D) - Data Over Cable Service Interface Specifications, (A) - Station,\n"
1003                        "(C) - Customer VLAN, (S) - Service VLAN, (M) - Two-port MAC Relay (TPMR)\n\n");
1004
1005                 printf("Total entries displayed: %d\n", j);
1006         }
1007
1008         return 0;
1009 }
1010
1011 static void help(void) {
1012         printf("%s [OPTIONS...]\n\n"
1013                "Query and control the networking subsystem.\n\n"
1014                "  -h --help             Show this help\n"
1015                "     --version          Show package version\n"
1016                "     --no-pager         Do not pipe output into a pager\n"
1017                "     --no-legend        Do not show the headers and footers\n"
1018                "  -a --all              Show status for all links\n\n"
1019                "Commands:\n"
1020                "  list                  List links\n"
1021                "  status LINK           Show link status\n"
1022                "  lldp                  Show lldp information\n"
1023                , program_invocation_short_name);
1024 }
1025
1026 static int parse_argv(int argc, char *argv[]) {
1027
1028         enum {
1029                 ARG_VERSION = 0x100,
1030                 ARG_NO_PAGER,
1031                 ARG_NO_LEGEND,
1032         };
1033
1034         static const struct option options[] = {
1035                 { "help",      no_argument,       NULL, 'h'           },
1036                 { "version",   no_argument,       NULL, ARG_VERSION   },
1037                 { "no-pager",  no_argument,       NULL, ARG_NO_PAGER  },
1038                 { "no-legend", no_argument,       NULL, ARG_NO_LEGEND },
1039                 { "all",       no_argument,       NULL, 'a'           },
1040                 {}
1041         };
1042
1043         int c;
1044
1045         assert(argc >= 0);
1046         assert(argv);
1047
1048         while ((c = getopt_long(argc, argv, "ha", options, NULL)) >= 0) {
1049
1050                 switch (c) {
1051
1052                 case 'h':
1053                         help();
1054                         return 0;
1055
1056                 case ARG_VERSION:
1057                         puts(PACKAGE_STRING);
1058                         puts(SYSTEMD_FEATURES);
1059                         return 0;
1060
1061                 case ARG_NO_PAGER:
1062                         arg_no_pager = true;
1063                         break;
1064
1065                 case ARG_NO_LEGEND:
1066                         arg_legend = false;
1067                         break;
1068
1069                 case 'a':
1070                         arg_all = true;
1071                         break;
1072
1073                 case '?':
1074                         return -EINVAL;
1075
1076                 default:
1077                         assert_not_reached("Unhandled option");
1078                 }
1079         }
1080
1081         return 1;
1082 }
1083
1084 static int networkctl_main(int argc, char *argv[]) {
1085         const Verb verbs[] = {
1086                 { "list", VERB_ANY, 1, VERB_DEFAULT, list_links },
1087                 { "status", 1, VERB_ANY, 0, link_status },
1088                 { "lldp", VERB_ANY, 1, VERB_DEFAULT, link_lldp_status },
1089                 {}
1090         };
1091
1092         return dispatch_verb(argc, argv, verbs, NULL);
1093 }
1094
1095 int main(int argc, char* argv[]) {
1096         int r;
1097
1098         log_parse_environment();
1099         log_open();
1100
1101         r = parse_argv(argc, argv);
1102         if (r <= 0)
1103                 goto finish;
1104
1105         r = networkctl_main(argc, argv);
1106
1107 finish:
1108         pager_close();
1109
1110         return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
1111 }