diff --git a/SOURCES/0179-agetty-backport-RHEL-8-version.patch b/SOURCES/0179-agetty-backport-RHEL-8-version.patch
new file mode 100644
index 0000000..4a2bfad
--- /dev/null
+++ b/SOURCES/0179-agetty-backport-RHEL-8-version.patch
@@ -0,0 +1,1912 @@
+From ea152b4e9656945f17d18bf4e5ece91e3e57ebb1 Mon Sep 17 00:00:00 2001
+From: Karel Zak <kzak@redhat.com>
+Date: Tue, 29 Jan 2019 11:57:55 +0100
+Subject: [PATCH] agetty: backport RHEL-8 version
+
+The code is identical to RHEL-8.0, except:
+
+ * disabled ISSUEDIR_SUPPORT
+ * disabled AGETTY_RELOAD
+ * removed \e and \e{name} feature
+
+Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=1664752
+Signed-off-by: Karel Zak <kzak@redhat.com>
+---
+ include/pathnames.h |    5 +-
+ term-utils/agetty.c | 1141 +++++++++++++++++++++++++++++++------------
+ 2 files changed, 839 insertions(+), 307 deletions(-)
+
+diff --git a/include/pathnames.h b/include/pathnames.h
+index fa4bddbad..ec5eef918 100644
+--- a/include/pathnames.h
++++ b/include/pathnames.h
+@@ -64,9 +64,10 @@
+ 
+ /* used in term-utils/agetty.c */
+ #define _PATH_ISSUE		"/etc/issue"
+-#define _PATH_OS_RELEASE	"/etc/os-release"
++#define _PATH_ISSUEDIR		_PATH_ISSUE ".d"
++#define _PATH_OS_RELEASE_ETC	"/etc/os-release"
++#define _PATH_OS_RELEASE_USR	"/usr/lib/os-release"
+ #define _PATH_NUMLOCK_ON	_PATH_LOCALSTATEDIR "/numlock-on"
+-
+ #define _PATH_LOGINDEFS		"/etc/login.defs"
+ 
+ /* used in misc-utils/look.c */
+diff --git a/term-utils/agetty.c b/term-utils/agetty.c
+index 948d77246..c3c7ab504 100644
+--- a/term-utils/agetty.c
++++ b/term-utils/agetty.c
+@@ -10,6 +10,7 @@
+  *
+  * This program is freely distributable.
+  */
++
+ #include <stdio.h>
+ #include <unistd.h>
+ #include <stdlib.h>
+@@ -20,19 +21,21 @@
+ #include <sys/ioctl.h>
+ #include <sys/types.h>
+ #include <sys/stat.h>
++#include <sys/wait.h>
+ #include <fcntl.h>
+ #include <stdarg.h>
+ #include <ctype.h>
+-#include <utmp.h>
++#include <utmpx.h>
+ #include <getopt.h>
+ #include <time.h>
+-#include <sys/file.h>
+ #include <sys/socket.h>
+ #include <langinfo.h>
+ #include <grp.h>
+ #include <arpa/inet.h>
+ #include <netdb.h>
+ #include <ifaddrs.h>
++#include <net/if.h>
++#include <sys/utsname.h>
+ 
+ #include "strutils.h"
+ #include "all-io.h"
+@@ -41,14 +44,37 @@
+ #include "c.h"
+ #include "widechar.h"
+ #include "ttyutils.h"
++#include "env.h"
++
++#ifdef USE_PLYMOUTH_SUPPORT
++# include "plymouth-ctrl.h"
++#endif
++
++#ifdef HAVE_SYS_PARAM_H
++# include <sys/param.h>
++#endif
++
++#if defined(__FreeBSD_kernel__)
++# include <pty.h>
++# ifdef HAVE_UTMP_H
++#  include <utmp.h>
++# endif
++# ifdef HAVE_LIBUTIL_H
++#  include <libutil.h>
++# endif
++#endif
+ 
+ #ifdef __linux__
+ #  include <sys/kd.h>
+-#  include <sys/param.h>
+ #  define USE_SYSLOG
+ #  ifndef DEFAULT_VCTERM
+ #    define DEFAULT_VCTERM "linux"
+ #  endif
++#  if defined (__s390__) || defined (__s390x__)
++#    define DEFAULT_TTYS0  "dumb"
++#    define DEFAULT_TTY32  "ibm327x"
++#    define DEFAULT_TTYS1  "vt220"
++#  endif
+ #  ifndef DEFAULT_STERM
+ #    define DEFAULT_STERM  "vt102"
+ #  endif
+@@ -69,6 +95,10 @@
+ #  endif
+ #endif
+ 
++#ifdef __FreeBSD_kernel__
++#define USE_SYSLOG
++#endif
++
+ /* If USE_SYSLOG is undefined all diagnostics go to /dev/console. */
+ #ifdef	USE_SYSLOG
+ #  include <syslog.h>
+@@ -86,9 +116,9 @@
+ /*
+  * Things you may want to modify.
+  *
+- * If ISSUE is not defined, agetty will never display the contents of the
+- * /etc/issue file. You will not want to spit out large "issue" files at the
+- * wrong baud rate. Relevant for System V only.
++ * If ISSUE_SUPPORT is not defined, agetty will never display the contents of
++ * the /etc/issue file. You will not want to spit out large "issue" files at
++ * the wrong baud rate. Relevant for System V only.
+  *
+  * You may disagree with the default line-editing etc. characters defined
+  * below. Note, however, that DEL cannot be used for interrupt generation
+@@ -97,14 +127,26 @@
+ 
+ /* Displayed before the login prompt. */
+ #ifdef	SYSV_STYLE
+-#  define ISSUE _PATH_ISSUE
+-#  include <sys/utsname.h>
++#  define ISSUE_SUPPORT
+ #endif
+ 
+ /* Login prompt. */
+ #define LOGIN		"login: "
+ #define LOGIN_ARGV_MAX	16		/* Numbers of args for login */
+ 
++/*
++ * agetty --reload
++ */
++#ifdef AGETTY_RELOAD
++# include <sys/inotify.h>
++# include <linux/netlink.h>
++# include <linux/rtnetlink.h>
++# define AGETTY_RELOAD_FILENAME "/run/agetty.reload"	/* trigger file */
++# define AGETTY_RELOAD_FDNONE	-2			/* uninitialized fd */
++static int inotify_fd = AGETTY_RELOAD_FDNONE;
++static int netlink_fd = AGETTY_RELOAD_FDNONE;
++#endif
++
+ /*
+  * When multiple baud rates are specified on the command line, the first one
+  * we will try is the first one specified.
+@@ -116,7 +158,7 @@
+ 
+ struct options {
+ 	int flags;			/* toggle switches, see below */
+-	int timeout;			/* time-out period */
++	unsigned int timeout;			/* time-out period */
+ 	char *autolog;			/* login the user automatically */
+ 	char *chdir;			/* Chdir before the login */
+ 	char *chroot;			/* Chroot before the login */
+@@ -126,11 +168,11 @@ struct options {
+ 	char *vcline;			/* line of virtual console */
+ 	char *term;			/* terminal type */
+ 	char *initstring;		/* modem init string */
+-	char *issue;			/* alternative issue file */
++	char *issue;			/* alternative issue file or directory */
+ 	char *erasechars;		/* string with erase chars */
+ 	char *killchars;		/* string with kill chars */
+ 	char *osrelease;		/* /etc/os-release data */
+-	int delay;			/* Sleep seconds before prompt */
++	unsigned int delay;			/* Sleep seconds before prompt */
+ 	int nice;			/* Run login with this priority */
+ 	int numspeed;			/* number of baud rates to try */
+ 	int clocal;			/* CLOCAL_MODE_* */
+@@ -145,12 +187,12 @@ enum {
+ };
+ 
+ #define	F_PARSE		(1<<0)	/* process modem status messages */
+-#define	F_ISSUE		(1<<1)	/* display /etc/issue */
++#define	F_ISSUE		(1<<1)	/* display /etc/issue or /etc/issue.d */
+ #define	F_RTSCTS	(1<<2)	/* enable RTS/CTS flow control */
+ 
+ #define F_INITSTRING    (1<<4)	/* initstring is set */
+ #define F_WAITCRLF	(1<<5)	/* wait for CR or LF */
+-#define F_CUSTISSUE	(1<<6)	/* give alternative issue file */
++
+ #define F_NOPROMPT	(1<<7)	/* do not ask for login name! */
+ #define F_LCUC		(1<<8)	/* support for *LCUC stty modes */
+ #define F_KEEPSPEED	(1<<9)	/* follow baud rate from kernel */
+@@ -189,16 +231,14 @@ static const struct Speedtab speedtab[] = {
+ 	{2400, B2400},
+ 	{4800, B4800},
+ 	{9600, B9600},
+-#ifdef	B19200
++#ifdef B19200
+ 	{19200, B19200},
+-#endif
+-#ifdef	B38400
+-	{38400, B38400},
+-#endif
+-#ifdef	EXTA
++#elif defined(EXTA)
+ 	{19200, EXTA},
+ #endif
+-#ifdef	EXTB
++#ifdef B38400
++	{38400, B38400},
++#elif defined(EXTB)
+ 	{38400, EXTB},
+ #endif
+ #ifdef B57600
+@@ -209,6 +249,42 @@ static const struct Speedtab speedtab[] = {
+ #endif
+ #ifdef B230400
+ 	{230400, B230400},
++#endif
++#ifdef B460800
++	{460800, B460800},
++#endif
++#ifdef B500000
++	{500000, B500000},
++#endif
++#ifdef B576000
++	{576000, B576000},
++#endif
++#ifdef B921600
++	{921600, B921600},
++#endif
++#ifdef B1000000
++	{1000000, B1000000},
++#endif
++#ifdef B1152000
++	{1152000, B1152000},
++#endif
++#ifdef B1500000
++	{1500000, B1500000},
++#endif
++#ifdef B2000000
++	{2000000, B2000000},
++#endif
++#ifdef B2500000
++	{2500000, B2500000},
++#endif
++#ifdef B3000000
++	{3000000, B3000000},
++#endif
++#ifdef B3500000
++	{3500000, B3500000},
++#endif
++#ifdef B4000000
++	{4000000, B4000000},
+ #endif
+ 	{0, 0},
+ };
+@@ -221,6 +297,7 @@ 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 list_speeds(void);
+ 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);
+@@ -231,7 +308,8 @@ static void termio_final(struct options *op,
+ 			 struct termios *tp, struct chardata *cp);
+ static int caps_lock(char *s);
+ static speed_t bcode(char *s);
+-static void usage(FILE * out) __attribute__((__noreturn__));
++static void usage(void) __attribute__((__noreturn__));
++static void exit_slowly(int code) __attribute__((__noreturn__));
+ static void log_err(const char *, ...) __attribute__((__noreturn__))
+ 			       __attribute__((__format__(printf, 1, 2)));
+ static void log_warn (const char *, ...)
+@@ -239,13 +317,16 @@ static void log_warn (const char *, ...)
+ static ssize_t append(char *dest, size_t len, const char  *sep, const char *src);
+ static void check_username (const char* nm);
+ static void login_options_to_argv(char *argv[], int *argc, char *str, char *username);
++static void reload_agettys(void);
++static void print_issue_file(struct options *op, struct termios *tp);
+ 
+ /* Fake hostname for ut_host specified on command line. */
+ static char *fakehost;
+ 
+ #ifdef DEBUGGING
++# include "closestream.h"
+ # ifndef DEBUG_OUTPUT
+-#  define DEBUG_OUTPUT "/dev/ttyp0"
++#  define DEBUG_OUTPUT "/dev/tty10"
+ # endif
+ # define debug(s) do { fprintf(dbf,s); fflush(dbf); } while (0)
+ FILE *dbf;
+@@ -261,8 +342,7 @@ int main(int argc, char **argv)
+ 	struct options options = {
+ 		.flags  =  F_ISSUE,		/* show /etc/issue (SYSV_STYLE) */
+ 		.login  =  _PATH_LOGIN,		/* default login program */
+-		.tty    = "tty1",		/* default tty line */
+-		.issue  =  ISSUE		/* default issue file */
++		.tty    = "tty1"		/* default tty line */
+ 	};
+ 	char *login_argv[LOGIN_ARGV_MAX + 1];
+ 	int login_argc = 0;
+@@ -283,8 +363,12 @@ int main(int argc, char **argv)
+ 
+ #ifdef DEBUGGING
+ 	dbf = fopen(DEBUG_OUTPUT, "w");
+-	for (int i = 1; i < argc; i++)
++	for (int i = 1; i < argc; i++) {
++		if (i > 1)
++			debug(" ");
+ 		debug(argv[i]);
++	}
++	debug("\n");
+ #endif				/* DEBUGGING */
+ 
+ 	/* Parse command-line arguments. */
+@@ -311,6 +395,13 @@ int main(int argc, char **argv)
+ 	sigaction(SIGHUP, &sa_hup, NULL);
+ 
+ 	tcsetpgrp(STDIN_FILENO, getpid());
++
++	/* Default is to follow the current line speed and then default to 9600 */
++	if ((options.flags & F_VCONSOLE) == 0 && options.numspeed == 0) {
++		options.speeds[options.numspeed++] = bcode("9600");
++		options.flags |= F_KEEPSPEED;
++	}
++
+ 	/* Initialize the termios settings (raw mode, eight-bit, blocking i/o). */
+ 	debug("calling termio_init\n");
+ 	termio_init(&options, &termios);
+@@ -337,7 +428,7 @@ int main(int argc, char **argv)
+ 
+ 	/* Set the optional timer. */
+ 	if (options.timeout)
+-		alarm((unsigned) options.timeout);
++		alarm(options.timeout);
+ 
+ 	/* Optionally wait for CR or LF before writing /etc/issue */
+ 	if (serial_tty_option(&options, F_WAITCRLF)) {
+@@ -362,7 +453,9 @@ int main(int argc, char **argv)
+ 		username = options.autolog;
+ 	}
+ 
+-	if ((options.flags & F_NOPROMPT) == 0) {
++	if (options.flags & F_NOPROMPT) {	/* --skip-login */
++		print_issue_file(&options, &termios);
++	} else {				/* regular (auto)login */
+ 		if (options.autolog) {
+ 			/* Autologin prompt */
+ 			do_prompt(&options, &termios);
+@@ -372,7 +465,7 @@ int main(int argc, char **argv)
+ 			debug("reading login name\n");
+ 			while ((username =
+ 				get_logname(&options, &termios, &chardata)) == NULL)
+-				if ((options.flags & F_VCONSOLE) == 0)
++				if ((options.flags & F_VCONSOLE) == 0 && options.numspeed)
+ 					next_speed(&options, &termios);
+ 		}
+ 	}
+@@ -403,9 +496,12 @@ int main(int argc, char **argv)
+ 		login_options_to_argv(login_argv, &login_argc,
+ 				      options.logopt, username);
+ 	} else {
+-		if (fakehost && (options.flags & F_REMOTE)) {
+-			login_argv[login_argc++] = "-h";
+-			login_argv[login_argc++] = fakehost;
++		if (options.flags & F_REMOTE) {
++			if (fakehost) {
++				login_argv[login_argc++] = "-h";
++				login_argv[login_argc++] = fakehost;
++			} else if (options.flags & F_NOHOSTNAME)
++				login_argv[login_argc++] = "-H";
+ 		}
+ 		if (username) {
+ 			if (options.autolog)
+@@ -418,25 +514,18 @@ int main(int argc, char **argv)
+ 
+ 	login_argv[login_argc] = NULL;	/* last login argv */
+ 
+-	if (options.chroot) {
+-		if (chroot(options.chroot) < 0)
+-			log_err(_("%s: can't change root directory %s: %m"),
+-				options.tty, options.chroot);
+-	}
+-	if (options.chdir) {
+-		if (chdir(options.chdir) < 0)
+-			log_err(_("%s: can't change working directory %s: %m"),
+-				options.tty, options.chdir);
+-	}
+-	if (options.nice) {
+-		if (nice(options.nice) < 0)
+-			log_warn(_("%s: can't change process priority: %m"),
+-				options.tty);
+-	}
+-	if (options.osrelease)
+-		free(options.osrelease);
++	if (options.chroot && chroot(options.chroot) < 0)
++		log_err(_("%s: can't change root directory %s: %m"),
++			options.tty, options.chroot);
++	if (options.chdir && chdir(options.chdir) < 0)
++		log_err(_("%s: can't change working directory %s: %m"),
++			options.tty, options.chdir);
++	if (options.nice && nice(options.nice) < 0)
++		log_warn(_("%s: can't change process priority: %m"),
++			 options.tty);
++
++	free(options.osrelease);
+ #ifdef DEBUGGING
+-	fprintf(dbf, "read %c\n", ch);
+ 	if (close_stream(dbf) != 0)
+ 		log_err("write failed: %s", DEBUG_OUTPUT);
+ #endif
+@@ -477,7 +566,7 @@ static char *replace_u(char *str, char *username)
+ 			log_err(_("failed to allocate memory: %m"));
+ 
+ 		if (p != str) {
+-			/* copy chars befor \u */
++			/* copy chars before \u */
+ 			memcpy(tp, str, p - str);
+ 			tp += p - str;
+ 		}
+@@ -527,6 +616,55 @@ static void login_options_to_argv(char *argv[], int *argc,
+ 	*argc = i;
+ }
+ 
++static void output_version(void)
++{
++	static const char *features[] = {
++#ifdef DEBUGGING
++		"debug",
++#endif
++#ifdef CRTSCTS
++		"flow control",
++#endif
++#ifdef KDGKBLED
++		"hints",
++#endif
++#ifdef ISSUE_SUPPORT
++		"issue",
++#endif
++#ifdef ISSUEDIR_SUPPORT
++		"issue.d",
++#endif
++#ifdef KDGKBMODE
++		"keyboard mode",
++#endif
++#ifdef USE_PLYMOUTH_SUPPORT
++		"plymouth",
++#endif
++#ifdef AGETTY_RELOAD
++		"reload",
++#endif
++#ifdef USE_SYSLOG
++		"syslog",
++#endif
++#ifdef HAVE_WIDECHAR
++		"widechar",
++#endif
++		NULL
++	};
++	unsigned int i;
++
++	printf( _("%s from %s"), program_invocation_short_name, PACKAGE_STRING);
++	fputs(" (", stdout);
++	for (i = 0; features[i]; i++) {
++		if (0 < i)
++			fputs(", ", stdout);
++		printf("%s", features[i]);
++	}
++	fputs(")\n", stdout);
++}
++
++#define is_speed(str) (strlen((str)) == strspn((str), "0123456789,"))
++
+ /* Parse command-line arguments. */
+ static void parse_args(int argc, char **argv, struct options *op)
+ {
+@@ -540,46 +678,50 @@ static void parse_args(int argc, char **argv, struct options *op)
+ 		HELP_OPTION,
+ 		ERASE_CHARS_OPTION,
+ 		KILL_CHARS_OPTION,
++		RELOAD_OPTION,
++		LIST_SPEEDS_OPTION,
+ 	};
+ 	const struct option longopts[] = {
+-		{  "8bits",	     no_argument,	 0,  '8'  },
+-		{  "autologin",	     required_argument,	 0,  'a'  },
+-		{  "noreset",	     no_argument,	 0,  'c'  },
+-		{  "chdir",	     required_argument,	 0,  'C'  },
+-		{  "delay",	     required_argument,	 0,  'd'  },
+-		{  "remote",         no_argument,        0,  'E'  },
+-		{  "issue-file",     required_argument,  0,  'f'  },
+-		{  "flow-control",   no_argument,	 0,  'h'  },
+-		{  "host",	     required_argument,  0,  'H'  },
+-		{  "noissue",	     no_argument,	 0,  'i'  },
+-		{  "init-string",    required_argument,  0,  'I'  },
+-		{  "noclear",	     no_argument,	 0,  'J'  },
+-		{  "login-program",  required_argument,  0,  'l'  },
+-		{  "local-line",     optional_argument,	 0,  'L'  },
+-		{  "extract-baud",   no_argument,	 0,  'm'  },
+-		{  "skip-login",     no_argument,	 0,  'n'  },
+-		{  "nonewline",	     no_argument,	 0,  'N'  },
+-		{  "login-options",  required_argument,  0,  'o'  },
+-		{  "login-pause",    no_argument,        0,  'p'  },
+-		{  "nice",	     required_argument,  0,  'P'  },
+-		{  "chroot",	     required_argument,	 0,  'r'  },
+-		{  "hangup",	     no_argument,	 0,  'R'  },
+-		{  "keep-baud",      no_argument,	 0,  's'  },
+-		{  "timeout",	     required_argument,  0,  't'  },
+-		{  "detect-case",    no_argument,	 0,  'U'  },
+-		{  "wait-cr",	     no_argument,	 0,  'w'  },
+-		{  "nohints",        no_argument,        0,  NOHINTS_OPTION },
+-		{  "nohostname",     no_argument,	 0,  NOHOSTNAME_OPTION },
+-		{  "long-hostname",  no_argument,	 0,  LONGHOSTNAME_OPTION },
+-		{  "version",	     no_argument,	 0,  VERSION_OPTION  },
+-		{  "help",	     no_argument,	 0,  HELP_OPTION     },
+-		{  "erase-chars",    required_argument,  0,  ERASE_CHARS_OPTION },
+-		{  "kill-chars",     required_argument,  0,  KILL_CHARS_OPTION },
+-		{ NULL, 0, 0, 0 }
++		{  "8bits",	     no_argument,	 NULL,  '8'  },
++		{  "autologin",	     required_argument,	 NULL,  'a'  },
++		{  "noreset",	     no_argument,	 NULL,  'c'  },
++		{  "chdir",	     required_argument,	 NULL,  'C'  },
++		{  "delay",	     required_argument,	 NULL,  'd'  },
++		{  "remote",         no_argument,        NULL,  'E'  },
++		{  "issue-file",     required_argument,  NULL,  'f'  },
++		{  "flow-control",   no_argument,	 NULL,  'h'  },
++		{  "host",	     required_argument,  NULL,  'H'  },
++		{  "noissue",	     no_argument,	 NULL,  'i'  },
++		{  "init-string",    required_argument,  NULL,  'I'  },
++		{  "noclear",	     no_argument,	 NULL,  'J'  },
++		{  "login-program",  required_argument,  NULL,  'l'  },
++		{  "local-line",     optional_argument,	 NULL,  'L'  },
++		{  "extract-baud",   no_argument,	 NULL,  'm'  },
++		{  "list-speeds",    no_argument,	 NULL,	LIST_SPEEDS_OPTION },
++		{  "skip-login",     no_argument,	 NULL,  'n'  },
++		{  "nonewline",	     no_argument,	 NULL,  'N'  },
++		{  "login-options",  required_argument,  NULL,  'o'  },
++		{  "login-pause",    no_argument,        NULL,  'p'  },
++		{  "nice",	     required_argument,  NULL,  'P'  },
++		{  "chroot",	     required_argument,	 NULL,  'r'  },
++		{  "hangup",	     no_argument,	 NULL,  'R'  },
++		{  "keep-baud",      no_argument,	 NULL,  's'  },
++		{  "timeout",	     required_argument,  NULL,  't'  },
++		{  "detect-case",    no_argument,	 NULL,  'U'  },
++		{  "wait-cr",	     no_argument,	 NULL,  'w'  },
++		{  "nohints",        no_argument,        NULL,  NOHINTS_OPTION },
++		{  "nohostname",     no_argument,	 NULL,  NOHOSTNAME_OPTION },
++		{  "long-hostname",  no_argument,	 NULL,  LONGHOSTNAME_OPTION },
++		{  "reload",         no_argument,        NULL,  RELOAD_OPTION },
++		{  "version",	     no_argument,	 NULL,  VERSION_OPTION  },
++		{  "help",	     no_argument,	 NULL,  HELP_OPTION     },
++		{  "erase-chars",    required_argument,  NULL,  ERASE_CHARS_OPTION },
++		{  "kill-chars",     required_argument,  NULL,  KILL_CHARS_OPTION },
++		{ NULL, 0, NULL, 0 }
+ 	};
+ 
+ 	while ((c = getopt_long(argc, argv,
+-			   "8a:cC:d:Ef:hH:iI:Jl:LmnNo:pP:r:Rst:Uw", longopts,
++			   "8a:cC:d:Ef:hH:iI:Jl:L::mnNo:pP:r:Rst:Uw", longopts,
+ 			    NULL)) != -1) {
+ 		switch (c) {
+ 		case '8':
+@@ -595,13 +737,12 @@ static void parse_args(int argc, char **argv, struct options *op)
+ 			op->chdir = optarg;
+ 			break;
+ 		case 'd':
+-			op->delay = atoi(optarg);
++			op->delay = strtou32_or_err(optarg,  _("invalid delay argument"));
+ 			break;
+ 		case 'E':
+ 			op->flags |= F_REMOTE;
+ 			break;
+ 		case 'f':
+-			op->flags |= F_CUSTISSUE;
+ 			op->issue = optarg;
+ 			break;
+ 		case 'h':
+@@ -634,7 +775,7 @@ static void parse_args(int argc, char **argv, struct options *op)
+ 				else if (strcmp(optarg, "=auto") == 0)
+ 					op->clocal = CLOCAL_MODE_AUTO;
+ 				else
+-					log_err(_("unssuported --local-line mode argument"));
++					log_err(_("invalid argument of --local-line"));
+ 			}
+ 			break;
+ 		case 'm':
+@@ -643,6 +784,9 @@ static void parse_args(int argc, char **argv, struct options *op)
+ 		case 'n':
+ 			op->flags |= F_NOPROMPT;
+ 			break;
++		case 'N':
++			op->flags |= F_NONL;
++			break;
+ 		case 'o':
+ 			op->logopt = optarg;
+ 			break;
+@@ -650,7 +794,7 @@ static void parse_args(int argc, char **argv, struct options *op)
+ 			op->flags |= F_LOGINPAUSE;
+ 			break;
+ 		case 'P':
+-			op->nice = atoi(optarg);
++			op->nice = strtos32_or_err(optarg,  _("invalid nice argument"));
+ 			break;
+ 		case 'r':
+ 			op->chroot = optarg;
+@@ -662,8 +806,7 @@ static void parse_args(int argc, char **argv, struct options *op)
+ 			op->flags |= F_KEEPSPEED;
+ 			break;
+ 		case 't':
+-			if ((op->timeout = atoi(optarg)) <= 0)
+-				log_err(_("bad timeout value: %s"), optarg);
++			op->timeout = strtou32_or_err(optarg,  _("invalid timeout argument"));
+ 			break;
+ 		case 'U':
+ 			op->flags |= F_LCUC;
+@@ -686,14 +829,19 @@ static void parse_args(int argc, char **argv, struct options *op)
+ 		case KILL_CHARS_OPTION:
+ 			op->killchars = optarg;
+ 			break;
++		case RELOAD_OPTION:
++			reload_agettys();
++			exit(EXIT_SUCCESS);
++		case LIST_SPEEDS_OPTION:
++			list_speeds();
++			exit(EXIT_SUCCESS);
+ 		case VERSION_OPTION:
+-			printf(_("%s from %s\n"), program_invocation_short_name,
+-			       PACKAGE_STRING);
++			output_version();
+ 			exit(EXIT_SUCCESS);
+ 		case HELP_OPTION:
+-			usage(stdout);
++			usage();
+ 		default:
+-			usage(stderr);
++			errtryhelp(EXIT_FAILURE);
+ 		}
+ 	}
+ 
+@@ -701,26 +849,26 @@ static void parse_args(int argc, char **argv, struct options *op)
+ 
+ 	if (argc < optind + 1) {
+ 		log_warn(_("not enough arguments"));
+-		usage(stderr);
++		errx(EXIT_FAILURE, _("not enough arguments"));
+ 	}
+ 
+ 	/* Accept "tty", "baudrate tty", and "tty baudrate". */
+-	if ('0' <= argv[optind][0] && argv[optind][0] <= '9') {
++	if (is_speed(argv[optind])) {
+ 		/* Assume BSD style speed. */
+ 		parse_speeds(op, argv[optind++]);
+ 		if (argc < optind + 1) {
+-			warn(_("not enough arguments"));
+-			usage(stderr);
++			log_warn(_("not enough arguments"));
++			errx(EXIT_FAILURE, _("not enough arguments"));
+ 		}
+ 		op->tty = argv[optind++];
+ 	} else {
+ 		op->tty = argv[optind++];
+ 		if (argc > optind) {
+-			char *v = argv[optind++];
+-			if ('0' <= *v && *v <= '9')
++			char *v = argv[optind];
++			if (is_speed(v)) {
+ 				parse_speeds(op, v);
+-			else
+-				op->speeds[op->numspeed++] = bcode("9600");
++				optind++;
++			}
+ 		}
+ 	}
+ 
+@@ -732,45 +880,6 @@ static void parse_args(int argc, char **argv, struct options *op)
+ 	if (argc > optind && argv[optind])
+ 		op->term = argv[optind];
+ 
+-#ifdef DO_DEVFS_FIDDLING
+-	/*
+-	 * Some devfs junk, following Goswin Brederlow:
+-	 *   turn ttyS<n> into tts/<n>
+-	 *   turn tty<n> into vc/<n>
+-	 * http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=72241
+-	 */
+-	if (op->tty && strlen(op->tty) < 90) {
+-		char dev_name[100];
+-		struct stat st;
+-
+-		if (strncmp(op->tty, "ttyS", 4) == 0) {
+-			strcpy(dev_name, "/dev/");
+-			strcat(dev_name, op->tty);
+-			if (stat(dev_name, &st) < 0) {
+-				strcpy(dev_name, "/dev/tts/");
+-				strcat(dev_name, op->tty + 4);
+-				if (stat(dev_name, &st) == 0) {
+-					op->tty = strdup(dev_name + 5);
+-					if (!op->tty)
+-						log_err(_("failed to allocate memory: %m"));
+-				}
+-			}
+-		} else if (strncmp(op->tty, "tty", 3) == 0) {
+-			strcpy(dev_name, "/dev/");
+-			strncat(dev_name, op->tty, 90);
+-			if (stat(dev_name, &st) < 0) {
+-				strcpy(dev_name, "/dev/vc/");
+-				strcat(dev_name, op->tty + 3);
+-				if (stat(dev_name, &st) == 0) {
+-					op->tty = strdup(dev_name + 5);
+-					if (!op->tty)
+-						log_err(_("failed to allocate memory: %m"));
+-				}
+-			}
+-		}
+-	}
+-#endif				/* DO_DEVFS_FIDDLING */
+-
+ 	debug("exiting parseargs\n");
+ }
+ 
+@@ -778,15 +887,20 @@ static void parse_args(int argc, char **argv, struct options *op)
+ static void parse_speeds(struct options *op, char *arg)
+ {
+ 	char *cp;
++	char *str = strdup(arg);
++
++	if (!str)
++		log_err(_("failed to allocate memory: %m"));
+ 
+-	debug("entered parse_speeds\n");
+-	for (cp = strtok(arg, ","); cp != NULL; cp = strtok((char *)0, ",")) {
++	debug("entered parse_speeds:\n");
++	for (cp = strtok(str, ","); cp != NULL; cp = strtok((char *)0, ",")) {
+ 		if ((op->speeds[op->numspeed++] = bcode(cp)) <= 0)
+ 			log_err(_("bad speed: %s"), cp);
+ 		if (op->numspeed >= MAX_SPEED)
+ 			log_err(_("too many alternate speeds"));
+ 	}
+ 	debug("exiting parsespeeds\n");
++	free(str);
+ }
+ 
+ #ifdef	SYSV_STYLE
+@@ -794,13 +908,13 @@ static void parse_speeds(struct options *op, char *arg)
+ /* Update our utmp entry. */
+ static void update_utmp(struct options *op)
+ {
+-	struct utmp ut;
++	struct utmpx ut;
+ 	time_t t;
+ 	pid_t pid = getpid();
+ 	pid_t sid = getsid(0);
+ 	char *vcline = op->vcline;
+ 	char *line   = op->tty;
+-	struct utmp *utp;
++	struct utmpx *utp;
+ 
+ 	/*
+ 	 * The utmp file holds miscellaneous information about things started by
+@@ -810,8 +924,8 @@ static void update_utmp(struct options *op)
+ 	 * utmp file can be opened for update, and if we are able to find our
+ 	 * entry in the utmp file.
+ 	 */
+-	utmpname(_PATH_UTMP);
+-	setutent();
++	utmpxname(_PATH_UTMP);
++	setutxent();
+ 
+ 	/*
+ 	 * Find my pid in utmp.
+@@ -822,7 +936,7 @@ static void update_utmp(struct options *op)
+ 	 * FIXME: The present code is taken from login.c, so if this is changed,
+ 	 * maybe login has to be changed as well (is this true?).
+ 	 */
+-	while ((utp = getutent()))
++	while ((utp = getutxent()))
+ 		if (utp->ut_pid == pid
+ 				&& utp->ut_type >= INIT_PROCESS
+ 				&& utp->ut_type <= DEAD_PROCESS)
+@@ -852,33 +966,15 @@ static void update_utmp(struct options *op)
+ 	if (fakehost)
+ 		strncpy(ut.ut_host, fakehost, sizeof(ut.ut_host));
+ 	time(&t);
+-	ut.ut_time = t;
++	ut.ut_tv.tv_sec = t;
+ 	ut.ut_type = LOGIN_PROCESS;
+ 	ut.ut_pid = pid;
+ 	ut.ut_session = sid;
+ 
+-	pututline(&ut);
+-	endutent();
++	pututxline(&ut);
++	endutxent();
+ 
+-	{
+-#ifdef HAVE_UPDWTMP
+-		updwtmp(_PATH_WTMP, &ut);
+-#else
+-		int ut_fd;
+-		int lf;
+-
+-		if ((lf = open(_PATH_WTMPLOCK, O_CREAT | O_WRONLY, 0660)) >= 0) {
+-			flock(lf, LOCK_EX);
+-			if ((ut_fd =
+-			     open(_PATH_WTMP, O_APPEND | O_WRONLY)) >= 0) {
+-				write_all(ut_fd, &ut, sizeof(ut));
+-				close(ut_fd);
+-			}
+-			flock(lf, LOCK_UN);
+-			close(lf);
+-		}
+-#endif				/* HAVE_UPDWTMP */
+-	}
++	updwtmpx(_PATH_WTMP, &ut);
+ }
+ 
+ #endif				/* SYSV_STYLE */
+@@ -888,6 +984,9 @@ static void open_tty(char *tty, struct termios *tp, struct options *op)
+ {
+ 	const pid_t pid = getpid();
+ 	int closed = 0;
++#ifndef KDGKBMODE
++	int serial;
++#endif
+ 
+ 	/* Set up new standard input, unless we are given an already opened port. */
+ 
+@@ -903,8 +1002,12 @@ static void open_tty(char *tty, struct termios *tp, struct options *op)
+ 		if ((gr = getgrnam("tty")))
+ 			gid = gr->gr_gid;
+ 
+-		if (((len = snprintf(buf, sizeof(buf), "/dev/%s", tty)) >=
+-		     (int)sizeof(buf)) || (len < 0))
++		len = snprintf(buf, sizeof(buf), "/dev/%s", tty);
++		if (len < 0 || (size_t)len >= sizeof(buf))
++			log_err(_("/dev/%s: cannot open as standard input: %m"), tty);
++
++		/* Open the tty as standard input. */
++		if ((fd = open(buf, O_RDWR|O_NOCTTY|O_NONBLOCK, 0)) < 0)
+ 			log_err(_("/dev/%s: cannot open as standard input: %m"), tty);
+ 
+ 		/*
+@@ -913,24 +1016,20 @@ static void open_tty(char *tty, struct termios *tp, struct options *op)
+ 		 * Linux login(1) will change tty permissions. Use root owner and group
+ 		 * with permission -rw------- for the period between getty and login.
+ 		 */
+-		if (chown(buf, 0, gid) || chmod(buf, (gid ? 0620 : 0600))) {
++		if (fchown(fd, 0, gid) || fchmod(fd, (gid ? 0620 : 0600))) {
+ 			if (errno == EROFS)
+ 				log_warn("%s: %m", buf);
+ 			else
+ 				log_err("%s: %m", buf);
+ 		}
+ 
+-		/* Open the tty as standard input. */
+-		if ((fd = open(buf, O_RDWR|O_NOCTTY|O_NONBLOCK, 0)) < 0)
+-			log_err(_("/dev/%s: cannot open as standard input: %m"), tty);
+-
+ 		/* Sanity checks... */
+-		if (!isatty(fd))
+-			log_err(_("/dev/%s: not a character device"), tty);
+ 		if (fstat(fd, &st) < 0)
+ 			log_err("%s: %m", buf);
+ 		if ((st.st_mode & S_IFMT) != S_IFCHR)
+ 			log_err(_("/dev/%s: not a character device"), tty);
++		if (!isatty(fd))
++			log_err(_("/dev/%s: not a tty"), tty);
+ 
+ 		if (((tid = tcgetsid(fd)) < 0) || (pid != tid)) {
+ 			if (ioctl(fd, TIOCSCTTY, 1) == -1)
+@@ -946,7 +1045,7 @@ static void open_tty(char *tty, struct termios *tp, struct options *op)
+ 				debug("TIOCNOTTY ioctl failed\n");
+ 
+ 			/*
+-			 * Let's close all file decriptors before vhangup
++			 * Let's close all file descriptors before vhangup
+ 			 * https://lkml.org/lkml/2012/6/5/145
+ 			 */
+ 			close(fd);
+@@ -1015,22 +1114,66 @@ static void open_tty(char *tty, struct termios *tp, struct options *op)
+ 	if (tcgetattr(STDIN_FILENO, tp) < 0)
+ 		log_err(_("%s: failed to get terminal attributes: %m"), tty);
+ 
++#if defined (__s390__) || defined (__s390x__)
++	if (!op->term) {
++	        /*
++		 * Special terminal on first serial line on a S/390(x) which
++		 * is due legacy reasons a block terminal of type 3270 or
++		 * higher.  Whereas the second serial line on a S/390(x) is
++		 * a real character terminal which is compatible with VT220.
++		 */
++		if (strcmp(op->tty, "ttyS0") == 0)		/* linux/drivers/s390/char/con3215.c */
++			op->term = DEFAULT_TTYS0;
++		else if (strncmp(op->tty, "3270/tty", 8) == 0)	/* linux/drivers/s390/char/con3270.c */
++			op->term = DEFAULT_TTY32;
++		else if (strcmp(op->tty, "ttyS1") == 0)		/* linux/drivers/s390/char/sclp_vt220.c */
++			op->term = DEFAULT_TTYS1;
++	}
++#endif
++
++#if defined(__FreeBSD_kernel__)
++	login_tty (0);
++#endif
++
+ 	/*
+ 	 * Detect if this is a virtual console or serial/modem line.
+ 	 * In case of a virtual console the ioctl KDGKBMODE succeeds
+ 	 * whereas on other lines it will fails.
+ 	 */
+-	if (ioctl(STDIN_FILENO, KDGKBMODE, &op->kbmode) == 0) {
++#ifdef KDGKBMODE
++	if (ioctl(STDIN_FILENO, KDGKBMODE, &op->kbmode) == 0)
++#else
++	if (ioctl(STDIN_FILENO, TIOCMGET, &serial) < 0 && (errno == EINVAL))
++#endif
++	{
+ 		op->flags |= F_VCONSOLE;
+ 		if (!op->term)
+ 			op->term = DEFAULT_VCTERM;
+ 	} else {
++#ifdef K_RAW
+ 		op->kbmode = K_RAW;
++#endif
+ 		if (!op->term)
+ 			op->term = DEFAULT_STERM;
+ 	}
+ 
+-	setenv("TERM", op->term, 1);
++	if (setenv("TERM", op->term, 1) != 0)
++		log_err(_("failed to set the %s environment variable"), "TERM");
++}
++
++/* Initialize termios settings. */
++static void termio_clear(int fd)
++{
++	/*
++	 * Do not write a full reset (ESC c) because this destroys
++	 * the unicode mode again if the terminal was in unicode
++	 * mode.  Also it clears the CONSOLE_MAGIC features which
++	 * are required for some languages/console-fonts.
++	 * Just put the cursor to the home position (ESC [ H),
++	 * erase everything below the cursor (ESC [ J), and set the
++	 * scrolling region to the full window (ESC [ r)
++	 */
++	write_all(fd, "\033[r\033[H\033[J", 9);
+ }
+ 
+ /* Initialize termios settings. */
+@@ -1038,6 +1181,28 @@ static void termio_init(struct options *op, struct termios *tp)
+ {
+ 	speed_t ispeed, ospeed;
+ 	struct winsize ws;
++#ifdef USE_PLYMOUTH_SUPPORT
++	struct termios lock;
++	int i =  (plymouth_command(MAGIC_PING) == 0) ? PLYMOUTH_TERMIOS_FLAGS_DELAY : 0;
++	if (i)
++		plymouth_command(MAGIC_QUIT);
++	while (i-- > 0) {
++		/*
++		 * Even with TTYReset=no it seems with systemd or plymouth
++		 * the termios flags become changed from under the first
++		 * agetty on a serial system console as the flags are locked.
++		 */
++		memset(&lock, 0, sizeof(struct termios));
++		if (ioctl(STDIN_FILENO, TIOCGLCKTRMIOS, &lock) < 0)
++			break;
++		if (!lock.c_iflag && !lock.c_oflag && !lock.c_cflag && !lock.c_lflag)
++			break;
++		debug("termios locked\n");
++		sleep(1);
++	}
++	memset(&lock, 0, sizeof(struct termios));
++	ioctl(STDIN_FILENO, TIOCSLCKTRMIOS, &lock);
++#endif
+ 
+ 	if (op->flags & F_VCONSOLE) {
+ #if defined(IUTF8) && defined(KDGKBMODE)
+@@ -1063,22 +1228,16 @@ static void termio_init(struct options *op, struct termios *tp)
+ 		if ((tp->c_cflag & (CS8|PARODD|PARENB)) == CS8)
+ 			op->flags |= F_EIGHTBITS;
+ 
+-		if ((op->flags & F_NOCLEAR) == 0) {
+-			/*
+-			 * Do not write a full reset (ESC c) because this destroys
+-			 * the unicode mode again if the terminal was in unicode
+-			 * mode.  Also it clears the CONSOLE_MAGIC features which
+-			 * are required for some languages/console-fonts.
+-			 * Just put the cursor to the home position (ESC [ H),
+-			 * erase everything below the cursor (ESC [ J), and set the
+-			 * scrolling region to the full window (ESC [ r)
+-			 */
+-			write_all(STDOUT_FILENO, "\033[r\033[H\033[J", 9);
+-		}
++		if ((op->flags & F_NOCLEAR) == 0)
++			termio_clear(STDOUT_FILENO);
+ 		return;
+ 	}
+ 
+-	if (op->flags & F_KEEPSPEED) {
++	/*
++	 * Serial line
++	 */
++
++	if (op->flags & F_KEEPSPEED || !op->numspeed) {
+ 		/* Save the original setting. */
+ 		ispeed = cfgetispeed(tp);
+ 		ospeed = cfgetospeed(tp);
+@@ -1097,9 +1256,6 @@ static void termio_init(struct options *op, struct termios *tp)
+ 	 * later on.
+ 	 */
+ 
+-	 /* Flush input and output queues, important for modems! */
+-	tcflush(STDIN_FILENO, TCIOFLUSH);
+-
+ 	/* The defaul is set c_iflag in termio_final() according to chardata.
+ 	 * Unfortunately, the chardata are not set according to the serial line
+ 	 * if --autolog is enabled. In this case we do not read from the line
+@@ -1124,7 +1280,7 @@ static void termio_init(struct options *op, struct termios *tp)
+ 
+ 	/*
+ 	 * Note that the speed is stored in the c_cflag termios field, so we have
+-	 * set the speed always when the cflag se reseted.
++	 * set the speed always when the cflag is reset.
+ 	 */
+ 	cfsetispeed(tp, ispeed);
+ 	cfsetospeed(tp, ospeed);
+@@ -1150,15 +1306,10 @@ static void termio_init(struct options *op, struct termios *tp)
+ 
+ 	/* Check for terminal size and if not found set default */
+ 	if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) == 0) {
+-		int set = 0;
+-		if (ws.ws_row == 0) {
++		if (ws.ws_row == 0)
+ 			ws.ws_row = 24;
+-			set++;
+-		}
+-		if (ws.ws_col == 0) {
++		if (ws.ws_col == 0)
+ 			ws.ws_col = 80;
+-			set++;
+-		}
+ 		if (ioctl(STDIN_FILENO, TIOCSWINSZ, &ws))
+ 			debug("TIOCSWINSZ ioctl failed\n");
+ 	}
+@@ -1168,8 +1319,11 @@ static void termio_init(struct options *op, struct termios *tp)
+ 	if (op->flags & F_RTSCTS)
+ 		tp->c_cflag |= CRTSCTS;
+ #endif
++	 /* Flush input and output queues, important for modems! */
++	tcflush(STDIN_FILENO, TCIOFLUSH);
+ 
+-	tcsetattr(STDIN_FILENO, TCSANOW, tp);
++	if (tcsetattr(STDIN_FILENO, TCSANOW, tp))
++		log_warn(_("setting terminal attributes failed: %m"));
+ 
+ 	/* Go to blocking input even in local mode. */
+ 	fcntl(STDIN_FILENO, F_SETFL,
+@@ -1190,6 +1344,10 @@ static void reset_vc(const struct options *op, struct termios *tp)
+ 
+ 	if (tcsetattr(STDIN_FILENO, TCSADRAIN, tp))
+ 		log_warn(_("setting terminal attributes failed: %m"));
++
++	/* Go to blocking input even in local mode. */
++	fcntl(STDIN_FILENO, F_SETFL,
++	      fcntl(STDIN_FILENO, F_GETFL, 0) & ~O_NONBLOCK);
+ }
+ 
+ /* Extract baud rate from modem status message. */
+@@ -1273,7 +1431,7 @@ static char *xgetdomainname(void)
+ {
+ #ifdef HAVE_GETDOMAINNAME
+ 	char *name;
+-	size_t sz = get_hostname_max() + 1;
++	const size_t sz = get_hostname_max() + 1;
+ 
+ 	name = malloc(sizeof(char) * sz);
+ 	if (!name)
+@@ -1285,8 +1443,9 @@ static char *xgetdomainname(void)
+ 	}
+ 	name[sz - 1] = '\0';
+ 	return name;
+-#endif
++#else
+ 	return NULL;
++#endif
+ }
+ 
+ 
+@@ -1299,10 +1458,13 @@ static char *read_os_release(struct options *op, const char *varname)
+ 
+ 	/* read the file only once */
+ 	if (!op->osrelease) {
+-		fd = open(_PATH_OS_RELEASE, O_RDONLY);
++		fd = open(_PATH_OS_RELEASE_ETC, O_RDONLY);
+ 		if (fd == -1) {
+-			log_warn(_("cannot open: %s: %m"), _PATH_OS_RELEASE);
+-			return NULL;
++			fd = open(_PATH_OS_RELEASE_USR, O_RDONLY);
++			if (fd == -1) {
++				log_warn(_("cannot open os-release file"));
++				return NULL;
++			}
+ 		}
+ 
+ 		if (fstat(fd, &st) < 0 || st.st_size > 4 * 1024 * 1024)
+@@ -1359,8 +1521,7 @@ static char *read_os_release(struct options *op, const char *varname)
+ 			}
+ 			break;
+ 		}
+-		if (ret)
+-			free(ret);
++		free(ret);
+ 		ret = strdup(p);
+ 		if (!ret)
+ 			log_err(_("failed to allocate memory: %m"));
+@@ -1373,20 +1534,251 @@ done:
+ 	return ret;
+ }
+ 
+-/* Show login prompt, optionally preceded by /etc/issue contents. */
+-static void do_prompt(struct options *op, struct termios *tp)
++#ifdef AGETTY_RELOAD
++static void open_netlink(void)
+ {
+-#ifdef	ISSUE
+-	FILE *fd;
+-#endif				/* ISSUE */
++	struct sockaddr_nl addr = { 0, };
++	int sock;
+ 
++	if (netlink_fd != AGETTY_RELOAD_FDNONE)
++		return;
++
++	sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
++	if (sock >= 0) {
++		addr.nl_family = AF_NETLINK;
++		addr.nl_pid = getpid();
++		addr.nl_groups = RTMGRP_IPV4_IFADDR | RTMGRP_IPV6_IFADDR;
++		if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0)
++			close(sock);
++		else
++			netlink_fd = sock;
++	}
++}
++
++static int process_netlink_msg(int *changed)
++{
++	char buf[4096];
++	struct sockaddr_nl snl;
++	struct nlmsghdr *h;
++	int rc;
++
++	struct iovec iov = {
++		.iov_base = buf,
++		.iov_len = sizeof(buf)
++	};
++	struct msghdr msg = {
++		.msg_name = &snl,
++		.msg_namelen = sizeof(snl),
++		.msg_iov = &iov,
++		.msg_iovlen = 1,
++		.msg_control = NULL,
++		.msg_controllen = 0,
++		.msg_flags = 0
++	};
++
++	rc = recvmsg(netlink_fd, &msg, MSG_DONTWAIT);
++	if (rc < 0) {
++		if (errno == EWOULDBLOCK || errno == EAGAIN)
++			return 0;
++
++		/* Failure, just stop listening for changes */
++		close(netlink_fd);
++		netlink_fd = AGETTY_RELOAD_FDNONE;
++		return 0;
++	}
++
++	for (h = (struct nlmsghdr *)buf; NLMSG_OK(h, (unsigned int)rc); h = NLMSG_NEXT(h, rc)) {
++		if (h->nlmsg_type == NLMSG_DONE ||
++		    h->nlmsg_type == NLMSG_ERROR) {
++			close(netlink_fd);
++			netlink_fd = AGETTY_RELOAD_FDNONE;
++			return 0;
++		}
++
++		*changed = 1;
++		break;
++	}
++
++	return 1;
++}
++
++static int process_netlink(void)
++{
++	int changed = 0;
++	while (process_netlink_msg(&changed));
++	return changed;
++}
++
++static int wait_for_term_input(int fd)
++{
++	char buffer[sizeof(struct inotify_event) + NAME_MAX + 1];
++	fd_set rfds;
++
++	if (inotify_fd == AGETTY_RELOAD_FDNONE) {
++		/* make sure the reload trigger file exists */
++		int reload_fd = open(AGETTY_RELOAD_FILENAME,
++					O_CREAT|O_CLOEXEC|O_RDONLY,
++					S_IRUSR|S_IWUSR);
++
++		/* initialize reload trigger inotify stuff */
++		if (reload_fd >= 0) {
++			inotify_fd = inotify_init1(IN_NONBLOCK | IN_CLOEXEC);
++			if (inotify_fd > 0)
++				inotify_add_watch(inotify_fd, AGETTY_RELOAD_FILENAME,
++					  IN_ATTRIB | IN_MODIFY);
++
++			close(reload_fd);
++		} else
++			log_warn(_("failed to create reload file: %s: %m"),
++					AGETTY_RELOAD_FILENAME);
++	}
++
++	while (1) {
++		int nfds = fd;
++
++		FD_ZERO(&rfds);
++		FD_SET(fd, &rfds);
++
++		if (inotify_fd >= 0) {
++			FD_SET(inotify_fd, &rfds);
++			nfds = max(nfds, inotify_fd);
++		}
++		if (netlink_fd >= 0) {
++			FD_SET(netlink_fd, &rfds);
++			nfds = max(nfds, netlink_fd);
++		}
++
++		/* If waiting fails, just fall through, presumably reading input will fail */
++		if (select(nfds + 1, &rfds, NULL, NULL, NULL) < 0)
++			return 1;
++
++		if (FD_ISSET(fd, &rfds)) {
++			return 1;
++
++		} else if (netlink_fd >= 0 && FD_ISSET(netlink_fd, &rfds)) {
++			if (!process_netlink())
++				continue;
++
++		/* Just drain the inotify buffer */
++		} else if (inotify_fd >= 0 && FD_ISSET(inotify_fd, &rfds)) {
++			while (read(inotify_fd, buffer, sizeof (buffer)) > 0);
++		}
++
++		return 0;
++	}
++}
++#endif  /* AGETTY_RELOAD */
++
++#ifdef ISSUEDIR_SUPPORT
++static int issuedir_filter(const struct dirent *d)
++{
++	size_t namesz;
++
++#ifdef _DIRENT_HAVE_D_TYPE
++	if (d->d_type != DT_UNKNOWN && d->d_type != DT_REG &&
++	    d->d_type != DT_LNK)
++		return 0;
++#endif
++	if (*d->d_name == '.')
++		return 0;
++
++	namesz = strlen(d->d_name);
++	if (!namesz || namesz < ISSUEDIR_EXTSIZ + 1 ||
++	    strcmp(d->d_name + (namesz - ISSUEDIR_EXTSIZ), ISSUEDIR_EXT))
++		return 0;
++
++	/* Accept this */
++	return 1;
++}
++
++static FILE *issuedir_next_file(int dd, struct dirent **namelist, int nfiles, int *n)
++{
++	while (*n < nfiles) {
++		struct dirent *d = namelist[*n];
++		struct stat st;
++		FILE *f;
++
++		(*n)++;
++
++		if (fstatat(dd, d->d_name, &st, 0) ||
++		    !S_ISREG(st.st_mode))
++			continue;
++
++		f = fopen_at(dd, d->d_name, O_RDONLY|O_CLOEXEC, "r" UL_CLOEXECSTR);
++		if (f)
++			return f;
++	}
++	return NULL;
++}
++
++#endif /* ISSUEDIR_SUPPORT */
++
++#ifndef ISSUE_SUPPORT
++static void print_issue_file(struct options *op, struct termios *tp __attribute__((__unused__)))
++{
++	if ((op->flags & F_NONL) == 0) {
++		/* Issue not in use, start with a new line. */
++		write_all(STDOUT_FILENO, "\r\n", 2);
++	}
++}
++#else /* ISSUE_SUPPORT */
++
++static void print_issue_file(struct options *op, struct termios *tp)
++{
++	const char *filename, *dirname = NULL;
++	FILE *f = NULL;
++#ifdef ISSUEDIR_SUPPORT
++	int dd = -1, nfiles = 0, i;
++	struct dirent **namelist = NULL;
++#endif
+ 	if ((op->flags & F_NONL) == 0) {
+ 		/* Issue not in use, start with a new line. */
+ 		write_all(STDOUT_FILENO, "\r\n", 2);
+ 	}
+ 
+-#ifdef	ISSUE
+-	if ((op->flags & F_ISSUE) && (fd = fopen(op->issue, "r"))) {
++	if (!(op->flags & F_ISSUE))
++		return;
++
++	/*
++	 * The custom issue file or directory specified by: agetty -f <path>.
++	 * Note that nothing is printed if the file/dir does not exist.
++	 */
++	filename = op->issue;
++	if (filename) {
++		struct stat st;
++
++		if (stat(filename, &st) < 0)
++			return;
++		if (S_ISDIR(st.st_mode)) {
++			dirname = filename;
++			filename = NULL;
++		}
++	} else {
++		/* The default /etc/issue and optional /etc/issue.d directory
++		 * as extension to the file. The /etc/issue.d directory is
++		 * ignored if there is no /etc/issue file. The file may be
++		 * empty or symlink.
++		 */
++		if (access(_PATH_ISSUE, F_OK|R_OK) != 0)
++			return;
++		filename  = _PATH_ISSUE;
++		dirname = _PATH_ISSUEDIR;
++	}
++
++#ifdef ISSUEDIR_SUPPORT
++	if (dirname) {
++		dd = open(dirname, O_RDONLY|O_CLOEXEC|O_DIRECTORY);
++		if (dd >= 0)
++			nfiles = scandirat(dd, ".", &namelist, issuedir_filter, versionsort);
++		if (nfiles <= 0)
++			dirname = NULL;
++	}
++	i = 0;
++#endif
++	if (filename)
++		f = fopen(filename, "r");
++
++	if (f || dirname) {
+ 		int c, oflag = tp->c_oflag;	    /* Save current setting. */
+ 
+ 		if ((op->flags & F_VCONSOLE) == 0) {
+@@ -1395,12 +1787,23 @@ static void do_prompt(struct options *op, struct termios *tp)
+ 			tcsetattr(STDIN_FILENO, TCSADRAIN, tp);
+ 		}
+ 
+-		while ((c = getc(fd)) != EOF) {
+-			if (c == '\\')
+-				output_special_char(getc(fd), op, tp, fd);
+-			else
+-				putchar(c);
+-		}
++		do {
++#ifdef ISSUEDIR_SUPPORT
++			if (!f && i < nfiles)
++				f = issuedir_next_file(dd, namelist, nfiles, &i);
++#endif
++			if (!f)
++				break;
++			while ((c = getc(f)) != EOF) {
++				if (c == '\\')
++					output_special_char(getc(f), op, tp, f);
++				else
++					putchar(c);
++			}
++			fclose(f);
++			f = NULL;
++		} while (dirname);
++
+ 		fflush(stdout);
+ 
+ 		if ((op->flags & F_VCONSOLE) == 0) {
+@@ -1409,11 +1812,36 @@ static void do_prompt(struct options *op, struct termios *tp)
+ 			/* Wait till output is gone. */
+ 			tcsetattr(STDIN_FILENO, TCSADRAIN, tp);
+ 		}
+-		fclose(fd);
+ 	}
+-#endif	/* ISSUE */
++
++#ifdef ISSUEDIR_SUPPORT
++	for (i = 0; i < nfiles; i++)
++		free(namelist[i]);
++	free(namelist);
++	if (dd >= 0)
++		close(dd);
++#endif
++}
++#endif /* ISSUE_SUPPORT */
++
++/* Show login prompt, optionally preceded by /etc/issue contents. */
++static void do_prompt(struct options *op, struct termios *tp)
++{
++#ifdef AGETTY_RELOAD
++again:
++#endif
++	print_issue_file(op, tp);
++
+ 	if (op->flags & F_LOGINPAUSE) {
+ 		puts(_("[press ENTER to login]"));
++#ifdef AGETTY_RELOAD
++		if (!wait_for_term_input(STDIN_FILENO)) {
++			/* reload issue */
++			if (op->flags & F_VCONSOLE)
++				termio_clear(STDOUT_FILENO);
++			goto again;
++		}
++#endif
+ 		getc(stdin);
+ 	}
+ #ifdef KDGKBLED
+@@ -1533,18 +1961,36 @@ static char *get_logname(struct options *op, struct termios *tp, struct chardata
+ 	*bp = '\0';
+ 
+ 	while (*logname == '\0') {
+-
+ 		/* Write issue file and prompt */
+ 		do_prompt(op, tp);
+ 
++#ifdef AGETTY_RELOAD
++		if (!wait_for_term_input(STDIN_FILENO)) {
++			/* refresh prompt -- discard input data, clear terminal
++			 * and call do_prompt() again
++			 */
++			if ((op->flags & F_VCONSOLE) == 0)
++				sleep(1);
++			tcflush(STDIN_FILENO, TCIFLUSH);
++			if (op->flags & F_VCONSOLE)
++				termio_clear(STDOUT_FILENO);
++			bp = logname;
++			*bp = '\0';
++			continue;
++		}
++#endif
+ 		cp->eol = '\0';
+ 
+ 		/* Read name, watch for break and end-of-line. */
+ 		while (cp->eol == '\0') {
+ 
+ 			char key;
++			ssize_t readres;
+ 
+-			if (read(STDIN_FILENO, &c, 1) < 1) {
++			debug("read from FD\n");
++			readres = read(STDIN_FILENO, &c, 1);
++			if (readres < 0) {
++				debug("read failed\n");
+ 
+ 				/* The terminal could be open with O_NONBLOCK when
+ 				 * -L (force CLOCAL) is specified...  */
+@@ -1558,12 +2004,15 @@ static char *get_logname(struct options *op, struct termios *tp, struct chardata
+ 				case ESRCH:
+ 				case EINVAL:
+ 				case ENOENT:
+-					break;
++					exit_slowly(EXIT_SUCCESS);
+ 				default:
+ 					log_err(_("%s: read: %m"), op->tty);
+ 				}
+ 			}
+ 
++			if (readres == 0)
++				c = 0;
++
+ 			/* Do parity bit handling. */
+ 			if (eightbit)
+ 				ascval = c;
+@@ -1588,8 +2037,10 @@ static char *get_logname(struct options *op, struct termios *tp, struct chardata
+ 			switch (key) {
+ 			case 0:
+ 				*bp = 0;
+-				if (op->numspeed > 1)
++				if (op->numspeed > 1 && !(op->flags & F_VCONSOLE))
+ 					return NULL;
++				if (readres == 0)
++					exit_slowly(EXIT_SUCCESS);
+ 				break;
+ 			case CR:
+ 			case NL:
+@@ -1627,6 +2078,7 @@ static char *get_logname(struct options *op, struct termios *tp, struct chardata
+ 			}
+ 		}
+ 	}
++
+ #ifdef HAVE_WIDECHAR
+ 	if ((op->flags & (F_EIGHTBITS|F_UTF8)) == (F_EIGHTBITS|F_UTF8)) {
+ 		/* Check out UTF-8 multibyte characters */
+@@ -1637,7 +2089,7 @@ static char *get_logname(struct options *op, struct termios *tp, struct chardata
+ 		if (len < 0)
+ 			log_err(_("%s: invalid character conversion for login name"), op->tty);
+ 
+-		wcs = (wchar_t *) malloc((len + 1) * sizeof(wchar_t));
++		wcs = malloc((len + 1) * sizeof(wchar_t));
+ 		if (!wcs)
+ 			log_err(_("failed to allocate memory: %m"));
+ 
+@@ -1702,12 +2154,12 @@ static void termio_final(struct options *op, struct termios *tp, struct chardata
+ 	case 1:
+ 		/* odd parity */
+ 		tp->c_cflag |= PARODD;
+-		/* do not break */
++		/* fallthrough */
+ 	case 2:
+ 		/* even parity */
+ 		tp->c_cflag |= PARENB;
+ 		tp->c_iflag |= INPCK | ISTRIP;
+-		/* do not break */
++		/* fallthrough */
+ 	case (1 | 2):
+ 		/* no parity bit */
+ 		tp->c_cflag &= ~CSIZE;
+@@ -1767,11 +2219,17 @@ static speed_t bcode(char *s)
+ 	return 0;
+ }
+ 
+-static void __attribute__ ((__noreturn__)) usage(FILE *out)
++static void __attribute__((__noreturn__)) usage(void)
+ {
++	FILE *out = stdout;
++
+ 	fputs(USAGE_HEADER, out);
+-	fprintf(out, _(" %1$s [options] line [baud_rate,...] [termtype]\n"
+-		       " %1$s [options] baud_rate,... line [termtype]\n"), program_invocation_short_name);
++	fprintf(out, _(" %1$s [options] <line> [<baud_rate>,...] [<termtype>]\n"
++		       " %1$s [options] <baud_rate>,... <line> [<termtype>]\n"), program_invocation_short_name);
++
++	fputs(USAGE_SEPARATOR, out);
++	fputs(_("Open a terminal and set its mode.\n"), out);
++
+ 	fputs(USAGE_OPTIONS, out);
+ 	fputs(_(" -8, --8bits                assume 8-bit tty\n"), out);
+ 	fputs(_(" -a, --autologin <user>     login the specified user automatically\n"), out);
+@@ -1782,10 +2240,12 @@ static void __attribute__ ((__noreturn__)) usage(FILE *out)
+ 	fputs(_(" -H, --host <hostname>      specify login host\n"), out);
+ 	fputs(_(" -i, --noissue              do not display issue file\n"), out);
+ 	fputs(_(" -I, --init-string <string> set init string\n"), out);
++	fputs(_(" -J  --noclear              do not clear the screen before prompt\n"), out);
+ 	fputs(_(" -l, --login-program <file> specify login program\n"), out);
+-	fputs(_(" -L, --local-line[=<mode>]  cotrol local line flag\n"), out);
++	fputs(_(" -L, --local-line[=<mode>]  control the local line flag\n"), out);
+ 	fputs(_(" -m, --extract-baud         extract baud rate during connect\n"), out);
+ 	fputs(_(" -n, --skip-login           do not prompt for login\n"), out);
++	fputs(_(" -N  --nonewline            do not print a newline before issue\n"), out);
+ 	fputs(_(" -o, --login-options <opts> options that are passed to login\n"), out);
+ 	fputs(_(" -p, --login-pause          wait for any key before the login\n"), out);
+ 	fputs(_(" -r, --chroot <dir>         change root to the directory\n"), out);
+@@ -1794,18 +2254,29 @@ static void __attribute__ ((__noreturn__)) usage(FILE *out)
+ 	fputs(_(" -t, --timeout <number>     login process timeout\n"), out);
+ 	fputs(_(" -U, --detect-case          detect uppercase terminal\n"), out);
+ 	fputs(_(" -w, --wait-cr              wait carriage-return\n"), out);
+-	fputs(_("     --noclear              do not clear the screen before prompt\n"), out);
+ 	fputs(_("     --nohints              do not print hints\n"), out);
+-	fputs(_("     --nonewline            do not print a newline before issue\n"), out);
+ 	fputs(_("     --nohostname           no hostname at all will be shown\n"), out);
+ 	fputs(_("     --long-hostname        show full qualified hostname\n"), out);
+ 	fputs(_("     --erase-chars <string> additional backspace chars\n"), out);
+ 	fputs(_("     --kill-chars <string>  additional kill chars\n"), out);
+-	fputs(_("     --help                 display this help and exit\n"), out);
+-	fputs(_("     --version              output version information and exit\n"), out);
+-	fprintf(out, USAGE_MAN_TAIL("agetty(8)"));
++	fputs(_("     --chdir <directory>    chdir before the login\n"), out);
++	fputs(_("     --delay <number>       sleep seconds before prompt\n"), out);
++	fputs(_("     --nice <number>        run login with this priority\n"), out);
++	fputs(_("     --reload               reload prompts on running agetty instances\n"), out);
++	fputs(_("     --list-speeds          display supported baud rates\n"), out);
++	printf( "     --help                 %s\n", USAGE_OPTSTR_HELP);
++	printf( "     --version              %s\n", USAGE_OPTSTR_VERSION);
++	printf(USAGE_MAN_TAIL("agetty(8)"));
++
++	exit(EXIT_SUCCESS);
++}
++
++static void list_speeds(void)
++{
++	const struct Speedtab *sp;
+ 
+-	exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS);
++	for (sp = speedtab; sp->speed; sp++)
++		printf("%10ld\n", sp->speed);
+ }
+ 
+ /*
+@@ -1855,6 +2326,13 @@ static void dolog(int priority, const char *fmt, va_list ap)
+ #endif				/* USE_SYSLOG */
+ }
+ 
++static void exit_slowly(int code)
++{
++	/* Be kind to init(8). */
++	sleep(10);
++	exit(code);
++}
++
+ static void log_err(const char *fmt, ...)
+ {
+ 	va_list ap;
+@@ -1863,9 +2341,7 @@ static void log_err(const char *fmt, ...)
+ 	dolog(LOG_ERR, fmt, ap);
+ 	va_end(ap);
+ 
+-	/* Be kind to init(8). */
+-	sleep(10);
+-	exit(EXIT_FAILURE);
++	exit_slowly(EXIT_FAILURE);
+ }
+ 
+ static void log_warn(const char *fmt, ...)
+@@ -1877,41 +2353,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)
++{
++	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)
+ {
+-	if (!iface)
++	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)
+@@ -1919,9 +2424,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;
+@@ -1930,12 +2432,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);
+ 	}
+@@ -1974,22 +2472,25 @@ static void output_special_char(unsigned char c, struct options *op,
+ {
+ 	struct utsname uts;
+ 
+-	uname(&uts);
+-
+ 	switch (c) {
+ 	case 's':
++		uname(&uts);
+ 		printf("%s", uts.sysname);
+ 		break;
+ 	case 'n':
++		uname(&uts);
+ 		printf("%s", uts.nodename);
+ 		break;
+ 	case 'r':
++		uname(&uts);
+ 		printf("%s", uts.release);
+ 		break;
+ 	case 'v':
++		uname(&uts);
+ 		printf("%s", uts.version);
+ 		break;
+ 	case 'm':
++		uname(&uts);
+ 		printf("%s", uts.machine);
+ 		break;
+ 	case 'o':
+@@ -2066,30 +2567,39 @@ static void output_special_char(unsigned char c, struct options *op,
+ 	{
+ 		char *var = NULL, varname[64];
+ 
+-		if (get_escape_argument(fp, varname, sizeof(varname)))
++		/* \S{varname} */
++		if (get_escape_argument(fp, varname, sizeof(varname))) {
+ 			var = read_os_release(op, varname);
+-		else if (!(var = read_os_release(op, "PRETTY_NAME")))
+-			var = uts.sysname;
+-		if (var) {
+-			if (strcmp(varname, "ANSI_COLOR") == 0)
+-				printf("\033[%sm", var);
+-			else
+-				printf("%s", var);
+-			if (var != uts.sysname)
+-				free(var);
++			if (var) {
++				if (strcmp(varname, "ANSI_COLOR") == 0)
++					printf("\033[%sm", var);
++				else
++					fputs(var, stdout);
++			}
++		/* \S */
++		} else if ((var = read_os_release(op, "PRETTY_NAME"))) {
++			fputs(var, stdout);
++
++		/* \S and PRETTY_NAME not found */
++		} else {
++			uname(&uts);
++			fputs(uts.sysname, stdout);
+ 		}
++
++		free(var);
++
+ 		break;
+ 	}
+ 	case 'u':
+ 	case 'U':
+ 	{
+ 		int users = 0;
+-		struct utmp *ut;
+-		setutent();
+-		while ((ut = getutent()))
++		struct utmpx *ut;
++		setutxent();
++		while ((ut = getutxent()))
+ 			if (ut->ut_type == USER_PROCESS)
+ 				users++;
+-		endutent();
++		endutxent();
+ 		if (c == 'U')
+ 			printf(P_("%d user", "%d users", users), users);
+ 		else
+@@ -2100,17 +2610,22 @@ 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;
++#ifdef AGETTY_RELOAD
++		open_netlink();
++#endif
++
++		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:
+@@ -2162,7 +2677,7 @@ static void init_special_char(char* arg, struct options *op)
+ }
+ 
+ /*
+- * Appends @str to @dest and if @dest is not empty then use use @sep as a
++ * Appends @str to @dest and if @dest is not empty then use @sep as a
+  * separator. The maximal final length of the @dest is @len.
+  *
+  * Returns the final @dest length or -1 in case of error.
+@@ -2217,3 +2732,19 @@ err:
+ 	log_err(_("checkname failed: %m"));
+ }
+ 
++static void reload_agettys(void)
++{
++#ifdef AGETTY_RELOAD
++	int fd = open(AGETTY_RELOAD_FILENAME, O_CREAT|O_CLOEXEC|O_WRONLY,
++					      S_IRUSR|S_IWUSR);
++	if (fd < 0)
++		err(EXIT_FAILURE, _("cannot open %s"), AGETTY_RELOAD_FILENAME);
++
++	if (futimens(fd, NULL) < 0 || close(fd) < 0)
++		err(EXIT_FAILURE, _("cannot touch file %s"),
++		    AGETTY_RELOAD_FILENAME);
++#else
++	/* very unusual */
++	errx(EXIT_FAILURE, _("--reload is unsupported on your system"));
++#endif
++}
+-- 
+2.20.1
+
diff --git a/SPECS/util-linux.spec b/SPECS/util-linux.spec
index a7ec932..974ba18 100644
--- a/SPECS/util-linux.spec
+++ b/SPECS/util-linux.spec
@@ -2,7 +2,7 @@
 Summary: A collection of basic system utilities
 Name: util-linux
 Version: 2.23.2
-Release: 59%{?dist}
+Release: 59%{?dist}.1
 License: GPLv2 and GPLv2+ and LGPLv2+ and BSD with advertising and Public Domain
 Group: System Environment/Base
 URL: http://en.wikipedia.org/wiki/Util-linux
@@ -436,6 +436,11 @@ Patch177: 0177-mount-append-inverting-options-for-mount.-type-on-us.patch
 # 1616264 - Login to emergency shell failed
 Patch178: 0178-sulogin-backport-RHEL-8-version.patch
 
+# RHEL7.6.Z
+#
+# 1664752 - Bull (Atos) server lands up in invalid stty settings on the serial console after boot preventing login
+Patch179: 0179-agetty-backport-RHEL-8-version.patch
+
 %description
 The util-linux package contains a large variety of low-level system
 utilities that are necessary for a Linux system to function. Among
@@ -1204,6 +1209,9 @@ fi
 %{_libdir}/pkgconfig/uuid.pc
 
 %changelog
+* Thu Jan 31 2019 Karel Zak <kzak@redhat.com> 2.23.2-59.el7_6.1
+- fix #1664752 - Bull (Atos) server lands up in invalid stty settings on the serial console after boot preventing login
+
 * Mon Aug 20 2018 Karel Zak <kzak@redhat.com> 2.23.2-59
 - fix #1618711 - exec option in mount unable to override the implicit noexec in user option
 - fix #1616264 - Login to emergency shell failed