600 lines
14 KiB
Plaintext
600 lines
14 KiB
Plaintext
--- blogd.c
|
|
+++ blogd.c 2006-08-10 18:41:55.000000000 +0200
|
|
@@ -155,25 +155,60 @@ static void reset_signal(int sig, struct
|
|
* To be able to reconnect to real tty on EIO
|
|
*/
|
|
static char * tty;
|
|
+static char * second;
|
|
static void reconnect(int fd)
|
|
{
|
|
int newfd = -1;
|
|
|
|
- if ((newfd = open(tty, O_WRONLY|O_NONBLOCK|O_NOCTTY)) < 0)
|
|
- error("can not open %s: %s\n", tty, strerror(errno));
|
|
-
|
|
- if (newfd != 1)
|
|
- dup2(newfd, 1);
|
|
- if (newfd != 2)
|
|
- dup2(newfd, 2);
|
|
-
|
|
- if (fd == 1 || fd == 2)
|
|
- goto out;
|
|
- if (newfd != fd)
|
|
- dup2(newfd, fd);
|
|
-out:
|
|
- if (newfd > 2)
|
|
- close(newfd);
|
|
+ switch (fd) {
|
|
+ case 0: /* Standard in */
|
|
+
|
|
+ if (tty == (char*)0)
|
|
+ break;
|
|
+
|
|
+ if ((newfd = open(tty, O_RDWR|O_NONBLOCK|O_NOCTTY)) < 0)
|
|
+ error("can not open %s: %s\n", tty, strerror(errno));
|
|
+
|
|
+ if (newfd != 0) {
|
|
+ dup2(newfd, 0);
|
|
+ close(newfd);
|
|
+ }
|
|
+
|
|
+ break;
|
|
+
|
|
+ case 1: /* Standard out */
|
|
+ case 2: /* Standard error */
|
|
+
|
|
+ if (tty == (char*)0)
|
|
+ break;
|
|
+
|
|
+ if ((newfd = open(tty, O_WRONLY|O_NONBLOCK|O_NOCTTY)) < 0)
|
|
+ error("can not open %s: %s\n", tty, strerror(errno));
|
|
+
|
|
+ if (newfd != 1)
|
|
+ dup2(newfd, 1);
|
|
+ if (newfd != 2)
|
|
+ dup2(newfd, 2);
|
|
+ if (newfd > 2)
|
|
+ close(newfd);
|
|
+
|
|
+ break;
|
|
+
|
|
+ default: /* IO of second console */
|
|
+
|
|
+ if (second == (char*)0)
|
|
+ break;
|
|
+
|
|
+ if ((newfd = open(second, O_WRONLY|O_NONBLOCK|O_NOCTTY)) < 0)
|
|
+ error("can not open %s: %s\n", second, strerror(errno));
|
|
+
|
|
+ if (newfd != fd) {
|
|
+ dup2(newfd, fd);
|
|
+ close(newfd);
|
|
+ }
|
|
+
|
|
+ break;
|
|
+ }
|
|
}
|
|
|
|
/*
|
|
@@ -181,7 +216,7 @@ out:
|
|
*/
|
|
int main(int argc, char *argv[])
|
|
{
|
|
- int fd, flags;
|
|
+ int fd, fd2, flags;
|
|
int ptm, pts, cntrtty = 1;
|
|
pid_t pid, ppid = getppid();
|
|
char ptsname[NAME_MAX+1];
|
|
@@ -198,7 +233,7 @@ int main(int argc, char *argv[])
|
|
if (argc == 2)
|
|
tty = argv[1];
|
|
else
|
|
- tty = fetchtty(getpid(), ppid);
|
|
+ tty = fetchtty(getpid(), ppid, NULL);
|
|
|
|
if (!tty || !*tty)
|
|
error("can not discover real system console tty, boot logging disabled.\n");
|
|
@@ -241,6 +276,38 @@ int main(int argc, char *argv[])
|
|
if (!w.ws_col)
|
|
w.ws_row = 80;
|
|
|
|
+ fd2 = -1;
|
|
+ do {
|
|
+
|
|
+ if ((second = secondtty(tty)) == (char*)0)
|
|
+ break;
|
|
+
|
|
+ if ((fd2 = open(second, O_WRONLY|O_NONBLOCK|O_NOCTTY)) < 0) {
|
|
+ warn("can not open %s: %s\n", second, strerror(errno));
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ if ((flags = fcntl(fd2, F_GETFL)) < 0) {
|
|
+ warn("can not get terminal flags of %s: %s\n", second, strerror(errno));
|
|
+ close(fd2);
|
|
+ fd2 = -1;
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ flags &= ~(O_NONBLOCK);
|
|
+ flags |= O_NOCTTY;
|
|
+ if (fcntl(fd2, F_SETFL, flags) < 0) {
|
|
+ warn("can not set terminal flags of %s: %s\n", second, strerror(errno));
|
|
+ close(fd2);
|
|
+ fd2 = -1;
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ out:
|
|
+ free(second);
|
|
+
|
|
+ } while (0);
|
|
+
|
|
if (openpty(&ptm, &pts, ptsname, &t, &w) < 0)
|
|
error("can not open pty/tty pair: %s\n", strerror(errno));
|
|
|
|
@@ -268,12 +335,15 @@ int main(int argc, char *argv[])
|
|
dup2(fd, 1);
|
|
dup2(fd, 2);
|
|
close(ptm);
|
|
- close(fd);
|
|
+ if (fd > 2)
|
|
+ close(fd);
|
|
break;
|
|
case -1:
|
|
close(pts);
|
|
close(ptm);
|
|
close(fd);
|
|
+ if (fd2 > 0)
|
|
+ close(fd2);
|
|
error("can not fork to become daemon: %s\n", strerror(errno));
|
|
break;
|
|
default:
|
|
@@ -282,12 +352,13 @@ int main(int argc, char *argv[])
|
|
close(pts);
|
|
close(ptm);
|
|
close(fd);
|
|
+ if (fd2 > 0)
|
|
+ close(fd2);
|
|
fprintf(stdout, "\rBoot logging started on %s(%s) at %.24s\n", tty, name, stt);
|
|
fflush(stdout);
|
|
exit(0);
|
|
}
|
|
- free(name);
|
|
- prepareIO(reconnect, pidfile, 0, 1);
|
|
+ prepareIO(reconnect, pidfile, 0, 1, fd2);
|
|
while (!signaled)
|
|
safeIO();
|
|
|
|
@@ -297,6 +368,10 @@ int main(int argc, char *argv[])
|
|
if (!cntrtty)
|
|
kill(ppid, SIGCONT);
|
|
|
|
+ if (fd2 > 0) {
|
|
+ (void)tcflush(fd2, TCOFLUSH);
|
|
+ close(fd2);
|
|
+ }
|
|
(void)tcflush(1, TCOFLUSH);
|
|
close(1);
|
|
(void)tcflush(2, TCOFLUSH);
|
|
--- libconsole.c
|
|
+++ libconsole.c 2006-08-10 18:41:23.000000000 +0200
|
|
@@ -158,41 +158,52 @@ static void (*vc_reconnect)(int fd) = NU
|
|
static inline void safeout (int fd, const char *ptr, size_t s)
|
|
{
|
|
int saveerr = errno;
|
|
- static int repeated;
|
|
+ int repeated = 0;
|
|
+ static int eiocount;
|
|
|
|
- repeated = 0;
|
|
while (s > 0) {
|
|
ssize_t p = write (fd, ptr, s);
|
|
if (p < 0) {
|
|
- if (repeated++ > 1000)
|
|
- error("Repeated error on writing to fd %d: %s\n", fd, STRERR);
|
|
- if (errno == EPIPE)
|
|
+ if (errno == EPIPE) {
|
|
+ warn("error on writing to fd %d: %s\n", fd, STRERR);
|
|
exit (0);
|
|
+ }
|
|
if (errno == EINTR) {
|
|
errno = 0;
|
|
continue;
|
|
}
|
|
if (errno == EAGAIN) { /* Kernel 2.6 seems todo this very often */
|
|
+ int ret;
|
|
fd_set check;
|
|
- struct timeval two = {2, 0};
|
|
|
|
- errno = 0;
|
|
+ if (repeated++ > 1000)
|
|
+ error("repeated error on writing to fd %d: %s\n", fd, STRERR);
|
|
+
|
|
FD_ZERO (&check);
|
|
FD_SET (fd, &check);
|
|
|
|
/* Avoid high load: wait upto two seconds if system is not ready */
|
|
- select(fd + 1, (fd_set*)0, &check, (fd_set*)0, &two);
|
|
errno = 0;
|
|
+ do {
|
|
+ struct timeval two = {2, 0};
|
|
+ ret = select(fd + 1, (fd_set*)0, &check, (fd_set*)0, &two);
|
|
+
|
|
+ } while ((ret < 0) && (errno == EINTR));
|
|
+
|
|
+ if (ret < 0)
|
|
+ error("can not write to fd %d: %s\n", fd, STRERR);
|
|
|
|
+ errno = 0;
|
|
continue;
|
|
}
|
|
- if (errno == EIO && vc_reconnect) {
|
|
+ if (errno == EIO) {
|
|
+ if ((eiocount++ > 10) || !vc_reconnect)
|
|
+ error("can not write to fd %d: %s\n", fd, STRERR);
|
|
(*vc_reconnect)(fd);
|
|
- vc_reconnect = NULL;
|
|
errno = 0;
|
|
continue;
|
|
}
|
|
- error("Can not write to fd %d: %s\n", fd, STRERR);
|
|
+ error("can not write to fd %d: %s\n", fd, STRERR);
|
|
}
|
|
repeated = 0;
|
|
ptr += p;
|
|
@@ -267,6 +278,7 @@ out:
|
|
*/
|
|
static FILE * flog = NULL;
|
|
static int fdwrite = -1;
|
|
+static int fdsec = -1;
|
|
static int fdread = -1;
|
|
static int fdfifo = -1;
|
|
|
|
@@ -714,12 +726,13 @@ static void *action(void *dummy)
|
|
static void (*rw_connect)(void) = NULL;
|
|
static const char *fifo_name = _PATH_BLOG_FIFO;
|
|
|
|
-void prepareIO(void (*rfunc)(int), void (*cfunc)(void), const int in, const int out)
|
|
+void prepareIO(void (*rfunc)(int), void (*cfunc)(void), const int in, const int out, const int second)
|
|
{
|
|
vc_reconnect = rfunc;
|
|
rw_connect = cfunc;
|
|
fdread = in;
|
|
fdwrite = out;
|
|
+ fdsec = second;
|
|
|
|
if (fifo_name && fdfifo < 0) {
|
|
struct stat st;
|
|
@@ -729,7 +742,7 @@ void prepareIO(void (*rfunc)(int), void
|
|
(void)mkfifo(fifo_name, 0600);
|
|
errno = 0;
|
|
if (!stat(fifo_name, &st) && S_ISFIFO(st.st_mode)) {
|
|
- if ((fdfifo = open(fifo_name, O_RDWR)) < 0)
|
|
+ if ((fdfifo = open(fifo_name, O_RDWR|O_NOCTTY)) < 0)
|
|
warn("can not open named fifo %s: %s\n", fifo_name, STRERR);
|
|
}
|
|
}
|
|
@@ -769,12 +782,17 @@ static void more_input (struct timeval *
|
|
const ssize_t cnt = safein(fdread, (char*)trans, sizeof(trans));
|
|
|
|
if (cnt > 0) {
|
|
- parselog(trans, cnt); /* Parse and make copy of the input */
|
|
+ parselog(trans, cnt); /* Parse and make copy of the input */
|
|
+
|
|
+ safeout(fdwrite, (char*)trans, cnt); /* Write copy of input to real tty */
|
|
+ (void)tcdrain(fdwrite);
|
|
|
|
- safeout(fdwrite, (char*)trans, cnt); /* Write copy of input to real tty */
|
|
- tcdrain(fdwrite);
|
|
+ if (fdsec > 0) {
|
|
+ safeout(fdsec, (char*)trans, cnt); /* Write copy of input to second tty */
|
|
+ (void)tcdrain(fdsec);
|
|
+ }
|
|
|
|
- flushlog();
|
|
+ flushlog();
|
|
}
|
|
}
|
|
|
|
@@ -883,6 +901,8 @@ void closeIO(void)
|
|
} else
|
|
warn("no message logging because /var file system is not accessible\n");
|
|
(void)tcdrain(fdwrite); /* Hold in sync with console */
|
|
+ if (fdsec > 0)
|
|
+ (void)tcdrain(fdsec); /* Hold in sync with second console */
|
|
|
|
do {
|
|
/*
|
|
@@ -926,6 +946,8 @@ void closeIO(void)
|
|
flog = NULL;
|
|
xout:
|
|
(void)tcdrain(fdwrite);
|
|
+ if (fdsec > 0)
|
|
+ (void)tcdrain(fdsec);
|
|
|
|
return;
|
|
}
|
|
@@ -941,7 +963,7 @@ static void ctty(pid_t pid, unsigned int
|
|
int fd;
|
|
|
|
sprintf(fetched, "/proc/%d/stat", (int)pid);
|
|
- if ((fd = open(fetched, O_RDONLY)) < 0)
|
|
+ if ((fd = open(fetched, O_RDONLY|O_NOCTTY)) < 0)
|
|
error("can not open(%s): %s\n", fetched, STRERR);
|
|
cnt = safein(fd, fetched, sizeof(fetched));
|
|
close(fd);
|
|
@@ -1034,12 +1056,11 @@ static int checkdev(char ** retname, uns
|
|
int found = 0;
|
|
struct dirent * d;
|
|
struct stat st;
|
|
- char * name = NULL;
|
|
static int deep;
|
|
|
|
memset(&st, 0, sizeof(struct stat));
|
|
while ((d = readdir(dev))) {
|
|
- name = d->d_name;
|
|
+ char * name = d->d_name;
|
|
|
|
if (*name == '.')
|
|
continue;
|
|
@@ -1143,6 +1164,14 @@ static int checkdev(char ** retname, uns
|
|
}
|
|
|
|
found++;
|
|
+
|
|
+ /*
|
|
+ * Allocate memory to be able to return several
|
|
+ * different buffers for different files names.
|
|
+ */
|
|
+ name = strdup(name);
|
|
+ if (!name)
|
|
+ error("checkdev(): %s\n", STRERR);
|
|
*retname = name;
|
|
break;
|
|
}
|
|
@@ -1151,7 +1180,7 @@ static int checkdev(char ** retname, uns
|
|
}
|
|
|
|
/* main routine to fetch tty */
|
|
-char * fetchtty(const pid_t pid, const pid_t ppid)
|
|
+char * fetchtty(const pid_t pid, const pid_t ppid, unsigned int *mjmi)
|
|
{
|
|
unsigned int tty = 0, found = 0;
|
|
char * name = NULL;
|
|
@@ -1167,14 +1196,15 @@ char * fetchtty(const pid_t pid, const p
|
|
if (!(name = ttyname(0)) || !strcmp(name, "/dev/console"))
|
|
tty = fallback(pid, ppid);
|
|
else {
|
|
- strcpy(lnk, name);
|
|
- free(name);
|
|
- name = lnk;
|
|
+ name = strdup(name);
|
|
+ if (!name)
|
|
+ error("fetchtty(): %s\n", STRERR);
|
|
goto out;
|
|
}
|
|
#ifdef TIOCGDEV
|
|
}
|
|
#endif
|
|
+ if (mjmi) *mjmi = tty;
|
|
|
|
if (!(dev = opendir("/dev")))
|
|
error("can not opendir(/dev): %s\n", STRERR);
|
|
@@ -1186,8 +1216,131 @@ char * fetchtty(const pid_t pid, const p
|
|
if (!name)
|
|
goto out;
|
|
|
|
- if (!found)
|
|
- *name = '\0';
|
|
+ if (!found) {
|
|
+ free(name);
|
|
+ name = (char*)0;
|
|
+ }
|
|
out:
|
|
return name;
|
|
}
|
|
+
|
|
+/* Do we have some more system console around? */
|
|
+char * secondtty(char * compare)
|
|
+{
|
|
+ char buf[1024], *ptr, *shcmp, *res = (char*)0;
|
|
+ unsigned int tty = 0, found = 0;
|
|
+ int fd = -1, len;
|
|
+ char * name = (char*)0;
|
|
+ DIR * dev;
|
|
+
|
|
+ if ((fd = open("/proc/cmdline", O_RDONLY|O_NOCTTY)) < 0) {
|
|
+ warn("can not open /proc/cmdline\n");
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ if ((len = read(fd, buf, sizeof(buf) - 1)) < 0) {
|
|
+ warn("can not read /proc/cmdline\n");
|
|
+ close(fd);
|
|
+ goto out;
|
|
+ }
|
|
+ close(fd);
|
|
+
|
|
+ if (len == 0)
|
|
+ goto out;
|
|
+
|
|
+ shcmp = compare;
|
|
+ if (!strncmp(shcmp, "/dev/", 5))
|
|
+ shcmp += 5;
|
|
+
|
|
+ /*
|
|
+ * Check for e.g. /dev/tty[1-9] which is equal to /dev/tty0
|
|
+ */
|
|
+ if (!strncmp(shcmp, "tty", 3)) {
|
|
+ size_t len = strspn(shcmp + 3, "123456789");
|
|
+
|
|
+ if (strlen(shcmp) == len + 3) {
|
|
+ compare = "/dev/tty0";
|
|
+ shcmp = "tty0";
|
|
+ }
|
|
+ }
|
|
+
|
|
+ ptr = &buf[len];
|
|
+ while (ptr >= &buf[0]) {
|
|
+ if (*ptr == ',' || *ptr == ' ' || *ptr == '\t' || *ptr == '\r' || *ptr == '\n') {
|
|
+ *ptr-- = 0;
|
|
+ continue;
|
|
+ }
|
|
+ if (*ptr == 'c' && !strncmp(ptr, "console=", 8)) {
|
|
+ char * console = ptr + 8;
|
|
+
|
|
+ if (!strncmp(console, "/dev/", 5))
|
|
+ console += 5;
|
|
+
|
|
+ /*
|
|
+ * Compare known console tty with that of the kernel command
|
|
+ * line. If already known skip this console tty and search
|
|
+ * for the next one.
|
|
+ */
|
|
+ if (strcmp(shcmp, console)) {
|
|
+ res = console; /* New device not identical to tty */
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ ptr--;
|
|
+ }
|
|
+
|
|
+ if (!res)
|
|
+ goto out;
|
|
+
|
|
+ if (!(dev = opendir("/dev")))
|
|
+ error("can not opendir(/dev): %s\n", STRERR);
|
|
+ pushd("/dev");
|
|
+
|
|
+ /* Open second console e.g. /dev/tty0 */
|
|
+ if ((fd = open(res, O_RDWR|O_NONBLOCK|O_NOCTTY)) < 0)
|
|
+ goto out;
|
|
+
|
|
+ /*
|
|
+ * We do this because if we would write out the buffered
|
|
+ * messages to e.g. /dev/tty0 after this we would (re)read
|
|
+ * those and buffer them again which leads to an endless loop.
|
|
+ */
|
|
+#ifdef TIOCGDEV
|
|
+ if (ioctl (fd, TIOCGDEV, &tty) < 0) {
|
|
+ if (errno == EINVAL && !getenv("NOTIOCGDEV"))
|
|
+ warn("Warning: the ioctl TIOCGDEV is not known by the kernel\n");
|
|
+ close(fd);
|
|
+ popd();
|
|
+ closedir(dev);
|
|
+ goto out;
|
|
+ }
|
|
+#else
|
|
+# error The ioctl TIOCGDEV is not defined (SuSE TIOCGDEV patch is missed)
|
|
+#endif
|
|
+ close(fd);
|
|
+
|
|
+ /* Try to open the real device e.g. /dev/tty1 */
|
|
+ found = checkdev(&name, tty, dev);
|
|
+
|
|
+ popd();
|
|
+ closedir(dev);
|
|
+
|
|
+ if (!name)
|
|
+ goto out;
|
|
+
|
|
+ if (!found) {
|
|
+ free(name);
|
|
+ name = (char*)0;
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ if (!strcmp(compare, name)) {
|
|
+ free(name);
|
|
+ name = (char*)0;
|
|
+ goto out; /* Already in use */
|
|
+ }
|
|
+
|
|
+ return name;
|
|
+out:
|
|
+ return (char*)0;
|
|
+}
|
|
--- libconsole.h
|
|
+++ libconsole.h 2006-08-10 18:41:28.000000000 +0200
|
|
@@ -1,6 +1,7 @@
|
|
extern void pushd(const char * path);
|
|
extern void popd(void);
|
|
-extern char * fetchtty(const pid_t pid, const pid_t ppid);
|
|
-extern void prepareIO(void (*rfunc)(int), void (*cfunc)(void), const int in, const int out);
|
|
+extern char * fetchtty(const pid_t pid, const pid_t ppid, unsigned int *mjmi);
|
|
+extern char * secondtty(char * compare);
|
|
+extern void prepareIO(void (*rfunc)(int), void (*cfunc)(void), const int in, const int out, const int second);
|
|
extern void safeIO (void);
|
|
extern void closeIO(void);
|
|
--- showconsole.8
|
|
+++ showconsole.8 2006-08-10 18:55:37.000000000 +0200
|
|
@@ -16,6 +16,7 @@ Setconsole \- sets the underlying tty of
|
|
.SH SYNOPSIS
|
|
.\"
|
|
.B showconsole
|
|
+.RI [ -n ]
|
|
.PP
|
|
.B setconsole /dev/tty<xy> < /dev/console
|
|
.SH DESCRIPTION
|
|
@@ -38,6 +39,15 @@ with
|
|
and exactly one argument, a valid character device
|
|
is given.
|
|
\."
|
|
+.SH OPTIONS
|
|
+.TP
|
|
+.B \-n
|
|
+Return the major and minor device numbers instead of
|
|
+the device file name. This can be used to asked the
|
|
+kernel for the major and minor device numbers of a not
|
|
+existing device file in
|
|
+.IR /dev .
|
|
+\."
|
|
.SH BUGS
|
|
.B showconsole
|
|
needs a mounted
|
|
--- showconsole.c
|
|
+++ showconsole.c 2006-08-10 18:51:15.000000000 +0200
|
|
@@ -51,7 +51,7 @@ void warn (const char *fmt, ...)
|
|
*/
|
|
int main(int argc, char *argv[])
|
|
{
|
|
- char * tty = NULL;
|
|
+ char * tty = NULL, numeric = 0;
|
|
myname = basename(*argv);
|
|
|
|
if (!strcmp(myname, "setconsole")) {
|
|
@@ -73,8 +73,30 @@ int main(int argc, char *argv[])
|
|
close(fdc);
|
|
goto out;
|
|
}
|
|
- tty = fetchtty(getpid(), getppid());
|
|
- if (tty)
|
|
+
|
|
+ if (argc == 2) {
|
|
+ const char* opt = argv[1];
|
|
+ if (opt && *opt++ == '-' && *opt++ == 'n' && *opt == '\0')
|
|
+ numeric++;
|
|
+ else
|
|
+ error("Usage: %s [-n]\n", myname);
|
|
+ } else if (argc > 2)
|
|
+ error("Usage: %s [-n]\n", myname);
|
|
+
|
|
+ if (numeric) {
|
|
+ unsigned int dev = 0;
|
|
+ (void)fetchtty(getpid(), getppid(), &dev);
|
|
+
|
|
+ if (dev)
|
|
+ printf("%u %u\n", major(dev), minor(dev));
|
|
+ else {
|
|
+ error("real tty unknown\n");
|
|
+ fprintf(stderr, "real tty unknown\n");
|
|
+ }
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ if ((tty = fetchtty(getpid(), getppid(), NULL)))
|
|
printf("%s\n", tty);
|
|
else {
|
|
error("real tty unknown\n");
|