agetty: add \4 and \6 issue file sequences to print IP addresses

Based on Andrea Bonomi <a.bonomi@endian.com> ideas.

Signed-off-by: Karel Zak <kzak@redhat.com>
This commit is contained in:
Karel Zak 2012-09-13 12:54:36 +02:00
parent df0bd828b1
commit 2b945eda3d
2 changed files with 121 additions and 3 deletions

View File

@ -268,6 +268,14 @@ may contain certain escape codes to display the system name, date and
time etc. All escape codes consist of a backslash (\\) immediately
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}).
.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}}
.TP
b
Insert the baudrate of the current line.

View File

@ -31,6 +31,9 @@
#include <netdb.h>
#include <langinfo.h>
#include <grp.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <ifaddrs.h>
#include "strutils.h"
#include "all-io.h"
@ -242,7 +245,8 @@ static void open_tty(char *tty, struct termios *tp, struct options *op);
static void termio_init(struct options *op, struct termios *tp);
static void reset_vc (const struct options *op, struct termios *tp);
static void auto_baud(struct termios *tp);
static void output_special_char (unsigned char c, struct options *op, struct termios *tp);
static void output_special_char (unsigned char c, struct options *op,
struct termios *tp, FILE *fp);
static void do_prompt(struct options *op, struct termios *tp);
static void next_speed(struct options *op, struct termios *tp);
static char *get_logname(struct options *op,
@ -1240,7 +1244,7 @@ static void do_prompt(struct options *op, struct termios *tp)
while ((c = getc(fd)) != EOF) {
if (c == '\\')
output_special_char(getc(fd), op, tp);
output_special_char(getc(fd), op, tp, fd);
else
putchar(c);
}
@ -1696,8 +1700,97 @@ 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)
{
if (!iface)
return;
if (addrs->ifa_name
&& strcmp(addrs->ifa_name, iface) == 0
&& addrs->ifa_addr
&& addrs->ifa_addr->sa_family == family) {
void *addr = NULL;
char buff[INET6_ADDRSTRLEN + 1];
switch (addrs->ifa_addr->sa_family) {
case AF_INET:
addr = &((struct sockaddr_in *) addrs->ifa_addr)->sin_addr;
break;
case AF_INET6:
addr = &((struct sockaddr_in6 *) addrs->ifa_addr)->sin6_addr;
break;
}
if (addr) {
inet_ntop(addrs->ifa_addr->sa_family, addr, buff, sizeof(buff));
printf("%s", buff);
}
} else if (addrs->ifa_next)
output_iface_ip(addrs->ifa_next, iface, family);
}
static void output_ip(sa_family_t family)
{
char host[MAXHOSTNAMELEN + 1];
struct addrinfo hints, *info = NULL;
memset(&hints, 0, sizeof(hints));
hints.ai_family = family;
if (family == AF_INET6)
hints.ai_flags = AI_V4MAPPED;
if (gethostname(host, sizeof(host)) == 0
&& getaddrinfo(host, NULL, &hints, &info) == 0
&& info) {
void *addr = NULL;
char buff[INET6_ADDRSTRLEN + 1];
switch (info->ai_family) {
case AF_INET:
addr = &((struct sockaddr_in *) info->ai_addr)->sin_addr;
break;
case AF_INET6:
addr = &((struct sockaddr_in6 *) info->ai_addr)->sin6_addr;
break;
}
inet_ntop(info->ai_family, (void *) addr, buff, sizeof(buff));
printf("%s", buff);
freeaddrinfo(info);
}
}
/*
* parses \x{argument}, if not argument specified then returns NULL, the @fd
* has to point to one char after the sequence (it means '{').
*/
static char *get_escape_argument(FILE *fd, char *buf, size_t bufsz)
{
size_t i = 0;
int c = fgetc(fd);
if (c == EOF || (unsigned char) c != '{') {
ungetc(c, fd);
return NULL;
}
do {
c = fgetc(fd);
if (c == EOF)
return NULL;
if ((unsigned char) c != '}' && i < bufsz - 1)
buf[i++] = (unsigned char) c;
} while ((unsigned char) c != '}');
buf[i] = '\0';
return buf;
}
static void output_special_char(unsigned char c, struct options *op,
struct termios *tp)
struct termios *tp, FILE *fp)
{
struct utsname uts;
@ -1808,6 +1901,23 @@ static void output_special_char(unsigned char c, struct options *op,
printf((users == 1) ? _("user") : _("users"));
break;
}
case '4':
case '6':
{
sa_family_t family = c == '4' ? AF_INET : AF_INET6;
char iface[128];
if (get_escape_argument(fp, iface, sizeof(iface))) { /* interface IP */
struct ifaddrs *addrs;
int status = getifaddrs(&addrs);
if (status != 0)
break;
output_iface_ip(addrs, iface, family);
freeifaddrs(addrs);
} else /* host IP */
output_ip(family);
break;
}
default:
putchar(c);
break;