From cec26d957a2facce4c595246c7dbdd3808bf44cd59b3cfa79efc5dddcfc1b60a Mon Sep 17 00:00:00 2001 From: "Dr. Werner Fink" Date: Thu, 31 Mar 2011 15:11:27 +0000 Subject: [PATCH] . OBS-URL: https://build.opensuse.org/package/show/Base:System/sysvinit?expand=0&rev=113 --- showconsole-1.14.dif | 80 +- sysvinit-2.88dsf-multiple-sulogin.patch | 1301 +++++++++++++++++++++++ sysvinit.changes | 9 +- sysvinit.spec | 2 + 4 files changed, 1387 insertions(+), 5 deletions(-) create mode 100644 sysvinit-2.88dsf-multiple-sulogin.patch diff --git a/showconsole-1.14.dif b/showconsole-1.14.dif index b8f1594..7bff08d 100644 --- a/showconsole-1.14.dif +++ b/showconsole-1.14.dif @@ -1,4 +1,76 @@ ---- .dummy -+++ .dummy 2011-03-25 17:58:16.867926297 +0000 -@@ -0,0 +1 @@ -+Remove if real patch is required +--- blogd.c ++++ blogd.c 2011-03-31 14:59:37.543926064 +0000 +@@ -336,7 +336,7 @@ int main(int argc, char *argv[]) + dup2(0, 2); + + secondtty(cons, st.st_rdev); +-exit(0); ++ + (void)ioctl(0, TIOCCONS, NULL); /* Undo any current map if any */ + close(0); + +@@ -351,22 +351,34 @@ exit(0); + #endif + c->max_canon = _POSIX_MAX_CANON; + c->tlock = 0; +- if (tcgetattr(cons->fd, &cons->otio) < 0) ++ if (tcgetattr(c->fd, &c->otio) < 0) + continue; + c->tlock = 1; +-#if 1 ++ + iflag = c->otio.c_iflag; + oflag = c->otio.c_oflag; + +- c->otio.c_iflag |= (ICRNL | IGNBRK); +- c->otio.c_iflag &= ~(INLCR | IGNCR | BRKINT); +- c->otio.c_oflag |= (ONLCR | OPOST); +- c->otio.c_oflag &= ~(OCRNL | ONLRET); +- (void)tcsetattr(cons->fd, TCSADRAIN, &cons->otio); ++ if (ioctl(c->fd, TIOCMGET, &flags) == 0) { ++ ispeed = cfgetispeed(&c->otio); ++ ospeed = cfgetospeed(&c->otio); ++ ++ c->otio.c_iflag = c->otio.c_lflag = 0; ++ c->otio.c_oflag = (ONLCR | OPOST); ++ c->otio.c_cflag = CREAD | CS8 | HUPCL | (c->otio.c_cflag & CLOCAL); ++ ++ cfsetispeed(&c->otio, ispeed); ++ cfsetospeed(&c->otio, ospeed); ++ } else { ++ c->otio.c_iflag |= (ICRNL | IGNBRK); ++ c->otio.c_iflag &= ~(INLCR | IGNCR | BRKINT); ++ c->otio.c_oflag |= (ONLCR | OPOST); ++ c->otio.c_oflag &= ~(OCRNL | ONLRET); ++ } ++ (void)tcsetattr(c->fd, TCSADRAIN, &c->otio); + + c->otio.c_iflag = iflag; + c->otio.c_oflag = oflag; +-#endif ++ + if ((c->otio.c_lflag & ICANON) == 0) { + c->otio.c_lflag |= ICANON | IEXTEN | ISIG | ECHO|ECHOE|ECHOK|ECHOKE; + c->otio.c_oflag |= OPOST; +--- libconsole.c ++++ libconsole.c 2011-03-31 14:44:34.988426227 +0000 +@@ -302,7 +302,7 @@ out: + /* + * The stdio file pointer for our log file + */ +-struct console *restrict cons; ++struct console *cons; + static FILE * flog = NULL; + static int fdread = -1; + static int fdfifo = -1; +@@ -1463,6 +1463,10 @@ static void consalloc(struct console *re + return; + } + tail->next = newc; ++ tail->tlock = 0; ++ tail->max_canon = _POSIX_MAX_CANON; ++ memset(&tail->ltio, 0, sizeof(tail->ltio)); ++ memset(&tail->otio, 0, sizeof(tail->otio)); + tail = tail->next; + + if ((flags = fcntl(newc->fd, F_GETFL)) < 0) diff --git a/sysvinit-2.88dsf-multiple-sulogin.patch b/sysvinit-2.88dsf-multiple-sulogin.patch new file mode 100644 index 0000000..539a355 --- /dev/null +++ b/sysvinit-2.88dsf-multiple-sulogin.patch @@ -0,0 +1,1301 @@ +Index: src/sulogin.c +=================================================================== +--- src/sulogin.c (revision 98) ++++ src/sulogin.c (working copy) +@@ -28,8 +28,10 @@ + * + */ + ++#include + #include + #include ++#include + #include + #include + #include +@@ -44,13 +46,34 @@ + #include + #if defined(__GLIBC__) + # include ++# define dovoid(f) if ((f)){} + #endif ++#ifdef __linux__ ++# include ++# include ++# include ++# include ++# include ++# ifndef TMPFS_MAGIC ++# define TMPFS_MAGIC 0x01021994 ++# endif ++# ifndef MNT_DETACH ++# define MNT_DETACH 2 ++# endif ++#endif + ++#define BS CTRL('h') ++#define NL CTRL('j') ++#define CR CTRL('m') ++ + #ifdef WITH_SELINUX + # include + # include + #endif + ++#include "consoles.h" ++#define CONMAX 16 ++ + #define CHECK_DES 1 + #define CHECK_MD5 1 + +@@ -63,102 +86,218 @@ + + static int timeout; + static int profile; ++static volatile uint32_t openfd; /* Remember higher file descriptors */ ++static volatile uint32_t *usemask; + +-static void (*saved_sigint) = SIG_DFL; +-static void (*saved_sigtstp) = SIG_DFL; +-static void (*saved_sigquit) = SIG_DFL; ++static sighandler_t saved_sigint = SIG_DFL; ++static sighandler_t saved_sigtstp = SIG_DFL; ++static sighandler_t saved_sigquit = SIG_DFL; ++static sighandler_t saved_sighup = SIG_DFL; + + static volatile sig_atomic_t alarm_rised; ++static volatile sig_atomic_t sigchild; + + #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) ++void tcinit(struct console *con) + { +- struct termios tty; +- int serial; ++ int serial, flags; ++ struct termios *tio = &con->tio; ++ int fd = con->fd; + +- /* Skip serial console */ +- if (ioctl (0, TIOCMGET, (char*)&serial) == 0) +- goto out; + /* Expected error */ + serial = errno = 0; + +- tcgetattr(0, &tty); ++ /* Get line attributes */ ++ if (tcgetattr(fd, tio) < 0) { ++ con->flags |= CON_NOTTY; ++ return; ++ } + +- /* Use defaults of 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); ++ /* Handle serial lines here */ ++ if (ioctl (fd, TIOCMGET, (char*)&serial) == 0) { ++ speed_t ispeed, ospeed; + ++ /* this is a modem line */ ++ con->flags |= CON_SERIAL; ++ ++ /* Flush input and output queues on modem lines */ ++ (void) tcflush(fd, TCIOFLUSH); ++ ++ ispeed = cfgetispeed(tio); ++ ospeed = cfgetospeed(tio); ++ ++ tio->c_iflag = tio->c_lflag = tio->c_oflag = 0; ++ tio->c_cflag = CREAD | CS8 | HUPCL | (tio->c_cflag & CLOCAL); ++ ++ cfsetispeed(tio, ispeed); ++ cfsetospeed(tio, ospeed); ++ ++ tio->c_line = 0; ++ tio->c_cc[VTIME] = 0; ++ tio->c_cc[VMIN] = 1; ++ ++ goto setattr; ++ } ++#if defined(SANE_TIO) && (SANE_TIO == 1) ++ /* ++ * Use defaults of for base settings ++ * of a local terminal line like a virtual console. ++ */ ++ tio->c_iflag |= TTYDEF_IFLAG; ++ tio->c_oflag |= TTYDEF_OFLAG; ++ tio->c_lflag |= TTYDEF_LFLAG; ++ tio->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); +- 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 |\ ++ tio->c_iflag |= (BRKINT | ICRNL | IMAXBEL); ++ tio->c_iflag &= ~(IGNBRK | INLCR | IGNCR | IXOFF | IUCLC | IXANY | ISTRIP); ++ tio->c_oflag |= (OPOST | ONLCR | NL0 | CR0 | TAB0 | BS0 | VT0 | FF0); ++ tio->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); ++ tio->c_lflag |= (ISIG | ICANON | IEXTEN | ECHO|ECHOE|ECHOK|ECHOKE); ++ tio->c_lflag &= ~(ECHONL|ECHOCTL|ECHOPRT | NOFLSH | XCASE | TOSTOP); ++ tio->c_cflag |= (CREAD | CS8 | CLOCAL | HUPCL | B38400); ++ tio->c_cflag &= ~(PARENB); + +- /* VTIME and VMIN can overlap with VEOF and VEOL since they are ++ /* ++ * 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; ++ tio->c_cc[VTIME] = 0; ++ tio->c_cc[VMIN] = CMIN; ++ tio->c_cc[VINTR] = CINTR; ++ tio->c_cc[VQUIT] = CQUIT; ++ tio->c_cc[VERASE] = CERASE; /* ASCII DEL (0177) */ ++ tio->c_cc[VKILL] = CKILL; ++ tio->c_cc[VEOF] = CEOF; ++# ifdef VSWTC ++ tio->c_cc[VSWTC] = _POSIX_VDISABLE; ++# else ++ tio->c_cc[VSWTCH] = _POSIX_VDISABLE; ++# endif ++ tio->c_cc[VSTART] = CSTART; ++ tio->c_cc[VSTOP] = CSTOP; ++ tio->c_cc[VSUSP] = CSUSP; ++ tio->c_cc[VEOL] = _POSIX_VDISABLE; ++ tio->c_cc[VREPRINT] = CREPRINT; ++ tio->c_cc[VDISCARD] = CDISCARD; ++ tio->c_cc[VWERASE] = CWERASE; ++ tio->c_cc[VLNEXT] = CLNEXT; ++ tio->c_cc[VEOL2] = _POSIX_VDISABLE; ++#endif ++setattr: ++ /* Set line attributes */ ++ tcsetattr(fd, TCSANOW, tio); + +- tcsetattr(0, TCSANOW, &tty); +-out: +- return; ++ /* Enable blocking mode for read and write */ ++ if ((flags = fcntl(fd, F_GETFL, 0)) != -1) ++ (void)fcntl(fd, F_SETFL, flags & ~O_NONBLOCK); + } ++ ++ ++/* ++ * Finalize the tty modes on modem lines. ++ */ ++static ++void tcfinal(struct console *con) ++{ ++ int serial; ++ struct termios *tio = &con->tio; ++ int fd = con->fd; ++ ++ /* Expected error */ ++ serial = errno = 0; ++ ++ if ((con->flags & CON_SERIAL) == 0) { ++#ifdef __linux__ ++ setenv("TERM", "linux", 1); ++#else ++ setenv("TERM", "vt100", 1); + #endif ++ return; ++ } ++ if (con->flags & CON_NOTTY) ++ return; ++ setenv("TERM", "vt100", 1); + ++ tio->c_oflag |= OPOST; + ++ tio->c_cc[VINTR] = CINTR; ++ tio->c_cc[VQUIT] = CQUIT; ++ tio->c_cc[VERASE] = con->cp.erase; ++ tio->c_cc[VKILL] = con->cp.kill; ++ tio->c_cc[VEOF] = CEOF; ++# ifdef VSWTC ++ tio->c_cc[VSWTC] = _POSIX_VDISABLE; ++# else ++ tio->c_cc[VSWTCH] = _POSIX_VDISABLE; ++# endif ++ tio->c_cc[VEOL] = _POSIX_VDISABLE; ++ ++ if (con->cp.eol == CR) { ++ tio->c_iflag |= ICRNL; ++ tio->c_iflag &= ~(INLCR|IGNCR); ++ tio->c_oflag |= ONLCR; ++ tio->c_oflag &= ~(OCRNL|ONLRET); ++ } ++ ++ switch (con->cp.parity) { ++ default: ++ case 0: ++ break; ++ case 1: /* odd parity */ ++ tio->c_cflag |= PARODD; ++ /* fall through */ ++ case 2: /* even parity */ ++ tio->c_cflag |= PARENB; ++ tio->c_iflag |= INPCK | ISTRIP; ++ /* fall through */ ++ case (1 | 2): /* no parity bit */ ++ tio->c_cflag &= ~CSIZE; ++ tio->c_cflag |= CS7; ++ break; ++ } ++ ++ /* Set line attributes */ ++ (void)tcsetattr(fd, TCSANOW, tio); ++} ++ + /* + * Called at timeout. + */ + static + # ifdef __GNUC__ ++__attribute__((__noinline__)) + void alrm_handler(int sig __attribute__((unused))) + # else + void alrm_handler(int sig) + # endif + { +- /* Timeout expired */ + alarm_rised++; ++} + +- signal(SIGINT, saved_sigint); +- signal(SIGTSTP, saved_sigtstp); +- signal(SIGQUIT, saved_sigquit); +- +- /* Never use exit(3) or stdio(3) within a signal handler */ ++/* ++ * Called at timeout. ++ */ ++static ++# ifdef __GNUC__ ++__attribute__((__noinline__)) ++void chld_handler(int sig __attribute__((unused))) ++# else ++void chld_handler(int sig) ++# endif ++{ ++ sigchild++; + } + + /* +@@ -343,57 +482,200 @@ + } + + /* +- * Ask for the password. Note that there is no +- * default timeout as we normally skip this during boot. ++ * Ask by prompt for the password. + */ + static +-char *getpasswd(char *crypted) ++void doprompt(const char *crypted, struct console *con) + { +- struct sigaction sa; +- struct termios old, tty; +- static char pass[128]; +- char *ret = pass; +- int i; ++ struct termios tty; ++ ++ if (con->flags & CON_SERIAL) { ++ tty = con->tio; ++ /* ++ * For prompting: map NL in output to CR-NL ++ * otherwise we may see stairs in the output. ++ */ ++ tty.c_oflag |= (ONLCR | OPOST); ++ (void) tcsetattr(con->fd, TCSADRAIN, &tty); ++ } ++ if (con->file == (FILE*)0) { ++ if ((con->file = fdopen(con->fd, "r+")) == (FILE*)0) ++ goto err; ++ } + #if defined(USE_ONELINE) + if (crypted[0]) +- printf("Give root password for login: "); ++ fprintf(con->file, "Give root password for login: "); + else +- printf("Press enter for login: "); ++ fprintf(con->file, "Press enter for login: "); + #else + if (crypted[0]) +- printf("Give root password for maintenance\n"); ++ fprintf(con->file, "Give root password for maintenance\n"); + else +- printf("Press enter for maintenance"); +- printf("(or type Control-D to continue): "); ++ fprintf(con->file, "Press enter for maintenance"); ++ fprintf(con->file, "(or type Control-D to continue): "); + #endif +- fflush(stdout); ++ fflush(con->file); ++err: ++ if (con->flags & CON_SERIAL) ++ (void) tcsetattr(con->fd, TCSADRAIN, &con->tio); ++} + +- tcgetattr(0, &old); +- tcgetattr(0, &tty); ++/* ++ * Make sure to have an own session and controlling terminal ++ */ ++static ++void setup(struct console *con) ++{ ++ pid_t pid, pgrp, ppgrp, ttypgrp; ++ int fd; ++ ++ if (con->flags & CON_NOTTY) ++ return; ++ fd = con->fd; ++ ++ /* ++ * Only go through this trouble if the new ++ * tty doesn't fall in this process group. ++ */ ++ pid = getpid(); ++ pgrp = getpgid(0); ++ ppgrp = getpgid(getppid()); ++ ttypgrp = tcgetpgrp(fd); ++ ++ if (pgrp != ttypgrp && ppgrp != ttypgrp) { ++ if (pid != getsid(0)) { ++ if (pid == getpgid(0)) ++ setpgid(0, getpgid(getppid())); ++ setsid(); ++ } ++ ++ signal(SIGHUP, SIG_IGN); ++ if (ttypgrp > 0) ++ ioctl(0, TIOCNOTTY, (char *)1); ++ signal(SIGHUP, saved_sighup); ++ if (fd > 0) close(0); ++ if (fd > 1) close(1); ++ if (fd > 2) close(2); ++ ++ ioctl(fd, TIOCSCTTY, (char *)1); ++ tcsetpgrp(fd, ppgrp); ++ } ++ dup2(fd, 0); ++ dup2(fd, 1); ++ dup2(fd, 2); ++ con->fd = 0; ++ ++ for (fd = 3; fd < 32; fd++) { ++ if (openfd & (1<flags & CON_NOTTY) ++ goto out; ++ fd = con->fd; ++ cp = &con->cp; ++ ++ tty = con->tio; + tty.c_iflag &= ~(IUCLC|IXON|IXOFF|IXANY); +- tty.c_lflag &= ~(ECHO|ECHOE|ECHOK|ECHONL|TOSTOP); +- tcsetattr(0, TCSANOW, &tty); ++ tty.c_lflag &= ~(ECHO|ECHOE|ECHOK|ECHONL|TOSTOP|ISIG); ++ tc = (tcsetattr(fd, TCSAFLUSH, &tty) == 0); + +- 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; ++ ptr = &pass[0]; ++ cp->eol = '\0'; ++ ++ eightbit = ((con->flags & CON_SERIAL) == 0 || (tty.c_cflag & (PARODD|PARENB)) == 0); ++ while (cp->eol == 0) { ++ if (read(fd, &c, 1) < 1) { ++ if (errno == EINTR || errno == EAGAIN) { ++ usleep(1000); ++ continue; ++ } ++ ret = (char*)0; ++ switch (errno) { ++ case 0: ++ case EIO: ++ case ESRCH: ++ case ENOENT: + break; ++ default: ++ fprintf(stderr, "sulogin: read(%s): %m\n", con->tty); ++ break; + } ++ goto quit; ++ } ++ ++ if (eightbit) ++ ascval = c; ++ else if (c != (ascval = (c & 0177))) { ++ uint32_t bits, mask; ++ for (bits = 1, mask = 1; mask & 0177; mask <<= 1) { ++ if (mask & ascval) ++ bits++; ++ } ++ cp->parity |= ((bits & 1) ? 1 : 2); ++ } ++ ++ switch (ascval) { ++ case CR: ++ case NL: ++ *ptr = '\0'; ++ cp->eol = ascval; ++ break; ++ case BS: ++ case CERASE: ++ cp->erase = ascval; ++ if (ptr > &pass[0]) ++ ptr--; ++ break; ++ case CKILL: ++ cp->kill = ascval; ++ while (ptr > &pass[0]) ++ ptr--; ++ break; ++ case CEOF: ++ tcfinal(con); ++ goto quit; ++ default: ++ if ((size_t)(ptr - &pass[0]) >= (sizeof(pass) -1 )) { ++ fprintf(stderr, "sulogin: input overrun at %s\n", con->tty); ++ ret = (char*)0; ++ goto quit; ++ } ++ *ptr++ = ascval; ++ break; ++ } + } ++quit: + alarm(0); +- tcsetattr(0, TCSANOW, &old); ++ if (tc) ++ (void)tcsetattr(fd, TCSAFLUSH, &con->tio); + printf("\n"); +- ++out: + return ret; + } + +@@ -411,7 +693,10 @@ + /* + * Set directory and shell. + */ +- (void)chdir(pwd->pw_dir); ++ if (chdir(pwd->pw_dir) < 0) { ++ if (chdir("/") < 0) ++ fprintf(stderr, "Change of working directory failed: %m\n"); ++ } + if ((p = getenv("SUSHELL")) != NULL) + sushell = p; + else if ((p = getenv("sushell")) != NULL) +@@ -431,7 +716,8 @@ + /* + * Set some important environment variables. + */ +- getcwd(home, sizeof(home)); ++ if (getcwd(home, sizeof(home)) == (char*)0) ++ strcpy(home, "/"); + setenv("HOME", home, 1); + setenv("LOGNAME", "root", 1); + setenv("USER", "root", 1); +@@ -445,17 +731,18 @@ + signal(SIGINT, saved_sigint); + signal(SIGTSTP, saved_sigtstp); + signal(SIGQUIT, saved_sigquit); ++ signal(SIGHUP, SIG_DFL); + #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); + } +@@ -474,6 +761,46 @@ + perror(STATICSH); + } + ++#ifdef __linux__ ++/* ++ * Make C library standard calls like ttyname(3) work. ++ */ ++static uint32_t mounts; ++#define MNT_PROCFS 0x0001 ++#define MNT_DEVTMPFS 0x0002 ++ ++static __attribute__((__noinline__)) ++void putmounts(void) ++{ ++ if (mounts & MNT_DEVTMPFS) ++ umount2("/dev", MNT_DETACH); ++ if (mounts & MNT_PROCFS) ++ umount2("/proc", MNT_DETACH); ++} ++ ++static __attribute__((__constructor__)) ++void getmounts(void) ++{ ++ struct statfs st; ++ if (statfs("/proc", &st) == 0 && st.f_type != PROC_SUPER_MAGIC) { ++ if (mount("proc", "/proc", "proc", MS_RELATIME, NULL) == 0) ++ mounts |= MNT_PROCFS; ++ } ++ if (statfs("/dev", &st) == 0 && st.f_type != TMPFS_MAGIC) { ++ if (mount("devtmpfs", "/dev", "devtmpfs", MS_RELATIME, "mode=0755,nr_inodes=0") == 0) { ++ mounts |= MNT_DEVTMPFS; ++ (void)mknod("/dev/console", S_IFCHR|S_IRUSR|S_IWUSR, makedev(TTYAUX_MAJOR, 1)); ++ if (symlink("/proc/self/fd", "/dev/fd") == 0) { ++ dovoid(symlink("fd/0", "/dev/stdin")); ++ dovoid(symlink("fd/1", "/dev/stdout")); ++ dovoid(symlink("fd/2", "/dev/stderr")); ++ } ++ } ++ } ++ if (mounts) atexit(putmounts); ++} ++#endif ++ + static + void usage(void) + { +@@ -483,13 +810,21 @@ + int main(int argc, char **argv) + { + char *tty = NULL; +- char *p; + struct passwd *pwd; +- int c, fd = -1; ++ int c, status = 0; + int opt_e = 0; +- pid_t pid, pgrp, ppgrp, ttypgrp; ++ struct console *con; ++ pid_t pid; + + /* ++ * We are init. We hence need to set uo a session. ++ */ ++ if ((pid = getpid()) == 1) { ++ setsid(); ++ (void)ioctl(0, TIOCSCTTY, (char *)1); ++ } ++ ++ /* + * See if we have a timeout flag. + */ + opterr = 0; +@@ -514,77 +849,24 @@ + exit(1); + } + +- /* +- * See if we need to open an other tty device. +- */ + saved_sigint = signal(SIGINT, SIG_IGN); + saved_sigquit = signal(SIGQUIT, SIG_IGN); + saved_sigtstp = signal(SIGTSTP, SIG_IGN); +- if (optind < argc) tty = argv[optind]; ++ saved_sighup = signal(SIGHUP, SIG_IGN); + +- if (tty || (tty = getenv("CONSOLE"))) { ++ /* ++ * See if we need to open an other tty device. ++ */ ++ if (optind < argc) ++ tty = argv[optind]; ++ if (!tty || *tty == '\0') ++ tty = getenv("CONSOLE"); + +- if ((fd = open(tty, O_RDWR)) < 0) { +- perror(tty); +- fd = dup(0); +- } ++ /* ++ * Detect possible consoles, use stdin as fallback. ++ */ ++ detect_consoles(tty, 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. + */ +@@ -594,31 +876,97 @@ + } + + /* +- * Ask for the password. ++ * Prompt for input on the consoles + */ +- while(pwd) { +- int failed = 0; +- if ((p = getpasswd(pwd->pw_passwd)) == NULL) break; +- if (pwd->pw_passwd[0] == 0 || +- strcmp(crypt(p, pwd->pw_passwd), pwd->pw_passwd) == 0) { +- sushell(pwd); +- failed++; ++ for (con = consoles; con && con->id < CONMAX; con = con->next) { ++ if (con->fd >= 0) { ++ openfd |= (1<fd); ++ tcinit(con); ++ continue; + } +- signal(SIGQUIT, SIG_IGN); +- signal(SIGTSTP, SIG_IGN); +- signal(SIGINT, SIG_IGN); +- if (failed) { +- printf("Can not execute su shell.\n"); ++ if ((con->fd = open(con->tty, O_RDWR | O_NOCTTY | O_NONBLOCK)) < 0) ++ continue; ++ openfd |= (1<fd); ++ tcinit(con); ++ } ++ con = consoles; ++ usemask = (uint32_t*)mmap(NULL, sizeof(uint32_t), PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_SHARED, -1, 0); ++ ++ if (con->next == (struct console*)0) ++ goto nofork; ++ ++ signal(SIGCHLD, chld_handler); ++ do { ++ switch ((con->pid = fork())) { ++ case 0: ++ signal(SIGCHLD, SIG_DFL); ++ /* fall through */ ++ nofork: ++ setup(con); ++ while (1) { ++ char *passwd = pwd->pw_passwd; ++ char *answer; ++ int failed = 0; ++ ++ doprompt(passwd, con); ++ if ((answer = getpasswd(con)) == NULL) ++ break; ++ ++ if (passwd[0] == '\0' || ++ strcmp(crypt(answer, passwd), passwd) == 0) { ++ *usemask |= (1<id); ++ sushell(pwd); ++ *usemask &= ~(1<id); ++ failed++; ++ } ++ signal(SIGQUIT, SIG_IGN); ++ signal(SIGTSTP, SIG_IGN); ++ signal(SIGINT, SIG_IGN); ++ ++ if (failed) { ++ fprintf(stderr, "Can not execute su shell.\n"); ++ break; ++ } ++ fprintf(stderr, "Login incorrect.\n"); ++ } ++ if (alarm_rised) { ++ tcfinal(con); ++ printf("Timed out.\n"); ++ } ++ /* ++ * User may pressed Control-D. ++ */ ++ exit(0); ++ case -1: ++ fprintf(stderr, "sulogin: can not fork: %m\n"); ++ /* fall through */ ++ default: + break; +- } else +- printf("Login incorrect.\n"); ++ } ++ } while ((con = con->next) && (con->id < CONMAX)); ++ ++ while ((pid = wait(&status))) { ++ if (errno == ECHILD) ++ break; ++ if (pid < 0) ++ continue; ++ for (con = consoles; con && con->id < CONMAX; con = con->next) { ++ if (con->pid == pid) { ++ *usemask &= ~(1<id); ++ continue; ++ } ++ if (kill(con->pid, 0) < 0) { ++ *usemask &= ~(1<id); ++ continue; ++ } ++ if (*usemask & (1<id)) ++ continue; ++ kill(con->pid, SIGHUP); ++ usleep(5000); ++ kill(con->pid, SIGKILL); ++ } + } ++ signal(SIGCHLD, SIG_DFL); + +- if (alarm_rised) +- printf("Timed out.\n"); +- +- /* +- * User may pressed Control-D. +- */ + return 0; + } +Index: src/consoles.c +=================================================================== +--- src/consoles.c (revision 100) ++++ src/consoles.c (working copy) +@@ -27,9 +27,23 @@ + #include + #include + #include ++#include ++#ifdef __linux__ ++# ifndef TIOCGDEV ++# include ++# include ++# include ++# endif ++#endif ++#include + #include ++#include + #include "consoles.h" + ++#ifdef __linux__ ++# include ++#endif ++ + #if !defined(__STDC_VERSION__) || (__STDC_VERSION__ < 199901L) + # ifndef typeof + # define typeof __typeof__ +@@ -43,8 +57,93 @@ + + 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, ++ * 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 */ ++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__ */ ++ + static dev_t comparedev; +-static char* scandev(DIR *dir) ++static ++#ifdef __GNUC__ ++__attribute__((__nonnull__,__malloc__,__hot__)) ++#endif ++char* scandev(DIR *dir) + { + char *name = (char*)0; + struct dirent *dent; +@@ -69,41 +168,232 @@ + return name; + } + +-void detect_consoles(void) ++static ++struct chardata initcp = { ++ CERASE, ++ CKILL, ++ CTRL('r'), ++ 0 ++}; ++ ++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; ++} ++ ++void detect_consoles(const char *console, int fallback) ++{ ++#ifdef __linux__ ++ char *attrib, *cmdline; + FILE *fc; +- if ((fc = fopen("/proc/consoles", "r"))) { ++ ++ if ((fc = fopen("/proc/consoles", "re"))) { + char fbuf[16]; + int maj, min; + DIR *dir; + dir = opendir("/dev"); + if (!dir) +- goto out; ++ goto out1; + while ((fscanf(fc, "%*s %*s (%[^)]) %d:%d", &fbuf[0], &maj, &min) == 3)) { +- struct console *restrict tail; + char * name; + + if (!strchr(fbuf, 'E')) + continue; + comparedev = makedev(maj, min); ++ + name = scandev(dir); ++ if (!name) ++ continue; ++ consalloc(name); ++ } ++ closedir(dir); ++out1: ++ fclose(fc); ++ return; ++ } + ++ if ((attrib = actattr("console"))) { ++ char *words = attrib, *token; ++ DIR *dir; ++ ++ dir = opendir("/dev"); ++ if (!dir) ++ goto out2; ++ 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); ++out2: ++ free(attrib); ++ return; + +- if (posix_memalign((void*)&tail, sizeof(void*), alignof(typeof(struct console))) != 0) +- perror("memory allocation"); ++ } + +- tail->next = (struct console*)0; +- tail->tty = name; ++ if ((cmdline = oneline("/proc/cmdline"))) { ++ char *words= cmdline, *token; ++ DIR *dir; + +- if (!consoles) +- consoles = tail; +- else +- consoles->next = tail; ++ dir = opendir("/dev"); ++ if (!dir) ++ goto out3; ++ while ((token = strsep(&words, " \t\r\n"))) { ++#ifdef TIOCGDEV ++ unsigned int devnum; ++#else ++ struct vt_stat vt; ++ struct stat st; ++#endif ++ char *colon, *name; ++ int fd; ++ ++ 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); +-out: +- fclose(fc); ++out3: ++ free(cmdline); ++ return; + } ++#endif /* __linux __ */ ++ if (console && *console) { ++ int fd; ++ DIR *dir; ++ char *name; ++#ifdef TIOCGDEV ++ unsigned int devnum; ++#else ++# ifdef __linux__ ++ struct vt_stat vt; ++# endif ++ struct stat st; ++#endif ++ ++ if ((fd = open(console, O_RDWR|O_NONBLOCK|O_NOCTTY|O_CLOEXEC)) < 0) ++ return; ++#ifdef TIOCGDEV ++ if (ioctl (fd, TIOCGDEV, &devnum) < 0) { ++ close(fd); ++ return; ++ } ++ comparedev = (dev_t)devnum; ++#else ++ if (fstat(fd, &st) < 0) { ++ close(fd); ++ return; ++ } ++# ifdef __linux__ ++ comparedev = st.st_rdev; ++ if (comparedev == makedev(TTY_MAJOR, 0)) { ++ if (ioctl(fd, VT_GETSTATE, &vt) < 0) { ++ close(fd); ++ return; ++ } ++ comparedev = makedev(TTY_MAJOR, (int)vt.v_active); ++ } ++# endif ++#endif ++ close(fd); ++ dir = opendir("/dev"); ++ if (!dir) ++ return; ++ name = scandev(dir); ++ if (name) ++ consalloc(name); ++ closedir(dir); ++ return; ++ } ++ ++ if (fallback >= 0) { ++ const char *name = ttyname(fallback); ++ if (!name) ++ name = "/dev/console"; ++ consalloc(strdup(name)); ++ if (consoles) ++ consoles->fd = fallback; ++ } + } +Index: src/consoles.h +=================================================================== +--- src/consoles.h (revision 100) ++++ src/consoles.h (working copy) +@@ -21,13 +21,28 @@ + * Author: Werner Fink + */ + ++#include ++#include ++#include + #include + ++struct chardata { ++ uint8_t erase; ++ uint8_t kill; ++ uint8_t eol; ++ uint8_t parity; ++}; + struct console { +- char * tty; +- int tlock; +- struct termios ltio, otio; ++ 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 void detect_consoles(void); ++extern void detect_consoles(const char *console, int fallback); +Index: src/Makefile +=================================================================== +--- src/Makefile (revision 100) ++++ src/Makefile (working copy) +@@ -105,7 +105,7 @@ + runlevel: runlevel.o + + sulogin: LDLIBS += $(SULOGINLIBS) $(STATIC) +-sulogin: sulogin.o ++sulogin: sulogin.o consoles.o + + wall: dowall.o wall.o + diff --git a/sysvinit.changes b/sysvinit.changes index 45045c0..eee74ba 100644 --- a/sysvinit.changes +++ b/sysvinit.changes @@ -1,4 +1,11 @@ -------------------------------------------------------------------- +------------------------------------------------------------------ +Thu Mar 31 16:14:55 CEST 2011 - werner@suse.de + +- Remove debug code from showconsole/blogd +- Make serial console tc init work even with blogd +- sulogin: add support for multiple console devices + +------------------------------------------------------------------ Fri Mar 25 18:59:05 CET 2011 - werner@suse.de - New showconsole verion 1.14 diff --git a/sysvinit.spec b/sysvinit.spec index 4e8a8db..444ffbd 100644 --- a/sysvinit.spec +++ b/sysvinit.spec @@ -49,6 +49,7 @@ Patch1: sysvinit-2.82-startstop.patch Patch2: sysvinit-2.88dsf-suse.patch Patch3: sysvinit-2.88dsf-no-kill.patch Patch4: notify-pam-dead.patch +Patch5: sysvinit-2.88dsf-multiple-sulogin.patch Patch20: powerd-2.0.2.dif Patch21: powerd-2.0.2-getaddrinfo.patch Patch30: killproc-2.19.dif @@ -89,6 +90,7 @@ sysvinit package. %patch2 -p0 -b .suse %patch3 -p0 -b .no-kill %patch4 -p0 -b .pam +%patch5 -p0 -b .sulogin %patch pushd ../powerd-%{PDVER} %patch20