]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
agetty: use the "best" interface for \4 and \6
authorKarel Zak <kzak@redhat.com>
Tue, 13 May 2014 13:07:08 +0000 (15:07 +0200)
committerKarel Zak <kzak@redhat.com>
Tue, 13 May 2014 13:23:42 +0000 (15:23 +0200)
The issue file escape sequences \4 and \6 prints the host IP when no
interface is specified. That's useless on some virtual machines where
gethostname()+getaddrinfo() returns 127.0.0.1.

The seems better to print IP of the "best" interface (UP, RUNNING, non-LOOPBACK)
and use gethostname() as painful fallback only.

Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=1090935
Signed-off-by: Karel Zak <kzak@redhat.com>
term-utils/agetty.8
term-utils/agetty.c

index ad0bfa02b2bdf0e46dc6e346e0c6c7ab84e71ce6..5fd80858fa1ba3e9297ee8aae6254600486e7c19 100644 (file)
@@ -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.
index 5163550fbd4bc8b1383e2d47e7338d06a00968d5..7840f402dfabf381e037b1f4a0214b0cc0de28ff 100644 (file)
@@ -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: