/* * bootlogd.c Store output from the console during bootup into a file. * The file is usually located on the /var partition, and * gets written (and fsynced) as soon as possible. * * Version: @(#)bootlogd 2.74 01-Apr-1998 miquels@cistron.nl * * Bugs: Uses openpty(), only available in glibc. Sorry. * * This file is part of the sysvinit suite, * Copyright 1991-1998 Miquel van Smoorenburg. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include char *Version = "@(#) bootlogd 2.74 01-Apr-1998 MvS"; /* * Until the kernel knows about TIOCGDEV, use a really ugly * non-portable (not even between architectures) hack. */ #define TIOCTTYGSTRUCT_HACK 1 /* * Scan /dev and find the device name. * Side-effect: directory is changed to /dev */ int findtty(char *res, dev_t dev) { DIR *dir; struct dirent *ent; struct stat st; int r = 0; if (chdir("/dev") < 0 || (dir = opendir(".")) == NULL) { perror("bootlogd: /dev"); return -1; } while ((ent = readdir(dir)) != NULL) { if (lstat(ent->d_name, &st) != 0) continue; if (!S_ISCHR(st.st_mode)) continue; if (st.st_rdev == dev) { printf("Found it: %s: %04x\n", ent->d_name, (int)st.st_rdev); break; } } if (ent == NULL) { fprintf(stderr, "bootlogd: cannot find console device\n"); r = -1; } else strcpy(res, ent->d_name); closedir(dir); return r; } /* * Find out the _real_ console. Assume that stdin is connected to * the console device (/dev/console). */ int consolename(char *res) { struct stat st; #if TIOCTTYGSTRUCT_HACK char buf[4096]; struct utsname uts; int offset = -1; int *kdev; dev_t dev; #endif fstat(0, &st); if (st.st_rdev != 0x0501 && 0) { /* * Old kernel, can find real device easily. */ printf("Looking for device %04x\n", (int)st.st_rdev); return findtty(res, st.st_rdev); } /* * New kernel and new console device - hard to find * out what device the real console is .. */ #if TIOCTTYGSTRUCT_HACK if (ioctl(0, TIOCTTYGSTRUCT, buf) != 0) { perror("bootlogd: TIOCTTYGSTRUCT"); return -1; } uname(&uts); if (strncmp(uts.release, "2.0.", 4) == 0) offset = 236; if (strncmp(uts.release, "2.1.", 4) == 0) offset = 268; if (offset < 0) { fprintf(stderr, "bootlogd: don't know offsetof" "(struct tty_struct, device) for %s\n", uts.release); return -1; } kdev = (int *)(&buf[offset]); dev = (dev_t)(*kdev); printf("Looking for device %04x\n", (int)dev); return findtty(res, st.st_rdev); #endif } int main(int argc, char **argv) { int ptm, pts; char buf[1024]; int realfd; int n; /* * Open console device directly. */ if (consolename(buf) < 0) return 1; if ((realfd = open(buf, O_WRONLY)) < 0) { fprintf(stderr, "bootlogd: %s: %s\n", buf, strerror(errno)); return 1; } /* * Grab a pty, and redirect console messages to it. */ if (openpty(&ptm, &pts, buf, NULL, NULL) < 0) { fprintf(stderr, "bootlogd: cannot allocate pseudo tty\n"); return 1; } (void)ioctl(0, TIOCCONS, NULL); if (ioctl(pts, TIOCCONS, NULL) < 0) { perror("bootlogd: TIOCCONS"); return 1; } /* * Read the console messages from the pty, and write * to the real console. */ while((n = read(ptm, buf, sizeof(buf))) >= 0) { write(realfd, buf, n); } close(pts); close(ptm); close(realfd); return 0; }