home *** CD-ROM | disk | FTP | other *** search
/ Chip 1998 February / CHIP_2_98.iso / misc / src / install / .#install2.c.1.79 < prev    next >
Text File  |  1997-11-04  |  31KB  |  1,203 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 (kickstart) {
  256.     if ((rc = getDriveList(&drives, &numDrives))) return rc;
  257.     return kickstartPartitioning(&state->table, &state->fstab, drives);
  258.     }
  259.  
  260.     do {
  261.     if ((rc = useNewFdisk(&useNew))) return rc;
  262.  
  263.     if (useNew) {
  264.         if ((rc = getDriveList(&drives, &numDrives))) return rc;
  265.         if ((rc = FSEditPartitions(&state->table, &state->fstab,
  266.                     drives, &state->intf,
  267.                        &state->netc, &state->dl))) return rc;
  268.     } else {
  269.         do {
  270.         if ((rc = partitionDrives())) return rc;
  271.         if ((rc = findAllPartitions(NULL, &state->table))) return rc;
  272.  
  273.         rc = setupMountTable(state->table, &state->fstab, &state->intf,
  274.                    &state->netc, &state->dl);
  275.         if (rc) return rc;
  276.         } while (rc);
  277.     }
  278.     } while (rc);
  279.  
  280.     return rc;
  281. }
  282.  
  283. static int findInstallFiles(struct installState * state) {
  284.     int rc;
  285.  
  286.     if (!state->table.parts) { 
  287.     rc = findAllPartitions(NULL, &state->table);
  288.     if (rc) return rc;
  289.     }
  290.  
  291.     if (state->method->prepareRoot) {
  292.     rc = state->method->prepareRoot(state->method, state->table,
  293.                     &state->netc, &state->intf,
  294.                     &state->dl);
  295.     if (rc) return rc;
  296.     }
  297.  
  298.     if ((rc = state->method->getPackageSet(state->method, &state->ps)))
  299.     return rc;
  300.     if ((state->method->getComponentSet(state->method, &state->ps, 
  301.      &state->cs)) )
  302.     return rc;
  303.  
  304.     return 0;
  305. }
  306.  
  307. static int formatPartitions(struct installState * state) {
  308.     int i;
  309.  
  310.     if (kickstart) {
  311.     for (i = 0; i < state->fstab.numEntries; i++) {
  312.         if (state->fstab.entries[i].type == PART_EXT2)
  313.         state->fstab.entries[i].doFormat = 1;
  314.     }
  315.  
  316.     return 0;
  317.     }
  318.  
  319.     return queryFormatFilesystems(&state->fstab);
  320. }
  321.  
  322. static int setupSwap(struct installState * state) {
  323.     return activeSwapSpace(&state->table, &state->fstab);
  324. }
  325.  
  326. static int choosePackages(struct installState * state) {
  327.     return psSelectPackages(&state->ps, &state->cs, 0, 0);
  328. }
  329.  
  330. static int doInstallStep(struct installState * state) {
  331.     int rc;
  332.     char * netSharedPath = NULL;
  333.     FILE * f;
  334.     int netSharedLength;
  335.     int i;
  336.  
  337.     if (!state->isUpgrade) {
  338.     if (!kickstart) {
  339.         rc = newtWinChoice("Install log", "Ok", "Cancel", "A complete log "
  340.             "of your installation will be in /tmp/install.log "
  341.             "after rebooting your system. You may want to keep "
  342.             "this file for later reference.");
  343.         if (rc == 1) return INST_CANCEL;
  344.     }
  345.  
  346.     rc = formatFilesystems(&state->fstab);
  347.     if (rc) return rc;
  348.  
  349.     rc = mountFilesystems(&state->fstab);
  350.     if (rc) return rc;
  351.  
  352.     if (state->method->prepareMedia) {
  353.         rc = state->method->prepareMedia(state->method, &state->fstab);
  354.         if (rc) {
  355.         umountFilesystems(&state->fstab);
  356.         return rc;
  357.         }
  358.     }
  359.     } else {
  360.     if (!kickstart) {
  361.         rc = newtWinChoice("Upgrade log", "Ok", "Cancel", "A complete log "
  362.             "of your upgrade will be in /tmp/upgrade.log when "
  363.             "the upgrade is finished. After rebooting, please "
  364.             "read it to ensure configuration files are properly "
  365.             "updated.");
  366.         if (rc == 1) return INST_CANCEL;
  367.     }
  368.     }
  369.  
  370.     /* FIXME: should this read the net shared path from /etc/rpmrc
  371.        during upgrades??? Probably. */
  372.     for (i = netSharedLength = 0; i < state->fstab.numEntries; i++) 
  373.     if (state->fstab.entries[i].type == PART_NFS)
  374.         netSharedLength += 1 + strlen(state->fstab.entries[i].mntpoint);
  375.  
  376.     if (netSharedLength) {
  377.     netSharedPath = alloca(netSharedLength);
  378.     *netSharedPath = '\0';
  379.     for (i = netSharedLength = 0; i < state->fstab.numEntries; i++) {
  380.         if (state->fstab.entries[i].type == PART_NFS) {
  381.         if (*netSharedPath) strcat(netSharedPath, ":");
  382.         strcat(netSharedPath, state->fstab.entries[i].mntpoint);
  383.         }
  384.         }
  385.  
  386.     logMessage("netSharedPath is: %s\n", netSharedPath);
  387.     }
  388.  
  389.     rc = doInstall(state->method, &state->ps, 
  390.            netSharedPath, state->keyboard, state->isUpgrade);
  391.  
  392.     if (netSharedPath && access("/mnt/etc/rpmrc", X_OK)) {
  393.     logMessage("creating /etc/rpmrc for netshared info (as none exists)");
  394.     f = fopen("/mnt/etc/rpmrc", "w");
  395.     if (!f) {
  396.         errorWindow("error creating /mnt/etc/rpmrc: %s");
  397.     } else {
  398.         fprintf(f, "netsharedpath: %s\n", netSharedPath);
  399.         fclose(f);
  400.     }
  401.     }
  402.  
  403.     sync();
  404.     sync();
  405.  
  406.     if (!rc) psFreeComponentSet(&state->cs);
  407.  
  408.     configPCMCIA(state->pcmcia);
  409.  
  410.     return rc;
  411. }
  412.  
  413.  
  414. static char mksalt(int seed) {
  415.     int num = seed % 64;
  416.  
  417.     if (num < 26)
  418.     return 'a' + num;
  419.     else if (num < 52)
  420.     return 'A' + (num - 26);
  421.     else if (num < 62)
  422.     return '0' + (num - 52);
  423.     else if (num == 63)
  424.     return '.';
  425.     else
  426.     return '/';
  427. }
  428.  
  429. static int setRootPassword(struct installState * state) {
  430.     newtComponent form = NULL, text, pw1Entry, pw2Entry;
  431.     char * pw1 = NULL, * pw2;
  432.     int done = 0;
  433.     char salt[3];
  434.     char cmd[200];
  435.     struct timeval time1, time2;
  436.     char * pw;
  437.     pid_t pid;
  438.     int status, rc;
  439.     char ** argv;
  440.     int argc;
  441.     poptContext optCon;
  442.     int skipCrypt = 0;
  443.     struct poptOption ksOptions[] = {
  444.         { "iscrypted", '\0', POPT_ARG_STRING, &skipCrypt, 0 },
  445.         { 0, 0, 0, 0, 0 }
  446.     };
  447.  
  448.     if (kickstart) {
  449.     if (!ksGetCommand(KS_CMD_ROOTPW, NULL, &argc, &argv)) {
  450.         optCon = poptGetContext(NULL, argc, argv, ksOptions, 0);
  451.  
  452.         if ((rc = poptGetNextOpt(optCon)) < -1) {
  453.         newtWinMessage("rootpw command",  "Ok",
  454.                "bad argument to kickstart rootpw command %s: %s",
  455.                poptBadOption(optCon, POPT_BADOPTION_NOALIAS), 
  456.                poptStrerror(rc));
  457.         }
  458.  
  459.         if (!(pw1 = poptGetArg(optCon))) {
  460.         newtWinMessage("rootpw command",  "Ok",
  461.                "Missing password");
  462.         skipCrypt = 0;
  463.         }
  464.  
  465.         if (poptGetArg(optCon))
  466.         newtWinMessage("rootpw command",  "Ok",
  467.                "Unexpected arguments");
  468.  
  469.         poptFreeContext(optCon);
  470.     }
  471.     }    
  472.  
  473.     if (!pw1) {
  474.     gettimeofday(&time1, NULL);
  475.  
  476.     newtCenteredWindow(50, 14, "Root Password");
  477.  
  478.     form = newtForm(NULL, NULL, 0);
  479.  
  480.     text = newtTextbox(1, 1, 47, 5, NEWT_TEXTBOX_WRAP);
  481.     newtTextboxSetText(text,
  482.         "Pick a root password. You must type it twice to ensure you know "
  483.         "what it is and didn't make a mistake in typing. Remember that the "
  484.         "root password is a critical part of system security!");
  485.  
  486.     newtFormAddComponent(form, newtLabel(3, 7, "Password        :"));
  487.     newtFormAddComponent(form, newtLabel(3, 8, "Password (again):"));
  488.  
  489.     pw1Entry = newtEntry(21, 7, "", 24, &pw1, NEWT_ENTRY_HIDDEN);
  490.     pw2Entry = newtEntry(21, 8, "", 24, &pw2, NEWT_ENTRY_HIDDEN);
  491.  
  492.     newtFormAddComponents(form, text, pw1Entry, pw2Entry, NULL);
  493.  
  494.     newtFormAddComponent(form, newtButton(20, 10, "Ok"));
  495.  
  496.     do {
  497.         newtFormSetCurrent(form, pw1Entry);
  498.         newtRunForm(form);
  499.         
  500.         if (testing) {
  501.         done = 1;
  502.         } else if (strcmp(pw1, pw2)) {
  503.         newtWinMessage("Password Mismatch", "Ok",
  504.                 "The passwords you entered were different. Please "
  505.                 "try again.");
  506.         newtEntrySet(pw1Entry, "", 0);
  507.         newtEntrySet(pw2Entry, "", 0);
  508.         } else if (strlen(pw1) < 6)  {
  509.         newtWinMessage("Password Mismatch", "Ok",
  510.                 "The root password must be at least 6 characters "
  511.                 "long.");
  512.         newtEntrySet(pw1Entry, "", 0);
  513.         newtEntrySet(pw2Entry, "", 0);
  514.         } else
  515.         done = 1;
  516.     } while (!done);
  517.  
  518.     newtPopWindow();
  519.     }
  520.  
  521.     if (testing) return 0;
  522.  
  523.     if (!skipCrypt) {
  524.     gettimeofday(&time2, NULL);
  525.  
  526.     salt[0] = mksalt(time1.tv_usec);
  527.     salt[1] = mksalt(time2.tv_usec);
  528.     salt[2] = '\0';
  529.  
  530.     pw = crypt(pw1, salt);
  531.     } else {
  532.     pw = pw1;
  533.     }
  534.  
  535.     sprintf(cmd, "/bin/sed 's&root::&root:%s:&' < /etc/passwd > "
  536.         "/etc/passwd.new", pw);
  537.  
  538.     if (!kickstart)
  539.     newtFormDestroy(form);
  540.  
  541.     if (!(pid = fork())) {
  542.     chroot("/mnt");
  543.     chdir("/mnt");
  544.  
  545.     exit(system(cmd));
  546.     }
  547.  
  548.     waitpid(pid, &status, 0);
  549.  
  550.     unlink("/mnt/etc/passwd");
  551.     rename("/mnt/etc/passwd.new", "/mnt/etc/passwd");
  552.  
  553.     return 0;
  554. }
  555.     
  556. static int configureTimezone(struct installState * state) {
  557.     return timeConfig();
  558. }
  559.  
  560. static int configureServices(struct installState * state) {
  561.     return servicesConfig();
  562. }
  563.  
  564. static int setupBootloader(struct installState * state) {
  565.     static int first = 1;
  566. #ifdef __alpha
  567.     int rc;
  568. #else
  569.     int rc;
  570.     int append = 0;
  571.     char * version;
  572.     int i;
  573. #endif
  574.  
  575.     if (!state->isUpgrade && first) {
  576.     writeFstab(&state->fstab);
  577.     setupSerialConsole();
  578.     }
  579.  
  580.     #ifdef __alpha__
  581.     if (first) {
  582.         first = 0;
  583.         rc = kernelCopy(state->kernel);
  584.         if (rc) return rc;
  585.     }
  586.  
  587.     return INST_NOP;
  588.     #else
  589.     first = 0;
  590.  
  591.     if (state->isUpgrade && !access("/mnt/etc/conf.modules", X_OK)) {
  592.         rc = readModuleConfPersist("/mnt/etc", state->dl);
  593.         if (rc) return rc;
  594.         append = 1;
  595.     }
  596.  
  597.     writeModuleConf("/mnt/etc", state->dl, 1);
  598.  
  599.     for (i = 0; i < state->ps.numPackages; i++) {
  600.         if (!strncmp(state->ps.packages[i]->name, "kernel", 6)) break;
  601.     }
  602.  
  603.     if (i == state->ps.numPackages) {
  604.         errorWindow("I couldn't find a kernel!");
  605.         return INST_ERROR;
  606.     } 
  607.  
  608.     headerGetEntry(state->ps.packages[i]->h, RPMTAG_VERSION, NULL, 
  609.                (void *) &version, NULL);
  610.  
  611.     logMessage("installed kernel version %s", version);
  612.  
  613.     /* installLilo installs silo on the SPARC */
  614.     return installLilo("/mnt/etc", state->table, state->fstab, version);
  615.     #endif
  616. }
  617.  
  618. static int finishNetworking(struct installState * state) {
  619.     int rc;
  620.  
  621.     rc = checkNetConfig(&state->intf, &state->netc, &state->dl);
  622.     if (rc) return rc;
  623.  
  624.     writeNetConfig("/mnt/etc/sysconfig", &state->netc, &state->intf, 0);
  625.     writeNetInterfaceConfig("/mnt/etc/sysconfig/network-scripts", &state->intf);
  626.     writeResolvConf("/mnt/etc", &state->netc);
  627.     writeHosts("/mnt/etc", &state->netc, &state->intf);
  628.  
  629.     return 0;
  630. }
  631.  
  632. static int selectPath(struct installState * state) {
  633.     int result;
  634.  
  635.     memset(state, 0, sizeof(state));
  636.  
  637.     if (kickstart) {
  638.     if (!ksGetCommand(KS_CMD_UPGRADE, NULL, NULL, NULL)) {
  639.         state->steps = upgradeSteps;
  640.         state->isUpgrade = 1;
  641.     } else {
  642.         state->steps = installSteps;
  643.     }
  644.  
  645.     return 0;
  646.     }
  647.  
  648.     result = newtWinChoice("Installation Path", "Install", "Upgrade",
  649.     "Would you like to install a new system or upgrade a system which "
  650.     "already contains Red Hat 2.0 or later?");
  651.    
  652.     if (result == 1) {
  653.     state->steps = upgradeSteps;
  654.     state->isUpgrade = 1;
  655.     } else
  656.     state->steps = installSteps;
  657.  
  658.     return 0;
  659. }
  660.  
  661. static int upgrFindInstall(struct installState * state) {
  662.     int rc;
  663.  
  664.     /* this also turns on swap for us */
  665.     rc = readMountTable(state->table, &state->fstab);
  666.     if (rc) return rc;
  667.  
  668.     if (!testing) {
  669.     mountFilesystems(&state->fstab);
  670.  
  671.     if (state->method->prepareMedia) {
  672.         rc = state->method->prepareMedia(state->method, &state->fstab);
  673.         if (rc) {
  674.         umountFilesystems(&state->fstab);
  675.         return rc;
  676.         }
  677.     }
  678.     }
  679.  
  680.     return 0;
  681. }
  682.  
  683. static int upgrChoosePackages(struct installState * state) {
  684.     int firstTime = 1;
  685.     char * upgradeList, * rpmconvertbin;
  686.     int rc;
  687.     char * path;
  688.     char * argv[] = { NULL, NULL };
  689.  
  690.     if (testing)
  691.     path = "/";
  692.     else
  693.     path = "/mnt";
  694.  
  695.     if (firstTime) {
  696.     if (access("/mnt/var/lib/rpm/packages.rpm", R_OK)) {
  697.         if (access("/mnt/var/lib/rpm/packages", R_OK)) {
  698.         errorWindow("No RPM database exists!");
  699.         return INST_ERROR;
  700.         }
  701.  
  702.         if (state->method->getFile(state->method, "rpmconvert", 
  703.             &rpmconvertbin, 1)) {
  704.         return INST_ERROR;
  705.         }
  706.     
  707.         symlink("/mnt/var", "/var");
  708.         winStatus(35, 3, "Upgrade", "Converting RPM database...");
  709.         chmod(rpmconvertbin, 0755);
  710.         argv[0] = rpmconvertbin;
  711.         rc = runProgram(RUN_LOG, rpmconvertbin, argv);
  712.         if (state->method->rmFiles)
  713.         unlink(rpmconvertbin);
  714.  
  715.         newtPopWindow();
  716.         if (rc) return INST_ERROR;
  717.     }
  718.     
  719.     winStatus(35, 3, "Upgrade", "Finding packages to upgrade...");
  720.     /* we shouldn't have to redo this as all of the headers are already
  721.        loaded XXX */
  722.     if (state->method->getFile(state->method, "hdlist", &upgradeList, 1))
  723.         return INST_ERROR;
  724.     rc = ugFindUpgradePackages(&state->ps, path, upgradeList);
  725.     if (state->method->rmFiles)
  726.         unlink(upgradeList);
  727.     newtPopWindow();
  728.     if (rc) return rc;
  729.     firstTime = 0;
  730.     psVerifyDependencies(&state->ps, 1);
  731.     }
  732.  
  733.     return psSelectPackages(&state->ps, &state->cs, 0, 1);
  734. }
  735.  
  736. #define DO_RETRY    1
  737. #define DO_NEXT        2
  738. #define DO_PREV        3
  739. #define DO_MENU        4
  740.  
  741. static int errcanChoices(char * name, int wasCancelled) {
  742.     newtComponent form, retry, previous, menu, text, exitb, answer;
  743.     char textBuf[1000];
  744.  
  745.     if (wasCancelled) {
  746.     sprintf(textBuf, "You cancelled step \"%s\".\n\n", name);
  747.     newtCenteredWindow(50, 16, "Cancelled");
  748.     } else {
  749.     sprintf(textBuf, "An error occured during step \"%s\" of the "
  750.         "install.\n\n", name);
  751.     newtCenteredWindow(50, 16, "Error");
  752.     }
  753.  
  754.     form = newtForm(NULL, NULL, 0);
  755.  
  756.     strcat(textBuf, "You may retry that step, return to the previous step "
  757.             "in the install, or see a menu of installation steps "
  758.             "which will allow you to move around in the install "
  759.             "more freely. It is not recommended to use the menu "
  760.             "unless you are already familiar with Red Hat Linux. "
  761.             "What would you like to do?");
  762.  
  763.     text = newtTextbox(1, 1, 48, 10, NEWT_TEXTBOX_WRAP);
  764.     newtTextboxSetText(text, textBuf);
  765.   
  766.     if (testing) {
  767.     previous = newtButton(1, 12, "Previous");
  768.     retry = newtButton(15, 12, "Retry");
  769.     menu = newtButton(28, 12, "Menu");
  770.     exitb = newtButton(39, 12, "Exit");
  771.     newtFormAddComponents(form, text, previous, retry, menu, exitb, NULL);
  772.     } else {
  773.     previous = newtButton(5, 12, "Previous");
  774.     retry = newtButton(20, 12, "Retry");
  775.     menu = newtButton(38, 12, "Menu");
  776.     newtFormAddComponents(form, text, previous, retry, menu, NULL);
  777.     }
  778.  
  779.     answer = newtRunForm(form);
  780.  
  781.     newtPopWindow();
  782.     newtFormDestroy(form);
  783.  
  784.     if (answer == previous)
  785.     return DO_PREV;
  786.     else if (answer == retry)
  787.     return DO_RETRY;
  788.     else if (answer == menu)
  789.     return DO_MENU;
  790.  
  791.     newtFinished();
  792.     exit(0); 
  793. }
  794.  
  795. static int stepMenu(struct installState * state, int currStep) {
  796.     newtComponent form, listbox, okay, text;
  797.     int firstStep = currStep;
  798.     long i;
  799.     int numChoices, listHeight;
  800.     char buf[200];
  801.  
  802.     newtCenteredWindow(50, 16, "Installation Steps");
  803.  
  804.     while (state->steps[firstStep].prev != -1)
  805.     firstStep = state->steps[firstStep].prev;
  806.  
  807.     form = newtForm(NULL, NULL, 0);
  808.  
  809.     i = firstStep, numChoices = 0;
  810.     do {
  811.     numChoices++;
  812.     i = state->steps[i].next;
  813.     } while (state->steps[i].prev != -1 && state->steps[i].next != STEP_DONE);
  814.     numChoices++;
  815.  
  816.     if (numChoices > 6)
  817.     listHeight = 6;
  818.     else
  819.     listHeight = 0;
  820.  
  821.     listbox = newtListbox(10, 4, listHeight, NEWT_LISTBOX_RETURNEXIT);
  822.  
  823.     text = newtTextbox(1, 1, 48, 3, NEWT_TEXTBOX_WRAP);
  824.     newtTextboxSetText(text, 
  825.         "What step would you like to run? Steps with a * next "
  826.         "to them have already been completed.");
  827.  
  828.     newtListboxAddEntry(listbox, "  Continue with install", 
  829.             (void *) STEP_DONE + 1);
  830.     for (i = firstStep; i < (firstStep + numChoices); i++) {
  831.     if (state->steps[i].completed)
  832.        strcpy(buf, "* ");
  833.     else
  834.        strcpy(buf, "  ");
  835.  
  836.     strcat(buf, state->steps[i].name);
  837.     newtListboxAddEntry(listbox, buf, (void *) i);
  838.     }
  839.  
  840.     okay = newtButton(23, 11, "Ok");
  841.     newtFormAddComponents(form, text, listbox, okay, NULL);
  842.  
  843.     newtRunForm(form);
  844.  
  845.     i = (long) newtListboxGetCurrent(listbox);
  846.  
  847.     newtFormDestroy(form);
  848.     newtPopWindow();
  849.  
  850.     if (i == STEP_DONE + 1)
  851.     return -1;
  852.  
  853.     return i;
  854. }
  855.  
  856. static int getNextStep(struct installState * state, int lastStep, int lastrc) {
  857.     int choice;
  858.     int nextStep;
  859.  
  860.     if (state->lastChoice == DO_MENU)
  861.     choice = DO_MENU;
  862.     else if (lastrc == INST_ERROR) {
  863.     choice = errcanChoices(state->steps[lastStep].name, 0);
  864.     kickstart = 0;
  865.     } else if (lastrc == INST_CANCEL) {
  866.     choice = errcanChoices(state->steps[lastStep].name, 1);
  867.     } else if (lastrc == INST_NOP) {
  868.     choice = state->lastChoice;
  869.     } else {
  870.     choice = DO_NEXT;
  871.     }
  872.  
  873.     switch (choice) {
  874.       case DO_PREV:
  875.     nextStep = state->steps[lastStep].prev;
  876.     while (nextStep != -1 && state->steps[nextStep].skipOnCancel && 
  877.            state->steps[nextStep].prev != -1)
  878.         nextStep = state->steps[nextStep].prev;
  879.  
  880.     if (nextStep == -1 || nextStep == lastStep) {
  881.         newtWinMessage("Cancelled", "Ok", "I can't go to the previous step"
  882.               " from here. You will have to try again.");
  883.         nextStep = lastStep;
  884.     }
  885.     break;
  886.  
  887.       case DO_RETRY:
  888.     nextStep = lastStep;
  889.     break;
  890.  
  891.       case DO_MENU:
  892.     nextStep = stepMenu(state, lastStep);
  893.     if (nextStep == -1) {
  894.         choice = DO_NEXT;
  895.  
  896.         if (lastrc)
  897.         nextStep = lastStep;
  898.         else
  899.         nextStep = state->steps[lastStep].next;
  900.     }
  901.     break;
  902.  
  903.       case DO_NEXT: default:
  904.         nextStep = state->steps[lastStep].next;
  905.     break;
  906.     }
  907.  
  908.     state->lastChoice = choice;
  909.  
  910.     return nextStep;
  911. }
  912.  
  913. void doSuspend(void) {
  914.     pid_t pid;
  915.     int status;
  916.  
  917.     if (testing) {
  918.     newtFinished();
  919.     exit(1);
  920.     }
  921.  
  922.     newtSuspend();
  923.     if (!(pid = fork())) {
  924.     printf("\n\nType <exit> to return to the install program.\n\n");
  925.     execl("/bin/sh", "-/bin/sh", NULL);
  926.     perror("error execing /bin/sh");
  927.     sleep(5);
  928.     exit(1);
  929.     }
  930.     waitpid(pid, &status, 0);
  931.     newtResume();
  932. }
  933.  
  934. static void setupSerialConsole(void) {
  935.     int first = 1;
  936.     struct stat sb;
  937.     char * argv[10] = { "/usr/sbin/setconsole", "--speed", NULL, NULL, NULL };
  938.     struct termios tos;
  939.     speed_t speed;
  940.  
  941.     if (!first) return;
  942.     first = 0;
  943.  
  944.     if (fstat(0, &sb)) {
  945.     logMessage("error stat'ing stdin: %s", strerror(errno));
  946.     return;
  947.     }
  948.  
  949.     if (!S_ISCHR(sb.st_mode)) {
  950.     logMessage("stdin isn't a character device!!! ack!");
  951.     return;
  952.     }
  953.  
  954.     if (major(sb.st_rdev) != 4) {
  955.     if (minor(sb.st_rdev) == 64)
  956.         argv[3] = "ttya";
  957.     else
  958.         argv[3] = "ttyb";
  959.  
  960.         tcgetattr(0, &tos);
  961.     speed = cfgetospeed(&tos);
  962.     switch (speed) {
  963.         case B38400:    argv[2] = "38400"; break;
  964.         case B19200:    argv[2] = "19200"; break;
  965.         default:        argv[2] = "9600";  break;
  966.     }
  967.  
  968.     if (access("/mnt/usr/sbin/setconsole", X_OK)) {
  969.         logMessage("/mnt/usr/sbin/setconsole does not exist -- skipping");
  970.         return;
  971.     }
  972.  
  973.     logMessage("setting up %s as serial console, speed is %s", argv[3], 
  974.             argv[2]);
  975.     runProgramRoot(RUN_LOG, "/mnt", "/usr/sbin/setconsole", argv);
  976.     }
  977. }
  978.  
  979. static int configurePrinter(struct installState * state) {
  980.     if (kickstart)
  981.     return 0;
  982.     else if (testing) {
  983.     return doConfigurePrinters("/");
  984.     } else if (!access("/mnt/usr/bin/lpr", X_OK)) {
  985.     return doConfigurePrinters("/mnt");
  986.     }
  987.  
  988.     return INST_NOP;
  989. }
  990.  
  991. int main(int argc, char ** argv) {
  992.     char ** argptr;
  993.     int step = STEP_FIRST;
  994.     int rc = 0;
  995.     struct installState state;
  996.     int i;
  997.     int isForce = 0;
  998.     int len = strlen(argv[0]);
  999.     char * spaces;
  1000.     int isRescue = 0;
  1001.     DIR * dir;
  1002.     struct dirent * ent;
  1003.     char * kickstartFile = NULL;
  1004.  
  1005.     spaces = strdup("                                                      ");
  1006.  
  1007.     if (!strcmp(argv[0] + len - 6, "umount")) {
  1008.     return umountCommand(argc, argv);
  1009.     } else if (!strcmp(argv[0] + len - 5, "mount")) {
  1010.     return mountCommand(argc, argv);
  1011.     } else if (!strcmp(argv[0] + len - 5, "mkdir")) {
  1012.     return mkdirCommand(argc, argv);
  1013.     } else if (!strcmp(argv[0] + len - 5, "mknod")) {
  1014.     return mknodCommand(argc, argv);
  1015.     } else if (!strcmp(argv[0] + len - 3, "cat")) {
  1016.     return catCommand(argc, argv);
  1017.     } else if (!strcmp(argv[0] + len - 2, "rm")) {
  1018.     return rmCommand(argc, argv);
  1019.     } else if (!strcmp(argv[0] + len - 5, "chmod")) {
  1020.     return chmodCommand(argc, argv);
  1021.     } else if (!strcmp(argv[0] + len - 5, "lsmod")) {
  1022.     return lsmodCommand(argc, argv);
  1023.     } else if (!strcmp(argv[0] + len - 6, "mkswap")) {
  1024.     return mkswapCommand(argc, argv);
  1025.     } else if (!strcmp(argv[0] + len - 6, "swapon")) {
  1026.     return swaponCommand(argc, argv);
  1027.     }
  1028.  
  1029.     /* if this fails, it's okay -- it might help with free space though */
  1030.     unlink("/sbin/install");
  1031.  
  1032.     newtSetSuspendCallback(doSuspend);
  1033.  
  1034.     memset(&state, 0, sizeof(state));
  1035.     state.steps = installSteps;            /* blind guess */
  1036.  
  1037.     argptr = argv + 1;
  1038.     while (*argptr) {
  1039.     if (!strcmp(*argptr, "--method")) {
  1040.         argptr++;
  1041.         if (!*argptr) {
  1042.         fprintf(stderr, "--method requires argument\n");
  1043.         exit(1);
  1044.         }
  1045.         state.method = findInstallMethod(*argptr);
  1046.         if (!state.method) {
  1047.         fprintf(stderr, "unknown install method: %s\n", *argptr);
  1048.         exit(1);
  1049.         }
  1050.     } else if (!strcmp(*argptr, "--force")) {
  1051.         isForce = 1;
  1052.     } else if (!strcmp(*argptr, "--kickstart") || 
  1053.            !strcmp(*argptr, "--ks")) {
  1054.         argptr++;
  1055.         if (!*argptr) 
  1056.         fprintf(stderr, "--kickstart requires argument\n");
  1057.         kickstartFile = *argptr;
  1058.     } else if (!strcmp(*argptr, "--rescue")) {
  1059.         isRescue = 1;
  1060.     } else if (!strcmp(*argptr, "--expert")) {
  1061.         expert = 1;
  1062.     } else if (!strcmp(*argptr, "--test")) {
  1063.         testing = 1;
  1064.     } else if (!strcmp(*argptr, "--pcmcia")) {
  1065.         argptr++;
  1066.         if (!*argptr) {
  1067.         fprintf(stderr, "--pcmcia requires argument\n");
  1068.         exit(1);
  1069.         }
  1070.         state.pcmcia = *argptr;
  1071.     } else if (!strcmp(*argptr, "--kernel")) {
  1072.         argptr++;
  1073.         if (!*argptr) {
  1074.         fprintf(stderr, "--kernel requires argument\n");
  1075.         exit(1);
  1076.         }
  1077.         state.kernel = *argptr;
  1078.     } else {
  1079.         /* skipping unknown arguments allows for future expansion */
  1080.         fprintf(stderr, "unknown argument: %s\n", *argptr);
  1081.     }
  1082.     argptr++;
  1083.     }
  1084.  
  1085.     if (!isRescue && !state.method) {
  1086.     fprintf(stderr, "--method argument is required\n");
  1087.     exit(1);
  1088.     }
  1089.  
  1090.     if (!testing && !isForce && (getpid() > 50)) {
  1091.     fprintf(stderr, "you're running me on a live system! that's ");
  1092.     fprintf(stderr, "incredibly stupid.\n");
  1093.     exit(1);
  1094.     }
  1095.  
  1096.     fprintf(stderr, "in second stage install\n");
  1097.     
  1098.     openLog();
  1099.  
  1100.     logMessage("second stage install running (version " VERSION " built "
  1101.         __DATE__ " " __TIME__ ")");
  1102.  
  1103.     logDebugMessage(("extra log messages are enabled"));
  1104.  
  1105.     spawnShell();
  1106.  
  1107.     newtInit();
  1108.     newtCls();
  1109.  
  1110.     newtDrawRootText(0, 0, "Red Hat Linux (C) 1997 Red Hat Software");
  1111.     newtPushHelpLine(NULL);
  1112.  
  1113.     if (isRescue) {
  1114.     do {
  1115.         rc = setupSCSIInterfaces(0, &state.dl);
  1116.     } while (rc);
  1117.  
  1118.     /* cut! we're out of here */
  1119.  
  1120.     newtFinished();
  1121.  
  1122.     execl("/bin/sh", "-/bin/sh", NULL);
  1123.     fprintf(stderr, "ack! I couldn't manage to execl() /bin/sh: %s",
  1124.             strerror(errno));
  1125.     while (1);
  1126.     }
  1127.  
  1128.     readNetConfig("/tmp", &state.netc);
  1129.  
  1130.     dir = opendir("/tmp");
  1131.     if (!dir) 
  1132.     logMessage("failed to open directory /tmp: %s", strerror(errno));
  1133.     else {
  1134.     errno = 0;
  1135.     while ((ent = readdir(dir))) {
  1136.         if (!strncmp("ifcfg-", ent->d_name, 6)) break;
  1137.     }
  1138.  
  1139.     if (!ent && errno) {
  1140.         logMessage("error reading directory entry: %s", strerror(errno));
  1141.     } else if (ent) {
  1142.         logMessage("found network config file %s", ent->d_name);
  1143.         readNetInterfaceConfig("/tmp", ent->d_name + 6, &state.intf);
  1144.     }
  1145.     }
  1146.     closedir(dir);
  1147.  
  1148.     readModuleConf("/tmp", &state.dl);
  1149.  
  1150.     /* make sure we don't pick up any gunk from the outside world */
  1151.     putenv("PATH=/usr/bin:/bin:/sbin:/usr/sbin");
  1152.     putenv("LD_LIBRARY_PATH=");
  1153.  
  1154.     if (kickstartFile) {
  1155.         if (ksReadCommands(kickstartFile)) 
  1156.         kickstartFile = NULL;
  1157.     else
  1158.         kickstart = 1;
  1159.  
  1160.     #ifndef __sparc__ 
  1161.     setupKeyboard(&state.keyboard);
  1162.     #endif
  1163.     } else {
  1164.     #ifndef __sparc__ 
  1165.     readKbdConfig("/tmp", &state.keyboard);
  1166.     #endif
  1167.     }
  1168.  
  1169.     while (step != STEP_DONE) {
  1170.     i = strlen(state.steps[step].name);
  1171.     newtDrawRootText(0, 0 - i, state.steps[step].name);
  1172.     newtRefresh();
  1173.     rc = state.steps[step].fn(&state);
  1174.     if (!rc)
  1175.         state.steps[step].completed = 1;
  1176.  
  1177.     spaces[i] = '\0';
  1178.     newtDrawRootText(0, 0 - i, spaces);
  1179.     spaces[i] = ' ';
  1180.  
  1181.     step = getNextStep(&state, step, rc);
  1182.     }
  1183.  
  1184.     if (kickstart)
  1185.     ksRunPost();
  1186.  
  1187.     newtDrawRootText(0, 72, "Complete");
  1188.     newtWinMessage("Done", "Ok", 
  1189.     "Congratulations, installation is complete.\n\n"
  1190.     "Remove the floppy from the drive and "
  1191.     "press return to reboot. For information on fixes which are "
  1192.     "available for this release of Red Hat Linux, consult the "
  1193.     "Errata available from http://www.redhat.com.\n\n"
  1194.     "Information on configuring your system is available in the post "
  1195.     "install chapter of the Official Red Hat Linux User's Guide.");
  1196.  
  1197.     umountFilesystems(&state.fstab);
  1198.  
  1199.     newtFinished();
  1200.  
  1201.     return 0;
  1202. }
  1203.