home *** CD-ROM | disk | FTP | other *** search
/ PC Plus SuperCD (UK) 1999 May / pcp151c.iso / misc / src / installinit / init.c next >
Encoding:
C/C++ Source or Header  |  1998-10-12  |  15.0 KB  |  724 lines

  1. /*
  2.  * init.c
  3.  * 
  4.  * This is the install type init 
  5.  *
  6.  * Erik Troan (ewt@redhat.com)
  7.  *
  8.  * Copyright 1996 Red Hat Software 
  9.  *
  10.  * This software may be freely redistributed under the terms of the GNU
  11.  * public license.
  12.  *
  13.  * You should have received a copy of the GNU General Public License
  14.  * along with this program; if not, write to the Free Software
  15.  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  16.  *
  17.  */
  18.  
  19. #if USE_MINILIBC
  20. #include "minilibc.h"
  21. #else
  22. #include <ctype.h>
  23. #include <errno.h>
  24. #include <fcntl.h>
  25. #include <net/if.h>
  26. #include <signal.h>
  27. #include <stdio.h>
  28. #include <stdlib.h>
  29. #include <string.h>
  30. #include <sys/ioctl.h>
  31. #include <sys/klog.h>
  32. #include <sys/mount.h>
  33. #include <sys/socket.h>
  34. #include <sys/stat.h>
  35. #include <sys/time.h>
  36. #include <sys/types.h>
  37. #include <sys/un.h>
  38. #include <sys/wait.h>
  39. #include <unistd.h>
  40. #include <sys/ioctl.h>
  41. #include <sys/reboot.h>
  42. #include <termios.h>
  43.  
  44.  
  45. #define syslog klogctl
  46. #endif
  47.  
  48. #define KICK_FLOPPY     1
  49. #define KICK_BOOTP    2
  50.  
  51. #define MS_REMOUNT      32
  52.  
  53. #define ENV_PATH         0
  54. #define ENV_LD_LIBRARY_PATH     1
  55. #define ENV_HOME        2
  56. #define ENV_TERM        3
  57. #define ENV_DEBUG        4
  58.  
  59. char * environ[] = {
  60.     "PATH=/usr/bin:/bin:/sbin:/usr/sbin:/mnt/sbin:/mnt/usr/sbin:"
  61.            "/mnt/bin:/mnt/usr/bin",
  62.     "LD_LIBRARY_PATH=/lib:/usr/lib:/mnt/lib:/mnt/usr/lib",
  63.     "HOME=/",
  64.     "TERM=linux",
  65.     "DEBUG=",
  66.     NULL
  67. };
  68.  
  69.  
  70. /* 
  71.  * this needs to handle the following cases:
  72.  *
  73.  *    1) run from a CD root filesystem
  74.  *    2) run from a read only nfs rooted filesystem
  75.  *      3) run from a floppy
  76.  *    4) run from a floppy that's been loaded into a ramdisk 
  77.  *
  78.  */
  79.  
  80. int testing;
  81.  
  82. void printstr(char * string) {
  83.     write(1, string, strlen(string));
  84. }
  85.  
  86. void fatal_error(int usePerror) {
  87. /* FIXME */
  88. #if 0
  89.     if (usePerror) 
  90.     perror("failed:");
  91.     else
  92. #endif
  93.     printf("failed.\n");
  94.  
  95.     printf("\nI can't recover from this.\n");
  96.     while (1) ;
  97. }
  98.  
  99. int doMke2fs(char * device, char * size) {
  100.     char * args[] = { "/usr/bin/mke2fs", NULL, NULL, NULL };
  101.     int pid, status;
  102.  
  103.     args[1] = device;
  104.     args[2] = size;
  105.  
  106.     if (!(pid = fork())) {
  107.     /* child */
  108.     execve("/usr/bin/mke2fs", args, environ);
  109.     fatal_error(1);
  110.     }
  111.  
  112.     wait4(-1, &status, 0, NULL);
  113.     
  114.     return 0;
  115. }
  116.  
  117. int hasNetConfiged(void) {
  118.     int rc;
  119.     int s;
  120.     struct ifconf configs;
  121.     struct ifreq devs[10];
  122.  
  123.     #ifdef __i386__
  124.     return 0;
  125.     #endif
  126.  
  127.     s = socket(AF_INET, SOCK_STREAM, 0);
  128.     if (s < 0) {
  129.     /* FIXME was perror*/
  130.     printf("error creating socket: %d\n", errno);
  131.     return 0;
  132.     } else {
  133.     /* this is just good enough to tell us if we have anything 
  134.        configured */
  135.     configs.ifc_len = sizeof(devs);
  136.     configs.ifc_buf = (void *) devs;
  137.  
  138.     rc = ioctl(s, SIOCGIFCONF, &configs);
  139.     if (rc < 0) {
  140.         /* FIXME was perror*/
  141.         printstr("SIOCGIFCONF");
  142.         return 0;
  143.     }
  144.     if (configs.ifc_len == 0) {
  145.         return 0;
  146.     }
  147.  
  148.     return 1;
  149.     }
  150.  
  151.     return 0;
  152. }
  153.  
  154. void doklog(char * fn) {
  155.     fd_set readset, unixs;
  156.     int in, out, i;
  157.     int log;
  158.     int s;
  159.     int sock = -1;
  160.     struct sockaddr_un sockaddr;
  161.     char buf[1024];
  162.     int readfd;
  163.  
  164.     in = open("/proc/kmsg", O_RDONLY,0);
  165.     if (in < 0) {
  166.     /* FIXME: was perror */
  167.     printstr("open /proc/kmsg");
  168.     return;
  169.     }
  170.  
  171.     out = open(fn, O_WRONLY, 0);
  172.     if (out < 0) 
  173.     printf("couldn't open %s for syslog -- still using /tmp/syslog\n", fn);
  174.  
  175.     log = open("/tmp/syslog", O_WRONLY | O_CREAT, 0644);
  176.     if (log < 0) {
  177.     /* FIXME: was perror */
  178.     printstr("error opening /tmp/syslog");
  179.     sleep(5);
  180.     
  181.     close(in);
  182.     return;
  183.     }
  184.  
  185.     /* if we get this far, we should be in good shape */
  186.  
  187.     if (fork()) {
  188.     /* parent */
  189.     close(in);
  190.     close(out);
  191.     close(log);
  192.     return;
  193.     }
  194.     close(0); 
  195.     close(1);
  196.     close(2);
  197.  
  198.     dup2(1, log);
  199.  
  200. #if defined(USE_LOGDEV)
  201.     /* now open the syslog socket */
  202.     sockaddr.sun_family = AF_UNIX;
  203.     strcpy(sockaddr.sun_path, "/dev/log");
  204.     sock = socket(AF_UNIX, SOCK_STREAM, 0);
  205.     if (sock < 0) {
  206.     printf("error creating socket: %d\n", errno);
  207.     sleep(5);
  208.     }
  209.     printstr("got socket\n");
  210.     if (bind(sock, (struct sockaddr *) &sockaddr, sizeof(sockaddr.sun_family) + 
  211.             strlen(sockaddr.sun_path))) {
  212.     printf("bind error: %d\n", errno);
  213.     sleep(5);
  214.     }
  215.     printstr("bound socket\n");
  216.     chmod("/dev/log", 0666);
  217.     if (listen(sock, 5)) {
  218.     printf("listen error: %d\n", errno);
  219.     sleep(5);
  220.     }
  221. #endif
  222.  
  223.     syslog(8, NULL, 1);
  224.  
  225.     FD_ZERO(&unixs);
  226.     while (1) {
  227.     memcpy(&readset, &unixs, sizeof(unixs));
  228.  
  229.     if (sock >= 0) FD_SET(sock, &readset);
  230.     FD_SET(in, &readset);
  231.  
  232.     i = select(20, &readset, NULL, NULL, NULL);
  233.     if (i <= 0) continue;
  234.  
  235.     if (FD_ISSET(in, &readset)) {
  236.         i = read(in, buf, sizeof(buf));
  237.         if (i > 0) {
  238.         if (out >= 0) write(out, buf, i);
  239.         write(log, buf, i);
  240.         }
  241.     } 
  242.  
  243.     for (readfd = 0; readfd < 20; ++readfd) {
  244.         if (FD_ISSET(readfd, &readset) && FD_ISSET(readfd, &unixs)) {
  245.         i = read(readfd, buf, sizeof(buf));
  246.         if (i > 0) {
  247.             if (out >= 0) {
  248.             write(out, buf, i);
  249.             write(out, "\n", 1);
  250.             }
  251.  
  252.             write(log, buf, i);
  253.             write(log, "\n", 1);
  254.         } else if (i == 0) {
  255.             /* socket closed */
  256.             close(readfd);
  257.             FD_CLR(readfd, &unixs);
  258.         }
  259.         }
  260.     }
  261.  
  262.     if (sock >= 0 && FD_ISSET(sock, &readset)) {
  263.         s = sizeof(sockaddr);
  264.         readfd = accept(sock, (struct sockaddr *) &sockaddr, &s);
  265.         if (readfd < 0) {
  266.         if (out >= 0) write(out, "error in accept\n", 16);
  267.         write(log, "error in accept\n", 16);
  268.         close(sock);
  269.         sock = -1;
  270.         } else {
  271.         FD_SET(readfd, &unixs);
  272.         }
  273.     }
  274.     }    
  275. }
  276.  
  277. #if defined(__alpha__)
  278. char * findKernel(void) {
  279.     char * dev, * file;
  280.     struct stat sb;
  281.  
  282.     dev = getenv("bootdevice");
  283.     file = getenv("bootfile");
  284.  
  285.     if (!dev || !file) {
  286.     printf("I can't find your kernel. When you are booting"
  287.         " from a CDROM, you must pass\n");
  288.     printf("the bootfile argument to the kernel if your"
  289.         " boot loader doesn't do so automatically.\n");
  290.     printf("\n");
  291.     printf("You should now reboot your system and try "    
  292.         "again\n");
  293.  
  294.     while (1) ;
  295.     }
  296.  
  297.     if (!strcmp(dev, "fd0")) {
  298.     if (!strcmp(file, "vmlinux.gz")) {
  299.         printf("The kernel on a boot floppy must be named vmlinux.gz. "
  300.                "You\n");
  301.         printf("are using a kernel named %s instead. You'll have "
  302.            "to\n", file);
  303.         printf("fix this and try again.\n");
  304.  
  305.         while (1) ;
  306.     }
  307.  
  308.     return NULL;
  309.     } else {
  310.     if (stat(file, &sb)) {
  311.         printf("I can't find your kernel. When you are booting"
  312.             " from a CDROM, you must pass\n");
  313.         printf("the bootfile argument to the kernel if your"
  314.             " boot loader doesn't do so automatically.\n");
  315.         printf("\n");
  316.         printf("You should now reboot your system and try "    
  317.             "again\n");
  318.  
  319.         while (1) ;
  320.     }
  321.  
  322.     return file;
  323.     }
  324. }
  325. #endif 
  326.  
  327. int setupTerminal(int fd) {
  328.     struct winsize winsize;
  329.  
  330.     if (ioctl(fd, TIOCGWINSZ, &winsize)) {
  331.     printf("failed to get winsize");
  332.     fatal_error(1);
  333.     }
  334.  
  335.     winsize.ws_row = 24;
  336.     winsize.ws_col = 80;
  337.  
  338.     if (ioctl(fd, TIOCSWINSZ, &winsize)) {
  339.     printf("failed to set winsize");
  340.     fatal_error(1);
  341.     }
  342.  
  343.     environ[ENV_TERM] = "TERM=vt100";
  344.  
  345.     return 0;
  346. }
  347.  
  348. void unmountFilesystems(void) {
  349.     int fd, size;
  350.     char buf[65535];            /* this should be big enough */
  351.     char * chptr, * start;
  352.     struct {
  353.     char * name;
  354.     int len;
  355.     } filesystems[500], tmp;
  356.     int numFilesystems = 0;
  357.     int i, j;
  358.  
  359.     fd = open("/proc/mounts", O_RDONLY, 0);
  360.     if (fd < 1) {
  361.     /* FIXME: was perror */
  362.     printstr("failed to open /proc/mounts");
  363.     sleep(2);
  364.     return;
  365.     }
  366.  
  367.     size = read(fd, buf, sizeof(buf) - 1);
  368.     buf[size] = '\0';
  369.  
  370.     close(fd);
  371.  
  372.     chptr = buf;
  373.     while (*chptr) {
  374.     while (*chptr != ' ') chptr++;
  375.     chptr++;
  376.     start = chptr;
  377.     while (*chptr != ' ') chptr++;
  378.     *chptr++ = '\0';
  379.     filesystems[numFilesystems].name = start;
  380.     filesystems[numFilesystems].len = strlen(start);
  381.     numFilesystems++;
  382.     while (*chptr != '\n') chptr++;
  383.     chptr++;
  384.     }
  385.  
  386.     /* look ma, a *bubble* sort */
  387.     for (i = 0; i < (numFilesystems - 1); i++) {
  388.     for (j = i; j < numFilesystems; j++) {
  389.         if (filesystems[i].len < filesystems[j].len) {
  390.         tmp = filesystems[i];
  391.         filesystems[i] = filesystems[j];
  392.         filesystems[j] = tmp;
  393.         }
  394.     }
  395.     }
  396.  
  397.     /* -1 because the last one will always be '/' */
  398.     for (i = 0; i < numFilesystems - 1; i++) {
  399.     printf("\t%s", filesystems[i].name);
  400.     if (!testing) {
  401.         if (umount(filesystems[i].name) < 0) {
  402.         /* FIXME printf(" failed: %s", strerror(errno));*/
  403.         printstr(" umount failed");
  404.         }
  405.     }
  406.     printf("\n");
  407.     }
  408. }
  409.  
  410. void readargs(int * isRescue, int * isSerial, int * isExpert, int * isKick,
  411.           int * forceSupp) {
  412.     char buf[512];
  413.     char * arg;
  414.     int fd;
  415.     int size;
  416.     int done = 0;
  417.     char * start, * end;
  418.  
  419.     printf("opening /proc/cmdline... ");
  420.  
  421.     if ((fd = open("/proc/cmdline", O_RDONLY, 0)) < 0) fatal_error(1);
  422.  
  423.     size = read(fd, buf, sizeof(buf) - 1);
  424.     buf[size] = '\0';
  425.     close(fd);
  426.  
  427.     printf("done\n");
  428.  
  429.     printf("checking command line arguments... ");
  430.     start = buf;
  431.  
  432.     while (!done) {
  433.     while (*start && isspace(*start)) start++;
  434.     if (!(*start)) break;
  435.     
  436.     end = start;
  437.     while (*end && !isspace(*end) && *end != '\n') end++;
  438.  
  439.     if (!*end) done = 1;
  440.     *end = '\0';
  441.  
  442.     if (!*start ||
  443.         !strcmp(start, "auto") ||
  444.         !strncmp(start, "BOOT_IMAGE", 10) ||
  445.         !strncmp(start, "initrd=", 7) ||
  446.         !strncmp(start, "bootdevice=", 11) ||
  447.         !strncmp(start, "bootfile=", 9) ||
  448.         !strcmp(start, "ro") ||
  449.         !strncmp(start, "root=", 5) ||
  450.         !strncmp(start, "mem=", 4) ||
  451.         !strncmp(start, "hda=", 4) ||
  452.         !strncmp(start, "hdb=", 4) ||
  453.         !strncmp(start, "hdc=", 4) ||
  454.         !strncmp(start, "hdd=", 4) ||
  455.         !strncmp(start, "load_ramdisk", 12) ||
  456.         !strncmp(start, "prompt_ramdisk", 14)) {
  457.         /* lilo does this for us -- we don't care */
  458.     } else if (!strcmp(start, "debug")) {
  459.         printf("\n\tdebug disk mode enabled");
  460.         environ[ENV_DEBUG] = "DEBUG=1";
  461.     } else if (!strcmp(start, "rescue")) {
  462.         printf("\n\trescue disk mode enabled");
  463.         *isRescue = 1;
  464.     } else if (!strcmp(start, "serial")) {
  465.         printf("\n\tserial mode enabled");
  466.         *isSerial = 1;
  467.     } else if (!strcmp(start, "expert")) {
  468.         printf("\n\texpert mode enabled");
  469.         *isExpert = 1;
  470.     } else if (!strcmp(start, "supp")) {
  471.         *forceSupp = 1;
  472.     } else if (!strncmp(start, "kickstart", 9) || 
  473.                    !strncmp(start, "ks", 2)) {
  474.         arg = strchr(start, '=');
  475.  
  476.         if (arg) {
  477.         *isKick = KICK_FLOPPY;
  478.         printf("\n\tan floppy kickstart install will be performed");
  479.         } else {
  480.         *isKick = KICK_BOOTP;
  481.         printf("\n\tan bootp kickstart install will be performed");
  482.         }
  483.     } else {
  484.         printf("\n\tunknown option '%s'!", start);
  485.         sleep(5);
  486.     }
  487.  
  488.     start = end + 1;
  489.     }
  490.     printf("done\n");
  491. }
  492.  
  493. void main(void) {
  494.     pid_t installpid, childpid;
  495.     int waitStatus;
  496.     int fd;
  497.     int nfsRoot = 0;
  498.     int roRoot = 0;
  499.     int cdRoot = 0;
  500.     int isRescue = 0;
  501.     int isSerial = 0;
  502.     int isExpert = 0;
  503.     int isKick = 0;
  504.     int doReboot = 0;
  505.     int doShutdown =0;
  506.     int forceSupp = 0;
  507.     #ifdef __alpha__
  508.     char * kernel;
  509.     #endif
  510.     char * argv[15];
  511.     char ** argvp = argv;
  512.  
  513.     /* getpid() != 1 should work, by linuxrc tends to get a larger pid */
  514.     testing = (getpid() > 50);
  515.  
  516.     if (!testing) {
  517.     /* turn off screen blanking */
  518.     printstr("\033[9;0]");
  519.     printstr("\033[8]");
  520.     }
  521.  
  522.     printstr("hello\n");
  523.  
  524.     printf("Red Hat install init version %s starting\n", VERSION);
  525.  
  526.     printf("mounting /proc filesystem... "); 
  527.  
  528.     if (!testing) {
  529.     if (mount("/proc", "/proc", "proc", 0, NULL))
  530.         fatal_error(1);
  531.     }
  532.  
  533.     printf("done\n");
  534.  
  535.     readargs(&isRescue, &isSerial, &isExpert, &isKick, &forceSupp);
  536.  
  537.     if (isSerial) {
  538.     fd = open("/dev/cua0", O_RDWR, 0);
  539.     if (fd < 0) {
  540.         printf("failed to open /dev/cua0");
  541.         fatal_error(1);
  542.     }
  543.     write(fd, "Switching to serial console...", 29);
  544.  
  545.     /* gulp */
  546.     dup2(fd, 0);
  547.     dup2(fd, 1);
  548.     dup2(fd, 2);
  549.  
  550.     printf("done\n\n");
  551.  
  552.     printf("Red Hat install init version %s using a serial console\n", 
  553.         VERSION);
  554.  
  555.     printf("remember, cereal is an important part of a nutritionally "
  556.            "balanced breakfast.\n\n");
  557.  
  558.     setupTerminal(0);
  559.  
  560.     close(fd);
  561.     }
  562.  
  563.     if (!testing)
  564.     sethostname("localhost.localdomain", 21);
  565.     /* the default domainname (as of 2.0.35) is "(none)", which confuses 
  566.        glibc */
  567.     setdomainname("", 0);
  568.  
  569.     printf("checking for NFS root filesystem...");
  570.     if (hasNetConfiged()) {
  571.     printf("yes\n");
  572.     roRoot = nfsRoot = 1;
  573.     } else {
  574.     printf("no\n");
  575.     }
  576.  
  577.     if (!nfsRoot) {
  578.     printf("trying to remount root filesystem read write... ");
  579.     if (mount("/", "/", NULL, MS_REMOUNT | MS_MGC_VAL, NULL)) {
  580.         printf("failed (but that's okay)\n");
  581.     
  582.         roRoot = 1;
  583.     } else {
  584.         printf("done\n");
  585.  
  586.         /* 2.0.18 (at least) lets us remount a CD r/w!! */
  587.         printf("checking for writeable /tmp... ");
  588.         fd = open("/tmp/tmp", O_WRONLY | O_CREAT, 0644);
  589.         if (fd < 0) {
  590.         printf("no (probably a CD rooted install)\n");
  591.         roRoot = 1;
  592.         } else {
  593.         close(fd);
  594.         unlink("/tmp/tmp");
  595.         printf("yes\n");
  596.         }
  597.     }
  598.     }
  599.  
  600.     if (!testing && roRoot) {
  601.     printf("creating 100k of ramdisk space... ");
  602.     if (doMke2fs("/dev/ram", "100"))
  603.         fatal_error(0);
  604.  
  605.     printf("done\n");
  606.     
  607.     printf("mounting /tmp from ramdisk... ");
  608.     if (mount("/dev/ram", "/tmp", "ext2", 0, NULL))
  609.         fatal_error(1);
  610.  
  611.     printf("done\n");
  612.  
  613.     if (!nfsRoot) cdRoot = 1;
  614.     }
  615.  
  616.     /* Now we have some /tmp space set up, and /etc and /dev point to
  617.        it. We should be in pretty good shape. */
  618.  
  619.     if (!testing) 
  620.     doklog("/dev/tty4");
  621.  
  622.     /* Go into normal init mode - keep going, and then do a orderly shutdown
  623.        when:
  624.  
  625.     1) /bin/install exits
  626.     2) we receive a SIGHUP 
  627.     */
  628.  
  629.     printf("running install...\n"); 
  630.  
  631.     if (!(installpid = fork())) {
  632.     /* child */
  633.     if (nfsRoot || cdRoot) {
  634.         symlink("/", "/tmp/rhimage");
  635.         symlink("/", "/tmp/image");
  636.  
  637.         *argvp++ = "/usr/bin/runinstall2";
  638.         *argvp++ = argv[0];
  639.         *argvp++ = "--method";
  640.         *argvp++ = nfsRoot ? "nfs" : "cdrom";
  641.  
  642. #        if defined(__alpha__)
  643.         if (cdRoot && (kernel = findKernel())) {
  644.             *argvp++ = "--kernel";
  645.             *argvp++ = kernel;
  646.         } 
  647. #        endif
  648.     } else {
  649.         *argvp++ = "/bin/install";
  650.     }
  651.  
  652.     if (isRescue) 
  653.         *argvp++ = "--rescue";
  654.  
  655.     if (isExpert) *argvp++ = "--expert";
  656.     if (forceSupp) *argvp++ = "--forcesupp";
  657.     if (isKick == KICK_FLOPPY) 
  658.         *argvp++ = "--ks=floppy";
  659.     else if (isKick)
  660.         *argvp++ = "--ks=bootp";
  661.  
  662.     *argvp++ = NULL;
  663.  
  664.     execve(argv[0], argv, environ);
  665.  
  666.     exit(0);
  667.     }
  668.  
  669.     while (!doShutdown) {
  670.     childpid = wait4(-1, &waitStatus, 0, NULL);
  671.  
  672.     if (childpid == installpid) 
  673.         doShutdown = 1;
  674.     }
  675.  
  676.     if (!WIFEXITED(waitStatus) || WEXITSTATUS(waitStatus)) {
  677.     printf("install exited abnormally ");
  678.     if (WIFSIGNALED(waitStatus)) {
  679.         printf("-- recieved signal %d", WTERMSIG(waitStatus));
  680.     }
  681.     printf("\n");
  682.     } else {
  683.     doReboot = 1;
  684.     }
  685.  
  686.     if (testing)
  687.         exit(0);
  688.  
  689.     sync(); sync();
  690.  
  691.     if (!testing) {
  692.     printf("sending termination signals...");
  693.     kill(-1, 15);
  694.     sleep(2);
  695.     printf("done\n");
  696.  
  697.     printf("sending kill signals...");
  698.     kill(-1, 9);
  699.     sleep(2);
  700.     printf("done\n");
  701.     }
  702.  
  703.     printf("unmounting filesystems...\n"); 
  704.     unmountFilesystems();
  705.  
  706.     if (doReboot) {
  707.     printf("rebooting system\n");
  708.     sleep(2);
  709.  
  710.     #if USE_MINILIBC
  711.         reboot(0xfee1dead, 672274793, 0x1234567);
  712.     #else
  713.         reboot(RB_AUTOBOOT);
  714.     #endif
  715.     } else {
  716.     printf("you may safely reboot your system\n");
  717.     while (1);
  718.     }
  719.  
  720.     exit(0);
  721.  
  722.     return;
  723. }
  724.