All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/5] sulogin: use the linked lists from list.h for consoles list
@ 2012-12-07  8:00 Werner Fink
  2012-12-07  8:00 ` [PATCH 2/5] sulogin: make usleep() workaround work Werner Fink
                   ` (4 more replies)
  0 siblings, 5 replies; 20+ messages in thread
From: Werner Fink @ 2012-12-07  8:00 UTC (permalink / raw)
  To: util-linux; +Cc: Karel Zak, Werner Fink

with this the double linked list feature from util-linux is used
instead of the single linked list.

Signed-off-by: Werner Fink <werner@suse.de>
---
 include/consoles.h |    6 ++--
 lib/consoles.c     |   77 ++++++++++++++++++++++++++++++++--------------------
 2 files changed, 51 insertions(+), 32 deletions(-)

diff --git include/consoles.h include/consoles.h
index 2283d02..2544263 100644
--- include/consoles.h
+++ include/consoles.h
@@ -2,6 +2,7 @@
  * consoles.h	    Header file for routines to detect the system consoles
  *
  * Copyright (c) 2011 SuSE LINUX Products GmbH, All rights reserved.
+ * Copyright (c) 2012 Werner Fink <werner@suse.de>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -25,6 +26,7 @@
 #include <stdint.h>
 #include <stdio.h>
 #include <termios.h>
+#include <list.h>
 
 struct chardata {
 	uint8_t	erase;
@@ -33,6 +35,7 @@ struct chardata {
 	uint8_t parity;
 };
 struct console {
+	struct list_head entry;
 	char *tty;
 	FILE *file;
 	uint32_t flags;
@@ -42,8 +45,7 @@ struct console {
 	pid_t pid;
 	struct chardata cp;
 	struct termios tio;
-	struct console *next;
 };
 
 extern int detect_consoles(const char *device, int fallback,
-			   struct console **consoles);
+			   struct list_head *consoles);
diff --git lib/consoles.c lib/consoles.c
index 7bc21b6..38c8208 100644
--- lib/consoles.c
+++ lib/consoles.c
@@ -3,6 +3,7 @@
  *
  * Copyright (c) 2011 SuSE LINUX Products GmbH, All rights reserved.
  * Copyright (C) 2012 Karel Zak <kzak@redhat.com>
+ * Copyright (C) 2012 Werner Fink <werner@suse.de>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -56,6 +57,7 @@
 #endif
 
 #define alignof(type)		((sizeof(type)+(sizeof(void*)-1)) & ~(sizeof(void*)-1))
+#define	strsize(string)		(strlen((string))+1)
 
 static int consoles_debug;
 #define DBG(x)	do { \
@@ -200,7 +202,7 @@ static
 #ifdef __GNUC__
 __attribute__((__nonnull__,__hot__))
 #endif
-int append_console(struct console **list, char * name)
+int append_console(struct list_head *consoles, const char *name)
 {
 	static const struct chardata initcp = {
 		.erase	= CERASE,
@@ -210,16 +212,21 @@ int append_console(struct console **list, char * name)
 	};
 	struct console *restrict tail;
 	struct console *last;
+	
+	if (list_empty(consoles))
+		last = NULL;
+	else
+		last = list_entry(consoles->prev, struct console, entry);
 
 	DBG(dbgprint("appenging %s", name));
 
-	if (posix_memalign((void*)&tail, sizeof(void*), alignof(typeof(struct console))) != 0)
+	if (posix_memalign((void*)&tail, sizeof(void*),
+			   alignof(struct console)+strsize(name)) != 0)
 		return -ENOMEM;
 
-	for (last = *list; last && last->next; last = last->next);
-
-	tail->next = NULL;
-	tail->tty = name;
+	list_add_tail(&tail->entry, consoles);
+	tail->tty = ((char*)tail)+alignof(struct console);
+	strcpy(tail->tty, name);
 
 	tail->file = (FILE*)0;
 	tail->flags = 0;
@@ -229,11 +236,6 @@ int append_console(struct console **list, char * name)
 	memset(&tail->tio, 0, sizeof(tail->tio));
 	memcpy(&tail->cp, &initcp, sizeof(struct chardata));
 
-	if (!last)
-		*list = tail;
-	else
-		last->next = tail;
-
 	return 0;
 }
 
@@ -245,7 +247,7 @@ int append_console(struct console **list, char * name)
  *	  1	- recoverable error
  *	  2	- detection not available
  */
-static int detect_consoles_from_proc(struct console **consoles)
+static int detect_consoles_from_proc(struct list_head *consoles)
 {
 	char fbuf[16 + 1];
 	DIR *dir = NULL;
@@ -274,11 +276,12 @@ static int detect_consoles_from_proc(struct console **consoles)
 		if (!name)
 			continue;
 		rc = append_console(consoles, name);
+		free(name);
 		if (rc < 0)
 			goto done;
 	}
 
-	rc = *consoles ? 0 : 1;
+	rc = list_empty(consoles) ? 1 : 0;
 done:
 	if (dir)
 		closedir(dir);
@@ -295,7 +298,7 @@ done:
  *	  1	- recoverable error
  *	  2	- detection not available
  */
-static int detect_consoles_from_sysfs(struct console **consoles)
+static int detect_consoles_from_sysfs(struct list_head *consoles)
 {
 	char *attrib = NULL, *words, *token;
 	DIR *dir = NULL;
@@ -335,11 +338,12 @@ static int detect_consoles_from_sysfs(struct console **consoles)
 		if (!name)
 			continue;
 		rc = append_console(consoles, name);
+		free(name);
 		if (rc < 0)
 			goto done;
 	}
 
-	rc = *consoles ? 0 : 1;
+	rc = list_empty(consoles) ? 1 : 0;
 done:
 	free(attrib);
 	if (dir)
@@ -349,7 +353,7 @@ done:
 }
 
 
-static int detect_consoles_from_cmdline(struct console **consoles)
+static int detect_consoles_from_cmdline(struct list_head *consoles)
 {
 	char *cmdline, *words, *token;
 	dev_t comparedev;
@@ -422,11 +426,12 @@ static int detect_consoles_from_cmdline(struct console **consoles)
 		if (!name)
 			continue;
 		rc = append_console(consoles, name);
+		free(name);
 		if (rc < 0)
 			goto done;
 	}
 
-	rc = *consoles ? 0 : 1;
+	rc = list_empty(consoles) ? 1 : 0;
 done:
 	if (dir)
 		closedir(dir);
@@ -435,7 +440,7 @@ done:
 	return rc;
 }
 
-static int detect_consoles_from_tiocgdev(struct console **consoles,
+static int detect_consoles_from_tiocgdev(struct list_head *consoles,
 					int fallback,
 					const char *device)
 {
@@ -445,6 +450,7 @@ static int detect_consoles_from_tiocgdev(struct console **consoles,
 	int rc = 1, fd = -1;
 	dev_t comparedev;
 	DIR *dir = NULL;
+	struct console *console;
 
 	DBG(dbgprint("trying tiocgdev"));
 
@@ -478,12 +484,16 @@ static int detect_consoles_from_tiocgdev(struct console **consoles,
 		}
 	}
 	rc = append_console(consoles, name);
+	free(name);
 	if (rc < 0)
 		goto done;
-	if (*consoles &&  (!device || !*device))
-		(*consoles)->fd = fallback;
-
-	rc = *consoles ? 0 : 1;
+	if (list_empty(consoles)) {
+		rc = 1;
+		goto done;
+	}
+	console = list_entry(consoles->prev, struct console, entry);
+	if (console &&  (!device || !*device))
+		console->fd = fallback;
 done:
 	if (fd >= 0)
 		close(fd);
@@ -503,7 +513,7 @@ done:
  * Returns 1 if stdout and stderr should be reconnected and 0
  * otherwise or less than zero on error.
  */
-int detect_consoles(const char *device, int fallback, struct console **consoles)
+int detect_consoles(const char *device, int fallback, struct list_head *consoles)
 {
 	int fd, reconnect = 0, rc;
 	dev_t comparedev = 0;
@@ -581,10 +591,11 @@ int detect_consoles(const char *device, int fallback, struct console **consoles)
 
 		if (name) {
 			rc = append_console(consoles, name);
+			free(name);
 			if (rc < 0)
 				return rc;
 		}
-		if (!*consoles)
+		if (list_empty(consoles))
 			goto fallback;
 
 		DBG(dbgprint("detection success [rc=%d]", reconnect));
@@ -632,7 +643,7 @@ console:
 	if (rc < 0)
 		return rc;		/* fatal error */
 
-	if (*consoles) {
+	if (!list_empty(consoles)) {
 		DBG(dbgprint("detection success [rc=%d]", reconnect));
 		return reconnect;
 	}
@@ -642,6 +653,7 @@ console:
 fallback:
 	if (fallback >= 0) {
 		const char *name;
+		struct console *console;
 
 		if (device && *device != '\0')
 			name = device;
@@ -653,8 +665,11 @@ fallback:
 		rc = append_console(consoles, strdup(name));
 		if (rc < 0)
 			return rc;
-		if (*consoles)
-			(*consoles)->fd = fallback;
+		if (list_empty(consoles))
+			return 1;
+		console = list_entry(consoles->prev, struct console, entry);
+		if (console)
+			console->fd = fallback;
 	}
 
 	DBG(dbgprint("detection done by fallback [rc=%d]", reconnect));
@@ -667,7 +682,7 @@ int main(int argc, char *argv[])
 {
 	char *name = NULL;
 	int fd, re;
-	struct console *p, *consoles = NULL;
+	struct list_head *p, consoles = {&consoles, &consoles};
 
 	if (argc == 2) {
 		name = argv[1];
@@ -682,8 +697,10 @@ int main(int argc, char *argv[])
 
 	re = detect_consoles(name, fd, &consoles);
 
-	for (p = consoles; p; p = p->next)
-		printf("%s: id=%d %s\n", p->tty, p->id, re ? "(reconnect) " : "");
+	list_for_each(p, &consoles) {
+		struct console *c = list_entry(p, struct console, entry);
+		printf("%s: id=%d %s\n", c->tty, c->id, re ? "(reconnect) " : "");
+	}
 
 	return 0;
 }
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH 2/5] sulogin: make usleep() workaround work
  2012-12-07  8:00 [PATCH 1/5] sulogin: use the linked lists from list.h for consoles list Werner Fink
@ 2012-12-07  8:00 ` Werner Fink
  2012-12-18 15:07   ` Karel Zak
  2012-12-07  8:00 ` [PATCH 3/5] sulogin: use alarm function to indicate if a timeout occurs Werner Fink
                   ` (3 subsequent siblings)
  4 siblings, 1 reply; 20+ messages in thread
From: Werner Fink @ 2012-12-07  8:00 UTC (permalink / raw)
  To: util-linux; +Cc: Karel Zak, Werner Fink

Simply fix a compile problem found during debugging console.c

Signed-off-by: Werner Fink <werner@suse.de>
---
 include/c.h |   10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)

diff --git include/c.h include/c.h
index 1107287..ec1020e 100644
--- include/c.h
+++ include/c.h
@@ -19,6 +19,10 @@
 # include <err.h>
 #endif
 
+#ifndef HAVE_USLEEP
+# include <time.h>
+#endif
+
 /*
  * Compiler specific stuff
  */
@@ -246,13 +250,13 @@ static inline size_t get_hostname_max(void)
  * This function is marked obsolete in POSIX.1-2001 and removed in
  * POSIX.1-2008. It is replaced with nanosleep().
  */
-static inline usleep(useconds_t usec)
+static inline int usleep(useconds_t usec)
 {
 	struct timespec waittime = {
 		.tv_sec   =  usec / 1000000L,
 		.tv_nsec  = (usec % 1000000L) * 1000
-	}
-	nanosleep(&waittime, NULL);
+	};
+	return nanosleep(&waittime, NULL);
 }
 #endif
 
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH 3/5] sulogin: use alarm function to indicate if a timeout occurs
  2012-12-07  8:00 [PATCH 1/5] sulogin: use the linked lists from list.h for consoles list Werner Fink
  2012-12-07  8:00 ` [PATCH 2/5] sulogin: make usleep() workaround work Werner Fink
@ 2012-12-07  8:00 ` Werner Fink
  2012-12-18 15:15   ` Karel Zak
  2012-12-07  8:00 ` [PATCH 4/5] sulogin: mount temporary /dev and /proc if not found Werner Fink
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 20+ messages in thread
From: Werner Fink @ 2012-12-07  8:00 UTC (permalink / raw)
  To: util-linux; +Cc: Karel Zak, Werner Fink

A small change to use the alarm handler to indicate if a timeout occurs.

Signed-off-by: Werner Fink <werner@suse.de>
---
 login-utils/sulogin.c |   20 +++++++++++++++++---
 1 file changed, 17 insertions(+), 3 deletions(-)

diff --git login-utils/sulogin.c login-utils/sulogin.c
index db783a2..dbcc855 100644
--- login-utils/sulogin.c
+++ login-utils/sulogin.c
@@ -8,6 +8,7 @@
  *
  * Copyright (C) 1998-2003 Miquel van Smoorenburg.
  * Copyright (C) 2012 Karel Zak <kzak@redhat.com>
+ * Copyright (C) 2012 Werner Fink <werner@suse.de>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -60,12 +61,15 @@ struct sigaction saved_sigint;
 struct sigaction saved_sigtstp;
 struct sigaction saved_sigquit;
 
+static volatile sig_atomic_t alarm_rised;
+
 /*
  * Called at timeout.
  */
 static void alrm_handler(int sig __attribute__((unused)))
 {
-	return;
+	/* Timeout expired */
+	alarm_rised++;
 }
 
 static void mask_signal(int signal, void (*handler)(int),
@@ -594,17 +598,27 @@ int main(int argc, char **argv)
 	 * Ask for the password.
 	 */
 	while (pwd) {
+		int failed = 0;
 		if ((p = getpasswd(pwd->pw_passwd)) == NULL)
 			break;
 		if (pwd->pw_passwd[0] == 0 ||
-		    strcmp(crypt(p, pwd->pw_passwd), pwd->pw_passwd) == 0)
+		    strcmp(crypt(p, pwd->pw_passwd), pwd->pw_passwd) == 0) {
 			sushell(pwd);
+			failed++;
+		}
 		mask_signal(SIGQUIT, SIG_IGN, &saved_sigquit);
 		mask_signal(SIGTSTP, SIG_IGN, &saved_sigtstp);
 		mask_signal(SIGINT,  SIG_IGN, &saved_sigint);
-		fprintf(stderr, _("Login incorrect\n\n"));
+		if (failed) {
+		    fprintf(stderr, _("Can not execute su shell\n\n"));
+		    break;
+		} else
+		    fprintf(stderr, _("Login incorrect\n\n"));
 	}
 
+	if (alarm_rised)
+		fprintf(stderr, _("Timed out\n\n"));
+
 	/*
 	 * User pressed Control-D.
 	 */
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH 4/5] sulogin: mount temporary /dev and /proc if not found
  2012-12-07  8:00 [PATCH 1/5] sulogin: use the linked lists from list.h for consoles list Werner Fink
  2012-12-07  8:00 ` [PATCH 2/5] sulogin: make usleep() workaround work Werner Fink
  2012-12-07  8:00 ` [PATCH 3/5] sulogin: use alarm function to indicate if a timeout occurs Werner Fink
@ 2012-12-07  8:00 ` Werner Fink
  2012-12-07 14:17   ` Dave Reisner
  2012-12-18 15:17   ` Karel Zak
  2012-12-07  8:00 ` [PATCH 5/5] sulogin: add multi console feature from SysVinit sulogin Werner Fink
  2012-12-18 15:05 ` [PATCH 1/5] sulogin: use the linked lists from list.h for consoles list Karel Zak
  4 siblings, 2 replies; 20+ messages in thread
From: Werner Fink @ 2012-12-07  8:00 UTC (permalink / raw)
  To: util-linux; +Cc: Karel Zak, Werner Fink

This is very usefull if initrd can not loaded that is no /dev and no
/proc is found.  Also if the /etc/shadow and /etc/passwd is copied into
the initrd the sulogin can be used in initrd even before /dev and/or /proc
are mounted.

Signed-off-by: Werner Fink <werner@suse.de>
---
 configure.ac          |   10 ++++++++
 login-utils/sulogin.c |   57 ++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 67 insertions(+)

diff --git configure.ac configure.ac
index 3be3715..631002f 100644
--- configure.ac
+++ configure.ac
@@ -1296,6 +1296,16 @@ if test "x$enable_use_tty_group" = xyes; then
   AC_DEFINE(USE_TTY_GROUP, 1, [Should wall and write be installed setgid tty?])
 fi
 
+AC_ARG_ENABLE([use-emergency-dev],
+  AS_HELP_STRING([--disable-use-emergency-dev], [do not use emergency mount of /dev and /proc for sulogin]),
+  [], enable_use_emergency_dev=yes
+)
+AM_CONDITIONAL(USE_EMERGENCY_DEV, test "x$enable_use_emergency_dev" = xyes)
+
+if test "x$enable_use_emergency_dev" = xyes; then
+  AC_DEFINE(USE_EMERGENCY_DEV, 1, [Should sulogin use a emergency mount of /dev and /proc?])
+fi
+
 AC_ARG_ENABLE([makeinstall-chown],
   AS_HELP_STRING([--disable-makeinstall-chown], [do not do chown-like operations during "make install"]),
   [], enable_makeinstall_chown=yes
diff --git login-utils/sulogin.c login-utils/sulogin.c
index dbcc855..0b0d21c 100644
--- login-utils/sulogin.c
+++ login-utils/sulogin.c
@@ -47,6 +47,20 @@
 # include <selinux/get_context_list.h>
 #endif
 
+#ifdef USE_EMERGENCY_DEV
+# include <sys/statfs.h>
+# include <sys/mount.h>
+# include <linux/fs.h>
+# include <linux/magic.h>
+# include <linux/major.h>
+# ifndef TMPFS_MAGIC
+#  define TMPFS_MAGIC	0x01021994
+# endif
+# ifndef MNT_DETACH
+#  define MNT_DETACH	2
+# endif
+#endif
+
 #include "c.h"
 #include "closestream.h"
 #include "nls.h"
@@ -441,6 +455,49 @@ static void fixtty(void)
 		warn(_("tcsetattr failed"));
 }
 
+#ifdef USE_EMERGENCY_DEV
+/*
+ * Make C library standard calls such like ttyname(3) work
+ * even if the system does not show any of the standard
+ * directories.
+ */
+
+static uint32_t mounts;
+# define MNT_PROCFS	0x0001
+# define MNT_DEVTMPFS	0x0002
+
+static __attribute__((__noinline__)) void putmounts(void)
+{
+	if (mounts & MNT_DEVTMPFS)
+		umount2("/dev", MNT_DETACH);
+	if (mounts & MNT_PROCFS)
+		umount2("/proc", MNT_DETACH);
+}
+
+# define dovoid(f)	if ((f)){}
+static __attribute__((__constructor__)) void getmounts(void)
+{
+	struct statfs st;
+	if (statfs("/proc", &st) == 0 && st.f_type != PROC_SUPER_MAGIC) {
+		if (mount("proc", "/proc", "proc", MS_RELATIME, NULL) == 0)
+			mounts |= MNT_PROCFS;
+	}
+	if (statfs("/dev", &st) == 0 && st.f_type != TMPFS_MAGIC) {
+		if (mount("devtmpfs", "/dev", "devtmpfs", MS_RELATIME, "mode=0755,nr_inodes=0") == 0) {
+			mounts |= MNT_DEVTMPFS;
+			(void)mknod("/dev/console", S_IFCHR|S_IRUSR|S_IWUSR, makedev(TTYAUX_MAJOR, 1));
+			if (symlink("/proc/self/fd", "/dev/fd") == 0) {
+				dovoid(symlink("fd/0", "/dev/stdin"));
+				dovoid(symlink("fd/1", "/dev/stdout"));
+				dovoid(symlink("fd/2", "/dev/stderr"));
+			}
+		}
+	}
+	if (mounts) atexit(putmounts);
+}
+# undef dovoid
+#endif
+
 static void usage(FILE *out)
 {
 	fputs(USAGE_HEADER, out);
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH 5/5] sulogin: add multi console feature from SysVinit sulogin
  2012-12-07  8:00 [PATCH 1/5] sulogin: use the linked lists from list.h for consoles list Werner Fink
                   ` (2 preceding siblings ...)
  2012-12-07  8:00 ` [PATCH 4/5] sulogin: mount temporary /dev and /proc if not found Werner Fink
@ 2012-12-07  8:00 ` Werner Fink
  2012-12-07 10:27   ` Dr. Werner Fink
  2012-12-18 15:05 ` [PATCH 1/5] sulogin: use the linked lists from list.h for consoles list Karel Zak
  4 siblings, 1 reply; 20+ messages in thread
From: Werner Fink @ 2012-12-07  8:00 UTC (permalink / raw)
  To: util-linux; +Cc: Karel Zak, Werner Fink

Now after adding Conflicts=rescue.service to getty@.service and
serial-getty@.service and Conflicts=getty.target to rescue.target
all works with `systemctl rescue'.  Even adding init=/sbin/sulogin
to the kernels command line by using the `e' key in grub2 boot
menu works flawless.

Signed-off-by: Werner Fink <werner@suse.de>
---
 login-utils/sulogin.c |  665 ++++++++++++++++++++++++++++++++++++++-----------
 1 file changed, 516 insertions(+), 149 deletions(-)

diff --git login-utils/sulogin.c login-utils/sulogin.c
index 0b0d21c..c4e44a9 100644
--- login-utils/sulogin.c
+++ login-utils/sulogin.c
@@ -24,8 +24,10 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
+#include <sys/mman.h>
 #include <sys/types.h>
 #include <sys/stat.h>
+#include <sys/wait.h>
 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
@@ -67,15 +69,188 @@
 #include "pathnames.h"
 #include "strutils.h"
 #include "ttyutils.h"
+#include "consoles.h"
+#define CONMAX		16
+
+#define BS		CTRL('h')
+#define NL		CTRL('j')
+#define CR		CTRL('m')
 
 static unsigned int timeout;
 static int profile;
+static volatile uint32_t openfd;		/* Remember higher file descriptors */
+static volatile uint32_t *usemask;
 
 struct sigaction saved_sigint;
 struct sigaction saved_sigtstp;
 struct sigaction saved_sigquit;
+struct sigaction saved_sighup;
+struct sigaction saved_sigchld;
 
 static volatile sig_atomic_t alarm_rised;
+static volatile sig_atomic_t sigchild;
+
+#ifndef IUCLC
+# define IUCLC		0
+#endif
+
+/*
+ * Fix the tty modes and set reasonable defaults.
+ */
+static void tcinit(struct console *con)
+{
+	int mode = 0, flags = 0;
+	struct termios *tio = &con->tio;
+	int fd = con->fd;
+
+	errno = 0;
+
+	if (tcgetattr(fd, tio) < 0) {
+		warn(_("tcgetattr failed"));
+		con->flags |= CON_NOTTY;
+		return;
+	}
+
+	/* Handle serial lines here */
+	if (ioctl(fd, TIOCMGET, (char *) &mode) == 0) {
+		speed_t ispeed, ospeed;
+		struct winsize ws;
+
+		/* this is a modem line */
+		con->flags |= CON_SERIAL;
+
+		/* Flush input and output queues on modem lines */
+		(void) tcflush(fd, TCIOFLUSH);
+
+		ispeed = cfgetispeed(tio);
+		ospeed = cfgetospeed(tio);
+
+		if (!ispeed) ispeed = TTYDEF_SPEED;
+		if (!ospeed) ospeed = TTYDEF_SPEED;
+
+		tio->c_iflag = tio->c_lflag = tio->c_oflag = 0;
+		tio->c_cflag = CREAD | CS8 | HUPCL | (tio->c_cflag & CLOCAL);
+
+		cfsetispeed(tio, ispeed);
+		cfsetospeed(tio, ospeed);
+
+		tio->c_line         = 0;
+		tio->c_cc[VTIME]    = 0;
+		tio->c_cc[VMIN]     = 1;
+
+		if (ioctl(fd, TIOCGWINSZ, &ws) == 0) {
+			int set = 0;
+			if (ws.ws_row == 0) {
+				ws.ws_row = 24;
+				set++;
+			}
+			if (ws.ws_col == 0) {
+				ws.ws_col = 80;
+				set++;
+			}
+			if (set)
+				(void)ioctl(fd, TIOCSWINSZ, &ws);
+		}
+
+		setlocale(LC_CTYPE, "POSIX");
+		goto setattr;
+	}
+#if defined(IUTF8) && defined(KDGKBMODE)
+	/* Detect mode of current keyboard setup, e.g. for UTF-8 */
+	if (ioctl(fd, KDGKBMODE, &mode) < 0)
+		mode = K_RAW;
+	switch(mode) {
+	case K_UNICODE:
+		setlocale(LC_CTYPE, "C.UTF-8");
+		flags |= UL_TTY_UTF8;
+		break;
+	case K_RAW:
+	case K_MEDIUMRAW:
+	case K_XLATE:
+	default:
+		setlocale(LC_CTYPE, "POSIX");
+		break;
+	}
+#else
+	setlocale(LC_CTYPE, "POSIX");
+#endif
+	reset_virtual_console(tio, flags);
+setattr:
+	if (tcsetattr(fd, TCSANOW, tio))
+		warn(_("tcsetattr failed"));
+
+	/* Enable blocking mode for read and write */
+	if ((flags = fcntl(fd, F_GETFL, 0)) != -1)
+		(void)fcntl(fd, F_SETFL, flags & ~O_NONBLOCK);
+}
+
+/*
+ * Finalize the tty modes on modem lines.
+ */
+static void tcfinal(struct console *con)
+{
+	struct termios *tio;
+	int fd;
+
+	if ((con->flags & CON_SERIAL) == 0) {
+		setenv("TERM", "linux", 1);
+		return;
+	}
+	if (con->flags & CON_NOTTY)
+		return;
+
+	setenv("TERM", "vt102", 1);
+	tio = &con->tio;
+	fd = con->fd;
+
+	tio->c_iflag |= (IXON | IXOFF);
+	tio->c_lflag |= (ICANON | ISIG | ECHO|ECHOE|ECHOK|ECHOKE);
+	tio->c_oflag |= OPOST;
+
+	tio->c_cc[VINTR]    = CINTR;
+	tio->c_cc[VQUIT]    = CQUIT;
+	tio->c_cc[VERASE]   = con->cp.erase;
+	tio->c_cc[VKILL]    = con->cp.kill;
+	tio->c_cc[VEOF]     = CEOF;
+#ifdef VSWTC
+	tio->c_cc[VSWTC]    = _POSIX_VDISABLE;
+#else
+	tio->c_cc[VSWTCH]   = _POSIX_VDISABLE;
+#endif
+	tio->c_cc[VSTART]   = CSTART;
+	tio->c_cc[VSTOP]    = CSTOP;
+	tio->c_cc[VSUSP]    = CSUSP;
+	tio->c_cc[VEOL]     = _POSIX_VDISABLE;
+
+	if (con->cp.eol == CR) {
+		tio->c_iflag |= ICRNL;
+		tio->c_iflag &= ~(INLCR|IGNCR);
+		tio->c_oflag |= ONLCR;
+		tio->c_oflag &= ~(OCRNL|ONLRET);
+	}
+
+	switch (con->cp.parity) {
+	default:
+	case 0:
+		tio->c_cflag &= ~(PARODD | PARENB);
+		tio->c_iflag &= ~(INPCK | ISTRIP);
+		break;
+	case 1:				/* odd parity */
+		tio->c_cflag |= PARODD;
+		/* fall through */
+	case 2:				/* even parity */
+		tio->c_cflag |= PARENB;
+		tio->c_iflag |= (INPCK | ISTRIP);
+		/* fall through */
+	case (1 | 2):			/* no parity bit */
+		tio->c_cflag &= ~CSIZE;
+		tio->c_cflag |= CS7;
+		break;
+	}
+
+	/* Set line attributes */
+	(void)tcsetattr(fd, TCSANOW, tio);
+}
 
 /*
  * Called at timeout.
@@ -86,6 +261,11 @@ static void alrm_handler(int sig __attribute__((unused)))
 	alarm_rised++;
 }
 
+static void chld_handler(int sig __attribute__((unused)))
+{
+	sigchild++;
+}
+
 static void mask_signal(int signal, void (*handler)(int),
 		struct sigaction *origaction)
 {
@@ -95,8 +275,7 @@ static void mask_signal(int signal, void (*handler)(int),
 	sigemptyset(&newaction.sa_mask);
 	newaction.sa_flags = 0;
 
-	sigaction(signal, NULL, origaction);
-	sigaction(signal, &newaction, NULL);
+	sigaction(signal, &newaction, origaction);
 }
 
 static void unmask_signal(int signal, struct sigaction *sa)
@@ -296,51 +475,202 @@ static struct passwd *getrootpwent(int try_manually)
 }
 
 /*
+ * Ask by prompt for the password.
+ */
+static void doprompt(const char *crypted, struct console *con)
+{
+	struct termios tty;
+
+	if (con->flags & CON_SERIAL) {
+		tty = con->tio;
+		/*
+		 * For prompting: map NL in output to CR-NL
+		 * otherwise we may see stairs in the output.
+		 */
+		tty.c_oflag |= (ONLCR | OPOST);
+		(void) tcsetattr(con->fd, TCSADRAIN, &tty);
+	}
+	if (con->file == (FILE*)0) {
+		if  ((con->file = fdopen(con->fd, "r+")) == (FILE*)0)
+			goto err;
+	}
+#if defined(USE_ONELINE)
+	if (crypted[0])
+		fprintf(con->file, _("Give root password for login: "));
+	else
+		fprintf(con->file, _("Press enter for login: "));
+#else
+	if (crypted[0])
+		fprintf(con->file, _("Give root password for maintenance\n"));
+	else
+		fprintf(con->file, _("Press enter for maintenance"));
+	fprintf(con->file, _("(or type Control-D to continue): "));
+#endif
+	fflush(con->file);
+err:
+	if (con->flags & CON_SERIAL)
+		(void) tcsetattr(con->fd, TCSADRAIN, &con->tio);
+}
+
+/*
+ * Make sure to have an own session and controlling terminal
+ */
+static void setup(struct console *con)
+{
+	pid_t pid, pgrp, ppgrp, ttypgrp;
+	int fd;
+
+	if (con->flags & CON_NOTTY)
+		return;
+	fd = con->fd;
+
+	/*
+	 * Only go through this trouble if the new
+	 * tty doesn't fall in this process group.
+	 */
+	pid = getpid();
+	pgrp = getpgid(0);
+	ppgrp = getpgid(getppid());
+	ttypgrp = tcgetpgrp(fd);
+
+	if (pgrp != ttypgrp && ppgrp != ttypgrp) {
+		if (pid != getsid(0)) {
+			if (pid == getpgid(0))
+				setpgid(0, getpgid(getppid()));
+			setsid();
+		}
+
+		mask_signal(SIGHUP, SIG_IGN, &saved_sighup);
+		if (ttypgrp > 0)
+			ioctl(STDIN_FILENO, TIOCNOTTY, (char *)1);
+		unmask_signal(SIGHUP, &saved_sighup);
+		if (fd > STDIN_FILENO)  close(STDIN_FILENO);
+		if (fd > STDOUT_FILENO) close(STDOUT_FILENO);
+		if (fd > STDERR_FILENO) close(STDERR_FILENO);
+
+		ioctl(fd, TIOCSCTTY, (char *)1);
+		tcsetpgrp(fd, ppgrp);
+	}
+	dup2(fd, STDIN_FILENO);
+	dup2(fd, STDOUT_FILENO);
+	dup2(fd, STDERR_FILENO);
+	con->fd = STDIN_FILENO;
+
+	for (fd = STDERR_FILENO+1; fd < 32; fd++) {
+		if (openfd & (1<<fd)) {
+			close(fd);
+			openfd &= ~(1<<fd);
+		}
+	}
+}
+
+/*
  * Ask for the password. Note that there is no default timeout as we normally
  * skip this during boot.
  */
-static char *getpasswd(char *crypted)
+static char *getpasswd(struct console *con)
 {
 	struct sigaction sa;
-	struct termios old, tty;
-	static char pass[128];
+	struct termios tty;
+	static char pass[128], *ptr;
+	struct chardata *cp;
 	char *ret = pass;
-	size_t i;
+	unsigned char tc;
+	char c, ascval;
+	int eightbit;
+	int fd;
 
-	if (crypted[0])
-		printf(_("Give root password for maintenance\n"));
-	else
-		printf(_("Press enter for maintenance"));
-	printf(_("(or type Control-D to continue): "));
-	fflush(stdout);
+	if (con->flags & CON_NOTTY)
+		goto out;
+	fd = con->fd;
+	cp = &con->cp;
+	tty = con->tio;
 
-	tcgetattr(0, &old);
-	tcgetattr(0, &tty);
 	tty.c_iflag &= ~(IUCLC|IXON|IXOFF|IXANY);
-	tty.c_lflag &= ~(ECHO|ECHOE|ECHOK|ECHONL|TOSTOP);
-	tcsetattr(0, TCSANOW, &tty);
-
-	pass[sizeof(pass) - 1] = 0;
+	tty.c_lflag &= ~(ECHO|ECHOE|ECHOK|ECHONL|TOSTOP|ISIG);
+	tc = (tcsetattr(fd, TCSAFLUSH, &tty) == 0);
 
 	sa.sa_handler = alrm_handler;
 	sa.sa_flags = 0;
 	sigaction(SIGALRM, &sa, NULL);
-	if (timeout)
-		alarm(timeout);
+	if (timeout) alarm(timeout);
 
-	if (read(0, pass, sizeof(pass) - 1) <= 0)
-		ret = NULL;
-	else {
-		for (i = 0; i < sizeof(pass) && pass[i]; i++)
-			if (pass[i] == '\r' || pass[i] == '\n') {
-				pass[i] = 0;
+	ptr = &pass[0];
+	cp->eol = *ptr = '\0';
+
+	eightbit = ((con->flags & CON_SERIAL) == 0 || (tty.c_cflag & (PARODD|PARENB)) == 0);
+	while (cp->eol == '\0') {
+		if (read(fd, &c, 1) < 1) {
+			if (errno == EINTR || errno == EAGAIN) {
+				usleep(1000);
+				continue;
+			}
+			ret = (char*)0;
+			switch (errno) {
+			case 0:
+			case EIO:
+			case ESRCH:
+			case EINVAL:
+			case ENOENT:
 				break;
+			default:
+				fprintf(stderr, "sulogin: read(%s): %m\n\r", con->tty);
+				break;
+			}
+			goto quit;
+		}
+
+		if (eightbit)
+			ascval = c;
+		else if (c != (ascval = (c & 0177))) {
+			uint32_t bits, mask;
+			for (bits = 1, mask = 1; mask & 0177; mask <<= 1) {
+				if (mask & ascval)
+					bits++;
+			}
+			cp->parity |= ((bits & 1) ? 1 : 2);
+		}
+
+		switch (ascval) {
+		case 0:
+			*ptr = '\0';
+			goto quit; 
+		case CR:
+		case NL:
+			*ptr = '\0';
+			cp->eol = ascval;
+			break;
+		case BS:
+		case CERASE:
+			cp->erase = ascval;
+			if (ptr > &pass[0])
+				ptr--;
+			break;
+		case CKILL:
+			cp->kill = ascval;
+			while (ptr > &pass[0])
+				ptr--;
+			break;
+		case CEOF:
+			goto quit;		
+		default:
+			if ((size_t)(ptr - &pass[0]) >= (sizeof(pass) -1 )) {
+				 fprintf(stderr, "sulogin: input overrun at %s\n\r", con->tty);
+				 ret = (char*)0;
+				 goto quit;
 			}
+			*ptr++ = ascval;
+			break;
+		}
 	}
+quit:
 	alarm(0);
-	tcsetattr(0, TCSANOW, &old);
-	printf("\n");
-
+	if (tc)
+		(void)tcsetattr(fd, TCSAFLUSH, &con->tio);
+	if (ret && *ret != '\0')
+		tcfinal(con);
+	printf("\r\n");
+out:
 	return ret;
 }
 
@@ -385,9 +715,10 @@ static void sushell(struct passwd *pwd)
 	/*
 	 * Set some important environment variables.
 	 */
-	if (getcwd(home, sizeof(home)) != NULL)
-		setenv("HOME", home, 1);
+	if (getcwd(home, sizeof(home)) == NULL)
+		strcpy(home, "/");
 
+	setenv("HOME", home, 1);
 	setenv("LOGNAME", "root", 1);
 	setenv("USER", "root", 1);
 	if (!profile)
@@ -400,6 +731,7 @@ static void sushell(struct passwd *pwd)
 	unmask_signal(SIGINT, &saved_sigint);
 	unmask_signal(SIGTSTP, &saved_sigtstp);
 	unmask_signal(SIGQUIT, &saved_sigquit);
+	mask_signal(SIGHUP, SIG_DFL, NULL);
 
 #ifdef HAVE_LIBSELINUX
 	if (is_selinux_enabled() > 0) {
@@ -425,36 +757,6 @@ static void sushell(struct passwd *pwd)
 	warn(_("%s: exec failed"), "/bin/sh");
 }
 
-static void fixtty(void)
-{
-	struct termios tp;
-	int x = 0, fl = 0;
-
-	/* Skip serial console */
-	if (ioctl(STDIN_FILENO, TIOCMGET, (char *) &x) == 0)
-		return;
-
-#if defined(IUTF8) && defined(KDGKBMODE)
-	/* Detect mode of current keyboard setup, e.g. for UTF-8 */
-	if (ioctl(STDIN_FILENO, KDGKBMODE, &x) == 0 && x == K_UNICODE) {
-		setlocale(LC_CTYPE, "C.UTF-8");
-		fl |= UL_TTY_UTF8;
-	}
-#else
-	setlocale(LC_CTYPE, "POSIX");
-#endif
-	memset(&tp, 0, sizeof(struct termios));
-	if (tcgetattr(STDIN_FILENO, &tp) < 0) {
-		warn(_("tcgetattr failed"));
-		return;
-	}
-
-	reset_virtual_console(&tp, fl);
-
-	if (tcsetattr(STDIN_FILENO, TCSADRAIN, &tp))
-		warn(_("tcsetattr failed"));
-}
-
 #ifdef USE_EMERGENCY_DEV
 /*
  * Make C library standard calls such like ttyname(3) work
@@ -518,13 +820,14 @@ static void usage(FILE *out)
 
 int main(int argc, char **argv)
 {
+	struct list_head consoles = {&consoles, &consoles}, *ptr;
+	struct console *con;
 	char *tty = NULL;
-	char *p;
 	struct passwd *pwd;
-	int c, fd = -1;
+	int c, status = 0;
+	int reconnect = 0;
 	int opt_e = 0;
-	pid_t pid, pgrp, ppgrp, ttypgrp;
-	struct sigaction saved_sighup;
+	pid_t pid;
 
 	static const struct option longopts[] = {
 		{ "login-shell",  0, 0, 'p' },
@@ -535,10 +838,18 @@ int main(int argc, char **argv)
 		{ NULL,           0, 0, 0 }
 	};
 
+	/*
+	 * If we are init we need to set up a own session.
+	 */
+	if ((pid = getpid()) == 1) {
+		setsid();
+		(void)ioctl(STDIN_FILENO, TIOCSCTTY, (char *)1);
+	}
+
 	setlocale(LC_ALL, "");
 	bindtextdomain(PACKAGE, LOCALEDIR);
 	textdomain(PACKAGE);
-	atexit(close_stdout);
+	atexit(close_stdout); /* XXX */
 
 	/*
 	 * See if we have a timeout flag.
@@ -570,78 +881,45 @@ int main(int argc, char **argv)
 	if (geteuid() != 0)
 		errx(EXIT_FAILURE, _("only root can run this program."));
 
-	/*
-	 * See if we need to open an other tty device.
-	 */
 	mask_signal(SIGQUIT, SIG_IGN, &saved_sigquit);
 	mask_signal(SIGTSTP, SIG_IGN, &saved_sigtstp);
 	mask_signal(SIGINT,  SIG_IGN, &saved_sigint);
+	mask_signal(SIGHUP,  SIG_IGN, &saved_sighup);
+
+	/*
+	 * See if we need to open an other tty device.
+	 */
 	if (optind < argc)
 		tty = argv[optind];
 
-	if (tty || (tty = getenv("CONSOLE"))) {
-
-		if ((fd = open(tty, O_RDWR)) < 0) {
-			warn(_("cannot open %s"), tty);
-			fd = dup(STDIN_FILENO);
-		}
-
-		if (fd < 0) {
-			warn(_("cannot duplicate stdin file descriptor"));
-		} else if (!isatty(fd)) {
-			warn(_("%s: not a tty"), tty);
-			close(fd);
-		} else {
+	if (!tty || *tty == '\0')
+		tty = getenv("CONSOLE");
 
-			/*
-			 * Only go through this trouble if the new tty doesn't
-			 * fall in this process group.
-			 */
-			pid = getpid();
-			pgrp = getpgid(0);
-			ppgrp = getpgid(getppid());
-			ttypgrp = tcgetpgrp(fd);
-
-			if (pgrp != ttypgrp && ppgrp != ttypgrp) {
-				if (pid != getsid(0)) {
-					if (pid == getpgid(0))
-						setpgid(0, getpgid(getppid()));
-					setsid();
-				}
+	/*
+	 * Detect possible consoles, use stdin as fallback.
+	 * If an optional tty is given, reconnect it to stdin.
+	 */
+	reconnect = detect_consoles(tty, STDIN_FILENO, &consoles);
 
-				sigaction(SIGHUP, NULL, &saved_sighup);
-				if (ttypgrp > 0)
-					ioctl(0, TIOCNOTTY, (char *)1);
-				sigaction(SIGHUP, &saved_sighup, NULL);
-				close(STDIN_FILENO);
-				close(STDOUT_FILENO);
-				close(STDERR_FILENO);
-				if (fd > 2)
-					close(fd);
-				if ((fd = open(tty, O_RDWR|O_NOCTTY)) < 0)
-					warn(_("cannot open %s"), tty);
-				else {
-					ioctl(STDIN_FILENO, TIOCSCTTY, (char *)1);
-					tcsetpgrp(fd, ppgrp);
-					dup2(fd, STDIN_FILENO);
-					dup2(fd, STDOUT_FILENO);
-					dup2(fd, STDERR_FILENO);
-
-					if (fd > STDERR_FILENO)
-						close(fd);
-				}
-			} else
-				if (fd > STDERR_FILENO)
-					close(fd);
-		}
-	} else if (getpid() == 1) {
-		/* We are init. We hence need to set a session anyway */
-		setsid();
-		if (ioctl(STDIN_FILENO, TIOCSCTTY, (char *)1))
-			warn(_("TIOCSCTTY: ioctl failed"));
+	/*
+	 * If previous stdin was not the speified tty and therefore reconnected
+	 * to the specified tty also reconnect stdout and stderr.
+	 */
+	if (reconnect) {
+		if (isatty(STDOUT_FILENO) == 0)
+			dup2(STDOUT_FILENO, STDIN_FILENO);
+		if (isatty(STDERR_FILENO) == 0)
+			dup2(STDOUT_FILENO, STDERR_FILENO);
 	}
 
-	fixtty();
+	/*
+	 * Should not happen
+	 */
+	if (list_empty(&consoles)) {
+		if (!errno)
+			errno = ENOENT;
+		errx(EXIT_FAILURE, _("cannot open console: %m\n"));
+	}
 
 	/*
 	 * Get the root password.
@@ -652,32 +930,121 @@ int main(int argc, char **argv)
 	}
 
 	/*
-	 * Ask for the password.
+	 * Ask for the password on the consoles.
 	 */
-	while (pwd) {
-		int failed = 0;
-		if ((p = getpasswd(pwd->pw_passwd)) == NULL)
+	list_for_each(ptr, &consoles) {
+		con = list_entry(ptr, struct console, entry);
+		if (con->id >= CONMAX)
 			break;
-		if (pwd->pw_passwd[0] == 0 ||
-		    strcmp(crypt(p, pwd->pw_passwd), pwd->pw_passwd) == 0) {
-			sushell(pwd);
-			failed++;
+		if (con->fd >= 0) {
+			openfd |= (1<<con->fd);
+			tcinit(con);
+			continue;
 		}
-		mask_signal(SIGQUIT, SIG_IGN, &saved_sigquit);
-		mask_signal(SIGTSTP, SIG_IGN, &saved_sigtstp);
-		mask_signal(SIGINT,  SIG_IGN, &saved_sigint);
-		if (failed) {
-		    fprintf(stderr, _("Can not execute su shell\n\n"));
-		    break;
-		} else
-		    fprintf(stderr, _("Login incorrect\n\n"));
+		if ((con->fd = open(con->tty, O_RDWR | O_NOCTTY | O_NONBLOCK)) < 0)
+			continue;
+		openfd |= (1<<con->fd);
+		tcinit(con);
 	}
+	ptr = (&consoles)->next;
+	usemask = (uint32_t*)mmap(NULL, sizeof(uint32_t), PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_SHARED, -1, 0);
 
-	if (alarm_rised)
-		fprintf(stderr, _("Timed out\n\n"));
+	if (ptr->next == &consoles) {
+		con = list_entry(ptr, struct console, entry);
+		goto nofork;
+	}
 
-	/*
-	 * User pressed Control-D.
-	 */
+	mask_signal(SIGCHLD, chld_handler, &saved_sigchld);
+	do {
+		con = list_entry(ptr, struct console, entry);
+		if (con->id >= CONMAX)
+			break;
+
+		switch ((con->pid = fork())) {
+		case 0:
+			mask_signal(SIGCHLD, SIG_DFL, NULL);
+			/* fall through */
+		nofork:
+			setup(con);
+			while (1) {
+				const char *passwd = pwd->pw_passwd;
+				const char *answer;
+				int failed = 0, doshell = 0;
+
+				doprompt(passwd, con);
+				if ((answer = getpasswd(con)) == NULL)
+					break;
+
+				if (passwd[0] == '\0')
+					doshell++;
+				else {
+					const char *cryptbuf;
+					cryptbuf = crypt(answer, passwd);
+					if (cryptbuf == NULL)
+						warnx(_("crypt failed: %m\n"));
+					else if (strcmp(cryptbuf, pwd->pw_passwd) == 0)
+						doshell++;
+				}
+
+				if (doshell) {
+					*usemask |= (1<<con->id);
+					sushell(pwd);
+					*usemask &= ~(1<<con->id);
+					failed++;
+				}
+
+				mask_signal(SIGQUIT, SIG_IGN, &saved_sigquit);
+				mask_signal(SIGTSTP, SIG_IGN, &saved_sigtstp);
+				mask_signal(SIGINT,  SIG_IGN, &saved_sigint);
+
+				if (failed) {
+					fprintf(stderr, _("Can not execute su shell\n\n"));
+					break;
+				}
+				fprintf(stderr, _("Login incorrect\n\n"));
+			}
+			if (alarm_rised) {
+				tcfinal(con);
+				warnx(_("Timed out\n\n"));
+			}
+			/*
+			 * User pressed Control-D.
+			 */
+			exit(0);
+		case -1:
+			warnx(_("Can not fork: %m\n"));
+			/* fall through */
+		default:
+			break;
+		}
+
+		ptr = ptr->next;
+
+	} while (ptr != &consoles);
+
+	while ((pid = wait(&status))) {
+		if (errno == ECHILD)
+			break;
+		if (pid < 0)
+			continue;
+		list_for_each(ptr, &consoles) {
+			con = list_entry(ptr, struct console, entry);
+			if (con->pid == pid) {
+				*usemask &= ~(1<<con->id);
+				continue;
+			}
+			if (kill(con->pid, 0) < 0) {
+				*usemask &= ~(1<<con->id);
+				continue;
+			}
+			if (*usemask & (1<<con->id))
+				continue;
+			kill(con->pid, SIGHUP);
+			usleep(5000);
+			kill(con->pid, SIGKILL);
+		}
+	}
+
+	mask_signal(SIGCHLD, SIG_DFL, NULL);
 	return EXIT_SUCCESS;
 }
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* Re: [PATCH 5/5] sulogin: add multi console feature from SysVinit sulogin
  2012-12-07  8:00 ` [PATCH 5/5] sulogin: add multi console feature from SysVinit sulogin Werner Fink
@ 2012-12-07 10:27   ` Dr. Werner Fink
  0 siblings, 0 replies; 20+ messages in thread
From: Dr. Werner Fink @ 2012-12-07 10:27 UTC (permalink / raw)
  To: util-linux; +Cc: Karel Zak

[-- Attachment #1: Type: text/plain, Size: 834 bytes --]

On Fri, Dec 07, 2012 at 09:00:58AM +0100, Werner Fink wrote:
> Now after adding Conflicts=rescue.service to getty@.service and
> serial-getty@.service and Conflicts=getty.target to rescue.target
> all works with `systemctl rescue'.  Even adding init=/sbin/sulogin
> to the kernels command line by using the `e' key in grub2 boot
> menu works flawless.
> 
> Signed-off-by: Werner Fink <werner@suse.de>


Hi, just a picture from the virtual system, the terminal above is
the serial line within an xterm running socat and screen, the window
below is the VirtualBox its self. I've done a login first on the
serial line as this is had shown the grub2 menue.  After this a
login on tty1 haf followed.


   Werner

-- 
  "Having a smoking section in a restaurant is like having
          a peeing section in a swimming pool." -- Edward Burr

[-- Attachment #2: sulogin.png --]
[-- Type: image/png, Size: 34397 bytes --]

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH 4/5] sulogin: mount temporary /dev and /proc if not found
  2012-12-07  8:00 ` [PATCH 4/5] sulogin: mount temporary /dev and /proc if not found Werner Fink
@ 2012-12-07 14:17   ` Dave Reisner
  2012-12-07 15:49     ` [util-linux] " Dr. Werner Fink
  2012-12-18 15:17   ` Karel Zak
  1 sibling, 1 reply; 20+ messages in thread
From: Dave Reisner @ 2012-12-07 14:17 UTC (permalink / raw)
  To: Werner Fink; +Cc: util-linux, Karel Zak

On Fri, Dec 07, 2012 at 09:00:57AM +0100, Werner Fink wrote:
> This is very usefull if initrd can not loaded that is no /dev and no
> /proc is found.  Also if the /etc/shadow and /etc/passwd is copied into
> the initrd the sulogin can be used in initrd even before /dev and/or /proc
> are mounted.
> 
> Signed-off-by: Werner Fink <werner@suse.de>
> ---
>  configure.ac          |   10 ++++++++
>  login-utils/sulogin.c |   57 ++++++++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 67 insertions(+)
> 
> diff --git configure.ac configure.ac
> index 3be3715..631002f 100644
> --- configure.ac
> +++ configure.ac
> @@ -1296,6 +1296,16 @@ if test "x$enable_use_tty_group" = xyes; then
>    AC_DEFINE(USE_TTY_GROUP, 1, [Should wall and write be installed setgid tty?])
>  fi
>  
> +AC_ARG_ENABLE([use-emergency-dev],
> +  AS_HELP_STRING([--disable-use-emergency-dev], [do not use emergency mount of /dev and /proc for sulogin]),
> +  [], enable_use_emergency_dev=yes
> +)
> +AM_CONDITIONAL(USE_EMERGENCY_DEV, test "x$enable_use_emergency_dev" = xyes)
> +
> +if test "x$enable_use_emergency_dev" = xyes; then
> +  AC_DEFINE(USE_EMERGENCY_DEV, 1, [Should sulogin use a emergency mount of /dev and /proc?])
> +fi
> +
>  AC_ARG_ENABLE([makeinstall-chown],
>    AS_HELP_STRING([--disable-makeinstall-chown], [do not do chown-like operations during "make install"]),
>    [], enable_makeinstall_chown=yes
> diff --git login-utils/sulogin.c login-utils/sulogin.c
> index dbcc855..0b0d21c 100644
> --- login-utils/sulogin.c
> +++ login-utils/sulogin.c
> @@ -47,6 +47,20 @@
>  # include <selinux/get_context_list.h>
>  #endif
>  
> +#ifdef USE_EMERGENCY_DEV
> +# include <sys/statfs.h>
> +# include <sys/mount.h>
> +# include <linux/fs.h>
> +# include <linux/magic.h>
> +# include <linux/major.h>
> +# ifndef TMPFS_MAGIC
> +#  define TMPFS_MAGIC	0x01021994
> +# endif
> +# ifndef MNT_DETACH
> +#  define MNT_DETACH	2
> +# endif
> +#endif
> +
>  #include "c.h"
>  #include "closestream.h"
>  #include "nls.h"
> @@ -441,6 +455,49 @@ static void fixtty(void)
>  		warn(_("tcsetattr failed"));
>  }
>  
> +#ifdef USE_EMERGENCY_DEV
> +/*
> + * Make C library standard calls such like ttyname(3) work
> + * even if the system does not show any of the standard
> + * directories.
> + */
> +
> +static uint32_t mounts;
> +# define MNT_PROCFS	0x0001
> +# define MNT_DEVTMPFS	0x0002
> +
> +static __attribute__((__noinline__)) void putmounts(void)
> +{
> +	if (mounts & MNT_DEVTMPFS)
> +		umount2("/dev", MNT_DETACH);
> +	if (mounts & MNT_PROCFS)
> +		umount2("/proc", MNT_DETACH);
> +}
> +
> +# define dovoid(f)	if ((f)){}
> +static __attribute__((__constructor__)) void getmounts(void)
> +{
> +	struct statfs st;
> +	if (statfs("/proc", &st) == 0 && st.f_type != PROC_SUPER_MAGIC) {

Why not use the standard mountpoint check -- compare the devno with / ?

> +		if (mount("proc", "/proc", "proc", MS_RELATIME, NULL) == 0)
> +			mounts |= MNT_PROCFS;
> +	}
> +	if (statfs("/dev", &st) == 0 && st.f_type != TMPFS_MAGIC) {
> +		if (mount("devtmpfs", "/dev", "devtmpfs", MS_RELATIME, "mode=0755,nr_inodes=0") == 0) {
> +			mounts |= MNT_DEVTMPFS;

Isn't all the work below here redundant? devtmpfs provides these
things.

> +			(void)mknod("/dev/console", S_IFCHR|S_IRUSR|S_IWUSR, makedev(TTYAUX_MAJOR, 1));
> +			if (symlink("/proc/self/fd", "/dev/fd") == 0) {
> +				dovoid(symlink("fd/0", "/dev/stdin"));
> +				dovoid(symlink("fd/1", "/dev/stdout"));
> +				dovoid(symlink("fd/2", "/dev/stderr"));
> +			}
> +		}
> +	}
> +	if (mounts) atexit(putmounts);
> +}
> +# undef dovoid
> +#endif
> +
>  static void usage(FILE *out)
>  {
>  	fputs(USAGE_HEADER, out);
> -- 
> 1.7.10.4
> 
> --
> To unsubscribe from this list: send the line "unsubscribe util-linux" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [util-linux] [PATCH 4/5] sulogin: mount temporary /dev and /proc if not found
  2012-12-07 14:17   ` Dave Reisner
@ 2012-12-07 15:49     ` Dr. Werner Fink
  2012-12-07 17:01       ` Dave Reisner
  0 siblings, 1 reply; 20+ messages in thread
From: Dr. Werner Fink @ 2012-12-07 15:49 UTC (permalink / raw)
  To: Werner Fink, util-linux, Karel Zak

On Fri, Dec 07, 2012 at 09:17:09AM -0500, Dave Reisner wrote:
> On Fri, Dec 07, 2012 at 09:00:57AM +0100, Werner Fink wrote:
> > +# define dovoid(f)	if ((f)){}
> > +static __attribute__((__constructor__)) void getmounts(void)
> > +{
> > +	struct statfs st;
> > +	if (statfs("/proc", &st) == 0 && st.f_type != PROC_SUPER_MAGIC) {
> 
> Why not use the standard mountpoint check -- compare the devno with / ?
> 
> > +		if (mount("proc", "/proc", "proc", MS_RELATIME, NULL) == 0)
> > +			mounts |= MNT_PROCFS;
> > +	}
> > +	if (statfs("/dev", &st) == 0 && st.f_type != TMPFS_MAGIC) {
> > +		if (mount("devtmpfs", "/dev", "devtmpfs", MS_RELATIME, "mode=0755,nr_inodes=0") == 0) {
> > +			mounts |= MNT_DEVTMPFS;
> 
> Isn't all the work below here redundant? devtmpfs provides these
> things.
> 
> > +			(void)mknod("/dev/console", S_IFCHR|S_IRUSR|S_IWUSR, makedev(TTYAUX_MAJOR, 1));
> > +			if (symlink("/proc/self/fd", "/dev/fd") == 0) {
> > +				dovoid(symlink("fd/0", "/dev/stdin"));
> > +				dovoid(symlink("fd/1", "/dev/stdout"));
> > +				dovoid(symlink("fd/2", "/dev/stderr"));
> > +			}
> > +		}
> > +	}
> > +	if (mounts) atexit(putmounts);
> > +}
> > +# undef dovoid
> > +#endif
> > +
> >  static void usage(FILE *out)
> >  {
> >  	fputs(USAGE_HEADER, out);

We're talking about the very early boot stage, there is no udev nor anything else
and the I've choosen this as this had worked very well in initrd where it had crashed
before.  I do not say that there is no other way to do this but this way it works and
the links I've done had been missed.

If in initrd the sulogin will be called after mounting /proc and /dev and running
udev rules or enabling the links in initrd then the code does only check for existence
of /proc and /dev.

  Werner

-- 
  "Having a smoking section in a restaurant is like having
          a peeing section in a swimming pool." -- Edward Burr

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [util-linux] [PATCH 4/5] sulogin: mount temporary /dev and /proc if not found
  2012-12-07 15:49     ` [util-linux] " Dr. Werner Fink
@ 2012-12-07 17:01       ` Dave Reisner
  2012-12-07 17:25         ` Dr. Werner Fink
  2012-12-10 12:27         ` Werner Fink
  0 siblings, 2 replies; 20+ messages in thread
From: Dave Reisner @ 2012-12-07 17:01 UTC (permalink / raw)
  To: Werner Fink, util-linux, Karel Zak

On Fri, Dec 07, 2012 at 04:49:17PM +0100, Dr. Werner Fink wrote:
> On Fri, Dec 07, 2012 at 09:17:09AM -0500, Dave Reisner wrote:
> > On Fri, Dec 07, 2012 at 09:00:57AM +0100, Werner Fink wrote:
> > > +# define dovoid(f)	if ((f)){}
> > > +static __attribute__((__constructor__)) void getmounts(void)
> > > +{
> > > +	struct statfs st;
> > > +	if (statfs("/proc", &st) == 0 && st.f_type != PROC_SUPER_MAGIC) {
> > 
> > Why not use the standard mountpoint check -- compare the devno with / ?
> > 
> > > +		if (mount("proc", "/proc", "proc", MS_RELATIME, NULL) == 0)
> > > +			mounts |= MNT_PROCFS;
> > > +	}
> > > +	if (statfs("/dev", &st) == 0 && st.f_type != TMPFS_MAGIC) {
> > > +		if (mount("devtmpfs", "/dev", "devtmpfs", MS_RELATIME, "mode=0755,nr_inodes=0") == 0) {
> > > +			mounts |= MNT_DEVTMPFS;
> > 
> > Isn't all the work below here redundant? devtmpfs provides these
> > things.
> > 
> > > +			(void)mknod("/dev/console", S_IFCHR|S_IRUSR|S_IWUSR, makedev(TTYAUX_MAJOR, 1));
> > > +			if (symlink("/proc/self/fd", "/dev/fd") == 0) {
> > > +				dovoid(symlink("fd/0", "/dev/stdin"));
> > > +				dovoid(symlink("fd/1", "/dev/stdout"));
> > > +				dovoid(symlink("fd/2", "/dev/stderr"));
> > > +			}
> > > +		}
> > > +	}
> > > +	if (mounts) atexit(putmounts);
> > > +}
> > > +# undef dovoid
> > > +#endif
> > > +
> > >  static void usage(FILE *out)
> > >  {
> > >  	fputs(USAGE_HEADER, out);
> 
> We're talking about the very early boot stage, there is no udev nor anything else
> and the I've choosen this as this had worked very well in initrd where it had crashed
> before.  I do not say that there is no other way to do this but this way it works and
> the links I've done had been missed.

Ok, I didn't realize udev still was responsible for these links these
days, but perusing the code shows otherwise. Could you explain why
sulogin is wanted in the initramfs? Seems like an odd use case to me.

> If in initrd the sulogin will be called after mounting /proc and /dev and running
> udev rules or enabling the links in initrd then the code does only check for existence
> of /proc and /dev.

If you're in the initramfs, rootfs is tmpfs. Won't your statfs check
return a buffer which has f_type == TMPFS_MAGIC even if /dev is not
mounted?

>   Werner
> 
> -- 
>   "Having a smoking section in a restaurant is like having
>           a peeing section in a swimming pool." -- Edward Burr
> --
> To unsubscribe from this list: send the line "unsubscribe util-linux" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [util-linux] [PATCH 4/5] sulogin: mount temporary /dev and /proc if not found
  2012-12-07 17:01       ` Dave Reisner
@ 2012-12-07 17:25         ` Dr. Werner Fink
  2012-12-10 12:27         ` Werner Fink
  1 sibling, 0 replies; 20+ messages in thread
From: Dr. Werner Fink @ 2012-12-07 17:25 UTC (permalink / raw)
  To: util-linux

On Fri, Dec 07, 2012 at 12:01:18PM -0500, Dave Reisner wrote:
> 
> Ok, I didn't realize udev still was responsible for these links these
> days, but perusing the code shows otherwise. Could you explain why
> sulogin is wanted in the initramfs? Seems like an odd use case to me.
> 
> > If in initrd the sulogin will be called after mounting /proc and /dev and running
> > udev rules or enabling the links in initrd then the code does only check for existence
> > of /proc and /dev.
> 
> If you're in the initramfs, rootfs is tmpfs. Won't your statfs check
> return a buffer which has f_type == TMPFS_MAGIC even if /dev is not
> mounted?

Hmmm ... maybe a check for RAMFS_MAGIC should be done before to
distinguish between TMPFS_MAGIC or RAMFS_MAGIC for the initrd.
Or the mounted /proc could be used to check for /dev

    Werner

-- 
  "Having a smoking section in a restaurant is like having
          a peeing section in a swimming pool." -- Edward Burr

^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH 4/5] sulogin: mount temporary /dev and /proc if not found
  2012-12-07 17:01       ` Dave Reisner
  2012-12-07 17:25         ` Dr. Werner Fink
@ 2012-12-10 12:27         ` Werner Fink
  2012-12-10 12:27           ` [PATCH 5/5] sulogin: add multi console feature from SysVinit sulogin Werner Fink
  2012-12-18 15:23           ` [PATCH 4/5] sulogin: mount temporary /dev and /proc if not found Karel Zak
  1 sibling, 2 replies; 20+ messages in thread
From: Werner Fink @ 2012-12-10 12:27 UTC (permalink / raw)
  To: util-linux; +Cc: Karel Zak, Werner Fink

On Fri, Dec 07, 2012 at 12:01:18PM -0500, Dave Reisner wrote:
>
> If you're in the initramfs, rootfs is tmpfs. Won't your statfs check
> return a buffer which has f_type == TMPFS_MAGIC even if /dev is not
> mounted?

Indeed it could be a poroblem, therefore I've moved the stuff to lib/conosle.c
and switch over to device comparission as you suggested.  Also if /dev has
been mounted by this code I'll also create missing nodes during scan of e.g.
/proc/consoles

On Fri, Dec 07, 2012 at 09:00:57AM +0100, Werner Fink wrote:
> 
> This is very usefull if initrd can not loaded that is no /dev and no
> /proc is found.  Also if the /etc/shadow and /etc/passwd is copied into
> the initrd the sulogin can be used in initrd even before /dev and/or /proc
> are mounted.


Signed-off-by: Werner Fink <werner@suse.de>
---
 configure.ac   |   10 +++++++++
 lib/consoles.c |   66 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 76 insertions(+)

diff --git configure.ac configure.ac
index 3be3715..631002f 100644
--- configure.ac
+++ configure.ac
@@ -1296,6 +1296,16 @@ if test "x$enable_use_tty_group" = xyes; then
   AC_DEFINE(USE_TTY_GROUP, 1, [Should wall and write be installed setgid tty?])
 fi
 
+AC_ARG_ENABLE([use-emergency-dev],
+  AS_HELP_STRING([--disable-use-emergency-dev], [do not use emergency mount of /dev and /proc for sulogin]),
+  [], enable_use_emergency_dev=yes
+)
+AM_CONDITIONAL(USE_EMERGENCY_DEV, test "x$enable_use_emergency_dev" = xyes)
+
+if test "x$enable_use_emergency_dev" = xyes; then
+  AC_DEFINE(USE_EMERGENCY_DEV, 1, [Should sulogin use a emergency mount of /dev and /proc?])
+fi
+
 AC_ARG_ENABLE([makeinstall-chown],
   AS_HELP_STRING([--disable-makeinstall-chown], [do not do chown-like operations during "make install"]),
   [], enable_makeinstall_chown=yes
diff --git lib/consoles.c lib/consoles.c
index 38c8208..9f0617a 100644
--- lib/consoles.c
+++ lib/consoles.c
@@ -39,6 +39,16 @@
 #include <dirent.h>
 #include <unistd.h>
 
+#ifdef USE_EMERGENCY_DEV
+# include <sys/mount.h>
+# include <linux/fs.h>
+# include <linux/magic.h>
+# include <linux/major.h>
+# ifndef MNT_DETACH
+#  define MNT_DETACH   2
+# endif
+#endif
+
 #include "c.h"
 #include "canonicalize.h"
 #include "consoles.h"
@@ -77,6 +87,57 @@ dbgprint(const char *mesg, ...)
 	fputc('\n', stderr);
 }
 
+#ifdef USE_EMERGENCY_DEV
+/*
+ * Make C library standard calls such like ttyname(3) work
+ * even if the system does not show any of the standard
+ * directories.
+ */
+
+static uint32_t mounts;
+# define MNT_PROCFS    0x0001
+# define MNT_DEVTMPFS  0x0002
+
+static __attribute__((__destructor__)) void putmounts(void)
+{
+	if (mounts & MNT_DEVTMPFS)
+		umount2("/dev", MNT_DETACH);
+	if (mounts & MNT_PROCFS)
+		umount2("/proc", MNT_DETACH);
+}
+
+# define dovoid(f)     if ((f)){}
+static __attribute__((__constructor__)) void getmounts(void)
+{
+	struct stat rt;
+	struct stat xt;
+	if (mounts) {
+		mounts = 0;
+		return;
+	}
+	if (stat("/", &rt) != 0) {
+		warn("can not get file status of root file system\n");
+		return;
+	}
+	if (stat("/proc", &xt) == 0 && rt.st_dev == xt.st_dev) {
+		if (mount("proc", "/proc", "proc", MS_RELATIME, NULL) == 0)
+			mounts |= MNT_PROCFS;
+	}
+	if (stat("/dev", &xt) == 0 && rt.st_dev == xt.st_dev) {
+		if (mount("devtmpfs", "/dev", "devtmpfs", MS_RELATIME, "mode=0755,nr_inodes=0") == 0) {
+			mounts |= MNT_DEVTMPFS;
+			(void)mknod("/dev/console", S_IFCHR|S_IRUSR|S_IWUSR, makedev(TTYAUX_MAJOR, 1));
+			if (symlink("/proc/self/fd", "/dev/fd") == 0) {
+				dovoid(symlink("fd/0", "/dev/stdin"));
+				dovoid(symlink("fd/1", "/dev/stdout"));
+				dovoid(symlink("fd/2", "/dev/stderr"));
+			}
+		}
+	}
+}
+# undef dovoid
+#endif
+
 /*
  * Read and allocate one line from file,
  * the caller has to free the result
@@ -182,6 +243,11 @@ char* scandev(DIR *dir, dev_t comparedev)
 			continue;
 		if ((size_t)snprintf(path, sizeof(path), "/dev/%s", dent->d_name) >= sizeof(path))
 			continue;
+#ifdef USE_EMERGENCY_DEV
+		if (mounts & MNT_DEVTMPFS)
+			(void)mknod(path, S_IFCHR|S_IRUSR|S_IWUSR, comparedev);
+#endif
+
 		name = canonicalize_path(path);
 		break;
 	}
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH 5/5] sulogin: add multi console feature from SysVinit sulogin
  2012-12-10 12:27         ` Werner Fink
@ 2012-12-10 12:27           ` Werner Fink
  2012-12-18 15:18             ` Karel Zak
  2012-12-18 15:23           ` [PATCH 4/5] sulogin: mount temporary /dev and /proc if not found Karel Zak
  1 sibling, 1 reply; 20+ messages in thread
From: Werner Fink @ 2012-12-10 12:27 UTC (permalink / raw)
  To: util-linux; +Cc: Karel Zak, Werner Fink

Now after adding Conflicts=rescue.service to getty@.service and
serial-getty@.service and Conflicts=getty.target to rescue.target
all works with `systemctl rescue'.  Even adding init=/sbin/sulogin
to the kernels command line by using the `e' key in grub2 boot
menu works flawless.

This version is without the emergency code as I've this moved to
lib/console.c where it belongs to.

Signed-off-by: Werner Fink <werner@suse.de>
---
 login-utils/sulogin.c |  665 ++++++++++++++++++++++++++++++++++++++-----------
 1 file changed, 516 insertions(+), 149 deletions(-)

diff --git login-utils/sulogin.c login-utils/sulogin.c
index 9fdbb69..b489535 100644
--- login-utils/sulogin.c
+++ login-utils/sulogin.c
@@ -24,8 +24,10 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
+#include <sys/mman.h>
 #include <sys/types.h>
 #include <sys/stat.h>
+#include <sys/wait.h>
 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
@@ -53,15 +55,188 @@
 #include "pathnames.h"
 #include "strutils.h"
 #include "ttyutils.h"
+#include "consoles.h"
+#define CONMAX		16
+
+#define BS		CTRL('h')
+#define NL		CTRL('j')
+#define CR		CTRL('m')
 
 static unsigned int timeout;
 static int profile;
+static volatile uint32_t openfd;		/* Remember higher file descriptors */
+static volatile uint32_t *usemask;
 
 struct sigaction saved_sigint;
 struct sigaction saved_sigtstp;
 struct sigaction saved_sigquit;
+struct sigaction saved_sighup;
+struct sigaction saved_sigchld;
 
 static volatile sig_atomic_t alarm_rised;
+static volatile sig_atomic_t sigchild;
+
+#ifndef IUCLC
+# define IUCLC		0
+#endif
+
+/*
+ * Fix the tty modes and set reasonable defaults.
+ */
+static void tcinit(struct console *con)
+{
+	int mode = 0, flags = 0;
+	struct termios *tio = &con->tio;
+	int fd = con->fd;
+
+	errno = 0;
+
+	if (tcgetattr(fd, tio) < 0) {
+		warn(_("tcgetattr failed"));
+		con->flags |= CON_NOTTY;
+		return;
+	}
+
+	/* Handle serial lines here */
+	if (ioctl(fd, TIOCMGET, (char *) &mode) == 0) {
+		speed_t ispeed, ospeed;
+		struct winsize ws;
+
+		/* this is a modem line */
+		con->flags |= CON_SERIAL;
+
+		/* Flush input and output queues on modem lines */
+		(void) tcflush(fd, TCIOFLUSH);
+
+		ispeed = cfgetispeed(tio);
+		ospeed = cfgetospeed(tio);
+
+		if (!ispeed) ispeed = TTYDEF_SPEED;
+		if (!ospeed) ospeed = TTYDEF_SPEED;
+
+		tio->c_iflag = tio->c_lflag = tio->c_oflag = 0;
+		tio->c_cflag = CREAD | CS8 | HUPCL | (tio->c_cflag & CLOCAL);
+
+		cfsetispeed(tio, ispeed);
+		cfsetospeed(tio, ospeed);
+
+		tio->c_line         = 0;
+		tio->c_cc[VTIME]    = 0;
+		tio->c_cc[VMIN]     = 1;
+
+		if (ioctl(fd, TIOCGWINSZ, &ws) == 0) {
+			int set = 0;
+			if (ws.ws_row == 0) {
+				ws.ws_row = 24;
+				set++;
+			}
+			if (ws.ws_col == 0) {
+				ws.ws_col = 80;
+				set++;
+			}
+			if (set)
+				(void)ioctl(fd, TIOCSWINSZ, &ws);
+		}
+
+		setlocale(LC_CTYPE, "POSIX");
+		goto setattr;
+	}
+#if defined(IUTF8) && defined(KDGKBMODE)
+	/* Detect mode of current keyboard setup, e.g. for UTF-8 */
+	if (ioctl(fd, KDGKBMODE, &mode) < 0)
+		mode = K_RAW;
+	switch(mode) {
+	case K_UNICODE:
+		setlocale(LC_CTYPE, "C.UTF-8");
+		flags |= UL_TTY_UTF8;
+		break;
+	case K_RAW:
+	case K_MEDIUMRAW:
+	case K_XLATE:
+	default:
+		setlocale(LC_CTYPE, "POSIX");
+		break;
+	}
+#else
+	setlocale(LC_CTYPE, "POSIX");
+#endif
+	reset_virtual_console(tio, flags);
+setattr:
+	if (tcsetattr(fd, TCSANOW, tio))
+		warn(_("tcsetattr failed"));
+
+	/* Enable blocking mode for read and write */
+	if ((flags = fcntl(fd, F_GETFL, 0)) != -1)
+		(void)fcntl(fd, F_SETFL, flags & ~O_NONBLOCK);
+}
+
+/*
+ * Finalize the tty modes on modem lines.
+ */
+static void tcfinal(struct console *con)
+{
+	struct termios *tio;
+	int fd;
+
+	if ((con->flags & CON_SERIAL) == 0) {
+		setenv("TERM", "linux", 1);
+		return;
+	}
+	if (con->flags & CON_NOTTY)
+		return;
+
+	setenv("TERM", "vt102", 1);
+	tio = &con->tio;
+	fd = con->fd;
+
+	tio->c_iflag |= (IXON | IXOFF);
+	tio->c_lflag |= (ICANON | ISIG | ECHO|ECHOE|ECHOK|ECHOKE);
+	tio->c_oflag |= OPOST;
+
+	tio->c_cc[VINTR]    = CINTR;
+	tio->c_cc[VQUIT]    = CQUIT;
+	tio->c_cc[VERASE]   = con->cp.erase;
+	tio->c_cc[VKILL]    = con->cp.kill;
+	tio->c_cc[VEOF]     = CEOF;
+#ifdef VSWTC
+	tio->c_cc[VSWTC]    = _POSIX_VDISABLE;
+#else
+	tio->c_cc[VSWTCH]   = _POSIX_VDISABLE;
+#endif
+	tio->c_cc[VSTART]   = CSTART;
+	tio->c_cc[VSTOP]    = CSTOP;
+	tio->c_cc[VSUSP]    = CSUSP;
+	tio->c_cc[VEOL]     = _POSIX_VDISABLE;
+
+	if (con->cp.eol == CR) {
+		tio->c_iflag |= ICRNL;
+		tio->c_iflag &= ~(INLCR|IGNCR);
+		tio->c_oflag |= ONLCR;
+		tio->c_oflag &= ~(OCRNL|ONLRET);
+	}
+
+	switch (con->cp.parity) {
+	default:
+	case 0:
+		tio->c_cflag &= ~(PARODD | PARENB);
+		tio->c_iflag &= ~(INPCK | ISTRIP);
+		break;
+	case 1:				/* odd parity */
+		tio->c_cflag |= PARODD;
+		/* fall through */
+	case 2:				/* even parity */
+		tio->c_cflag |= PARENB;
+		tio->c_iflag |= (INPCK | ISTRIP);
+		/* fall through */
+	case (1 | 2):			/* no parity bit */
+		tio->c_cflag &= ~CSIZE;
+		tio->c_cflag |= CS7;
+		break;
+	}
+
+	/* Set line attributes */
+	(void)tcsetattr(fd, TCSANOW, tio);
+}
 
 /*
  * Called at timeout.
@@ -72,6 +247,11 @@ static void alrm_handler(int sig __attribute__((unused)))
 	alarm_rised++;
 }
 
+static void chld_handler(int sig __attribute__((unused)))
+{
+	sigchild++;
+}
+
 static void mask_signal(int signal, void (*handler)(int),
 		struct sigaction *origaction)
 {
@@ -81,8 +261,7 @@ static void mask_signal(int signal, void (*handler)(int),
 	sigemptyset(&newaction.sa_mask);
 	newaction.sa_flags = 0;
 
-	sigaction(signal, NULL, origaction);
-	sigaction(signal, &newaction, NULL);
+	sigaction(signal, &newaction, origaction);
 }
 
 static void unmask_signal(int signal, struct sigaction *sa)
@@ -282,51 +461,202 @@ static struct passwd *getrootpwent(int try_manually)
 }
 
 /*
+ * Ask by prompt for the password.
+ */
+static void doprompt(const char *crypted, struct console *con)
+{
+	struct termios tty;
+
+	if (con->flags & CON_SERIAL) {
+		tty = con->tio;
+		/*
+		 * For prompting: map NL in output to CR-NL
+		 * otherwise we may see stairs in the output.
+		 */
+		tty.c_oflag |= (ONLCR | OPOST);
+		(void) tcsetattr(con->fd, TCSADRAIN, &tty);
+	}
+	if (con->file == (FILE*)0) {
+		if  ((con->file = fdopen(con->fd, "r+")) == (FILE*)0)
+			goto err;
+	}
+#if defined(USE_ONELINE)
+	if (crypted[0])
+		fprintf(con->file, _("Give root password for login: "));
+	else
+		fprintf(con->file, _("Press enter for login: "));
+#else
+	if (crypted[0])
+		fprintf(con->file, _("Give root password for maintenance\n"));
+	else
+		fprintf(con->file, _("Press enter for maintenance"));
+	fprintf(con->file, _("(or type Control-D to continue): "));
+#endif
+	fflush(con->file);
+err:
+	if (con->flags & CON_SERIAL)
+		(void) tcsetattr(con->fd, TCSADRAIN, &con->tio);
+}
+
+/*
+ * Make sure to have an own session and controlling terminal
+ */
+static void setup(struct console *con)
+{
+	pid_t pid, pgrp, ppgrp, ttypgrp;
+	int fd;
+
+	if (con->flags & CON_NOTTY)
+		return;
+	fd = con->fd;
+
+	/*
+	 * Only go through this trouble if the new
+	 * tty doesn't fall in this process group.
+	 */
+	pid = getpid();
+	pgrp = getpgid(0);
+	ppgrp = getpgid(getppid());
+	ttypgrp = tcgetpgrp(fd);
+
+	if (pgrp != ttypgrp && ppgrp != ttypgrp) {
+		if (pid != getsid(0)) {
+			if (pid == getpgid(0))
+				setpgid(0, getpgid(getppid()));
+			setsid();
+		}
+
+		mask_signal(SIGHUP, SIG_IGN, &saved_sighup);
+		if (ttypgrp > 0)
+			ioctl(STDIN_FILENO, TIOCNOTTY, (char *)1);
+		unmask_signal(SIGHUP, &saved_sighup);
+		if (fd > STDIN_FILENO)  close(STDIN_FILENO);
+		if (fd > STDOUT_FILENO) close(STDOUT_FILENO);
+		if (fd > STDERR_FILENO) close(STDERR_FILENO);
+
+		ioctl(fd, TIOCSCTTY, (char *)1);
+		tcsetpgrp(fd, ppgrp);
+	}
+	dup2(fd, STDIN_FILENO);
+	dup2(fd, STDOUT_FILENO);
+	dup2(fd, STDERR_FILENO);
+	con->fd = STDIN_FILENO;
+
+	for (fd = STDERR_FILENO+1; fd < 32; fd++) {
+		if (openfd & (1<<fd)) {
+			close(fd);
+			openfd &= ~(1<<fd);
+		}
+	}
+}
+
+/*
  * Ask for the password. Note that there is no default timeout as we normally
  * skip this during boot.
  */
-static char *getpasswd(char *crypted)
+static char *getpasswd(struct console *con)
 {
 	struct sigaction sa;
-	struct termios old, tty;
-	static char pass[128];
+	struct termios tty;
+	static char pass[128], *ptr;
+	struct chardata *cp;
 	char *ret = pass;
-	size_t i;
+	unsigned char tc;
+	char c, ascval;
+	int eightbit;
+	int fd;
 
-	if (crypted[0])
-		printf(_("Give root password for maintenance\n"));
-	else
-		printf(_("Press enter for maintenance"));
-	printf(_("(or type Control-D to continue): "));
-	fflush(stdout);
+	if (con->flags & CON_NOTTY)
+		goto out;
+	fd = con->fd;
+	cp = &con->cp;
+	tty = con->tio;
 
-	tcgetattr(0, &old);
-	tcgetattr(0, &tty);
 	tty.c_iflag &= ~(IUCLC|IXON|IXOFF|IXANY);
-	tty.c_lflag &= ~(ECHO|ECHOE|ECHOK|ECHONL|TOSTOP);
-	tcsetattr(0, TCSANOW, &tty);
-
-	pass[sizeof(pass) - 1] = 0;
+	tty.c_lflag &= ~(ECHO|ECHOE|ECHOK|ECHONL|TOSTOP|ISIG);
+	tc = (tcsetattr(fd, TCSAFLUSH, &tty) == 0);
 
 	sa.sa_handler = alrm_handler;
 	sa.sa_flags = 0;
 	sigaction(SIGALRM, &sa, NULL);
-	if (timeout)
-		alarm(timeout);
+	if (timeout) alarm(timeout);
 
-	if (read(0, pass, sizeof(pass) - 1) <= 0)
-		ret = NULL;
-	else {
-		for (i = 0; i < sizeof(pass) && pass[i]; i++)
-			if (pass[i] == '\r' || pass[i] == '\n') {
-				pass[i] = 0;
+	ptr = &pass[0];
+	cp->eol = *ptr = '\0';
+
+	eightbit = ((con->flags & CON_SERIAL) == 0 || (tty.c_cflag & (PARODD|PARENB)) == 0);
+	while (cp->eol == '\0') {
+		if (read(fd, &c, 1) < 1) {
+			if (errno == EINTR || errno == EAGAIN) {
+				usleep(1000);
+				continue;
+			}
+			ret = (char*)0;
+			switch (errno) {
+			case 0:
+			case EIO:
+			case ESRCH:
+			case EINVAL:
+			case ENOENT:
 				break;
+			default:
+				fprintf(stderr, "sulogin: read(%s): %m\n\r", con->tty);
+				break;
+			}
+			goto quit;
+		}
+
+		if (eightbit)
+			ascval = c;
+		else if (c != (ascval = (c & 0177))) {
+			uint32_t bits, mask;
+			for (bits = 1, mask = 1; mask & 0177; mask <<= 1) {
+				if (mask & ascval)
+					bits++;
+			}
+			cp->parity |= ((bits & 1) ? 1 : 2);
+		}
+
+		switch (ascval) {
+		case 0:
+			*ptr = '\0';
+			goto quit; 
+		case CR:
+		case NL:
+			*ptr = '\0';
+			cp->eol = ascval;
+			break;
+		case BS:
+		case CERASE:
+			cp->erase = ascval;
+			if (ptr > &pass[0])
+				ptr--;
+			break;
+		case CKILL:
+			cp->kill = ascval;
+			while (ptr > &pass[0])
+				ptr--;
+			break;
+		case CEOF:
+			goto quit;		
+		default:
+			if ((size_t)(ptr - &pass[0]) >= (sizeof(pass) -1 )) {
+				 fprintf(stderr, "sulogin: input overrun at %s\n\r", con->tty);
+				 ret = (char*)0;
+				 goto quit;
 			}
+			*ptr++ = ascval;
+			break;
+		}
 	}
+quit:
 	alarm(0);
-	tcsetattr(0, TCSANOW, &old);
-	printf("\n");
-
+	if (tc)
+		(void)tcsetattr(fd, TCSAFLUSH, &con->tio);
+	if (ret && *ret != '\0')
+		tcfinal(con);
+	printf("\r\n");
+out:
 	return ret;
 }
 
@@ -371,9 +701,10 @@ static void sushell(struct passwd *pwd)
 	/*
 	 * Set some important environment variables.
 	 */
-	if (getcwd(home, sizeof(home)) != NULL)
-		setenv("HOME", home, 1);
+	if (getcwd(home, sizeof(home)) == NULL)
+		strcpy(home, "/");
 
+	setenv("HOME", home, 1);
 	setenv("LOGNAME", "root", 1);
 	setenv("USER", "root", 1);
 	if (!profile)
@@ -386,6 +717,7 @@ static void sushell(struct passwd *pwd)
 	unmask_signal(SIGINT, &saved_sigint);
 	unmask_signal(SIGTSTP, &saved_sigtstp);
 	unmask_signal(SIGQUIT, &saved_sigquit);
+	mask_signal(SIGHUP, SIG_DFL, NULL);
 
 #ifdef HAVE_LIBSELINUX
 	if (is_selinux_enabled() > 0) {
@@ -411,36 +743,6 @@ static void sushell(struct passwd *pwd)
 	warn(_("%s: exec failed"), "/bin/sh");
 }
 
-static void fixtty(void)
-{
-	struct termios tp;
-	int x = 0, fl = 0;
-
-	/* Skip serial console */
-	if (ioctl(STDIN_FILENO, TIOCMGET, (char *) &x) == 0)
-		return;
-
-#if defined(IUTF8) && defined(KDGKBMODE)
-	/* Detect mode of current keyboard setup, e.g. for UTF-8 */
-	if (ioctl(STDIN_FILENO, KDGKBMODE, &x) == 0 && x == K_UNICODE) {
-		setlocale(LC_CTYPE, "C.UTF-8");
-		fl |= UL_TTY_UTF8;
-	}
-#else
-	setlocale(LC_CTYPE, "POSIX");
-#endif
-	memset(&tp, 0, sizeof(struct termios));
-	if (tcgetattr(STDIN_FILENO, &tp) < 0) {
-		warn(_("tcgetattr failed"));
-		return;
-	}
-
-	reset_virtual_console(&tp, fl);
-
-	if (tcsetattr(STDIN_FILENO, TCSADRAIN, &tp))
-		warn(_("tcsetattr failed"));
-}
-
 static void usage(FILE *out)
 {
 	fputs(USAGE_HEADER, out);
@@ -461,13 +763,14 @@ static void usage(FILE *out)
 
 int main(int argc, char **argv)
 {
+	struct list_head consoles = {&consoles, &consoles}, *ptr;
+	struct console *con;
 	char *tty = NULL;
-	char *p;
 	struct passwd *pwd;
-	int c, fd = -1;
+	int c, status = 0;
+	int reconnect = 0;
 	int opt_e = 0;
-	pid_t pid, pgrp, ppgrp, ttypgrp;
-	struct sigaction saved_sighup;
+	pid_t pid;
 
 	static const struct option longopts[] = {
 		{ "login-shell",  0, 0, 'p' },
@@ -478,10 +781,18 @@ int main(int argc, char **argv)
 		{ NULL,           0, 0, 0 }
 	};
 
+	/*
+	 * If we are init we need to set up a own session.
+	 */
+	if ((pid = getpid()) == 1) {
+		setsid();
+		(void)ioctl(STDIN_FILENO, TIOCSCTTY, (char *)1);
+	}
+
 	setlocale(LC_ALL, "");
 	bindtextdomain(PACKAGE, LOCALEDIR);
 	textdomain(PACKAGE);
-	atexit(close_stdout);
+	atexit(close_stdout); /* XXX */
 
 	/*
 	 * See if we have a timeout flag.
@@ -513,78 +824,45 @@ int main(int argc, char **argv)
 	if (geteuid() != 0)
 		errx(EXIT_FAILURE, _("only root can run this program."));
 
-	/*
-	 * See if we need to open an other tty device.
-	 */
 	mask_signal(SIGQUIT, SIG_IGN, &saved_sigquit);
 	mask_signal(SIGTSTP, SIG_IGN, &saved_sigtstp);
 	mask_signal(SIGINT,  SIG_IGN, &saved_sigint);
+	mask_signal(SIGHUP,  SIG_IGN, &saved_sighup);
+
+	/*
+	 * See if we need to open an other tty device.
+	 */
 	if (optind < argc)
 		tty = argv[optind];
 
-	if (tty || (tty = getenv("CONSOLE"))) {
-
-		if ((fd = open(tty, O_RDWR)) < 0) {
-			warn(_("cannot open %s"), tty);
-			fd = dup(STDIN_FILENO);
-		}
-
-		if (fd < 0) {
-			warn(_("cannot duplicate stdin file descriptor"));
-		} else if (!isatty(fd)) {
-			warn(_("%s: not a tty"), tty);
-			close(fd);
-		} else {
+	if (!tty || *tty == '\0')
+		tty = getenv("CONSOLE");
 
-			/*
-			 * Only go through this trouble if the new tty doesn't
-			 * fall in this process group.
-			 */
-			pid = getpid();
-			pgrp = getpgid(0);
-			ppgrp = getpgid(getppid());
-			ttypgrp = tcgetpgrp(fd);
-
-			if (pgrp != ttypgrp && ppgrp != ttypgrp) {
-				if (pid != getsid(0)) {
-					if (pid == getpgid(0))
-						setpgid(0, getpgid(getppid()));
-					setsid();
-				}
+	/*
+	 * Detect possible consoles, use stdin as fallback.
+	 * If an optional tty is given, reconnect it to stdin.
+	 */
+	reconnect = detect_consoles(tty, STDIN_FILENO, &consoles);
 
-				sigaction(SIGHUP, NULL, &saved_sighup);
-				if (ttypgrp > 0)
-					ioctl(0, TIOCNOTTY, (char *)1);
-				sigaction(SIGHUP, &saved_sighup, NULL);
-				close(STDIN_FILENO);
-				close(STDOUT_FILENO);
-				close(STDERR_FILENO);
-				if (fd > 2)
-					close(fd);
-				if ((fd = open(tty, O_RDWR|O_NOCTTY)) < 0)
-					warn(_("cannot open %s"), tty);
-				else {
-					ioctl(STDIN_FILENO, TIOCSCTTY, (char *)1);
-					tcsetpgrp(fd, ppgrp);
-					dup2(fd, STDIN_FILENO);
-					dup2(fd, STDOUT_FILENO);
-					dup2(fd, STDERR_FILENO);
-
-					if (fd > STDERR_FILENO)
-						close(fd);
-				}
-			} else
-				if (fd > STDERR_FILENO)
-					close(fd);
-		}
-	} else if (getpid() == 1) {
-		/* We are init. We hence need to set a session anyway */
-		setsid();
-		if (ioctl(STDIN_FILENO, TIOCSCTTY, (char *)1))
-			warn(_("TIOCSCTTY: ioctl failed"));
+	/*
+	 * If previous stdin was not the speified tty and therefore reconnected
+	 * to the specified tty also reconnect stdout and stderr.
+	 */
+	if (reconnect) {
+		if (isatty(STDOUT_FILENO) == 0)
+			dup2(STDOUT_FILENO, STDIN_FILENO);
+		if (isatty(STDERR_FILENO) == 0)
+			dup2(STDOUT_FILENO, STDERR_FILENO);
 	}
 
-	fixtty();
+	/*
+	 * Should not happen
+	 */
+	if (list_empty(&consoles)) {
+		if (!errno)
+			errno = ENOENT;
+		errx(EXIT_FAILURE, _("cannot open console: %m\n"));
+	}
 
 	/*
 	 * Get the root password.
@@ -595,32 +873,121 @@ int main(int argc, char **argv)
 	}
 
 	/*
-	 * Ask for the password.
+	 * Ask for the password on the consoles.
 	 */
-	while (pwd) {
-		int failed = 0;
-		if ((p = getpasswd(pwd->pw_passwd)) == NULL)
+	list_for_each(ptr, &consoles) {
+		con = list_entry(ptr, struct console, entry);
+		if (con->id >= CONMAX)
 			break;
-		if (pwd->pw_passwd[0] == 0 ||
-		    strcmp(crypt(p, pwd->pw_passwd), pwd->pw_passwd) == 0) {
-			sushell(pwd);
-			failed++;
+		if (con->fd >= 0) {
+			openfd |= (1<<con->fd);
+			tcinit(con);
+			continue;
 		}
-		mask_signal(SIGQUIT, SIG_IGN, &saved_sigquit);
-		mask_signal(SIGTSTP, SIG_IGN, &saved_sigtstp);
-		mask_signal(SIGINT,  SIG_IGN, &saved_sigint);
-		if (failed) {
-		    fprintf(stderr, _("Can not execute su shell\n\n"));
-		    break;
-		} else
-		    fprintf(stderr, _("Login incorrect\n\n"));
+		if ((con->fd = open(con->tty, O_RDWR | O_NOCTTY | O_NONBLOCK)) < 0)
+			continue;
+		openfd |= (1<<con->fd);
+		tcinit(con);
 	}
+	ptr = (&consoles)->next;
+	usemask = (uint32_t*)mmap(NULL, sizeof(uint32_t), PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_SHARED, -1, 0);
 
-	if (alarm_rised)
-		fprintf(stderr, _("Timed out\n\n"));
+	if (ptr->next == &consoles) {
+		con = list_entry(ptr, struct console, entry);
+		goto nofork;
+	}
 
-	/*
-	 * User pressed Control-D.
-	 */
+	mask_signal(SIGCHLD, chld_handler, &saved_sigchld);
+	do {
+		con = list_entry(ptr, struct console, entry);
+		if (con->id >= CONMAX)
+			break;
+
+		switch ((con->pid = fork())) {
+		case 0:
+			mask_signal(SIGCHLD, SIG_DFL, NULL);
+			/* fall through */
+		nofork:
+			setup(con);
+			while (1) {
+				const char *passwd = pwd->pw_passwd;
+				const char *answer;
+				int failed = 0, doshell = 0;
+
+				doprompt(passwd, con);
+				if ((answer = getpasswd(con)) == NULL)
+					break;
+
+				if (passwd[0] == '\0')
+					doshell++;
+				else {
+					const char *cryptbuf;
+					cryptbuf = crypt(answer, passwd);
+					if (cryptbuf == NULL)
+						warnx(_("crypt failed: %m\n"));
+					else if (strcmp(cryptbuf, pwd->pw_passwd) == 0)
+						doshell++;
+				}
+
+				if (doshell) {
+					*usemask |= (1<<con->id);
+					sushell(pwd);
+					*usemask &= ~(1<<con->id);
+					failed++;
+				}
+
+				mask_signal(SIGQUIT, SIG_IGN, &saved_sigquit);
+				mask_signal(SIGTSTP, SIG_IGN, &saved_sigtstp);
+				mask_signal(SIGINT,  SIG_IGN, &saved_sigint);
+
+				if (failed) {
+					fprintf(stderr, _("Can not execute su shell\n\n"));
+					break;
+				}
+				fprintf(stderr, _("Login incorrect\n\n"));
+			}
+			if (alarm_rised) {
+				tcfinal(con);
+				warnx(_("Timed out\n\n"));
+			}
+			/*
+			 * User pressed Control-D.
+			 */
+			exit(0);
+		case -1:
+			warnx(_("Can not fork: %m\n"));
+			/* fall through */
+		default:
+			break;
+		}
+
+		ptr = ptr->next;
+
+	} while (ptr != &consoles);
+
+	while ((pid = wait(&status))) {
+		if (errno == ECHILD)
+			break;
+		if (pid < 0)
+			continue;
+		list_for_each(ptr, &consoles) {
+			con = list_entry(ptr, struct console, entry);
+			if (con->pid == pid) {
+				*usemask &= ~(1<<con->id);
+				continue;
+			}
+			if (kill(con->pid, 0) < 0) {
+				*usemask &= ~(1<<con->id);
+				continue;
+			}
+			if (*usemask & (1<<con->id))
+				continue;
+			kill(con->pid, SIGHUP);
+			usleep(5000);
+			kill(con->pid, SIGKILL);
+		}
+	}
+
+	mask_signal(SIGCHLD, SIG_DFL, NULL);
 	return EXIT_SUCCESS;
 }
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* Re: [PATCH 1/5] sulogin: use the linked lists from list.h for consoles list
  2012-12-07  8:00 [PATCH 1/5] sulogin: use the linked lists from list.h for consoles list Werner Fink
                   ` (3 preceding siblings ...)
  2012-12-07  8:00 ` [PATCH 5/5] sulogin: add multi console feature from SysVinit sulogin Werner Fink
@ 2012-12-18 15:05 ` Karel Zak
  4 siblings, 0 replies; 20+ messages in thread
From: Karel Zak @ 2012-12-18 15:05 UTC (permalink / raw)
  To: Werner Fink; +Cc: util-linux

On Fri, Dec 07, 2012 at 09:00:54AM +0100, Werner Fink wrote:
>  include/consoles.h |    6 ++--
>  lib/consoles.c     |   77 ++++++++++++++++++++++++++++++++--------------------
>  2 files changed, 51 insertions(+), 32 deletions(-)

 Applied, thanks. I have added list_last_entry() to avoid
 consoles->prev usage in the code.o

    Karel

-- 
 Karel Zak  <kzak@redhat.com>
 http://karelzak.blogspot.com

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH 2/5] sulogin: make usleep() workaround work
  2012-12-07  8:00 ` [PATCH 2/5] sulogin: make usleep() workaround work Werner Fink
@ 2012-12-18 15:07   ` Karel Zak
  0 siblings, 0 replies; 20+ messages in thread
From: Karel Zak @ 2012-12-18 15:07 UTC (permalink / raw)
  To: Werner Fink; +Cc: util-linux

On Fri, Dec 07, 2012 at 09:00:55AM +0100, Werner Fink wrote:
>  include/c.h |   10 +++++++---
>  1 file changed, 7 insertions(+), 3 deletions(-)

 Applied, thanks.

-- 
 Karel Zak  <kzak@redhat.com>
 http://karelzak.blogspot.com

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH 3/5] sulogin: use alarm function to indicate if a timeout occurs
  2012-12-07  8:00 ` [PATCH 3/5] sulogin: use alarm function to indicate if a timeout occurs Werner Fink
@ 2012-12-18 15:15   ` Karel Zak
  0 siblings, 0 replies; 20+ messages in thread
From: Karel Zak @ 2012-12-18 15:15 UTC (permalink / raw)
  To: Werner Fink; +Cc: util-linux

On Fri, Dec 07, 2012 at 09:00:56AM +0100, Werner Fink wrote:
>  login-utils/sulogin.c |   20 +++++++++++++++++---
>  1 file changed, 17 insertions(+), 3 deletions(-)

 Applied, thanks.

-- 
 Karel Zak  <kzak@redhat.com>
 http://karelzak.blogspot.com

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH 4/5] sulogin: mount temporary /dev and /proc if not found
  2012-12-07  8:00 ` [PATCH 4/5] sulogin: mount temporary /dev and /proc if not found Werner Fink
  2012-12-07 14:17   ` Dave Reisner
@ 2012-12-18 15:17   ` Karel Zak
  1 sibling, 0 replies; 20+ messages in thread
From: Karel Zak @ 2012-12-18 15:17 UTC (permalink / raw)
  To: Werner Fink; +Cc: util-linux

On Fri, Dec 07, 2012 at 09:00:57AM +0100, Werner Fink wrote:
>  configure.ac          |   10 ++++++++
>  login-utils/sulogin.c |   57 ++++++++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 67 insertions(+)

 Applied with some minor changes, thanks.

> +AC_ARG_ENABLE([use-emergency-dev],
> +  AS_HELP_STRING([--disable-use-emergency-dev], [do not use emergency mount of /dev and /proc for sulogin]),
> +  [], enable_use_emergency_dev=yes
> +)

 renamed to --disable-sulogin-emergency-mount

    Karel

-- 
 Karel Zak  <kzak@redhat.com>
 http://karelzak.blogspot.com

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH 5/5] sulogin: add multi console feature from SysVinit sulogin
  2012-12-10 12:27           ` [PATCH 5/5] sulogin: add multi console feature from SysVinit sulogin Werner Fink
@ 2012-12-18 15:18             ` Karel Zak
  0 siblings, 0 replies; 20+ messages in thread
From: Karel Zak @ 2012-12-18 15:18 UTC (permalink / raw)
  To: Werner Fink; +Cc: util-linux

On Mon, Dec 10, 2012 at 01:27:11PM +0100, Werner Fink wrote:
>  login-utils/sulogin.c |  665 ++++++++++++++++++++++++++++++++++++++-----------
>  1 file changed, 516 insertions(+), 149 deletions(-)

 Applied, thanks.

-- 
 Karel Zak  <kzak@redhat.com>
 http://karelzak.blogspot.com

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH 4/5] sulogin: mount temporary /dev and /proc if not found
  2012-12-10 12:27         ` Werner Fink
  2012-12-10 12:27           ` [PATCH 5/5] sulogin: add multi console feature from SysVinit sulogin Werner Fink
@ 2012-12-18 15:23           ` Karel Zak
  2012-12-23  4:33             ` Dave Reisner
  1 sibling, 1 reply; 20+ messages in thread
From: Karel Zak @ 2012-12-18 15:23 UTC (permalink / raw)
  To: Werner Fink; +Cc: util-linux

On Mon, Dec 10, 2012 at 01:27:10PM +0100, Werner Fink wrote:
>  configure.ac   |   10 +++++++++
>  lib/consoles.c |   66 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 76 insertions(+)

 Note that I have applied this (fixed) version of the patch.

    Karel

-- 
 Karel Zak  <kzak@redhat.com>
 http://karelzak.blogspot.com

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH 4/5] sulogin: mount temporary /dev and /proc if not found
  2012-12-18 15:23           ` [PATCH 4/5] sulogin: mount temporary /dev and /proc if not found Karel Zak
@ 2012-12-23  4:33             ` Dave Reisner
  2012-12-23 21:53               ` Karel Zak
  0 siblings, 1 reply; 20+ messages in thread
From: Dave Reisner @ 2012-12-23  4:33 UTC (permalink / raw)
  To: Karel Zak; +Cc: Werner Fink, util-linux

On Tue, Dec 18, 2012 at 04:23:11PM +0100, Karel Zak wrote:
> On Mon, Dec 10, 2012 at 01:27:10PM +0100, Werner Fink wrote:
> >  configure.ac   |   10 +++++++++
> >  lib/consoles.c |   66 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> >  2 files changed, 76 insertions(+)
> 
>  Note that I have applied this (fixed) version of the patch.
> 
>     Karel
> 

This is pretty broken. Using the constructor and destructor attributes
means that ANY programs linking in the code will invoke these functions.
As it's not a direct inclusion, but part of a libtool convenience lib,
the effect is pretty severe:

$ git grep -F libcommon.la | wc -l
78

This includes things such as libblkid and libmount, among others.

It wouldn't generally matter (though I'm still in favor of finding
another solution for this), but this breaks early userspace pretty hard.
Invoking mount (or even findmnt) will preemptively run this code. I'm
not clear on why, but the filesystems were NOT umounted by the
destructor, and my busybox umount as well as util-linux's switch_root
simply failed with EINVAL.

I suggest that this code be relegated to sulogin.

d

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH 4/5] sulogin: mount temporary /dev and /proc if not found
  2012-12-23  4:33             ` Dave Reisner
@ 2012-12-23 21:53               ` Karel Zak
  0 siblings, 0 replies; 20+ messages in thread
From: Karel Zak @ 2012-12-23 21:53 UTC (permalink / raw)
  To: Werner Fink, util-linux

On Sat, Dec 22, 2012 at 11:33:42PM -0500, Dave Reisner wrote:
> I suggest that this code be relegated to sulogin.

 Fixed:
    - removed from libcommon (it's sulogin specific)
    - removed the attributes

  Karel


-- 
 Karel Zak  <kzak@redhat.com>
 http://karelzak.blogspot.com

^ permalink raw reply	[flat|nested] 20+ messages in thread

end of thread, other threads:[~2012-12-23 21:54 UTC | newest]

Thread overview: 20+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-12-07  8:00 [PATCH 1/5] sulogin: use the linked lists from list.h for consoles list Werner Fink
2012-12-07  8:00 ` [PATCH 2/5] sulogin: make usleep() workaround work Werner Fink
2012-12-18 15:07   ` Karel Zak
2012-12-07  8:00 ` [PATCH 3/5] sulogin: use alarm function to indicate if a timeout occurs Werner Fink
2012-12-18 15:15   ` Karel Zak
2012-12-07  8:00 ` [PATCH 4/5] sulogin: mount temporary /dev and /proc if not found Werner Fink
2012-12-07 14:17   ` Dave Reisner
2012-12-07 15:49     ` [util-linux] " Dr. Werner Fink
2012-12-07 17:01       ` Dave Reisner
2012-12-07 17:25         ` Dr. Werner Fink
2012-12-10 12:27         ` Werner Fink
2012-12-10 12:27           ` [PATCH 5/5] sulogin: add multi console feature from SysVinit sulogin Werner Fink
2012-12-18 15:18             ` Karel Zak
2012-12-18 15:23           ` [PATCH 4/5] sulogin: mount temporary /dev and /proc if not found Karel Zak
2012-12-23  4:33             ` Dave Reisner
2012-12-23 21:53               ` Karel Zak
2012-12-18 15:17   ` Karel Zak
2012-12-07  8:00 ` [PATCH 5/5] sulogin: add multi console feature from SysVinit sulogin Werner Fink
2012-12-07 10:27   ` Dr. Werner Fink
2012-12-18 15:05 ` [PATCH 1/5] sulogin: use the linked lists from list.h for consoles list Karel Zak

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.