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";
#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 (r < 0) return r;
if (n < 0) return 0;
/*
* 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;
}