summaryrefslogtreecommitdiffstats
path: root/term-utils
diff options
context:
space:
mode:
authorKarel Zak2014-05-13 15:07:08 +0200
committerKarel Zak2014-05-13 15:23:42 +0200
commit0f283438bfdf7b6e6e916b63a2c317d938b1463a (patch)
tree13b2371c39f5d962d71a045d343cd0263640fb91 /term-utils
parentlib/colors: add to the man page hint about $HOME stuff (diff)
downloadkernel-qcow2-util-linux-0f283438bfdf7b6e6e916b63a2c317d938b1463a.tar.gz
kernel-qcow2-util-linux-0f283438bfdf7b6e6e916b63a2c317d938b1463a.tar.xz
kernel-qcow2-util-linux-0f283438bfdf7b6e6e916b63a2c317d938b1463a.zip
agetty: use the "best" interface for \4 and \6
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>
Diffstat (limited to 'term-utils')
-rw-r--r--term-utils/agetty.89
-rw-r--r--term-utils/agetty.c100
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: