diff options
-rw-r--r-- | term-utils/agetty.8 | 9 | ||||
-rw-r--r-- | term-utils/agetty.c | 100 |
2 files changed, 67 insertions, 42 deletions
diff --git a/term-utils/agetty.8 b/term-utils/agetty.8 index ad0bfa02b..5fd80858f 100644 --- a/term-utils/agetty.8 +++ b/term-utils/agetty.8 @@ -305,12 +305,13 @@ followed by one of the letters explained below. .TP 4 or 4{interface} -Insert the IPv4 address of the machine hostname or IPv4 address the configured -network interface if the interface argument is specified (e.g. \\4{eth0}). +Insert the IPv4 address the specified network interface (e.g. \\4{eth0}) +and if the interface argument is not specified then select the first fully +configured (UP, non-LOCALBACK, RUNNING) interface. If not found any +configured interface fall back to IP address of the machine hostname. .TP 6 or 6{interface} -Insert the IPv6 address of the machine hostname or IPv6 address the configured -network interface if the interface argument is specified (e.g. \\6{eth0}} +The same as \\4 but for IPv6. .TP b Insert the baudrate of the current line. diff --git a/term-utils/agetty.c b/term-utils/agetty.c index 5163550fb..7840f402d 100644 --- a/term-utils/agetty.c +++ b/term-utils/agetty.c @@ -34,6 +34,7 @@ #include <arpa/inet.h> #include <netdb.h> #include <ifaddrs.h> +#include <net/if.h> #include "strutils.h" #include "all-io.h" @@ -1952,41 +1953,70 @@ static void log_warn(const char *fmt, ...) va_end(ap); } -static void output_iface_ip(struct ifaddrs *addrs, const char *iface, sa_family_t family) +static void print_addr(sa_family_t family, void *addr) { - if (!iface) + char buff[INET6_ADDRSTRLEN + 1]; + + inet_ntop(family, addr, buff, sizeof(buff)); + printf("%s", buff); +} + +/* + * Prints IP for the specified interface (@iface), if the interface is not + * specified then prints the "best" one (UP, RUNNING, non-LOOPBACK). If not + * found the "best" interface then prints at least host IP. + */ +static void output_iface_ip(struct ifaddrs *addrs, + const char *iface, + sa_family_t family) +{ + struct ifaddrs *p; + struct addrinfo hints, *info = NULL; + char *host = NULL; + void *addr = NULL; + + if (!addrs) return; - if (addrs->ifa_name - && strcmp(addrs->ifa_name, iface) == 0 - && addrs->ifa_addr - && addrs->ifa_addr->sa_family == family) { + for (p = addrs; p; p = p->ifa_next) { - void *addr = NULL; - char buff[INET6_ADDRSTRLEN + 1]; + if (!p->ifa_name || + !p->ifa_addr || + p->ifa_addr->sa_family != family) + continue; + + if (iface) { + /* Filter out by interface name */ + if (strcmp(p->ifa_name, iface) != 0) + continue; + } else { + /* Select the "best" interface */ + if ((p->ifa_flags & IFF_LOOPBACK) || + !(p->ifa_flags & IFF_UP) || + !(p->ifa_flags & IFF_RUNNING)) + continue; + } - switch (addrs->ifa_addr->sa_family) { + addr = NULL; + switch (p->ifa_addr->sa_family) { case AF_INET: - addr = &((struct sockaddr_in *) addrs->ifa_addr)->sin_addr; + addr = &((struct sockaddr_in *) p->ifa_addr)->sin_addr; break; case AF_INET6: - addr = &((struct sockaddr_in6 *) addrs->ifa_addr)->sin6_addr; + addr = &((struct sockaddr_in6 *) p->ifa_addr)->sin6_addr; break; } + if (addr) { - inet_ntop(addrs->ifa_addr->sa_family, addr, buff, sizeof(buff)); - printf("%s", buff); + print_addr(family, addr); + return; } + } - } else if (addrs->ifa_next) - output_iface_ip(addrs->ifa_next, iface, family); -} - -static void output_ip(sa_family_t family) -{ - char *host; - struct addrinfo hints, *info = NULL; + if (iface) + return; + /* Hmm.. not found the best interface, print host IP at least */ memset(&hints, 0, sizeof(hints)); hints.ai_family = family; if (family == AF_INET6) @@ -1994,9 +2024,6 @@ static void output_ip(sa_family_t family) host = xgethostname(); if (host && getaddrinfo(host, NULL, &hints, &info) == 0 && info) { - - void *addr = NULL; - switch (info->ai_family) { case AF_INET: addr = &((struct sockaddr_in *) info->ai_addr)->sin_addr; @@ -2005,12 +2032,8 @@ static void output_ip(sa_family_t family) addr = &((struct sockaddr_in6 *) info->ai_addr)->sin6_addr; break; } - if (addr) { - char buff[INET6_ADDRSTRLEN + 1]; - - inet_ntop(info->ai_family, (void *) addr, buff, sizeof(buff)); - printf("%s", buff); - } + if (addr) + print_addr(family, addr); freeaddrinfo(info); } @@ -2175,17 +2198,18 @@ static void output_special_char(unsigned char c, struct options *op, case '6': { sa_family_t family = c == '4' ? AF_INET : AF_INET6; + struct ifaddrs *addrs = NULL; char iface[128]; - if (get_escape_argument(fp, iface, sizeof(iface))) { /* interface IP */ - struct ifaddrs *addrs; - int status = getifaddrs(&addrs); - if (status != 0) - break; + if (getifaddrs(&addrs)) + break; + + if (get_escape_argument(fp, iface, sizeof(iface))) output_iface_ip(addrs, iface, family); - freeifaddrs(addrs); - } else /* host IP */ - output_ip(family); + else + output_iface_ip(addrs, NULL, family); + + freeifaddrs(addrs); break; } default: |