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.)
This commit is contained in:
Jesse Smith 2018-02-20 19:34:45 -04:00
parent f52d703c8e
commit 986bee63c0

View File

@ -57,6 +57,7 @@
char *Version = "@(#) bootlogd 2.86 03-Jun-2004 miquels@cistron.nl"; char *Version = "@(#) bootlogd 2.86 03-Jun-2004 miquels@cistron.nl";
#define LOGFILE "/var/log/boot" #define LOGFILE "/var/log/boot"
#define MAX_CONSOLES 16
char ringbuf[32768]; char ringbuf[32768];
char *endptr = ringbuf + sizeof(ringbuf); char *endptr = ringbuf + sizeof(ringbuf);
@ -68,6 +69,11 @@ int didnl = 1;
int createlogfile = 0; int createlogfile = 0;
int syncalot = 0; int syncalot = 0;
struct real_cons {
char name[1024];
int fd;
};
/* /*
* Console devices as listed on the kernel command line and * Console devices as listed on the kernel command line and
* the mapping to actual devices in /dev * 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). * the console device (/dev/console).
*/ */
int consolename(char *res, int rlen) int consolenames(struct real_cons *cons, int max_consoles)
{ {
#ifdef TIOCGDEV #ifdef TIOCGDEV
unsigned int kdev; unsigned int kdev;
@ -242,34 +248,9 @@ int consolename(char *res, int rlen)
char buf[256]; char buf[256];
char *p; char *p;
int didmount = 0; int didmount = 0;
int n, r; int n;
int fd; int fd;
int considx, num_consoles = 0;
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
#ifdef __linux__ #ifdef __linux__
/* /*
@ -278,7 +259,7 @@ int consolename(char *res, int rlen)
stat("/", &st); stat("/", &st);
if (stat("/proc", &st2) < 0) { if (stat("/proc", &st2) < 0) {
perror("bootlogd: /proc"); perror("bootlogd: /proc");
return -1; return 0;
} }
if (st.st_dev == st2.st_dev) { if (st.st_dev == st2.st_dev) {
if (mount("proc", "/proc", "proc", 0, NULL) < 0) { if (mount("proc", "/proc", "proc", 0, NULL) < 0) {
@ -288,21 +269,21 @@ int consolename(char *res, int rlen)
didmount = 1; didmount = 1;
} }
n = 0; n = -1;
r = -1;
if ((fd = open("/proc/cmdline", O_RDONLY)) < 0) { if ((fd = open("/proc/cmdline", O_RDONLY)) < 0) {
perror("bootlogd: /proc/cmdline"); perror("bootlogd: /proc/cmdline");
} else { } else {
buf[0] = 0; buf[0] = 0;
if ((n = read(fd, buf, sizeof(buf) - 1)) >= 0) if ((n = read(fd, buf, sizeof(buf) - 1)) < 0)
r = 0;
else
perror("bootlogd: /proc/cmdline"); perror("bootlogd: /proc/cmdline");
close(fd); close(fd);
} }
if (didmount) umount("/proc"); if (didmount) umount("/proc");
if (n < 0) return 0;
if (r < 0) return r;
/* /*
* OK, so find console= in /proc/cmdline. * OK, so find console= in /proc/cmdline.
@ -310,21 +291,32 @@ int consolename(char *res, int rlen)
*/ */
p = buf + n; p = buf + n;
*p-- = 0; *p-- = 0;
r = -1;
while (p >= buf) { while (p >= buf) {
if (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') { if (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') {
*p-- = 0; *p-- = 0;
continue; continue;
} }
if (strncmp(p, "console=", 8) == 0 && if (strncmp(p, "console=", 8) == 0 &&
isconsole(p + 8, res, rlen)) { isconsole(p + 8, cons[num_consoles].name, sizeof(cons[num_consoles].name))) {
r = 0; /*
break; * 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--; p--;
} }
if (r == 0) return r; if (num_consoles > 0) return num_consoles;
#endif #endif
/* /*
@ -332,12 +324,12 @@ int consolename(char *res, int rlen)
* guess the default console. * guess the default console.
*/ */
for (n = 0; defcons[n]; n++) for (n = 0; defcons[n]; n++)
if (isconsole(defcons[n], res, rlen)) if (isconsole(defcons[n], cons[0].name, sizeof(cons[0].name)))
return 0; return 1;
fprintf(stderr, "bootlogd: cannot deduce real console device\n"); 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; struct timeval tv;
fd_set fds; fd_set fds;
char buf[1024]; char buf[1024];
char realcons[1024];
char *p; char *p;
char *logfile; char *logfile;
char *pidfile; char *pidfile;
@ -492,6 +483,9 @@ int main(int argc, char **argv)
#ifndef __linux__ /* BSD-style ioctl needs an argument. */ #ifndef __linux__ /* BSD-style ioctl needs an argument. */
int on = 1; int on = 1;
#endif #endif
int considx;
struct real_cons cons[MAX_CONSOLES];
int num_consoles, consoles_left;
fp = NULL; fp = NULL;
logfile = LOGFILE; logfile = LOGFILE;
@ -538,6 +532,7 @@ int main(int argc, char **argv)
/* /*
* Open console device directly. * Open console device directly.
*/ */
/*
if (consolename(realcons, sizeof(realcons)) < 0) if (consolename(realcons, sizeof(realcons)) < 0)
return 1; return 1;
@ -550,6 +545,25 @@ int main(int argc, char **argv)
fprintf(stderr, "bootlogd: %s: %s\n", realcons, strerror(errno)); fprintf(stderr, "bootlogd: %s: %s\n", realcons, strerror(errno));
return 1; 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. * 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) { if ((n = read(ptm, inptr, endptr - inptr)) >= 0) {
/* /*
* Write data (in chunks if needed) * Write data (in chunks if needed)
* to the real output device. * to the real output devices.
*/ */
m = n; for (considx = 0; considx < num_consoles; considx++) {
p = inptr; if (cons[considx].fd < 0) continue;
while (m > 0) { m = n;
i = write(realfd, p, m); p = inptr;
if (i >= 0) { while (m > 0) {
m -= i; i = write(cons[considx].fd, p, m);
p += i; if (i >= 0) {
continue; m -= i;
} p += i;
/* continue;
* Handle EIO (somebody hung }
* up our filedescriptor) /*
*/ * Handle EIO (somebody hung
realfd = write_err(pts, realfd, * up our filedescriptor)
realcons, errno); */
if (realfd >= 0) continue; cons[considx].fd = write_err(pts,
got_signal = 1; /* Not really */ cons[considx].fd,
break; 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(pts);
close(ptm); close(ptm);
close(realfd); for (considx = 0; considx < num_consoles; considx++) {
close(cons[considx].fd);
}
return 0; return 0;
} }