util-linux.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 00/13] Initial import of sulogin
@ 2012-02-28 16:45 Dave Reisner
  2012-02-28 16:45 ` [PATCH 01/13] fstab.5: fix misspelling of deprecated Dave Reisner
                   ` (14 more replies)
  0 siblings, 15 replies; 25+ messages in thread
From: Dave Reisner @ 2012-02-28 16:45 UTC (permalink / raw)
  To: util-linux; +Cc: Dave Reisner

This is an initial stab at importing sulogin from sysvinit and making it a bit
more universal. I've removed the distro specific code and brought the rest of
it more in line with the style of the remainder of the repo. I've also added
internationalization and cleaned up the manpage.

Dave Reisner (13):
  fstab.5: fix misspelling of deprecated
  sulogin: initial import from sysvinit
  sulogin.8: refactor manpage
  sulogin: whitespace fixes
  sulogin: replace older signal() with sigaction()
  sulogin: remove CHECK_{DES,MD5} defines
  sulogin: remove USE_ONELINE and SANE_TIO defines
  sulogin: use size_t for iterator to avoid cast
  sulogin: get rid of calls to /bin/sash
  sulogin: use pathnames.h for file locations
  sulogin: header/include cleanup
  sulogin: use a more standard usage output
  sulogin: add i18n strings

 login-utils/Makefile.am |    6 +-
 login-utils/sulogin.8   |   60 +++++
 login-utils/sulogin.c   |  556 +++++++++++++++++++++++++++++++++++++++++++++++
 mount/fstab.5           |    2 +-
 4 files changed, 622 insertions(+), 2 deletions(-)
 create mode 100644 login-utils/sulogin.8
 create mode 100644 login-utils/sulogin.c

-- 
1.7.9.2


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

* [PATCH 01/13] fstab.5: fix misspelling of deprecated
  2012-02-28 16:45 [PATCH 00/13] Initial import of sulogin Dave Reisner
@ 2012-02-28 16:45 ` Dave Reisner
  2012-02-28 16:45 ` [PATCH 02/13] sulogin: initial import from sysvinit Dave Reisner
                   ` (13 subsequent siblings)
  14 siblings, 0 replies; 25+ messages in thread
From: Dave Reisner @ 2012-02-28 16:45 UTC (permalink / raw)
  To: util-linux; +Cc: Dave Reisner

Signed-off-by: Dave Reisner <dreisner@archlinux.org>
---
 mount/fstab.5 |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/mount/fstab.5 b/mount/fstab.5
index b0cd763..c618947 100644
--- a/mount/fstab.5
+++ b/mount/fstab.5
@@ -167,7 +167,7 @@ support filesystem
 The subtype is defined by '.subtype' suffix.  For
 example 'fuse.sshfs'. It's recommended to use subtype notation rather than add
 any prefix to the first fstab field (for example 'sshfs#example.com' is
-depreacated). 
+deprecated).
 .RE
 
 .B The fourth field
-- 
1.7.9.2


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

* [PATCH 02/13] sulogin: initial import from sysvinit
  2012-02-28 16:45 [PATCH 00/13] Initial import of sulogin Dave Reisner
  2012-02-28 16:45 ` [PATCH 01/13] fstab.5: fix misspelling of deprecated Dave Reisner
@ 2012-02-28 16:45 ` Dave Reisner
  2012-02-28 18:45   ` Davidlohr Bueso
  2012-02-28 16:45 ` [PATCH 03/13] sulogin.8: refactor manpage Dave Reisner
                   ` (12 subsequent siblings)
  14 siblings, 1 reply; 25+ messages in thread
From: Dave Reisner @ 2012-02-28 16:45 UTC (permalink / raw)
  To: util-linux; +Cc: Dave Reisner

Import the source and manpage of sulogin. Only the selinux #ifdef is
changed to match our autotool setup.

Signed-off-by: Dave Reisner <dreisner@archlinux.org>
---
 login-utils/Makefile.am |    6 +-
 login-utils/sulogin.8   |   87 +++++++
 login-utils/sulogin.c   |  605 +++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 697 insertions(+), 1 deletion(-)
 create mode 100644 login-utils/sulogin.8
 create mode 100644 login-utils/sulogin.c

diff --git a/login-utils/Makefile.am b/login-utils/Makefile.am
index 47274bf..6d5f4e9 100644
--- a/login-utils/Makefile.am
+++ b/login-utils/Makefile.am
@@ -14,6 +14,7 @@ endif
 if BUILD_LOGIN_UTILS
 
 bin_PROGRAMS += login
+sbin_PROGRAMS += sulogin
 usrbin_exec_PROGRAMS += \
 	chfn \
 	chsh \
@@ -26,7 +27,8 @@ dist_man_MANS += \
 	login.1 \
 	newgrp.1 \
 	vigr.8 \
-	vipw.8
+	vipw.8 \
+	sulogin.8
 
 # login, chfn and chsh libs
 login_ldadd_common =
@@ -57,6 +59,7 @@ chsh_LDADD = $(login_ldadd_common)
 login_LDADD = $(login_ldadd_common)
 newgrp_LDADD =
 vipw_LDADD =
+sulogin_LDADD =
 
 chfn_CFLAGS = $(SUID_CFLAGS) $(AM_CFLAGS)
 chsh_CFLAGS = $(SUID_CFLAGS) $(AM_CFLAGS)
@@ -70,6 +73,7 @@ login_ldadd_common += -lpam -lpam_misc
 
 if HAVE_LIBCRYPT
 newgrp_LDADD += -lcrypt
+sulogin_LDADD += -lcrypt
 endif
 
 if HAVE_AUDIT
diff --git a/login-utils/sulogin.8 b/login-utils/sulogin.8
new file mode 100644
index 0000000..4b5d153
--- /dev/null
+++ b/login-utils/sulogin.8
@@ -0,0 +1,87 @@
+'\" -*- coding: UTF-8 -*-
+.\" Copyright (C) 1998-2006 Miquel van Smoorenburg.
+.\"
+.\" 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
+.\" the Free Software Foundation; either version 2 of the License, or
+.\" (at your option) any later version.
+.\"
+.\" This program is distributed in the hope that it will be useful,
+.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
+.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+.\" GNU General Public License for more details.
+.\"
+.\" You should have received a copy of the GNU General Public License
+.\" along with this program; if not, write to the Free Software
+.\" Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+.\"
+.TH SULOGIN 8 "17 Jan 2006" "" "Linux System Administrator's Manual"
+.SH NAME
+sulogin \- Single-user login
+.SH SYNOPSIS
+.B sulogin
+[ \fB\-e\fP ]
+[ \fB\-p\fP ]
+[ \fB\-t\fP \fISECONDS\fP ]
+[ \fITTY\fP ]
+.SH DESCRIPTION
+.I sulogin
+is invoked by \fBinit(8)\fP when the system goes into single user mode.
+(This is done through an entry in \fIinittab(5)\fP.)
+\fBInit\fP also
+tries to execute \fIsulogin\fP when
+the boot loader (e.g., \fBgrub\fP(8))
+passes it the \fB\-b\fP option.
+.PP
+The user is prompted
+.IP "" .5i
+Give root password for system maintenance
+.br
+(or type Control\-D for normal startup):
+.PP
+\fIsulogin\fP will be connected to the current terminal, or to the
+optional device that can be specified on the command line
+(typically \fB/dev/console\fP).
+.PP
+If the \fB\-t\fP option is used then the program only waits
+the given number of seconds for user input.
+.PP
+If the \fB\-p\fP option is used then the single-user shell is invoked
+with a \fIdash\fP as the first character in \fIargv[0]\fP.
+This causes the shell process to behave as a login shell.
+The default is \fInot\fP to do this,
+so that the shell will \fInot\fP read \fB/etc/profile\fP
+or \fB$HOME/.profile\fP at startup.
+.PP
+After the user exits the single-user shell,
+or presses control\-D at the prompt,
+the system will (continue to) boot to the default runlevel.
+.SH ENVIRONMENT VARIABLES
+\fIsulogin\fP looks for the environment variable \fBSUSHELL\fP or
+\fBsushell\fP to determine what shell to start. If the environment variable
+is not set, it will try to execute root's shell from /etc/passwd. If that
+fails it will fall back to \fB/bin/sh\fP.
+.PP
+This is very valuable together with the \fB\-b\fP option to init. To boot
+the system into single user mode, with the root file system mounted read/write,
+using a special "fail safe" shell that is statically linked (this example
+is valid for the LILO bootprompt)
+.PP
+boot: linux \-b rw sushell=/sbin/sash
+.SH FALLBACK METHODS
+\fIsulogin\fP checks the root password using the standard method (getpwnam)
+first.
+Then, if the \fB\-e\fP option was specified,
+\fIsulogin\fP examines these files directly to find the root password:
+.PP
+/etc/passwd,
+.br
+/etc/shadow (if present)
+.PP
+If they are damaged or nonexistent, sulogin will start a root shell
+without asking for a password. Only use the \fB\-e\fP option if you
+are sure the console is physically protected against unauthorized access.
+.SH AUTHOR
+Miquel van Smoorenburg <miquels@cistron.nl>
+.SH SEE ALSO
+init(8), inittab(5).
diff --git a/login-utils/sulogin.c b/login-utils/sulogin.c
new file mode 100644
index 0000000..969fc52
--- /dev/null
+++ b/login-utils/sulogin.c
@@ -0,0 +1,605 @@
+/*
+ * sulogin	This program gives Linux machines a reasonable
+ *		secure way to boot single user. It forces the
+ *		user to supply the root password before a
+ *		shell is started.
+ *
+ *		If there is a shadow password file and the
+ *		encrypted root password is "x" the shadow
+ *		password will be used.
+ *
+ * Version:	@(#)sulogin 2.85-3 23-Apr-2003 miquels@cistron.nl
+ *
+ * Copyright (C) 1998-2003 Miquel van Smoorenburg.
+ *
+ * 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * 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/types.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <pwd.h>
+#include <shadow.h>
+#include <termios.h>
+#include <sys/ttydefaults.h>
+#include <errno.h>
+#include <sys/ioctl.h>
+#if defined(__GLIBC__)
+#  include <crypt.h>
+#endif
+
+#ifdef HAVE_LIBSELINUX
+#  include <selinux/selinux.h>
+#  include <selinux/get_context_list.h>
+#endif
+
+#define CHECK_DES	1
+#define CHECK_MD5	1
+
+#define F_PASSWD	"/etc/passwd"
+#define F_SHADOW	"/etc/shadow"
+#define BINSH		"/bin/sh"
+#define STATICSH	"/bin/sash"
+
+static int timeout;
+static int profile;
+
+static void (*saved_sigint)  = SIG_DFL;
+static void (*saved_sigtstp) = SIG_DFL;
+static void (*saved_sigquit) = SIG_DFL;
+
+#ifndef IUCLC
+#  define IUCLC	0
+#endif
+
+#if defined(SANE_TIO) && (SANE_TIO == 1)
+/*
+ *	Fix the tty modes and set reasonable defaults.
+ *	(I'm not sure if this is needed under Linux, but..)
+ */
+static
+void fixtty(void)
+{
+	struct termios tty;
+	int serial;
+
+	/* Skip serial console */
+	if (ioctl (0, TIOCMGET, (char*)&serial) == 0)
+		goto out;
+	/* Expected error */
+	serial = errno = 0;
+
+	tcgetattr(0, &tty);
+
+	/* Use defaults of <sys/ttydefaults.h> for base settings */
+	tty.c_iflag |= TTYDEF_IFLAG;
+	tty.c_oflag |= TTYDEF_OFLAG;
+	tty.c_lflag |= TTYDEF_LFLAG;
+	tty.c_cflag |= (TTYDEF_SPEED | TTYDEF_CFLAG);
+
+	/* Sane setting, allow eight bit characters, no carriage return delay
+	 * the same result as `stty sane cr0 pass8'
+	 */
+	tty.c_iflag |=  (BRKINT | ICRNL | IMAXBEL);
+#ifdef IUTF8 /* Not defined on FreeBSD */
+	tty.c_iflag |= IUTF8;
+#endif /* IUTF8 */
+	tty.c_iflag &= ~(IGNBRK | INLCR | IGNCR | IXOFF | IUCLC | IXANY | ISTRIP);
+	tty.c_oflag |=  (OPOST | ONLCR | NL0 | CR0 | TAB0 | BS0 | VT0 | FF0);
+	tty.c_oflag &= ~(OLCUC | OCRNL | ONOCR | ONLRET | OFILL | OFDEL |\
+			 NLDLY|CRDLY|TABDLY|BSDLY|VTDLY|FFDLY);
+	tty.c_lflag |=  (ISIG | ICANON | IEXTEN | ECHO|ECHOE|ECHOK|ECHOCTL|ECHOKE);
+	tty.c_lflag &= ~(ECHONL | NOFLSH | XCASE | TOSTOP | ECHOPRT);
+	tty.c_cflag |=  (CREAD | CS8 | B9600);
+	tty.c_cflag &= ~(PARENB);
+
+	/* VTIME and VMIN can overlap with VEOF and VEOL since they are
+	 * only used for non-canonical mode. We just set the at the
+	 * beginning, so nothing bad should happen.
+	 */
+	tty.c_cc[VTIME]    = 0;
+	tty.c_cc[VMIN]     = 1;
+	tty.c_cc[VINTR]    = CINTR;
+	tty.c_cc[VQUIT]    = CQUIT;
+	tty.c_cc[VERASE]   = CERASE; /* ASCII DEL (0177) */
+	tty.c_cc[VKILL]    = CKILL;
+	tty.c_cc[VEOF]     = CEOF;
+	tty.c_cc[VSWTC]    = _POSIX_VDISABLE;
+	tty.c_cc[VSTART]   = CSTART;
+	tty.c_cc[VSTOP]    = CSTOP;
+	tty.c_cc[VSUSP]    = CSUSP;
+	tty.c_cc[VEOL]     = _POSIX_VDISABLE;
+	tty.c_cc[VREPRINT] = CREPRINT;
+	tty.c_cc[VDISCARD] = CDISCARD;
+	tty.c_cc[VWERASE]  = CWERASE;
+	tty.c_cc[VLNEXT]   = CLNEXT;
+	tty.c_cc[VEOL2]    = _POSIX_VDISABLE;
+
+	tcsetattr(0, TCSANOW, &tty);
+out:
+	return;
+}
+#endif
+
+
+/*
+ *	Called at timeout.
+ */
+static
+# ifdef __GNUC__
+void alrm_handler(int sig __attribute__((unused)))
+# else
+void alrm_handler(int sig)
+# endif
+{
+}
+
+/*
+ *	See if an encrypted password is valid. The encrypted
+ *	password is checked for traditional-style DES and
+ *	FreeBSD-style MD5 encryption.
+ */
+static
+int valid(const char *pass)
+{
+	const char *s;
+	char id[5];
+	size_t len;
+	off_t off;
+
+	if (pass[0] == 0) return 1;
+#if CHECK_MD5
+	if (pass[0] != '$') goto check_des;
+
+	/*
+	 *	up to 4 bytes for the signature e.g. $1$
+	 */
+	for(s = pass+1; *s && *s != '$'; s++)
+		;
+	if (*s++ != '$') return 0;
+	if ((off = (off_t)(s-pass)) > 4 || off < 3) return 0;
+
+	memset(id, '\0', sizeof(id));
+	strncpy(id, pass, off);
+
+	/*
+	 *	up to 16 bytes for the salt
+	 */
+	for(; *s && *s != '$'; s++)
+		;
+	if (*s++ != '$') return 0;
+	if ((off_t)(s-pass) > 16) return 0;
+	len = strlen(s);
+
+	/*
+	 *	the MD5 hash (128 bits or 16 bytes) encoded in base64 = 22 bytes
+	 */
+	if ((strcmp(id, "$1$") == 0) && (len < 22 || len > 24)) return 0;
+
+	/*
+	 *	the SHA-256 hash 43 bytes
+	 */
+	if ((strcmp(id, "$5$") == 0) && (len < 42 || len > 44)) return 0;
+
+	/*
+	 *      the SHA-512 hash 86 bytes
+	 */
+	if ((strcmp(id, "$6$") == 0) && (len < 85 || len > 87)) return 0;
+
+	/*
+	 *	e.g. Blowfish hash
+	 */
+	return 1;
+check_des:
+#endif
+#if CHECK_DES
+	if (strlen(pass) != 13) return 0;
+	for (s = pass; *s; s++) {
+		if ((*s < '0' || *s > '9') &&
+		    (*s < 'a' || *s > 'z') &&
+		    (*s < 'A' || *s > 'Z') &&
+		    *s != '.' && *s != '/') return 0;
+	}
+#endif
+	return 1;
+}
+
+/*
+ *	Set a variable if the value is not NULL.
+ */
+static
+void set(char **var, char *val)
+{
+	if (val) *var = val;
+}
+
+/*
+ *	Get the root password entry.
+ */
+static
+struct passwd *getrootpwent(int try_manually)
+{
+	static struct passwd pwd;
+	struct passwd *pw;
+	struct spwd *spw;
+	FILE *fp;
+	static char line[256];
+	static char sline[256];
+	char *p;
+
+	/*
+	 *	First, we try to get the password the standard
+	 *	way using normal library calls.
+	 */
+	if ((pw = getpwnam("root")) &&
+	    !strcmp(pw->pw_passwd, "x") &&
+	    (spw = getspnam("root")))
+		pw->pw_passwd = spw->sp_pwdp;
+	if (pw || !try_manually) return pw;
+
+	/*
+	 *	If we come here, we could not retrieve the root
+	 *	password through library calls and we try to
+	 *	read the password and shadow files manually.
+	 */
+	pwd.pw_name = "root";
+	pwd.pw_passwd = "";
+	pwd.pw_gecos = "Super User";
+	pwd.pw_dir = "/";
+	pwd.pw_shell = "";
+	pwd.pw_uid = 0;
+	pwd.pw_gid = 0;
+
+	if ((fp = fopen(F_PASSWD, "r")) == NULL) {
+		perror(F_PASSWD);
+		return &pwd;
+	}
+
+	/*
+	 *	Find root in the password file.
+	 */
+	while((p = fgets(line, 256, fp)) != NULL) {
+		if (strncmp(line, "root:", 5) != 0)
+			continue;
+		p += 5;
+		set(&pwd.pw_passwd, strsep(&p, ":"));
+		(void)strsep(&p, ":");
+		(void)strsep(&p, ":");
+		set(&pwd.pw_gecos, strsep(&p, ":"));
+		set(&pwd.pw_dir, strsep(&p, ":"));
+		set(&pwd.pw_shell, strsep(&p, "\n"));
+		p = line;
+		break;
+	}
+	fclose(fp);
+
+	/*
+	 *	If the encrypted password is valid
+	 *	or not found, return.
+	 */
+	if (p == NULL) {
+		fprintf(stderr, "%s: no entry for root\n", F_PASSWD);
+		return &pwd;
+	}
+	if (valid(pwd.pw_passwd)) return &pwd;
+
+	/*
+	 *	The password is invalid. If there is a
+	 *	shadow password, try it.
+	 */
+	strcpy(pwd.pw_passwd, "");
+	if ((fp = fopen(F_SHADOW, "r")) == NULL) {
+		fprintf(stderr, "%s: root password garbled\n", F_PASSWD);
+		return &pwd;
+	}
+	while((p = fgets(sline, 256, fp)) != NULL) {
+		if (strncmp(sline, "root:", 5) != 0)
+			continue;
+		p += 5;
+		set(&pwd.pw_passwd, strsep(&p, ":"));
+		break;
+	}
+	fclose(fp);
+
+	/*
+	 *	If the password is still invalid,
+	 *	NULL it, and return.
+	 */
+	if (p == NULL) {
+		fprintf(stderr, "%s: no entry for root\n", F_SHADOW);
+		strcpy(pwd.pw_passwd, "");
+	}
+	if (!valid(pwd.pw_passwd)) {
+		fprintf(stderr, "%s: root password garbled\n", F_SHADOW);
+		strcpy(pwd.pw_passwd, ""); }
+	return &pwd;
+}
+
+/*
+ *	Ask for the password. Note that there is no
+ *	default timeout as we normally skip this during boot.
+ */
+static
+char *getpasswd(char *crypted)
+{
+	struct sigaction sa;
+	struct termios old, tty;
+	static char pass[128];
+	char *ret = pass;
+	int i;
+#if defined(USE_ONELINE)
+	if (crypted[0])
+		printf("Give root password for login: ");
+	else
+		printf("Press enter for login: ");
+#else
+	if (crypted[0])
+		printf("Give root password for maintenance\n");
+	else
+		printf("Press enter for maintenance");
+	printf("(or type Control-D to continue): ");
+#endif
+	fflush(stdout);
+
+	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;
+
+	sa.sa_handler = alrm_handler;
+	sa.sa_flags = 0;
+	sigaction(SIGALRM, &sa, NULL);
+	if (timeout) alarm(timeout);
+
+	if (read(0, pass, sizeof(pass) - 1) <= 0)
+		ret = NULL;
+	else {
+		for(i = 0; i < (int)sizeof(pass) && pass[i]; i++)
+			if (pass[i] == '\r' || pass[i] == '\n') {
+				pass[i] = 0;
+				break;
+			}
+	}
+	alarm(0);
+	tcsetattr(0, TCSANOW, &old);
+	printf("\n");
+
+	return ret;
+}
+
+/*
+ *	Password was OK, execute a shell.
+ */
+static
+void sushell(struct passwd *pwd)
+{
+	char shell[128];
+	char home[128];
+	char *p;
+	char *sushell;
+
+	/*
+	 *	Set directory and shell.
+	 */
+	(void)chdir(pwd->pw_dir);
+	if ((p = getenv("SUSHELL")) != NULL)
+		sushell = p;
+	else if ((p = getenv("sushell")) != NULL)
+		sushell = p;
+	else {
+		if (pwd->pw_shell[0])
+			sushell = pwd->pw_shell;
+		else
+			sushell = BINSH;
+	}
+	if ((p = strrchr(sushell, '/')) == NULL)
+		p = sushell;
+	else
+		p++;
+	snprintf(shell, sizeof(shell), profile ? "-%s" : "%s", p);
+
+	/*
+	 *	Set some important environment variables.
+	 */
+	getcwd(home, sizeof(home));
+	setenv("HOME", home, 1);
+	setenv("LOGNAME", "root", 1);
+	setenv("USER", "root", 1);
+	if (!profile)
+		setenv("SHLVL","0",1);
+
+	/*
+	 *	Try to execute a shell.
+	 */
+	setenv("SHELL", sushell, 1);
+	signal(SIGINT,  saved_sigint);
+	signal(SIGTSTP, saved_sigtstp);
+	signal(SIGQUIT, saved_sigquit);
+#ifdef WITH_SELINUX
+	if (is_selinux_enabled() > 0) {
+	  security_context_t scon=NULL;
+	  char *seuser=NULL;
+	  char *level=NULL;
+	  if (getseuserbyname("root", &seuser, &level) == 0)
+		  if (get_default_context_with_level(seuser, level, 0, &scon) == 0) {
+			  if (setexeccon(scon) != 0) 
+				  fprintf(stderr, "setexeccon faile\n");
+			  freecon(scon);
+		  }
+		free(seuser);
+		free(level);
+	}
+#endif
+	execl(sushell, shell, NULL);
+	perror(sushell);
+
+	setenv("SHELL", BINSH, 1);
+	execl(BINSH, profile ? "-sh" : "sh", NULL);
+	perror(BINSH);
+
+	/* Fall back to staticly linked shell if both the users shell
+	   and /bin/sh failed to execute. */
+	setenv("SHELL", STATICSH, 1);
+	execl(STATICSH, STATICSH, NULL);
+	perror(STATICSH);
+}
+
+static
+void usage(void)
+{
+	fprintf(stderr, "Usage: sulogin [-e] [-p] [-t timeout] [tty device]\n");
+}
+
+int main(int argc, char **argv)
+{
+	char *tty = NULL;
+	char *p;
+	struct passwd *pwd;
+	int c, fd = -1;
+	int opt_e = 0;
+	pid_t pid, pgrp, ppgrp, ttypgrp;
+
+	/*
+	 *	See if we have a timeout flag.
+	 */
+	opterr = 0;
+	while((c = getopt(argc, argv, "ept:")) != EOF) switch(c) {
+		case 't':
+			timeout = atoi(optarg);
+			break;
+		case 'p':
+			profile = 1;
+			break;
+		case 'e':
+			opt_e = 1;
+			break;
+		default:
+			usage();
+			/* Do not exit! */
+			break;
+	}
+
+	if (geteuid() != 0) {
+		fprintf(stderr, "sulogin: only root can run sulogin.\n");
+		exit(1);
+	}
+
+	/*
+	 *	See if we need to open an other tty device.
+	 */
+	saved_sigint  = signal(SIGINT,  SIG_IGN);
+	saved_sigtstp = signal(SIGQUIT, SIG_IGN);
+	saved_sigquit = signal(SIGTSTP, SIG_IGN);
+	if (optind < argc) tty = argv[optind];
+
+	if (tty || (tty = getenv("CONSOLE"))) {
+
+		if ((fd = open(tty, O_RDWR)) < 0) {
+			perror(tty);
+			fd = dup(0);
+		}
+
+		if (!isatty(fd)) {
+			fprintf(stderr, "%s: not a tty\n", tty);
+			close(fd);
+		} else {
+
+			/*
+			 *	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();
+				}
+
+				signal(SIGHUP, SIG_IGN);
+				if (ttypgrp > 0)
+					ioctl(0, TIOCNOTTY, (char *)1);
+				signal(SIGHUP, SIG_DFL);
+				close(0);
+				close(1);
+				close(2);
+				if (fd > 2)
+					close(fd);
+				if ((fd = open(tty, O_RDWR|O_NOCTTY)) < 0) {
+					perror(tty);
+				} else {
+					ioctl(0, TIOCSCTTY, (char *)1);
+					tcsetpgrp(fd, ppgrp);
+					dup2(fd, 0);
+					dup2(fd, 1);
+					dup2(fd, 2);
+					if (fd > 2)
+						close(fd);
+				}
+			} else
+				if (fd > 2)
+					close(fd);
+		}
+	} else if (getpid() == 1) {
+		/* We are init. We hence need to set a session anyway */
+		setsid();
+		if (ioctl(0, TIOCSCTTY, (char *)1))
+			perror("ioctl(TIOCSCTTY)");
+	}
+
+#if defined(SANE_TIO) && (SANE_TIO == 1)
+	fixtty();
+#endif
+
+	/*
+	 *	Get the root password.
+	 */
+	if ((pwd = getrootpwent(opt_e)) == NULL) {
+		fprintf(stderr, "sulogin: cannot open password database!\n");
+		sleep(2);
+	}
+
+	/*
+	 *	Ask for the password.
+	 */
+	while(pwd) {
+		if ((p = getpasswd(pwd->pw_passwd)) == NULL) break;
+		if (pwd->pw_passwd[0] == 0 ||
+		    strcmp(crypt(p, pwd->pw_passwd), pwd->pw_passwd) == 0)
+			sushell(pwd);
+		saved_sigquit = signal(SIGQUIT, SIG_IGN);
+		saved_sigtstp = signal(SIGTSTP, SIG_IGN);
+		saved_sigint  = signal(SIGINT,  SIG_IGN);
+		printf("Login incorrect.\n");
+	}
+
+	/*
+	 *	User pressed Control-D.
+	 */
+	return 0;
+}
-- 
1.7.9.2


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

* [PATCH 03/13] sulogin.8: refactor manpage
  2012-02-28 16:45 [PATCH 00/13] Initial import of sulogin Dave Reisner
  2012-02-28 16:45 ` [PATCH 01/13] fstab.5: fix misspelling of deprecated Dave Reisner
  2012-02-28 16:45 ` [PATCH 02/13] sulogin: initial import from sysvinit Dave Reisner
@ 2012-02-28 16:45 ` Dave Reisner
  2012-02-28 16:45 ` [PATCH 04/13] sulogin: whitespace fixes Dave Reisner
                   ` (11 subsequent siblings)
  14 siblings, 0 replies; 25+ messages in thread
From: Dave Reisner @ 2012-02-28 16:45 UTC (permalink / raw)
  To: util-linux; +Cc: Dave Reisner

- Use a more standard layout using .IP macros for options
- Avoid direct references to sysvinit

Signed-off-by: Dave Reisner <dreisner@archlinux.org>
---
 login-utils/sulogin.8 |   69 +++++++++++++++----------------------------------
 1 file changed, 21 insertions(+), 48 deletions(-)

diff --git a/login-utils/sulogin.8 b/login-utils/sulogin.8
index 4b5d153..e5d2f28 100644
--- a/login-utils/sulogin.8
+++ b/login-utils/sulogin.8
@@ -15,73 +15,46 @@
 .\" along with this program; if not, write to the Free Software
 .\" Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 .\"
-.TH SULOGIN 8 "17 Jan 2006" "" "Linux System Administrator's Manual"
+.TH SULOGIN 8 "28 Feb 2012" "" "Linux System Administrator's Manual"
 .SH NAME
 sulogin \- Single-user login
 .SH SYNOPSIS
 .B sulogin
-[ \fB\-e\fP ]
-[ \fB\-p\fP ]
-[ \fB\-t\fP \fISECONDS\fP ]
-[ \fITTY\fP ]
+.RB [ options ]
+.RB [ tty ]
 .SH DESCRIPTION
 .I sulogin
-is invoked by \fBinit(8)\fP when the system goes into single user mode.
-(This is done through an entry in \fIinittab(5)\fP.)
-\fBInit\fP also
-tries to execute \fIsulogin\fP when
-the boot loader (e.g., \fBgrub\fP(8))
-passes it the \fB\-b\fP option.
+is invoked by \fBinit\fP when the system goes into single user mode.
 .PP
-The user is prompted
+The user is prompted:
 .IP "" .5i
 Give root password for system maintenance
 .br
 (or type Control\-D for normal startup):
 .PP
 \fIsulogin\fP will be connected to the current terminal, or to the
-optional device that can be specified on the command line
+optional tty device that can be specified on the command line
 (typically \fB/dev/console\fP).
 .PP
-If the \fB\-t\fP option is used then the program only waits
-the given number of seconds for user input.
-.PP
-If the \fB\-p\fP option is used then the single-user shell is invoked
-with a \fIdash\fP as the first character in \fIargv[0]\fP.
-This causes the shell process to behave as a login shell.
-The default is \fInot\fP to do this,
-so that the shell will \fInot\fP read \fB/etc/profile\fP
-or \fB$HOME/.profile\fP at startup.
-.PP
-After the user exits the single-user shell,
-or presses control\-D at the prompt,
-the system will (continue to) boot to the default runlevel.
+After the user exits the single-user shell or presses control\-D at the
+prompt, the system will continue to boot.
+.SH OPTIONS
+.IP "\fB\-t \fIseconds\fP"
+Specify the maximum amount of time to wait for user input. By default,
+sulogin will wait forever.
+.IP "\fB\-p\fP"
+Specifying this option causes sulogin to start the shell process as a
+login shell.
+.IP "\fB\-e\fP"
+If the default method of obtaining the root password via \fBgetpwnam\fP(3) from
+the system fails, manually examine /etc/passwd and /etc/shadow to get the
+password. If they are damaged or nonexistent, sulogin will start a root shell
+without asking for a password. Only use the \fB\-e\fP option if you are sure
+the console is physically protected against unauthorized access.
 .SH ENVIRONMENT VARIABLES
 \fIsulogin\fP looks for the environment variable \fBSUSHELL\fP or
 \fBsushell\fP to determine what shell to start. If the environment variable
 is not set, it will try to execute root's shell from /etc/passwd. If that
 fails it will fall back to \fB/bin/sh\fP.
-.PP
-This is very valuable together with the \fB\-b\fP option to init. To boot
-the system into single user mode, with the root file system mounted read/write,
-using a special "fail safe" shell that is statically linked (this example
-is valid for the LILO bootprompt)
-.PP
-boot: linux \-b rw sushell=/sbin/sash
-.SH FALLBACK METHODS
-\fIsulogin\fP checks the root password using the standard method (getpwnam)
-first.
-Then, if the \fB\-e\fP option was specified,
-\fIsulogin\fP examines these files directly to find the root password:
-.PP
-/etc/passwd,
-.br
-/etc/shadow (if present)
-.PP
-If they are damaged or nonexistent, sulogin will start a root shell
-without asking for a password. Only use the \fB\-e\fP option if you
-are sure the console is physically protected against unauthorized access.
 .SH AUTHOR
 Miquel van Smoorenburg <miquels@cistron.nl>
-.SH SEE ALSO
-init(8), inittab(5).
-- 
1.7.9.2


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

* [PATCH 04/13] sulogin: whitespace fixes
  2012-02-28 16:45 [PATCH 00/13] Initial import of sulogin Dave Reisner
                   ` (2 preceding siblings ...)
  2012-02-28 16:45 ` [PATCH 03/13] sulogin.8: refactor manpage Dave Reisner
@ 2012-02-28 16:45 ` Dave Reisner
  2012-02-28 16:45 ` [PATCH 05/13] sulogin: replace older signal() with sigaction() Dave Reisner
                   ` (10 subsequent siblings)
  14 siblings, 0 replies; 25+ messages in thread
From: Dave Reisner @ 2012-02-28 16:45 UTC (permalink / raw)
  To: util-linux; +Cc: Dave Reisner

Use a code style more inline with the rest of the project.

Signed-off-by: Dave Reisner <dreisner@archlinux.org>
---
 login-utils/sulogin.c |  124 ++++++++++++++++++++++++++++---------------------
 1 file changed, 71 insertions(+), 53 deletions(-)

diff --git a/login-utils/sulogin.c b/login-utils/sulogin.c
index 969fc52..a444af1 100644
--- a/login-utils/sulogin.c
+++ b/login-utils/sulogin.c
@@ -75,8 +75,7 @@ static void (*saved_sigquit) = SIG_DFL;
  *	Fix the tty modes and set reasonable defaults.
  *	(I'm not sure if this is needed under Linux, but..)
  */
-static
-void fixtty(void)
+static void fixtty(void)
 {
 	struct termios tty;
 	int serial;
@@ -157,25 +156,29 @@ void alrm_handler(int sig)
  *	password is checked for traditional-style DES and
  *	FreeBSD-style MD5 encryption.
  */
-static
-int valid(const char *pass)
+static int valid(const char *pass)
 {
 	const char *s;
 	char id[5];
 	size_t len;
 	off_t off;
 
-	if (pass[0] == 0) return 1;
+	if (pass[0] == 0)
+		return 1;
 #if CHECK_MD5
-	if (pass[0] != '$') goto check_des;
+	if (pass[0] != '$')
+		goto check_des;
 
 	/*
 	 *	up to 4 bytes for the signature e.g. $1$
 	 */
-	for(s = pass+1; *s && *s != '$'; s++)
-		;
-	if (*s++ != '$') return 0;
-	if ((off = (off_t)(s-pass)) > 4 || off < 3) return 0;
+	for (s = pass+1; *s && *s != '$'; s++);
+
+	if (*s++ != '$')
+		return 0;
+
+	if ((off = (off_t)(s-pass)) > 4 || off < 3)
+		return 0;
 
 	memset(id, '\0', sizeof(id));
 	strncpy(id, pass, off);
@@ -183,26 +186,33 @@ int valid(const char *pass)
 	/*
 	 *	up to 16 bytes for the salt
 	 */
-	for(; *s && *s != '$'; s++)
-		;
-	if (*s++ != '$') return 0;
-	if ((off_t)(s-pass) > 16) return 0;
+	for (; *s && *s != '$'; s++);
+
+	if (*s++ != '$')
+		return 0;
+
+	if ((off_t)(s-pass) > 16)
+		return 0;
+
 	len = strlen(s);
 
 	/*
 	 *	the MD5 hash (128 bits or 16 bytes) encoded in base64 = 22 bytes
 	 */
-	if ((strcmp(id, "$1$") == 0) && (len < 22 || len > 24)) return 0;
+	if ((strcmp(id, "$1$") == 0) && (len < 22 || len > 24))
+		return 0;
 
 	/*
 	 *	the SHA-256 hash 43 bytes
 	 */
-	if ((strcmp(id, "$5$") == 0) && (len < 42 || len > 44)) return 0;
+	if ((strcmp(id, "$5$") == 0) && (len < 42 || len > 44))
+		return 0;
 
 	/*
 	 *      the SHA-512 hash 86 bytes
 	 */
-	if ((strcmp(id, "$6$") == 0) && (len < 85 || len > 87)) return 0;
+	if ((strcmp(id, "$6$") == 0) && (len < 85 || len > 87))
+		return 0;
 
 	/*
 	 *	e.g. Blowfish hash
@@ -211,12 +221,15 @@ int valid(const char *pass)
 check_des:
 #endif
 #if CHECK_DES
-	if (strlen(pass) != 13) return 0;
+	if (strlen(pass) != 13)
+		return 0;
+
 	for (s = pass; *s; s++) {
 		if ((*s < '0' || *s > '9') &&
 		    (*s < 'a' || *s > 'z') &&
 		    (*s < 'A' || *s > 'Z') &&
-		    *s != '.' && *s != '/') return 0;
+		    *s != '.' && *s != '/')
+			return 0;
 	}
 #endif
 	return 1;
@@ -225,17 +238,16 @@ check_des:
 /*
  *	Set a variable if the value is not NULL.
  */
-static
-void set(char **var, char *val)
+static void set(char **var, char *val)
 {
-	if (val) *var = val;
+	if (val)
+		*var = val;
 }
 
 /*
  *	Get the root password entry.
  */
-static
-struct passwd *getrootpwent(int try_manually)
+static struct passwd *getrootpwent(int try_manually)
 {
 	static struct passwd pwd;
 	struct passwd *pw;
@@ -253,7 +265,8 @@ struct passwd *getrootpwent(int try_manually)
 	    !strcmp(pw->pw_passwd, "x") &&
 	    (spw = getspnam("root")))
 		pw->pw_passwd = spw->sp_pwdp;
-	if (pw || !try_manually) return pw;
+	if (pw || !try_manually)
+		return pw;
 
 	/*
 	 *	If we come here, we could not retrieve the root
@@ -276,13 +289,13 @@ struct passwd *getrootpwent(int try_manually)
 	/*
 	 *	Find root in the password file.
 	 */
-	while((p = fgets(line, 256, fp)) != NULL) {
+	while ((p = fgets(line, 256, fp)) != NULL) {
 		if (strncmp(line, "root:", 5) != 0)
 			continue;
 		p += 5;
 		set(&pwd.pw_passwd, strsep(&p, ":"));
-		(void)strsep(&p, ":");
-		(void)strsep(&p, ":");
+		strsep(&p, ":");
+		strsep(&p, ":");
 		set(&pwd.pw_gecos, strsep(&p, ":"));
 		set(&pwd.pw_dir, strsep(&p, ":"));
 		set(&pwd.pw_shell, strsep(&p, "\n"));
@@ -299,7 +312,8 @@ struct passwd *getrootpwent(int try_manually)
 		fprintf(stderr, "%s: no entry for root\n", F_PASSWD);
 		return &pwd;
 	}
-	if (valid(pwd.pw_passwd)) return &pwd;
+	if (valid(pwd.pw_passwd))
+		return &pwd;
 
 	/*
 	 *	The password is invalid. If there is a
@@ -310,7 +324,7 @@ struct passwd *getrootpwent(int try_manually)
 		fprintf(stderr, "%s: root password garbled\n", F_PASSWD);
 		return &pwd;
 	}
-	while((p = fgets(sline, 256, fp)) != NULL) {
+	while ((p = fgets(sline, 256, fp)) != NULL) {
 		if (strncmp(sline, "root:", 5) != 0)
 			continue;
 		p += 5;
@@ -329,7 +343,8 @@ struct passwd *getrootpwent(int try_manually)
 	}
 	if (!valid(pwd.pw_passwd)) {
 		fprintf(stderr, "%s: root password garbled\n", F_SHADOW);
-		strcpy(pwd.pw_passwd, ""); }
+		strcpy(pwd.pw_passwd, "");
+	}
 	return &pwd;
 }
 
@@ -337,8 +352,7 @@ struct passwd *getrootpwent(int try_manually)
  *	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(char *crypted)
 {
 	struct sigaction sa;
 	struct termios old, tty;
@@ -370,12 +384,13 @@ char *getpasswd(char *crypted)
 	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 < (int)sizeof(pass) && pass[i]; i++)
+		for (i = 0; i < (int)sizeof(pass) && pass[i]; i++)
 			if (pass[i] == '\r' || pass[i] == '\n') {
 				pass[i] = 0;
 				break;
@@ -391,8 +406,7 @@ char *getpasswd(char *crypted)
 /*
  *	Password was OK, execute a shell.
  */
-static
-void sushell(struct passwd *pwd)
+static void sushell(struct passwd *pwd)
 {
 	char shell[128];
 	char home[128];
@@ -402,7 +416,7 @@ void sushell(struct passwd *pwd)
 	/*
 	 *	Set directory and shell.
 	 */
-	(void)chdir(pwd->pw_dir);
+	chdir(pwd->pw_dir);
 	if ((p = getenv("SUSHELL")) != NULL)
 		sushell = p;
 	else if ((p = getenv("sushell")) != NULL)
@@ -438,15 +452,16 @@ void sushell(struct passwd *pwd)
 	signal(SIGQUIT, saved_sigquit);
 #ifdef WITH_SELINUX
 	if (is_selinux_enabled() > 0) {
-	  security_context_t scon=NULL;
-	  char *seuser=NULL;
-	  char *level=NULL;
-	  if (getseuserbyname("root", &seuser, &level) == 0)
-		  if (get_default_context_with_level(seuser, level, 0, &scon) == 0) {
-			  if (setexeccon(scon) != 0) 
-				  fprintf(stderr, "setexeccon faile\n");
-			  freecon(scon);
-		  }
+		security_context_t scon=NULL;
+		char *seuser=NULL;
+		char *level=NULL;
+		if (getseuserbyname("root", &seuser, &level) == 0) {
+			if (get_default_context_with_level(seuser, level, 0, &scon) == 0) {
+				if (setexeccon(scon) != 0)
+					fprintf(stderr, "setexeccon failed\n");
+				freecon(scon);
+			}
+		}
 		free(seuser);
 		free(level);
 	}
@@ -465,8 +480,7 @@ void sushell(struct passwd *pwd)
 	perror(STATICSH);
 }
 
-static
-void usage(void)
+static void usage(void)
 {
 	fprintf(stderr, "Usage: sulogin [-e] [-p] [-t timeout] [tty device]\n");
 }
@@ -484,7 +498,8 @@ int main(int argc, char **argv)
 	 *	See if we have a timeout flag.
 	 */
 	opterr = 0;
-	while((c = getopt(argc, argv, "ept:")) != EOF) switch(c) {
+	while ((c = getopt(argc, argv, "ept:")) != EOF) {
+		switch(c) {
 		case 't':
 			timeout = atoi(optarg);
 			break;
@@ -498,6 +513,7 @@ int main(int argc, char **argv)
 			usage();
 			/* Do not exit! */
 			break;
+		}
 	}
 
 	if (geteuid() != 0) {
@@ -511,7 +527,8 @@ int main(int argc, char **argv)
 	saved_sigint  = signal(SIGINT,  SIG_IGN);
 	saved_sigtstp = signal(SIGQUIT, SIG_IGN);
 	saved_sigquit = signal(SIGTSTP, SIG_IGN);
-	if (optind < argc) tty = argv[optind];
+	if (optind < argc)
+		tty = argv[optind];
 
 	if (tty || (tty = getenv("CONSOLE"))) {
 
@@ -587,8 +604,9 @@ int main(int argc, char **argv)
 	/*
 	 *	Ask for the password.
 	 */
-	while(pwd) {
-		if ((p = getpasswd(pwd->pw_passwd)) == NULL) break;
+	while (pwd) {
+		if ((p = getpasswd(pwd->pw_passwd)) == NULL)
+			break;
 		if (pwd->pw_passwd[0] == 0 ||
 		    strcmp(crypt(p, pwd->pw_passwd), pwd->pw_passwd) == 0)
 			sushell(pwd);
-- 
1.7.9.2


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

* [PATCH 05/13] sulogin: replace older signal() with sigaction()
  2012-02-28 16:45 [PATCH 00/13] Initial import of sulogin Dave Reisner
                   ` (3 preceding siblings ...)
  2012-02-28 16:45 ` [PATCH 04/13] sulogin: whitespace fixes Dave Reisner
@ 2012-02-28 16:45 ` Dave Reisner
  2012-02-28 16:45 ` [PATCH 06/13] sulogin: remove CHECK_{DES,MD5} defines Dave Reisner
                   ` (9 subsequent siblings)
  14 siblings, 0 replies; 25+ messages in thread
From: Dave Reisner @ 2012-02-28 16:45 UTC (permalink / raw)
  To: util-linux; +Cc: Dave Reisner

This provides a more reliable means of saving and restoring signal
handlers and avoids ugly (invalid) function pointer assignments. This
also removes the #ifdef blocking usage of a GCC attribute, which is
widely used in the rest of the codebase.

Signed-off-by: Dave Reisner <dreisner@archlinux.org>
---
 login-utils/sulogin.c |   55 +++++++++++++++++++++++++++++++------------------
 1 file changed, 35 insertions(+), 20 deletions(-)

diff --git a/login-utils/sulogin.c b/login-utils/sulogin.c
index a444af1..27099ab 100644
--- a/login-utils/sulogin.c
+++ b/login-utils/sulogin.c
@@ -62,9 +62,9 @@
 static int timeout;
 static int profile;
 
-static void (*saved_sigint)  = SIG_DFL;
-static void (*saved_sigtstp) = SIG_DFL;
-static void (*saved_sigquit) = SIG_DFL;
+struct sigaction saved_sigint;
+struct sigaction saved_sigtstp;
+struct sigaction saved_sigquit;
 
 #ifndef IUCLC
 #  define IUCLC	0
@@ -142,13 +142,27 @@ out:
 /*
  *	Called at timeout.
  */
-static
-# ifdef __GNUC__
-void alrm_handler(int sig __attribute__((unused)))
-# else
-void alrm_handler(int sig)
-# endif
+static void alrm_handler(int sig __attribute__((unused)))
 {
+	return;
+}
+
+static void mask_signal(int signal, void (*handler)(int),
+		struct sigaction *origaction)
+{
+	struct sigaction newaction;
+
+	newaction.sa_handler = handler;
+	sigemptyset(&newaction.sa_mask);
+	newaction.sa_flags = 0;
+
+	sigaction(signal, NULL, origaction);
+	sigaction(signal, &newaction, NULL);
+}
+
+static void unmask_signal(int signal, struct sigaction *sa)
+{
+	sigaction(signal, sa, NULL);
 }
 
 /*
@@ -447,9 +461,9 @@ static void sushell(struct passwd *pwd)
 	 *	Try to execute a shell.
 	 */
 	setenv("SHELL", sushell, 1);
-	signal(SIGINT,  saved_sigint);
-	signal(SIGTSTP, saved_sigtstp);
-	signal(SIGQUIT, saved_sigquit);
+	unmask_signal(SIGINT, &saved_sigint);
+	unmask_signal(SIGTSTP, &saved_sigtstp);
+	unmask_signal(SIGQUIT, &saved_sigquit);
 #ifdef WITH_SELINUX
 	if (is_selinux_enabled() > 0) {
 		security_context_t scon=NULL;
@@ -493,6 +507,7 @@ int main(int argc, char **argv)
 	int c, fd = -1;
 	int opt_e = 0;
 	pid_t pid, pgrp, ppgrp, ttypgrp;
+	struct sigaction saved_sighup;
 
 	/*
 	 *	See if we have a timeout flag.
@@ -524,9 +539,9 @@ int main(int argc, char **argv)
 	/*
 	 *	See if we need to open an other tty device.
 	 */
-	saved_sigint  = signal(SIGINT,  SIG_IGN);
-	saved_sigtstp = signal(SIGQUIT, SIG_IGN);
-	saved_sigquit = signal(SIGTSTP, SIG_IGN);
+	mask_signal(SIGQUIT, SIG_IGN, &saved_sigquit);
+	mask_signal(SIGTSTP, SIG_IGN, &saved_sigtstp);
+	mask_signal(SIGINT,  SIG_IGN, &saved_sigint);
 	if (optind < argc)
 		tty = argv[optind];
 
@@ -558,10 +573,10 @@ int main(int argc, char **argv)
 					setsid();
 				}
 
-				signal(SIGHUP, SIG_IGN);
+				sigaction(SIGHUP, NULL, &saved_sighup);
 				if (ttypgrp > 0)
 					ioctl(0, TIOCNOTTY, (char *)1);
-				signal(SIGHUP, SIG_DFL);
+				sigaction(SIGHUP, &saved_sighup, NULL);
 				close(0);
 				close(1);
 				close(2);
@@ -610,9 +625,9 @@ int main(int argc, char **argv)
 		if (pwd->pw_passwd[0] == 0 ||
 		    strcmp(crypt(p, pwd->pw_passwd), pwd->pw_passwd) == 0)
 			sushell(pwd);
-		saved_sigquit = signal(SIGQUIT, SIG_IGN);
-		saved_sigtstp = signal(SIGTSTP, SIG_IGN);
-		saved_sigint  = signal(SIGINT,  SIG_IGN);
+		mask_signal(SIGQUIT, SIG_IGN, &saved_sigquit);
+		mask_signal(SIGTSTP, SIG_IGN, &saved_sigtstp);
+		mask_signal(SIGINT,  SIG_IGN, &saved_sigint);
 		printf("Login incorrect.\n");
 	}
 
-- 
1.7.9.2


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

* [PATCH 06/13] sulogin: remove CHECK_{DES,MD5} defines
  2012-02-28 16:45 [PATCH 00/13] Initial import of sulogin Dave Reisner
                   ` (4 preceding siblings ...)
  2012-02-28 16:45 ` [PATCH 05/13] sulogin: replace older signal() with sigaction() Dave Reisner
@ 2012-02-28 16:45 ` Dave Reisner
  2012-02-28 16:45 ` [PATCH 07/13] sulogin: remove USE_ONELINE and SANE_TIO defines Dave Reisner
                   ` (8 subsequent siblings)
  14 siblings, 0 replies; 25+ messages in thread
From: Dave Reisner @ 2012-02-28 16:45 UTC (permalink / raw)
  To: util-linux; +Cc: Dave Reisner

Remove these always-true defines along with their #ifdef statements.

Signed-off-by: Dave Reisner <dreisner@archlinux.org>
---
 login-utils/sulogin.c |    7 -------
 1 file changed, 7 deletions(-)

diff --git a/login-utils/sulogin.c b/login-utils/sulogin.c
index 27099ab..218b17e 100644
--- a/login-utils/sulogin.c
+++ b/login-utils/sulogin.c
@@ -51,9 +51,6 @@
 #  include <selinux/get_context_list.h>
 #endif
 
-#define CHECK_DES	1
-#define CHECK_MD5	1
-
 #define F_PASSWD	"/etc/passwd"
 #define F_SHADOW	"/etc/shadow"
 #define BINSH		"/bin/sh"
@@ -179,7 +176,6 @@ static int valid(const char *pass)
 
 	if (pass[0] == 0)
 		return 1;
-#if CHECK_MD5
 	if (pass[0] != '$')
 		goto check_des;
 
@@ -233,8 +229,6 @@ static int valid(const char *pass)
 	 */
 	return 1;
 check_des:
-#endif
-#if CHECK_DES
 	if (strlen(pass) != 13)
 		return 0;
 
@@ -245,7 +239,6 @@ check_des:
 		    *s != '.' && *s != '/')
 			return 0;
 	}
-#endif
 	return 1;
 }
 
-- 
1.7.9.2


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

* [PATCH 07/13] sulogin: remove USE_ONELINE and SANE_TIO defines
  2012-02-28 16:45 [PATCH 00/13] Initial import of sulogin Dave Reisner
                   ` (5 preceding siblings ...)
  2012-02-28 16:45 ` [PATCH 06/13] sulogin: remove CHECK_{DES,MD5} defines Dave Reisner
@ 2012-02-28 16:45 ` Dave Reisner
  2012-02-28 16:45 ` [PATCH 08/13] sulogin: use size_t for iterator to avoid cast Dave Reisner
                   ` (7 subsequent siblings)
  14 siblings, 0 replies; 25+ messages in thread
From: Dave Reisner @ 2012-02-28 16:45 UTC (permalink / raw)
  To: util-linux; +Cc: Dave Reisner

This was only ever compiled in for a single distro, with no clear
indication of why.

Signed-off-by: Dave Reisner <dreisner@archlinux.org>
---
 login-utils/sulogin.c |   85 +------------------------------------------------
 1 file changed, 1 insertion(+), 84 deletions(-)

diff --git a/login-utils/sulogin.c b/login-utils/sulogin.c
index 218b17e..b6cbd05 100644
--- a/login-utils/sulogin.c
+++ b/login-utils/sulogin.c
@@ -63,79 +63,6 @@ struct sigaction saved_sigint;
 struct sigaction saved_sigtstp;
 struct sigaction saved_sigquit;
 
-#ifndef IUCLC
-#  define IUCLC	0
-#endif
-
-#if defined(SANE_TIO) && (SANE_TIO == 1)
-/*
- *	Fix the tty modes and set reasonable defaults.
- *	(I'm not sure if this is needed under Linux, but..)
- */
-static void fixtty(void)
-{
-	struct termios tty;
-	int serial;
-
-	/* Skip serial console */
-	if (ioctl (0, TIOCMGET, (char*)&serial) == 0)
-		goto out;
-	/* Expected error */
-	serial = errno = 0;
-
-	tcgetattr(0, &tty);
-
-	/* Use defaults of <sys/ttydefaults.h> for base settings */
-	tty.c_iflag |= TTYDEF_IFLAG;
-	tty.c_oflag |= TTYDEF_OFLAG;
-	tty.c_lflag |= TTYDEF_LFLAG;
-	tty.c_cflag |= (TTYDEF_SPEED | TTYDEF_CFLAG);
-
-	/* Sane setting, allow eight bit characters, no carriage return delay
-	 * the same result as `stty sane cr0 pass8'
-	 */
-	tty.c_iflag |=  (BRKINT | ICRNL | IMAXBEL);
-#ifdef IUTF8 /* Not defined on FreeBSD */
-	tty.c_iflag |= IUTF8;
-#endif /* IUTF8 */
-	tty.c_iflag &= ~(IGNBRK | INLCR | IGNCR | IXOFF | IUCLC | IXANY | ISTRIP);
-	tty.c_oflag |=  (OPOST | ONLCR | NL0 | CR0 | TAB0 | BS0 | VT0 | FF0);
-	tty.c_oflag &= ~(OLCUC | OCRNL | ONOCR | ONLRET | OFILL | OFDEL |\
-			 NLDLY|CRDLY|TABDLY|BSDLY|VTDLY|FFDLY);
-	tty.c_lflag |=  (ISIG | ICANON | IEXTEN | ECHO|ECHOE|ECHOK|ECHOCTL|ECHOKE);
-	tty.c_lflag &= ~(ECHONL | NOFLSH | XCASE | TOSTOP | ECHOPRT);
-	tty.c_cflag |=  (CREAD | CS8 | B9600);
-	tty.c_cflag &= ~(PARENB);
-
-	/* VTIME and VMIN can overlap with VEOF and VEOL since they are
-	 * only used for non-canonical mode. We just set the at the
-	 * beginning, so nothing bad should happen.
-	 */
-	tty.c_cc[VTIME]    = 0;
-	tty.c_cc[VMIN]     = 1;
-	tty.c_cc[VINTR]    = CINTR;
-	tty.c_cc[VQUIT]    = CQUIT;
-	tty.c_cc[VERASE]   = CERASE; /* ASCII DEL (0177) */
-	tty.c_cc[VKILL]    = CKILL;
-	tty.c_cc[VEOF]     = CEOF;
-	tty.c_cc[VSWTC]    = _POSIX_VDISABLE;
-	tty.c_cc[VSTART]   = CSTART;
-	tty.c_cc[VSTOP]    = CSTOP;
-	tty.c_cc[VSUSP]    = CSUSP;
-	tty.c_cc[VEOL]     = _POSIX_VDISABLE;
-	tty.c_cc[VREPRINT] = CREPRINT;
-	tty.c_cc[VDISCARD] = CDISCARD;
-	tty.c_cc[VWERASE]  = CWERASE;
-	tty.c_cc[VLNEXT]   = CLNEXT;
-	tty.c_cc[VEOL2]    = _POSIX_VDISABLE;
-
-	tcsetattr(0, TCSANOW, &tty);
-out:
-	return;
-}
-#endif
-
-
 /*
  *	Called at timeout.
  */
@@ -366,18 +293,12 @@ static char *getpasswd(char *crypted)
 	static char pass[128];
 	char *ret = pass;
 	int i;
-#if defined(USE_ONELINE)
-	if (crypted[0])
-		printf("Give root password for login: ");
-	else
-		printf("Press enter for login: ");
-#else
+
 	if (crypted[0])
 		printf("Give root password for maintenance\n");
 	else
 		printf("Press enter for maintenance");
 	printf("(or type Control-D to continue): ");
-#endif
 	fflush(stdout);
 
 	tcgetattr(0, &old);
@@ -597,10 +518,6 @@ int main(int argc, char **argv)
 			perror("ioctl(TIOCSCTTY)");
 	}
 
-#if defined(SANE_TIO) && (SANE_TIO == 1)
-	fixtty();
-#endif
-
 	/*
 	 *	Get the root password.
 	 */
-- 
1.7.9.2


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

* [PATCH 08/13] sulogin: use size_t for iterator to avoid cast
  2012-02-28 16:45 [PATCH 00/13] Initial import of sulogin Dave Reisner
                   ` (6 preceding siblings ...)
  2012-02-28 16:45 ` [PATCH 07/13] sulogin: remove USE_ONELINE and SANE_TIO defines Dave Reisner
@ 2012-02-28 16:45 ` Dave Reisner
  2012-02-28 16:45 ` [PATCH 09/13] sulogin: get rid of calls to /bin/sash Dave Reisner
                   ` (6 subsequent siblings)
  14 siblings, 0 replies; 25+ messages in thread
From: Dave Reisner @ 2012-02-28 16:45 UTC (permalink / raw)
  To: util-linux; +Cc: Dave Reisner

Signed-off-by: Dave Reisner <dreisner@archlinux.org>
---
 login-utils/sulogin.c |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/login-utils/sulogin.c b/login-utils/sulogin.c
index b6cbd05..5894f85 100644
--- a/login-utils/sulogin.c
+++ b/login-utils/sulogin.c
@@ -292,7 +292,7 @@ static char *getpasswd(char *crypted)
 	struct termios old, tty;
 	static char pass[128];
 	char *ret = pass;
-	int i;
+	size_t i;
 
 	if (crypted[0])
 		printf("Give root password for maintenance\n");
@@ -318,7 +318,7 @@ static char *getpasswd(char *crypted)
 	if (read(0, pass, sizeof(pass) - 1) <= 0)
 		ret = NULL;
 	else {
-		for (i = 0; i < (int)sizeof(pass) && pass[i]; i++)
+		for (i = 0; i < sizeof(pass) && pass[i]; i++)
 			if (pass[i] == '\r' || pass[i] == '\n') {
 				pass[i] = 0;
 				break;
-- 
1.7.9.2


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

* [PATCH 09/13] sulogin: get rid of calls to /bin/sash
  2012-02-28 16:45 [PATCH 00/13] Initial import of sulogin Dave Reisner
                   ` (7 preceding siblings ...)
  2012-02-28 16:45 ` [PATCH 08/13] sulogin: use size_t for iterator to avoid cast Dave Reisner
@ 2012-02-28 16:45 ` Dave Reisner
  2012-02-28 16:45 ` [PATCH 10/13] sulogin: use pathnames.h for file locations Dave Reisner
                   ` (5 subsequent siblings)
  14 siblings, 0 replies; 25+ messages in thread
From: Dave Reisner @ 2012-02-28 16:45 UTC (permalink / raw)
  To: util-linux; +Cc: Dave Reisner

This probably doesn't exist on most systems, and if the root's shell and
/bin/sh fail to execute, it seems unlikely that /bin/sash will save us.

Signed-off-by: Dave Reisner <dreisner@archlinux.org>
---
 login-utils/sulogin.c |    7 -------
 1 file changed, 7 deletions(-)

diff --git a/login-utils/sulogin.c b/login-utils/sulogin.c
index 5894f85..451bca4 100644
--- a/login-utils/sulogin.c
+++ b/login-utils/sulogin.c
@@ -54,7 +54,6 @@
 #define F_PASSWD	"/etc/passwd"
 #define F_SHADOW	"/etc/shadow"
 #define BINSH		"/bin/sh"
-#define STATICSH	"/bin/sash"
 
 static int timeout;
 static int profile;
@@ -400,12 +399,6 @@ static void sushell(struct passwd *pwd)
 	setenv("SHELL", BINSH, 1);
 	execl(BINSH, profile ? "-sh" : "sh", NULL);
 	perror(BINSH);
-
-	/* Fall back to staticly linked shell if both the users shell
-	   and /bin/sh failed to execute. */
-	setenv("SHELL", STATICSH, 1);
-	execl(STATICSH, STATICSH, NULL);
-	perror(STATICSH);
 }
 
 static void usage(void)
-- 
1.7.9.2


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

* [PATCH 10/13] sulogin: use pathnames.h for file locations
  2012-02-28 16:45 [PATCH 00/13] Initial import of sulogin Dave Reisner
                   ` (8 preceding siblings ...)
  2012-02-28 16:45 ` [PATCH 09/13] sulogin: get rid of calls to /bin/sash Dave Reisner
@ 2012-02-28 16:45 ` Dave Reisner
  2012-02-28 16:45 ` [PATCH 11/13] sulogin: header/include cleanup Dave Reisner
                   ` (4 subsequent siblings)
  14 siblings, 0 replies; 25+ messages in thread
From: Dave Reisner @ 2012-02-28 16:45 UTC (permalink / raw)
  To: util-linux; +Cc: Dave Reisner

This covers /etc/shadow and /etc/passwd. We don't have a define for
/bin/sh -- just replace the macro with the hardcoded string as done
elsewhere.

Signed-off-by: Dave Reisner <dreisner@archlinux.org>
---
 login-utils/sulogin.c |   26 ++++++++++++--------------
 1 file changed, 12 insertions(+), 14 deletions(-)

diff --git a/login-utils/sulogin.c b/login-utils/sulogin.c
index 451bca4..17ad044 100644
--- a/login-utils/sulogin.c
+++ b/login-utils/sulogin.c
@@ -51,9 +51,7 @@
 #  include <selinux/get_context_list.h>
 #endif
 
-#define F_PASSWD	"/etc/passwd"
-#define F_SHADOW	"/etc/shadow"
-#define BINSH		"/bin/sh"
+#include "pathnames.h"
 
 static int timeout;
 static int profile;
@@ -214,8 +212,8 @@ static struct passwd *getrootpwent(int try_manually)
 	pwd.pw_uid = 0;
 	pwd.pw_gid = 0;
 
-	if ((fp = fopen(F_PASSWD, "r")) == NULL) {
-		perror(F_PASSWD);
+	if ((fp = fopen(_PATH_PASSWD, "r")) == NULL) {
+		perror(_PATH_PASSWD);
 		return &pwd;
 	}
 
@@ -242,7 +240,7 @@ static struct passwd *getrootpwent(int try_manually)
 	 *	or not found, return.
 	 */
 	if (p == NULL) {
-		fprintf(stderr, "%s: no entry for root\n", F_PASSWD);
+		fprintf(stderr, "%s: no entry for root\n", _PATH_PASSWD);
 		return &pwd;
 	}
 	if (valid(pwd.pw_passwd))
@@ -253,8 +251,8 @@ static struct passwd *getrootpwent(int try_manually)
 	 *	shadow password, try it.
 	 */
 	strcpy(pwd.pw_passwd, "");
-	if ((fp = fopen(F_SHADOW, "r")) == NULL) {
-		fprintf(stderr, "%s: root password garbled\n", F_PASSWD);
+	if ((fp = fopen(_PATH_SHADOW_PASSWD, "r")) == NULL) {
+		fprintf(stderr, "%s: root password garbled\n", _PATH_PASSWD);
 		return &pwd;
 	}
 	while ((p = fgets(sline, 256, fp)) != NULL) {
@@ -271,11 +269,11 @@ static struct passwd *getrootpwent(int try_manually)
 	 *	NULL it, and return.
 	 */
 	if (p == NULL) {
-		fprintf(stderr, "%s: no entry for root\n", F_SHADOW);
+		fprintf(stderr, "%s: no entry for root\n", _PATH_SHADOW_PASSWD);
 		strcpy(pwd.pw_passwd, "");
 	}
 	if (!valid(pwd.pw_passwd)) {
-		fprintf(stderr, "%s: root password garbled\n", F_SHADOW);
+		fprintf(stderr, "%s: root password garbled\n", _PATH_SHADOW_PASSWD);
 		strcpy(pwd.pw_passwd, "");
 	}
 	return &pwd;
@@ -352,7 +350,7 @@ static void sushell(struct passwd *pwd)
 		if (pwd->pw_shell[0])
 			sushell = pwd->pw_shell;
 		else
-			sushell = BINSH;
+			sushell = "/bin/sh";
 	}
 	if ((p = strrchr(sushell, '/')) == NULL)
 		p = sushell;
@@ -396,9 +394,9 @@ static void sushell(struct passwd *pwd)
 	execl(sushell, shell, NULL);
 	perror(sushell);
 
-	setenv("SHELL", BINSH, 1);
-	execl(BINSH, profile ? "-sh" : "sh", NULL);
-	perror(BINSH);
+	setenv("SHELL", "/bin/sh", 1);
+	execl("/bin/sh", profile ? "-sh" : "sh", NULL);
+	perror("/bin/sh");
 }
 
 static void usage(void)
-- 
1.7.9.2


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

* [PATCH 11/13] sulogin: header/include cleanup
  2012-02-28 16:45 [PATCH 00/13] Initial import of sulogin Dave Reisner
                   ` (9 preceding siblings ...)
  2012-02-28 16:45 ` [PATCH 10/13] sulogin: use pathnames.h for file locations Dave Reisner
@ 2012-02-28 16:45 ` Dave Reisner
  2012-02-28 16:45 ` [PATCH 12/13] sulogin: use a more standard usage output Dave Reisner
                   ` (3 subsequent siblings)
  14 siblings, 0 replies; 25+ messages in thread
From: Dave Reisner @ 2012-02-28 16:45 UTC (permalink / raw)
  To: util-linux; +Cc: Dave Reisner

- use our own crypt.h compile time check
- remove ttydefaults.h include -- get this via termios.h, the same as
  agetty

Signed-off-by: Dave Reisner <dreisner@archlinux.org>
---
 login-utils/sulogin.c |    3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/login-utils/sulogin.c b/login-utils/sulogin.c
index 17ad044..f276a3e 100644
--- a/login-utils/sulogin.c
+++ b/login-utils/sulogin.c
@@ -39,10 +39,9 @@
 #include <pwd.h>
 #include <shadow.h>
 #include <termios.h>
-#include <sys/ttydefaults.h>
 #include <errno.h>
 #include <sys/ioctl.h>
-#if defined(__GLIBC__)
+#ifdef HAVE_CRYPT_H
 #  include <crypt.h>
 #endif
 
-- 
1.7.9.2


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

* [PATCH 12/13] sulogin: use a more standard usage output
  2012-02-28 16:45 [PATCH 00/13] Initial import of sulogin Dave Reisner
                   ` (10 preceding siblings ...)
  2012-02-28 16:45 ` [PATCH 11/13] sulogin: header/include cleanup Dave Reisner
@ 2012-02-28 16:45 ` Dave Reisner
  2012-02-28 16:45 ` [PATCH 13/13] sulogin: add i18n strings Dave Reisner
                   ` (2 subsequent siblings)
  14 siblings, 0 replies; 25+ messages in thread
From: Dave Reisner @ 2012-02-28 16:45 UTC (permalink / raw)
  To: util-linux; +Cc: Dave Reisner

Signed-off-by: Dave Reisner <dreisner@archlinux.org>
---
 login-utils/sulogin.c |   24 ++++++++++++++++++++----
 1 file changed, 20 insertions(+), 4 deletions(-)

diff --git a/login-utils/sulogin.c b/login-utils/sulogin.c
index f276a3e..6cb075c 100644
--- a/login-utils/sulogin.c
+++ b/login-utils/sulogin.c
@@ -50,6 +50,8 @@
 #  include <selinux/get_context_list.h>
 #endif
 
+#include "c.h"
+#include "nls.h"
 #include "pathnames.h"
 
 static int timeout;
@@ -398,9 +400,20 @@ static void sushell(struct passwd *pwd)
 	perror("/bin/sh");
 }
 
-static void usage(void)
+static void usage(FILE *out)
 {
-	fprintf(stderr, "Usage: sulogin [-e] [-p] [-t timeout] [tty device]\n");
+	fprintf(out, USAGE_HEADER);
+	fprintf(out, _(
+			" %s [options] [tty device]\n"), program_invocation_short_name);
+
+	fprintf(out, USAGE_OPTIONS);
+	fprintf(out, _(
+			" -p        start a login shell\n"
+			" -t SEC    set max time to wait for a password (default: no limit)\n"
+			" -e        examine shadow files directly if getpwnam(3) fails\n"
+			" -h        display this help message\n"));
+
+	fprintf(out, _("\nFor more information see sulogin(8).\n"));
 }
 
 int main(int argc, char **argv)
@@ -417,7 +430,7 @@ int main(int argc, char **argv)
 	 *	See if we have a timeout flag.
 	 */
 	opterr = 0;
-	while ((c = getopt(argc, argv, "ept:")) != EOF) {
+	while ((c = getopt(argc, argv, "ehpt:")) != EOF) {
 		switch(c) {
 		case 't':
 			timeout = atoi(optarg);
@@ -428,8 +441,11 @@ int main(int argc, char **argv)
 		case 'e':
 			opt_e = 1;
 			break;
+		case 'h':
+			usage(stdout);
+			return 0;
 		default:
-			usage();
+			usage(stderr);
 			/* Do not exit! */
 			break;
 		}
-- 
1.7.9.2


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

* [PATCH 13/13] sulogin: add i18n strings
  2012-02-28 16:45 [PATCH 00/13] Initial import of sulogin Dave Reisner
                   ` (11 preceding siblings ...)
  2012-02-28 16:45 ` [PATCH 12/13] sulogin: use a more standard usage output Dave Reisner
@ 2012-02-28 16:45 ` Dave Reisner
  2012-02-28 16:48 ` [PATCH 00/13] Initial import of sulogin Dave Reisner
  2012-03-12 14:20 ` sulogin merged into util-linux (Re: [PATCH 00/13] Initial import of sulogin) Karel Zak
  14 siblings, 0 replies; 25+ messages in thread
From: Dave Reisner @ 2012-02-28 16:45 UTC (permalink / raw)
  To: util-linux; +Cc: Dave Reisner

Signed-off-by: Dave Reisner <dreisner@archlinux.org>
---
 login-utils/sulogin.c |   26 ++++++++++++++------------
 1 file changed, 14 insertions(+), 12 deletions(-)

diff --git a/login-utils/sulogin.c b/login-utils/sulogin.c
index 6cb075c..bed1fd3 100644
--- a/login-utils/sulogin.c
+++ b/login-utils/sulogin.c
@@ -241,7 +241,7 @@ static struct passwd *getrootpwent(int try_manually)
 	 *	or not found, return.
 	 */
 	if (p == NULL) {
-		fprintf(stderr, "%s: no entry for root\n", _PATH_PASSWD);
+		fprintf(stderr, _("%s: no entry for root\n"), _PATH_PASSWD);
 		return &pwd;
 	}
 	if (valid(pwd.pw_passwd))
@@ -253,7 +253,7 @@ static struct passwd *getrootpwent(int try_manually)
 	 */
 	strcpy(pwd.pw_passwd, "");
 	if ((fp = fopen(_PATH_SHADOW_PASSWD, "r")) == NULL) {
-		fprintf(stderr, "%s: root password garbled\n", _PATH_PASSWD);
+		fprintf(stderr, _("%s: root password garbled\n"), _PATH_PASSWD);
 		return &pwd;
 	}
 	while ((p = fgets(sline, 256, fp)) != NULL) {
@@ -270,11 +270,11 @@ static struct passwd *getrootpwent(int try_manually)
 	 *	NULL it, and return.
 	 */
 	if (p == NULL) {
-		fprintf(stderr, "%s: no entry for root\n", _PATH_SHADOW_PASSWD);
+		fprintf(stderr, _("%s: no entry for root\n"), _PATH_SHADOW_PASSWD);
 		strcpy(pwd.pw_passwd, "");
 	}
 	if (!valid(pwd.pw_passwd)) {
-		fprintf(stderr, "%s: root password garbled\n", _PATH_SHADOW_PASSWD);
+		fprintf(stderr, _("%s: root password garbled\n"), _PATH_SHADOW_PASSWD);
 		strcpy(pwd.pw_passwd, "");
 	}
 	return &pwd;
@@ -293,10 +293,10 @@ static char *getpasswd(char *crypted)
 	size_t i;
 
 	if (crypted[0])
-		printf("Give root password for maintenance\n");
+		printf(_("Give root password for maintenance\n"));
 	else
-		printf("Press enter for maintenance");
-	printf("(or type Control-D to continue): ");
+		printf(_("Press enter for maintenance"));
+	printf(_("(or type Control-D to continue): "));
 	fflush(stdout);
 
 	tcgetattr(0, &old);
@@ -384,7 +384,7 @@ static void sushell(struct passwd *pwd)
 		if (getseuserbyname("root", &seuser, &level) == 0) {
 			if (get_default_context_with_level(seuser, level, 0, &scon) == 0) {
 				if (setexeccon(scon) != 0)
-					fprintf(stderr, "setexeccon failed\n");
+					fprintf(stderr, _("setexeccon failed\n"));
 				freecon(scon);
 			}
 		}
@@ -409,7 +409,7 @@ static void usage(FILE *out)
 	fprintf(out, USAGE_OPTIONS);
 	fprintf(out, _(
 			" -p        start a login shell\n"
-			" -t SEC    set max time to wait for a password (default: no limit)\n"
+			" -t SEC    max time to wait for a password (default: no limit)\n"
 			" -e        examine shadow files directly if getpwnam(3) fails\n"
 			" -h        display this help message\n"));
 
@@ -452,7 +452,8 @@ int main(int argc, char **argv)
 	}
 
 	if (geteuid() != 0) {
-		fprintf(stderr, "sulogin: only root can run sulogin.\n");
+		fprintf(stderr, _("%s: only root can run this program.\n"),
+				program_invocation_short_name);
 		exit(1);
 	}
 
@@ -528,7 +529,8 @@ int main(int argc, char **argv)
 	 *	Get the root password.
 	 */
 	if ((pwd = getrootpwent(opt_e)) == NULL) {
-		fprintf(stderr, "sulogin: cannot open password database!\n");
+		fprintf(stderr, _("%s: cannot open password database.\n"),
+				program_invocation_short_name);
 		sleep(2);
 	}
 
@@ -544,7 +546,7 @@ int main(int argc, char **argv)
 		mask_signal(SIGQUIT, SIG_IGN, &saved_sigquit);
 		mask_signal(SIGTSTP, SIG_IGN, &saved_sigtstp);
 		mask_signal(SIGINT,  SIG_IGN, &saved_sigint);
-		printf("Login incorrect.\n");
+		printf(_("Login incorrect\n"));
 	}
 
 	/*
-- 
1.7.9.2


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

* Re: [PATCH 00/13] Initial import of sulogin
  2012-02-28 16:45 [PATCH 00/13] Initial import of sulogin Dave Reisner
                   ` (12 preceding siblings ...)
  2012-02-28 16:45 ` [PATCH 13/13] sulogin: add i18n strings Dave Reisner
@ 2012-02-28 16:48 ` Dave Reisner
  2012-10-12 12:53   ` [util-linux] " Dr. Werner Fink
  2012-03-12 14:20 ` sulogin merged into util-linux (Re: [PATCH 00/13] Initial import of sulogin) Karel Zak
  14 siblings, 1 reply; 25+ messages in thread
From: Dave Reisner @ 2012-02-28 16:48 UTC (permalink / raw)
  To: util-linux

On Tue, Feb 28, 2012 at 11:45:08AM -0500, Dave Reisner wrote:
> This is an initial stab at importing sulogin from sysvinit and making it a bit
> more universal. I've removed the distro specific code and brought the rest of
> it more in line with the style of the remainder of the repo. I've also added
> internationalization and cleaned up the manpage.

Err, forgot... these patches live in a repo below on the 'sulogin'
branch:

  git://code.falconindy.com/util-linux.git

> Dave Reisner (13):
>   fstab.5: fix misspelling of deprecated
>   sulogin: initial import from sysvinit
>   sulogin.8: refactor manpage
>   sulogin: whitespace fixes
>   sulogin: replace older signal() with sigaction()
>   sulogin: remove CHECK_{DES,MD5} defines
>   sulogin: remove USE_ONELINE and SANE_TIO defines
>   sulogin: use size_t for iterator to avoid cast
>   sulogin: get rid of calls to /bin/sash
>   sulogin: use pathnames.h for file locations
>   sulogin: header/include cleanup
>   sulogin: use a more standard usage output
>   sulogin: add i18n strings
> 
>  login-utils/Makefile.am |    6 +-
>  login-utils/sulogin.8   |   60 +++++
>  login-utils/sulogin.c   |  556 +++++++++++++++++++++++++++++++++++++++++++++++
>  mount/fstab.5           |    2 +-
>  4 files changed, 622 insertions(+), 2 deletions(-)
>  create mode 100644 login-utils/sulogin.8
>  create mode 100644 login-utils/sulogin.c
> 
> -- 
> 1.7.9.2
> 

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

* Re: [PATCH 02/13] sulogin: initial import from sysvinit
  2012-02-28 16:45 ` [PATCH 02/13] sulogin: initial import from sysvinit Dave Reisner
@ 2012-02-28 18:45   ` Davidlohr Bueso
  0 siblings, 0 replies; 25+ messages in thread
From: Davidlohr Bueso @ 2012-02-28 18:45 UTC (permalink / raw)
  To: Dave Reisner; +Cc: util-linux, Dave Reisner

On Tue, 2012-02-28 at 11:45 -0500, Dave Reisner wrote:
> Import the source and manpage of sulogin. Only the selinux #ifdef is
> changed to match our autotool setup.
> 
> Signed-off-by: Dave Reisner <dreisner@archlinux.org>

When adding new code to util-linux, specially importing legacy tools, it
would be good to integrate them correctly with our "API" and standards,
otherwise someone else will have to do that.  Please look at other,
already existing tools.

Just *some* comments below.

Thanks,
Davidlohr

> ---
>  login-utils/Makefile.am |    6 +-
>  login-utils/sulogin.8   |   87 +++++++
>  login-utils/sulogin.c   |  605 +++++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 697 insertions(+), 1 deletion(-)
>  create mode 100644 login-utils/sulogin.8
>  create mode 100644 login-utils/sulogin.c
> 
> diff --git a/login-utils/Makefile.am b/login-utils/Makefile.am
> index 47274bf..6d5f4e9 100644
> --- a/login-utils/Makefile.am
> +++ b/login-utils/Makefile.am
> @@ -14,6 +14,7 @@ endif
>  if BUILD_LOGIN_UTILS
>  
>  bin_PROGRAMS += login
> +sbin_PROGRAMS += sulogin
>  usrbin_exec_PROGRAMS += \
>  	chfn \
>  	chsh \
> @@ -26,7 +27,8 @@ dist_man_MANS += \
>  	login.1 \
>  	newgrp.1 \
>  	vigr.8 \
> -	vipw.8
> +	vipw.8 \
> +	sulogin.8
>  
>  # login, chfn and chsh libs
>  login_ldadd_common =
> @@ -57,6 +59,7 @@ chsh_LDADD = $(login_ldadd_common)
>  login_LDADD = $(login_ldadd_common)
>  newgrp_LDADD =
>  vipw_LDADD =
> +sulogin_LDADD =
>  
>  chfn_CFLAGS = $(SUID_CFLAGS) $(AM_CFLAGS)
>  chsh_CFLAGS = $(SUID_CFLAGS) $(AM_CFLAGS)
> @@ -70,6 +73,7 @@ login_ldadd_common += -lpam -lpam_misc
>  
>  if HAVE_LIBCRYPT
>  newgrp_LDADD += -lcrypt
> +sulogin_LDADD += -lcrypt
>  endif
>  
>  if HAVE_AUDIT
> diff --git a/login-utils/sulogin.8 b/login-utils/sulogin.8
> new file mode 100644
> index 0000000..4b5d153
> --- /dev/null
> +++ b/login-utils/sulogin.8
> @@ -0,0 +1,87 @@
> +'\" -*- coding: UTF-8 -*-
> +.\" Copyright (C) 1998-2006 Miquel van Smoorenburg.
> +.\"
> +.\" 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
> +.\" the Free Software Foundation; either version 2 of the License, or
> +.\" (at your option) any later version.
> +.\"
> +.\" This program is distributed in the hope that it will be useful,
> +.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
> +.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +.\" GNU General Public License for more details.
> +.\"
> +.\" You should have received a copy of the GNU General Public License
> +.\" along with this program; if not, write to the Free Software
> +.\" Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
> +.\"
> +.TH SULOGIN 8 "17 Jan 2006" "" "Linux System Administrator's Manual"
> +.SH NAME
> +sulogin \- Single-user login
> +.SH SYNOPSIS
> +.B sulogin
> +[ \fB\-e\fP ]
> +[ \fB\-p\fP ]
> +[ \fB\-t\fP \fISECONDS\fP ]
> +[ \fITTY\fP ]
> +.SH DESCRIPTION
> +.I sulogin
> +is invoked by \fBinit(8)\fP when the system goes into single user mode.
> +(This is done through an entry in \fIinittab(5)\fP.)
> +\fBInit\fP also
> +tries to execute \fIsulogin\fP when
> +the boot loader (e.g., \fBgrub\fP(8))
> +passes it the \fB\-b\fP option.
> +.PP
> +The user is prompted
> +.IP "" .5i
> +Give root password for system maintenance
> +.br
> +(or type Control\-D for normal startup):
> +.PP
> +\fIsulogin\fP will be connected to the current terminal, or to the
> +optional device that can be specified on the command line
> +(typically \fB/dev/console\fP).
> +.PP
> +If the \fB\-t\fP option is used then the program only waits
> +the given number of seconds for user input.
> +.PP
> +If the \fB\-p\fP option is used then the single-user shell is invoked
> +with a \fIdash\fP as the first character in \fIargv[0]\fP.
> +This causes the shell process to behave as a login shell.
> +The default is \fInot\fP to do this,
> +so that the shell will \fInot\fP read \fB/etc/profile\fP
> +or \fB$HOME/.profile\fP at startup.
> +.PP
> +After the user exits the single-user shell,
> +or presses control\-D at the prompt,
> +the system will (continue to) boot to the default runlevel.
> +.SH ENVIRONMENT VARIABLES
> +\fIsulogin\fP looks for the environment variable \fBSUSHELL\fP or
> +\fBsushell\fP to determine what shell to start. If the environment variable
> +is not set, it will try to execute root's shell from /etc/passwd. If that
> +fails it will fall back to \fB/bin/sh\fP.
> +.PP
> +This is very valuable together with the \fB\-b\fP option to init. To boot
> +the system into single user mode, with the root file system mounted read/write,
> +using a special "fail safe" shell that is statically linked (this example
> +is valid for the LILO bootprompt)
> +.PP
> +boot: linux \-b rw sushell=/sbin/sash
> +.SH FALLBACK METHODS
> +\fIsulogin\fP checks the root password using the standard method (getpwnam)
> +first.
> +Then, if the \fB\-e\fP option was specified,
> +\fIsulogin\fP examines these files directly to find the root password:
> +.PP
> +/etc/passwd,
> +.br
> +/etc/shadow (if present)
> +.PP
> +If they are damaged or nonexistent, sulogin will start a root shell
> +without asking for a password. Only use the \fB\-e\fP option if you
> +are sure the console is physically protected against unauthorized access.
> +.SH AUTHOR
> +Miquel van Smoorenburg <miquels@cistron.nl>
> +.SH SEE ALSO
> +init(8), inittab(5).
> diff --git a/login-utils/sulogin.c b/login-utils/sulogin.c
> new file mode 100644
> index 0000000..969fc52
> --- /dev/null
> +++ b/login-utils/sulogin.c
> @@ -0,0 +1,605 @@
> +/*
> + * sulogin	This program gives Linux machines a reasonable
> + *		secure way to boot single user. It forces the
> + *		user to supply the root password before a
> + *		shell is started.
> + *
> + *		If there is a shadow password file and the
> + *		encrypted root password is "x" the shadow
> + *		password will be used.
> + *
> + * Version:	@(#)sulogin 2.85-3 23-Apr-2003 miquels@cistron.nl
> + *
> + * Copyright (C) 1998-2003 Miquel van Smoorenburg.
> + *
> + * 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
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + * 
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + * 
> + * You should have received a copy of the GNU General Public License
> + * 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/types.h>
> +#include <sys/stat.h>
> +#include <stdio.h>
> +#include <string.h>
> +#include <stdlib.h>
> +#include <unistd.h>
> +#include <fcntl.h>
> +#include <signal.h>
> +#include <pwd.h>
> +#include <shadow.h>
> +#include <termios.h>
> +#include <sys/ttydefaults.h>
> +#include <errno.h>
> +#include <sys/ioctl.h>
> +#if defined(__GLIBC__)
> +#  include <crypt.h>
> +#endif
> +
> +#ifdef HAVE_LIBSELINUX
> +#  include <selinux/selinux.h>
> +#  include <selinux/get_context_list.h>
> +#endif
> +
> +#define CHECK_DES	1
> +#define CHECK_MD5	1
> +
> +#define F_PASSWD	"/etc/passwd"
> +#define F_SHADOW	"/etc/shadow"
> +#define BINSH		"/bin/sh"
> +#define STATICSH	"/bin/sash"
> +
> +static int timeout;
> +static int profile;
> +
> +static void (*saved_sigint)  = SIG_DFL;
> +static void (*saved_sigtstp) = SIG_DFL;
> +static void (*saved_sigquit) = SIG_DFL;
> +
> +#ifndef IUCLC
> +#  define IUCLC	0
> +#endif
> +
> +#if defined(SANE_TIO) && (SANE_TIO == 1)
> +/*
> + *	Fix the tty modes and set reasonable defaults.
> + *	(I'm not sure if this is needed under Linux, but..)
> + */
> +static
> +void fixtty(void)
> +{
> +	struct termios tty;
> +	int serial;
> +
> +	/* Skip serial console */
> +	if (ioctl (0, TIOCMGET, (char*)&serial) == 0)
> +		goto out;
> +	/* Expected error */
> +	serial = errno = 0;
> +
> +	tcgetattr(0, &tty);
> +
> +	/* Use defaults of <sys/ttydefaults.h> for base settings */
> +	tty.c_iflag |= TTYDEF_IFLAG;
> +	tty.c_oflag |= TTYDEF_OFLAG;
> +	tty.c_lflag |= TTYDEF_LFLAG;
> +	tty.c_cflag |= (TTYDEF_SPEED | TTYDEF_CFLAG);
> +
> +	/* Sane setting, allow eight bit characters, no carriage return delay
> +	 * the same result as `stty sane cr0 pass8'
> +	 */
> +	tty.c_iflag |=  (BRKINT | ICRNL | IMAXBEL);
> +#ifdef IUTF8 /* Not defined on FreeBSD */
> +	tty.c_iflag |= IUTF8;
> +#endif /* IUTF8 */
> +	tty.c_iflag &= ~(IGNBRK | INLCR | IGNCR | IXOFF | IUCLC | IXANY | ISTRIP);
> +	tty.c_oflag |=  (OPOST | ONLCR | NL0 | CR0 | TAB0 | BS0 | VT0 | FF0);
> +	tty.c_oflag &= ~(OLCUC | OCRNL | ONOCR | ONLRET | OFILL | OFDEL |\
> +			 NLDLY|CRDLY|TABDLY|BSDLY|VTDLY|FFDLY);
> +	tty.c_lflag |=  (ISIG | ICANON | IEXTEN | ECHO|ECHOE|ECHOK|ECHOCTL|ECHOKE);
> +	tty.c_lflag &= ~(ECHONL | NOFLSH | XCASE | TOSTOP | ECHOPRT);
> +	tty.c_cflag |=  (CREAD | CS8 | B9600);
> +	tty.c_cflag &= ~(PARENB);

ouch, ugly!

> +
> +	/* VTIME and VMIN can overlap with VEOF and VEOL since they are
> +	 * only used for non-canonical mode. We just set the at the
> +	 * beginning, so nothing bad should happen.
> +	 */
> +	tty.c_cc[VTIME]    = 0;
> +	tty.c_cc[VMIN]     = 1;
> +	tty.c_cc[VINTR]    = CINTR;
> +	tty.c_cc[VQUIT]    = CQUIT;
> +	tty.c_cc[VERASE]   = CERASE; /* ASCII DEL (0177) */
> +	tty.c_cc[VKILL]    = CKILL;
> +	tty.c_cc[VEOF]     = CEOF;
> +	tty.c_cc[VSWTC]    = _POSIX_VDISABLE;
> +	tty.c_cc[VSTART]   = CSTART;
> +	tty.c_cc[VSTOP]    = CSTOP;
> +	tty.c_cc[VSUSP]    = CSUSP;
> +	tty.c_cc[VEOL]     = _POSIX_VDISABLE;
> +	tty.c_cc[VREPRINT] = CREPRINT;
> +	tty.c_cc[VDISCARD] = CDISCARD;
> +	tty.c_cc[VWERASE]  = CWERASE;
> +	tty.c_cc[VLNEXT]   = CLNEXT;
> +	tty.c_cc[VEOL2]    = _POSIX_VDISABLE;
> +
> +	tcsetattr(0, TCSANOW, &tty);
> +out:
> +	return;
> +}
> +#endif
> +
> +
> +/*
> + *	Called at timeout.
> + */
> +static
> +# ifdef __GNUC__
> +void alrm_handler(int sig __attribute__((unused)))
> +# else
> +void alrm_handler(int sig)
> +# endif
> +{
> +}
> +
> +/*
> + *	See if an encrypted password is valid. The encrypted
> + *	password is checked for traditional-style DES and
> + *	FreeBSD-style MD5 encryption.
> + */
> +static
> +int valid(const char *pass)
> +{
> +	const char *s;
> +	char id[5];
> +	size_t len;
> +	off_t off;
> +
> +	if (pass[0] == 0) return 1;
> +#if CHECK_MD5
> +	if (pass[0] != '$') goto check_des;
> +
> +	/*
> +	 *	up to 4 bytes for the signature e.g. $1$
> +	 */
> +	for(s = pass+1; *s && *s != '$'; s++)
> +		;
> +	if (*s++ != '$') return 0;
> +	if ((off = (off_t)(s-pass)) > 4 || off < 3) return 0;
> +
> +	memset(id, '\0', sizeof(id));
> +	strncpy(id, pass, off);
> +
> +	/*
> +	 *	up to 16 bytes for the salt
> +	 */
> +	for(; *s && *s != '$'; s++)
> +		;
> +	if (*s++ != '$') return 0;
> +	if ((off_t)(s-pass) > 16) return 0;
> +	len = strlen(s);
> +
> +	/*
> +	 *	the MD5 hash (128 bits or 16 bytes) encoded in base64 = 22 bytes
> +	 */
> +	if ((strcmp(id, "$1$") == 0) && (len < 22 || len > 24)) return 0;
> +
> +	/*
> +	 *	the SHA-256 hash 43 bytes
> +	 */
> +	if ((strcmp(id, "$5$") == 0) && (len < 42 || len > 44)) return 0;
> +
> +	/*
> +	 *      the SHA-512 hash 86 bytes
> +	 */
> +	if ((strcmp(id, "$6$") == 0) && (len < 85 || len > 87)) return 0;
> +
> +	/*
> +	 *	e.g. Blowfish hash
> +	 */
> +	return 1;
> +check_des:
> +#endif
> +#if CHECK_DES
> +	if (strlen(pass) != 13) return 0;
> +	for (s = pass; *s; s++) {
> +		if ((*s < '0' || *s > '9') &&
> +		    (*s < 'a' || *s > 'z') &&
> +		    (*s < 'A' || *s > 'Z') &&
> +		    *s != '.' && *s != '/') return 0;
> +	}
> +#endif
> +	return 1;
> +}
> +
> +/*
> + *	Set a variable if the value is not NULL.
> + */
> +static
> +void set(char **var, char *val)
> +{
> +	if (val) *var = val;
> +}

macro?

> +
> +/*
> + *	Get the root password entry.
> + */
> +static
> +struct passwd *getrootpwent(int try_manually)
> +{
> +	static struct passwd pwd;
> +	struct passwd *pw;
> +	struct spwd *spw;
> +	FILE *fp;
> +	static char line[256];
> +	static char sline[256];
> +	char *p;
> +
> +	/*
> +	 *	First, we try to get the password the standard
> +	 *	way using normal library calls.
> +	 */
> +	if ((pw = getpwnam("root")) &&
> +	    !strcmp(pw->pw_passwd, "x") &&
> +	    (spw = getspnam("root")))
> +		pw->pw_passwd = spw->sp_pwdp;
> +	if (pw || !try_manually) return pw;
> +
> +	/*
> +	 *	If we come here, we could not retrieve the root
> +	 *	password through library calls and we try to
> +	 *	read the password and shadow files manually.
> +	 */
> +	pwd.pw_name = "root";
> +	pwd.pw_passwd = "";
> +	pwd.pw_gecos = "Super User";
> +	pwd.pw_dir = "/";
> +	pwd.pw_shell = "";
> +	pwd.pw_uid = 0;
> +	pwd.pw_gid = 0;
> +
> +	if ((fp = fopen(F_PASSWD, "r")) == NULL) {
> +		perror(F_PASSWD);
warn-family?

> +		return &pwd;
> +	}
> +
> +	/*
> +	 *	Find root in the password file.
> +	 */
> +	while((p = fgets(line, 256, fp)) != NULL) {
> +		if (strncmp(line, "root:", 5) != 0)
> +			continue;
> +		p += 5;
> +		set(&pwd.pw_passwd, strsep(&p, ":"));
> +		(void)strsep(&p, ":");
> +		(void)strsep(&p, ":");
> +		set(&pwd.pw_gecos, strsep(&p, ":"));
> +		set(&pwd.pw_dir, strsep(&p, ":"));
> +		set(&pwd.pw_shell, strsep(&p, "\n"));
> +		p = line;
> +		break;
> +	}
> +	fclose(fp);
> +
> +	/*
> +	 *	If the encrypted password is valid
> +	 *	or not found, return.
> +	 */
> +	if (p == NULL) {
> +		fprintf(stderr, "%s: no entry for root\n", F_PASSWD);
ditto.

> +		return &pwd;
> +	}
> +	if (valid(pwd.pw_passwd)) return &pwd;
> +
> +	/*
> +	 *	The password is invalid. If there is a
> +	 *	shadow password, try it.
> +	 */
> +	strcpy(pwd.pw_passwd, "");
> +	if ((fp = fopen(F_SHADOW, "r")) == NULL) {
> +		fprintf(stderr, "%s: root password garbled\n", F_PASSWD);
> +		return &pwd;
> +	}
> +	while((p = fgets(sline, 256, fp)) != NULL) {
> +		if (strncmp(sline, "root:", 5) != 0)
> +			continue;
> +		p += 5;
> +		set(&pwd.pw_passwd, strsep(&p, ":"));
> +		break;
> +	}
> +	fclose(fp);
> +
> +	/*
> +	 *	If the password is still invalid,
> +	 *	NULL it, and return.
> +	 */
> +	if (p == NULL) {
> +		fprintf(stderr, "%s: no entry for root\n", F_SHADOW);
> +		strcpy(pwd.pw_passwd, "");
> +	}
> +	if (!valid(pwd.pw_passwd)) {
> +		fprintf(stderr, "%s: root password garbled\n", F_SHADOW);
> +		strcpy(pwd.pw_passwd, ""); }
> +	return &pwd;
> +}
> +
> +/*
> + *	Ask for the password. Note that there is no
> + *	default timeout as we normally skip this during boot.
> + */
> +static
> +char *getpasswd(char *crypted)
> +{
> +	struct sigaction sa;
> +	struct termios old, tty;
> +	static char pass[128];
> +	char *ret = pass;
> +	int i;
> +#if defined(USE_ONELINE)
> +	if (crypted[0])
> +		printf("Give root password for login: ");
> +	else
> +		printf("Press enter for login: ");
> +#else
> +	if (crypted[0])
> +		printf("Give root password for maintenance\n");
> +	else
> +		printf("Press enter for maintenance");
> +	printf("(or type Control-D to continue): ");
> +#endif
> +	fflush(stdout);
> +
> +	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;
> +
> +	sa.sa_handler = alrm_handler;
> +	sa.sa_flags = 0;
> +	sigaction(SIGALRM, &sa, NULL);
> +	if (timeout) alarm(timeout);
> +
> +	if (read(0, pass, sizeof(pass) - 1) <= 0)
> +		ret = NULL;
> +	else {
> +		for(i = 0; i < (int)sizeof(pass) && pass[i]; i++)
> +			if (pass[i] == '\r' || pass[i] == '\n') {
> +				pass[i] = 0;
> +				break;
> +			}
> +	}
> +	alarm(0);
> +	tcsetattr(0, TCSANOW, &old);
> +	printf("\n");
> +
> +	return ret;
> +}
> +
> +/*
> + *	Password was OK, execute a shell.
> + */
> +static
> +void sushell(struct passwd *pwd)
> +{
> +	char shell[128];
> +	char home[128];
> +	char *p;
> +	char *sushell;
> +
> +	/*
> +	 *	Set directory and shell.
> +	 */
> +	(void)chdir(pwd->pw_dir);
> +	if ((p = getenv("SUSHELL")) != NULL)
> +		sushell = p;
> +	else if ((p = getenv("sushell")) != NULL)
> +		sushell = p;
> +	else {
> +		if (pwd->pw_shell[0])
> +			sushell = pwd->pw_shell;
> +		else
> +			sushell = BINSH;
> +	}
> +	if ((p = strrchr(sushell, '/')) == NULL)
> +		p = sushell;
> +	else
> +		p++;
> +	snprintf(shell, sizeof(shell), profile ? "-%s" : "%s", p);
> +
> +	/*
> +	 *	Set some important environment variables.
> +	 */
> +	getcwd(home, sizeof(home));
> +	setenv("HOME", home, 1);
> +	setenv("LOGNAME", "root", 1);
> +	setenv("USER", "root", 1);
> +	if (!profile)
> +		setenv("SHLVL","0",1);
> +
> +	/*
> +	 *	Try to execute a shell.
> +	 */
> +	setenv("SHELL", sushell, 1);
> +	signal(SIGINT,  saved_sigint);
> +	signal(SIGTSTP, saved_sigtstp);
> +	signal(SIGQUIT, saved_sigquit);
> +#ifdef WITH_SELINUX
> +	if (is_selinux_enabled() > 0) {
> +	  security_context_t scon=NULL;
> +	  char *seuser=NULL;
> +	  char *level=NULL;
> +	  if (getseuserbyname("root", &seuser, &level) == 0)
> +		  if (get_default_context_with_level(seuser, level, 0, &scon) == 0) {
> +			  if (setexeccon(scon) != 0) 
> +				  fprintf(stderr, "setexeccon faile\n");
> +			  freecon(scon);
> +		  }
> +		free(seuser);
> +		free(level);
> +	}
> +#endif
> +	execl(sushell, shell, NULL);
> +	perror(sushell);
> +
> +	setenv("SHELL", BINSH, 1);
> +	execl(BINSH, profile ? "-sh" : "sh", NULL);
> +	perror(BINSH);
> +
> +	/* Fall back to staticly linked shell if both the users shell
> +	   and /bin/sh failed to execute. */
> +	setenv("SHELL", STATICSH, 1);
> +	execl(STATICSH, STATICSH, NULL);
> +	perror(STATICSH);
> +}
> +
> +static
> +void usage(void)
> +{
> +	fprintf(stderr, "Usage: sulogin [-e] [-p] [-t timeout] [tty device]\n");
> +}

We are trying to standarize things like this.

> +
> +int main(int argc, char **argv)
> +{
> +	char *tty = NULL;
> +	char *p;
> +	struct passwd *pwd;
> +	int c, fd = -1;
> +	int opt_e = 0;
> +	pid_t pid, pgrp, ppgrp, ttypgrp;
> +
> +	/*
> +	 *	See if we have a timeout flag.
> +	 */

NLS?

> +	opterr = 0;
> +	while((c = getopt(argc, argv, "ept:")) != EOF) switch(c) {

longopts would be nice.

> +		case 't':
> +			timeout = atoi(optarg);
> +			break;
> +		case 'p':
> +			profile = 1;
> +			break;
> +		case 'e':
> +			opt_e = 1;
> +			break;
> +		default:
> +			usage();
> +			/* Do not exit! */
> +			break;
> +	}
> +
> +	if (geteuid() != 0) {
> +		fprintf(stderr, "sulogin: only root can run sulogin.\n");
> +		exit(1);
> +	}
> +
> +	/*
> +	 *	See if we need to open an other tty device.
> +	 */
> +	saved_sigint  = signal(SIGINT,  SIG_IGN);
> +	saved_sigtstp = signal(SIGQUIT, SIG_IGN);
> +	saved_sigquit = signal(SIGTSTP, SIG_IGN);
> +	if (optind < argc) tty = argv[optind];
> +
> +	if (tty || (tty = getenv("CONSOLE"))) {
> +
> +		if ((fd = open(tty, O_RDWR)) < 0) {
> +			perror(tty);
> +			fd = dup(0);
> +		}
> +
> +		if (!isatty(fd)) {
> +			fprintf(stderr, "%s: not a tty\n", tty);
> +			close(fd);
> +		} else {
> +
> +			/*
> +			 *	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();
> +				}
> +
> +				signal(SIGHUP, SIG_IGN);
> +				if (ttypgrp > 0)
> +					ioctl(0, TIOCNOTTY, (char *)1);
> +				signal(SIGHUP, SIG_DFL);
> +				close(0);
> +				close(1);
> +				close(2);
> +				if (fd > 2)
> +					close(fd);
> +				if ((fd = open(tty, O_RDWR|O_NOCTTY)) < 0) {
> +					perror(tty);
> +				} else {
> +					ioctl(0, TIOCSCTTY, (char *)1);
> +					tcsetpgrp(fd, ppgrp);
> +					dup2(fd, 0);
> +					dup2(fd, 1);
> +					dup2(fd, 2);
> +					if (fd > 2)
> +						close(fd);
> +				}
> +			} else
> +				if (fd > 2)
> +					close(fd);
> +		}
> +	} else if (getpid() == 1) {
> +		/* We are init. We hence need to set a session anyway */
> +		setsid();
> +		if (ioctl(0, TIOCSCTTY, (char *)1))
> +			perror("ioctl(TIOCSCTTY)");
> +	}
> +
> +#if defined(SANE_TIO) && (SANE_TIO == 1)
> +	fixtty();
> +#endif
> +
> +	/*
> +	 *	Get the root password.
> +	 */
> +	if ((pwd = getrootpwent(opt_e)) == NULL) {
> +		fprintf(stderr, "sulogin: cannot open password database!\n");
> +		sleep(2);
> +	}
> +
> +	/*
> +	 *	Ask for the password.
> +	 */
> +	while(pwd) {
> +		if ((p = getpasswd(pwd->pw_passwd)) == NULL) break;
> +		if (pwd->pw_passwd[0] == 0 ||
> +		    strcmp(crypt(p, pwd->pw_passwd), pwd->pw_passwd) == 0)
> +			sushell(pwd);
> +		saved_sigquit = signal(SIGQUIT, SIG_IGN);
> +		saved_sigtstp = signal(SIGTSTP, SIG_IGN);
> +		saved_sigint  = signal(SIGINT,  SIG_IGN);
> +		printf("Login incorrect.\n");
> +	}
> +
> +	/*
> +	 *	User pressed Control-D.
> +	 */
> +	return 0;
> +}



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

* sulogin merged into util-linux (Re: [PATCH 00/13] Initial import of sulogin)
  2012-02-28 16:45 [PATCH 00/13] Initial import of sulogin Dave Reisner
                   ` (13 preceding siblings ...)
  2012-02-28 16:48 ` [PATCH 00/13] Initial import of sulogin Dave Reisner
@ 2012-03-12 14:20 ` Karel Zak
  14 siblings, 0 replies; 25+ messages in thread
From: Karel Zak @ 2012-03-12 14:20 UTC (permalink / raw)
  To: Dave Reisner; +Cc: util-linux, Dave Reisner, Dr. Werner Fink, sysvinit-devel


 CC: to sysvinit upstream and Werner -- guys, sulogin has been merged
 into util-linux, because we believe that sulogin(8) is init independent
 util and it also seems that we can share some virtual console
 initialization code with agetty.

 It would be nice to mark sulogin in sysvinit as deprecated in favour of
 the util-linux version :-)

On Tue, Feb 28, 2012 at 11:45:08AM -0500, Dave Reisner wrote:
> This is an initial stab at importing sulogin from sysvinit and making it a bit
> more universal. I've removed the distro specific code and brought the rest of
> it more in line with the style of the remainder of the repo. I've also added
> internationalization and cleaned up the manpage.

Merged with some changes:

 - use err.h stuff
 - add long options
 - initialize NLS
 - add --disable-sulogin (enabled by default)
 - use virtual console initialization code from agetty (that's the
   same code used by Suse in the original sulogin in sysvinit).

Thanks!

    Karel

> Dave Reisner (13):
>   fstab.5: fix misspelling of deprecated
>   sulogin: initial import from sysvinit
>   sulogin.8: refactor manpage
>   sulogin: whitespace fixes
>   sulogin: replace older signal() with sigaction()
>   sulogin: remove CHECK_{DES,MD5} defines
>   sulogin: remove USE_ONELINE and SANE_TIO defines
>   sulogin: use size_t for iterator to avoid cast
>   sulogin: get rid of calls to /bin/sash
>   sulogin: use pathnames.h for file locations
>   sulogin: header/include cleanup
>   sulogin: use a more standard usage output
>   sulogin: add i18n strings

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

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

* Re: [util-linux] [PATCH 00/13] Initial import of sulogin
  2012-02-28 16:48 ` [PATCH 00/13] Initial import of sulogin Dave Reisner
@ 2012-10-12 12:53   ` Dr. Werner Fink
  2012-10-12 13:23     ` Karel Zak
  0 siblings, 1 reply; 25+ messages in thread
From: Dr. Werner Fink @ 2012-10-12 12:53 UTC (permalink / raw)
  To: util-linux

On Tue, Feb 28, 2012 at 11:48:40AM -0500, Dave Reisner wrote:
> On Tue, Feb 28, 2012 at 11:45:08AM -0500, Dave Reisner wrote:
> > This is an initial stab at importing sulogin from sysvinit and making it a bit
> > more universal. I've removed the distro specific code and brought the rest of
> > it more in line with the style of the remainder of the repo. I've also added
> > internationalization and cleaned up the manpage.
> 
> Err, forgot... these patches live in a repo below on the 'sulogin'
> branch:

Question: Why the code for multi console support was not included?
IMHO this is not distro specific code even if I've written this
code for sysvinit.

     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] 25+ messages in thread

* Re: [util-linux] [PATCH 00/13] Initial import of sulogin
  2012-10-12 12:53   ` [util-linux] " Dr. Werner Fink
@ 2012-10-12 13:23     ` Karel Zak
  2012-10-12 14:07       ` Dr. Werner Fink
  0 siblings, 1 reply; 25+ messages in thread
From: Karel Zak @ 2012-10-12 13:23 UTC (permalink / raw)
  To: util-linux

On Fri, Oct 12, 2012 at 02:53:09PM +0200, Dr. Werner Fink wrote:
> On Tue, Feb 28, 2012 at 11:48:40AM -0500, Dave Reisner wrote:
> > On Tue, Feb 28, 2012 at 11:45:08AM -0500, Dave Reisner wrote:
> > > This is an initial stab at importing sulogin from sysvinit and making it a bit
> > > more universal. I've removed the distro specific code and brought the rest of
> > > it more in line with the style of the remainder of the repo. I've also added
> > > internationalization and cleaned up the manpage.
> > 
> > Err, forgot... these patches live in a repo below on the 'sulogin'
> > branch:
> 
> Question: Why the code for multi console support was not included?

 Time... (the patch is one huge rewrite, I'd like to split it to more
 patches). I'm busy with some others things, so next week.

    Karel

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

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

* Re: [util-linux] [PATCH 00/13] Initial import of sulogin
  2012-10-12 13:23     ` Karel Zak
@ 2012-10-12 14:07       ` Dr. Werner Fink
  2012-11-09  8:38         ` Karel Zak
  2012-11-09 12:09         ` Karel Zak
  0 siblings, 2 replies; 25+ messages in thread
From: Dr. Werner Fink @ 2012-10-12 14:07 UTC (permalink / raw)
  To: util-linux

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

On Fri, Oct 12, 2012 at 03:23:36PM +0200, Karel Zak wrote:
> On Fri, Oct 12, 2012 at 02:53:09PM +0200, Dr. Werner Fink wrote:
> > On Tue, Feb 28, 2012 at 11:48:40AM -0500, Dave Reisner wrote:
> > > On Tue, Feb 28, 2012 at 11:45:08AM -0500, Dave Reisner wrote:
> > > > This is an initial stab at importing sulogin from sysvinit and making it a bit
> > > > more universal. I've removed the distro specific code and brought the rest of
> > > > it more in line with the style of the remainder of the repo. I've also added
> > > > internationalization and cleaned up the manpage.
> > > 
> > > Err, forgot... these patches live in a repo below on the 'sulogin'
> > > branch:
> > 
> > Question: Why the code for multi console support was not included?
> 
>  Time... (the patch is one huge rewrite, I'd like to split it to more
>  patches). I'm busy with some others things, so next week.

Yep, this missing feature is also known here ;)
Maybe the attached patch help as it only adds the /proc/consoles and
/sys/class/tty/ scanner into common lib and leave sulogin untouched.

The integration into sulogin.c could then be done later

   Werner

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

[-- Attachment #2: util-linux-consoles.patch --]
[-- Type: text/x-patch, Size: 13732 bytes --]

>From 308abe7d8d567adb22b48d242bcffe3d6e16aa68 Mon Sep 17 00:00:00 2001
From: Werner Fink <werner@suse.de>
Date: Fri, 12 Oct 2012 14:35:22 +0200
Subject: [PATCH] Add code to detect all system consoles

Signed-off-by: Werner Fink <werner@suse.de>
---
 include/Makemodule.am |    1 +
 include/consoles.h    |   48 +++++
 lib/Makemodule.am     |    1 +
 lib/consoles.c        |  507 +++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 557 insertions(+), 0 deletions(-)
 create mode 100644 include/consoles.h
 create mode 100644 lib/consoles.c

diff --git a/include/Makemodule.am b/include/Makemodule.am
index 9f9b78e..8905237 100644
--- a/include/Makemodule.am
+++ b/include/Makemodule.am
@@ -8,6 +8,7 @@ dist_noinst_HEADERS += \
 	include/canonicalize.h \
 	include/carefulputc.h \
 	include/closestream.h \
+	include/consoles.h \
 	include/cpuset.h \
 	include/crc32.h \
 	include/env.h \
diff --git a/include/consoles.h b/include/consoles.h
new file mode 100644
index 0000000..c669eb2
--- /dev/null
+++ b/include/consoles.h
@@ -0,0 +1,48 @@
+/*
+ * consoles.h	    Header file for routines to detect the system consoles
+ *
+ * Copyright (c) 2011 SuSE LINUX Products GmbH, All rights reserved.
+ *
+ * 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
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *  
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING); if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ * Author: Werner Fink <werner@suse.de>
+ */
+
+#include <sys/types.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <termios.h>
+
+struct chardata {
+	uint8_t	erase;
+	uint8_t kill;
+	uint8_t eol;
+	uint8_t parity;
+};
+struct console {
+	char *tty;
+	FILE *file;
+	uint32_t flags;
+	int fd, id;
+#define	CON_SERIAL	0x0001
+#define	CON_NOTTY	0x0002
+	pid_t pid;
+	struct chardata cp;
+	struct termios tio;
+	struct console *next;
+};
+extern struct console *consoles;
+extern int detect_consoles(const char *, int);
diff --git a/lib/Makemodule.am b/lib/Makemodule.am
index 33a3eb8..e51bd27 100644
--- a/lib/Makemodule.am
+++ b/lib/Makemodule.am
@@ -27,6 +27,7 @@ libcommon_la_SOURCES = \
 
 if LINUX
 libcommon_la_SOURCES += \
+	lib/consoles.c
 	lib/linux_version.c \
 	lib/loopdev.c
 endif
diff --git a/lib/consoles.c b/lib/consoles.c
new file mode 100644
index 0000000..7b3be9b
--- /dev/null
+++ b/lib/consoles.c
@@ -0,0 +1,507 @@
+/*
+ * consoles.c	    Routines to detect the system consoles
+ *
+ * Copyright (c) 2011 SuSE LINUX Products GmbH, All rights reserved.
+ *
+ * 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
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *  
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING); if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ * Author: Werner Fink <werner@suse.de>
+ */
+
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#ifdef __linux__
+#  include <sys/vt.h>
+#  include <sys/kd.h>
+#  include <linux/serial.h>
+#endif
+#include <fcntl.h>
+#include <dirent.h>
+#include <unistd.h>
+#include "consoles.h"
+
+#ifdef __linux__
+# include <linux/major.h>
+#endif
+
+#if !defined(__STDC_VERSION__) || (__STDC_VERSION__ < 199901L)
+# ifndef  typeof
+#  define typeof		__typeof__
+# endif
+# ifndef  restrict
+#  define restrict		__restrict__
+# endif
+#endif
+
+#define alignof(type)		((sizeof(type)+(sizeof(void*)-1)) & ~(sizeof(void*)-1))
+
+struct console *consoles;
+
+/*
+ * Read and allocate one line from file,
+ * the caller has to free the result
+ */
+static
+#ifdef __GNUC__
+__attribute__((__nonnull__))
+#endif
+char *oneline(const char *file)
+{
+	FILE *fp;
+	char *ret = (char*)0, *nl;
+	size_t len = 0;
+
+	if ((fp = fopen(file, "re")) == (FILE*)0)
+		goto err;
+	if (getline(&ret, &len, fp) < 0)
+		goto out;
+	if (len)
+		ret[len-1] = '\0';
+	if ((nl = strchr(ret, '\n')))
+		*nl = '\0';
+out:
+	fclose(fp);
+err:
+	return ret;
+}
+
+#ifdef __linux__
+/*
+ *  Read and determine active attribute for tty below
+ *  /sys/class/tty, the caller has to free the result.
+ */
+static
+__attribute__((__malloc__))
+char *actattr(const char *tty)
+{
+	char *ret = (char*)0;
+	char *path;
+
+	if (!tty || *tty == '\0')
+		goto err;
+
+	if (asprintf(&path, "/sys/class/tty/%s/active", tty) < 0)
+		goto err;
+
+	if ((ret = oneline(path)) == (char*)0)
+		goto out;
+out:
+	free(path);
+err:
+	return ret;
+}
+
+/*
+ * Read and determine device attribute for tty below
+ * /sys/class/tty.
+ */
+static
+dev_t devattr(const char *tty)
+{
+	unsigned int maj, min;
+	dev_t dev = 0;
+	char *path, *value;
+
+	if (!tty || *tty == '\0')
+		goto err;
+
+	if (asprintf(&path, "/sys/class/tty/%s/dev", tty) < 0)
+		goto err;
+
+	if ((value = oneline(path)) == (char*)0)
+		goto out;
+
+	if (sscanf(value, "%u:%u", &maj, &min) == 2)
+		dev = makedev(maj, min);
+	free(value);
+out:
+	free(path);
+err:
+	return dev;
+}
+#endif /* __linux__ */
+
+/*
+ * Search below /dev for the characer device in
+ * the local `dev_t comparedev' variable.
+ */
+static dev_t comparedev;
+static
+#ifdef __GNUC__
+__attribute__((__nonnull__,__malloc__,__hot__))
+#endif
+char* scandev(DIR *dir)
+{
+	char *name = (char*)0;
+	struct dirent *dent;
+	int fd;
+
+	fd = dirfd(dir);
+	rewinddir(dir);
+	while ((dent = readdir(dir))) {
+		char path[PATH_MAX];
+		struct stat st;
+		if (fstatat(fd, dent->d_name, &st, 0) < 0)
+			continue;
+		if (!S_ISCHR(st.st_mode))
+			continue;
+		if (comparedev != st.st_rdev)
+			continue;
+		if ((size_t)snprintf(path, sizeof(path), "/dev/%s", dent->d_name) >= sizeof(path))
+			continue;
+		name = realpath(path, NULL);
+		break;
+	}
+	return name;
+}
+
+/*
+ * Default control characters for an unknown terminal line.
+ */
+static
+struct chardata initcp = {
+	CERASE,
+	CKILL,
+	CTRL('r'),
+	0
+};
+
+/*
+ * Allocate an aligned `struct console' memory area,
+ * initialize its default values, and append it to
+ * the global linked list.
+ */
+
+static int concount;		/* Counter for console IDs */
+
+static
+#ifdef __GNUC__
+__attribute__((__nonnull__,__hot__))
+#endif
+void consalloc(char * name)
+{
+	struct console *restrict tail;
+
+	if (posix_memalign((void*)&tail, sizeof(void*), alignof(typeof(struct console))) != 0)
+		perror("memory allocation");
+
+	tail->next = (struct console*)0;
+	tail->tty = name;
+
+	tail->file = (FILE*)0;
+	tail->flags = 0;
+	tail->fd = -1;
+	tail->id = concount++;
+	tail->pid = 0;
+	memset(&tail->tio, 0, sizeof(tail->tio));
+	memcpy(&tail->cp, &initcp, sizeof(struct chardata));
+
+	if (!consoles)
+		consoles = tail;
+	else
+		consoles->next = tail;
+}
+
+/*
+ * Try to detect the real device(s) used for the system console
+ * /dev/console if but only if /dev/console is used.  On Linux
+ * this can be more than one device, e.g. a serial line as well
+ * as a virtual console as well as a simple printer.
+ *
+ * Returns 1 if stdout and stderr should be reconnected and 0
+ * otherwise.
+ */
+int detect_consoles(const char *device, int fallback)
+{
+	int fd, ret = 0;
+#ifdef __linux__
+	char *attrib, *cmdline;
+	FILE *fc;
+#endif
+	if (!device || *device == '\0')
+		fd = dup(fallback);
+	else {
+		fd = open(device, O_RDWR|O_NONBLOCK|O_NOCTTY|O_CLOEXEC);
+		ret = 1;
+	}
+
+	if (fd >= 0) {
+		DIR *dir;
+		char *name;
+		struct stat st;
+#ifdef TIOCGDEV
+		unsigned int devnum;
+#endif
+
+		if (fstat(fd, &st) < 0) {
+			close(fd);
+			goto fallback;
+		}
+		comparedev = st.st_rdev;
+
+		if (ret && (fstat(fallback, &st) < 0 || comparedev != st.st_rdev))
+			dup2(fd, fallback);
+#ifdef __linux__
+		/*
+		 * Check if the device detection for Linux system console should be used.
+		 */
+		if (comparedev == makedev(TTYAUX_MAJOR, 0)) {	/* /dev/tty	*/
+			close(fd);
+			device = "/dev/tty";
+			goto fallback;
+		}
+		if (comparedev == makedev(TTYAUX_MAJOR, 1)) {	/* /dev/console */
+			close(fd);
+			goto console;
+		}
+		if (comparedev == makedev(TTYAUX_MAJOR, 2)) {	/* /dev/ptmx	*/
+			close(fd);
+			device = "/dev/tty";
+			goto fallback;
+		}
+		if (comparedev == makedev(TTY_MAJOR, 0)) {	/* /dev/tty0	*/
+			struct vt_stat vt;
+			if (ioctl(fd, VT_GETSTATE, &vt) < 0) {
+				close(fd);
+				goto fallback;
+			}
+			comparedev = makedev(TTY_MAJOR, (int)vt.v_active);
+		}
+#endif
+#ifdef TIOCGDEV
+		if (ioctl (fd, TIOCGDEV, &devnum) < 0) {
+			close(fd);
+			goto fallback;
+		}
+		comparedev = (dev_t)devnum;
+#endif
+		close(fd);
+		dir = opendir("/dev");
+		if (!dir)
+			goto fallback;
+		name = scandev(dir);
+		if (name)
+			consalloc(name);
+		closedir(dir);
+		if (!consoles)
+			goto fallback;
+		return ret;
+	}
+#ifdef __linux__
+console:
+	/*
+	 * Detection of devices used for Linux system consolei using
+	 * the /proc/consoles API with kernel 2.6.38 and higher.
+	 */
+	if ((fc = fopen("/proc/consoles", "re"))) {
+		char fbuf[16];
+		int maj, min;
+		DIR *dir;
+		dir = opendir("/dev");
+		if (!dir) {
+			fclose(fc);
+			goto fallback;
+		}
+		while ((fscanf(fc, "%*s %*s (%[^)]) %d:%d", &fbuf[0], &maj, &min) == 3)) {
+			char * name;
+
+			if (!strchr(fbuf, 'E'))
+				continue;
+			comparedev = makedev(maj, min);
+
+			name = scandev(dir);
+			if (!name)
+				continue;
+			consalloc(name);
+		}
+		closedir(dir);
+		fclose(fc);
+		return ret;
+	}
+	/*
+	 * Detection of devices used for Linux system console using
+	 * the sysfs /sys/class/tty/ API with kernel 2.6.37 and higher.
+	 */
+	if ((attrib = actattr("console"))) {
+		char *words = attrib, *token;
+		DIR *dir;
+
+		dir = opendir("/dev");
+		if (!dir) {
+			free(attrib);
+			goto fallback;
+		}
+		while ((token = strsep(&words, " \t\r\n"))) {
+			char * name;
+
+			if (*token == '\0')
+				continue;
+			comparedev = devattr(token);
+			if (comparedev == makedev(TTY_MAJOR, 0)) {
+				char *tmp = actattr(token);
+				if (!tmp)
+					continue;
+				comparedev = devattr(tmp);
+				free(tmp);
+			}
+
+			name = scandev(dir);
+			if (!name)
+				continue;
+			consalloc(name);
+		}
+		closedir(dir);
+		free(attrib);
+		if (!consoles)
+			goto fallback;
+		return ret;
+
+	}
+	/*
+	 * Detection of devices used for Linux system console using
+	 * kernel parameter on the kernels command line.
+	 */
+	if ((cmdline = oneline("/proc/cmdline"))) {
+		char *words= cmdline, *token;
+		DIR *dir;
+
+		dir = opendir("/dev");
+		if (!dir) {
+			free(cmdline);
+			goto fallback;
+		}
+		while ((token = strsep(&words, " \t\r\n"))) {
+#ifdef TIOCGDEV
+			unsigned int devnum;
+#else
+			struct vt_stat vt;
+			struct stat st;
+#endif
+			char *colon, *name;
+
+			if (*token != 'c')
+				continue;
+
+			if (strncmp(token, "console=", 8) != 0)
+				continue;
+			token += 8;
+
+			if (strcmp(token, "brl") == 0)
+				token += 4;
+			if ((colon = strchr(token, ',')))
+				*colon = '\0';
+
+			if (asprintf(&name, "/dev/%s", token) < 0)
+				continue;
+
+			if ((fd = open(name, O_RDWR|O_NONBLOCK|O_NOCTTY|O_CLOEXEC)) < 0) {
+				free(name);
+				continue;
+			}
+			free(name);
+#ifdef TIOCGDEV
+			if (ioctl (fd, TIOCGDEV, &devnum) < 0) {
+				close(fd);
+				continue;
+			}
+			comparedev = (dev_t)devnum;
+#else
+			if (fstat(fd, &st) < 0) {
+				close(fd);
+				continue;
+			}
+			comparedev = st.st_rdev;
+			if (comparedev == makedev(TTY_MAJOR, 0)) {
+				if (ioctl(fd, VT_GETSTATE, &vt) < 0) {
+					close(fd);
+					continue;
+				}
+				comparedev = makedev(TTY_MAJOR, (int)vt.v_active);
+			}
+#endif
+			close(fd);
+
+			name = scandev(dir);
+			if (!name)
+				continue;
+			consalloc(name);
+		}
+		closedir(dir);
+		free(cmdline);
+		/*
+		 * Detection of the device used for Linux system console using
+		 * the ioctl TIOCGDEV if available (e.g. official 2.6.38).
+		 */
+		if (!consoles) {
+#ifdef TIOCGDEV
+			unsigned int devnum;
+			const char *name;
+
+			if (!device || *device == '\0')
+				fd = dup(fallback);
+			else	fd = open(device, O_RDWR|O_NONBLOCK|O_NOCTTY|O_CLOEXEC);
+
+			if (fd < 0)
+				goto fallback;
+
+			if (ioctl (fd, TIOCGDEV, &devnum) < 0) {
+				close(fd);
+				goto fallback;
+			}
+			comparedev = (dev_t)devnum;
+			close(fd);
+
+			if (device && *device != '\0')
+				name = device;
+			else	name = ttyname(fallback);
+
+			if (!name)
+				name = "/dev/tty1";
+
+			consalloc(strdup(name));
+			if (consoles) {
+				if (!device || *device == '\0')
+					consoles->fd = fallback;
+				return ret;
+			}
+#endif
+			goto fallback;
+		}
+		return ret;
+	}
+#endif /* __linux __ */
+fallback:
+	if (fallback >= 0) {
+		const char *name;
+		
+		if (device && *device != '\0')
+			name = device;
+		else	name = ttyname(fallback);
+
+		if (!name)
+			name = "/dev/tty";
+
+		consalloc(strdup(name));
+		if (consoles)
+			consoles->fd = fallback;
+	}
+	return ret;
+}
-- 
1.7.7


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

* Re: [util-linux] [PATCH 00/13] Initial import of sulogin
  2012-10-12 14:07       ` Dr. Werner Fink
@ 2012-11-09  8:38         ` Karel Zak
  2012-11-09  8:45           ` Karel Zak
  2012-11-09 12:09         ` Karel Zak
  1 sibling, 1 reply; 25+ messages in thread
From: Karel Zak @ 2012-11-09  8:38 UTC (permalink / raw)
  To: util-linux; +Cc: Philipp Thomas, Werner Fin

On Fri, Oct 12, 2012 at 04:07:57PM +0200, Dr. Werner Fink wrote:
> +static
> +#ifdef __GNUC__
> +__attribute__((__nonnull__,__hot__))
> +#endif
> +void consalloc(char * name)
> +{
> +	struct console *restrict tail;
> +
> +	if (posix_memalign((void*)&tail, sizeof(void*), alignof(typeof(struct console))) != 0)
> +		perror("memory allocation");

 why not malloc() ?

> +
> +	tail->next = (struct console*)0;
> +	tail->tty = name;
> +
> +	tail->file = (FILE*)0;
> +	tail->flags = 0;
> +	tail->fd = -1;
> +	tail->id = concount++;
> +	tail->pid = 0;
> +	memset(&tail->tio, 0, sizeof(tail->tio));
> +	memcpy(&tail->cp, &initcp, sizeof(struct chardata));
> +
> +	if (!consoles)
> +		consoles = tail;
> +	else
> +		consoles->next = tail;
> +}

 It does not look like a list. It always update the same pointer
 consoles->next but not "consoles", so the result is list with only
 two items (first and the last item).

 If you want to create a list you have to always update two pointers
 (the "->next" and pointer to the first/last item).

    Karel



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

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

* Re: [util-linux] [PATCH 00/13] Initial import of sulogin
  2012-11-09  8:38         ` Karel Zak
@ 2012-11-09  8:45           ` Karel Zak
  0 siblings, 0 replies; 25+ messages in thread
From: Karel Zak @ 2012-11-09  8:45 UTC (permalink / raw)
  To: util-linux; +Cc: Philipp Thomas, Werner Fin

On Fri, Nov 09, 2012 at 09:38:45AM +0100, Karel Zak wrote:
> On Fri, Oct 12, 2012 at 04:07:57PM +0200, Dr. Werner Fink wrote:
> > +static
> > +#ifdef __GNUC__
> > +__attribute__((__nonnull__,__hot__))
> > +#endif
> > +void consalloc(char * name)
> > +{
> > +	struct console *restrict tail;
> > +
> > +	if (posix_memalign((void*)&tail, sizeof(void*), alignof(typeof(struct console))) != 0)
> > +		perror("memory allocation");
> 
>  why not malloc() ?
> 
> > +
> > +	tail->next = (struct console*)0;
> > +	tail->tty = name;
> > +
> > +	tail->file = (FILE*)0;
> > +	tail->flags = 0;
> > +	tail->fd = -1;
> > +	tail->id = concount++;
> > +	tail->pid = 0;
> > +	memset(&tail->tio, 0, sizeof(tail->tio));
> > +	memcpy(&tail->cp, &initcp, sizeof(struct chardata));
> > +
> > +	if (!consoles)
> > +		consoles = tail;
> > +	else
> > +		consoles->next = tail;
> > +}
> 
>  It does not look like a list. It always update the same pointer
>  consoles->next but not "consoles", so the result is list with only
>  two items (first and the last item).
> 
>  If you want to create a list you have to always update two pointers
>  (the "->next" and pointer to the first/last item).

 Note that the right code is something like:

    struct console *last;

    [...]

	for (last = consoles; last && last->next; last = last->next);

	if (!last)
		consoles = tail;
	else
		last->next = tail;

    Karel

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

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

* Re: [util-linux] [PATCH 00/13] Initial import of sulogin
  2012-10-12 14:07       ` Dr. Werner Fink
  2012-11-09  8:38         ` Karel Zak
@ 2012-11-09 12:09         ` Karel Zak
  2012-11-30 15:57           ` Dr. Werner Fink
  1 sibling, 1 reply; 25+ messages in thread
From: Karel Zak @ 2012-11-09 12:09 UTC (permalink / raw)
  To: util-linux

On Fri, Oct 12, 2012 at 04:07:57PM +0200, Dr. Werner Fink wrote:
> >  Time... (the patch is one huge rewrite, I'd like to split it to more
> >  patches). I'm busy with some others things, so next week.
> 
> Yep, this missing feature is also known here ;)
> Maybe the attached patch help as it only adds the /proc/consoles and
> /sys/class/tty/ scanner into common lib and leave sulogin untouched.
> 
> The integration into sulogin.c could then be done later

 Good idea. I have merged the lib/consoles.c with some changes:

    - removed all global variables
    - refactoring (one separate function for each detection method)
    - add debug messages
    - fix some disadvantages
    - add small test program

 Now we need a patch(s) for sulogin.c. It should be relatively simple
 task as we already have Philipp's prototype.

 http://www.spinics.net/lists/util-linux-ng/msg06916.html

 Any suggestion how to test the code?

   Karel


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

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

* Re: [util-linux] [PATCH 00/13] Initial import of sulogin
  2012-11-09 12:09         ` Karel Zak
@ 2012-11-30 15:57           ` Dr. Werner Fink
  2012-12-04 12:12             ` Dr. Werner Fink
  0 siblings, 1 reply; 25+ messages in thread
From: Dr. Werner Fink @ 2012-11-30 15:57 UTC (permalink / raw)
  To: util-linux; +Cc: Karel Zak

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

On Fri, Nov 09, 2012 at 01:09:19PM +0100, Karel Zak wrote:
> On Fri, Oct 12, 2012 at 04:07:57PM +0200, Dr. Werner Fink wrote:
> > >  Time... (the patch is one huge rewrite, I'd like to split it to more
> > >  patches). I'm busy with some others things, so next week.
> > 
> > Yep, this missing feature is also known here ;)
> > Maybe the attached patch help as it only adds the /proc/consoles and
> > /sys/class/tty/ scanner into common lib and leave sulogin untouched.
> > 
> > The integration into sulogin.c could then be done later
> 
>  Good idea. I have merged the lib/consoles.c with some changes:
> 
>     - removed all global variables
>     - refactoring (one separate function for each detection method)
>     - add debug messages
>     - fix some disadvantages
>     - add small test program
> 
>  Now we need a patch(s) for sulogin.c. It should be relatively simple
>  task as we already have Philipp's prototype.
> 
>  http://www.spinics.net/lists/util-linux-ng/msg06916.html
> 
>  Any suggestion how to test the code?

For such things a VirtualBox or KVM client is usefull, if a serial
console is used then you can see both of the consoles.  In the meanwhile
I've tried to move from single linked lists to double linked list as
found in include/list.h.  Now the usage of posix_memalign() makes sense
as with this the area for the structure as well as for the string in the
structure can be allocated in one step (and also freed in one step).

During debugging I've found that the usleep() inline in include/c.h
is broken as the default type is missed and semi colon as well.

   Werner

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

[-- Attachment #2: util-linux-consoles.patch --]
[-- Type: text/x-patch, Size: 8236 bytes --]

>From 93015b7d4b6884d8ca68694c7bffeae9ea7c6726 Mon Sep 17 00:00:00 2001
From: Werner Fink <werner@suse.de>
Date: Fri, 30 Nov 2012 16:38:09 +0100
Subject: [PATCH] Use the linked lists from list.h for consoles 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 a/include/consoles.h b/include/consoles.h
index 2283d02..2544263 100644
--- a/include/consoles.h
+++ b/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 a/lib/consoles.c b/lib/consoles.c
index 7bc21b6..38c8208 100644
--- a/lib/consoles.c
+++ b/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.7


[-- Attachment #3: util-linux-usleep.patch --]
[-- Type: text/x-patch, Size: 1044 bytes --]

>From 0f259c192a6b9e6710e4f4576abe28dd6f5c982a Mon Sep 17 00:00:00 2001
From: Werner Fink <werner@suse.de>
Date: Fri, 30 Nov 2012 16:52:37 +0100
Subject: [PATCH] Make usleep() workaround work

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

diff --git a/include/c.h b/include/c.h
index 1107287..ec1020e 100644
--- a/include/c.h
+++ b/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.9.2


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

* Re: [util-linux] [PATCH 00/13] Initial import of sulogin
  2012-11-30 15:57           ` Dr. Werner Fink
@ 2012-12-04 12:12             ` Dr. Werner Fink
  0 siblings, 0 replies; 25+ messages in thread
From: Dr. Werner Fink @ 2012-12-04 12:12 UTC (permalink / raw)
  To: Karel Zak; +Cc: util-linux

On Fri, Nov 30, 2012 at 04:57:26PM +0100, Werner Fink wrote:
> On Fri, Nov 09, 2012 at 01:09:19PM +0100, Karel Zak wrote:
> > On Fri, Oct 12, 2012 at 04:07:57PM +0200, Dr. Werner Fink wrote:
> > > >  Time... (the patch is one huge rewrite, I'd like to split it to more
> > > >  patches). I'm busy with some others things, so next week.
> > > 
> > > Yep, this missing feature is also known here ;)
> > > Maybe the attached patch help as it only adds the /proc/consoles and
> > > /sys/class/tty/ scanner into common lib and leave sulogin untouched.
> > > 
> > > The integration into sulogin.c could then be done later
> > 
> >  Good idea. I have merged the lib/consoles.c with some changes:
> > 
> >     - removed all global variables
> >     - refactoring (one separate function for each detection method)
> >     - add debug messages
> >     - fix some disadvantages
> >     - add small test program
> > 
> >  Now we need a patch(s) for sulogin.c. It should be relatively simple
> >  task as we already have Philipp's prototype.
> > 
> >  http://www.spinics.net/lists/util-linux-ng/msg06916.html
> > 
> >  Any suggestion how to test the code?

I've up and running a VirtualBox guest with a serial as well as a virtual
console. From the compiled consoles test (-DTEST_PROGRAM) I see:

  g243:~ # ./consoles /dev/console 
  /dev/tty7: id=0 (reconnect) 
  /dev/ttyS0: id=1 (reconnect) 
  g243:~ # cat /proc/cmdline
  BOOT_IMAGE=/boot/vmlinuz-3.4.11-2.16-desktop root=UUID=5ece074f-824b-45b0-8fa6-aa61c06beb87 resume=/dev/disk/by-id/ata-VBOX_HARDDISK_VB96c77b27-f0603953-part1 splash=silent console=ttyS0,115200 console=tty0 showopts

> For such things a VirtualBox or KVM client is usefull, if a serial
> console is used then you can see both of the consoles.  In the meanwhile
> I've tried to move from single linked lists to double linked list as
> found in include/list.h.  Now the usage of posix_memalign() makes sense
> as with this the area for the structure as well as for the string in the
> structure can be allocated in one step (and also freed in one step).

For the VirtualBox I use a sub directory /dev/vboxtty/ owned and writable by
the group vboxusers.  Below this the VirtualBox creates the ttyS0 as a socket
pair and I start a simple script using socat and screen with:

 #!/bin/bash
 : ${tty:=ttyS0}
 dir=/dev/vboxtty
 pty=$dir/tty${tty#ttyS}
 socat unix-connect:$dir/ttyS0,oobinline pty,link=$pty,b38400,parenb=1,cs8,istrip=0,icanon=1 &
 exec screen -O -A -f $pty b38400,parenb=1,cs8,istrip=0,icanon=1

with this one can see the boot messages on both the serial console and on the
window used by the VirtualBox for its own virtual console(s).

   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] 25+ messages in thread

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

Thread overview: 25+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-02-28 16:45 [PATCH 00/13] Initial import of sulogin Dave Reisner
2012-02-28 16:45 ` [PATCH 01/13] fstab.5: fix misspelling of deprecated Dave Reisner
2012-02-28 16:45 ` [PATCH 02/13] sulogin: initial import from sysvinit Dave Reisner
2012-02-28 18:45   ` Davidlohr Bueso
2012-02-28 16:45 ` [PATCH 03/13] sulogin.8: refactor manpage Dave Reisner
2012-02-28 16:45 ` [PATCH 04/13] sulogin: whitespace fixes Dave Reisner
2012-02-28 16:45 ` [PATCH 05/13] sulogin: replace older signal() with sigaction() Dave Reisner
2012-02-28 16:45 ` [PATCH 06/13] sulogin: remove CHECK_{DES,MD5} defines Dave Reisner
2012-02-28 16:45 ` [PATCH 07/13] sulogin: remove USE_ONELINE and SANE_TIO defines Dave Reisner
2012-02-28 16:45 ` [PATCH 08/13] sulogin: use size_t for iterator to avoid cast Dave Reisner
2012-02-28 16:45 ` [PATCH 09/13] sulogin: get rid of calls to /bin/sash Dave Reisner
2012-02-28 16:45 ` [PATCH 10/13] sulogin: use pathnames.h for file locations Dave Reisner
2012-02-28 16:45 ` [PATCH 11/13] sulogin: header/include cleanup Dave Reisner
2012-02-28 16:45 ` [PATCH 12/13] sulogin: use a more standard usage output Dave Reisner
2012-02-28 16:45 ` [PATCH 13/13] sulogin: add i18n strings Dave Reisner
2012-02-28 16:48 ` [PATCH 00/13] Initial import of sulogin Dave Reisner
2012-10-12 12:53   ` [util-linux] " Dr. Werner Fink
2012-10-12 13:23     ` Karel Zak
2012-10-12 14:07       ` Dr. Werner Fink
2012-11-09  8:38         ` Karel Zak
2012-11-09  8:45           ` Karel Zak
2012-11-09 12:09         ` Karel Zak
2012-11-30 15:57           ` Dr. Werner Fink
2012-12-04 12:12             ` Dr. Werner Fink
2012-03-12 14:20 ` sulogin merged into util-linux (Re: [PATCH 00/13] Initial import of sulogin) Karel Zak

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).