LCOV - code coverage report
Current view: top level - network - networkctl.c (source / functions) Hit Total Coverage
Test: systemd_full.info Lines: 23 956 2.4 %
Date: 2019-08-23 13:36:53 Functions: 4 35 11.4 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 7 900 0.8 %

           Branch data     Line data    Source code
       1                 :            : /* SPDX-License-Identifier: LGPL-2.1+ */
       2                 :            : 
       3                 :            : #include <getopt.h>
       4                 :            : #include <linux/if_addrlabel.h>
       5                 :            : #include <net/if.h>
       6                 :            : #include <stdbool.h>
       7                 :            : #include <sys/stat.h>
       8                 :            : #include <sys/types.h>
       9                 :            : #include <unistd.h>
      10                 :            : 
      11                 :            : #include "sd-bus.h"
      12                 :            : #include "sd-device.h"
      13                 :            : #include "sd-hwdb.h"
      14                 :            : #include "sd-lldp.h"
      15                 :            : #include "sd-netlink.h"
      16                 :            : #include "sd-network.h"
      17                 :            : 
      18                 :            : #include "alloc-util.h"
      19                 :            : #include "arphrd-list.h"
      20                 :            : #include "bus-common-errors.h"
      21                 :            : #include "bus-error.h"
      22                 :            : #include "bus-util.h"
      23                 :            : #include "device-util.h"
      24                 :            : #include "ether-addr-util.h"
      25                 :            : #include "ethtool-util.h"
      26                 :            : #include "fd-util.h"
      27                 :            : #include "format-table.h"
      28                 :            : #include "format-util.h"
      29                 :            : #include "hwdb-util.h"
      30                 :            : #include "local-addresses.h"
      31                 :            : #include "locale-util.h"
      32                 :            : #include "macro.h"
      33                 :            : #include "main-func.h"
      34                 :            : #include "netlink-util.h"
      35                 :            : #include "pager.h"
      36                 :            : #include "parse-util.h"
      37                 :            : #include "pretty-print.h"
      38                 :            : #include "set.h"
      39                 :            : #include "socket-util.h"
      40                 :            : #include "sort-util.h"
      41                 :            : #include "sparse-endian.h"
      42                 :            : #include "stdio-util.h"
      43                 :            : #include "string-table.h"
      44                 :            : #include "string-util.h"
      45                 :            : #include "strv.h"
      46                 :            : #include "strxcpyx.h"
      47                 :            : #include "terminal-util.h"
      48                 :            : #include "verbs.h"
      49                 :            : 
      50                 :            : /* Kernel defines MODULE_NAME_LEN as 64 - sizeof(unsigned long). So, 64 is enough. */
      51                 :            : #define NETDEV_KIND_MAX 64
      52                 :            : 
      53                 :            : static PagerFlags arg_pager_flags = 0;
      54                 :            : static bool arg_legend = true;
      55                 :            : static bool arg_all = false;
      56                 :            : static bool arg_stats = false;
      57                 :            : 
      58                 :          0 : static char *link_get_type_string(unsigned short iftype, sd_device *d) {
      59                 :            :         const char *t, *devtype;
      60                 :            :         char *p;
      61                 :            : 
      62   [ #  #  #  # ]:          0 :         if (d &&
      63                 :          0 :             sd_device_get_devtype(d, &devtype) >= 0 &&
      64         [ #  # ]:          0 :             !isempty(devtype))
      65                 :          0 :                 return strdup(devtype);
      66                 :            : 
      67                 :          0 :         t = arphrd_to_name(iftype);
      68         [ #  # ]:          0 :         if (!t)
      69                 :          0 :                 return NULL;
      70                 :            : 
      71                 :          0 :         p = strdup(t);
      72         [ #  # ]:          0 :         if (!p)
      73                 :          0 :                 return NULL;
      74                 :            : 
      75                 :          0 :         ascii_strlower(p);
      76                 :          0 :         return p;
      77                 :            : }
      78                 :            : 
      79                 :          0 : static void operational_state_to_color(const char *state, const char **on, const char **off) {
      80         [ #  # ]:          0 :         assert(on);
      81         [ #  # ]:          0 :         assert(off);
      82                 :            : 
      83   [ #  #  #  #  :          0 :         if (STRPTR_IN_SET(state, "routable", "enslaved")) {
                   #  # ]
      84                 :          0 :                 *on = ansi_highlight_green();
      85                 :          0 :                 *off = ansi_normal();
      86         [ #  # ]:          0 :         } else if (streq_ptr(state, "degraded")) {
      87                 :          0 :                 *on = ansi_highlight_yellow();
      88                 :          0 :                 *off = ansi_normal();
      89                 :            :         } else
      90                 :          0 :                 *on = *off = "";
      91                 :          0 : }
      92                 :            : 
      93                 :          0 : static void setup_state_to_color(const char *state, const char **on, const char **off) {
      94         [ #  # ]:          0 :         assert(on);
      95         [ #  # ]:          0 :         assert(off);
      96                 :            : 
      97         [ #  # ]:          0 :         if (streq_ptr(state, "configured")) {
      98                 :          0 :                 *on = ansi_highlight_green();
      99                 :          0 :                 *off = ansi_normal();
     100         [ #  # ]:          0 :         } else if (streq_ptr(state, "configuring")) {
     101                 :          0 :                 *on = ansi_highlight_yellow();
     102                 :          0 :                 *off = ansi_normal();
     103   [ #  #  #  #  :          0 :         } else if (STRPTR_IN_SET(state, "failed", "linger")) {
                   #  # ]
     104                 :          0 :                 *on = ansi_highlight_red();
     105                 :          0 :                 *off = ansi_normal();
     106                 :            :         } else
     107                 :          0 :                 *on = *off = "";
     108                 :          0 : }
     109                 :            : 
     110                 :            : typedef struct VxLanInfo {
     111                 :            :         uint32_t vni;
     112                 :            :         uint32_t link;
     113                 :            : 
     114                 :            :         int local_family;
     115                 :            :         int group_family;
     116                 :            : 
     117                 :            :         union in_addr_union local;
     118                 :            :         union in_addr_union group;
     119                 :            : 
     120                 :            :         uint16_t dest_port;
     121                 :            : 
     122                 :            : } VxLanInfo;
     123                 :            : 
     124                 :            : typedef struct LinkInfo {
     125                 :            :         char name[IFNAMSIZ+1];
     126                 :            :         char netdev_kind[NETDEV_KIND_MAX];
     127                 :            :         int ifindex;
     128                 :            :         unsigned short iftype;
     129                 :            :         struct ether_addr mac_address;
     130                 :            :         uint32_t mtu;
     131                 :            :         uint32_t min_mtu;
     132                 :            :         uint32_t max_mtu;
     133                 :            :         uint32_t tx_queues;
     134                 :            :         uint32_t rx_queues;
     135                 :            : 
     136                 :            :         union {
     137                 :            :                 struct rtnl_link_stats64 stats64;
     138                 :            :                 struct rtnl_link_stats stats;
     139                 :            :         };
     140                 :            : 
     141                 :            :         uint64_t tx_bitrate;
     142                 :            :         uint64_t rx_bitrate;
     143                 :            : 
     144                 :            :         /* bridge info */
     145                 :            :         uint32_t forward_delay;
     146                 :            :         uint32_t hello_time;
     147                 :            :         uint32_t max_age;
     148                 :            :         uint32_t ageing_time;
     149                 :            :         uint32_t stp_state;
     150                 :            :         uint16_t priority;
     151                 :            :         uint8_t mcast_igmp_version;
     152                 :            : 
     153                 :            :         /* vxlan info */
     154                 :            :         VxLanInfo vxlan_info;
     155                 :            : 
     156                 :            :         /* ethtool info */
     157                 :            :         int autonegotiation;
     158                 :            :         size_t speed;
     159                 :            :         Duplex duplex;
     160                 :            :         NetDevPort port;
     161                 :            : 
     162                 :            :         bool has_mac_address:1;
     163                 :            :         bool has_tx_queues:1;
     164                 :            :         bool has_rx_queues:1;
     165                 :            :         bool has_stats64:1;
     166                 :            :         bool has_stats:1;
     167                 :            :         bool has_bitrates:1;
     168                 :            :         bool has_ethtool_link_info:1;
     169                 :            : } LinkInfo;
     170                 :            : 
     171                 :          0 : static int link_info_compare(const LinkInfo *a, const LinkInfo *b) {
     172         [ #  # ]:          0 :         return CMP(a->ifindex, b->ifindex);
     173                 :            : }
     174                 :            : 
     175                 :          0 : static int decode_netdev(sd_netlink_message *m, LinkInfo *info) {
     176                 :            :         const char *received_kind;
     177                 :            :         int r;
     178                 :            : 
     179         [ #  # ]:          0 :         assert(m);
     180         [ #  # ]:          0 :         assert(info);
     181                 :            : 
     182                 :          0 :         r = sd_netlink_message_enter_container(m, IFLA_LINKINFO);
     183         [ #  # ]:          0 :         if (r < 0)
     184                 :          0 :                 return r;
     185                 :            : 
     186                 :          0 :         r = sd_netlink_message_read_string(m, IFLA_INFO_KIND, &received_kind);
     187         [ #  # ]:          0 :         if (r < 0)
     188                 :          0 :                 return r;
     189                 :            : 
     190                 :          0 :         r = sd_netlink_message_enter_container(m, IFLA_INFO_DATA);
     191         [ #  # ]:          0 :         if (r < 0)
     192                 :          0 :                 return r;
     193                 :            : 
     194         [ #  # ]:          0 :         if (streq(received_kind, "bridge")) {
     195                 :          0 :                 (void) sd_netlink_message_read_u32(m, IFLA_BR_FORWARD_DELAY, &info->forward_delay);
     196                 :          0 :                 (void) sd_netlink_message_read_u32(m, IFLA_BR_HELLO_TIME, &info->hello_time);
     197                 :          0 :                 (void) sd_netlink_message_read_u32(m, IFLA_BR_MAX_AGE, &info->max_age);
     198                 :          0 :                 (void) sd_netlink_message_read_u32(m, IFLA_BR_AGEING_TIME, &info->ageing_time);
     199                 :          0 :                 (void) sd_netlink_message_read_u32(m, IFLA_BR_STP_STATE, &info->stp_state);
     200                 :          0 :                 (void) sd_netlink_message_read_u16(m, IFLA_BR_PRIORITY, &info->priority);
     201                 :          0 :                 (void) sd_netlink_message_read_u8(m, IFLA_BR_MCAST_IGMP_VERSION, &info->mcast_igmp_version);
     202                 :            : 
     203         [ #  # ]:          0 :         } else if (streq(received_kind, "vxlan")) {
     204                 :          0 :                 (void) sd_netlink_message_read_u32(m, IFLA_VXLAN_ID, &info->vxlan_info.vni);
     205                 :            : 
     206                 :          0 :                 r = sd_netlink_message_read_in_addr(m, IFLA_VXLAN_GROUP, &info->vxlan_info.group.in);
     207         [ #  # ]:          0 :                 if (r >= 0)
     208                 :          0 :                         info->vxlan_info.group_family = AF_INET;
     209                 :            :                 else {
     210                 :          0 :                         r = sd_netlink_message_read_in6_addr(m, IFLA_VXLAN_GROUP6, &info->vxlan_info.group.in6);
     211         [ #  # ]:          0 :                         if (r >= 0)
     212                 :          0 :                                 info->vxlan_info.group_family = AF_INET6;
     213                 :            :                 }
     214                 :            : 
     215                 :          0 :                 r = sd_netlink_message_read_in_addr(m, IFLA_VXLAN_LOCAL, &info->vxlan_info.local.in);
     216         [ #  # ]:          0 :                 if (r >= 0)
     217                 :          0 :                         info->vxlan_info.local_family = AF_INET;
     218                 :            :                 else {
     219                 :          0 :                         r = sd_netlink_message_read_in6_addr(m, IFLA_VXLAN_LOCAL6, &info->vxlan_info.local.in6);
     220         [ #  # ]:          0 :                         if (r >= 0)
     221                 :          0 :                                 info->vxlan_info.local_family = AF_INET6;
     222                 :            :                 }
     223                 :            : 
     224                 :          0 :                 (void) sd_netlink_message_read_u32(m, IFLA_VXLAN_LINK, &info->vxlan_info.link);
     225                 :          0 :                 (void) sd_netlink_message_read_u16(m, IFLA_VXLAN_PORT, &info->vxlan_info.dest_port);
     226                 :            :         }
     227                 :            : 
     228                 :          0 :         strncpy(info->netdev_kind, received_kind, IFNAMSIZ);
     229                 :            : 
     230                 :          0 :         (void) sd_netlink_message_exit_container(m);
     231                 :          0 :         (void) sd_netlink_message_exit_container(m);
     232                 :            : 
     233                 :          0 :         return 0;
     234                 :            : }
     235                 :            : 
     236                 :          0 : static int decode_link(sd_netlink_message *m, LinkInfo *info, char **patterns) {
     237                 :            :         const char *name;
     238                 :            :         int ifindex, r;
     239                 :            :         uint16_t type;
     240                 :            : 
     241         [ #  # ]:          0 :         assert(m);
     242         [ #  # ]:          0 :         assert(info);
     243                 :            : 
     244                 :          0 :         r = sd_netlink_message_get_type(m, &type);
     245         [ #  # ]:          0 :         if (r < 0)
     246                 :          0 :                 return r;
     247                 :            : 
     248         [ #  # ]:          0 :         if (type != RTM_NEWLINK)
     249                 :          0 :                 return 0;
     250                 :            : 
     251                 :          0 :         r = sd_rtnl_message_link_get_ifindex(m, &ifindex);
     252         [ #  # ]:          0 :         if (r < 0)
     253                 :          0 :                 return r;
     254                 :            : 
     255                 :          0 :         r = sd_netlink_message_read_string(m, IFLA_IFNAME, &name);
     256         [ #  # ]:          0 :         if (r < 0)
     257                 :          0 :                 return r;
     258                 :            : 
     259         [ #  # ]:          0 :         if (patterns) {
     260                 :            :                 char str[DECIMAL_STR_MAX(int)];
     261                 :            : 
     262         [ #  # ]:          0 :                 xsprintf(str, "%i", ifindex);
     263                 :            : 
     264   [ #  #  #  # ]:          0 :                 if (!strv_fnmatch(patterns, str, 0) && !strv_fnmatch(patterns, name, 0))
     265                 :          0 :                         return 0;
     266                 :            :         }
     267                 :            : 
     268                 :          0 :         r = sd_rtnl_message_link_get_type(m, &info->iftype);
     269         [ #  # ]:          0 :         if (r < 0)
     270                 :          0 :                 return r;
     271                 :            : 
     272                 :          0 :         strscpy(info->name, sizeof info->name, name);
     273                 :          0 :         info->ifindex = ifindex;
     274                 :            : 
     275                 :          0 :         info->has_mac_address =
     276         [ #  # ]:          0 :                 sd_netlink_message_read_ether_addr(m, IFLA_ADDRESS, &info->mac_address) >= 0 &&
     277         [ #  # ]:          0 :                 memcmp(&info->mac_address, &ETHER_ADDR_NULL, sizeof(struct ether_addr)) != 0;
     278                 :            : 
     279                 :          0 :         (void) sd_netlink_message_read_u32(m, IFLA_MTU, &info->mtu);
     280                 :          0 :         (void) sd_netlink_message_read_u32(m, IFLA_MIN_MTU, &info->min_mtu);
     281                 :          0 :         (void) sd_netlink_message_read_u32(m, IFLA_MAX_MTU, &info->max_mtu);
     282                 :            : 
     283                 :          0 :         info->has_rx_queues =
     284         [ #  # ]:          0 :                 sd_netlink_message_read_u32(m, IFLA_NUM_RX_QUEUES, &info->rx_queues) >= 0 &&
     285         [ #  # ]:          0 :                 info->rx_queues > 0;
     286                 :            : 
     287                 :          0 :         info->has_tx_queues =
     288         [ #  # ]:          0 :                 sd_netlink_message_read_u32(m, IFLA_NUM_TX_QUEUES, &info->tx_queues) >= 0 &&
     289         [ #  # ]:          0 :                 info->tx_queues > 0;
     290                 :            : 
     291         [ #  # ]:          0 :         if (sd_netlink_message_read(m, IFLA_STATS64, sizeof info->stats64, &info->stats64) >= 0)
     292                 :          0 :                 info->has_stats64 = true;
     293         [ #  # ]:          0 :         else if (sd_netlink_message_read(m, IFLA_STATS, sizeof info->stats, &info->stats) >= 0)
     294                 :          0 :                 info->has_stats = true;
     295                 :            : 
     296                 :            :         /* fill kind info */
     297                 :          0 :         (void) decode_netdev(m, info);
     298                 :            : 
     299                 :          0 :         return 1;
     300                 :            : }
     301                 :            : 
     302                 :          0 : static int acquire_link_bitrates(sd_bus *bus, LinkInfo *link) {
     303                 :          0 :         _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
     304                 :          0 :         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
     305                 :          0 :         _cleanup_free_ char *path = NULL, *ifindex_str = NULL;
     306                 :            :         int r;
     307                 :            : 
     308         [ #  # ]:          0 :         if (asprintf(&ifindex_str, "%i", link->ifindex) < 0)
     309                 :          0 :                 return -ENOMEM;
     310                 :            : 
     311                 :          0 :         r = sd_bus_path_encode("/org/freedesktop/network1/link", ifindex_str, &path);
     312         [ #  # ]:          0 :         if (r < 0)
     313                 :          0 :                 return r;
     314                 :            : 
     315                 :          0 :         r = sd_bus_call_method(
     316                 :            :                         bus,
     317                 :            :                         "org.freedesktop.network1",
     318                 :            :                         path,
     319                 :            :                         "org.freedesktop.DBus.Properties",
     320                 :            :                         "Get",
     321                 :            :                         &error,
     322                 :            :                         &reply,
     323                 :            :                         "ss",
     324                 :            :                         "org.freedesktop.network1.Link",
     325                 :            :                         "BitRates");
     326         [ #  # ]:          0 :         if (r < 0) {
     327   [ #  #  #  # ]:          0 :                 bool quiet = sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_PROPERTY) ||
     328                 :          0 :                              sd_bus_error_has_name(&error, BUS_ERROR_SPEED_METER_INACTIVE);
     329                 :            : 
     330   [ #  #  #  # ]:          0 :                 return log_full_errno(quiet ? LOG_DEBUG : LOG_WARNING,
     331                 :            :                                       r, "Failed to query link bit rates: %s", bus_error_message(&error, r));
     332                 :            :         }
     333                 :            : 
     334                 :          0 :         r = sd_bus_message_enter_container(reply, 'v', "(tt)");
     335         [ #  # ]:          0 :         if (r < 0)
     336         [ #  # ]:          0 :                 return bus_log_parse_error(r);
     337                 :            : 
     338                 :          0 :         r = sd_bus_message_read(reply, "(tt)", &link->tx_bitrate, &link->rx_bitrate);
     339         [ #  # ]:          0 :         if (r < 0)
     340         [ #  # ]:          0 :                 return bus_log_parse_error(r);
     341                 :            : 
     342                 :          0 :         r = sd_bus_message_exit_container(reply);
     343         [ #  # ]:          0 :         if (r < 0)
     344         [ #  # ]:          0 :                 return bus_log_parse_error(r);
     345                 :            : 
     346                 :          0 :         link->has_bitrates = true;
     347                 :            : 
     348                 :          0 :         return 0;
     349                 :            : }
     350                 :            : 
     351                 :          0 : static int acquire_link_info(sd_bus *bus, sd_netlink *rtnl, char **patterns, LinkInfo **ret) {
     352                 :          0 :         _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL;
     353                 :          0 :         _cleanup_free_ LinkInfo *links = NULL;
     354                 :          0 :         _cleanup_close_ int fd = -1;
     355                 :          0 :         size_t allocated = 0, c = 0, j;
     356                 :            :         sd_netlink_message *i;
     357                 :            :         int r;
     358                 :            : 
     359         [ #  # ]:          0 :         assert(rtnl);
     360         [ #  # ]:          0 :         assert(ret);
     361                 :            : 
     362                 :          0 :         r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, 0);
     363         [ #  # ]:          0 :         if (r < 0)
     364                 :          0 :                 return rtnl_log_create_error(r);
     365                 :            : 
     366                 :          0 :         r = sd_netlink_message_request_dump(req, true);
     367         [ #  # ]:          0 :         if (r < 0)
     368                 :          0 :                 return rtnl_log_create_error(r);
     369                 :            : 
     370                 :          0 :         r = sd_netlink_call(rtnl, req, 0, &reply);
     371         [ #  # ]:          0 :         if (r < 0)
     372         [ #  # ]:          0 :                 return log_error_errno(r, "Failed to enumerate links: %m");
     373                 :            : 
     374         [ #  # ]:          0 :         for (i = reply; i; i = sd_netlink_message_next(i)) {
     375         [ #  # ]:          0 :                 if (!GREEDY_REALLOC0(links, allocated, c+1))
     376                 :          0 :                         return -ENOMEM;
     377                 :            : 
     378                 :          0 :                 r = decode_link(i, links + c, patterns);
     379         [ #  # ]:          0 :                 if (r < 0)
     380                 :          0 :                         return r;
     381         [ #  # ]:          0 :                 if (r == 0)
     382                 :          0 :                         continue;
     383                 :            : 
     384                 :          0 :                 r = ethtool_get_link_info(&fd, links[c].name,
     385                 :          0 :                                           &links[c].autonegotiation, &links[c].speed,
     386                 :          0 :                                           &links[c].duplex, &links[c].port);
     387         [ #  # ]:          0 :                 if (r >= 0)
     388                 :          0 :                         links[c].has_ethtool_link_info = true;
     389                 :            : 
     390                 :          0 :                 c++;
     391                 :            :         }
     392                 :            : 
     393                 :          0 :         typesafe_qsort(links, c, link_info_compare);
     394                 :            : 
     395         [ #  # ]:          0 :         if (bus)
     396         [ #  # ]:          0 :                 for (j = 0; j < c; j++)
     397                 :          0 :                         (void) acquire_link_bitrates(bus, links + j);
     398                 :            : 
     399                 :          0 :         *ret = TAKE_PTR(links);
     400                 :            : 
     401                 :          0 :         return (int) c;
     402                 :            : }
     403                 :            : 
     404                 :          0 : static int list_links(int argc, char *argv[], void *userdata) {
     405                 :          0 :         _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
     406                 :          0 :         _cleanup_free_ LinkInfo *links = NULL;
     407                 :          0 :         _cleanup_(table_unrefp) Table *table = NULL;
     408                 :            :         TableCell *cell;
     409                 :            :         int c, i, r;
     410                 :            : 
     411                 :          0 :         r = sd_netlink_open(&rtnl);
     412         [ #  # ]:          0 :         if (r < 0)
     413         [ #  # ]:          0 :                 return log_error_errno(r, "Failed to connect to netlink: %m");
     414                 :            : 
     415         [ #  # ]:          0 :         c = acquire_link_info(NULL, rtnl, argc > 1 ? argv + 1 : NULL, &links);
     416         [ #  # ]:          0 :         if (c < 0)
     417                 :          0 :                 return c;
     418                 :            : 
     419                 :          0 :         (void) pager_open(arg_pager_flags);
     420                 :            : 
     421                 :          0 :         table = table_new("idx", "link", "type", "operational", "setup");
     422         [ #  # ]:          0 :         if (!table)
     423                 :          0 :                 return log_oom();
     424                 :            : 
     425                 :          0 :         table_set_header(table, arg_legend);
     426                 :            : 
     427         [ #  # ]:          0 :         assert_se(cell = table_get_cell(table, 0, 0));
     428                 :          0 :         (void) table_set_minimum_width(table, cell, 3);
     429                 :          0 :         (void) table_set_weight(table, cell, 0);
     430                 :          0 :         (void) table_set_ellipsize_percent(table, cell, 100);
     431                 :          0 :         (void) table_set_align_percent(table, cell, 100);
     432                 :            : 
     433         [ #  # ]:          0 :         assert_se(cell = table_get_cell(table, 0, 1));
     434                 :          0 :         (void) table_set_ellipsize_percent(table, cell, 100);
     435                 :            : 
     436         [ #  # ]:          0 :         for (i = 0; i < c; i++) {
     437   [ #  #  #  # ]:          0 :                 _cleanup_free_ char *setup_state = NULL, *operational_state = NULL;
     438         [ #  # ]:          0 :                 _cleanup_(sd_device_unrefp) sd_device *d = NULL;
     439                 :            :                 const char *on_color_operational, *off_color_operational,
     440                 :            :                            *on_color_setup, *off_color_setup;
     441                 :            :                 char devid[2 + DECIMAL_STR_MAX(int)];
     442         [ #  # ]:          0 :                 _cleanup_free_ char *t = NULL;
     443                 :            : 
     444                 :          0 :                 (void) sd_network_link_get_operational_state(links[i].ifindex, &operational_state);
     445                 :          0 :                 operational_state_to_color(operational_state, &on_color_operational, &off_color_operational);
     446                 :            : 
     447                 :          0 :                 r = sd_network_link_get_setup_state(links[i].ifindex, &setup_state);
     448         [ #  # ]:          0 :                 if (r == -ENODATA) /* If there's no info available about this iface, it's unmanaged by networkd */
     449                 :          0 :                         setup_state = strdup("unmanaged");
     450                 :          0 :                 setup_state_to_color(setup_state, &on_color_setup, &off_color_setup);
     451                 :            : 
     452         [ #  # ]:          0 :                 xsprintf(devid, "n%i", links[i].ifindex);
     453                 :          0 :                 (void) sd_device_new_from_device_id(&d, devid);
     454                 :            : 
     455                 :          0 :                 t = link_get_type_string(links[i].iftype, d);
     456                 :            : 
     457                 :          0 :                 r = table_add_many(table,
     458                 :            :                                    TABLE_INT, links[i].ifindex,
     459                 :            :                                    TABLE_STRING, links[i].name,
     460                 :            :                                    TABLE_STRING, strna(t),
     461                 :            :                                    TABLE_STRING, strna(operational_state),
     462                 :            :                                    TABLE_SET_COLOR, on_color_operational,
     463                 :            :                                    TABLE_STRING, strna(setup_state),
     464                 :            :                                    TABLE_SET_COLOR, on_color_setup);
     465         [ #  # ]:          0 :                 if (r < 0)
     466                 :          0 :                         return r;
     467                 :            :         }
     468                 :            : 
     469                 :          0 :         r = table_print(table, NULL);
     470         [ #  # ]:          0 :         if (r < 0)
     471         [ #  # ]:          0 :                 return log_error_errno(r, "Failed to print table: %m");
     472                 :            : 
     473         [ #  # ]:          0 :         if (arg_legend)
     474                 :          0 :                 printf("\n%i links listed.\n", c);
     475                 :            : 
     476                 :          0 :         return 0;
     477                 :            : }
     478                 :            : 
     479                 :            : /* IEEE Organizationally Unique Identifier vendor string */
     480                 :          0 : static int ieee_oui(sd_hwdb *hwdb, const struct ether_addr *mac, char **ret) {
     481                 :            :         const char *description;
     482                 :            :         char modalias[STRLEN("OUI:XXYYXXYYXXYY") + 1], *desc;
     483                 :            :         int r;
     484                 :            : 
     485         [ #  # ]:          0 :         assert(ret);
     486                 :            : 
     487         [ #  # ]:          0 :         if (!hwdb)
     488                 :          0 :                 return -EINVAL;
     489                 :            : 
     490         [ #  # ]:          0 :         if (!mac)
     491                 :          0 :                 return -EINVAL;
     492                 :            : 
     493                 :            :         /* skip commonly misused 00:00:00 (Xerox) prefix */
     494         [ #  # ]:          0 :         if (memcmp(mac, "\0\0\0", 3) == 0)
     495                 :          0 :                 return -EINVAL;
     496                 :            : 
     497         [ #  # ]:          0 :         xsprintf(modalias, "OUI:" ETHER_ADDR_FORMAT_STR,
     498                 :            :                  ETHER_ADDR_FORMAT_VAL(*mac));
     499                 :            : 
     500                 :          0 :         r = sd_hwdb_get(hwdb, modalias, "ID_OUI_FROM_DATABASE", &description);
     501         [ #  # ]:          0 :         if (r < 0)
     502                 :          0 :                 return r;
     503                 :            : 
     504                 :          0 :         desc = strdup(description);
     505         [ #  # ]:          0 :         if (!desc)
     506                 :          0 :                 return -ENOMEM;
     507                 :            : 
     508                 :          0 :         *ret = desc;
     509                 :            : 
     510                 :          0 :         return 0;
     511                 :            : }
     512                 :            : 
     513                 :          0 : static int get_gateway_description(
     514                 :            :                 sd_netlink *rtnl,
     515                 :            :                 sd_hwdb *hwdb,
     516                 :            :                 int ifindex,
     517                 :            :                 int family,
     518                 :            :                 union in_addr_union *gateway,
     519                 :            :                 char **gateway_description) {
     520                 :          0 :         _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL;
     521                 :            :         sd_netlink_message *m;
     522                 :            :         int r;
     523                 :            : 
     524         [ #  # ]:          0 :         assert(rtnl);
     525         [ #  # ]:          0 :         assert(ifindex >= 0);
     526   [ #  #  #  # ]:          0 :         assert(IN_SET(family, AF_INET, AF_INET6));
     527         [ #  # ]:          0 :         assert(gateway);
     528         [ #  # ]:          0 :         assert(gateway_description);
     529                 :            : 
     530                 :          0 :         r = sd_rtnl_message_new_neigh(rtnl, &req, RTM_GETNEIGH, ifindex, family);
     531         [ #  # ]:          0 :         if (r < 0)
     532                 :          0 :                 return r;
     533                 :            : 
     534                 :          0 :         r = sd_netlink_message_request_dump(req, true);
     535         [ #  # ]:          0 :         if (r < 0)
     536                 :          0 :                 return r;
     537                 :            : 
     538                 :          0 :         r = sd_netlink_call(rtnl, req, 0, &reply);
     539         [ #  # ]:          0 :         if (r < 0)
     540                 :          0 :                 return r;
     541                 :            : 
     542         [ #  # ]:          0 :         for (m = reply; m; m = sd_netlink_message_next(m)) {
     543                 :          0 :                 union in_addr_union gw = IN_ADDR_NULL;
     544                 :          0 :                 struct ether_addr mac = ETHER_ADDR_NULL;
     545                 :            :                 uint16_t type;
     546                 :            :                 int ifi, fam;
     547                 :            : 
     548                 :          0 :                 r = sd_netlink_message_get_errno(m);
     549         [ #  # ]:          0 :                 if (r < 0) {
     550         [ #  # ]:          0 :                         log_error_errno(r, "got error: %m");
     551                 :          0 :                         continue;
     552                 :            :                 }
     553                 :            : 
     554                 :          0 :                 r = sd_netlink_message_get_type(m, &type);
     555         [ #  # ]:          0 :                 if (r < 0) {
     556         [ #  # ]:          0 :                         log_error_errno(r, "could not get type: %m");
     557                 :          0 :                         continue;
     558                 :            :                 }
     559                 :            : 
     560         [ #  # ]:          0 :                 if (type != RTM_NEWNEIGH) {
     561         [ #  # ]:          0 :                         log_error("type is not RTM_NEWNEIGH");
     562                 :          0 :                         continue;
     563                 :            :                 }
     564                 :            : 
     565                 :          0 :                 r = sd_rtnl_message_neigh_get_family(m, &fam);
     566         [ #  # ]:          0 :                 if (r < 0) {
     567         [ #  # ]:          0 :                         log_error_errno(r, "could not get family: %m");
     568                 :          0 :                         continue;
     569                 :            :                 }
     570                 :            : 
     571         [ #  # ]:          0 :                 if (fam != family) {
     572         [ #  # ]:          0 :                         log_error("family is not correct");
     573                 :          0 :                         continue;
     574                 :            :                 }
     575                 :            : 
     576                 :          0 :                 r = sd_rtnl_message_neigh_get_ifindex(m, &ifi);
     577         [ #  # ]:          0 :                 if (r < 0) {
     578         [ #  # ]:          0 :                         log_error_errno(r, "could not get ifindex: %m");
     579                 :          0 :                         continue;
     580                 :            :                 }
     581                 :            : 
     582   [ #  #  #  # ]:          0 :                 if (ifindex > 0 && ifi != ifindex)
     583                 :          0 :                         continue;
     584                 :            : 
     585      [ #  #  # ]:          0 :                 switch (fam) {
     586                 :          0 :                 case AF_INET:
     587                 :          0 :                         r = sd_netlink_message_read_in_addr(m, NDA_DST, &gw.in);
     588         [ #  # ]:          0 :                         if (r < 0)
     589                 :          0 :                                 continue;
     590                 :            : 
     591                 :          0 :                         break;
     592                 :          0 :                 case AF_INET6:
     593                 :          0 :                         r = sd_netlink_message_read_in6_addr(m, NDA_DST, &gw.in6);
     594         [ #  # ]:          0 :                         if (r < 0)
     595                 :          0 :                                 continue;
     596                 :            : 
     597                 :          0 :                         break;
     598                 :          0 :                 default:
     599                 :          0 :                         continue;
     600                 :            :                 }
     601                 :            : 
     602         [ #  # ]:          0 :                 if (!in_addr_equal(fam, &gw, gateway))
     603                 :          0 :                         continue;
     604                 :            : 
     605                 :          0 :                 r = sd_netlink_message_read(m, NDA_LLADDR, sizeof(mac), &mac);
     606         [ #  # ]:          0 :                 if (r < 0)
     607                 :          0 :                         continue;
     608                 :            : 
     609                 :          0 :                 r = ieee_oui(hwdb, &mac, gateway_description);
     610         [ #  # ]:          0 :                 if (r < 0)
     611                 :          0 :                         continue;
     612                 :            : 
     613                 :          0 :                 return 0;
     614                 :            :         }
     615                 :            : 
     616                 :          0 :         return -ENODATA;
     617                 :            : }
     618                 :            : 
     619                 :          0 : static int dump_gateways(
     620                 :            :                 sd_netlink *rtnl,
     621                 :            :                 sd_hwdb *hwdb,
     622                 :            :                 Table *table,
     623                 :            :                 int ifindex) {
     624                 :          0 :         _cleanup_free_ struct local_address *local = NULL;
     625                 :            :         int r, n, i;
     626                 :            : 
     627         [ #  # ]:          0 :         assert(rtnl);
     628         [ #  # ]:          0 :         assert(table);
     629                 :            : 
     630                 :          0 :         n = local_gateways(rtnl, ifindex, AF_UNSPEC, &local);
     631         [ #  # ]:          0 :         if (n < 0)
     632                 :          0 :                 return n;
     633                 :            : 
     634         [ #  # ]:          0 :         for (i = 0; i < n; i++) {
     635   [ #  #  #  #  :          0 :                 _cleanup_free_ char *gateway = NULL, *description = NULL, *with_description = NULL;
                   #  # ]
     636                 :            : 
     637         [ #  # ]:          0 :                 r = table_add_many(table,
     638                 :            :                                    TABLE_EMPTY,
     639                 :            :                                    TABLE_STRING, i == 0 ? "Gateway:" : "");
     640         [ #  # ]:          0 :                 if (r < 0)
     641                 :          0 :                         return r;
     642                 :            : 
     643                 :          0 :                 r = in_addr_to_string(local[i].family, &local[i].address, &gateway);
     644         [ #  # ]:          0 :                 if (r < 0)
     645                 :          0 :                         return r;
     646                 :            : 
     647                 :          0 :                 r = get_gateway_description(rtnl, hwdb, local[i].ifindex, local[i].family, &local[i].address, &description);
     648         [ #  # ]:          0 :                 if (r < 0)
     649         [ #  # ]:          0 :                         log_debug_errno(r, "Could not get description of gateway: %m");
     650                 :            : 
     651         [ #  # ]:          0 :                 if (description) {
     652                 :          0 :                         with_description = strjoin(gateway, " (", description, ")");
     653         [ #  # ]:          0 :                         if (!with_description)
     654                 :          0 :                                 return -ENOMEM;
     655                 :            :                 }
     656                 :            : 
     657                 :            :                 /* Show interface name for the entry if we show
     658                 :            :                  * entries for all interfaces */
     659         [ #  # ]:          0 :                 if (ifindex <= 0) {
     660                 :            :                         char name[IF_NAMESIZE+1];
     661                 :            : 
     662         [ #  # ]:          0 :                         if (format_ifname(local[i].ifindex, name))
     663         [ #  # ]:          0 :                                 r = table_add_cell_stringf(table, NULL, "%s on %s", with_description ?: gateway, name);
     664                 :            :                         else
     665         [ #  # ]:          0 :                                 r = table_add_cell_stringf(table, NULL, "%s on %%%i", with_description ?: gateway, local[i].ifindex);
     666                 :            :                 } else
     667         [ #  # ]:          0 :                         r = table_add_cell(table, NULL, TABLE_STRING, with_description ?: gateway);
     668         [ #  # ]:          0 :                 if (r < 0)
     669                 :          0 :                         return r;
     670                 :            :         }
     671                 :            : 
     672                 :          0 :         return 0;
     673                 :            : }
     674                 :            : 
     675                 :          0 : static int dump_addresses(
     676                 :            :                 sd_netlink *rtnl,
     677                 :            :                 Table *table,
     678                 :            :                 int ifindex) {
     679                 :            : 
     680                 :          0 :         _cleanup_free_ struct local_address *local = NULL;
     681                 :            :         int r, n, i;
     682                 :            : 
     683         [ #  # ]:          0 :         assert(rtnl);
     684         [ #  # ]:          0 :         assert(table);
     685                 :            : 
     686                 :          0 :         n = local_addresses(rtnl, ifindex, AF_UNSPEC, &local);
     687         [ #  # ]:          0 :         if (n < 0)
     688                 :          0 :                 return n;
     689                 :            : 
     690         [ #  # ]:          0 :         for (i = 0; i < n; i++) {
     691         [ #  # ]:          0 :                 _cleanup_free_ char *pretty = NULL;
     692                 :            : 
     693         [ #  # ]:          0 :                 r = table_add_many(table,
     694                 :            :                                    TABLE_EMPTY,
     695                 :            :                                    TABLE_STRING, i == 0 ? "Address:" : "");
     696         [ #  # ]:          0 :                 if (r < 0)
     697                 :          0 :                         return r;
     698                 :            : 
     699                 :          0 :                 r = in_addr_to_string(local[i].family, &local[i].address, &pretty);
     700         [ #  # ]:          0 :                 if (r < 0)
     701                 :          0 :                         return r;
     702                 :            : 
     703         [ #  # ]:          0 :                 if (ifindex <= 0) {
     704                 :            :                         char name[IF_NAMESIZE+1];
     705                 :            : 
     706         [ #  # ]:          0 :                         if (format_ifname(local[i].ifindex, name))
     707                 :          0 :                                 r = table_add_cell_stringf(table, NULL, "%s on %s", pretty, name);
     708                 :            :                         else
     709                 :          0 :                                 r = table_add_cell_stringf(table, NULL, "%s on %%%i", pretty, local[i].ifindex);
     710                 :            :                 } else
     711                 :          0 :                         r = table_add_cell(table, NULL, TABLE_STRING, pretty);
     712         [ #  # ]:          0 :                 if (r < 0)
     713                 :          0 :                         return r;
     714                 :            :         }
     715                 :            : 
     716                 :          0 :         return 0;
     717                 :            : }
     718                 :            : 
     719                 :          0 : static int dump_address_labels(sd_netlink *rtnl) {
     720                 :          0 :         _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL;
     721                 :          0 :         _cleanup_(table_unrefp) Table *table = NULL;
     722                 :            :         sd_netlink_message *m;
     723                 :            :         TableCell *cell;
     724                 :            :         int r;
     725                 :            : 
     726         [ #  # ]:          0 :         assert(rtnl);
     727                 :            : 
     728                 :          0 :         r = sd_rtnl_message_new_addrlabel(rtnl, &req, RTM_GETADDRLABEL, 0, AF_INET6);
     729         [ #  # ]:          0 :         if (r < 0)
     730         [ #  # ]:          0 :                 return log_error_errno(r, "Could not allocate RTM_GETADDRLABEL message: %m");
     731                 :            : 
     732                 :          0 :         r = sd_netlink_message_request_dump(req, true);
     733         [ #  # ]:          0 :         if (r < 0)
     734                 :          0 :                 return r;
     735                 :            : 
     736                 :          0 :         r = sd_netlink_call(rtnl, req, 0, &reply);
     737         [ #  # ]:          0 :         if (r < 0)
     738                 :          0 :                 return r;
     739                 :            : 
     740                 :          0 :         table = table_new("label", "prefix/prefixlen");
     741         [ #  # ]:          0 :         if (!table)
     742                 :          0 :                 return -ENOMEM;
     743                 :            : 
     744                 :          0 :         r = table_set_sort(table, 0, SIZE_MAX);
     745         [ #  # ]:          0 :         if (r < 0)
     746                 :          0 :                 return r;
     747                 :            : 
     748         [ #  # ]:          0 :         assert_se(cell = table_get_cell(table, 0, 0));
     749                 :          0 :         (void) table_set_align_percent(table, cell, 100);
     750                 :          0 :         (void) table_set_ellipsize_percent(table, cell, 100);
     751                 :            : 
     752         [ #  # ]:          0 :         assert_se(cell = table_get_cell(table, 0, 1));
     753                 :          0 :         (void) table_set_align_percent(table, cell, 100);
     754                 :            : 
     755         [ #  # ]:          0 :         for (m = reply; m; m = sd_netlink_message_next(m)) {
     756      [ #  #  # ]:          0 :                 _cleanup_free_ char *pretty = NULL;
     757                 :          0 :                 union in_addr_union prefix = IN_ADDR_NULL;
     758                 :            :                 uint8_t prefixlen;
     759                 :            :                 uint32_t label;
     760                 :            : 
     761                 :          0 :                 r = sd_netlink_message_get_errno(m);
     762         [ #  # ]:          0 :                 if (r < 0) {
     763         [ #  # ]:          0 :                         log_error_errno(r, "got error: %m");
     764                 :          0 :                         continue;
     765                 :            :                 }
     766                 :            : 
     767                 :          0 :                 r = sd_netlink_message_read_u32(m, IFAL_LABEL, &label);
     768   [ #  #  #  # ]:          0 :                 if (r < 0 && r != -ENODATA) {
     769         [ #  # ]:          0 :                         log_error_errno(r, "Could not read IFAL_LABEL, ignoring: %m");
     770                 :          0 :                         continue;
     771                 :            :                 }
     772                 :            : 
     773                 :          0 :                 r = sd_netlink_message_read_in6_addr(m, IFAL_ADDRESS, &prefix.in6);
     774         [ #  # ]:          0 :                 if (r < 0)
     775                 :          0 :                         continue;
     776                 :            : 
     777                 :          0 :                 r = in_addr_to_string(AF_INET6, &prefix, &pretty);
     778         [ #  # ]:          0 :                 if (r < 0)
     779                 :          0 :                         continue;
     780                 :            : 
     781                 :          0 :                 r = sd_rtnl_message_addrlabel_get_prefixlen(m, &prefixlen);
     782         [ #  # ]:          0 :                 if (r < 0)
     783                 :          0 :                         continue;
     784                 :            : 
     785                 :          0 :                 r = table_add_cell(table, NULL, TABLE_UINT32, &label);
     786         [ #  # ]:          0 :                 if (r < 0)
     787                 :          0 :                         return r;
     788                 :            : 
     789                 :          0 :                 r = table_add_cell_stringf(table, NULL, "%s/%u", pretty, prefixlen);
     790         [ #  # ]:          0 :                 if (r < 0)
     791                 :          0 :                         return r;
     792                 :            :         }
     793                 :            : 
     794                 :          0 :         return table_print(table, NULL);
     795                 :            : }
     796                 :            : 
     797                 :          0 : static int list_address_labels(int argc, char *argv[], void *userdata) {
     798                 :          0 :         _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
     799                 :            :         int r;
     800                 :            : 
     801                 :          0 :         r = sd_netlink_open(&rtnl);
     802         [ #  # ]:          0 :         if (r < 0)
     803         [ #  # ]:          0 :                 return log_error_errno(r, "Failed to connect to netlink: %m");
     804                 :            : 
     805                 :          0 :         dump_address_labels(rtnl);
     806                 :            : 
     807                 :          0 :         return 0;
     808                 :            : }
     809                 :            : 
     810                 :          0 : static int open_lldp_neighbors(int ifindex, FILE **ret) {
     811                 :          0 :         _cleanup_free_ char *p = NULL;
     812                 :            :         FILE *f;
     813                 :            : 
     814         [ #  # ]:          0 :         if (asprintf(&p, "/run/systemd/netif/lldp/%i", ifindex) < 0)
     815                 :          0 :                 return -ENOMEM;
     816                 :            : 
     817                 :          0 :         f = fopen(p, "re");
     818         [ #  # ]:          0 :         if (!f)
     819                 :          0 :                 return -errno;
     820                 :            : 
     821                 :          0 :         *ret = f;
     822                 :          0 :         return 0;
     823                 :            : }
     824                 :            : 
     825                 :          0 : static int next_lldp_neighbor(FILE *f, sd_lldp_neighbor **ret) {
     826                 :          0 :         _cleanup_free_ void *raw = NULL;
     827                 :            :         size_t l;
     828                 :            :         le64_t u;
     829                 :            :         int r;
     830                 :            : 
     831         [ #  # ]:          0 :         assert(f);
     832         [ #  # ]:          0 :         assert(ret);
     833                 :            : 
     834                 :          0 :         l = fread(&u, 1, sizeof(u), f);
     835   [ #  #  #  # ]:          0 :         if (l == 0 && feof(f))
     836                 :          0 :                 return 0;
     837         [ #  # ]:          0 :         if (l != sizeof(u))
     838                 :          0 :                 return -EBADMSG;
     839                 :            : 
     840                 :            :         /* each LLDP packet is at most MTU size, but let's allow up to 4KiB just in case */
     841         [ #  # ]:          0 :         if (le64toh(u) >= 4096)
     842                 :          0 :                 return -EBADMSG;
     843                 :            : 
     844                 :          0 :         raw = new(uint8_t, le64toh(u));
     845         [ #  # ]:          0 :         if (!raw)
     846                 :          0 :                 return -ENOMEM;
     847                 :            : 
     848         [ #  # ]:          0 :         if (fread(raw, 1, le64toh(u), f) != le64toh(u))
     849                 :          0 :                 return -EBADMSG;
     850                 :            : 
     851                 :          0 :         r = sd_lldp_neighbor_from_raw(ret, raw, le64toh(u));
     852         [ #  # ]:          0 :         if (r < 0)
     853                 :          0 :                 return r;
     854                 :            : 
     855                 :          0 :         return 1;
     856                 :            : }
     857                 :            : 
     858                 :          0 : static int dump_lldp_neighbors(Table *table, const char *prefix, int ifindex) {
     859                 :          0 :         _cleanup_fclose_ FILE *f = NULL;
     860                 :          0 :         int r, c = 0;
     861                 :            : 
     862         [ #  # ]:          0 :         assert(table);
     863         [ #  # ]:          0 :         assert(prefix);
     864         [ #  # ]:          0 :         assert(ifindex > 0);
     865                 :            : 
     866                 :          0 :         r = open_lldp_neighbors(ifindex, &f);
     867         [ #  # ]:          0 :         if (r == -ENOENT)
     868                 :          0 :                 return 0;
     869         [ #  # ]:          0 :         if (r < 0)
     870                 :          0 :                 return r;
     871                 :            : 
     872                 :          0 :         for (;;) {
     873                 :          0 :                 const char *system_name = NULL, *port_id = NULL, *port_description = NULL;
     874      [ #  #  # ]:          0 :                 _cleanup_(sd_lldp_neighbor_unrefp) sd_lldp_neighbor *n = NULL;
     875                 :            : 
     876                 :          0 :                 r = next_lldp_neighbor(f, &n);
     877         [ #  # ]:          0 :                 if (r < 0)
     878                 :          0 :                         return r;
     879         [ #  # ]:          0 :                 if (r == 0)
     880                 :          0 :                         break;
     881                 :            : 
     882         [ #  # ]:          0 :                 r = table_add_many(table,
     883                 :            :                                    TABLE_EMPTY,
     884                 :            :                                    TABLE_STRING, c == 0 ? prefix : "");
     885         [ #  # ]:          0 :                 if (r < 0)
     886                 :          0 :                         return r;
     887                 :            : 
     888                 :          0 :                 (void) sd_lldp_neighbor_get_system_name(n, &system_name);
     889                 :          0 :                 (void) sd_lldp_neighbor_get_port_id_as_string(n, &port_id);
     890                 :          0 :                 (void) sd_lldp_neighbor_get_port_description(n, &port_description);
     891                 :            : 
     892   [ #  #  #  # ]:          0 :                 r = table_add_cell_stringf(table, NULL,
     893                 :            :                                            "%s on port %s%s%s%s",
     894                 :            :                                            strna(system_name), strna(port_id),
     895                 :          0 :                                            isempty(port_description) ? "" : " (",
     896                 :            :                                            strempty(port_description),
     897                 :          0 :                                            isempty(port_description) ? "" : ")");
     898         [ #  # ]:          0 :                 if (r < 0)
     899                 :          0 :                         return r;
     900                 :            : 
     901                 :          0 :                 c++;
     902                 :            :         }
     903                 :            : 
     904                 :          0 :         return c;
     905                 :            : }
     906                 :            : 
     907                 :          0 : static int dump_ifindexes(Table *table, const char *prefix, const int *ifindexes) {
     908                 :            :         unsigned c;
     909                 :            :         int r;
     910                 :            : 
     911         [ #  # ]:          0 :         assert(prefix);
     912                 :            : 
     913   [ #  #  #  # ]:          0 :         if (!ifindexes || ifindexes[0] <= 0)
     914                 :          0 :                 return 0;
     915                 :            : 
     916         [ #  # ]:          0 :         for (c = 0; ifindexes[c] > 0; c++) {
     917         [ #  # ]:          0 :                 r = table_add_many(table,
     918                 :            :                                    TABLE_EMPTY,
     919                 :            :                                    TABLE_STRING, c == 0 ? prefix : "",
     920                 :            :                                    TABLE_IFINDEX, ifindexes[c]);
     921         [ #  # ]:          0 :                 if (r < 0)
     922                 :          0 :                         return r;
     923                 :            :         }
     924                 :            : 
     925                 :          0 :         return 0;
     926                 :            : }
     927                 :            : 
     928                 :          0 : static int dump_list(Table *table, const char *prefix, char **l) {
     929                 :            :         char **i;
     930                 :            :         int r;
     931                 :            : 
     932         [ #  # ]:          0 :         if (strv_isempty(l))
     933                 :          0 :                 return 0;
     934                 :            : 
     935   [ #  #  #  # ]:          0 :         STRV_FOREACH(i, l) {
     936         [ #  # ]:          0 :                 r = table_add_many(table,
     937                 :            :                                    TABLE_EMPTY,
     938                 :            :                                    TABLE_STRING, i == l ? prefix : "",
     939                 :            :                                    TABLE_STRING, *i);
     940         [ #  # ]:          0 :                 if (r < 0)
     941                 :          0 :                         return r;
     942                 :            :         }
     943                 :            : 
     944                 :          0 :         return 0;
     945                 :            : }
     946                 :            : 
     947                 :            : #define DUMP_STATS_ONE(name, val_name)                                  \
     948                 :            :         r = table_add_many(table,                                       \
     949                 :            :                            TABLE_EMPTY,                                 \
     950                 :            :                            TABLE_STRING, name ":");                     \
     951                 :            :         if (r < 0)                                                      \
     952                 :            :                 return r;                                               \
     953                 :            :         r = table_add_cell(table, NULL,                                 \
     954                 :            :                            info->has_stats64 ? TABLE_UINT64 : TABLE_UINT32, \
     955                 :            :                            info->has_stats64 ? (void*) &info->stats64.val_name : (void*) &info->stats.val_name); \
     956                 :            :         if (r < 0)                                                      \
     957                 :            :                 return r;
     958                 :            : 
     959                 :          0 : static int dump_statistics(Table *table, const LinkInfo *info) {
     960                 :            :         int r;
     961                 :            : 
     962         [ #  # ]:          0 :         if (!arg_stats)
     963                 :          0 :                 return 0;
     964                 :            : 
     965   [ #  #  #  # ]:          0 :         if (!info->has_stats64 && !info->has_stats)
     966                 :          0 :                 return 0;
     967                 :            : 
     968   [ #  #  #  #  :          0 :         DUMP_STATS_ONE("Rx Packets", rx_packets);
             #  #  #  # ]
     969   [ #  #  #  #  :          0 :         DUMP_STATS_ONE("Tx Packets", tx_packets);
             #  #  #  # ]
     970   [ #  #  #  #  :          0 :         DUMP_STATS_ONE("Rx Bytes", rx_bytes);
             #  #  #  # ]
     971   [ #  #  #  #  :          0 :         DUMP_STATS_ONE("Tx Bytes", tx_bytes);
             #  #  #  # ]
     972   [ #  #  #  #  :          0 :         DUMP_STATS_ONE("Rx Errors", rx_errors);
             #  #  #  # ]
     973   [ #  #  #  #  :          0 :         DUMP_STATS_ONE("Tx Errors", tx_errors);
             #  #  #  # ]
     974   [ #  #  #  #  :          0 :         DUMP_STATS_ONE("Rx Dropped", rx_dropped);
             #  #  #  # ]
     975   [ #  #  #  #  :          0 :         DUMP_STATS_ONE("Tx Dropped", tx_dropped);
             #  #  #  # ]
     976   [ #  #  #  #  :          0 :         DUMP_STATS_ONE("Multicast Packets", multicast);
             #  #  #  # ]
     977   [ #  #  #  #  :          0 :         DUMP_STATS_ONE("Collisions", collisions);
             #  #  #  # ]
     978                 :            : 
     979                 :          0 :         return 0;
     980                 :            : }
     981                 :            : 
     982                 :          0 : static int link_status_one(
     983                 :            :                 sd_netlink *rtnl,
     984                 :            :                 sd_hwdb *hwdb,
     985                 :            :                 const LinkInfo *info) {
     986                 :            : 
     987                 :          0 :         _cleanup_strv_free_ char **dns = NULL, **ntp = NULL, **search_domains = NULL, **route_domains = NULL;
     988                 :          0 :         _cleanup_free_ char *setup_state = NULL, *operational_state = NULL, *tz = NULL;
     989                 :          0 :         _cleanup_(sd_device_unrefp) sd_device *d = NULL;
     990                 :            :         char devid[2 + DECIMAL_STR_MAX(int)];
     991                 :          0 :         _cleanup_free_ char *t = NULL, *network = NULL;
     992                 :          0 :         const char *driver = NULL, *path = NULL, *vendor = NULL, *model = NULL, *link = NULL;
     993                 :            :         const char *on_color_operational, *off_color_operational,
     994                 :            :                 *on_color_setup, *off_color_setup;
     995                 :          0 :         _cleanup_free_ int *carrier_bound_to = NULL, *carrier_bound_by = NULL;
     996                 :          0 :         _cleanup_(table_unrefp) Table *table = NULL;
     997                 :            :         TableCell *cell;
     998                 :            :         int r;
     999                 :            : 
    1000         [ #  # ]:          0 :         assert(rtnl);
    1001         [ #  # ]:          0 :         assert(info);
    1002                 :            : 
    1003                 :          0 :         (void) sd_network_link_get_operational_state(info->ifindex, &operational_state);
    1004                 :          0 :         operational_state_to_color(operational_state, &on_color_operational, &off_color_operational);
    1005                 :            : 
    1006                 :          0 :         r = sd_network_link_get_setup_state(info->ifindex, &setup_state);
    1007         [ #  # ]:          0 :         if (r == -ENODATA) /* If there's no info available about this iface, it's unmanaged by networkd */
    1008                 :          0 :                 setup_state = strdup("unmanaged");
    1009                 :          0 :         setup_state_to_color(setup_state, &on_color_setup, &off_color_setup);
    1010                 :            : 
    1011                 :          0 :         (void) sd_network_link_get_dns(info->ifindex, &dns);
    1012                 :          0 :         (void) sd_network_link_get_search_domains(info->ifindex, &search_domains);
    1013                 :          0 :         (void) sd_network_link_get_route_domains(info->ifindex, &route_domains);
    1014                 :          0 :         (void) sd_network_link_get_ntp(info->ifindex, &ntp);
    1015                 :            : 
    1016         [ #  # ]:          0 :         xsprintf(devid, "n%i", info->ifindex);
    1017                 :            : 
    1018                 :          0 :         (void) sd_device_new_from_device_id(&d, devid);
    1019                 :            : 
    1020         [ #  # ]:          0 :         if (d) {
    1021                 :          0 :                 (void) sd_device_get_property_value(d, "ID_NET_LINK_FILE", &link);
    1022                 :          0 :                 (void) sd_device_get_property_value(d, "ID_NET_DRIVER", &driver);
    1023                 :          0 :                 (void) sd_device_get_property_value(d, "ID_PATH", &path);
    1024                 :            : 
    1025         [ #  # ]:          0 :                 if (sd_device_get_property_value(d, "ID_VENDOR_FROM_DATABASE", &vendor) < 0)
    1026                 :          0 :                         (void) sd_device_get_property_value(d, "ID_VENDOR", &vendor);
    1027                 :            : 
    1028         [ #  # ]:          0 :                 if (sd_device_get_property_value(d, "ID_MODEL_FROM_DATABASE", &model) < 0)
    1029                 :          0 :                         (void) sd_device_get_property_value(d, "ID_MODEL", &model);
    1030                 :            :         }
    1031                 :            : 
    1032                 :          0 :         t = link_get_type_string(info->iftype, d);
    1033                 :            : 
    1034                 :          0 :         (void) sd_network_link_get_network_file(info->ifindex, &network);
    1035                 :            : 
    1036                 :          0 :         (void) sd_network_link_get_carrier_bound_to(info->ifindex, &carrier_bound_to);
    1037                 :          0 :         (void) sd_network_link_get_carrier_bound_by(info->ifindex, &carrier_bound_by);
    1038                 :            : 
    1039                 :          0 :         table = table_new("dot", "key", "value");
    1040         [ #  # ]:          0 :         if (!table)
    1041                 :          0 :                 return -ENOMEM;
    1042                 :            : 
    1043         [ #  # ]:          0 :         assert_se(cell = table_get_cell(table, 0, 0));
    1044                 :          0 :         (void) table_set_ellipsize_percent(table, cell, 100);
    1045                 :            : 
    1046         [ #  # ]:          0 :         assert_se(cell = table_get_cell(table, 0, 1));
    1047                 :          0 :         (void) table_set_ellipsize_percent(table, cell, 100);
    1048                 :            : 
    1049                 :          0 :         table_set_header(table, false);
    1050                 :            : 
    1051                 :          0 :         r = table_add_many(table,
    1052                 :            :                            TABLE_STRING, special_glyph(SPECIAL_GLYPH_BLACK_CIRCLE),
    1053                 :            :                            TABLE_SET_COLOR, on_color_operational);
    1054         [ #  # ]:          0 :         if (r < 0)
    1055                 :          0 :                 return r;
    1056                 :          0 :         r = table_add_cell_stringf(table, &cell, "%i: %s", info->ifindex, info->name);
    1057         [ #  # ]:          0 :         if (r < 0)
    1058                 :          0 :                 return r;
    1059                 :          0 :         (void) table_set_align_percent(table, cell, 0);
    1060                 :            : 
    1061                 :          0 :         r = table_add_many(table,
    1062                 :            :                            TABLE_EMPTY,
    1063                 :            :                            TABLE_EMPTY,
    1064                 :            :                            TABLE_STRING, "Link File:",
    1065                 :            :                            TABLE_SET_ALIGN_PERCENT, 100,
    1066                 :            :                            TABLE_STRING, strna(link),
    1067                 :            :                            TABLE_EMPTY,
    1068                 :            :                            TABLE_STRING, "Network File:",
    1069                 :            :                            TABLE_STRING, strna(network),
    1070                 :            :                            TABLE_EMPTY,
    1071                 :            :                            TABLE_STRING, "Type:",
    1072                 :            :                            TABLE_STRING, strna(t),
    1073                 :            :                            TABLE_EMPTY,
    1074                 :            :                            TABLE_STRING, "State:");
    1075         [ #  # ]:          0 :         if (r < 0)
    1076                 :          0 :                 return r;
    1077                 :          0 :         r = table_add_cell_stringf(table, NULL, "%s%s%s (%s%s%s)",
    1078                 :            :                                    on_color_operational, strna(operational_state), off_color_operational,
    1079                 :            :                                    on_color_setup, strna(setup_state), off_color_setup);
    1080         [ #  # ]:          0 :         if (r < 0)
    1081                 :          0 :                 return r;
    1082                 :            : 
    1083         [ #  # ]:          0 :         if (path) {
    1084                 :          0 :                 r = table_add_many(table,
    1085                 :            :                                    TABLE_EMPTY,
    1086                 :            :                                    TABLE_STRING, "Path:",
    1087                 :            :                                    TABLE_STRING, path);
    1088         [ #  # ]:          0 :                 if (r < 0)
    1089                 :          0 :                         return r;
    1090                 :            :         }
    1091         [ #  # ]:          0 :         if (driver) {
    1092                 :          0 :                 r = table_add_many(table,
    1093                 :            :                                    TABLE_EMPTY,
    1094                 :            :                                    TABLE_STRING, "Driver:",
    1095                 :            :                                    TABLE_STRING, driver);
    1096         [ #  # ]:          0 :                 if (r < 0)
    1097                 :          0 :                         return r;
    1098                 :            :         }
    1099         [ #  # ]:          0 :         if (vendor) {
    1100                 :          0 :                 r = table_add_many(table,
    1101                 :            :                                    TABLE_EMPTY,
    1102                 :            :                                    TABLE_STRING, "Vendor:",
    1103                 :            :                                    TABLE_STRING, vendor);
    1104         [ #  # ]:          0 :                 if (r < 0)
    1105                 :          0 :                         return r;
    1106                 :            :         }
    1107         [ #  # ]:          0 :         if (model) {
    1108                 :          0 :                 r = table_add_many(table,
    1109                 :            :                                    TABLE_EMPTY,
    1110                 :            :                                    TABLE_STRING, "Model:",
    1111                 :            :                                    TABLE_STRING, model);
    1112         [ #  # ]:          0 :                 if (r < 0)
    1113                 :          0 :                         return r;
    1114                 :            :         }
    1115                 :            : 
    1116         [ #  # ]:          0 :         if (info->has_mac_address) {
    1117         [ #  # ]:          0 :                 _cleanup_free_ char *description = NULL;
    1118                 :            :                 char ea[ETHER_ADDR_TO_STRING_MAX];
    1119                 :            : 
    1120                 :          0 :                 (void) ieee_oui(hwdb, &info->mac_address, &description);
    1121                 :            : 
    1122                 :          0 :                 r = table_add_many(table,
    1123                 :            :                                    TABLE_EMPTY,
    1124                 :            :                                    TABLE_STRING, "HW Address:");
    1125         [ #  # ]:          0 :                 if (r < 0)
    1126                 :          0 :                         return r;
    1127                 :          0 :                 r = table_add_cell_stringf(table, NULL, "%s%s%s%s",
    1128                 :            :                                            ether_addr_to_string(&info->mac_address, ea),
    1129         [ #  # ]:          0 :                                            description ? " (" : "",
    1130                 :            :                                            strempty(description),
    1131         [ #  # ]:          0 :                                            description ? ")" : "");
    1132         [ #  # ]:          0 :                 if (r < 0)
    1133                 :          0 :                         return r;
    1134                 :            :         }
    1135                 :            : 
    1136         [ #  # ]:          0 :         if (info->mtu > 0) {
    1137                 :            :                 char min_str[DECIMAL_STR_MAX(uint32_t)], max_str[DECIMAL_STR_MAX(uint32_t)];
    1138                 :            : 
    1139         [ #  # ]:          0 :                 xsprintf(min_str, "%" PRIu32, info->min_mtu);
    1140         [ #  # ]:          0 :                 xsprintf(max_str, "%" PRIu32, info->max_mtu);
    1141                 :            : 
    1142                 :          0 :                 r = table_add_many(table,
    1143                 :            :                                    TABLE_EMPTY,
    1144                 :            :                                    TABLE_STRING, "MTU:");
    1145         [ #  # ]:          0 :                 if (r < 0)
    1146                 :          0 :                         return r;
    1147                 :          0 :                 r = table_add_cell_stringf(table, NULL, "%" PRIu32 "%s%s%s%s%s%s%s",
    1148                 :            :                                            info->mtu,
    1149   [ #  #  #  # ]:          0 :                                            info->min_mtu > 0 || info->max_mtu > 0 ? " (" : "",
    1150         [ #  # ]:          0 :                                            info->min_mtu > 0 ? "min: " : "",
    1151         [ #  # ]:          0 :                                            info->min_mtu > 0 ? min_str : "",
    1152   [ #  #  #  # ]:          0 :                                            info->min_mtu > 0 && info->max_mtu > 0 ? ", " : "",
    1153         [ #  # ]:          0 :                                            info->max_mtu > 0 ? "max: " : "",
    1154         [ #  # ]:          0 :                                            info->max_mtu > 0 ? max_str : "",
    1155   [ #  #  #  # ]:          0 :                                            info->min_mtu > 0 || info->max_mtu > 0 ? ")" : "");
    1156         [ #  # ]:          0 :                 if (r < 0)
    1157                 :          0 :                         return r;
    1158                 :            :         }
    1159                 :            : 
    1160         [ #  # ]:          0 :         if (streq_ptr(info->netdev_kind, "bridge")) {
    1161                 :          0 :                 r = table_add_many(table,
    1162                 :            :                                    TABLE_EMPTY,
    1163                 :            :                                    TABLE_STRING, "Forward Delay:",
    1164                 :            :                                    TABLE_TIMESPAN_MSEC, jiffies_to_usec(info->forward_delay),
    1165                 :            :                                    TABLE_EMPTY,
    1166                 :            :                                    TABLE_STRING, "Hello Time:",
    1167                 :            :                                    TABLE_TIMESPAN_MSEC, jiffies_to_usec(info->hello_time),
    1168                 :            :                                    TABLE_EMPTY,
    1169                 :            :                                    TABLE_STRING, "Max Age:",
    1170                 :            :                                    TABLE_TIMESPAN_MSEC, jiffies_to_usec(info->max_age),
    1171                 :            :                                    TABLE_EMPTY,
    1172                 :            :                                    TABLE_STRING, "Ageing Time:",
    1173                 :            :                                    TABLE_TIMESPAN_MSEC, jiffies_to_usec(info->ageing_time),
    1174                 :            :                                    TABLE_EMPTY,
    1175                 :            :                                    TABLE_STRING, "Priority:",
    1176                 :            :                                    TABLE_UINT16, info->priority,
    1177                 :            :                                    TABLE_EMPTY,
    1178                 :            :                                    TABLE_STRING, "STP:",
    1179                 :            :                                    TABLE_BOOLEAN, info->stp_state > 0,
    1180                 :            :                                    TABLE_EMPTY,
    1181                 :            :                                    TABLE_STRING, "Multicast IGMP Version:",
    1182                 :            :                                    TABLE_UINT8, info->mcast_igmp_version);
    1183         [ #  # ]:          0 :                 if (r < 0)
    1184                 :          0 :                         return r;
    1185                 :            : 
    1186         [ #  # ]:          0 :         } else if (streq_ptr(info->netdev_kind, "vxlan")) {
    1187         [ #  # ]:          0 :                 if (info->vxlan_info.vni > 0) {
    1188                 :          0 :                         r = table_add_many(table,
    1189                 :            :                                            TABLE_EMPTY,
    1190                 :            :                                            TABLE_STRING, "VNI:",
    1191                 :            :                                            TABLE_UINT32, info->vxlan_info.vni);
    1192         [ #  # ]:          0 :                         if (r < 0)
    1193                 :          0 :                                 return r;
    1194                 :            :                 }
    1195                 :            : 
    1196   [ #  #  #  # ]:          0 :                 if (IN_SET(info->vxlan_info.group_family, AF_INET, AF_INET6)) {
    1197         [ #  # ]:          0 :                         r = table_add_many(table,
    1198                 :            :                                            TABLE_EMPTY,
    1199                 :            :                                            TABLE_STRING, "Group:",
    1200                 :            :                                            info->vxlan_info.group_family == AF_INET ? TABLE_IN_ADDR : TABLE_IN6_ADDR,
    1201                 :            :                                            &info->vxlan_info.group);
    1202         [ #  # ]:          0 :                         if (r < 0)
    1203                 :          0 :                                 return r;
    1204                 :            :                 }
    1205                 :            : 
    1206   [ #  #  #  # ]:          0 :                 if (IN_SET(info->vxlan_info.local_family, AF_INET, AF_INET6)) {
    1207         [ #  # ]:          0 :                         r = table_add_many(table,
    1208                 :            :                                            TABLE_EMPTY,
    1209                 :            :                                            TABLE_STRING, "Local:",
    1210                 :            :                                            info->vxlan_info.local_family == AF_INET ? TABLE_IN_ADDR : TABLE_IN6_ADDR,
    1211                 :            :                                            &info->vxlan_info.local);
    1212         [ #  # ]:          0 :                         if (r < 0)
    1213                 :          0 :                                 return r;
    1214                 :            :                 }
    1215                 :            : 
    1216         [ #  # ]:          0 :                 if (info->vxlan_info.dest_port > 0) {
    1217                 :          0 :                         r = table_add_many(table,
    1218                 :            :                                            TABLE_EMPTY,
    1219                 :            :                                            TABLE_STRING, "Destination Port:",
    1220                 :            :                                            TABLE_UINT16, be16toh(info->vxlan_info.dest_port));
    1221         [ #  # ]:          0 :                         if (r < 0)
    1222                 :          0 :                                 return r;
    1223                 :            :                 }
    1224                 :            : 
    1225         [ #  # ]:          0 :                 if (info->vxlan_info.link > 0) {
    1226                 :          0 :                         r = table_add_many(table,
    1227                 :            :                                            TABLE_EMPTY,
    1228                 :            :                                            TABLE_STRING, "Underlying Device:",
    1229                 :            :                                            TABLE_IFINDEX, info->vxlan_info.link);
    1230         [ #  # ]:          0 :                         if (r < 0)
    1231                 :          0 :                                  return r;
    1232                 :            :                 }
    1233                 :            :         }
    1234                 :            : 
    1235         [ #  # ]:          0 :         if (info->has_bitrates) {
    1236                 :            :                 char tx[FORMAT_BYTES_MAX], rx[FORMAT_BYTES_MAX];
    1237                 :            : 
    1238                 :          0 :                 r = table_add_many(table,
    1239                 :            :                                    TABLE_EMPTY,
    1240                 :            :                                    TABLE_STRING, "Bit Rate (Tx/Rx):");
    1241         [ #  # ]:          0 :                 if (r < 0)
    1242                 :          0 :                         return r;
    1243                 :          0 :                 r = table_add_cell_stringf(table, NULL, "%sbps/%sbps",
    1244                 :            :                                            format_bytes_full(tx, sizeof tx, info->tx_bitrate, 0),
    1245                 :            :                                            format_bytes_full(rx, sizeof rx, info->rx_bitrate, 0));
    1246         [ #  # ]:          0 :                 if (r < 0)
    1247                 :          0 :                         return r;
    1248                 :            :         }
    1249                 :            : 
    1250   [ #  #  #  # ]:          0 :         if (info->has_tx_queues || info->has_rx_queues) {
    1251                 :          0 :                 r = table_add_many(table,
    1252                 :            :                                    TABLE_EMPTY,
    1253                 :            :                                    TABLE_STRING, "Queue Length (Tx/Rx):");
    1254         [ #  # ]:          0 :                 if (r < 0)
    1255                 :          0 :                         return r;
    1256                 :          0 :                 r = table_add_cell_stringf(table, NULL, "%" PRIu32 "/%" PRIu32, info->tx_queues, info->rx_queues);
    1257         [ #  # ]:          0 :                 if (r < 0)
    1258                 :          0 :                         return r;
    1259                 :            :         }
    1260                 :            : 
    1261         [ #  # ]:          0 :         if (info->has_ethtool_link_info) {
    1262                 :          0 :                 const char *duplex = duplex_to_string(info->duplex);
    1263                 :          0 :                 const char *port = port_to_string(info->port);
    1264                 :            : 
    1265   [ #  #  #  # ]:          0 :                 if (IN_SET(info->autonegotiation, AUTONEG_DISABLE, AUTONEG_ENABLE)) {
    1266                 :          0 :                         r = table_add_many(table,
    1267                 :            :                                            TABLE_EMPTY,
    1268                 :            :                                            TABLE_STRING, "Auto negotiation:",
    1269                 :            :                                            TABLE_BOOLEAN, info->autonegotiation == AUTONEG_ENABLE);
    1270         [ #  # ]:          0 :                         if (r < 0)
    1271                 :          0 :                                 return r;
    1272                 :            :                 }
    1273                 :            : 
    1274         [ #  # ]:          0 :                 if (info->speed > 0) {
    1275                 :          0 :                         r = table_add_many(table,
    1276                 :            :                                            TABLE_EMPTY,
    1277                 :            :                                            TABLE_STRING, "Speed:",
    1278                 :            :                                            TABLE_BPS, (uint64_t) info->speed);
    1279         [ #  # ]:          0 :                         if (r < 0)
    1280                 :          0 :                                 return r;
    1281                 :            :                 }
    1282                 :            : 
    1283         [ #  # ]:          0 :                 if (duplex) {
    1284                 :          0 :                         r = table_add_many(table,
    1285                 :            :                                            TABLE_EMPTY,
    1286                 :            :                                            TABLE_STRING, "Duplex:",
    1287                 :            :                                            TABLE_STRING, duplex);
    1288         [ #  # ]:          0 :                         if (r < 0)
    1289                 :          0 :                                 return r;
    1290                 :            :                 }
    1291                 :            : 
    1292         [ #  # ]:          0 :                 if (port) {
    1293                 :          0 :                         r = table_add_many(table,
    1294                 :            :                                            TABLE_EMPTY,
    1295                 :            :                                            TABLE_STRING, "Port:",
    1296                 :            :                                            TABLE_STRING, port);
    1297         [ #  # ]:          0 :                         if (r < 0)
    1298                 :          0 :                                 return r;
    1299                 :            :                 }
    1300                 :            :         }
    1301                 :            : 
    1302                 :          0 :         r = dump_addresses(rtnl, table, info->ifindex);
    1303         [ #  # ]:          0 :         if (r < 0)
    1304                 :          0 :                 return r;
    1305                 :          0 :         r = dump_gateways(rtnl, hwdb, table, info->ifindex);
    1306         [ #  # ]:          0 :         if (r < 0)
    1307                 :          0 :                 return r;
    1308                 :          0 :         r = dump_list(table, "DNS:", dns);
    1309         [ #  # ]:          0 :         if (r < 0)
    1310                 :          0 :                 return r;
    1311                 :          0 :         r = dump_list(table, "Search Domains:", search_domains);
    1312         [ #  # ]:          0 :         if (r < 0)
    1313                 :          0 :                 return r;
    1314                 :          0 :         r = dump_list(table, "Route Domains:", route_domains);
    1315         [ #  # ]:          0 :         if (r < 0)
    1316                 :          0 :                 return r;
    1317                 :          0 :         r = dump_list(table, "NTP:", ntp);
    1318         [ #  # ]:          0 :         if (r < 0)
    1319                 :          0 :                 return r;
    1320                 :          0 :         r = dump_ifindexes(table, "Carrier Bound To:", carrier_bound_to);
    1321         [ #  # ]:          0 :         if (r < 0)
    1322                 :          0 :                 return r;
    1323                 :          0 :         r = dump_ifindexes(table, "Carrier Bound By:", carrier_bound_by);
    1324         [ #  # ]:          0 :         if (r < 0)
    1325                 :          0 :                 return r;
    1326                 :            : 
    1327                 :          0 :         (void) sd_network_link_get_timezone(info->ifindex, &tz);
    1328         [ #  # ]:          0 :         if (tz) {
    1329                 :          0 :                 r = table_add_many(table,
    1330                 :            :                                    TABLE_EMPTY,
    1331                 :            :                                    TABLE_STRING, "Time Zone:",
    1332                 :            :                                    TABLE_STRING, tz);
    1333         [ #  # ]:          0 :                 if (r < 0)
    1334                 :          0 :                         return r;
    1335                 :            :         }
    1336                 :            : 
    1337                 :          0 :         r = dump_lldp_neighbors(table, "Connected To:", info->ifindex);
    1338         [ #  # ]:          0 :         if (r < 0)
    1339                 :          0 :                 return r;
    1340                 :            : 
    1341                 :          0 :         r = dump_statistics(table, info);
    1342         [ #  # ]:          0 :         if (r < 0)
    1343                 :          0 :                 return r;
    1344                 :            : 
    1345                 :          0 :         return table_print(table, NULL);
    1346                 :            : }
    1347                 :            : 
    1348                 :          0 : static int system_status(sd_netlink *rtnl, sd_hwdb *hwdb) {
    1349                 :          0 :         _cleanup_free_ char *operational_state = NULL;
    1350                 :          0 :         _cleanup_strv_free_ char **dns = NULL, **ntp = NULL, **search_domains = NULL, **route_domains = NULL;
    1351                 :            :         const char *on_color_operational, *off_color_operational;
    1352                 :          0 :         _cleanup_(table_unrefp) Table *table = NULL;
    1353                 :            :         TableCell *cell;
    1354                 :            :         int r;
    1355                 :            : 
    1356         [ #  # ]:          0 :         assert(rtnl);
    1357                 :            : 
    1358                 :          0 :         (void) sd_network_get_operational_state(&operational_state);
    1359                 :          0 :         operational_state_to_color(operational_state, &on_color_operational, &off_color_operational);
    1360                 :            : 
    1361                 :          0 :         table = table_new("dot", "key", "value");
    1362         [ #  # ]:          0 :         if (!table)
    1363                 :          0 :                 return -ENOMEM;
    1364                 :            : 
    1365         [ #  # ]:          0 :         assert_se(cell = table_get_cell(table, 0, 0));
    1366                 :          0 :         (void) table_set_ellipsize_percent(table, cell, 100);
    1367                 :            : 
    1368         [ #  # ]:          0 :         assert_se(cell = table_get_cell(table, 0, 1));
    1369                 :          0 :         (void) table_set_align_percent(table, cell, 100);
    1370                 :          0 :         (void) table_set_ellipsize_percent(table, cell, 100);
    1371                 :            : 
    1372                 :          0 :         table_set_header(table, false);
    1373                 :            : 
    1374                 :          0 :         r = table_add_many(table,
    1375                 :            :                            TABLE_STRING, special_glyph(SPECIAL_GLYPH_BLACK_CIRCLE),
    1376                 :            :                            TABLE_SET_COLOR, on_color_operational,
    1377                 :            :                            TABLE_STRING, "State:",
    1378                 :            :                            TABLE_STRING, strna(operational_state),
    1379                 :            :                            TABLE_SET_COLOR, on_color_operational);
    1380                 :            : 
    1381                 :          0 :         r = dump_addresses(rtnl, table, 0);
    1382         [ #  # ]:          0 :         if (r < 0)
    1383                 :          0 :                 return r;
    1384                 :          0 :         r = dump_gateways(rtnl, hwdb, table, 0);
    1385         [ #  # ]:          0 :         if (r < 0)
    1386                 :          0 :                 return r;
    1387                 :            : 
    1388                 :          0 :         (void) sd_network_get_dns(&dns);
    1389                 :          0 :         r = dump_list(table, "DNS:", dns);
    1390         [ #  # ]:          0 :         if (r < 0)
    1391                 :          0 :                 return r;
    1392                 :            : 
    1393                 :          0 :         (void) sd_network_get_search_domains(&search_domains);
    1394                 :          0 :         r = dump_list(table, "Search Domains:", search_domains);
    1395         [ #  # ]:          0 :         if (r < 0)
    1396                 :          0 :                 return r;
    1397                 :            : 
    1398                 :          0 :         (void) sd_network_get_route_domains(&route_domains);
    1399                 :          0 :         r = dump_list(table, "Route Domains:", route_domains);
    1400         [ #  # ]:          0 :         if (r < 0)
    1401                 :          0 :                 return r;
    1402                 :            : 
    1403                 :          0 :         (void) sd_network_get_ntp(&ntp);
    1404                 :          0 :         r = dump_list(table, "NTP:", ntp);
    1405         [ #  # ]:          0 :         if (r < 0)
    1406                 :          0 :                 return r;
    1407                 :            : 
    1408                 :          0 :         return table_print(table, NULL);
    1409                 :            : }
    1410                 :            : 
    1411                 :          0 : static int link_status(int argc, char *argv[], void *userdata) {
    1412                 :          0 :         _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
    1413                 :          0 :         _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
    1414                 :          0 :         _cleanup_(sd_hwdb_unrefp) sd_hwdb *hwdb = NULL;
    1415                 :          0 :         _cleanup_free_ LinkInfo *links = NULL;
    1416                 :            :         int r, c, i;
    1417                 :            : 
    1418                 :          0 :         (void) pager_open(arg_pager_flags);
    1419                 :            : 
    1420                 :          0 :         r = sd_bus_open_system(&bus);
    1421         [ #  # ]:          0 :         if (r < 0)
    1422         [ #  # ]:          0 :                 return log_error_errno(r, "Failed to connect system bus: %m");
    1423                 :            : 
    1424                 :          0 :         r = sd_netlink_open(&rtnl);
    1425         [ #  # ]:          0 :         if (r < 0)
    1426         [ #  # ]:          0 :                 return log_error_errno(r, "Failed to connect to netlink: %m");
    1427                 :            : 
    1428                 :          0 :         r = sd_hwdb_new(&hwdb);
    1429         [ #  # ]:          0 :         if (r < 0)
    1430         [ #  # ]:          0 :                 log_debug_errno(r, "Failed to open hardware database: %m");
    1431                 :            : 
    1432         [ #  # ]:          0 :         if (arg_all)
    1433                 :          0 :                 c = acquire_link_info(bus, rtnl, NULL, &links);
    1434         [ #  # ]:          0 :         else if (argc <= 1)
    1435                 :          0 :                 return system_status(rtnl, hwdb);
    1436                 :            :         else
    1437                 :          0 :                 c = acquire_link_info(bus, rtnl, argv + 1, &links);
    1438         [ #  # ]:          0 :         if (c < 0)
    1439                 :          0 :                 return c;
    1440                 :            : 
    1441         [ #  # ]:          0 :         for (i = 0; i < c; i++) {
    1442         [ #  # ]:          0 :                 if (i > 0)
    1443                 :          0 :                         fputc('\n', stdout);
    1444                 :            : 
    1445                 :          0 :                 link_status_one(rtnl, hwdb, links + i);
    1446                 :            :         }
    1447                 :            : 
    1448                 :          0 :         return 0;
    1449                 :            : }
    1450                 :            : 
    1451                 :          0 : static char *lldp_capabilities_to_string(uint16_t x) {
    1452                 :            :         static const char characters[] = {
    1453                 :            :                 'o', 'p', 'b', 'w', 'r', 't', 'd', 'a', 'c', 's', 'm',
    1454                 :            :         };
    1455                 :            :         char *ret;
    1456                 :            :         unsigned i;
    1457                 :            : 
    1458                 :          0 :         ret = new(char, ELEMENTSOF(characters) + 1);
    1459         [ #  # ]:          0 :         if (!ret)
    1460                 :          0 :                 return NULL;
    1461                 :            : 
    1462         [ #  # ]:          0 :         for (i = 0; i < ELEMENTSOF(characters); i++)
    1463         [ #  # ]:          0 :                 ret[i] = (x & (1U << i)) ? characters[i] : '.';
    1464                 :            : 
    1465                 :          0 :         ret[i] = 0;
    1466                 :          0 :         return ret;
    1467                 :            : }
    1468                 :            : 
    1469                 :          0 : static void lldp_capabilities_legend(uint16_t x) {
    1470                 :          0 :         unsigned w, i, cols = columns();
    1471                 :            :         static const char* const table[] = {
    1472                 :            :                 "o - Other",
    1473                 :            :                 "p - Repeater",
    1474                 :            :                 "b - Bridge",
    1475                 :            :                 "w - WLAN Access Point",
    1476                 :            :                 "r - Router",
    1477                 :            :                 "t - Telephone",
    1478                 :            :                 "d - DOCSIS cable device",
    1479                 :            :                 "a - Station",
    1480                 :            :                 "c - Customer VLAN",
    1481                 :            :                 "s - Service VLAN",
    1482                 :            :                 "m - Two-port MAC Relay (TPMR)",
    1483                 :            :         };
    1484                 :            : 
    1485         [ #  # ]:          0 :         if (x == 0)
    1486                 :          0 :                 return;
    1487                 :            : 
    1488                 :          0 :         printf("\nCapability Flags:\n");
    1489         [ #  # ]:          0 :         for (w = 0, i = 0; i < ELEMENTSOF(table); i++)
    1490   [ #  #  #  # ]:          0 :                 if (x & (1U << i) || arg_all) {
    1491                 :            :                         bool newline;
    1492                 :            : 
    1493         [ #  # ]:          0 :                         newline = w + strlen(table[i]) + (w == 0 ? 0 : 2) > cols;
    1494         [ #  # ]:          0 :                         if (newline)
    1495                 :          0 :                                 w = 0;
    1496   [ #  #  #  # ]:          0 :                         w += printf("%s%s%s", newline ? "\n" : "", w == 0 ? "" : "; ", table[i]);
    1497                 :            :                 }
    1498                 :          0 :         puts("");
    1499                 :            : }
    1500                 :            : 
    1501                 :          0 : static int link_lldp_status(int argc, char *argv[], void *userdata) {
    1502                 :          0 :         _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
    1503                 :          0 :         _cleanup_free_ LinkInfo *links = NULL;
    1504                 :          0 :         _cleanup_(table_unrefp) Table *table = NULL;
    1505                 :          0 :         int i, r, c, m = 0;
    1506                 :          0 :         uint16_t all = 0;
    1507                 :            :         TableCell *cell;
    1508                 :            : 
    1509                 :          0 :         r = sd_netlink_open(&rtnl);
    1510         [ #  # ]:          0 :         if (r < 0)
    1511         [ #  # ]:          0 :                 return log_error_errno(r, "Failed to connect to netlink: %m");
    1512                 :            : 
    1513         [ #  # ]:          0 :         c = acquire_link_info(NULL, rtnl, argc > 1 ? argv + 1 : NULL, &links);
    1514         [ #  # ]:          0 :         if (c < 0)
    1515                 :          0 :                 return c;
    1516                 :            : 
    1517                 :          0 :         (void) pager_open(arg_pager_flags);
    1518                 :            : 
    1519                 :          0 :         table = table_new("link",
    1520                 :            :                           "chassis id",
    1521                 :            :                           "system name",
    1522                 :            :                           "caps",
    1523                 :            :                           "port id",
    1524                 :            :                           "port description");
    1525         [ #  # ]:          0 :         if (!table)
    1526                 :          0 :                 return -ENOMEM;
    1527                 :            : 
    1528                 :          0 :         table_set_header(table, arg_legend);
    1529                 :            : 
    1530         [ #  # ]:          0 :         assert_se(cell = table_get_cell(table, 0, 0));
    1531                 :          0 :         table_set_minimum_width(table, cell, 16);
    1532                 :            : 
    1533         [ #  # ]:          0 :         assert_se(cell = table_get_cell(table, 0, 1));
    1534                 :          0 :         table_set_minimum_width(table, cell, 17);
    1535                 :            : 
    1536         [ #  # ]:          0 :         assert_se(cell = table_get_cell(table, 0, 2));
    1537                 :          0 :         table_set_minimum_width(table, cell, 16);
    1538                 :            : 
    1539         [ #  # ]:          0 :         assert_se(cell = table_get_cell(table, 0, 3));
    1540                 :          0 :         table_set_minimum_width(table, cell, 11);
    1541                 :            : 
    1542         [ #  # ]:          0 :         assert_se(cell = table_get_cell(table, 0, 4));
    1543                 :          0 :         table_set_minimum_width(table, cell, 17);
    1544                 :            : 
    1545         [ #  # ]:          0 :         assert_se(cell = table_get_cell(table, 0, 5));
    1546                 :          0 :         table_set_minimum_width(table, cell, 16);
    1547                 :            : 
    1548         [ #  # ]:          0 :         for (i = 0; i < c; i++) {
    1549      [ #  #  # ]:          0 :                 _cleanup_fclose_ FILE *f = NULL;
    1550                 :            : 
    1551                 :          0 :                 r = open_lldp_neighbors(links[i].ifindex, &f);
    1552         [ #  # ]:          0 :                 if (r == -ENOENT)
    1553                 :          0 :                         continue;
    1554         [ #  # ]:          0 :                 if (r < 0) {
    1555         [ #  # ]:          0 :                         log_warning_errno(r, "Failed to open LLDP data for %i, ignoring: %m", links[i].ifindex);
    1556                 :          0 :                         continue;
    1557                 :            :                 }
    1558                 :            : 
    1559                 :          0 :                 for (;;) {
    1560   [ #  #  #  #  :          0 :                         _cleanup_free_ char *cid = NULL, *pid = NULL, *sname = NULL, *pdesc = NULL, *capabilities = NULL;
          #  #  #  #  #  
          #  #  #  #  #  
                      # ]
    1561                 :          0 :                         const char *chassis_id = NULL, *port_id = NULL, *system_name = NULL, *port_description = NULL;
    1562      [ #  #  # ]:          0 :                         _cleanup_(sd_lldp_neighbor_unrefp) sd_lldp_neighbor *n = NULL;
    1563                 :            :                         uint16_t cc;
    1564                 :            : 
    1565                 :          0 :                         r = next_lldp_neighbor(f, &n);
    1566         [ #  # ]:          0 :                         if (r < 0) {
    1567         [ #  # ]:          0 :                                 log_warning_errno(r, "Failed to read neighbor data: %m");
    1568                 :          0 :                                 break;
    1569                 :            :                         }
    1570         [ #  # ]:          0 :                         if (r == 0)
    1571                 :          0 :                                 break;
    1572                 :            : 
    1573                 :          0 :                         (void) sd_lldp_neighbor_get_chassis_id_as_string(n, &chassis_id);
    1574                 :          0 :                         (void) sd_lldp_neighbor_get_port_id_as_string(n, &port_id);
    1575                 :          0 :                         (void) sd_lldp_neighbor_get_system_name(n, &system_name);
    1576                 :          0 :                         (void) sd_lldp_neighbor_get_port_description(n, &port_description);
    1577                 :            : 
    1578         [ #  # ]:          0 :                         if (chassis_id) {
    1579                 :          0 :                                 cid = ellipsize(chassis_id, 17, 100);
    1580         [ #  # ]:          0 :                                 if (cid)
    1581                 :          0 :                                         chassis_id = cid;
    1582                 :            :                         }
    1583                 :            : 
    1584         [ #  # ]:          0 :                         if (port_id) {
    1585                 :          0 :                                 pid = ellipsize(port_id, 17, 100);
    1586         [ #  # ]:          0 :                                 if (pid)
    1587                 :          0 :                                         port_id = pid;
    1588                 :            :                         }
    1589                 :            : 
    1590         [ #  # ]:          0 :                         if (system_name) {
    1591                 :          0 :                                 sname = ellipsize(system_name, 16, 100);
    1592         [ #  # ]:          0 :                                 if (sname)
    1593                 :          0 :                                         system_name = sname;
    1594                 :            :                         }
    1595                 :            : 
    1596         [ #  # ]:          0 :                         if (port_description) {
    1597                 :          0 :                                 pdesc = ellipsize(port_description, 16, 100);
    1598         [ #  # ]:          0 :                                 if (pdesc)
    1599                 :          0 :                                         port_description = pdesc;
    1600                 :            :                         }
    1601                 :            : 
    1602         [ #  # ]:          0 :                         if (sd_lldp_neighbor_get_enabled_capabilities(n, &cc) >= 0) {
    1603                 :          0 :                                 capabilities = lldp_capabilities_to_string(cc);
    1604                 :          0 :                                 all |= cc;
    1605                 :            :                         }
    1606                 :            : 
    1607                 :          0 :                         r = table_add_many(table,
    1608                 :            :                                            TABLE_STRING, links[i].name,
    1609                 :            :                                            TABLE_STRING, strna(chassis_id),
    1610                 :            :                                            TABLE_STRING, strna(system_name),
    1611                 :            :                                            TABLE_STRING, strna(capabilities),
    1612                 :            :                                            TABLE_STRING, strna(port_id),
    1613                 :            :                                            TABLE_STRING, strna(port_description));
    1614         [ #  # ]:          0 :                         if (r < 0)
    1615                 :          0 :                                 return r;
    1616                 :            : 
    1617                 :          0 :                         m++;
    1618                 :            :                 }
    1619                 :            :         }
    1620                 :            : 
    1621                 :          0 :         r = table_print(table, NULL);
    1622         [ #  # ]:          0 :         if (r < 0)
    1623                 :          0 :                 return r;
    1624                 :            : 
    1625         [ #  # ]:          0 :         if (arg_legend) {
    1626                 :          0 :                 lldp_capabilities_legend(all);
    1627                 :          0 :                 printf("\n%i neighbors listed.\n", m);
    1628                 :            :         }
    1629                 :            : 
    1630                 :          0 :         return 0;
    1631                 :            : }
    1632                 :            : 
    1633                 :          0 : static int link_delete_send_message(sd_netlink *rtnl, int index) {
    1634                 :          0 :         _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
    1635                 :            :         int r;
    1636                 :            : 
    1637         [ #  # ]:          0 :         assert(rtnl);
    1638                 :            : 
    1639                 :          0 :         r = sd_rtnl_message_new_link(rtnl, &req, RTM_DELLINK, index);
    1640         [ #  # ]:          0 :         if (r < 0)
    1641                 :          0 :                 return rtnl_log_create_error(r);
    1642                 :            : 
    1643                 :          0 :         r = sd_netlink_call(rtnl, req, 0, NULL);
    1644         [ #  # ]:          0 :         if (r < 0)
    1645                 :          0 :                 return r;
    1646                 :            : 
    1647                 :          0 :         return 0;
    1648                 :            : }
    1649                 :            : 
    1650                 :          0 : static int link_delete(int argc, char *argv[], void *userdata) {
    1651                 :          0 :         _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
    1652                 :          0 :         _cleanup_set_free_ Set *indexes = NULL;
    1653                 :            :         int index, r, i;
    1654                 :            :         Iterator j;
    1655                 :            :         void *p;
    1656                 :            : 
    1657                 :          0 :         r = sd_netlink_open(&rtnl);
    1658         [ #  # ]:          0 :         if (r < 0)
    1659         [ #  # ]:          0 :                 return log_error_errno(r, "Failed to connect to netlink: %m");
    1660                 :            : 
    1661                 :          0 :         indexes = set_new(NULL);
    1662         [ #  # ]:          0 :         if (!indexes)
    1663                 :          0 :                 return log_oom();
    1664                 :            : 
    1665         [ #  # ]:          0 :         for (i = 1; i < argc; i++) {
    1666                 :          0 :                 r = parse_ifindex_or_ifname(argv[i], &index);
    1667         [ #  # ]:          0 :                 if (r < 0)
    1668         [ #  # ]:          0 :                         return log_error_errno(r, "Failed to resolve interface %s", argv[i]);
    1669                 :            : 
    1670                 :          0 :                 r = set_put(indexes, INT_TO_PTR(index));
    1671         [ #  # ]:          0 :                 if (r < 0)
    1672                 :          0 :                         return log_oom();
    1673                 :            :         }
    1674                 :            : 
    1675         [ #  # ]:          0 :         SET_FOREACH(p, indexes, j) {
    1676                 :          0 :                 r = link_delete_send_message(rtnl, PTR_TO_INT(p));
    1677         [ #  # ]:          0 :                 if (r < 0) {
    1678                 :            :                         char ifname[IF_NAMESIZE + 1];
    1679                 :            : 
    1680         [ #  # ]:          0 :                         if (format_ifname(index, ifname))
    1681         [ #  # ]:          0 :                                 return log_error_errno(r, "Failed to delete interface %s: %m", ifname);
    1682                 :            :                         else
    1683         [ #  # ]:          0 :                                 return log_error_errno(r, "Failed to delete interface %d: %m", index);
    1684                 :            :                 }
    1685                 :            :         }
    1686                 :            : 
    1687                 :          0 :         return r;
    1688                 :            : }
    1689                 :            : 
    1690                 :         12 : static int help(void) {
    1691                 :         12 :         _cleanup_free_ char *link = NULL;
    1692                 :            :         int r;
    1693                 :            : 
    1694                 :         12 :         r = terminal_urlify_man("networkctl", "1", &link);
    1695         [ -  + ]:         12 :         if (r < 0)
    1696                 :          0 :                 return log_oom();
    1697                 :            : 
    1698                 :         12 :         printf("%s [OPTIONS...]\n\n"
    1699                 :            :                "Query and control the networking subsystem.\n\n"
    1700                 :            :                "  -h --help             Show this help\n"
    1701                 :            :                "     --version          Show package version\n"
    1702                 :            :                "     --no-pager         Do not pipe output into a pager\n"
    1703                 :            :                "     --no-legend        Do not show the headers and footers\n"
    1704                 :            :                "  -a --all              Show status for all links\n"
    1705                 :            :                "  -s --stats            Show detailed link statics\n"
    1706                 :            :                "\nCommands:\n"
    1707                 :            :                "  list [PATTERN...]     List links\n"
    1708                 :            :                "  status [PATTERN...]   Show link status\n"
    1709                 :            :                "  lldp [PATTERN...]     Show LLDP neighbors\n"
    1710                 :            :                "  label                 Show current address label entries in the kernel\n"
    1711                 :            :                "  delete DEVICES        Delete virtual netdevs\n"
    1712                 :            :                "\nSee the %s for details.\n"
    1713                 :            :                , program_invocation_short_name
    1714                 :            :                , link
    1715                 :            :         );
    1716                 :            : 
    1717                 :         12 :         return 0;
    1718                 :            : }
    1719                 :            : 
    1720                 :         16 : static int parse_argv(int argc, char *argv[]) {
    1721                 :            : 
    1722                 :            :         enum {
    1723                 :            :                 ARG_VERSION = 0x100,
    1724                 :            :                 ARG_NO_PAGER,
    1725                 :            :                 ARG_NO_LEGEND,
    1726                 :            :         };
    1727                 :            : 
    1728                 :            :         static const struct option options[] = {
    1729                 :            :                 { "help",      no_argument,       NULL, 'h'           },
    1730                 :            :                 { "version",   no_argument,       NULL, ARG_VERSION   },
    1731                 :            :                 { "no-pager",  no_argument,       NULL, ARG_NO_PAGER  },
    1732                 :            :                 { "no-legend", no_argument,       NULL, ARG_NO_LEGEND },
    1733                 :            :                 { "all",       no_argument,       NULL, 'a'           },
    1734                 :            :                 { "stats",     no_argument,       NULL, 's'           },
    1735                 :            :                 {}
    1736                 :            :         };
    1737                 :            : 
    1738                 :            :         int c;
    1739                 :            : 
    1740         [ -  + ]:         16 :         assert(argc >= 0);
    1741         [ -  + ]:         16 :         assert(argv);
    1742                 :            : 
    1743         [ +  - ]:         16 :         while ((c = getopt_long(argc, argv, "has", options, NULL)) >= 0) {
    1744                 :            : 
    1745   [ +  -  -  -  :         16 :                 switch (c) {
             -  -  +  - ]
    1746                 :            : 
    1747                 :         12 :                 case 'h':
    1748                 :         12 :                         return help();
    1749                 :            : 
    1750                 :          0 :                 case ARG_VERSION:
    1751                 :          0 :                         return version();
    1752                 :            : 
    1753                 :          0 :                 case ARG_NO_PAGER:
    1754                 :          0 :                         arg_pager_flags |= PAGER_DISABLE;
    1755                 :          0 :                         break;
    1756                 :            : 
    1757                 :          0 :                 case ARG_NO_LEGEND:
    1758                 :          0 :                         arg_legend = false;
    1759                 :          0 :                         break;
    1760                 :            : 
    1761                 :          0 :                 case 'a':
    1762                 :          0 :                         arg_all = true;
    1763                 :          0 :                         break;
    1764                 :            : 
    1765                 :          0 :                 case 's':
    1766                 :          0 :                         arg_stats = true;
    1767                 :          0 :                         break;
    1768                 :            : 
    1769                 :          4 :                 case '?':
    1770                 :          4 :                         return -EINVAL;
    1771                 :            : 
    1772                 :          0 :                 default:
    1773                 :          0 :                         assert_not_reached("Unhandled option");
    1774                 :            :                 }
    1775                 :            :         }
    1776                 :            : 
    1777                 :          0 :         return 1;
    1778                 :            : }
    1779                 :            : 
    1780                 :          0 : static int networkctl_main(int argc, char *argv[]) {
    1781                 :            :         static const Verb verbs[] = {
    1782                 :            :                 { "list",   VERB_ANY, VERB_ANY, VERB_DEFAULT, list_links          },
    1783                 :            :                 { "status", VERB_ANY, VERB_ANY, 0,            link_status         },
    1784                 :            :                 { "lldp",   VERB_ANY, VERB_ANY, 0,            link_lldp_status    },
    1785                 :            :                 { "label",  VERB_ANY, VERB_ANY, 0,            list_address_labels },
    1786                 :            :                 { "delete", 2,        VERB_ANY, 0,            link_delete         },
    1787                 :            :                 {}
    1788                 :            :         };
    1789                 :            : 
    1790                 :          0 :         return dispatch_verb(argc, argv, verbs, NULL);
    1791                 :            : }
    1792                 :            : 
    1793                 :          0 : static void warn_networkd_missing(void) {
    1794                 :            : 
    1795         [ #  # ]:          0 :         if (access("/run/systemd/netif/state", F_OK) >= 0)
    1796                 :          0 :                 return;
    1797                 :            : 
    1798                 :          0 :         fprintf(stderr, "WARNING: systemd-networkd is not running, output will be incomplete.\n\n");
    1799                 :            : }
    1800                 :            : 
    1801                 :         16 : static int run(int argc, char* argv[]) {
    1802                 :            :         int r;
    1803                 :            : 
    1804                 :         16 :         log_show_color(true);
    1805                 :         16 :         log_parse_environment();
    1806                 :         16 :         log_open();
    1807                 :            : 
    1808                 :         16 :         r = parse_argv(argc, argv);
    1809         [ +  - ]:         16 :         if (r <= 0)
    1810                 :         16 :                 return r;
    1811                 :            : 
    1812                 :          0 :         warn_networkd_missing();
    1813                 :            : 
    1814                 :          0 :         return networkctl_main(argc, argv);
    1815                 :            : }
    1816                 :            : 
    1817                 :         16 : DEFINE_MAIN_FUNCTION(run);

Generated by: LCOV version 1.14