home *** CD-ROM | disk | FTP | other *** search
/ Chip 1998 February / CHIP_2_98.iso / misc / src / install / install2.c < prev    next >
C/C++ Source or Header  |  1997-11-10  |  31KB  |  1,205 lines

  1. /*
  2.  * install2.c
  3.  * 
  4.  * This is the second half of the install. It is exec'd from the first half
  5.  * once the secondary media has been mounted. It does a bunch of argv
  6.  * processing to figure out what the first half did. It's a bit of a hack, but
  7.  * it gives us a nice install as far as the user can see.
  8.  *
  9.  * Erik Troan (ewt@redhat.com)
  10.  *
  11.  * Copyright 1997 Red Hat Software 
  12.  *
  13.  * This software may be freely redistributed under the terms of the GNU
  14.  * public license.
  15.  *
  16.  * You should have received a copy of the GNU General Public License
  17.  * along with this program; if not, write to the Free Software
  18.  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  19.  *
  20.  */
  21.  
  22. /*
  23.  * We assume the following:
  24.  *
  25.  *    /usr/bin -> any binaries we might need
  26.  *
  27.  * it's up to the first stage installer to make sure this happens.
  28.  *
  29.  */
  30.  
  31. #include <dirent.h>
  32. #include <errno.h>
  33. #include <fcntl.h>
  34. #include <newt.h>
  35. #include <popt.h>
  36. #include <stdlib.h>
  37. #include <string.h>
  38. #include <sys/stat.h>
  39. #include <sys/sysmacros.h>
  40. #include <sys/time.h>
  41. #include <sys/wait.h>
  42. #include <termios.h>
  43. #include <unistd.h>
  44.  
  45. #include "commands.h"
  46. #include "config.h"
  47. #include "devices.h"
  48. #include "doit.h"
  49. #include "fs.h"
  50. #include "fsedit.h"
  51. #include "hd.h"
  52. #include "install.h"
  53. #include "kbd.h"
  54. #include "kernel.h"
  55. #include "kickstart.h"
  56. #include "lilo.h"
  57. #include "log.h"
  58. #include "methods.h"
  59. #include "mkswap.h"
  60. #include "net.h"
  61. #include "perror.h"
  62. #include "pkgs.h"
  63. #include "printercfg.h"
  64. #include "run.h"
  65. #include "scsi.h"
  66. #include "upgrade.h"
  67. #include "windows.h"
  68.  
  69. int testing = 0;
  70. int expert = 0;
  71. int kickstart = 0;
  72.  
  73. #define STEP_FIRST    0
  74.  
  75. #define STEP_PATH        0
  76. #define STEP_SCSI        1
  77. #define STEP_FDISKMTAB        2
  78. #define STEP_SWAP        3
  79. #define STEP_FINDPKGS         4
  80. #define STEP_FORMAT         5
  81. #define STEP_PICKPKGS         6
  82. #define STEP_DOIT        7
  83. #define STEP_FINISHNET        8
  84. #define STEP_TIMECONFIG        9
  85. #define STEP_SERVICES        10
  86. #define STEP_PRINTER        11
  87. #define STEP_ROOTPW        12
  88. #define STEP_LILO        13
  89.  
  90. #define STEP_UPG_SCSI        1
  91. #define STEP_UPG_PKGS        2
  92. #define STEP_UPG_MTAB        3
  93. #define STEP_UPG_FFILES        4
  94. #define STEP_UPG_DOIT        5
  95. #define STEP_UPG_FINISHNET    6
  96. #define STEP_UPG_LILO        7
  97.  
  98. #define STEP_DONE    1000
  99.  
  100. struct installState {
  101.     int isUpgrade, lastChoice;
  102.     char * pcmcia, * kernel, * keyboard;
  103.     struct partitionTable table;
  104.     struct fstab fstab;
  105.     struct pkgSet ps;
  106.     struct componentSet cs;
  107.     struct installMethod * method;
  108.     struct netInterface intf;
  109.     struct netConfig netc;
  110.     struct driversLoaded * dl;
  111.     struct installStep * steps;
  112. } ;
  113.  
  114. typedef int (*installStepFn)(struct installState * state);
  115.  
  116. static int setupSCSI(struct installState * state);
  117. static int partitionDisks(struct installState * state);
  118. static int setupSwap(struct installState * state);
  119. static int findInstallFiles(struct installState * state);
  120. static int formatPartitions(struct installState * state);
  121. static int choosePackages(struct installState * state);
  122. static int doInstallStep(struct installState * state);
  123. static int setRootPassword(struct installState * state);
  124. static int configureTimezone(struct installState * state);
  125. static int configureServices(struct installState * state);
  126. static int configurePrinter(struct installState * state);
  127. static int setupBootloader(struct installState * state);
  128. static int finishNetworking(struct installState * state);
  129. static int selectPath(struct installState * state);
  130. static int upgrChoosePackages(struct installState * state);
  131. static int upgrFindInstall(struct installState * state);
  132. static void setupSerialConsole(void);
  133.  
  134. struct installStep {
  135.     char * name;
  136.     int prev, next;
  137.     installStepFn fn;
  138.     int skipOnCancel;
  139.     int completed;
  140. };
  141.  
  142. struct installStep installSteps[] = { 
  143.     { "Select installation path",    -1,        STEP_SCSI,
  144.     selectPath, 0, 0 },
  145.     { "Setup SCSI",             STEP_PATH,     STEP_FDISKMTAB,
  146.     setupSCSI, 0, 0 },
  147.     { "Setup filesystems",         STEP_PATH,     STEP_SWAP,
  148.     partitionDisks, 0, 0 },
  149.     { "Setup swap space",         STEP_FDISKMTAB, STEP_FINDPKGS,
  150.     setupSwap, 0, 0 },
  151.     { "Find installation files",    STEP_SWAP,    STEP_FORMAT,
  152.     findInstallFiles, 1, 0 },
  153.     { "Choose partitions to format",    STEP_SWAP,    STEP_PICKPKGS,
  154.     formatPartitions, 0, 0 },
  155.     { "Choose packages to install",    STEP_FORMAT,    STEP_DOIT,
  156.     choosePackages, 0, 0 },
  157.     { "Install system",            STEP_PICKPKGS,    STEP_FINISHNET,
  158.     doInstallStep, 0, 0 },
  159.     { "Configure networking",        -1,        STEP_TIMECONFIG,
  160.     finishNetworking, 0, 0 },
  161.     { "Configure timezone",        STEP_FINISHNET,    STEP_SERVICES,
  162.     configureTimezone, 0, 0 },
  163.     { "Configure services",        STEP_TIMECONFIG,STEP_PRINTER,
  164.     configureServices, 0, 0 },
  165.     { "Configure printer",        STEP_SERVICES,    STEP_ROOTPW,
  166.     configurePrinter, 0, 0 },
  167.     { "Set root password",        STEP_PRINTER,    STEP_LILO,
  168.     setRootPassword, 0, 0 },
  169.     { "Install bootloader",        STEP_ROOTPW,    STEP_DONE,
  170.     setupBootloader, 0, 0 },
  171. };
  172.  
  173. struct installStep upgradeSteps[] = { 
  174.     { "Select installation path",    -1,        STEP_UPG_SCSI,
  175.     selectPath, 0, 0 },
  176.     { "Setup SCSI",             STEP_PATH,     STEP_UPG_PKGS,
  177.     setupSCSI, 0, 0 },
  178.     { "Find installation files",    STEP_PATH,    STEP_UPG_MTAB,
  179.     findInstallFiles, 1, 0 },
  180.     { "Find current installation",    STEP_UPG_PKGS,    STEP_UPG_FFILES,
  181.     upgrFindInstall, 0, 0 },
  182.     { "Choose packages to upgrade",    STEP_UPG_FFILES,STEP_UPG_DOIT,
  183.     upgrChoosePackages, 0, 0 },
  184.     { "Upgrade system",            -1,        STEP_UPG_FINISHNET,
  185.     doInstallStep, 0, 0 },
  186.     { "Install bootloader",        STEP_UPG_FINISHNET,    STEP_DONE,
  187.     setupBootloader, 0, 0 },
  188. };
  189.  
  190. void spawnShell(void) {
  191.     pid_t pid;
  192.     int fd;
  193.  
  194.     if (!testing) {
  195.     fd = open("/dev/tty2", O_RDWR);
  196.     if (fd < 0) {
  197.         logMessage("cannot open /dev/tty2 -- no shell will be provided");
  198.         return;
  199.     } else if (access("/usr/bin/sh",  X_OK))  {
  200.         logMessage("cannot open shell - /usr/bin/sh doesn't exist");
  201.         return;
  202.     }
  203.  
  204.     if (!(pid = fork())) {
  205.         dup2(fd, 0);
  206.         dup2(fd, 1);
  207.         dup2(fd, 2);
  208.  
  209.         close(fd);
  210.         setsid();
  211.  
  212.         execl("/bin/sh", "-/bin/sh", NULL);
  213.         logMessage(perrorstr("exec of /bin/sh failed"));
  214.     }
  215.  
  216.     close(fd);
  217.     }
  218. }
  219.  
  220. static int setupSCSI(struct installState * state) {
  221.     return setupSCSIInterfaces(0, &state->dl);
  222. }
  223.  
  224. static int useNewFdisk(int * useNew) {
  225.     int rc;
  226.  
  227.     rc = newtWinTernary("Disk Setup", "Disk Druid", "fdisk", "Cancel",
  228.         "Disk Druid is a tool for partitioning and setting up mount "
  229.         "points. It is designed to be easier to use than Linux's "
  230.         "traditional disk partitioning sofware, fdisk, as well "
  231.         "as more powerful. However, there are some cases where fdisk "
  232.         "may be preferred.\n\n"
  233.         "Which tool would you like to use?");
  234.  
  235.     if (rc == 3)
  236.     return INST_CANCEL;
  237.  
  238.     if (rc == 0 || rc == 1)
  239.     *useNew = 1;
  240.     else
  241.     *useNew = 0;
  242.  
  243.     return 0;
  244. }
  245.  
  246. static int partitionDisks(struct installState * state) {
  247.     int rc = 0;
  248.     char ** drives;
  249.     int useNew;
  250.     int numDrives;
  251.     
  252.     if (state->isUpgrade) 
  253.     return findAllPartitions(NULL, &state->table);
  254.  
  255. #if defined(__i386__) || defined(__alpha__)
  256.     if (kickstart) {
  257.     if ((rc = getDriveList(&drives, &numDrives))) return rc;
  258.     return kickstartPartitioning(&state->table, &state->fstab, drives);
  259.     }
  260. #endif
  261.  
  262.     do {
  263. #if defined(__i386__) || defined(__alpha__)
  264.     if ((rc = useNewFdisk(&useNew))) return rc;
  265. #else
  266.     useNew = 0;
  267. #endif
  268.  
  269.     if (useNew) {
  270. #if defined(__i386__) || defined(__alpha__)
  271.         if ((rc = getDriveList(&drives, &numDrives))) return rc;
  272.         if ((rc = FSEditPartitions(&state->table, &state->fstab,
  273.                     drives, &state->intf,
  274.                        &state->netc, &state->dl))) return rc;
  275. #endif
  276.     } else {
  277.         do {
  278.         if ((rc = partitionDrives())) return rc;
  279.         if ((rc = findAllPartitions(NULL, &state->table))) return rc;
  280.  
  281.         rc = setupMountTable(state->table, &state->fstab, &state->intf,
  282.                    &state->netc, &state->dl);
  283.         if (rc) return rc;
  284.         } while (rc);
  285.     }
  286.     } while (rc);
  287.  
  288.     return rc;
  289. }
  290.  
  291. static int findInstallFiles(struct installState * state) {
  292.     int rc;
  293.  
  294.     if (!state->table.parts) { 
  295.     rc = findAllPartitions(NULL, &state->table);
  296.     if (rc) return rc;
  297.     }
  298.  
  299.     if (state->method->prepareRoot) {
  300.     rc = state->method->prepareRoot(state->method, state->table,
  301.                     &state->netc, &state->intf,
  302.                     &state->dl);
  303.     if (rc) return rc;
  304.     }
  305.  
  306.     if ((rc = state->method->getPackageSet(state->method, &state->ps)))
  307.     return rc;
  308.     if ((state->method->getComponentSet(state->method, &state->ps, 
  309.      &state->cs)) )
  310.     return rc;
  311.  
  312.     return 0;
  313. }
  314.  
  315. static int formatPartitions(struct installState * state) {
  316.     int i;
  317.  
  318.     if (kickstart) {
  319.     for (i = 0; i < state->fstab.numEntries; i++) {
  320.         if (state->fstab.entries[i].type == PART_EXT2)
  321.         state->fstab.entries[i].doFormat = 1;
  322.     }
  323.  
  324.     return 0;
  325.     }
  326.  
  327.     return queryFormatFilesystems(&state->fstab);
  328. }
  329.  
  330. static int setupSwap(struct installState * state) {
  331.     return activeSwapSpace(&state->table, &state->fstab);
  332. }
  333.  
  334. static int choosePackages(struct installState * state) {
  335.     return psSelectPackages(&state->ps, &state->cs, 0, 0);
  336. }
  337.  
  338. static int doInstallStep(struct installState * state) {
  339.     int rc;
  340.     char * netSharedPath = NULL;
  341.     FILE * f;
  342.     int netSharedLength;
  343.     int i;
  344.  
  345.     if (!state->isUpgrade) {
  346.     if (!kickstart) {
  347.         rc = newtWinChoice("Install log", "Ok", "Cancel", "A complete log "
  348.             "of your installation will be in /tmp/install.log "
  349.             "after rebooting your system. You may want to keep "
  350.             "this file for later reference.");
  351.         if (rc == 1) return INST_CANCEL;
  352.     }
  353.  
  354.     rc = formatFilesystems(&state->fstab);
  355.     if (rc) return rc;
  356.  
  357.     rc = mountFilesystems(&state->fstab);
  358.     if (rc) return rc;
  359.  
  360.     if (state->method->prepareMedia) {
  361.         rc = state->method->prepareMedia(state->method, &state->fstab);
  362.         if (rc) {
  363.         umountFilesystems(&state->fstab);
  364.         return rc;
  365.         }
  366.     }
  367.     } else {
  368.     if (!kickstart) {
  369.         rc = newtWinChoice("Upgrade log", "Ok", "Cancel", "A complete log "
  370.             "of your upgrade will be in /tmp/upgrade.log when "
  371.             "the upgrade is finished. After rebooting, please "
  372.             "read it to ensure configuration files are properly "
  373.             "updated.");
  374.         if (rc == 1) return INST_CANCEL;
  375.     }
  376.     }
  377.  
  378.     /* FIXME: should this read the net shared path from /etc/rpmrc
  379.        during upgrades??? Probably. */
  380.     for (i = netSharedLength = 0; i < state->fstab.numEntries; i++) 
  381.     if (state->fstab.entries[i].type == PART_NFS)
  382.         netSharedLength += 1 + strlen(state->fstab.entries[i].mntpoint);
  383.  
  384.     if (netSharedLength) {
  385.     netSharedPath = alloca(netSharedLength);
  386.     *netSharedPath = '\0';
  387.     for (i = netSharedLength = 0; i < state->fstab.numEntries; i++) {
  388.         if (state->fstab.entries[i].type == PART_NFS) {
  389.         if (*netSharedPath) strcat(netSharedPath, ":");
  390.         strcat(netSharedPath, state->fstab.entries[i].mntpoint);
  391.         }
  392.         }
  393.  
  394.     logMessage("netSharedPath is: %s\n", netSharedPath);
  395.     }
  396.  
  397.     rc = doInstall(state->method, &state->ps, 
  398.            netSharedPath, state->keyboard, state->isUpgrade);
  399.  
  400.     if (netSharedPath && access("/mnt/etc/rpmrc", X_OK)) {
  401.     logMessage("creating /etc/rpmrc for netshared info (as none exists)");
  402.     f = fopen("/mnt/etc/rpmrc", "w");
  403.     if (!f) {
  404.         errorWindow("error creating /mnt/etc/rpmrc: %s");
  405.     } else {
  406.         fprintf(f, "netsharedpath: %s\n", netSharedPath);
  407.         fclose(f);
  408.     }
  409.     }
  410.  
  411.     sync();
  412.     sync();
  413.  
  414.     if (!rc) psFreeComponentSet(&state->cs);
  415.  
  416.     configPCMCIA(state->pcmcia);
  417.  
  418.     return rc;
  419. }
  420.  
  421.  
  422. static char mksalt(int seed) {
  423.     int num = seed % 64;
  424.  
  425.     if (num < 26)
  426.     return 'a' + num;
  427.     else if (num < 52)
  428.     return 'A' + (num - 26);
  429.     else if (num < 62)
  430.     return '0' + (num - 52);
  431.     else if (num == 63)
  432.     return '.';
  433.     else
  434.     return '/';
  435. }
  436.  
  437. static int setRootPassword(struct installState * state) {
  438.     newtComponent form = NULL, text, pw1Entry, pw2Entry;
  439.     char * pw1 = NULL, * pw2;
  440.     int done = 0;
  441.     char salt[3];
  442.     char cmd[200];
  443.     struct timeval time1, time2;
  444.     char * pw;
  445.     pid_t pid;
  446.     int status, rc;
  447.     char ** argv;
  448.     int argc;
  449.     poptContext optCon;
  450.     int skipCrypt = 0;
  451.     struct poptOption ksOptions[] = {
  452.         { "iscrypted", '\0', POPT_ARG_NONE, &skipCrypt, 0 },
  453.         { 0, 0, 0, 0, 0 }
  454.     };
  455.  
  456.     if (kickstart) {
  457.     if (!ksGetCommand(KS_CMD_ROOTPW, NULL, &argc, &argv)) {
  458.         optCon = poptGetContext(NULL, argc, argv, ksOptions, 0);
  459.  
  460.         if ((rc = poptGetNextOpt(optCon)) < -1) {
  461.         newtWinMessage("rootpw command",  "Ok",
  462.                "bad argument to kickstart rootpw command %s: %s",
  463.                poptBadOption(optCon, POPT_BADOPTION_NOALIAS), 
  464.                poptStrerror(rc));
  465.         }
  466.  
  467.         if (!(pw1 = poptGetArg(optCon))) {
  468.         newtWinMessage("rootpw command",  "Ok",
  469.                "Missing password");
  470.         skipCrypt = 0;
  471.         }
  472.  
  473.         if (poptGetArg(optCon))
  474.         newtWinMessage("rootpw command",  "Ok",
  475.                "Unexpected arguments");
  476.  
  477.         poptFreeContext(optCon);
  478.     }
  479.     }    
  480.  
  481.     if (!pw1) {
  482.     gettimeofday(&time1, NULL);
  483.  
  484.     newtCenteredWindow(50, 14, "Root Password");
  485.  
  486.     form = newtForm(NULL, NULL, 0);
  487.  
  488.     text = newtTextbox(1, 1, 47, 5, NEWT_TEXTBOX_WRAP);
  489.     newtTextboxSetText(text,
  490.         "Pick a root password. You must type it twice to ensure you know "
  491.         "what it is and didn't make a mistake in typing. Remember that the "
  492.         "root password is a critical part of system security!");
  493.  
  494.     newtFormAddComponent(form, newtLabel(3, 7, "Password        :"));
  495.     newtFormAddComponent(form, newtLabel(3, 8, "Password (again):"));
  496.  
  497.     pw1Entry = newtEntry(21, 7, "", 24, &pw1, NEWT_ENTRY_HIDDEN);
  498.     pw2Entry = newtEntry(21, 8, "", 24, &pw2, NEWT_ENTRY_HIDDEN);
  499.  
  500.     newtFormAddComponents(form, text, pw1Entry, pw2Entry, NULL);
  501.  
  502.     newtFormAddComponent(form, newtButton(20, 10, "Ok"));
  503.  
  504.     do {
  505.         newtFormSetCurrent(form, pw1Entry);
  506.         newtRunForm(form);
  507.         
  508.         if (testing) {
  509.         done = 1;
  510.         } else if (strcmp(pw1, pw2)) {
  511.         newtWinMessage("Password Mismatch", "Ok",
  512.                 "The passwords you entered were different. Please "
  513.                 "try again.");
  514.         newtEntrySet(pw1Entry, "", 0);
  515.         newtEntrySet(pw2Entry, "", 0);
  516.         } else if (strlen(pw1) < 6)  {
  517.         newtWinMessage("Password Mismatch", "Ok",
  518.                 "The root password must be at least 6 characters "
  519.                 "long.");
  520.         newtEntrySet(pw1Entry, "", 0);
  521.         newtEntrySet(pw2Entry, "", 0);
  522.         } else
  523.         done = 1;
  524.     } while (!done);
  525.  
  526.     newtPopWindow();
  527.     }
  528.  
  529.     if (testing) return 0;
  530.  
  531.     if (!skipCrypt) {
  532.     gettimeofday(&time2, NULL);
  533.  
  534.     salt[0] = mksalt(time1.tv_usec);
  535.     salt[1] = mksalt(time2.tv_usec);
  536.     salt[2] = '\0';
  537.  
  538.     pw = crypt(pw1, salt);
  539.     } else {
  540.     pw = pw1;
  541.     }
  542.  
  543.     sprintf(cmd, "/bin/sed 's&root::&root:%s:&' < /etc/passwd > "
  544.         "/etc/passwd.new", pw);
  545.  
  546.     if (!kickstart)
  547.     newtFormDestroy(form);
  548.  
  549.     if (!(pid = fork())) {
  550.     chroot("/mnt");
  551.     chdir("/mnt");
  552.  
  553.     exit(system(cmd));
  554.     }
  555.  
  556.     waitpid(pid, &status, 0);
  557.  
  558.     unlink("/mnt/etc/passwd");
  559.     rename("/mnt/etc/passwd.new", "/mnt/etc/passwd");
  560.  
  561.     return 0;
  562. }
  563.     
  564. static int configureTimezone(struct installState * state) {
  565.     return timeConfig();
  566. }
  567.  
  568. static int configureServices(struct installState * state) {
  569.     return servicesConfig();
  570. }
  571.  
  572. static int setupBootloader(struct installState * state) {
  573.     static int first = 1;
  574. #ifdef __alpha
  575.     int rc;
  576. #else
  577.     int rc;
  578.     int append = 0;
  579.     char * version;
  580.     int i;
  581. #endif
  582.  
  583.     if (!state->isUpgrade && first) {
  584.     writeFstab(&state->fstab);
  585.     setupSerialConsole();
  586.     }
  587.  
  588.     #ifdef __alpha__
  589.     if (first) {
  590.         first = 0;
  591.         rc = kernelCopy(state->kernel);
  592.         if (rc) return rc;
  593.     }
  594.  
  595.     return INST_NOP;
  596.     #else
  597.     first = 0;
  598.  
  599.     if (state->isUpgrade && !access("/mnt/etc/conf.modules", X_OK)) {
  600.         rc = readModuleConfPersist("/mnt/etc", state->dl);
  601.         if (rc) return rc;
  602.         append = 1;
  603.     }
  604.  
  605.     writeModuleConf("/mnt/etc", state->dl, 1);
  606.  
  607.     for (i = 0; i < state->ps.numPackages; i++) {
  608.         if (!strncmp(state->ps.packages[i]->name, "kernel", 6)) break;
  609.     }
  610.  
  611.     if (i == state->ps.numPackages) {
  612.         errorWindow("I couldn't find a kernel!");
  613.         return INST_ERROR;
  614.     } 
  615.  
  616.     headerGetEntry(state->ps.packages[i]->h, RPMTAG_VERSION, NULL, 
  617.                (void *) &version, NULL);
  618.  
  619.     logMessage("installed kernel version %s", version);
  620.  
  621.     /* installLilo installs silo on the SPARC */
  622.     return installLilo("/mnt/etc", state->table, state->fstab, version);
  623.     #endif
  624. }
  625.  
  626. static int finishNetworking(struct installState * state) {
  627.     int rc;
  628.  
  629.     rc = checkNetConfig(&state->intf, &state->netc, &state->dl);
  630.     if (rc) return rc;
  631.  
  632.     writeNetConfig("/mnt/etc/sysconfig", &state->netc, &state->intf, 0);
  633.     writeNetInterfaceConfig("/mnt/etc/sysconfig/network-scripts", &state->intf);
  634.     writeResolvConf("/mnt/etc", &state->netc);
  635.     writeHosts("/mnt/etc", &state->netc, &state->intf);
  636.  
  637.     return 0;
  638. }
  639.  
  640. static int selectPath(struct installState * state) {
  641.     int result;
  642.  
  643.     memset(state, 0, sizeof(state));
  644.  
  645.     if (kickstart) {
  646.     if (!ksGetCommand(KS_CMD_UPGRADE, NULL, NULL, NULL)) {
  647.         state->steps = upgradeSteps;
  648.         state->isUpgrade = 1;
  649.     } else {
  650.         state->steps = installSteps;
  651.     }
  652.  
  653.     return 0;
  654.     }
  655.  
  656.     result = newtWinChoice("Installation Path", "Install", "Upgrade",
  657.     "Would you like to install a new system or upgrade a system which "
  658.     "already contains Red Hat 2.0 or later?");
  659.    
  660.     if (result == 1) {
  661.     state->steps = upgradeSteps;
  662.     state->isUpgrade = 1;
  663.     } else
  664.     state->steps = installSteps;
  665.  
  666.     return 0;
  667. }
  668.  
  669. static int upgrFindInstall(struct installState * state) {
  670.     int rc;
  671.  
  672.     /* this also turns on swap for us */
  673.     rc = readMountTable(state->table, &state->fstab);
  674.     if (rc) return rc;
  675.  
  676.     if (!testing) {
  677.     mountFilesystems(&state->fstab);
  678.  
  679.     if (state->method->prepareMedia) {
  680.         rc = state->method->prepareMedia(state->method, &state->fstab);
  681.         if (rc) {
  682.         umountFilesystems(&state->fstab);
  683.         return rc;
  684.         }
  685.     }
  686.     }
  687.  
  688.     return 0;
  689. }
  690.  
  691. static int upgrChoosePackages(struct installState * state) {
  692.     int firstTime = 1;
  693.     char * rpmconvertbin;
  694.     int rc;
  695.     char * path;
  696.     char * argv[] = { NULL, NULL };
  697.  
  698.     if (testing)
  699.     path = "/";
  700.     else
  701.     path = "/mnt";
  702.  
  703.     if (firstTime) {
  704.     if (access("/mnt/var/lib/rpm/packages.rpm", R_OK)) {
  705.         if (access("/mnt/var/lib/rpm/packages", R_OK)) {
  706.         errorWindow("No RPM database exists!");
  707.         return INST_ERROR;
  708.         }
  709.  
  710.         if (state->method->getFile(state->method, "rpmconvert", 
  711.             &rpmconvertbin, 1)) {
  712.         return INST_ERROR;
  713.         }
  714.     
  715.         symlink("/mnt/var", "/var");
  716.         winStatus(35, 3, "Upgrade", "Converting RPM database...");
  717.         chmod(rpmconvertbin, 0755);
  718.         argv[0] = rpmconvertbin;
  719.         rc = runProgram(RUN_LOG, rpmconvertbin, argv);
  720.         if (state->method->rmFiles)
  721.         unlink(rpmconvertbin);
  722.  
  723.         newtPopWindow();
  724.         if (rc) return INST_ERROR;
  725.     }
  726.     
  727.     winStatus(35, 3, "Upgrade", "Finding packages to upgrade...");
  728.     rc = ugFindUpgradePackages(&state->ps, path);
  729.     newtPopWindow();
  730.     if (rc) return rc;
  731.     firstTime = 0;
  732.     psVerifyDependencies(&state->ps, 1);
  733.     }
  734.  
  735.     return psSelectPackages(&state->ps, &state->cs, 0, 1);
  736. }
  737.  
  738. #define DO_RETRY    1
  739. #define DO_NEXT        2
  740. #define DO_PREV        3
  741. #define DO_MENU        4
  742.  
  743. static int errcanChoices(char * name, int wasCancelled) {
  744.     newtComponent form, retry, previous, menu, text, exitb, answer;
  745.     char textBuf[1000];
  746.  
  747.     if (wasCancelled) {
  748.     sprintf(textBuf, "You cancelled step \"%s\".\n\n", name);
  749.     newtCenteredWindow(50, 16, "Cancelled");
  750.     } else {
  751.     sprintf(textBuf, "An error occured during step \"%s\" of the "
  752.         "install.\n\n", name);
  753.     newtCenteredWindow(50, 16, "Error");
  754.     }
  755.  
  756.     form = newtForm(NULL, NULL, 0);
  757.  
  758.     strcat(textBuf, "You may retry that step, return to the previous step "
  759.             "in the install, or see a menu of installation steps "
  760.             "which will allow you to move around in the install "
  761.             "more freely. It is not recommended to use the menu "
  762.             "unless you are already familiar with Red Hat Linux. "
  763.             "What would you like to do?");
  764.  
  765.     text = newtTextbox(1, 1, 48, 10, NEWT_TEXTBOX_WRAP);
  766.     newtTextboxSetText(text, textBuf);
  767.   
  768.     if (testing) {
  769.     previous = newtButton(1, 12, "Previous");
  770.     retry = newtButton(15, 12, "Retry");
  771.     menu = newtButton(28, 12, "Menu");
  772.     exitb = newtButton(39, 12, "Exit");
  773.     newtFormAddComponents(form, text, previous, retry, menu, exitb, NULL);
  774.     } else {
  775.     previous = newtButton(5, 12, "Previous");
  776.     retry = newtButton(20, 12, "Retry");
  777.     menu = newtButton(38, 12, "Menu");
  778.     newtFormAddComponents(form, text, previous, retry, menu, NULL);
  779.     }
  780.  
  781.     answer = newtRunForm(form);
  782.  
  783.     newtPopWindow();
  784.     newtFormDestroy(form);
  785.  
  786.     if (answer == previous)
  787.     return DO_PREV;
  788.     else if (answer == retry)
  789.     return DO_RETRY;
  790.     else if (answer == menu)
  791.     return DO_MENU;
  792.  
  793.     newtFinished();
  794.     exit(0); 
  795. }
  796.  
  797. static int stepMenu(struct installState * state, int currStep) {
  798.     newtComponent form, listbox, okay, text;
  799.     int firstStep = currStep;
  800.     long i;
  801.     int numChoices, listHeight;
  802.     char buf[200];
  803.  
  804.     newtCenteredWindow(50, 16, "Installation Steps");
  805.  
  806.     while (state->steps[firstStep].prev != -1)
  807.     firstStep = state->steps[firstStep].prev;
  808.  
  809.     form = newtForm(NULL, NULL, 0);
  810.  
  811.     i = firstStep, numChoices = 0;
  812.     do {
  813.     numChoices++;
  814.     i = state->steps[i].next;
  815.     } while (state->steps[i].prev != -1 && state->steps[i].next != STEP_DONE);
  816.     numChoices++;
  817.  
  818.     if (numChoices > 6)
  819.     listHeight = 6;
  820.     else
  821.     listHeight = 0;
  822.  
  823.     listbox = newtListbox(10, 4, listHeight, NEWT_LISTBOX_RETURNEXIT);
  824.  
  825.     text = newtTextbox(1, 1, 48, 3, NEWT_TEXTBOX_WRAP);
  826.     newtTextboxSetText(text, 
  827.         "What step would you like to run? Steps with a * next "
  828.         "to them have already been completed.");
  829.  
  830.     newtListboxAddEntry(listbox, "  Continue with install", 
  831.             (void *) STEP_DONE + 1);
  832.     for (i = firstStep; i < (firstStep + numChoices); i++) {
  833.     if (state->steps[i].completed)
  834.        strcpy(buf, "* ");
  835.     else
  836.        strcpy(buf, "  ");
  837.  
  838.     strcat(buf, state->steps[i].name);
  839.     newtListboxAddEntry(listbox, buf, (void *) i);
  840.     }
  841.  
  842.     okay = newtButton(23, 11, "Ok");
  843.     newtFormAddComponents(form, text, listbox, okay, NULL);
  844.  
  845.     newtRunForm(form);
  846.  
  847.     i = (long) newtListboxGetCurrent(listbox);
  848.  
  849.     newtFormDestroy(form);
  850.     newtPopWindow();
  851.  
  852.     if (i == STEP_DONE + 1)
  853.     return -1;
  854.  
  855.     return i;
  856. }
  857.  
  858. static int getNextStep(struct installState * state, int lastStep, int lastrc) {
  859.     int choice;
  860.     int nextStep;
  861.  
  862.     if (state->lastChoice == DO_MENU)
  863.     choice = DO_MENU;
  864.     else if (lastrc == INST_ERROR) {
  865.     choice = errcanChoices(state->steps[lastStep].name, 0);
  866.     kickstart = 0;
  867.     } else if (lastrc == INST_CANCEL) {
  868.     choice = errcanChoices(state->steps[lastStep].name, 1);
  869.     } else if (lastrc == INST_NOP) {
  870.     choice = state->lastChoice;
  871.     } else {
  872.     choice = DO_NEXT;
  873.     }
  874.  
  875.     switch (choice) {
  876.       case DO_PREV:
  877.     nextStep = state->steps[lastStep].prev;
  878.     while (nextStep != -1 && state->steps[nextStep].skipOnCancel && 
  879.            state->steps[nextStep].prev != -1)
  880.         nextStep = state->steps[nextStep].prev;
  881.  
  882.     if (nextStep == -1 || nextStep == lastStep) {
  883.         newtWinMessage("Cancelled", "Ok", "I can't go to the previous step"
  884.               " from here. You will have to try again.");
  885.         nextStep = lastStep;
  886.     }
  887.     break;
  888.  
  889.       case DO_RETRY:
  890.     nextStep = lastStep;
  891.     break;
  892.  
  893.       case DO_MENU:
  894.     nextStep = stepMenu(state, lastStep);
  895.     if (nextStep == -1) {
  896.         choice = DO_NEXT;
  897.  
  898.         if (lastrc)
  899.         nextStep = lastStep;
  900.         else
  901.         nextStep = state->steps[lastStep].next;
  902.     }
  903.     break;
  904.  
  905.       case DO_NEXT: default:
  906.         nextStep = state->steps[lastStep].next;
  907.     break;
  908.     }
  909.  
  910.     state->lastChoice = choice;
  911.  
  912.     return nextStep;
  913. }
  914.  
  915. void doSuspend(void) {
  916.     pid_t pid;
  917.     int status;
  918.  
  919.     if (testing) {
  920.     newtFinished();
  921.     exit(1);
  922.     }
  923.  
  924.     newtSuspend();
  925.     if (!(pid = fork())) {
  926.     printf("\n\nType <exit> to return to the install program.\n\n");
  927.     execl("/bin/sh", "-/bin/sh", NULL);
  928.     perror("error execing /bin/sh");
  929.     sleep(5);
  930.     exit(1);
  931.     }
  932.     waitpid(pid, &status, 0);
  933.     newtResume();
  934. }
  935.  
  936. static void setupSerialConsole(void) {
  937.     int first = 1;
  938.     struct stat sb;
  939.     char * argv[10] = { "/usr/sbin/setconsole", "--speed", NULL, NULL, NULL };
  940.     struct termios tos;
  941.     speed_t speed;
  942.  
  943.     if (!first) return;
  944.     first = 0;
  945.  
  946.     if (fstat(0, &sb)) {
  947.     logMessage("error stat'ing stdin: %s", strerror(errno));
  948.     return;
  949.     }
  950.  
  951.     if (!S_ISCHR(sb.st_mode)) {
  952.     logMessage("stdin isn't a character device!!! ack!");
  953.     return;
  954.     }
  955.  
  956.     if (major(sb.st_rdev) != 4) {
  957.     if (minor(sb.st_rdev) == 64)
  958.         argv[3] = "ttya";
  959.     else
  960.         argv[3] = "ttyb";
  961.  
  962.         tcgetattr(0, &tos);
  963.     speed = cfgetospeed(&tos);
  964.     switch (speed) {
  965.         case B38400:    argv[2] = "38400"; break;
  966.         case B19200:    argv[2] = "19200"; break;
  967.         default:        argv[2] = "9600";  break;
  968.     }
  969.  
  970.     if (access("/mnt/usr/sbin/setconsole", X_OK)) {
  971.         logMessage("/mnt/usr/sbin/setconsole does not exist -- skipping");
  972.         return;
  973.     }
  974.  
  975.     logMessage("setting up %s as serial console, speed is %s", argv[3], 
  976.             argv[2]);
  977.     runProgramRoot(RUN_LOG, "/mnt", "/usr/sbin/setconsole", argv);
  978.     }
  979. }
  980.  
  981. static int configurePrinter(struct installState * state) {
  982.     if (kickstart)
  983.     return 0;
  984.     else if (testing) {
  985.     return doConfigurePrinters("/");
  986.     } else if (!access("/mnt/usr/bin/lpr", X_OK)) {
  987.     return doConfigurePrinters("/mnt");
  988.     }
  989.  
  990.     return INST_NOP;
  991. }
  992.  
  993. int main(int argc, char ** argv) {
  994.     char ** argptr;
  995.     int step = STEP_FIRST;
  996.     int rc = 0;
  997.     struct installState state;
  998.     int i;
  999.     int isForce = 0;
  1000.     int len = strlen(argv[0]);
  1001.     char * spaces;
  1002.     int isRescue = 0;
  1003.     DIR * dir;
  1004.     struct dirent * ent;
  1005.     char * kickstartFile = NULL;
  1006.  
  1007.     spaces = strdup("                                                      ");
  1008.  
  1009.     if (!strcmp(argv[0] + len - 6, "umount")) {
  1010.     return umountCommand(argc, argv);
  1011.     } else if (!strcmp(argv[0] + len - 5, "mount")) {
  1012.     return mountCommand(argc, argv);
  1013.     } else if (!strcmp(argv[0] + len - 5, "mkdir")) {
  1014.     return mkdirCommand(argc, argv);
  1015.     } else if (!strcmp(argv[0] + len - 5, "mknod")) {
  1016.     return mknodCommand(argc, argv);
  1017.     } else if (!strcmp(argv[0] + len - 3, "cat")) {
  1018.     return catCommand(argc, argv);
  1019.     } else if (!strcmp(argv[0] + len - 2, "rm")) {
  1020.     return rmCommand(argc, argv);
  1021.     } else if (!strcmp(argv[0] + len - 5, "chmod")) {
  1022.     return chmodCommand(argc, argv);
  1023.     } else if (!strcmp(argv[0] + len - 5, "lsmod")) {
  1024.     return lsmodCommand(argc, argv);
  1025.     } else if (!strcmp(argv[0] + len - 6, "mkswap")) {
  1026.     return mkswapCommand(argc, argv);
  1027.     } else if (!strcmp(argv[0] + len - 6, "swapon")) {
  1028.     return swaponCommand(argc, argv);
  1029.     }
  1030.  
  1031.     /* if this fails, it's okay -- it might help with free space though */
  1032.     unlink("/sbin/install");
  1033.  
  1034.     newtSetSuspendCallback(doSuspend);
  1035.  
  1036.     memset(&state, 0, sizeof(state));
  1037.     state.steps = installSteps;            /* blind guess */
  1038.  
  1039.     argptr = argv + 1;
  1040.     while (*argptr) {
  1041.     if (!strcmp(*argptr, "--method")) {
  1042.         argptr++;
  1043.         if (!*argptr) {
  1044.         fprintf(stderr, "--method requires argument\n");
  1045.         exit(1);
  1046.         }
  1047.         state.method = findInstallMethod(*argptr);
  1048.         if (!state.method) {
  1049.         fprintf(stderr, "unknown install method: %s\n", *argptr);
  1050.         exit(1);
  1051.         }
  1052.     } else if (!strcmp(*argptr, "--force")) {
  1053.         isForce = 1;
  1054.     } else if (!strcmp(*argptr, "--kickstart") || 
  1055.            !strcmp(*argptr, "--ks")) {
  1056.         argptr++;
  1057.         if (!*argptr) 
  1058.         fprintf(stderr, "--kickstart requires argument\n");
  1059.         kickstartFile = *argptr;
  1060.     } else if (!strcmp(*argptr, "--rescue")) {
  1061.         isRescue = 1;
  1062.     } else if (!strcmp(*argptr, "--expert")) {
  1063.         expert = 1;
  1064.     } else if (!strcmp(*argptr, "--test")) {
  1065.         testing = 1;
  1066.     } else if (!strcmp(*argptr, "--pcmcia")) {
  1067.         argptr++;
  1068.         if (!*argptr) {
  1069.         fprintf(stderr, "--pcmcia requires argument\n");
  1070.         exit(1);
  1071.         }
  1072.         state.pcmcia = *argptr;
  1073.     } else if (!strcmp(*argptr, "--kernel")) {
  1074.         argptr++;
  1075.         if (!*argptr) {
  1076.         fprintf(stderr, "--kernel requires argument\n");
  1077.         exit(1);
  1078.         }
  1079.         state.kernel = *argptr;
  1080.     } else {
  1081.         /* skipping unknown arguments allows for future expansion */
  1082.         fprintf(stderr, "unknown argument: %s\n", *argptr);
  1083.     }
  1084.     argptr++;
  1085.     }
  1086.  
  1087.     if (!isRescue && !state.method) {
  1088.     fprintf(stderr, "--method argument is required\n");
  1089.     exit(1);
  1090.     }
  1091.  
  1092.     if (!testing && !isForce && (getpid() > 50)) {
  1093.     fprintf(stderr, "you're running me on a live system! that's ");
  1094.     fprintf(stderr, "incredibly stupid.\n");
  1095.     exit(1);
  1096.     }
  1097.  
  1098.     fprintf(stderr, "in second stage install\n");
  1099.     
  1100.     openLog();
  1101.  
  1102.     logMessage("second stage install running (version " VERSION " built "
  1103.         __DATE__ " " __TIME__ ")");
  1104.  
  1105.     logDebugMessage(("extra log messages are enabled"));
  1106.  
  1107.     spawnShell();
  1108.  
  1109.     newtInit();
  1110.     newtCls();
  1111.  
  1112.     newtDrawRootText(0, 0, "Red Hat Linux (C) 1997 Red Hat Software");
  1113.     newtPushHelpLine(NULL);
  1114.  
  1115.     if (isRescue) {
  1116.     do {
  1117.         rc = setupSCSIInterfaces(0, &state.dl);
  1118.     } while (rc);
  1119.  
  1120.     /* cut! we're out of here */
  1121.  
  1122.     newtFinished();
  1123.  
  1124.     execl("/bin/sh", "-/bin/sh", NULL);
  1125.     fprintf(stderr, "ack! I couldn't manage to execl() /bin/sh: %s",
  1126.             strerror(errno));
  1127.     while (1);
  1128.     }
  1129.  
  1130.     readNetConfig("/tmp", &state.netc);
  1131.  
  1132.     dir = opendir("/tmp");
  1133.     if (!dir) 
  1134.     logMessage("failed to open directory /tmp: %s", strerror(errno));
  1135.     else {
  1136.     errno = 0;
  1137.     while ((ent = readdir(dir))) {
  1138.         if (!strncmp("ifcfg-", ent->d_name, 6)) break;
  1139.     }
  1140.  
  1141.     if (!ent && errno) {
  1142.         logMessage("error reading directory entry: %s", strerror(errno));
  1143.     } else if (ent) {
  1144.         logMessage("found network config file %s", ent->d_name);
  1145.         readNetInterfaceConfig("/tmp", ent->d_name + 6, &state.intf);
  1146.     }
  1147.     }
  1148.     closedir(dir);
  1149.  
  1150.     readModuleConf("/tmp", &state.dl);
  1151.  
  1152.     /* make sure we don't pick up any gunk from the outside world */
  1153.     putenv("PATH=/usr/bin:/bin:/sbin:/usr/sbin");
  1154.     putenv("LD_LIBRARY_PATH=");
  1155.  
  1156.     if (kickstartFile) {
  1157.         if (ksReadCommands(kickstartFile)) 
  1158.         kickstartFile = NULL;
  1159.     else
  1160.         kickstart = 1;
  1161.  
  1162.     #ifndef __sparc__ 
  1163.     setupKeyboard(&state.keyboard);
  1164.     #endif
  1165.     } else {
  1166.     #ifndef __sparc__ 
  1167.     readKbdConfig("/tmp", &state.keyboard);
  1168.     #endif
  1169.     }
  1170.  
  1171.     while (step != STEP_DONE) {
  1172.     i = strlen(state.steps[step].name);
  1173.     newtDrawRootText(0, 0 - i, state.steps[step].name);
  1174.     newtRefresh();
  1175.     rc = state.steps[step].fn(&state);
  1176.     if (!rc)
  1177.         state.steps[step].completed = 1;
  1178.  
  1179.     spaces[i] = '\0';
  1180.     newtDrawRootText(0, 0 - i, spaces);
  1181.     spaces[i] = ' ';
  1182.  
  1183.     step = getNextStep(&state, step, rc);
  1184.     }
  1185.  
  1186.     if (kickstart)
  1187.     ksRunPost();
  1188.  
  1189.     newtDrawRootText(0, 72, "Complete");
  1190.     newtWinMessage("Done", "Ok", 
  1191.     "Congratulations, installation is complete.\n\n"
  1192.     "Remove the floppy from the drive and "
  1193.     "press return to reboot. For information on fixes which are "
  1194.     "available for this release of Red Hat Linux, consult the "
  1195.     "Errata available from http://www.redhat.com.\n\n"
  1196.     "Information on configuring your system is available in the post "
  1197.     "install chapter of the Official Red Hat Linux User's Guide.");
  1198.  
  1199.     umountFilesystems(&state.fstab);
  1200.  
  1201.     newtFinished();
  1202.  
  1203.     return 0;
  1204. }
  1205.