| File: | build-scan/../src/network/networkctl.c |
| Warning: | line 1062, column 13 Potential leak of memory pointed to by 'links' |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* SPDX-License-Identifier: LGPL-2.1+ */ | ||||
| 2 | |||||
| 3 | #include <getopt.h> | ||||
| 4 | #include <linux1/if_addrlabel.h> | ||||
| 5 | #include <net/if.h> | ||||
| 6 | #include <stdbool.h> | ||||
| 7 | |||||
| 8 | #include "sd-device.h" | ||||
| 9 | #include "sd-hwdb.h" | ||||
| 10 | #include "sd-lldp.h" | ||||
| 11 | #include "sd-netlink.h" | ||||
| 12 | #include "sd-network.h" | ||||
| 13 | |||||
| 14 | #include "alloc-util.h" | ||||
| 15 | #include "arphrd-list.h" | ||||
| 16 | #include "device-util.h" | ||||
| 17 | #include "ether-addr-util.h" | ||||
| 18 | #include "fd-util.h" | ||||
| 19 | #include "hwdb-util.h" | ||||
| 20 | #include "local-addresses.h" | ||||
| 21 | #include "locale-util.h" | ||||
| 22 | #include "macro.h" | ||||
| 23 | #include "netlink-util.h" | ||||
| 24 | #include "pager.h" | ||||
| 25 | #include "parse-util.h" | ||||
| 26 | #include "socket-util.h" | ||||
| 27 | #include "sparse-endian.h" | ||||
| 28 | #include "stdio-util.h" | ||||
| 29 | #include "string-table.h" | ||||
| 30 | #include "string-util.h" | ||||
| 31 | #include "strv.h" | ||||
| 32 | #include "strxcpyx.h" | ||||
| 33 | #include "terminal-util.h" | ||||
| 34 | #include "util.h" | ||||
| 35 | #include "verbs.h" | ||||
| 36 | |||||
| 37 | static bool_Bool arg_no_pager = false0; | ||||
| 38 | static bool_Bool arg_legend = true1; | ||||
| 39 | static bool_Bool arg_all = false0; | ||||
| 40 | |||||
| 41 | static char *link_get_type_string(unsigned short iftype, sd_device *d) { | ||||
| 42 | const char *t; | ||||
| 43 | char *p; | ||||
| 44 | |||||
| 45 | if (d) { | ||||
| 46 | const char *devtype = NULL((void*)0); | ||||
| 47 | |||||
| 48 | (void) sd_device_get_devtype(d, &devtype); | ||||
| 49 | if (!isempty(devtype)) | ||||
| 50 | return strdup(devtype); | ||||
| 51 | } | ||||
| 52 | |||||
| 53 | t = arphrd_to_name(iftype); | ||||
| 54 | if (!t) | ||||
| 55 | return NULL((void*)0); | ||||
| 56 | |||||
| 57 | p = strdup(t); | ||||
| 58 | if (!p) | ||||
| 59 | return NULL((void*)0); | ||||
| 60 | |||||
| 61 | ascii_strlower(p); | ||||
| 62 | return p; | ||||
| 63 | } | ||||
| 64 | |||||
| 65 | static void operational_state_to_color(const char *state, const char **on, const char **off) { | ||||
| 66 | assert(on)do { if ((__builtin_expect(!!(!(on)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("on"), "../src/network/networkctl.c", 66 , __PRETTY_FUNCTION__); } while (0); | ||||
| 67 | assert(off)do { if ((__builtin_expect(!!(!(off)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("off"), "../src/network/networkctl.c", 67 , __PRETTY_FUNCTION__); } while (0); | ||||
| 68 | |||||
| 69 | if (streq_ptr(state, "routable")) { | ||||
| 70 | *on = ansi_highlight_green(); | ||||
| 71 | *off = ansi_normal(); | ||||
| 72 | } else if (streq_ptr(state, "degraded")) { | ||||
| 73 | *on = ansi_highlight_yellow(); | ||||
| 74 | *off = ansi_normal(); | ||||
| 75 | } else | ||||
| 76 | *on = *off = ""; | ||||
| 77 | } | ||||
| 78 | |||||
| 79 | static void setup_state_to_color(const char *state, const char **on, const char **off) { | ||||
| 80 | assert(on)do { if ((__builtin_expect(!!(!(on)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("on"), "../src/network/networkctl.c", 80 , __PRETTY_FUNCTION__); } while (0); | ||||
| 81 | assert(off)do { if ((__builtin_expect(!!(!(off)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("off"), "../src/network/networkctl.c", 81 , __PRETTY_FUNCTION__); } while (0); | ||||
| 82 | |||||
| 83 | if (streq_ptr(state, "configured")) { | ||||
| 84 | *on = ansi_highlight_green(); | ||||
| 85 | *off = ansi_normal(); | ||||
| 86 | } else if (streq_ptr(state, "configuring")) { | ||||
| 87 | *on = ansi_highlight_yellow(); | ||||
| 88 | *off = ansi_normal(); | ||||
| 89 | } else if (STRPTR_IN_SET(state, "failed", "linger")({ const char* _x = (state); _x && (!!strv_find((((char **) ((const char*[]) { "failed", "linger", ((void*)0) }))), ( _x))); })) { | ||||
| 90 | *on = ansi_highlight_red(); | ||||
| 91 | *off = ansi_normal(); | ||||
| 92 | } else | ||||
| 93 | *on = *off = ""; | ||||
| 94 | } | ||||
| 95 | |||||
| 96 | typedef struct LinkInfo { | ||||
| 97 | char name[IFNAMSIZ16+1]; | ||||
| 98 | int ifindex; | ||||
| 99 | unsigned short iftype; | ||||
| 100 | struct ether_addr mac_address; | ||||
| 101 | uint32_t mtu; | ||||
| 102 | |||||
| 103 | bool_Bool has_mac_address:1; | ||||
| 104 | bool_Bool has_mtu:1; | ||||
| 105 | } LinkInfo; | ||||
| 106 | |||||
| 107 | static int link_info_compare(const void *a, const void *b) { | ||||
| 108 | const LinkInfo *x = a, *y = b; | ||||
| 109 | |||||
| 110 | return x->ifindex - y->ifindex; | ||||
| 111 | } | ||||
| 112 | |||||
| 113 | static int decode_link(sd_netlink_message *m, LinkInfo *info) { | ||||
| 114 | const char *name; | ||||
| 115 | uint16_t type; | ||||
| 116 | int r; | ||||
| 117 | |||||
| 118 | assert(m)do { if ((__builtin_expect(!!(!(m)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("m"), "../src/network/networkctl.c", 118 , __PRETTY_FUNCTION__); } while (0); | ||||
| 119 | assert(info)do { if ((__builtin_expect(!!(!(info)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("info"), "../src/network/networkctl.c", 119 , __PRETTY_FUNCTION__); } while (0); | ||||
| 120 | |||||
| 121 | r = sd_netlink_message_get_type(m, &type); | ||||
| 122 | if (r < 0) | ||||
| 123 | return r; | ||||
| 124 | |||||
| 125 | if (type != RTM_NEWLINKRTM_NEWLINK) | ||||
| 126 | return 0; | ||||
| 127 | |||||
| 128 | r = sd_rtnl_message_link_get_ifindex(m, &info->ifindex); | ||||
| 129 | if (r < 0) | ||||
| 130 | return r; | ||||
| 131 | |||||
| 132 | r = sd_netlink_message_read_string(m, IFLA_IFNAME, &name); | ||||
| 133 | if (r < 0) | ||||
| 134 | return r; | ||||
| 135 | |||||
| 136 | r = sd_rtnl_message_link_get_type(m, &info->iftype); | ||||
| 137 | if (r < 0) | ||||
| 138 | return r; | ||||
| 139 | |||||
| 140 | strscpy(info->name, sizeof info->name, name); | ||||
| 141 | |||||
| 142 | info->has_mac_address = | ||||
| 143 | sd_netlink_message_read_ether_addr(m, IFLA_ADDRESS, &info->mac_address) >= 0 && | ||||
| 144 | memcmp(&info->mac_address, ÐER_ADDR_NULL((const struct ether_addr){}), sizeof(struct ether_addr)) != 0; | ||||
| 145 | |||||
| 146 | info->has_mtu = | ||||
| 147 | sd_netlink_message_read_u32(m, IFLA_MTU, &info->mtu) && | ||||
| 148 | info->mtu > 0; | ||||
| 149 | |||||
| 150 | return 1; | ||||
| 151 | } | ||||
| 152 | |||||
| 153 | static int acquire_link_info_strv(sd_netlink *rtnl, char **l, LinkInfo **ret) { | ||||
| 154 | _cleanup_free___attribute__((cleanup(freep))) LinkInfo *links = NULL((void*)0); | ||||
| 155 | char **i; | ||||
| 156 | size_t c = 0; | ||||
| 157 | int r; | ||||
| 158 | |||||
| 159 | assert(rtnl)do { if ((__builtin_expect(!!(!(rtnl)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("rtnl"), "../src/network/networkctl.c", 159 , __PRETTY_FUNCTION__); } while (0); | ||||
| 160 | assert(ret)do { if ((__builtin_expect(!!(!(ret)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("ret"), "../src/network/networkctl.c", 160 , __PRETTY_FUNCTION__); } while (0); | ||||
| 161 | |||||
| 162 | links = new(LinkInfo, strv_length(l))((LinkInfo*) malloc_multiply(sizeof(LinkInfo), (strv_length(l )))); | ||||
| 163 | if (!links) | ||||
| 164 | return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/network/networkctl.c" , 164, __func__); | ||||
| 165 | |||||
| 166 | STRV_FOREACH(i, l)for ((i) = (l); (i) && *(i); (i)++) { | ||||
| 167 | _cleanup_(sd_netlink_message_unrefp)__attribute__((cleanup(sd_netlink_message_unrefp))) sd_netlink_message *req = NULL((void*)0), *reply = NULL((void*)0); | ||||
| 168 | int ifindex; | ||||
| 169 | |||||
| 170 | if (parse_ifindex(*i, &ifindex) >= 0) | ||||
| 171 | r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINKRTM_GETLINK, ifindex); | ||||
| 172 | else { | ||||
| 173 | r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINKRTM_GETLINK, 0); | ||||
| 174 | if (r < 0) | ||||
| 175 | return rtnl_log_create_error(r); | ||||
| 176 | |||||
| 177 | r = sd_netlink_message_append_string(req, IFLA_IFNAME, *i); | ||||
| 178 | } | ||||
| 179 | if (r < 0) | ||||
| 180 | return rtnl_log_create_error(r); | ||||
| 181 | |||||
| 182 | r = sd_netlink_call(rtnl, req, 0, &reply); | ||||
| 183 | if (r < 0) | ||||
| 184 | return log_error_errno(r, "Failed to request link: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/network/networkctl.c", 184, __func__, "Failed to request link: %m" ) : -abs(_e); }); | ||||
| 185 | |||||
| 186 | r = decode_link(reply, links + c); | ||||
| 187 | if (r < 0) | ||||
| 188 | return r; | ||||
| 189 | if (r > 0) | ||||
| 190 | c++; | ||||
| 191 | } | ||||
| 192 | |||||
| 193 | qsort_safe(links, c, sizeof(LinkInfo), link_info_compare); | ||||
| 194 | |||||
| 195 | *ret = TAKE_PTR(links)({ typeof(links) _ptr_ = (links); (links) = ((void*)0); _ptr_ ; }); | ||||
| 196 | |||||
| 197 | return (int) c; | ||||
| 198 | } | ||||
| 199 | |||||
| 200 | static int acquire_link_info_all(sd_netlink *rtnl, LinkInfo **ret) { | ||||
| 201 | _cleanup_(sd_netlink_message_unrefp)__attribute__((cleanup(sd_netlink_message_unrefp))) sd_netlink_message *req = NULL((void*)0), *reply = NULL((void*)0); | ||||
| 202 | _cleanup_free___attribute__((cleanup(freep))) LinkInfo *links = NULL((void*)0); | ||||
| 203 | size_t allocated = 0, c = 0; | ||||
| 204 | sd_netlink_message *i; | ||||
| 205 | int r; | ||||
| 206 | |||||
| 207 | assert(rtnl)do { if ((__builtin_expect(!!(!(rtnl)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("rtnl"), "../src/network/networkctl.c", 207 , __PRETTY_FUNCTION__); } while (0); | ||||
| 208 | assert(ret)do { if ((__builtin_expect(!!(!(ret)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("ret"), "../src/network/networkctl.c", 208 , __PRETTY_FUNCTION__); } while (0); | ||||
| 209 | |||||
| 210 | r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINKRTM_GETLINK, 0); | ||||
| 211 | if (r < 0) | ||||
| 212 | return rtnl_log_create_error(r); | ||||
| 213 | |||||
| 214 | r = sd_netlink_message_request_dump(req, true1); | ||||
| 215 | if (r < 0) | ||||
| 216 | return rtnl_log_create_error(r); | ||||
| 217 | |||||
| 218 | r = sd_netlink_call(rtnl, req, 0, &reply); | ||||
| 219 | if (r < 0) | ||||
| 220 | return log_error_errno(r, "Failed to enumerate links: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/network/networkctl.c", 220, __func__, "Failed to enumerate links: %m" ) : -abs(_e); }); | ||||
| 221 | |||||
| 222 | for (i = reply; i; i = sd_netlink_message_next(i)) { | ||||
| 223 | if (!GREEDY_REALLOC(links, allocated, c+1)greedy_realloc((void**) &(links), &(allocated), (c+1) , sizeof((links)[0]))) | ||||
| 224 | return -ENOMEM12; | ||||
| 225 | |||||
| 226 | r = decode_link(i, links + c); | ||||
| 227 | if (r < 0) | ||||
| 228 | return r; | ||||
| 229 | if (r > 0) | ||||
| 230 | c++; | ||||
| 231 | } | ||||
| 232 | |||||
| 233 | qsort_safe(links, c, sizeof(LinkInfo), link_info_compare); | ||||
| 234 | |||||
| 235 | *ret = TAKE_PTR(links)({ typeof(links) _ptr_ = (links); (links) = ((void*)0); _ptr_ ; }); | ||||
| 236 | |||||
| 237 | return (int) c; | ||||
| 238 | } | ||||
| 239 | |||||
| 240 | static int list_links(int argc, char *argv[], void *userdata) { | ||||
| 241 | _cleanup_(sd_netlink_unrefp)__attribute__((cleanup(sd_netlink_unrefp))) sd_netlink *rtnl = NULL((void*)0); | ||||
| 242 | _cleanup_free___attribute__((cleanup(freep))) LinkInfo *links = NULL((void*)0); | ||||
| 243 | int c, i, r; | ||||
| 244 | |||||
| 245 | r = sd_netlink_open(&rtnl); | ||||
| 246 | if (r < 0) | ||||
| 247 | return log_error_errno(r, "Failed to connect to netlink: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/network/networkctl.c", 247, __func__, "Failed to connect to netlink: %m" ) : -abs(_e); }); | ||||
| 248 | |||||
| 249 | if (argc > 1) | ||||
| 250 | c = acquire_link_info_strv(rtnl, argv + 1, &links); | ||||
| 251 | else | ||||
| 252 | c = acquire_link_info_all(rtnl, &links); | ||||
| 253 | if (c < 0) | ||||
| 254 | return c; | ||||
| 255 | |||||
| 256 | (void) pager_open(arg_no_pager, false0); | ||||
| 257 | |||||
| 258 | if (arg_legend) | ||||
| 259 | printf("%3s %-16s %-18s %-11s %-10s\n", | ||||
| 260 | "IDX", | ||||
| 261 | "LINK", | ||||
| 262 | "TYPE", | ||||
| 263 | "OPERATIONAL", | ||||
| 264 | "SETUP"); | ||||
| 265 | |||||
| 266 | for (i = 0; i < c; i++) { | ||||
| 267 | _cleanup_free___attribute__((cleanup(freep))) char *setup_state = NULL((void*)0), *operational_state = NULL((void*)0); | ||||
| 268 | _cleanup_(sd_device_unrefp)__attribute__((cleanup(sd_device_unrefp))) sd_device *d = NULL((void*)0); | ||||
| 269 | const char *on_color_operational, *off_color_operational, | ||||
| 270 | *on_color_setup, *off_color_setup; | ||||
| 271 | char devid[2 + DECIMAL_STR_MAX(int)(2+(sizeof(int) <= 1 ? 3 : sizeof(int) <= 2 ? 5 : sizeof (int) <= 4 ? 10 : sizeof(int) <= 8 ? 20 : sizeof(int[-2 *(sizeof(int) > 8)])))]; | ||||
| 272 | _cleanup_free___attribute__((cleanup(freep))) char *t = NULL((void*)0); | ||||
| 273 | |||||
| 274 | (void) sd_network_link_get_operational_state(links[i].ifindex, &operational_state); | ||||
| 275 | operational_state_to_color(operational_state, &on_color_operational, &off_color_operational); | ||||
| 276 | |||||
| 277 | r = sd_network_link_get_setup_state(links[i].ifindex, &setup_state); | ||||
| 278 | if (r == -ENODATA61) /* If there's no info available about this iface, it's unmanaged by networkd */ | ||||
| 279 | setup_state = strdup("unmanaged"); | ||||
| 280 | setup_state_to_color(setup_state, &on_color_setup, &off_color_setup); | ||||
| 281 | |||||
| 282 | xsprintf(devid, "n%i", links[i].ifindex)do { if ((__builtin_expect(!!(!(((size_t) snprintf(devid, __extension__ (__builtin_choose_expr( !__builtin_types_compatible_p(typeof (devid), typeof(&*(devid))), sizeof(devid)/sizeof((devid) [0]), ((void)0))), "n%i", links[i].ifindex) < (__extension__ (__builtin_choose_expr( !__builtin_types_compatible_p(typeof (devid), typeof(&*(devid))), sizeof(devid)/sizeof((devid) [0]), ((void)0))))))),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD , ("xsprintf: " "devid" "[] must be big enough"), "../src/network/networkctl.c" , 282, __PRETTY_FUNCTION__); } while (0); | ||||
| 283 | (void) sd_device_new_from_device_id(&d, devid); | ||||
| 284 | |||||
| 285 | t = link_get_type_string(links[i].iftype, d); | ||||
| 286 | |||||
| 287 | printf("%3i %-16s %-18s %s%-11s%s %s%-10s%s\n", | ||||
| 288 | links[i].ifindex, links[i].name, strna(t), | ||||
| 289 | on_color_operational, strna(operational_state), off_color_operational, | ||||
| 290 | on_color_setup, strna(setup_state), off_color_setup); | ||||
| 291 | } | ||||
| 292 | |||||
| 293 | if (arg_legend) | ||||
| 294 | printf("\n%i links listed.\n", c); | ||||
| 295 | |||||
| 296 | return 0; | ||||
| 297 | } | ||||
| 298 | |||||
| 299 | /* IEEE Organizationally Unique Identifier vendor string */ | ||||
| 300 | static int ieee_oui(sd_hwdb *hwdb, const struct ether_addr *mac, char **ret) { | ||||
| 301 | const char *description; | ||||
| 302 | char modalias[STRLEN("OUI:XXYYXXYYXXYY")(sizeof("""OUI:XXYYXXYYXXYY""") - 1) + 1], *desc; | ||||
| 303 | int r; | ||||
| 304 | |||||
| 305 | assert(ret)do { if ((__builtin_expect(!!(!(ret)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("ret"), "../src/network/networkctl.c", 305 , __PRETTY_FUNCTION__); } while (0); | ||||
| 306 | |||||
| 307 | if (!hwdb) | ||||
| 308 | return -EINVAL22; | ||||
| 309 | |||||
| 310 | if (!mac) | ||||
| 311 | return -EINVAL22; | ||||
| 312 | |||||
| 313 | /* skip commonly misused 00:00:00 (Xerox) prefix */ | ||||
| 314 | if (memcmp(mac, "\0\0\0", 3) == 0) | ||||
| 315 | return -EINVAL22; | ||||
| 316 | |||||
| 317 | xsprintf(modalias, "OUI:" ETHER_ADDR_FORMAT_STR,do { if ((__builtin_expect(!!(!(((size_t) snprintf(modalias, __extension__ (__builtin_choose_expr( !__builtin_types_compatible_p(typeof (modalias), typeof(&*(modalias))), sizeof(modalias)/sizeof ((modalias)[0]), ((void)0))), "OUI:" "%02X%02X%02X%02X%02X%02X" , (*mac).ether_addr_octet[0], (*mac).ether_addr_octet[1], (*mac ).ether_addr_octet[2], (*mac).ether_addr_octet[3], (*mac).ether_addr_octet [4], (*mac).ether_addr_octet[5]) < (__extension__ (__builtin_choose_expr ( !__builtin_types_compatible_p(typeof(modalias), typeof(& *(modalias))), sizeof(modalias)/sizeof((modalias)[0]), ((void )0))))))),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("xsprintf: " "modalias" "[] must be big enough"), "../src/network/networkctl.c" , 318, __PRETTY_FUNCTION__); } while (0) | ||||
| 318 | ETHER_ADDR_FORMAT_VAL(*mac))do { if ((__builtin_expect(!!(!(((size_t) snprintf(modalias, __extension__ (__builtin_choose_expr( !__builtin_types_compatible_p(typeof (modalias), typeof(&*(modalias))), sizeof(modalias)/sizeof ((modalias)[0]), ((void)0))), "OUI:" "%02X%02X%02X%02X%02X%02X" , (*mac).ether_addr_octet[0], (*mac).ether_addr_octet[1], (*mac ).ether_addr_octet[2], (*mac).ether_addr_octet[3], (*mac).ether_addr_octet [4], (*mac).ether_addr_octet[5]) < (__extension__ (__builtin_choose_expr ( !__builtin_types_compatible_p(typeof(modalias), typeof(& *(modalias))), sizeof(modalias)/sizeof((modalias)[0]), ((void )0))))))),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("xsprintf: " "modalias" "[] must be big enough"), "../src/network/networkctl.c" , 318, __PRETTY_FUNCTION__); } while (0); | ||||
| 319 | |||||
| 320 | r = sd_hwdb_get(hwdb, modalias, "ID_OUI_FROM_DATABASE", &description); | ||||
| 321 | if (r < 0) | ||||
| 322 | return r; | ||||
| 323 | |||||
| 324 | desc = strdup(description); | ||||
| 325 | if (!desc) | ||||
| 326 | return -ENOMEM12; | ||||
| 327 | |||||
| 328 | *ret = desc; | ||||
| 329 | |||||
| 330 | return 0; | ||||
| 331 | } | ||||
| 332 | |||||
| 333 | static int get_gateway_description( | ||||
| 334 | sd_netlink *rtnl, | ||||
| 335 | sd_hwdb *hwdb, | ||||
| 336 | int ifindex, | ||||
| 337 | int family, | ||||
| 338 | union in_addr_union *gateway, | ||||
| 339 | char **gateway_description) { | ||||
| 340 | _cleanup_(sd_netlink_message_unrefp)__attribute__((cleanup(sd_netlink_message_unrefp))) sd_netlink_message *req = NULL((void*)0), *reply = NULL((void*)0); | ||||
| 341 | sd_netlink_message *m; | ||||
| 342 | int r; | ||||
| 343 | |||||
| 344 | assert(rtnl)do { if ((__builtin_expect(!!(!(rtnl)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("rtnl"), "../src/network/networkctl.c", 344 , __PRETTY_FUNCTION__); } while (0); | ||||
| 345 | assert(ifindex >= 0)do { if ((__builtin_expect(!!(!(ifindex >= 0)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("ifindex >= 0"), "../src/network/networkctl.c" , 345, __PRETTY_FUNCTION__); } while (0); | ||||
| 346 | assert(IN_SET(family, AF_INET, AF_INET6))do { if ((__builtin_expect(!!(!(({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended[20 - sizeof((int[]){2, 10})/sizeof(int)]; switch(family) { case 2: case 10: _found = 1; break; default: break; } _found; })) ),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("IN_SET(family, AF_INET, AF_INET6)" ), "../src/network/networkctl.c", 346, __PRETTY_FUNCTION__); } while (0); | ||||
| 347 | assert(gateway)do { if ((__builtin_expect(!!(!(gateway)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("gateway"), "../src/network/networkctl.c" , 347, __PRETTY_FUNCTION__); } while (0); | ||||
| 348 | assert(gateway_description)do { if ((__builtin_expect(!!(!(gateway_description)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("gateway_description"), "../src/network/networkctl.c" , 348, __PRETTY_FUNCTION__); } while (0); | ||||
| 349 | |||||
| 350 | r = sd_rtnl_message_new_neigh(rtnl, &req, RTM_GETNEIGHRTM_GETNEIGH, ifindex, family); | ||||
| 351 | if (r < 0) | ||||
| 352 | return r; | ||||
| 353 | |||||
| 354 | r = sd_netlink_message_request_dump(req, true1); | ||||
| 355 | if (r < 0) | ||||
| 356 | return r; | ||||
| 357 | |||||
| 358 | r = sd_netlink_call(rtnl, req, 0, &reply); | ||||
| 359 | if (r < 0) | ||||
| 360 | return r; | ||||
| 361 | |||||
| 362 | for (m = reply; m; m = sd_netlink_message_next(m)) { | ||||
| 363 | union in_addr_union gw = {}; | ||||
| 364 | struct ether_addr mac = {}; | ||||
| 365 | uint16_t type; | ||||
| 366 | int ifi, fam; | ||||
| 367 | |||||
| 368 | r = sd_netlink_message_get_errno(m); | ||||
| 369 | if (r < 0) { | ||||
| 370 | log_error_errno(r, "got error: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/network/networkctl.c", 370, __func__, "got error: %m" ) : -abs(_e); }); | ||||
| 371 | continue; | ||||
| 372 | } | ||||
| 373 | |||||
| 374 | r = sd_netlink_message_get_type(m, &type); | ||||
| 375 | if (r < 0) { | ||||
| 376 | log_error_errno(r, "could not get type: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/network/networkctl.c", 376, __func__, "could not get type: %m" ) : -abs(_e); }); | ||||
| 377 | continue; | ||||
| 378 | } | ||||
| 379 | |||||
| 380 | if (type != RTM_NEWNEIGHRTM_NEWNEIGH) { | ||||
| 381 | log_error("type is not RTM_NEWNEIGH")({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/network/networkctl.c", 381, __func__, "type is not RTM_NEWNEIGH" ) : -abs(_e); }); | ||||
| 382 | continue; | ||||
| 383 | } | ||||
| 384 | |||||
| 385 | r = sd_rtnl_message_neigh_get_family(m, &fam); | ||||
| 386 | if (r < 0) { | ||||
| 387 | log_error_errno(r, "could not get family: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/network/networkctl.c", 387, __func__, "could not get family: %m" ) : -abs(_e); }); | ||||
| 388 | continue; | ||||
| 389 | } | ||||
| 390 | |||||
| 391 | if (fam != family) { | ||||
| 392 | log_error("family is not correct")({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/network/networkctl.c", 392, __func__, "family is not correct" ) : -abs(_e); }); | ||||
| 393 | continue; | ||||
| 394 | } | ||||
| 395 | |||||
| 396 | r = sd_rtnl_message_neigh_get_ifindex(m, &ifi); | ||||
| 397 | if (r < 0) { | ||||
| 398 | log_error_errno(r, "could not get ifindex: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/network/networkctl.c", 398, __func__, "could not get ifindex: %m" ) : -abs(_e); }); | ||||
| 399 | continue; | ||||
| 400 | } | ||||
| 401 | |||||
| 402 | if (ifindex > 0 && ifi != ifindex) | ||||
| 403 | continue; | ||||
| 404 | |||||
| 405 | switch (fam) { | ||||
| 406 | case AF_INET2: | ||||
| 407 | r = sd_netlink_message_read_in_addr(m, NDA_DST, &gw.in); | ||||
| 408 | if (r < 0) | ||||
| 409 | continue; | ||||
| 410 | |||||
| 411 | break; | ||||
| 412 | case AF_INET610: | ||||
| 413 | r = sd_netlink_message_read_in6_addr(m, NDA_DST, &gw.in6); | ||||
| 414 | if (r < 0) | ||||
| 415 | continue; | ||||
| 416 | |||||
| 417 | break; | ||||
| 418 | default: | ||||
| 419 | continue; | ||||
| 420 | } | ||||
| 421 | |||||
| 422 | if (!in_addr_equal(fam, &gw, gateway)) | ||||
| 423 | continue; | ||||
| 424 | |||||
| 425 | r = sd_netlink_message_read_ether_addr(m, NDA_LLADDR, &mac); | ||||
| 426 | if (r < 0) | ||||
| 427 | continue; | ||||
| 428 | |||||
| 429 | r = ieee_oui(hwdb, &mac, gateway_description); | ||||
| 430 | if (r < 0) | ||||
| 431 | continue; | ||||
| 432 | |||||
| 433 | return 0; | ||||
| 434 | } | ||||
| 435 | |||||
| 436 | return -ENODATA61; | ||||
| 437 | } | ||||
| 438 | |||||
| 439 | static int dump_gateways( | ||||
| 440 | sd_netlink *rtnl, | ||||
| 441 | sd_hwdb *hwdb, | ||||
| 442 | const char *prefix, | ||||
| 443 | int ifindex) { | ||||
| 444 | _cleanup_free___attribute__((cleanup(freep))) struct local_address *local = NULL((void*)0); | ||||
| 445 | int r, n, i; | ||||
| 446 | |||||
| 447 | assert(rtnl)do { if ((__builtin_expect(!!(!(rtnl)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("rtnl"), "../src/network/networkctl.c", 447 , __PRETTY_FUNCTION__); } while (0); | ||||
| 448 | assert(prefix)do { if ((__builtin_expect(!!(!(prefix)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("prefix"), "../src/network/networkctl.c" , 448, __PRETTY_FUNCTION__); } while (0); | ||||
| 449 | |||||
| 450 | n = local_gateways(rtnl, ifindex, AF_UNSPEC0, &local); | ||||
| 451 | if (n < 0) | ||||
| 452 | return n; | ||||
| 453 | |||||
| 454 | for (i = 0; i < n; i++) { | ||||
| 455 | _cleanup_free___attribute__((cleanup(freep))) char *gateway = NULL((void*)0), *description = NULL((void*)0); | ||||
| 456 | |||||
| 457 | r = in_addr_to_string(local[i].family, &local[i].address, &gateway); | ||||
| 458 | if (r < 0) | ||||
| 459 | return r; | ||||
| 460 | |||||
| 461 | r = get_gateway_description(rtnl, hwdb, local[i].ifindex, local[i].family, &local[i].address, &description); | ||||
| 462 | if (r < 0) | ||||
| 463 | log_debug_errno(r, "Could not get description of gateway: %m")({ int _level = ((7)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/network/networkctl.c", 463, __func__, "Could not get description of gateway: %m" ) : -abs(_e); }); | ||||
| 464 | |||||
| 465 | printf("%*s%s", | ||||
| 466 | (int) strlen(prefix), | ||||
| 467 | i == 0 ? prefix : "", | ||||
| 468 | gateway); | ||||
| 469 | |||||
| 470 | if (description) | ||||
| 471 | printf(" (%s)", description); | ||||
| 472 | |||||
| 473 | /* Show interface name for the entry if we show | ||||
| 474 | * entries for all interfaces */ | ||||
| 475 | if (ifindex <= 0) { | ||||
| 476 | char name[IF_NAMESIZE16+1]; | ||||
| 477 | |||||
| 478 | if (if_indextoname(local[i].ifindex, name)) { | ||||
| 479 | fputs(" on ", stdoutstdout); | ||||
| 480 | fputs(name, stdoutstdout); | ||||
| 481 | } else | ||||
| 482 | printf(" on %%%i", local[i].ifindex); | ||||
| 483 | } | ||||
| 484 | |||||
| 485 | fputc('\n', stdoutstdout); | ||||
| 486 | } | ||||
| 487 | |||||
| 488 | return 0; | ||||
| 489 | } | ||||
| 490 | |||||
| 491 | static int dump_addresses( | ||||
| 492 | sd_netlink *rtnl, | ||||
| 493 | const char *prefix, | ||||
| 494 | int ifindex) { | ||||
| 495 | |||||
| 496 | _cleanup_free___attribute__((cleanup(freep))) struct local_address *local = NULL((void*)0); | ||||
| 497 | int r, n, i; | ||||
| 498 | |||||
| 499 | assert(rtnl)do { if ((__builtin_expect(!!(!(rtnl)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("rtnl"), "../src/network/networkctl.c", 499 , __PRETTY_FUNCTION__); } while (0); | ||||
| 500 | assert(prefix)do { if ((__builtin_expect(!!(!(prefix)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("prefix"), "../src/network/networkctl.c" , 500, __PRETTY_FUNCTION__); } while (0); | ||||
| 501 | |||||
| 502 | n = local_addresses(rtnl, ifindex, AF_UNSPEC0, &local); | ||||
| 503 | if (n < 0) | ||||
| 504 | return n; | ||||
| 505 | |||||
| 506 | for (i = 0; i < n; i++) { | ||||
| 507 | _cleanup_free___attribute__((cleanup(freep))) char *pretty = NULL((void*)0); | ||||
| 508 | |||||
| 509 | r = in_addr_to_string(local[i].family, &local[i].address, &pretty); | ||||
| 510 | if (r < 0) | ||||
| 511 | return r; | ||||
| 512 | |||||
| 513 | printf("%*s%s", | ||||
| 514 | (int) strlen(prefix), | ||||
| 515 | i == 0 ? prefix : "", | ||||
| 516 | pretty); | ||||
| 517 | |||||
| 518 | if (ifindex <= 0) { | ||||
| 519 | char name[IF_NAMESIZE16+1]; | ||||
| 520 | |||||
| 521 | if (if_indextoname(local[i].ifindex, name)) { | ||||
| 522 | fputs(" on ", stdoutstdout); | ||||
| 523 | fputs(name, stdoutstdout); | ||||
| 524 | } else | ||||
| 525 | printf(" on %%%i", local[i].ifindex); | ||||
| 526 | } | ||||
| 527 | |||||
| 528 | fputc('\n', stdoutstdout); | ||||
| 529 | } | ||||
| 530 | |||||
| 531 | return 0; | ||||
| 532 | } | ||||
| 533 | |||||
| 534 | static int dump_address_labels(sd_netlink *rtnl) { | ||||
| 535 | _cleanup_(sd_netlink_message_unrefp)__attribute__((cleanup(sd_netlink_message_unrefp))) sd_netlink_message *req = NULL((void*)0), *reply = NULL((void*)0); | ||||
| 536 | sd_netlink_message *m; | ||||
| 537 | int r; | ||||
| 538 | |||||
| 539 | assert(rtnl)do { if ((__builtin_expect(!!(!(rtnl)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("rtnl"), "../src/network/networkctl.c", 539 , __PRETTY_FUNCTION__); } while (0); | ||||
| 540 | |||||
| 541 | r = sd_rtnl_message_new_addrlabel(rtnl, &req, RTM_GETADDRLABELRTM_GETADDRLABEL, 0, AF_INET610); | ||||
| 542 | if (r < 0) | ||||
| 543 | return log_error_errno(r, "Could not allocate RTM_GETADDRLABEL message: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/network/networkctl.c", 543, __func__, "Could not allocate RTM_GETADDRLABEL message: %m" ) : -abs(_e); }); | ||||
| 544 | |||||
| 545 | r = sd_netlink_message_request_dump(req, true1); | ||||
| 546 | if (r < 0) | ||||
| 547 | return r; | ||||
| 548 | |||||
| 549 | r = sd_netlink_call(rtnl, req, 0, &reply); | ||||
| 550 | if (r < 0) | ||||
| 551 | return r; | ||||
| 552 | |||||
| 553 | printf("%10s/%s %30s\n", "Prefix", "Prefixlen", "Label"); | ||||
| 554 | |||||
| 555 | for (m = reply; m; m = sd_netlink_message_next(m)) { | ||||
| 556 | _cleanup_free___attribute__((cleanup(freep))) char *pretty = NULL((void*)0); | ||||
| 557 | union in_addr_union prefix = {}; | ||||
| 558 | uint8_t prefixlen; | ||||
| 559 | uint32_t label; | ||||
| 560 | |||||
| 561 | r = sd_netlink_message_get_errno(m); | ||||
| 562 | if (r < 0) { | ||||
| 563 | log_error_errno(r, "got error: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/network/networkctl.c", 563, __func__, "got error: %m" ) : -abs(_e); }); | ||||
| 564 | continue; | ||||
| 565 | } | ||||
| 566 | |||||
| 567 | r = sd_netlink_message_read_u32(m, IFAL_LABEL, &label); | ||||
| 568 | if (r < 0 && r != -ENODATA61) { | ||||
| 569 | log_error_errno(r, "Could not read IFAL_LABEL, ignoring: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/network/networkctl.c", 569, __func__, "Could not read IFAL_LABEL, ignoring: %m" ) : -abs(_e); }); | ||||
| 570 | continue; | ||||
| 571 | } | ||||
| 572 | |||||
| 573 | r = sd_netlink_message_read_in6_addr(m, IFAL_ADDRESS, &prefix.in6); | ||||
| 574 | if (r < 0) | ||||
| 575 | continue; | ||||
| 576 | |||||
| 577 | r = in_addr_to_string(AF_INET610, &prefix, &pretty); | ||||
| 578 | if (r < 0) | ||||
| 579 | continue; | ||||
| 580 | |||||
| 581 | r = sd_rtnl_message_addrlabel_get_prefixlen(m, &prefixlen); | ||||
| 582 | if (r < 0) | ||||
| 583 | continue; | ||||
| 584 | |||||
| 585 | printf("%10s/%-5u %30u\n", pretty, prefixlen, label); | ||||
| 586 | } | ||||
| 587 | |||||
| 588 | return 0; | ||||
| 589 | } | ||||
| 590 | |||||
| 591 | static int list_address_labels(int argc, char *argv[], void *userdata) { | ||||
| 592 | _cleanup_(sd_netlink_unrefp)__attribute__((cleanup(sd_netlink_unrefp))) sd_netlink *rtnl = NULL((void*)0); | ||||
| 593 | int r; | ||||
| 594 | |||||
| 595 | r = sd_netlink_open(&rtnl); | ||||
| 596 | if (r < 0) | ||||
| 597 | return log_error_errno(r, "Failed to connect to netlink: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/network/networkctl.c", 597, __func__, "Failed to connect to netlink: %m" ) : -abs(_e); }); | ||||
| 598 | |||||
| 599 | dump_address_labels(rtnl); | ||||
| 600 | |||||
| 601 | return 0; | ||||
| 602 | } | ||||
| 603 | |||||
| 604 | static int open_lldp_neighbors(int ifindex, FILE **ret) { | ||||
| 605 | _cleanup_free___attribute__((cleanup(freep))) char *p = NULL((void*)0); | ||||
| 606 | FILE *f; | ||||
| 607 | |||||
| 608 | if (asprintf(&p, "/run/systemd/netif/lldp/%i", ifindex) < 0) | ||||
| 609 | return -ENOMEM12; | ||||
| 610 | |||||
| 611 | f = fopen(p, "re"); | ||||
| 612 | if (!f) | ||||
| 613 | return -errno(*__errno_location ()); | ||||
| 614 | |||||
| 615 | *ret = f; | ||||
| 616 | return 0; | ||||
| 617 | } | ||||
| 618 | |||||
| 619 | static int next_lldp_neighbor(FILE *f, sd_lldp_neighbor **ret) { | ||||
| 620 | _cleanup_free___attribute__((cleanup(freep))) void *raw = NULL((void*)0); | ||||
| 621 | size_t l; | ||||
| 622 | le64_t u; | ||||
| 623 | int r; | ||||
| 624 | |||||
| 625 | assert(f)do { if ((__builtin_expect(!!(!(f)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("f"), "../src/network/networkctl.c", 625 , __PRETTY_FUNCTION__); } while (0); | ||||
| 626 | assert(ret)do { if ((__builtin_expect(!!(!(ret)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("ret"), "../src/network/networkctl.c", 626 , __PRETTY_FUNCTION__); } while (0); | ||||
| 627 | |||||
| 628 | l = fread(&u, 1, sizeof(u), f); | ||||
| 629 | if (l == 0 && feof(f)) | ||||
| 630 | return 0; | ||||
| 631 | if (l != sizeof(u)) | ||||
| 632 | return -EBADMSG74; | ||||
| 633 | |||||
| 634 | /* each LLDP packet is at most MTU size, but let's allow up to 4KiB just in case */ | ||||
| 635 | if (le64toh(u) >= 4096) | ||||
| 636 | return -EBADMSG74; | ||||
| 637 | |||||
| 638 | raw = new(uint8_t, le64toh(u))((uint8_t*) malloc_multiply(sizeof(uint8_t), (le64toh(u)))); | ||||
| 639 | if (!raw) | ||||
| 640 | return -ENOMEM12; | ||||
| 641 | |||||
| 642 | if (fread(raw, 1, le64toh(u), f) != le64toh(u)) | ||||
| 643 | return -EBADMSG74; | ||||
| 644 | |||||
| 645 | r = sd_lldp_neighbor_from_raw(ret, raw, le64toh(u)); | ||||
| 646 | if (r < 0) | ||||
| 647 | return r; | ||||
| 648 | |||||
| 649 | return 1; | ||||
| 650 | } | ||||
| 651 | |||||
| 652 | static int dump_lldp_neighbors(const char *prefix, int ifindex) { | ||||
| 653 | _cleanup_fclose___attribute__((cleanup(fclosep))) FILE *f = NULL((void*)0); | ||||
| 654 | int r, c = 0; | ||||
| 655 | |||||
| 656 | assert(prefix)do { if ((__builtin_expect(!!(!(prefix)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("prefix"), "../src/network/networkctl.c" , 656, __PRETTY_FUNCTION__); } while (0); | ||||
| 657 | assert(ifindex > 0)do { if ((__builtin_expect(!!(!(ifindex > 0)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("ifindex > 0"), "../src/network/networkctl.c" , 657, __PRETTY_FUNCTION__); } while (0); | ||||
| 658 | |||||
| 659 | r = open_lldp_neighbors(ifindex, &f); | ||||
| 660 | if (r < 0) | ||||
| 661 | return r; | ||||
| 662 | |||||
| 663 | for (;;) { | ||||
| 664 | const char *system_name = NULL((void*)0), *port_id = NULL((void*)0), *port_description = NULL((void*)0); | ||||
| 665 | _cleanup_(sd_lldp_neighbor_unrefp)__attribute__((cleanup(sd_lldp_neighbor_unrefp))) sd_lldp_neighbor *n = NULL((void*)0); | ||||
| 666 | |||||
| 667 | r = next_lldp_neighbor(f, &n); | ||||
| 668 | if (r < 0) | ||||
| 669 | return r; | ||||
| 670 | if (r == 0) | ||||
| 671 | break; | ||||
| 672 | |||||
| 673 | printf("%*s", | ||||
| 674 | (int) strlen(prefix), | ||||
| 675 | c == 0 ? prefix : ""); | ||||
| 676 | |||||
| 677 | (void) sd_lldp_neighbor_get_system_name(n, &system_name); | ||||
| 678 | (void) sd_lldp_neighbor_get_port_id_as_string(n, &port_id); | ||||
| 679 | (void) sd_lldp_neighbor_get_port_description(n, &port_description); | ||||
| 680 | |||||
| 681 | printf("%s on port %s", strna(system_name), strna(port_id)); | ||||
| 682 | |||||
| 683 | if (!isempty(port_description)) | ||||
| 684 | printf(" (%s)", port_description); | ||||
| 685 | |||||
| 686 | putchar('\n'); | ||||
| 687 | |||||
| 688 | c++; | ||||
| 689 | } | ||||
| 690 | |||||
| 691 | return c; | ||||
| 692 | } | ||||
| 693 | |||||
| 694 | static void dump_ifindexes(const char *prefix, const int *ifindexes) { | ||||
| 695 | unsigned c; | ||||
| 696 | |||||
| 697 | assert(prefix)do { if ((__builtin_expect(!!(!(prefix)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("prefix"), "../src/network/networkctl.c" , 697, __PRETTY_FUNCTION__); } while (0); | ||||
| 698 | |||||
| 699 | if (!ifindexes || ifindexes[0] <= 0) | ||||
| 700 | return; | ||||
| 701 | |||||
| 702 | for (c = 0; ifindexes[c] > 0; c++) { | ||||
| 703 | char name[IF_NAMESIZE16+1]; | ||||
| 704 | |||||
| 705 | printf("%*s", | ||||
| 706 | (int) strlen(prefix), | ||||
| 707 | c == 0 ? prefix : ""); | ||||
| 708 | |||||
| 709 | if (if_indextoname(ifindexes[c], name)) | ||||
| 710 | fputs(name, stdoutstdout); | ||||
| 711 | else | ||||
| 712 | printf("%i", ifindexes[c]); | ||||
| 713 | |||||
| 714 | fputc('\n', stdoutstdout); | ||||
| 715 | } | ||||
| 716 | } | ||||
| 717 | |||||
| 718 | static void dump_list(const char *prefix, char **l) { | ||||
| 719 | char **i; | ||||
| 720 | |||||
| 721 | if (strv_isempty(l)) | ||||
| 722 | return; | ||||
| 723 | |||||
| 724 | STRV_FOREACH(i, l)for ((i) = (l); (i) && *(i); (i)++) { | ||||
| 725 | printf("%*s%s\n", | ||||
| 726 | (int) strlen(prefix), | ||||
| 727 | i == l ? prefix : "", | ||||
| 728 | *i); | ||||
| 729 | } | ||||
| 730 | } | ||||
| 731 | |||||
| 732 | static int link_status_one( | ||||
| 733 | sd_netlink *rtnl, | ||||
| 734 | sd_hwdb *hwdb, | ||||
| 735 | const LinkInfo *info) { | ||||
| 736 | |||||
| 737 | _cleanup_strv_free___attribute__((cleanup(strv_freep))) char **dns = NULL((void*)0), **ntp = NULL((void*)0), **search_domains = NULL((void*)0), **route_domains = NULL((void*)0); | ||||
| 738 | _cleanup_free___attribute__((cleanup(freep))) char *setup_state = NULL((void*)0), *operational_state = NULL((void*)0), *tz = NULL((void*)0); | ||||
| 739 | _cleanup_(sd_device_unrefp)__attribute__((cleanup(sd_device_unrefp))) sd_device *d = NULL((void*)0); | ||||
| 740 | char devid[2 + DECIMAL_STR_MAX(int)(2+(sizeof(int) <= 1 ? 3 : sizeof(int) <= 2 ? 5 : sizeof (int) <= 4 ? 10 : sizeof(int) <= 8 ? 20 : sizeof(int[-2 *(sizeof(int) > 8)])))]; | ||||
| 741 | _cleanup_free___attribute__((cleanup(freep))) char *t = NULL((void*)0), *network = NULL((void*)0); | ||||
| 742 | const char *driver = NULL((void*)0), *path = NULL((void*)0), *vendor = NULL((void*)0), *model = NULL((void*)0), *link = NULL((void*)0); | ||||
| 743 | const char *on_color_operational, *off_color_operational, | ||||
| 744 | *on_color_setup, *off_color_setup; | ||||
| 745 | _cleanup_free___attribute__((cleanup(freep))) int *carrier_bound_to = NULL((void*)0), *carrier_bound_by = NULL((void*)0); | ||||
| 746 | int r; | ||||
| 747 | |||||
| 748 | assert(rtnl)do { if ((__builtin_expect(!!(!(rtnl)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("rtnl"), "../src/network/networkctl.c", 748 , __PRETTY_FUNCTION__); } while (0); | ||||
| 749 | assert(info)do { if ((__builtin_expect(!!(!(info)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("info"), "../src/network/networkctl.c", 749 , __PRETTY_FUNCTION__); } while (0); | ||||
| 750 | |||||
| 751 | (void) sd_network_link_get_operational_state(info->ifindex, &operational_state); | ||||
| 752 | operational_state_to_color(operational_state, &on_color_operational, &off_color_operational); | ||||
| 753 | |||||
| 754 | r = sd_network_link_get_setup_state(info->ifindex, &setup_state); | ||||
| 755 | if (r == -ENODATA61) /* If there's no info available about this iface, it's unmanaged by networkd */ | ||||
| 756 | setup_state = strdup("unmanaged"); | ||||
| 757 | setup_state_to_color(setup_state, &on_color_setup, &off_color_setup); | ||||
| 758 | |||||
| 759 | (void) sd_network_link_get_dns(info->ifindex, &dns); | ||||
| 760 | (void) sd_network_link_get_search_domains(info->ifindex, &search_domains); | ||||
| 761 | (void) sd_network_link_get_route_domains(info->ifindex, &route_domains); | ||||
| 762 | (void) sd_network_link_get_ntp(info->ifindex, &ntp); | ||||
| 763 | |||||
| 764 | xsprintf(devid, "n%i", info->ifindex)do { if ((__builtin_expect(!!(!(((size_t) snprintf(devid, __extension__ (__builtin_choose_expr( !__builtin_types_compatible_p(typeof (devid), typeof(&*(devid))), sizeof(devid)/sizeof((devid) [0]), ((void)0))), "n%i", info->ifindex) < (__extension__ (__builtin_choose_expr( !__builtin_types_compatible_p(typeof (devid), typeof(&*(devid))), sizeof(devid)/sizeof((devid) [0]), ((void)0))))))),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD , ("xsprintf: " "devid" "[] must be big enough"), "../src/network/networkctl.c" , 764, __PRETTY_FUNCTION__); } while (0); | ||||
| 765 | |||||
| 766 | (void) sd_device_new_from_device_id(&d, devid); | ||||
| 767 | |||||
| 768 | if (d) { | ||||
| 769 | (void) sd_device_get_property_value(d, "ID_NET_LINK_FILE", &link); | ||||
| 770 | (void) sd_device_get_property_value(d, "ID_NET_DRIVER", &driver); | ||||
| 771 | (void) sd_device_get_property_value(d, "ID_PATH", &path); | ||||
| 772 | |||||
| 773 | r = sd_device_get_property_value(d, "ID_VENDOR_FROM_DATABASE", &vendor); | ||||
| 774 | if (r < 0) | ||||
| 775 | (void) sd_device_get_property_value(d, "ID_VENDOR", &vendor); | ||||
| 776 | |||||
| 777 | r = sd_device_get_property_value(d, "ID_MODEL_FROM_DATABASE", &model); | ||||
| 778 | if (r < 0) | ||||
| 779 | (void) sd_device_get_property_value(d, "ID_MODEL", &model); | ||||
| 780 | } | ||||
| 781 | |||||
| 782 | t = link_get_type_string(info->iftype, d); | ||||
| 783 | |||||
| 784 | (void) sd_network_link_get_network_file(info->ifindex, &network); | ||||
| 785 | |||||
| 786 | (void) sd_network_link_get_carrier_bound_to(info->ifindex, &carrier_bound_to); | ||||
| 787 | (void) sd_network_link_get_carrier_bound_by(info->ifindex, &carrier_bound_by); | ||||
| 788 | |||||
| 789 | printf("%s%s%s %i: %s\n", on_color_operational, special_glyph(BLACK_CIRCLE), off_color_operational, info->ifindex, info->name); | ||||
| 790 | |||||
| 791 | printf(" Link File: %s\n" | ||||
| 792 | " Network File: %s\n" | ||||
| 793 | " Type: %s\n" | ||||
| 794 | " State: %s%s%s (%s%s%s)\n", | ||||
| 795 | strna(link), | ||||
| 796 | strna(network), | ||||
| 797 | strna(t), | ||||
| 798 | on_color_operational, strna(operational_state), off_color_operational, | ||||
| 799 | on_color_setup, strna(setup_state), off_color_setup); | ||||
| 800 | |||||
| 801 | if (path) | ||||
| 802 | printf(" Path: %s\n", path); | ||||
| 803 | if (driver) | ||||
| 804 | printf(" Driver: %s\n", driver); | ||||
| 805 | if (vendor) | ||||
| 806 | printf(" Vendor: %s\n", vendor); | ||||
| 807 | if (model) | ||||
| 808 | printf(" Model: %s\n", model); | ||||
| 809 | |||||
| 810 | if (info->has_mac_address) { | ||||
| 811 | _cleanup_free___attribute__((cleanup(freep))) char *description = NULL((void*)0); | ||||
| 812 | char ea[ETHER_ADDR_TO_STRING_MAX(3*6)]; | ||||
| 813 | |||||
| 814 | (void) ieee_oui(hwdb, &info->mac_address, &description); | ||||
| 815 | |||||
| 816 | if (description) | ||||
| 817 | printf(" HW Address: %s (%s)\n", ether_addr_to_string(&info->mac_address, ea), description); | ||||
| 818 | else | ||||
| 819 | printf(" HW Address: %s\n", ether_addr_to_string(&info->mac_address, ea)); | ||||
| 820 | } | ||||
| 821 | |||||
| 822 | if (info->has_mtu) | ||||
| 823 | printf(" MTU: %" PRIu32"u" "\n", info->mtu); | ||||
| 824 | |||||
| 825 | (void) dump_addresses(rtnl, " Address: ", info->ifindex); | ||||
| 826 | (void) dump_gateways(rtnl, hwdb, " Gateway: ", info->ifindex); | ||||
| 827 | |||||
| 828 | dump_list(" DNS: ", dns); | ||||
| 829 | dump_list(" Search Domains: ", search_domains); | ||||
| 830 | dump_list(" Route Domains: ", route_domains); | ||||
| 831 | |||||
| 832 | dump_list(" NTP: ", ntp); | ||||
| 833 | |||||
| 834 | dump_ifindexes("Carrier Bound To: ", carrier_bound_to); | ||||
| 835 | dump_ifindexes("Carrier Bound By: ", carrier_bound_by); | ||||
| 836 | |||||
| 837 | (void) sd_network_link_get_timezone(info->ifindex, &tz); | ||||
| 838 | if (tz) | ||||
| 839 | printf(" Time Zone: %s\n", tz); | ||||
| 840 | |||||
| 841 | (void) dump_lldp_neighbors(" Connected To: ", info->ifindex); | ||||
| 842 | |||||
| 843 | return 0; | ||||
| 844 | } | ||||
| 845 | |||||
| 846 | static int system_status(sd_netlink *rtnl, sd_hwdb *hwdb) { | ||||
| 847 | _cleanup_free___attribute__((cleanup(freep))) char *operational_state = NULL((void*)0); | ||||
| 848 | _cleanup_strv_free___attribute__((cleanup(strv_freep))) char **dns = NULL((void*)0), **ntp = NULL((void*)0), **search_domains = NULL((void*)0), **route_domains = NULL((void*)0); | ||||
| 849 | const char *on_color_operational, *off_color_operational; | ||||
| 850 | |||||
| 851 | assert(rtnl)do { if ((__builtin_expect(!!(!(rtnl)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("rtnl"), "../src/network/networkctl.c", 851 , __PRETTY_FUNCTION__); } while (0); | ||||
| 852 | |||||
| 853 | (void) sd_network_get_operational_state(&operational_state); | ||||
| 854 | operational_state_to_color(operational_state, &on_color_operational, &off_color_operational); | ||||
| 855 | |||||
| 856 | printf("%s%s%s State: %s%s%s\n", | ||||
| 857 | on_color_operational, special_glyph(BLACK_CIRCLE), off_color_operational, | ||||
| 858 | on_color_operational, strna(operational_state), off_color_operational); | ||||
| 859 | |||||
| 860 | (void) dump_addresses(rtnl, " Address: ", 0); | ||||
| 861 | (void) dump_gateways(rtnl, hwdb, " Gateway: ", 0); | ||||
| 862 | |||||
| 863 | (void) sd_network_get_dns(&dns); | ||||
| 864 | dump_list(" DNS: ", dns); | ||||
| 865 | |||||
| 866 | (void) sd_network_get_search_domains(&search_domains); | ||||
| 867 | dump_list("Search Domains: ", search_domains); | ||||
| 868 | |||||
| 869 | (void) sd_network_get_route_domains(&route_domains); | ||||
| 870 | dump_list(" Route Domains: ", route_domains); | ||||
| 871 | |||||
| 872 | (void) sd_network_get_ntp(&ntp); | ||||
| 873 | dump_list(" NTP: ", ntp); | ||||
| 874 | |||||
| 875 | return 0; | ||||
| 876 | } | ||||
| 877 | |||||
| 878 | static int link_status(int argc, char *argv[], void *userdata) { | ||||
| 879 | _cleanup_(sd_netlink_unrefp)__attribute__((cleanup(sd_netlink_unrefp))) sd_netlink *rtnl = NULL((void*)0); | ||||
| 880 | _cleanup_(sd_hwdb_unrefp)__attribute__((cleanup(sd_hwdb_unrefp))) sd_hwdb *hwdb = NULL((void*)0); | ||||
| 881 | _cleanup_free___attribute__((cleanup(freep))) LinkInfo *links = NULL((void*)0); | ||||
| 882 | int r, c, i; | ||||
| 883 | |||||
| 884 | (void) pager_open(arg_no_pager, false0); | ||||
| 885 | |||||
| 886 | r = sd_netlink_open(&rtnl); | ||||
| 887 | if (r < 0) | ||||
| 888 | return log_error_errno(r, "Failed to connect to netlink: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/network/networkctl.c", 888, __func__, "Failed to connect to netlink: %m" ) : -abs(_e); }); | ||||
| 889 | |||||
| 890 | r = sd_hwdb_new(&hwdb); | ||||
| 891 | if (r < 0) | ||||
| 892 | log_debug_errno(r, "Failed to open hardware database: %m")({ int _level = ((7)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/network/networkctl.c", 892, __func__, "Failed to open hardware database: %m" ) : -abs(_e); }); | ||||
| 893 | |||||
| 894 | if (arg_all) | ||||
| 895 | c = acquire_link_info_all(rtnl, &links); | ||||
| 896 | else if (argc <= 1) | ||||
| 897 | return system_status(rtnl, hwdb); | ||||
| 898 | else | ||||
| 899 | c = acquire_link_info_strv(rtnl, argv + 1, &links); | ||||
| 900 | if (c < 0) | ||||
| 901 | return c; | ||||
| 902 | |||||
| 903 | for (i = 0; i < c; i++) { | ||||
| 904 | if (i > 0) | ||||
| 905 | fputc('\n', stdoutstdout); | ||||
| 906 | |||||
| 907 | link_status_one(rtnl, hwdb, links + i); | ||||
| 908 | } | ||||
| 909 | |||||
| 910 | return 0; | ||||
| 911 | } | ||||
| 912 | |||||
| 913 | static char *lldp_capabilities_to_string(uint16_t x) { | ||||
| 914 | static const char characters[] = { | ||||
| 915 | 'o', 'p', 'b', 'w', 'r', 't', 'd', 'a', 'c', 's', 'm', | ||||
| 916 | }; | ||||
| 917 | char *ret; | ||||
| 918 | unsigned i; | ||||
| 919 | |||||
| 920 | ret = new(char, ELEMENTSOF(characters) + 1)((char*) malloc_multiply(sizeof(char), (__extension__ (__builtin_choose_expr ( !__builtin_types_compatible_p(typeof(characters), typeof(& *(characters))), sizeof(characters)/sizeof((characters)[0]), ( (void)0))) + 1))); | ||||
| 921 | if (!ret) | ||||
| 922 | return NULL((void*)0); | ||||
| 923 | |||||
| 924 | for (i = 0; i < ELEMENTSOF(characters)__extension__ (__builtin_choose_expr( !__builtin_types_compatible_p (typeof(characters), typeof(&*(characters))), sizeof(characters )/sizeof((characters)[0]), ((void)0))); i++) | ||||
| 925 | ret[i] = (x & (1U << i)) ? characters[i] : '.'; | ||||
| 926 | |||||
| 927 | ret[i] = 0; | ||||
| 928 | return ret; | ||||
| 929 | } | ||||
| 930 | |||||
| 931 | static void lldp_capabilities_legend(uint16_t x) { | ||||
| 932 | unsigned w, i, cols = columns(); | ||||
| 933 | static const char* const table[] = { | ||||
| 934 | "o - Other", | ||||
| 935 | "p - Repeater", | ||||
| 936 | "b - Bridge", | ||||
| 937 | "w - WLAN Access Point", | ||||
| 938 | "r - Router", | ||||
| 939 | "t - Telephone", | ||||
| 940 | "d - DOCSIS cable device", | ||||
| 941 | "a - Station", | ||||
| 942 | "c - Customer VLAN", | ||||
| 943 | "s - Service VLAN", | ||||
| 944 | "m - Two-port MAC Relay (TPMR)", | ||||
| 945 | }; | ||||
| 946 | |||||
| 947 | if (x == 0) | ||||
| 948 | return; | ||||
| 949 | |||||
| 950 | printf("\nCapability Flags:\n"); | ||||
| 951 | for (w = 0, i = 0; i < ELEMENTSOF(table)__extension__ (__builtin_choose_expr( !__builtin_types_compatible_p (typeof(table), typeof(&*(table))), sizeof(table)/sizeof( (table)[0]), ((void)0))); i++) | ||||
| 952 | if (x & (1U << i) || arg_all) { | ||||
| 953 | bool_Bool newline; | ||||
| 954 | |||||
| 955 | newline = w + strlen(table[i]) + (w == 0 ? 0 : 2) > cols; | ||||
| 956 | if (newline) | ||||
| 957 | w = 0; | ||||
| 958 | w += printf("%s%s%s", newline ? "\n" : "", w == 0 ? "" : "; ", table[i]); | ||||
| 959 | } | ||||
| 960 | puts(""); | ||||
| 961 | } | ||||
| 962 | |||||
| 963 | static int link_lldp_status(int argc, char *argv[], void *userdata) { | ||||
| 964 | _cleanup_(sd_netlink_unrefp)__attribute__((cleanup(sd_netlink_unrefp))) sd_netlink *rtnl = NULL((void*)0); | ||||
| 965 | _cleanup_free___attribute__((cleanup(freep))) LinkInfo *links = NULL((void*)0); | ||||
| 966 | int i, r, c, m = 0; | ||||
| 967 | uint16_t all = 0; | ||||
| 968 | |||||
| 969 | r = sd_netlink_open(&rtnl); | ||||
| 970 | if (r < 0) | ||||
| |||||
| 971 | return log_error_errno(r, "Failed to connect to netlink: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/network/networkctl.c", 971, __func__, "Failed to connect to netlink: %m" ) : -abs(_e); }); | ||||
| 972 | |||||
| 973 | if (argc > 1) | ||||
| 974 | c = acquire_link_info_strv(rtnl, argv + 1, &links); | ||||
| 975 | else | ||||
| 976 | c = acquire_link_info_all(rtnl, &links); | ||||
| 977 | if (c
| ||||
| 978 | return c; | ||||
| 979 | |||||
| 980 | (void) pager_open(arg_no_pager, false0); | ||||
| 981 | |||||
| 982 | if (arg_legend) | ||||
| 983 | printf("%-16s %-17s %-16s %-11s %-17s %-16s\n", | ||||
| 984 | "LINK", | ||||
| 985 | "CHASSIS ID", | ||||
| 986 | "SYSTEM NAME", | ||||
| 987 | "CAPS", | ||||
| 988 | "PORT ID", | ||||
| 989 | "PORT DESCRIPTION"); | ||||
| 990 | |||||
| 991 | for (i = 0; i < c; i++) { | ||||
| 992 | _cleanup_fclose___attribute__((cleanup(fclosep))) FILE *f = NULL((void*)0); | ||||
| 993 | |||||
| 994 | r = open_lldp_neighbors(links[i].ifindex, &f); | ||||
| 995 | if (r == -ENOENT2) | ||||
| 996 | continue; | ||||
| 997 | if (r < 0) { | ||||
| 998 | log_warning_errno(r, "Failed to open LLDP data for %i, ignoring: %m", links[i].ifindex)({ int _level = ((4)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/network/networkctl.c", 998, __func__, "Failed to open LLDP data for %i, ignoring: %m" , links[i].ifindex) : -abs(_e); }); | ||||
| 999 | continue; | ||||
| 1000 | } | ||||
| 1001 | |||||
| 1002 | for (;;) { | ||||
| 1003 | _cleanup_free___attribute__((cleanup(freep))) char *cid = NULL((void*)0), *pid = NULL((void*)0), *sname = NULL((void*)0), *pdesc = NULL((void*)0); | ||||
| 1004 | const char *chassis_id = NULL((void*)0), *port_id = NULL((void*)0), *system_name = NULL((void*)0), *port_description = NULL((void*)0), *capabilities = NULL((void*)0); | ||||
| 1005 | _cleanup_(sd_lldp_neighbor_unrefp)__attribute__((cleanup(sd_lldp_neighbor_unrefp))) sd_lldp_neighbor *n = NULL((void*)0); | ||||
| 1006 | uint16_t cc; | ||||
| 1007 | |||||
| 1008 | r = next_lldp_neighbor(f, &n); | ||||
| 1009 | if (r < 0) { | ||||
| 1010 | log_warning_errno(r, "Failed to read neighbor data: %m")({ int _level = ((4)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/network/networkctl.c", 1010, __func__, "Failed to read neighbor data: %m" ) : -abs(_e); }); | ||||
| 1011 | break; | ||||
| 1012 | } | ||||
| 1013 | if (r == 0) | ||||
| 1014 | break; | ||||
| 1015 | |||||
| 1016 | (void) sd_lldp_neighbor_get_chassis_id_as_string(n, &chassis_id); | ||||
| 1017 | (void) sd_lldp_neighbor_get_port_id_as_string(n, &port_id); | ||||
| 1018 | (void) sd_lldp_neighbor_get_system_name(n, &system_name); | ||||
| 1019 | (void) sd_lldp_neighbor_get_port_description(n, &port_description); | ||||
| 1020 | |||||
| 1021 | if (chassis_id) { | ||||
| 1022 | cid = ellipsize(chassis_id, 17, 100); | ||||
| 1023 | if (cid) | ||||
| 1024 | chassis_id = cid; | ||||
| 1025 | } | ||||
| 1026 | |||||
| 1027 | if (port_id) { | ||||
| 1028 | pid = ellipsize(port_id, 17, 100); | ||||
| 1029 | if (pid) | ||||
| 1030 | port_id = pid; | ||||
| 1031 | } | ||||
| 1032 | |||||
| 1033 | if (system_name) { | ||||
| 1034 | sname = ellipsize(system_name, 16, 100); | ||||
| 1035 | if (sname) | ||||
| 1036 | system_name = sname; | ||||
| 1037 | } | ||||
| 1038 | |||||
| 1039 | if (port_description) { | ||||
| 1040 | pdesc = ellipsize(port_description, 16, 100); | ||||
| 1041 | if (pdesc) | ||||
| 1042 | port_description = pdesc; | ||||
| 1043 | } | ||||
| 1044 | |||||
| 1045 | if (sd_lldp_neighbor_get_enabled_capabilities(n, &cc) >= 0) { | ||||
| 1046 | capabilities = lldp_capabilities_to_string(cc); | ||||
| 1047 | all |= cc; | ||||
| 1048 | } | ||||
| 1049 | |||||
| 1050 | printf("%-16s %-17s %-16s %-11s %-17s %-16s\n", | ||||
| 1051 | links[i].name, | ||||
| 1052 | strna(chassis_id), | ||||
| 1053 | strna(system_name), | ||||
| 1054 | strna(capabilities), | ||||
| 1055 | strna(port_id), | ||||
| 1056 | strna(port_description)); | ||||
| 1057 | |||||
| 1058 | m++; | ||||
| 1059 | } | ||||
| 1060 | } | ||||
| 1061 | |||||
| 1062 | if (arg_legend) { | ||||
| |||||
| 1063 | lldp_capabilities_legend(all); | ||||
| 1064 | printf("\n%i neighbors listed.\n", m); | ||||
| 1065 | } | ||||
| 1066 | |||||
| 1067 | return 0; | ||||
| 1068 | } | ||||
| 1069 | |||||
| 1070 | static void help(void) { | ||||
| 1071 | printf("%s [OPTIONS...]\n\n" | ||||
| 1072 | "Query and control the networking subsystem.\n\n" | ||||
| 1073 | " -h --help Show this help\n" | ||||
| 1074 | " --version Show package version\n" | ||||
| 1075 | " --no-pager Do not pipe output into a pager\n" | ||||
| 1076 | " --no-legend Do not show the headers and footers\n" | ||||
| 1077 | " -a --all Show status for all links\n\n" | ||||
| 1078 | "Commands:\n" | ||||
| 1079 | " list [LINK...] List links\n" | ||||
| 1080 | " status [LINK...] Show link status\n" | ||||
| 1081 | " lldp [LINK...] Show LLDP neighbors\n" | ||||
| 1082 | " label Show current address label entries in the kernel\n" | ||||
| 1083 | , program_invocation_short_name); | ||||
| 1084 | } | ||||
| 1085 | |||||
| 1086 | static int parse_argv(int argc, char *argv[]) { | ||||
| 1087 | |||||
| 1088 | enum { | ||||
| 1089 | ARG_VERSION = 0x100, | ||||
| 1090 | ARG_NO_PAGER, | ||||
| 1091 | ARG_NO_LEGEND, | ||||
| 1092 | }; | ||||
| 1093 | |||||
| 1094 | static const struct option options[] = { | ||||
| 1095 | { "help", no_argument0, NULL((void*)0), 'h' }, | ||||
| 1096 | { "version", no_argument0, NULL((void*)0), ARG_VERSION }, | ||||
| 1097 | { "no-pager", no_argument0, NULL((void*)0), ARG_NO_PAGER }, | ||||
| 1098 | { "no-legend", no_argument0, NULL((void*)0), ARG_NO_LEGEND }, | ||||
| 1099 | { "all", no_argument0, NULL((void*)0), 'a' }, | ||||
| 1100 | {} | ||||
| 1101 | }; | ||||
| 1102 | |||||
| 1103 | int c; | ||||
| 1104 | |||||
| 1105 | assert(argc >= 0)do { if ((__builtin_expect(!!(!(argc >= 0)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("argc >= 0"), "../src/network/networkctl.c" , 1105, __PRETTY_FUNCTION__); } while (0); | ||||
| 1106 | assert(argv)do { if ((__builtin_expect(!!(!(argv)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("argv"), "../src/network/networkctl.c", 1106 , __PRETTY_FUNCTION__); } while (0); | ||||
| 1107 | |||||
| 1108 | while ((c = getopt_long(argc, argv, "ha", options, NULL((void*)0))) >= 0) { | ||||
| 1109 | |||||
| 1110 | switch (c) { | ||||
| 1111 | |||||
| 1112 | case 'h': | ||||
| 1113 | help(); | ||||
| 1114 | return 0; | ||||
| 1115 | |||||
| 1116 | case ARG_VERSION: | ||||
| 1117 | return version(); | ||||
| 1118 | |||||
| 1119 | case ARG_NO_PAGER: | ||||
| 1120 | arg_no_pager = true1; | ||||
| 1121 | break; | ||||
| 1122 | |||||
| 1123 | case ARG_NO_LEGEND: | ||||
| 1124 | arg_legend = false0; | ||||
| 1125 | break; | ||||
| 1126 | |||||
| 1127 | case 'a': | ||||
| 1128 | arg_all = true1; | ||||
| 1129 | break; | ||||
| 1130 | |||||
| 1131 | case '?': | ||||
| 1132 | return -EINVAL22; | ||||
| 1133 | |||||
| 1134 | default: | ||||
| 1135 | assert_not_reached("Unhandled option")do { log_assert_failed_unreachable_realm(LOG_REALM_SYSTEMD, ( "Unhandled option"), "../src/network/networkctl.c", 1135, __PRETTY_FUNCTION__ ); } while (0); | ||||
| 1136 | } | ||||
| 1137 | } | ||||
| 1138 | |||||
| 1139 | return 1; | ||||
| 1140 | } | ||||
| 1141 | |||||
| 1142 | static int networkctl_main(int argc, char *argv[]) { | ||||
| 1143 | static const Verb verbs[] = { | ||||
| 1144 | { "list", VERB_ANY((unsigned) -1), VERB_ANY((unsigned) -1), VERB_DEFAULT, list_links }, | ||||
| 1145 | { "status", VERB_ANY((unsigned) -1), VERB_ANY((unsigned) -1), 0, link_status }, | ||||
| 1146 | { "lldp", VERB_ANY((unsigned) -1), VERB_ANY((unsigned) -1), 0, link_lldp_status }, | ||||
| 1147 | { "label", VERB_ANY((unsigned) -1), VERB_ANY((unsigned) -1), 0, list_address_labels }, | ||||
| 1148 | {} | ||||
| 1149 | }; | ||||
| 1150 | |||||
| 1151 | return dispatch_verb(argc, argv, verbs, NULL((void*)0)); | ||||
| 1152 | } | ||||
| 1153 | |||||
| 1154 | static void warn_networkd_missing(void) { | ||||
| 1155 | |||||
| 1156 | if (access("/run/systemd/netif/state", F_OK0) >= 0) | ||||
| 1157 | return; | ||||
| 1158 | |||||
| 1159 | fprintf(stderrstderr, "WARNING: systemd-networkd is not running, output will be incomplete.\n\n"); | ||||
| 1160 | } | ||||
| 1161 | |||||
| 1162 | int main(int argc, char* argv[]) { | ||||
| 1163 | int r; | ||||
| 1164 | |||||
| 1165 | log_parse_environment()log_parse_environment_realm(LOG_REALM_SYSTEMD); | ||||
| 1166 | log_open(); | ||||
| 1167 | |||||
| 1168 | r = parse_argv(argc, argv); | ||||
| 1169 | if (r <= 0) | ||||
| 1170 | goto finish; | ||||
| 1171 | |||||
| 1172 | warn_networkd_missing(); | ||||
| 1173 | |||||
| 1174 | r = networkctl_main(argc, argv); | ||||
| 1175 | |||||
| 1176 | finish: | ||||
| 1177 | pager_close(); | ||||
| 1178 | |||||
| 1179 | return r < 0 ? EXIT_FAILURE1 : EXIT_SUCCESS0; | ||||
| 1180 | } |
| 1 | /* SPDX-License-Identifier: LGPL-2.1+ */ |
| 2 | #pragma once |
| 3 | |
| 4 | #include <alloca.h> |
| 5 | #include <stddef.h> |
| 6 | #include <stdlib.h> |
| 7 | #include <string.h> |
| 8 | |
| 9 | #include "macro.h" |
| 10 | |
| 11 | #define new(t, n)((t*) malloc_multiply(sizeof(t), (n))) ((t*) malloc_multiply(sizeof(t), (n))) |
| 12 | |
| 13 | #define new0(t, n)((t*) calloc((n), sizeof(t))) ((t*) calloc((n), sizeof(t))) |
| 14 | |
| 15 | #define newa(t, n)({ do { if ((__builtin_expect(!!(!(!size_multiply_overflow(sizeof (t), n))),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("!size_multiply_overflow(sizeof(t), n)" ), "../src/basic/alloc-util.h", 15, __PRETTY_FUNCTION__); } while (0); (t*) __builtin_alloca (sizeof(t)*(n)); }) \ |
| 16 | ({ \ |
| 17 | assert(!size_multiply_overflow(sizeof(t), n))do { if ((__builtin_expect(!!(!(!size_multiply_overflow(sizeof (t), n))),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("!size_multiply_overflow(sizeof(t), n)" ), "../src/basic/alloc-util.h", 17, __PRETTY_FUNCTION__); } while (0); \ |
| 18 | (t*) alloca(sizeof(t)*(n))__builtin_alloca (sizeof(t)*(n)); \ |
| 19 | }) |
| 20 | |
| 21 | #define newa0(t, n)({ do { if ((__builtin_expect(!!(!(!size_multiply_overflow(sizeof (t), n))),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("!size_multiply_overflow(sizeof(t), n)" ), "../src/basic/alloc-util.h", 21, __PRETTY_FUNCTION__); } while (0); (t*) ({ char *_new_; size_t _len_ = sizeof(t)*(n); _new_ = __builtin_alloca (_len_); (void *) memset(_new_, 0, _len_) ; }); }) \ |
| 22 | ({ \ |
| 23 | assert(!size_multiply_overflow(sizeof(t), n))do { if ((__builtin_expect(!!(!(!size_multiply_overflow(sizeof (t), n))),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("!size_multiply_overflow(sizeof(t), n)" ), "../src/basic/alloc-util.h", 23, __PRETTY_FUNCTION__); } while (0); \ |
| 24 | (t*) alloca0(sizeof(t)*(n))({ char *_new_; size_t _len_ = sizeof(t)*(n); _new_ = __builtin_alloca (_len_); (void *) memset(_new_, 0, _len_); }); \ |
| 25 | }) |
| 26 | |
| 27 | #define newdup(t, p, n)((t*) memdup_multiply(p, sizeof(t), (n))) ((t*) memdup_multiply(p, sizeof(t), (n))) |
| 28 | |
| 29 | #define newdup_suffix0(t, p, n)((t*) memdup_suffix0_multiply(p, sizeof(t), (n))) ((t*) memdup_suffix0_multiply(p, sizeof(t), (n))) |
| 30 | |
| 31 | #define malloc0(n)(calloc(1, (n))) (calloc(1, (n))) |
| 32 | |
| 33 | static inline void *mfree(void *memory) { |
| 34 | free(memory); |
| 35 | return NULL((void*)0); |
| 36 | } |
| 37 | |
| 38 | #define free_and_replace(a, b)({ free(a); (a) = (b); (b) = ((void*)0); 0; }) \ |
| 39 | ({ \ |
| 40 | free(a); \ |
| 41 | (a) = (b); \ |
| 42 | (b) = NULL((void*)0); \ |
| 43 | 0; \ |
| 44 | }) |
| 45 | |
| 46 | void* memdup(const void *p, size_t l) _alloc_(2); |
| 47 | void* memdup_suffix0(const void *p, size_t l) _alloc_(2); |
| 48 | |
| 49 | static inline void freep(void *p) { |
| 50 | free(*(void**) p); |
| 51 | } |
| 52 | |
| 53 | #define _cleanup_free___attribute__((cleanup(freep))) _cleanup_(freep)__attribute__((cleanup(freep))) |
| 54 | |
| 55 | static inline bool_Bool size_multiply_overflow(size_t size, size_t need) { |
| 56 | return _unlikely_(need != 0 && size > (SIZE_MAX / need))(__builtin_expect(!!(need != 0 && size > ((18446744073709551615UL ) / need)),0)); |
| 57 | } |
| 58 | |
| 59 | _malloc___attribute__ ((malloc)) _alloc_(1, 2) static inline void *malloc_multiply(size_t size, size_t need) { |
| 60 | if (size_multiply_overflow(size, need)) |
| 61 | return NULL((void*)0); |
| 62 | |
| 63 | return malloc(size * need); |
| 64 | } |
| 65 | |
| 66 | #if !HAVE_REALLOCARRAY1 |
| 67 | _alloc_(2, 3) static inline void *reallocarray(void *p, size_t need, size_t size) { |
| 68 | if (size_multiply_overflow(size, need)) |
| 69 | return NULL((void*)0); |
| 70 | |
| 71 | return realloc(p, size * need); |
| 72 | } |
| 73 | #endif |
| 74 | |
| 75 | _alloc_(2, 3) static inline void *memdup_multiply(const void *p, size_t size, size_t need) { |
| 76 | if (size_multiply_overflow(size, need)) |
| 77 | return NULL((void*)0); |
| 78 | |
| 79 | return memdup(p, size * need); |
| 80 | } |
| 81 | |
| 82 | _alloc_(2, 3) static inline void *memdup_suffix0_multiply(const void *p, size_t size, size_t need) { |
| 83 | if (size_multiply_overflow(size, need)) |
| 84 | return NULL((void*)0); |
| 85 | |
| 86 | return memdup_suffix0(p, size * need); |
| 87 | } |
| 88 | |
| 89 | void* greedy_realloc(void **p, size_t *allocated, size_t need, size_t size); |
| 90 | void* greedy_realloc0(void **p, size_t *allocated, size_t need, size_t size); |
| 91 | |
| 92 | #define GREEDY_REALLOC(array, allocated, need)greedy_realloc((void**) &(array), &(allocated), (need ), sizeof((array)[0])) \ |
| 93 | greedy_realloc((void**) &(array), &(allocated), (need), sizeof((array)[0])) |
| 94 | |
| 95 | #define GREEDY_REALLOC0(array, allocated, need)greedy_realloc0((void**) &(array), &(allocated), (need ), sizeof((array)[0])) \ |
| 96 | greedy_realloc0((void**) &(array), &(allocated), (need), sizeof((array)[0])) |
| 97 | |
| 98 | #define alloca0(n)({ char *_new_; size_t _len_ = n; _new_ = __builtin_alloca (_len_ ); (void *) memset(_new_, 0, _len_); }) \ |
| 99 | ({ \ |
| 100 | char *_new_; \ |
| 101 | size_t _len_ = n; \ |
| 102 | _new_ = alloca(_len_)__builtin_alloca (_len_); \ |
| 103 | (void *) memset(_new_, 0, _len_); \ |
| 104 | }) |
| 105 | |
| 106 | /* It's not clear what alignment glibc/gcc alloca() guarantee, hence provide a guaranteed safe version */ |
| 107 | #define alloca_align(size, align)({ void *_ptr_; size_t _mask_ = (align) - 1; _ptr_ = __builtin_alloca ((size) + _mask_); (void*)(((uintptr_t)_ptr_ + _mask_) & ~_mask_); }) \ |
| 108 | ({ \ |
| 109 | void *_ptr_; \ |
| 110 | size_t _mask_ = (align) - 1; \ |
| 111 | _ptr_ = alloca((size) + _mask_)__builtin_alloca ((size) + _mask_); \ |
| 112 | (void*)(((uintptr_t)_ptr_ + _mask_) & ~_mask_); \ |
| 113 | }) |
| 114 | |
| 115 | #define alloca0_align(size, align)({ void *_new_; size_t _size_ = (size); _new_ = ({ void *_ptr_ ; size_t _mask_ = ((align)) - 1; _ptr_ = __builtin_alloca ((_size_ ) + _mask_); (void*)(((uintptr_t)_ptr_ + _mask_) & ~_mask_ ); }); (void*)memset(_new_, 0, _size_); }) \ |
| 116 | ({ \ |
| 117 | void *_new_; \ |
| 118 | size_t _size_ = (size); \ |
| 119 | _new_ = alloca_align(_size_, (align))({ void *_ptr_; size_t _mask_ = ((align)) - 1; _ptr_ = __builtin_alloca ((_size_) + _mask_); (void*)(((uintptr_t)_ptr_ + _mask_) & ~_mask_); }); \ |
| 120 | (void*)memset(_new_, 0, _size_); \ |
| 121 | }) |
| 122 | |
| 123 | /* Takes inspiration from Rusts's Option::take() method: reads and returns a pointer, but at the same time resets it to |
| 124 | * NULL. See: https://doc.rust-lang.org/std/option/enum.Option.html#method.take */ |
| 125 | #define TAKE_PTR(ptr)({ typeof(ptr) _ptr_ = (ptr); (ptr) = ((void*)0); _ptr_; }) \ |
| 126 | ({ \ |
| 127 | typeof(ptr) _ptr_ = (ptr); \ |
| 128 | (ptr) = NULL((void*)0); \ |
| 129 | _ptr_; \ |
| 130 | }) |