home *** CD-ROM | disk | FTP | other *** search
- /*
- * 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.
- *
- */
-
- #if USE_MINILIBC
- #include "minilibc.h"
- #else
- #include <ctype.h>
- #include <errno.h>
- #include <fcntl.h>
- #include <net/if.h>
- #include <signal.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <sys/ioctl.h>
- #include <sys/klog.h>
- #include <sys/mount.h>
- #include <sys/socket.h>
- #include <sys/stat.h>
- #include <sys/time.h>
- #include <sys/types.h>
- #include <sys/un.h>
- #include <sys/wait.h>
- #include <unistd.h>
- #include <sys/ioctl.h>
- #include <sys/reboot.h>
- #include <termios.h>
-
-
- #define syslog klogctl
- #endif
-
- #define KICK_FLOPPY 1
- #define KICK_BOOTP 2
-
- #define MS_REMOUNT 32
-
- #define ENV_PATH 0
- #define ENV_LD_LIBRARY_PATH 1
- #define ENV_HOME 2
- #define ENV_TERM 3
- #define ENV_DEBUG 4
-
- char * environ[] = {
- "PATH=/usr/bin:/bin:/sbin:/usr/sbin:/mnt/sbin:/mnt/usr/sbin:"
- "/mnt/bin:/mnt/usr/bin",
- "LD_LIBRARY_PATH=/lib:/usr/lib:/mnt/lib:/mnt/usr/lib",
- "HOME=/",
- "TERM=linux",
- "DEBUG=",
- NULL
- };
-
-
- /*
- * 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 testing;
-
- void printstr(char * string) {
- write(1, string, strlen(string));
- }
-
- void fatal_error(int usePerror) {
- /* FIXME */
- #if 0
- if (usePerror)
- perror("failed:");
- else
- #endif
- printf("failed.\n");
-
- printf("\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())) {
- /* child */
- execve("/usr/bin/mke2fs", args, environ);
- fatal_error(1);
- }
-
- wait4(-1, &status, 0, NULL);
-
- 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) {
- /* FIXME was perror*/
- printf("error creating socket: %d\n", errno);
- 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) {
- /* FIXME was perror*/
- printstr("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;
- int log;
- int s;
- int sock = -1;
- struct sockaddr_un sockaddr;
- char buf[1024];
- int readfd;
-
- in = open("/proc/kmsg", O_RDONLY,0);
- if (in < 0) {
- /* FIXME: was perror */
- printstr("open /proc/kmsg");
- return;
- }
-
- out = open(fn, O_WRONLY, 0);
- if (out < 0)
- printf("couldn't open %s for syslog -- still using /tmp/syslog\n", fn);
-
- log = open("/tmp/syslog", O_WRONLY | O_CREAT, 0644);
- if (log < 0) {
- /* FIXME: was perror */
- printstr("error opening /tmp/syslog");
- sleep(5);
-
- close(in);
- return;
- }
-
- /* if we get this far, we should be in good shape */
-
- if (fork()) {
- /* parent */
- close(in);
- close(out);
- close(log);
- return;
- }
- close(0);
- close(1);
- close(2);
-
- dup2(1, log);
-
- #if defined(USE_LOGDEV)
- /* 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 < 0) {
- printf("error creating socket: %d\n", errno);
- sleep(5);
- }
- printstr("got socket\n");
- if (bind(sock, (struct sockaddr *) &sockaddr, sizeof(sockaddr.sun_family) +
- strlen(sockaddr.sun_path))) {
- printf("bind error: %d\n", errno);
- sleep(5);
- }
- printstr("bound socket\n");
- chmod("/dev/log", 0666);
- if (listen(sock, 5)) {
- printf("listen error: %d\n", errno);
- sleep(5);
- }
- #endif
-
- syslog(8, NULL, 1);
-
- FD_ZERO(&unixs);
- while (1) {
- memcpy(&readset, &unixs, sizeof(unixs));
-
- if (sock >= 0) FD_SET(sock, &readset);
- FD_SET(in, &readset);
-
- i = select(20, &readset, NULL, NULL, NULL);
- if (i <= 0) continue;
-
- if (FD_ISSET(in, &readset)) {
- i = read(in, buf, sizeof(buf));
- if (i > 0) {
- if (out >= 0) write(out, buf, i);
- write(log, buf, i);
- }
- }
-
- for (readfd = 0; readfd < 20; ++readfd) {
- if (FD_ISSET(readfd, &readset) && FD_ISSET(readfd, &unixs)) {
- i = read(readfd, buf, sizeof(buf));
- if (i > 0) {
- if (out >= 0) {
- write(out, buf, i);
- write(out, "\n", 1);
- }
-
- write(log, buf, i);
- write(log, "\n", 1);
- } else if (i == 0) {
- /* socket closed */
- close(readfd);
- FD_CLR(readfd, &unixs);
- }
- }
- }
-
- if (sock >= 0 && FD_ISSET(sock, &readset)) {
- s = sizeof(sockaddr);
- readfd = accept(sock, (struct sockaddr *) &sockaddr, &s);
- if (readfd < 0) {
- if (out >= 0) write(out, "error in accept\n", 16);
- write(log, "error in accept\n", 16);
- close(sock);
- sock = -1;
- } 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
-
- int setupTerminal(int fd) {
- struct winsize winsize;
-
- if (ioctl(fd, TIOCGWINSZ, &winsize)) {
- printf("failed to get winsize");
- fatal_error(1);
- }
-
- winsize.ws_row = 24;
- winsize.ws_col = 80;
-
- if (ioctl(fd, TIOCSWINSZ, &winsize)) {
- printf("failed to set winsize");
- fatal_error(1);
- }
-
- environ[ENV_TERM] = "TERM=vt100";
-
- return 0;
- }
-
- void unmountFilesystems(void) {
- int fd, size;
- char buf[65535]; /* this should be big enough */
- char * chptr, * start;
- struct {
- char * name;
- int len;
- } filesystems[500], tmp;
- int numFilesystems = 0;
- int i, j;
-
- fd = open("/proc/mounts", O_RDONLY, 0);
- if (fd < 1) {
- /* FIXME: was perror */
- printstr("failed to open /proc/mounts");
- sleep(2);
- return;
- }
-
- size = read(fd, buf, sizeof(buf) - 1);
- buf[size] = '\0';
-
- close(fd);
-
- chptr = buf;
- while (*chptr) {
- while (*chptr != ' ') chptr++;
- chptr++;
- start = chptr;
- while (*chptr != ' ') chptr++;
- *chptr++ = '\0';
- filesystems[numFilesystems].name = start;
- filesystems[numFilesystems].len = strlen(start);
- numFilesystems++;
- while (*chptr != '\n') chptr++;
- chptr++;
- }
-
- /* look ma, a *bubble* sort */
- for (i = 0; i < (numFilesystems - 1); i++) {
- for (j = i; j < numFilesystems; j++) {
- if (filesystems[i].len < filesystems[j].len) {
- tmp = filesystems[i];
- filesystems[i] = filesystems[j];
- filesystems[j] = tmp;
- }
- }
- }
-
- /* -1 because the last one will always be '/' */
- for (i = 0; i < numFilesystems - 1; i++) {
- printf("\t%s", filesystems[i].name);
- if (!testing) {
- if (umount(filesystems[i].name) < 0) {
- /* FIXME printf(" failed: %s", strerror(errno));*/
- printstr(" umount failed");
- }
- }
- printf("\n");
- }
- }
-
- void readargs(int * isRescue, int * isSerial, int * isExpert, int * isKick,
- int * forceSupp) {
- char buf[512];
- char * arg;
- int fd;
- int size;
- int done = 0;
- char * start, * end;
-
- printf("opening /proc/cmdline... ");
-
- if ((fd = open("/proc/cmdline", O_RDONLY, 0)) < 0) fatal_error(1);
-
- size = read(fd, buf, sizeof(buf) - 1);
- buf[size] = '\0';
- close(fd);
-
- printf("done\n");
-
- printf("checking command line arguments... ");
- start = buf;
-
- while (!done) {
- while (*start && isspace(*start)) start++;
- if (!(*start)) break;
-
- end = start;
- while (*end && !isspace(*end) && *end != '\n') end++;
-
- if (!*end) done = 1;
- *end = '\0';
-
- if (!*start ||
- !strcmp(start, "auto") ||
- !strncmp(start, "BOOT_IMAGE", 10) ||
- !strncmp(start, "initrd=", 7) ||
- !strncmp(start, "bootdevice=", 11) ||
- !strncmp(start, "bootfile=", 9) ||
- !strcmp(start, "ro") ||
- !strncmp(start, "root=", 5) ||
- !strncmp(start, "mem=", 4) ||
- !strncmp(start, "hda=", 4) ||
- !strncmp(start, "hdb=", 4) ||
- !strncmp(start, "hdc=", 4) ||
- !strncmp(start, "hdd=", 4) ||
- !strncmp(start, "load_ramdisk", 12) ||
- !strncmp(start, "prompt_ramdisk", 14)) {
- /* lilo does this for us -- we don't care */
- } else if (!strcmp(start, "debug")) {
- printf("\n\tdebug disk mode enabled");
- environ[ENV_DEBUG] = "DEBUG=1";
- } else if (!strcmp(start, "rescue")) {
- printf("\n\trescue disk mode enabled");
- *isRescue = 1;
- } else if (!strcmp(start, "serial")) {
- printf("\n\tserial mode enabled");
- *isSerial = 1;
- } else if (!strcmp(start, "expert")) {
- printf("\n\texpert mode enabled");
- *isExpert = 1;
- } else if (!strcmp(start, "supp")) {
- *forceSupp = 1;
- } else if (!strncmp(start, "kickstart", 9) ||
- !strncmp(start, "ks", 2)) {
- arg = strchr(start, '=');
-
- if (arg) {
- *isKick = KICK_FLOPPY;
- printf("\n\tan floppy kickstart install will be performed");
- } else {
- *isKick = KICK_BOOTP;
- printf("\n\tan bootp kickstart install will be performed");
- }
- } else {
- printf("\n\tunknown option '%s'!", start);
- sleep(5);
- }
-
- start = end + 1;
- }
- printf("done\n");
- }
-
- void main(void) {
- pid_t installpid, childpid;
- int waitStatus;
- int fd;
- int nfsRoot = 0;
- int roRoot = 0;
- int cdRoot = 0;
- int isRescue = 0;
- int isSerial = 0;
- int isExpert = 0;
- int isKick = 0;
- int doReboot = 0;
- int doShutdown =0;
- int forceSupp = 0;
- #ifdef __alpha__
- char * kernel;
- #endif
- char * argv[15];
- char ** argvp = argv;
-
- /* getpid() != 1 should work, by linuxrc tends to get a larger pid */
- testing = (getpid() > 50);
-
- if (!testing) {
- /* turn off screen blanking */
- printstr("\033[9;0]");
- printstr("\033[8]");
- }
-
- printstr("hello\n");
-
- printf("Red Hat install init version %s starting\n", VERSION);
-
- printf("mounting /proc filesystem... ");
-
- if (!testing) {
- if (mount("/proc", "/proc", "proc", 0, NULL))
- fatal_error(1);
- }
-
- printf("done\n");
-
- readargs(&isRescue, &isSerial, &isExpert, &isKick, &forceSupp);
-
- if (isSerial) {
- fd = open("/dev/cua0", O_RDWR, 0);
- if (fd < 0) {
- printf("failed to open /dev/cua0");
- fatal_error(1);
- }
- write(fd, "Switching to serial console...", 29);
-
- /* gulp */
- dup2(fd, 0);
- dup2(fd, 1);
- dup2(fd, 2);
-
- printf("done\n\n");
-
- printf("Red Hat install init version %s using a serial console\n",
- VERSION);
-
- printf("remember, cereal is an important part of a nutritionally "
- "balanced breakfast.\n\n");
-
- setupTerminal(0);
-
- close(fd);
- }
-
- if (!testing)
- sethostname("localhost.localdomain", 21);
- /* the default domainname (as of 2.0.35) is "(none)", which confuses
- glibc */
- setdomainname("", 0);
-
- printf("checking for NFS root filesystem...");
- 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 (!testing && roRoot) {
- printf("creating 100k of ramdisk space... ");
- if (doMke2fs("/dev/ram", "100"))
- fatal_error(0);
-
- printf("done\n");
-
- printf("mounting /tmp from ramdisk... ");
- 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. */
-
- if (!testing)
- doklog("/dev/tty4");
-
- /* 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())) {
- /* child */
- if (nfsRoot || cdRoot) {
- symlink("/", "/tmp/rhimage");
- symlink("/", "/tmp/image");
-
- *argvp++ = "/usr/bin/runinstall2";
- *argvp++ = argv[0];
- *argvp++ = "--method";
- *argvp++ = nfsRoot ? "nfs" : "cdrom";
-
- # if defined(__alpha__)
- if (cdRoot && (kernel = findKernel())) {
- *argvp++ = "--kernel";
- *argvp++ = kernel;
- }
- # endif
- } else {
- *argvp++ = "/bin/install";
- }
-
- if (isRescue)
- *argvp++ = "--rescue";
-
- if (isExpert) *argvp++ = "--expert";
- if (forceSupp) *argvp++ = "--forcesupp";
- if (isKick == KICK_FLOPPY)
- *argvp++ = "--ks=floppy";
- else if (isKick)
- *argvp++ = "--ks=bootp";
-
- *argvp++ = NULL;
-
- execve(argv[0], argv, environ);
-
- exit(0);
- }
-
- while (!doShutdown) {
- childpid = wait4(-1, &waitStatus, 0, NULL);
-
- if (childpid == installpid)
- doShutdown = 1;
- }
-
- if (!WIFEXITED(waitStatus) || WEXITSTATUS(waitStatus)) {
- printf("install exited abnormally ");
- if (WIFSIGNALED(waitStatus)) {
- printf("-- recieved signal %d", WTERMSIG(waitStatus));
- }
- printf("\n");
- } else {
- doReboot = 1;
- }
-
- if (testing)
- exit(0);
-
- sync(); sync();
-
- if (!testing) {
- printf("sending termination signals...");
- kill(-1, 15);
- sleep(2);
- printf("done\n");
-
- printf("sending kill signals...");
- kill(-1, 9);
- sleep(2);
- printf("done\n");
- }
-
- printf("unmounting filesystems...\n");
- unmountFilesystems();
-
- if (doReboot) {
- printf("rebooting system\n");
- sleep(2);
-
- #if USE_MINILIBC
- reboot(0xfee1dead, 672274793, 0x1234567);
- #else
- reboot(RB_AUTOBOOT);
- #endif
- } else {
- printf("you may safely reboot your system\n");
- while (1);
- }
-
- exit(0);
-
- return;
- }
-