commit 0f2907ccd2c03329079c1156cdf2974cdc4e93fe from: Chris Cappuccio via: GitHub date: Thu Mar 02 14:37:38 2023 UTC Merge pull request #54 from stspdotname/iface-status implement a cisco-style 'show interface status' command commit - e3c4ca9685cb6c571a1dff20cd7ffdd9fc13ef59 commit + 0f2907ccd2c03329079c1156cdf2974cdc4e93fe blob - 1d7172095b8d6aa24cd51143d65e5bb280634b4e blob + f5cf4677a95d48663795a2447b644bb23861ed22 --- complete.c +++ complete.c @@ -260,11 +260,11 @@ complete_ifname(char *word, int list, EditLine *el) StringList *words; size_t wordlen; unsigned char rv; + const char *status_cmd = "status"; + struct if_nameindex *ifn_list, *ifnp; words = sl_init(); wordlen = strlen(word); - - struct if_nameindex *ifn_list, *ifnp; if ((ifn_list = if_nameindex()) == NULL) return 0; @@ -275,6 +275,14 @@ complete_ifname(char *word, int list, EditLine *el) if (strncmp(word, ifnp->if_name, wordlen) == 0) sl_add(words, ifnp->if_name); } + + if (wordlen <= strlen(status_cmd) && + strncmp(word, status_cmd, wordlen) == 0) { + char *s = strdup(status_cmd); + if (s == NULL) + err(1, "strdup"); + sl_add(words, s); + } rv = complete_ambiguous(word, list, words, el); if_freenameindex(ifn_list); blob - da7b5a30346564f6d74d6cb28708265c35898d35 blob + 06e4244f301a60a0ef59c71689125fe9b577b2c9 --- externs.h +++ externs.h @@ -469,6 +469,11 @@ int phys_status(int, char *, char *, char *, int, int) int intmedia(char *, int, int, char **); int intmediaopt(char *, int, int, char **); int conf_media_status(FILE *, int, char *); +struct ifmediareq; +const char *get_ifm_linkstate_str(struct ifmediareq *); +const char *get_ifm_options_str(char *, size_t, uint64_t, uint64_t *); +const char *get_ifm_type_str(uint64_t); +const char *get_ifm_subtype_str(uint64_t); /* passwd.c */ #define NSHPASSWD_TEMP "/var/run/nshpasswd" blob - 154dfdd80956f1317b4e2eefa2322caf1dc6c2b4 blob + ff37c8bb238a7c157908dcaf8a18acf7bd72bfc7 --- if.c +++ if.c @@ -39,6 +39,7 @@ #include #include #include +#include #include #include #include @@ -50,6 +51,8 @@ #include "externs.h" char *iftype(int int_type); +const char *get_linkstate(int, int); +void show_int_status(char *, int); char *get_hwdaddr(char *ifname); void pack_ifaliasreq(struct ifaliasreq *, ip_t *, struct in_addr *, char *); void pack_in6aliasreq(struct in6_aliasreq *, ip_t *, struct in6_addr *, char *); @@ -99,6 +102,116 @@ void imr_init(char *ifname) return; strlcpy (imrif, ifname, IFNAMSIZ); memset (&imrsave, 0, sizeof(imrsave)); +} + +const char * +get_linkstate(int mt, int link_state) +{ + const struct if_status_description if_status_descriptions[] = + LINK_STATE_DESCRIPTIONS; + const struct if_status_description *p; + static char buf[8]; + + for (p = if_status_descriptions; p->ifs_string != NULL; p++) { + if (LINK_STATE_DESC_MATCH(p, mt, link_state)) + return (p->ifs_string); + } + snprintf(buf, sizeof(buf), "[#%d]", link_state); + return buf; +} + +void +show_int_status(char *ifname, int ifs) +{ + struct ifreq ifr; + struct ifmediareq ifmr; + int flags; + struct if_data if_data; + struct sockaddr_dl *sdl = NULL; + const char *link_state_desc = NULL; + struct ifaddrs *ifap, *ifa; + uint64_t *media_list = NULL, seen_options = 0; + const char *ifm_type = NULL, *ifm_subtype = NULL; + char ifm_options_current[128]; + char ifm_options_active[128]; + + ifm_options_current[0] = '\0'; + ifm_options_active[0] = '\0'; + + memset(&ifr, 0, sizeof(ifr)); + strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); + + flags = get_ifflags(ifname, ifs); + ifr.ifr_data = (caddr_t)&if_data; + if (ioctl(ifs, SIOCGIFDATA, (caddr_t)&ifr) < 0) { + printf("%% show_int_status: SIOCGIFDATA: %s\n", + strerror(errno)); + return; + } + + memset(&ifmr, 0, sizeof(ifmr)); + strlcpy(ifmr.ifm_name, ifname, sizeof(ifmr.ifm_name)); + + if (getifaddrs(&ifap) != 0) { + printf("%% show_int_status: getifaddrs: %s\n", + strerror(errno)); + return; + } + for (ifa = ifap; ifa; ifa = ifa->ifa_next) { + if (ifa->ifa_addr->sa_family == AF_LINK && + (strcmp(ifname, ifa->ifa_name) == 0)) { + sdl = (struct sockaddr_dl *)ifa->ifa_addr; + link_state_desc = get_linkstate(sdl->sdl_type, + if_data.ifi_link_state); + break; + } + } + + if (ioctl(ifs, SIOCGIFMEDIA, (caddr_t)&ifmr) != -1 && + ifmr.ifm_count > 0) { + media_list = calloc(ifmr.ifm_count, sizeof(*media_list)); + if (media_list == NULL) { + printf("%% show_int_status: calloc: %s\n", + strerror(errno)); + return; + } + ifmr.ifm_ulist = media_list; + if (ioctl(ifs, SIOCGIFMEDIA, (caddr_t)&ifmr) == -1) { + printf("%% show_int_status: SIOCGIFMEDIA: %s\n", + strerror(errno)); + return; + } + if (link_state_desc == NULL) + link_state_desc = get_ifm_linkstate_str(&ifmr); + } + + /* Avoid displaying "unknown" for any non-physical interface. */ + if (link_state_desc == NULL || strcmp(link_state_desc, "unknown") == 0) + link_state_desc = "-"; + + get_ifm_options_str(ifm_options_current, sizeof(ifm_options_current), + ifmr.ifm_current, &seen_options); + if (IFM_OPTIONS(ifmr.ifm_current) != IFM_OPTIONS(ifmr.ifm_active)) { + get_ifm_options_str(ifm_options_active, + sizeof(ifm_options_active), ifmr.ifm_active, &seen_options); + } + + ifm_type = get_ifm_type_str(ifmr.ifm_active); + /* Avoid displaying "autoselect" for any non-physical interface. */ + if (IFM_SUBTYPE(ifmr.ifm_active) != IFM_AUTO) + ifm_subtype = get_ifm_subtype_str(ifmr.ifm_active); + + printf(" %-7s %-7s %-15s %s%s%s%s%s%s%s\n", ifname, + (flags & IFF_UP) ? "up" : "down", link_state_desc, + ifm_type ? ifm_type : "", + ifm_type ? " " : "", + ifm_subtype ? ifm_subtype : "", + ifm_subtype ? " " : "", + ifm_options_current, + ifm_options_current[0] != '\0' ? " " : "", + ifm_options_active[0] != '\0' ? ifm_options_active : ""); + + free(media_list); } int @@ -124,12 +237,18 @@ show_int(int argc, char **argv) if (argc == 3) ifname = argv[2]; + if ((ifs = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + printf("%% show_int: %s\n", strerror(errno)); + return(1); + } + /* * Show all interfaces when no ifname specified. */ if (ifname == NULL) { if ((ifn_list = if_nameindex()) == NULL) { printf("%% show_int: if_nameindex failed\n"); + close(ifs); return 0; } for (ifnp = ifn_list; ifnp->if_name != NULL; ifnp++) { @@ -138,14 +257,23 @@ show_int(int argc, char **argv) show_int(3, args); } if_freenameindex(ifn_list); + close(ifs); return(0); + } else if (isprefix(ifname, "status")) { + if ((ifn_list = if_nameindex()) == NULL) { + printf("%% show_int: if_nameindex failed\n"); + close(ifs); + return 0; + } + puts("% Name Status Link Media"); + for (ifnp = ifn_list; ifnp->if_name != NULL; ifnp++) + show_int_status(ifnp->if_name, ifs); + if_freenameindex(ifn_list); + close(ifs); + return(0); } else if (!is_valid_ifname(ifname)) { printf("%% interface %s not found\n", ifname); - return(1); - } - - if ((ifs = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { - printf("%% show_int: %s\n", strerror(errno)); + close(ifs); return(1); } blob - 037a038913e6643f46e1614500cba779f5060ffc blob + 5dd1ae59534881e630104e0d7f762b8b8a732fde --- media.c +++ media.c @@ -228,21 +228,69 @@ init_current_media(int s, char *ifname) return(media_current); } -const char * -get_media_type_string(uint64_t mword) +const char * +get_ifm_linkstate_str(struct ifmediareq *ifmr) { + const uint64_t ifm_status_valid_list[] = IFM_STATUS_VALID_LIST; + const struct ifmedia_status_description *ifms; + int bitno; + + if ((ifmr->ifm_status & IFM_AVALID) == 0) + return NULL; + + for (bitno = 0; ifm_status_valid_list[bitno] != 0; bitno++) { + for (ifms = ifm_status_descriptions; + ifms->ifms_valid != 0; ifms++) { + if (ifms->ifms_type != IFM_TYPE(ifmr->ifm_current) || + ifms->ifms_valid != ifm_status_valid_list[bitno]) + continue; + return IFM_STATUS_DESC(ifms, ifmr->ifm_status); + } + } + + return NULL; +} + +const char * +get_ifm_options_str(char *buf, size_t size, uint64_t ifmw, + uint64_t *seen_options) +{ const struct ifmedia_description *desc; + buf[0] = '\0'; + + /* Find options. */ + for (desc = ifm_option_descriptions; desc->ifmt_string != NULL; + desc++) { + if (IFM_TYPE_MATCH(desc->ifmt_word, ifmw) && + (IFM_OPTIONS(ifmw) & IFM_OPTIONS(desc->ifmt_word)) != 0 && + (*seen_options & IFM_OPTIONS(desc->ifmt_word)) == 0) { + if (buf[0] != '\0') + strlcat(buf, " ", size); + strlcat(buf, desc->ifmt_string, size); + *seen_options |= IFM_OPTIONS(desc->ifmt_word); + } + } + + return buf; +} + +const char * +get_ifm_type_str(uint64_t mword) +{ + const struct ifmedia_description *desc; + for (desc = ifm_type_descriptions; desc->ifmt_string != NULL; desc++) { if (IFM_TYPE(mword) == desc->ifmt_word) return (desc->ifmt_string); } - return (""); + + return NULL; } const char * -get_media_subtype_string(uint64_t mword) +get_ifm_subtype_str(uint64_t mword) { const struct ifmedia_description *desc; @@ -252,6 +300,31 @@ get_media_subtype_string(uint64_t mword) IFM_SUBTYPE(desc->ifmt_word) == IFM_SUBTYPE(mword)) return (desc->ifmt_string); } + + return NULL; +} + +const char * +get_media_type_string(uint64_t mword) +{ + const char *s; + + s = get_ifm_type_str(mword); + if (s != NULL) + return (s); + + return (""); +} + +const char * +get_media_subtype_string(uint64_t mword) +{ + const char *s; + + s = get_ifm_subtype_str(mword); + if (s != NULL) + return (s); + return (""); }