/* * init.c * * This is the install type init * * Erik Troan (ewt@redhat.com) * * Copyright 1996 Red Hat Software * * This software may be freely redistributed under the terms of the GNU * public license. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef __alpha__ #include #endif /* * this needs to handle the following cases: * * 1) run from a CD root filesystem * 2) run from a read only nfs rooted filesystem * 3) run from a floppy * 4) run from a floppy that's been loaded into a ramdisk * */ int doShutdown; #define __LIBRARY__ #include #ifndef __alpha__ # define __NR_sys_syslog __NR_syslog _syscall3(int,syslog,int, type, char *, buf, int, len); #else # define syslog klogctl #endif void fatal_error(int usePerror) { if (usePerror) perror("failed:"); else fprintf(stderr, "failed.\n"); fprintf(stderr, "\nI can't recover from this.\n"); while (1) ; } int doMke2fs(char * device, char * size) { char * args[] = { "/usr/bin/mke2fs", NULL, NULL, NULL }; int pid, status; args[1] = device; args[2] = size; if (!(pid = fork())) { execv("/usr/bin/mke2fs", args); fatal_error(1); } wait(&status); return 0; } int hasNetConfiged(void) { int rc; int s; struct ifconf configs; struct ifreq devs[10]; #ifdef __i386__ return 0; #endif s = socket(AF_INET, SOCK_STREAM, 0); if (s < 0) { perror("socket"); return 0; } else { /* this is just good enough to tell us if we have anything configured */ configs.ifc_len = sizeof(devs); configs.ifc_buf = (void *) devs; rc = ioctl(s, SIOCGIFCONF, &configs); if (rc < 0) { perror("SIOCGIFCONF"); return 0; } if (configs.ifc_len == 0) { return 0; } return 1; } return 0; } void doklog(char * fn) { fd_set readset, unixs; int in, out, i; size_t s; int sock; struct sockaddr_un sockaddr; char buf[1024]; int readfd; if (fork()) return; in = open("/proc/kmsg", O_RDONLY); if (in < 0) { perror("open /proc/kmsg"); return; } out = open(fn, O_WRONLY); if (out < 0) { close(in); perror("open kmsg log"); return; } /* now open the syslog socket */ sockaddr.sun_family = AF_UNIX; strcpy(sockaddr.sun_path, "/dev/log"); sock = socket(AF_UNIX, SOCK_STREAM, 0); if (sock < 1) { write(out, "socket error\n", 13); } if (bind(sock, (struct sockaddr *) &sockaddr, sizeof(sockaddr.sun_family) + strlen(sockaddr.sun_path))) { write(out, "bind error\n", 11); } chmod("/dev/log", 0666); if (listen(sock, 5)) { write(out, "listen error\n", 13); } syslog(8, NULL, 1); FD_ZERO(&unixs); while (1) { memcpy(&readset, &unixs, sizeof(unixs)); FD_SET(sock, &readset); FD_SET(in, &readset); i = select(FD_SETSIZE, &readset, NULL, NULL, NULL); if (i <= 0) continue; if (FD_ISSET(in, &readset)) { i = read(in, buf, sizeof(buf)); if (i > 0) write(out, buf, i); } for (readfd = 0; readfd < FD_SETSIZE; ++readfd) { if (FD_ISSET(readfd, &readset) && FD_ISSET(readfd, &unixs)) { i = read(readfd, buf, sizeof(buf)); if (i > 0) { write(out, buf, i); write(out, "\n", 1); } else if (i == 0) { /* socket closed */ close(readfd); FD_CLR(readfd, &unixs); } } } if (FD_ISSET(sock, &readset)) { i = sizeof(sockaddr); readfd = accept(sock, (struct sockaddr *) &sockaddr, &s); if (readfd < 0) { /*write(out, "error in accept\n", 16);*/ } else { FD_SET(readfd, &unixs); } } } } #if defined(__alpha__) char * findKernel(void) { char * dev, * file; struct stat sb; dev = getenv("bootdevice"); file = getenv("bootfile"); if (!dev || !file) { printf("I can't find your kernel. When you are booting" " from a CDROM, you must pass\n"); printf("the bootfile argument to the kernel if your" " boot loader doesn't do so automatically.\n"); printf("\n"); printf("You should now reboot your system and try " "again\n"); while (1) ; } if (!strcmp(dev, "fd0")) { if (!strcmp(file, "vmlinux.gz")) { printf("The kernel on a boot floppy must be named vmlinux.gz. " "You\n"); printf("are using a kernel named %s instead. You'll have " "to\n", file); printf("fix this and try again.\n"); while (1) ; } return NULL; } else { if (stat(file, &sb)) { printf("I can't find your kernel. When you are booting" " from a CDROM, you must pass\n"); printf("the bootfile argument to the kernel if your" " boot loader doesn't do so automatically.\n"); printf("\n"); printf("You should now reboot your system and try " "again\n"); while (1) ; } return file; } } #endif void main(void) { pid_t installpid, childpid; int waitStatus; int fd; int nfsRoot = 0; int roRoot = 0; int cdRoot = 0; char * kernel; /* turn off screen blanking */ printf("\033[9;0]"); printf("\033[8]"); printf("Red Hat install init version %s starting\n", VERSION); putenv("PATH=/usr/bin:/bin:/sbin:/usr/sbin:/mnt/sbin:/mnt/usr/sbin:" "/mnt/bin:/mnt/usr/bin"); putenv("LD_LIBRARY_PATH=/mnt/lib:/mnt/usr/lib"); sethostname("localhost", 9); printf("mounting /proc filesystem... "); fflush(stdout); if (mount("/proc", "/proc", "proc", 0, NULL)) fatal_error(1); printf("done\n"); doklog("/dev/tty4"); printf("checking for NFS root filesystem..."); fflush(stdout); if (hasNetConfiged()) { printf("yes\n"); roRoot = nfsRoot = 1; } else { printf("no\n"); } if (!nfsRoot) { printf("trying to remount root filesystem read write... "); if (mount("/", "/", NULL, MS_REMOUNT | MS_MGC_VAL, NULL)) { printf("failed (but that's okay)\n"); roRoot = 1; } else { printf("done\n"); /* 2.0.18 (at least) lets us remount a CD r/w!! */ printf("checking for writeable /tmp... "); fd = open("/tmp/tmp", O_WRONLY | O_CREAT, 0644); if (fd < 0) { printf("no (probably a CD rooted install)\n"); roRoot = 1; } else { close(fd); unlink("/tmp/tmp"); printf("yes\n"); } } } if (roRoot) { printf("creating 100k of ramdisk space... "); fflush(stdout); if (doMke2fs("/dev/ram", "100")) fatal_error(0); printf("done\n"); printf("mounting /tmp from ramdisk... "); fflush(stdout); if (mount("/dev/ram", "/tmp", "ext2", 0, NULL)) fatal_error(1); printf("done\n"); if (!nfsRoot) cdRoot = 1; } /* Now we have some /tmp space set up, and /etc and /dev point to it. We should be in pretty good shape. */ /* Go into normal init mode - keep going, and then do a orderly shutdown when: 1) /bin/install exits 2) we receive a SIGHUP */ printf("running install...\n"); if (!(installpid = fork())) { if (nfsRoot) { symlink("/", "/tmp/rhimage"); symlink("/", "/tmp/image"); execl("/usr/bin/runinstall2", "/usr/bin/runinstall2", "--method", "nfs", NULL); } else if (cdRoot) { symlink("/", "/tmp/rhimage"); symlink("/", "/tmp/image"); # if defined(__alpha__) kernel = findKernel(); if (kernel) execl("/usr/bin/runinstall2", "/usr/bin/runinstall2", "--method", "cdrom", "--kernel", kernel, NULL); else execl("/usr/bin/runinstall2", "/usr/bin/runinstall2", "--method", "cdrom", NULL); # else execl("/usr/bin/runinstall2", "/usr/bin/runinstall2", "--method", "cdrom", NULL); # endif } else { execl("/bin/install", "/bin/install", NULL); } exit(0); } while (!doShutdown) { childpid = wait(&waitStatus); if (childpid == installpid) doShutdown = 1; } sync(); sync(); printf("rebooting system\n"); /* this should unmount filesystems, kill processes, etc */ sleep(2); #ifdef __alpha__ reboot(RB_AUTOBOOT); #else reboot(0xfee1dead, 672274793, 0x1234567); #endif }