From 986bee63c05ad98bea77997be7dd2bfc957cfc2f Mon Sep 17 00:00:00 2001 From: Jesse Smith Date: Tue, 20 Feb 2018 19:34:45 -0400 Subject: [PATCH] Allow multiple console output When booting a kernel with multiple serial console support, or multuiple console arguments ala "console=tty1 console=ttyS0,9600" the kernel will output messages to all consoles, init however will not. It will only send output to, and accept input from, the last of the consoles. This patch fixes it. (Author is Martin Buck.) --- src/bootlogd.c | 154 ++++++++++++++++++++++++++++--------------------- 1 file changed, 89 insertions(+), 65 deletions(-) diff --git a/src/bootlogd.c b/src/bootlogd.c index e64bffb..a5428ff 100644 --- a/src/bootlogd.c +++ b/src/bootlogd.c @@ -57,6 +57,7 @@ char *Version = "@(#) bootlogd 2.86 03-Jun-2004 miquels@cistron.nl"; #define LOGFILE "/var/log/boot" +#define MAX_CONSOLES 16 char ringbuf[32768]; char *endptr = ringbuf + sizeof(ringbuf); @@ -68,6 +69,11 @@ int didnl = 1; int createlogfile = 0; int syncalot = 0; +struct real_cons { + char name[1024]; + int fd; +}; + /* * Console devices as listed on the kernel command line and * the mapping to actual devices in /dev @@ -230,10 +236,10 @@ int isconsole(char *s, char *res, int rlen) } /* - * Find out the _real_ console. Assume that stdin is connected to + * Find out the _real_ console(s). Assume that stdin is connected to * the console device (/dev/console). */ -int consolename(char *res, int rlen) +int consolenames(struct real_cons *cons, int max_consoles) { #ifdef TIOCGDEV unsigned int kdev; @@ -242,34 +248,9 @@ int consolename(char *res, int rlen) char buf[256]; char *p; int didmount = 0; - int n, r; + int n; int fd; - - fstat(0, &st); - if (major(st.st_rdev) != 5 || minor(st.st_rdev) != 1) { - /* - * Old kernel, can find real device easily. - */ - int r = findtty(res, "/dev", rlen, st.st_rdev); - if (0 != r) - fprintf(stderr, "bootlogd: cannot find console device " - "%d:%d under /dev\n", major(st.st_rdev), minor(st.st_rdev)); - return r; - } - -#ifdef TIOCGDEV -# ifndef ENOIOCTLCMD -# define ENOIOCTLCMD 515 -# endif - if (ioctl(0, TIOCGDEV, &kdev) == 0) { - int r = findtty(res, "/dev", rlen, (dev_t)kdev); - if (0 != r) - fprintf(stderr, "bootlogd: cannot find console device " - "%d:%d under /dev\n", major(kdev), minor(kdev)); - return r; - } - if (errno != ENOIOCTLCMD) return -1; -#endif + int considx, num_consoles = 0; #ifdef __linux__ /* @@ -278,7 +259,7 @@ int consolename(char *res, int rlen) stat("/", &st); if (stat("/proc", &st2) < 0) { perror("bootlogd: /proc"); - return -1; + return 0; } if (st.st_dev == st2.st_dev) { if (mount("proc", "/proc", "proc", 0, NULL) < 0) { @@ -288,21 +269,21 @@ int consolename(char *res, int rlen) didmount = 1; } - n = 0; - r = -1; + n = -1; if ((fd = open("/proc/cmdline", O_RDONLY)) < 0) { perror("bootlogd: /proc/cmdline"); } else { buf[0] = 0; - if ((n = read(fd, buf, sizeof(buf) - 1)) >= 0) - r = 0; - else + if ((n = read(fd, buf, sizeof(buf) - 1)) < 0) perror("bootlogd: /proc/cmdline"); close(fd); } if (didmount) umount("/proc"); + + + if (n < 0) return 0; + - if (r < 0) return r; /* * OK, so find console= in /proc/cmdline. @@ -310,21 +291,32 @@ int consolename(char *res, int rlen) */ p = buf + n; *p-- = 0; - r = -1; while (p >= buf) { if (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') { *p-- = 0; continue; } if (strncmp(p, "console=", 8) == 0 && - isconsole(p + 8, res, rlen)) { - r = 0; - break; + isconsole(p + 8, cons[num_consoles].name, sizeof(cons[num_consoles].name))) { + /* + * Suppress duplicates + */ + for (considx = 0; considx < num_consoles; considx++) { + if (!strcmp(cons[num_consoles].name, cons[considx].name)) { + goto dontuse; + } + } + + num_consoles++; + if (num_consoles >= max_consoles) { + break; + } } +dontuse: p--; } - if (r == 0) return r; + if (num_consoles > 0) return num_consoles; #endif /* @@ -332,12 +324,12 @@ int consolename(char *res, int rlen) * guess the default console. */ for (n = 0; defcons[n]; n++) - if (isconsole(defcons[n], res, rlen)) - return 0; + if (isconsole(defcons[n], cons[0].name, sizeof(cons[0].name))) + return 1; fprintf(stderr, "bootlogd: cannot deduce real console device\n"); - return -1; + return 0; } @@ -479,7 +471,6 @@ int main(int argc, char **argv) struct timeval tv; fd_set fds; char buf[1024]; - char realcons[1024]; char *p; char *logfile; char *pidfile; @@ -492,6 +483,9 @@ int main(int argc, char **argv) #ifndef __linux__ /* BSD-style ioctl needs an argument. */ int on = 1; #endif + int considx; + struct real_cons cons[MAX_CONSOLES]; + int num_consoles, consoles_left; fp = NULL; logfile = LOGFILE; @@ -538,6 +532,7 @@ int main(int argc, char **argv) /* * Open console device directly. */ + /* if (consolename(realcons, sizeof(realcons)) < 0) return 1; @@ -550,6 +545,25 @@ int main(int argc, char **argv) fprintf(stderr, "bootlogd: %s: %s\n", realcons, strerror(errno)); return 1; } + */ + if ((num_consoles = consolenames(cons, MAX_CONSOLES)) <= 0) + return 1; + consoles_left = num_consoles; + for (considx = 0; considx < num_consoles; considx++) { + if (strcmp(cons[considx].name, "/dev/tty0") == 0) + strcpy(cons[considx].name, "/dev/tty1"); + if (strcmp(cons[considx].name, "/dev/vc/0") == 0) + strcpy(cons[considx].name, "/dev/vc/1"); + + if ((cons[considx].fd = open_nb(cons[considx].name)) < 0) { + fprintf(stderr, "bootlogd: %s: %s\n", + cons[considx].name, strerror(errno)); + consoles_left--; + } + } + if (!consoles_left) + return 1; + /* * Grab a pty, and redirect console messages to it. @@ -633,26 +647,34 @@ int main(int argc, char **argv) if ((n = read(ptm, inptr, endptr - inptr)) >= 0) { /* * Write data (in chunks if needed) - * to the real output device. + * to the real output devices. */ - m = n; - p = inptr; - while (m > 0) { - i = write(realfd, p, m); - if (i >= 0) { - m -= i; - p += i; - continue; - } - /* - * Handle EIO (somebody hung - * up our filedescriptor) - */ - realfd = write_err(pts, realfd, - realcons, errno); - if (realfd >= 0) continue; - got_signal = 1; /* Not really */ - break; + for (considx = 0; considx < num_consoles; considx++) { + if (cons[considx].fd < 0) continue; + m = n; + p = inptr; + while (m > 0) { + i = write(cons[considx].fd, p, m); + if (i >= 0) { + m -= i; + p += i; + continue; + } + /* + * Handle EIO (somebody hung + * up our filedescriptor) + */ + cons[considx].fd = write_err(pts, + cons[considx].fd, + cons[considx].name, errno); + if (cons[considx].fd >= 0) continue; + /* + * If this was the last console, + * generate a fake signal + */ + if (--consoles_left <= 0) got_signal = 1; + break; + } } /* @@ -698,7 +720,9 @@ int main(int argc, char **argv) close(pts); close(ptm); - close(realfd); + for (considx = 0; considx < num_consoles; considx++) { + close(cons[considx].fd); + } return 0; }