home *** CD-ROM | disk | FTP | other *** search
/ PC Plus SuperCD (UK) 1999 May / pcp151c.iso / misc / src / install / install.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-10-13  |  13.0 KB  |  542 lines

  1. /*
  2.  * install.c
  3.  * 
  4.  * This is the first half of the install. It does just enough to get the
  5.  * second half going. It, and everything it needs, has to fit on one floppy
  6.  * along with a kernel and modules. Needless to say, it's a bit tight.
  7.  *
  8.  * Erik Troan (ewt@redhat.com)
  9.  *
  10.  * Copyright 1998 Red Hat Software 
  11.  *
  12.  * This software may be freely redistributed under the terms of the GNU
  13.  * public license.
  14.  *
  15.  * You should have received a copy of the GNU General Public License
  16.  * along with this program; if not, write to the Free Software
  17.  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  18.  *
  19.  */
  20.  
  21. #include <alloca.h>
  22. #include <dirent.h>
  23. #include <errno.h>
  24. #include <fcntl.h>
  25. #include <netinet/in.h>        /* for ntohl */
  26. #include <popt.h>
  27. #include <stdarg.h>
  28. #include <stdio.h>
  29. #include <stdlib.h>
  30. #include <string.h>
  31. #include <sys/mount.h>
  32. #include <sys/stat.h>
  33. #include <sys/sysmacros.h>
  34. #include <sys/wait.h>
  35. #include <unistd.h>
  36. #include <zlib.h>
  37.  
  38. #include "devices.h"
  39. #include "fs.h"
  40. #include "install.h"
  41. #include "otherinsmod.h"
  42. #include "intl.h"
  43. #include "kbd.h"
  44. #include "kickstart.h"
  45. #include "lang.h"
  46. #include "log.h"
  47. #include "methods.h"
  48. #include "net.h"
  49. #include "newt.h"
  50. #include "run.h"
  51. #include "windows.h"
  52. #include "pcmcia-probing/pcmcia-probe.h"
  53.  
  54. #define KS_NONE        0
  55. #define KS_FLOPPY    1
  56. #define KS_BOOTP    2
  57. #define KS_FILE        3
  58.  
  59. int testing = 0;
  60. int expert = 0;
  61. int kickstart = 0;
  62. int debug = 1;
  63. char * ksFile;
  64.  
  65. /* hack */
  66. int rmmod_main(int argc, char ** argv);
  67.  
  68. /* librpm.a provides this */
  69. int cpioInstallArchive(gzFile stream, void * mappings,
  70.                int numMappings, void * cb, void * cbData,
  71.                char ** failedFile);
  72.  
  73. void welcome(void) {
  74.     if (!testing && !kickstart) {
  75.     newtWinMessage("Red Hat Linux", _("Ok"), 
  76.         _("Welcome to Red Hat Linux!\n\n"
  77.           "This installation process is outlined in detail in the "
  78.           "Official Red Hat Linux Installation Guide available from "
  79.           "Red Hat Software. If you have access to this manual, you "
  80.           "should read the installation section before continuing.\n\n"
  81.           "If you have purchased Official Red Hat Linux, be sure to "
  82.           "register your purchase through our web site, "
  83.           "http://www.redhat.com."));
  84.     }
  85. }
  86.  
  87. void mountFloppy() {
  88.     if (!testing) {
  89.     logMessage("mounting ext2 fs on floppy");
  90.     doMount("fd0", "/tmp/bootdisk", "ext2", 1, 0);
  91.     logMessage("floppy filesystem mounted on /tmp/bootdisk");
  92.     }
  93. }
  94.  
  95. int expandPcmciaArchive() {
  96.     gzFile stream;
  97.     char * failedFile;
  98.     int rc;
  99.  
  100.     stream = gzopen("/tmp/image/pcmcia.cgz", "r");
  101.  
  102.     if (!stream) {
  103.     logMessage("gzopen failed to read pcmcia.cgz: %s", strerror(errno));
  104.     return INST_ERROR;
  105.     }
  106.  
  107.     rc = cpioInstallArchive(stream, NULL, 0, NULL, NULL, &failedFile);
  108.     if (rc) {
  109.     logMessage("cpio expansion failed on file %s, error %d\n",
  110.            failedFile, rc);
  111.     gzclose(stream);
  112.     return INST_ERROR;
  113.     }
  114.  
  115.     gzclose(stream);
  116.  
  117.     return 0;
  118. }
  119.  
  120. #ifdef __i386__
  121. int setupPCMCIA(char ** arg, int direction) {
  122.     int rc;
  123.     struct driversLoaded * dl = NULL;
  124.     int status;
  125.     char * probeOutput;
  126.     static char pcic[20];
  127.  
  128.     /* just probe and if pcmcia controller exists we load support
  129.        automatically */
  130.     probeOutput = pcmciaProbeController();
  131.     if (probeOutput == NULL) {
  132.     if (direction < 0) return INST_CANCEL;
  133.     return INST_OKAY;
  134.     }
  135.  
  136.     logMessage("pcmcia probe returned: %s", probeOutput);
  137.  
  138.     if (strstr(probeOutput, "TCIC")) {
  139.     strcpy(pcic, "tcic");
  140.     } else
  141.     strcpy(pcic, "i82365");
  142.     logMessage("pcmcia pcic type: %s", pcic);
  143.  
  144.     /* go ahead and tell the rest of the install we found a
  145.        PCMCIA controller */
  146.     *arg = pcic;
  147.  
  148.     do {
  149.     rc = newtWinTernary(_("PCMCIA Support"), _("Yes"), _("No"), _("Back"),
  150.                 _("Do you need to use PCMCIA devices during the "
  151.                   "install? Answer no to this question if only "
  152.                   "need PCMCIA support after the install. You do "
  153.                   "not need install-time PCMCIA support if you "
  154.                   "are installing Red Hat Linux on a laptop with "
  155.                   "a build-in CDROM drive."));
  156.  
  157.     if (rc == 2) return INST_OKAY;
  158.     if (rc == 3) return INST_CANCEL;
  159.  
  160.     /* The parameters are just to make floppyRoot() fit as a prepareImage
  161.        method */
  162.     rc = floppyRoot(NULL, NULL, NULL, 0, NULL);
  163.     } while (rc);
  164.  
  165.     winStatus(35, 3, "PCMCIA", _("Loading PCMCIA support..."));
  166.  
  167.     expandPcmciaArchive();
  168.  
  169.     newtPopWindow();
  170.  
  171.     winStatus(40, 3, "PCMCIA", _("Starting PCMCIA services..."));
  172.  
  173.     loadModule("pcmcia_core", DRIVER_PCMCIA, DRIVER_MINOR_NONE, &dl);
  174.     loadModule(pcic, DRIVER_PCMCIA, DRIVER_MINOR_NONE, &dl);
  175.     loadModule("ds", DRIVER_PCMCIA, DRIVER_MINOR_NONE, &dl);
  176.  
  177.     if (!fork()) {
  178.     if (!fork()) {
  179.         execl("/sbin/cardmgr", "/sbin/cardmgr", NULL);
  180.         exit(-1);
  181.     }
  182.     exit(-1);
  183.     }
  184.  
  185.     wait(&status);
  186.  
  187.     /* if cardmgr a chance to get going */
  188.     sleep(5);
  189.  
  190.     newtPopWindow();
  191.  
  192.     return 0;
  193. }
  194. #endif
  195.  
  196. void doSuspend(void) {
  197.     pid_t pid;
  198.     int status;
  199.  
  200.     if (testing) {
  201.     newtFinished();
  202.     exit(1);
  203.     } else if (access("/bin/sh", X_OK)) {
  204.     return;
  205.     }
  206.  
  207.     newtSuspend();
  208.     if (!(pid = fork())) {
  209.     printf(_("\n\nType <exit> to return to the install program.\n\n"));
  210.     execl("/bin/sh", "-/bin/sh", NULL);
  211.     perror("error execing /bin/sh");
  212.     sleep(5);
  213.     exit(1);
  214.     }
  215.     waitpid(pid, &status, 0);
  216.     newtResume();
  217. }
  218.  
  219. void doKickstart(struct intfInfo * intf, struct netInfo * netc,
  220.          struct driversLoaded ** dl) {
  221.     char * file;
  222.     char * ksPath;
  223.     int rc;
  224.  
  225.     if (kickstart == KS_BOOTP) {
  226.     if ((bringUpNetworking(intf, netc, dl, 1))) {
  227.         kickstart = 0;
  228.     } else if (!(intf->set & INTFINFO_HAS_BOOTSERVER)) {
  229.         newtWinMessage(_("Kickstart Error"), _("Ok"), _("No kickstart "
  230.                "configuration file server can be found."));
  231.         kickstart = 0;
  232.     } else {
  233.         if (!(intf->set & INTFINFO_HAS_BOOTFILE)) {
  234.         file = "/kickstart/";
  235.         logMessage("bootp: no bootfile received");
  236.         } else {
  237.         file = intf->bootFile;
  238.         }
  239.  
  240.         ksPath = malloc(strlen(file) + strlen(netc->hostname) + 70);
  241.         strcpy(ksPath, inet_ntoa(intf->bootServer));
  242.         strcat(ksPath, ":");
  243.         strcat(ksPath, file);
  244.  
  245.         if (ksPath[strlen(ksPath) - 1] == '/') {
  246.         ksPath[strlen(ksPath) - 1] = '\0';
  247.         file = malloc(30);
  248.         sprintf(file, "%s-kickstart", inet_ntoa(intf->ip));
  249.         } else {
  250.         file = strrchr(ksPath, '/');
  251.         if (!file) {
  252.             file = ksPath;
  253.             ksPath = "/";
  254.         } else {
  255.             *file++ = '\0';
  256.         }
  257.         }
  258.  
  259.         logMessage("ks server: %s file: %s", ksPath, file);
  260.  
  261.         loadFilesystem("nfs", "nfs", dl);
  262.  
  263.         if ((rc = doMount(ksPath, "/tmp/ks", "nfs", 1, 0))) {
  264.         newtWinMessage(_("Error"), _("Ok"), 
  265.             _("I could not mount the kickstart path %s.\n"),
  266.             ksPath);
  267.         kickstart = 0;
  268.         } else {
  269.         ksFile = malloc(strlen(file) + 20);
  270.         sprintf(ksFile, "/tmp/ks/%s", file);
  271.  
  272.         if (ksReadCommands(ksFile)) 
  273.             kickstart = 0;
  274.         }
  275.     }
  276.     } 
  277.  
  278.     if (kickstart)
  279.     chooseLanguage();
  280. }
  281.  
  282. int main(int argc, char ** argv) {
  283.     char ** argptr, * arg;
  284.     struct installMethod * method;
  285.     int rc;
  286.     char * pcmciaArg = NULL;
  287.     int isSerial;
  288.     int force = 0;
  289.     struct stat sb;
  290.     char * childArgs[20];
  291.     struct intfInfo intf;
  292.     struct netInfo netc;
  293.     struct driversLoaded * dl = NULL;
  294.     char * ksMode = NULL;
  295.     int stage, direction;
  296.     char * keymap = NULL;
  297.     poptContext optCon;
  298.     int cont = 0;
  299.     int forceSupp = 0;
  300.     struct poptOption optionTable[] = {
  301.         { "expert", '\0', POPT_ARG_NONE, &expert, 0 },
  302.         { "force", '\0', POPT_ARG_NONE, &force, 0 },
  303.         { "forcesupp", '\0', POPT_ARG_NONE, &forceSupp, 0 },
  304.         { "kickstart", '\0', POPT_ARG_STRING, &ksMode, 0 },
  305.         { "ks", '\0', POPT_ARG_STRING, &ksMode, 0 },
  306.         { "test", '\0', POPT_ARG_NONE, &testing, 0 },
  307.         { 0, 0, 0, 0, 0 }
  308.     };
  309.  
  310.     if (!strcmp(argv[0] + strlen(argv[0]) - 6, "insmod")) {
  311.     return ourInsmodCommand(argc, argv);
  312.     } else if (!strcmp(argv[0] + strlen(argv[0]) - 5, "rmmod")) {
  313.     return rmmod_main(argc, argv);
  314.     } else if (!strcmp(argv[0], "install-continue")) {
  315.     cont = 1;
  316.     }
  317.  
  318.     memset(&intf, 0, sizeof(intf));
  319.     memset(&netc, 0, sizeof(netc));
  320.  
  321.     optCon = poptGetContext(NULL, argc, argv, optionTable, 0);
  322.  
  323.     if ((rc = poptGetNextOpt(optCon)) < -1) {
  324.     fprintf(stderr, "bad option %s: %s\n",
  325.                poptBadOption(optCon, POPT_BADOPTION_NOALIAS), 
  326.                poptStrerror(rc));
  327.     exit(1);
  328.     }
  329.  
  330.     if ((arg = poptGetArg(optCon))) {
  331.     fprintf(stderr, "unexpected argument: %s\n", arg);
  332.     exit(1);
  333.     }
  334.  
  335.     if (ksMode) {
  336.     if (testing) {
  337.         kickstart = KS_FILE;
  338.         ksFile = ksMode;
  339.     } else if (!strcmp(ksMode, "floppy"))
  340.         kickstart = KS_FLOPPY;
  341.     else if (!strcmp(ksMode, "bootp"))
  342.         kickstart = KS_BOOTP;
  343.     else {
  344.         fprintf(stderr, "unknown kickstart option %s\n", ksMode);
  345.         exit(1);
  346.     }
  347.     }
  348.  
  349.     if (!testing && !force && (getpid() > 50)) {
  350.     fprintf(stderr, "you're running me on a live system! that's ");
  351.     fprintf(stderr, "incredibly stupid.\n");
  352.     exit(1);
  353.     }
  354.  
  355.     openLog(testing);
  356.  
  357.     /* see if we're on a serial console -- if so, don't setup a keymap */
  358.     if (fstat(0, &sb)) {
  359.     logMessage("error stat'ing stdin: %s", strerror(errno));
  360.     return 1;
  361.     }
  362.  
  363.     if (!S_ISCHR(sb.st_mode)) {
  364.     logMessage("stdin isn't a character device!!! ack!");
  365.     return 1;
  366.     }
  367.  
  368.     isSerial = (major(sb.st_rdev) == 4 && minor(sb.st_dev) >= 64) ||
  369.                (major(sb.st_rdev) == 5 && minor(sb.st_dev) >= 64);
  370.  
  371.     logMessage("welcome to the Red Hat install "
  372.            "(first stage, version " VERSION " built " __DATE__ " "
  373.            __TIME__")");
  374.  
  375.     newtInit();
  376.     newtCls();
  377.     newtSetSuspendCallback(doSuspend);
  378.     newtDrawRootText(0, 0, _("Welcome to Red Hat Linux"));
  379.  
  380.     newtPushHelpLine(_("  <Tab>/<Alt-Tab> between elements  | <Space> selects | <F12> next screen "));
  381.  
  382.     /* kickstart from floppy needs to be handled before PCMCIA */
  383.     if (!cont && kickstart == KS_FLOPPY) {
  384.     if (devMakeInode("fd0", "/tmp/fd0"))
  385.         kickstart = 0;
  386.     else if (doMount("/tmp/fd0", "/tmp/ks", "msdos", 1, 0)) {
  387.         newtWinMessage(_("Error"), _("Ok"), 
  388.             _("I could not mount the boot floppy."));
  389.         kickstart = 0;
  390.     } else if (access("/tmp/ks/ks.cfg", R_OK)) {
  391.         newtWinMessage(_("Error"), _("Ok"), 
  392.             _("Cannot find ks.cfg on boot floppy."));
  393.         kickstart = 0;
  394.     } else {
  395.         int infd = -1, outfd = -1;
  396.         char buf[4096];
  397.         int i;
  398.  
  399.         if ((outfd = open("/tmp/ks.cfg", O_CREAT | O_RDWR, 0666)) < 0 
  400.              || (infd = open("/tmp/ks/ks.cfg", O_RDONLY)) < 0) {
  401.         newtWinMessage(_("Error"), _("Ok"), _("Error opening files "
  402.                    "for kickstart copy: %s\n"), strerror(errno));
  403.         kickstart = 0;
  404.         } else {
  405.         while ((i = read(infd, buf, sizeof(buf))) > 0) {
  406.             if (write(outfd, buf, i) != i) break;
  407.         }
  408.  
  409.         if (infd >= 0) close(infd);
  410.         if (outfd >= 0) close(outfd);
  411.  
  412.         if (!i) {
  413.             ksFile = alloca(30);
  414.             strcpy(ksFile, "/tmp/ks.cfg");
  415.  
  416.             if (ksReadCommands(ksFile)) 
  417.             kickstart = 0;
  418.         } else {
  419.             newtWinMessage(_("Error"), _("Ok"), 
  420.                    _("Error copying kickstart file from floppy."));
  421.             kickstart = 0;
  422.         }
  423.         }
  424.  
  425.         umount("/tmp/ks");
  426.         devRemoveInode("/tmp/fd0");
  427.     }
  428.     } else if (cont && kickstart == KS_FLOPPY) {
  429.      /* continue install after language re-exec - all data was lost */
  430.     ksFile = strdup("/tmp/ks.cfg");
  431.  
  432.     if (ksReadCommands(ksFile)) 
  433.         kickstart = 0;
  434.     } else if (kickstart == KS_FILE) {
  435.     rc = 0;
  436.     while (!rc) ;
  437.     if (ksReadCommands(ksFile)) 
  438.         kickstart = 0;
  439.     }
  440.  
  441.     direction = 1;
  442.     if (cont)
  443.     stage = 1;
  444.     else
  445.     stage = 0;
  446.  
  447.     do {
  448.     switch (stage) {
  449.       case 0:
  450.         if (!kickstart) {
  451.         welcome();
  452.         /* kickstart installs do this later */
  453.         chooseLanguage();
  454.         }
  455.         newtFinished();
  456.         argv[0] = "install-continue";
  457.         execv(testing ? "./install" : "/sbin/install", argv);
  458.         break;
  459.  
  460.       case 1:
  461.         setDefaultLanguage(1);
  462. #if defined(__i386__) || defined(__alpha__)
  463.         if (isSerial || kickstart) {
  464.         direction = 1, stage++;
  465.         break;
  466.         }
  467.         rc = setupKeyboard(&keymap); 
  468.         direction = (rc == INST_CANCEL) ? -1 : 1;
  469. #endif
  470.         stage += direction;
  471.         break;
  472.  
  473.       case 2:
  474. #if defined(__i386__)
  475.         rc = setupPCMCIA(&pcmciaArg, direction);
  476.         direction = (rc == INST_CANCEL) ? -1 : 1;
  477. #endif
  478.         stage += direction;
  479.         break;
  480.  
  481.       case 3:
  482.         doKickstart(&intf, &netc, &dl);
  483.         stage += direction;
  484.         break;
  485.  
  486.       case 4:
  487.         rc = chooseInstallMethod(forceSupp, &method, &netc, &intf, &dl);
  488.         direction = (rc == INST_CANCEL) ? -1 : 1;
  489.         stage += direction;
  490.         break;
  491.     }
  492.     } while (stage < 5);
  493.  
  494.     logMessage("method selection completed");
  495.  
  496.     /* FIXME: is this a decent test? */
  497.     if (intf.set) {
  498.     writeNetInterfaceConfig("/tmp", &intf);
  499.     writeNetConfig("/tmp", &netc, &intf, 1);
  500.     }
  501.     if (dl) writeModuleConf("/tmp", dl, 0);
  502.  
  503.     logMessage("state saved to /tmp");
  504.  
  505.     newtFinished();
  506.  
  507.     closeLog();
  508.  
  509.     if (testing) exit(0);
  510.  
  511.     argptr = childArgs;
  512.     *argptr++ = "/usr/bin/runinstall2";
  513.     *argptr++ = "--method";
  514.     *argptr++ = method->abbrev;
  515.  
  516.     if (expert)
  517.     *argptr++ = "--expert";
  518.  
  519.     if (pcmciaArg) {
  520.     *argptr++ = "--pcmcia";
  521.     *argptr++ = pcmciaArg;
  522.     }
  523.  
  524.     if (kickstart) {
  525.     *argptr++ = "--ks";
  526.     *argptr++ = ksFile;
  527.     }
  528.  
  529.     *argptr++ = NULL;
  530.  
  531.     execv(childArgs[0], childArgs);
  532.  
  533.     rc = errno;
  534.     openLog(testing);
  535.     logMessage("error in exec of second stage loader :-(");
  536.     logMessage("\terror:%s", strerror(rc));
  537.  
  538.     while (1) ;
  539.  
  540.     return 0;
  541. }
  542.