home *** CD-ROM | disk | FTP | other *** search
/ PC Plus SuperCD (UK) 1999 May / pcp151c.iso / misc / src / install / install2.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-10-13  |  40.0 KB  |  1,505 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 1998 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 <rpm/rpmlib.h>
  37. #include <stdlib.h>
  38. #include <string.h>
  39. #include <sys/ioctl.h>
  40. #include <sys/stat.h>
  41. #include <sys/sysmacros.h>
  42. #include <sys/time.h>
  43. #include <sys/wait.h>
  44. #include <termios.h>
  45. #include <unistd.h>
  46.  
  47. #include "commands.h"
  48. #include "config.h"
  49. #include "devices.h"
  50. #include "doit.h"
  51. #include "fs.h"
  52. #include "fsedit.h"
  53. #include "hd.h"
  54. #include "otherinsmod.h"
  55. #include "install.h"
  56. #include "intl.h"
  57. #include "hints.h"
  58. #include "kbd.h"
  59. #include "kernel.h"
  60. #include "kickstart.h"
  61. #include "lang.h"
  62. #include "libfdisk/libfdisk.h"
  63. #include "lilo.h"
  64. #include "log.h"
  65. #include "methods.h"
  66. #include "mkswap.h"
  67. #include "net.h"
  68. #include "pkgs.h"
  69. #include "printercfg.h"
  70. #include "run.h"
  71. #include "scsi.h"
  72. #include "upgrade.h"
  73. #include "windows.h"
  74.  
  75. int testing = 0;
  76. int expert = 0;
  77. int kickstart = 0;
  78. static int exitOnSuspend;
  79.  
  80. #define STEP_FIRST    0
  81.  
  82. #define STEP_PATH        0
  83. #define STEP_CLASS        1
  84. #define STEP_SCSI        2
  85. #define STEP_FDISKMTAB        3
  86. #define STEP_SWAP        4
  87. #define STEP_FINDPKGS         5
  88. #define STEP_FORMAT         6
  89. #define STEP_PICKPKGS         7
  90. #define STEP_DOIT        8
  91. #define STEP_FINISHNET        9
  92. #define STEP_TIMECONFIG        10
  93. #define STEP_SERVICES        11
  94. #define STEP_PRINTER        12
  95. #define STEP_ROOTPW        13
  96. #define STEP_BOOTDISK        14
  97. #define STEP_LILO        15
  98.  
  99. #define STEP_UPG_SCSI        1
  100. #define STEP_UPG_PKGS        2
  101. #define STEP_UPG_MTAB        3
  102. #define STEP_UPG_FFILES        4
  103. #define STEP_UPG_DOIT        5
  104. #define STEP_UPG_BOOTDISK    6
  105. #define STEP_UPG_LILO        7
  106.  
  107. #define STEP_DONE    1000
  108.  
  109. struct installState {
  110.     int isUpgrade, lastChoice, direction, isLocal;
  111.     char * pcmcia, * kernel, * keyboard;
  112.     struct partitionTable table;
  113.     struct fstab fstab;
  114.     struct pkgSet ps;
  115.     struct componentSet cs;
  116.     struct installMethod * method;
  117.     struct intfInfo intf, intfFinal;
  118.     struct netInfo netc, netcFinal;
  119.     struct driversLoaded * dl;
  120.     struct installStep * steps;
  121.     char * rootPath;
  122.     struct hints hints;
  123. } ;
  124.  
  125. typedef int (*installStepFn)(struct installState * state);
  126.  
  127. /* hack */
  128. int rmmod_main(int argc, char ** argv);
  129.  
  130. static int setupSCSI(struct installState * state);
  131. static int selectInstallClass(struct installState * state);
  132. static int partitionDisks(struct installState * state);
  133. static int setupSwap(struct installState * state);
  134. static int findInstallFiles(struct installState * state);
  135. static int formatPartitions(struct installState * state);
  136. static int choosePackages(struct installState * state);
  137. static int doInstallStep(struct installState * state);
  138. static int setRootPassword(struct installState * state);
  139. static int createBootdisk(struct installState * state);
  140. static int configureTimezone(struct installState * state);
  141. static int configureServices(struct installState * state);
  142. static int configurePrinter(struct installState * state);
  143. static int setupBootloader(struct installState * state);
  144. static int finishNetworking(struct installState * state);
  145. static int selectPath(struct installState * state);
  146. static int upgrChoosePackages(struct installState * state);
  147. static int upgrFindInstall(struct installState * state);
  148. static void setupSerialConsole(void);
  149.  
  150. struct installStep {
  151.     char * name;
  152.     int prev, next;
  153.     installStepFn fn;
  154.     int skipOnCancel, completed;
  155.     int skipOnLocal;
  156. };
  157.  
  158. /* this table is translated at run time */
  159. static struct installStep installSteps[] = { 
  160.     { N_("Select installation path"),    -1,        STEP_CLASS,
  161.     selectPath, 0, 0, 0 },
  162.     { N_("Select installation class"),    STEP_PATH,    STEP_SCSI,
  163.     selectInstallClass, 0, 0, 0 },
  164.     { N_("Setup SCSI"),         STEP_CLASS,     STEP_FDISKMTAB,
  165.     setupSCSI, 0, 0, 1 },    
  166.     { N_("Setup filesystems"),         STEP_SCSI,     STEP_SWAP,
  167.     partitionDisks, 0, 0, 1 },
  168.     { N_("Setup swap space"),         STEP_FDISKMTAB, STEP_FINDPKGS,
  169.     setupSwap, 0, 0, 1 },
  170.     { N_("Find installation files"),    STEP_SWAP,    STEP_FORMAT,
  171.     findInstallFiles, 1, 0, 0 },
  172.     { N_("Choose partitions to format"),STEP_SWAP,    STEP_PICKPKGS,
  173.     formatPartitions, 0, 0, 1 },
  174.     { N_("Choose packages to install"),    STEP_FORMAT,    STEP_DOIT,
  175.     choosePackages, 0, 0, 0 },
  176.     { N_("Install system"),        STEP_PICKPKGS,    STEP_FINISHNET,
  177.     doInstallStep, 0, 0, 0 },
  178.     { N_("Configure networking"),    -1,        STEP_TIMECONFIG,
  179.     finishNetworking, 0, 0, 0 },
  180.     { N_("Configure timezone"),        STEP_FINISHNET,    STEP_SERVICES,
  181.     configureTimezone, 0, 0, 0 },
  182.     { N_("Configure services"),        STEP_TIMECONFIG,STEP_PRINTER,
  183.     configureServices, 0, 0, 0 },
  184.     { N_("Configure printer"),        STEP_SERVICES,    STEP_ROOTPW,
  185.     configurePrinter, 0, 0, 0 },
  186.     { N_("Set root password"),        STEP_PRINTER,    STEP_BOOTDISK,
  187.     setRootPassword, 0, 0, 0 },
  188.     { N_("Create bootdisk"),        STEP_ROOTPW,    STEP_LILO,
  189.     createBootdisk, 0, 0, 1 },
  190.     { N_("Install bootloader"),        STEP_BOOTDISK,    STEP_DONE,
  191.     setupBootloader, 0, 0, 1 },
  192. };
  193.  
  194. /* this table is translated at run time */
  195. struct installStep upgradeSteps[] = { 
  196.     { N_("Select installation path"),    -1,        STEP_UPG_SCSI,
  197.     selectPath, 0, 0, 0 },
  198.     { N_("Setup SCSI"),         STEP_PATH,     STEP_UPG_PKGS,
  199.     setupSCSI, 0, 0, 0 },
  200.     { N_("Find installation files"),    STEP_PATH,    STEP_UPG_MTAB,
  201.     findInstallFiles, 1, 0, 0 },
  202.     { N_("Find current installation"),    STEP_UPG_PKGS,    STEP_UPG_FFILES,
  203.     upgrFindInstall, 0, 0, 0 },
  204.     { N_("Choose packages to upgrade"),    STEP_UPG_FFILES,STEP_UPG_DOIT,
  205.     upgrChoosePackages, 0, 0, 0 },
  206.     { N_("Upgrade system"),        STEP_UPG_FFILES,STEP_UPG_BOOTDISK,
  207.     doInstallStep, 0, 0, 0 },
  208.     { N_("Create bootdisk"),        -1,        STEP_UPG_LILO,
  209.     createBootdisk, 0, 0, 0 },
  210.     { N_("Install bootloader"),        STEP_UPG_BOOTDISK,    STEP_DONE,
  211.     setupBootloader, 0, 0, 0 },
  212. };
  213.  
  214. /* partition layout for a server */
  215. static struct attemptedPartition serverPartitioning[] = {
  216. #if defined(__i386__)
  217.     { "/boot",    16,    LINUX_NATIVE_PARTITION,    0, -1 },
  218. #elif defined(__alpha__)
  219.     { "/dos",    2,    DOS_PRIMARY_lt32MEG_PARTITION,    0, 1 },
  220. #endif
  221.     { "/",        256,    LINUX_NATIVE_PARTITION,    0, -1 },
  222.     { "/usr",    512,    LINUX_NATIVE_PARTITION,    1, -1 },
  223.     { "/var",    256,    LINUX_NATIVE_PARTITION,    0, -1 },
  224.     { "/home",    512,    LINUX_NATIVE_PARTITION,    1, -1 },
  225.     { "Swap-auto",    64,    LINUX_SWAP_PARTITION,    0, -1 },
  226.     { NULL, 0, 0, 0 } 
  227. };
  228.  
  229. void spawnShell(void) {
  230.     pid_t pid;
  231.     int fd;
  232.  
  233.     if (!testing) {
  234.     fd = open("/dev/tty2", O_RDWR);
  235.     if (fd < 0) {
  236.         logMessage("cannot open /dev/tty2 -- no shell will be provided");
  237.         return;
  238.     } else if (access("/bin/sh",  X_OK))  {
  239.         logMessage("cannot open shell - /usr/bin/sh doesn't exist");
  240.         return;
  241.     }
  242.  
  243.     if (!(pid = fork())) {
  244.         dup2(fd, 0);
  245.         dup2(fd, 1);
  246.         dup2(fd, 2);
  247.  
  248.         close(fd);
  249.         setsid();
  250.         if (ioctl(0, TIOCSCTTY, NULL)) {
  251.            perror("could not set new controlling tty");
  252.         }
  253.  
  254.         execl("/bin/sh", "-/bin/sh", NULL);
  255.         logMessage("exec of /bin/sh failed: %s", strerror(errno));
  256.     }
  257.  
  258.     close(fd);
  259.     }
  260. }
  261.  
  262. static int setupSCSI(struct installState * state) {
  263.     struct driversLoaded * drivers;
  264.  
  265.     if (state->direction < 0 && scsiDeviceAvailable())
  266.     return INST_CANCEL;
  267.  
  268.     /* If we have any scsi adapters configured from earlier, then
  269.        don't bother asking again */
  270.     drivers = state->dl;
  271.     while (drivers && drivers->type != DRIVER_SCSI) 
  272.     drivers = drivers->next;
  273.     if (drivers) return INST_OKAY;
  274.  
  275.     return setupSCSIInterfaces(0, &state->dl, 
  276.             state->hints.flags & HINT_AUTOSCSI, state->direction);
  277. }
  278.  
  279. static int useNewFdisk(int * useNew) {
  280.     int rc;
  281.  
  282.     rc = newtWinTernary(_("Disk Setup"), _("Disk Druid"), _("fdisk"), 
  283.             _("Back"),
  284.         _("Disk Druid is a tool for partitioning and setting up mount "
  285.           "points. It is designed to be easier to use than Linux's "
  286.           "traditional disk partitioning sofware, fdisk, as well "
  287.           "as more powerful. However, there are some cases where fdisk "
  288.           "may be preferred.\n\n"
  289.           "Which tool would you like to use?"));
  290.  
  291.     if (rc == 3)
  292.     return INST_CANCEL;
  293.  
  294.     if (rc == 0 || rc == 1)
  295.     *useNew = 1;
  296.     else
  297.     *useNew = 0;
  298.  
  299.     return 0;
  300. }
  301.  
  302. #define PART_METHOD    0
  303. #define PART_DDRUID    1
  304. #define PART_FDISK    2
  305. #define PART_FSTAB    3
  306. #define PART_DONE    10
  307.  
  308. static int partitionDisks(struct installState * state) {
  309.     int rc = 0;
  310.     char ** drives;
  311.     static int useNew;
  312.     int numDrives;
  313.     int stage;
  314.     int dir;
  315.     
  316.     if (state->isUpgrade) 
  317.     return findAllPartitions(NULL, &state->table);
  318.  
  319.     if (kickstart) {
  320.     if ((rc = getDriveList(&drives, &numDrives))) return rc;
  321.     return kickstartPartitioning(&state->table, &state->fstab, drives);
  322.     }
  323.  
  324.     if (state->direction > 0) 
  325.     stage = PART_METHOD;
  326.     else 
  327.     stage = PART_DDRUID;
  328.  
  329.     while (stage != 10) {
  330.     switch (stage) {
  331.       case PART_METHOD:
  332.         if (state->hints.flags & HINT_FORCEDDRUID) {
  333.         if (dir < 0) return INST_CANCEL;
  334.         useNew = 1;
  335.         } else {
  336.         if ((rc = useNewFdisk(&useNew))) return rc;
  337.         }
  338.         stage = useNew ? PART_DDRUID : PART_FDISK;
  339.         dir = 1;
  340.         break;
  341.  
  342.       case PART_DDRUID:
  343.         if ((rc = getDriveList(&drives, &numDrives))) return rc;
  344.         rc = FSEditPartitions(&state->table, &state->fstab, drives, 
  345.                   &state->intf, &state->netc, &state->dl, 
  346.                   state->hints.partitioning.attempts,
  347.                   (useNew ? 0 : FSEDIT_READONLY) |
  348.                     state->hints.partitioning.flags);
  349.         if (rc == INST_ERROR) return rc;
  350.         stage = PART_DONE, dir = 1;
  351.         if (rc && useNew) 
  352.         stage = PART_METHOD, dir = -1;
  353.         else if (rc)
  354.         stage = PART_FDISK;
  355.         break;
  356.  
  357.       case PART_FDISK:
  358.         if ((rc = partitionDrives()) == INST_ERROR) return rc;
  359.         stage = PART_DDRUID, dir = 1;
  360.         if (rc) stage = PART_METHOD, dir = -1;
  361.         break;
  362.     }
  363.     } 
  364.  
  365.     return 0;
  366. }
  367.  
  368. static int findInstallFiles(struct installState * state) {
  369.     int rc;
  370.     char * trFile;
  371.  
  372.     if (!state->table.parts) { 
  373.     rc = findAllPartitions(NULL, &state->table);
  374.     if (rc) return rc;
  375.     }
  376.  
  377.     if (state->method->prepareRoot) {
  378.     rc = state->method->prepareRoot(state->method, state->table,
  379.                     &state->netc, &state->intf,
  380.                     &state->dl);
  381.     if (rc) return rc;
  382.     }
  383.  
  384.     /* We can now load the third bit of the install. FIXME: This leaks
  385.        memory if we keep redoing it. I suspect much of this code does
  386.        though! */
  387.     if (state->method->getFile(state->method, "install3.tr", &trFile)) {
  388.     logMessage("getFile method failed for %s", "install3.tr");
  389.     } else {
  390.     loadLanguageStage(3, trFile);
  391.     if (state->method->rmFiles) unlink(trFile);
  392.     }
  393.  
  394.     /* XXX Hack as we did this after freezing the translations */
  395.     if (!getenv("LANG"))
  396.     winStatus(25, 3, "Scanning", _("Scanning packages..."));
  397.  
  398.     rc = state->method->getPackageSet(state->method, &state->ps);
  399.     if (!rc)
  400.     rc = state->method->getComponentSet(state->method, &state->ps, 
  401.                         &state->cs);
  402.  
  403.     if (!getenv("LANG"))
  404.     newtPopWindow();
  405.  
  406.     return rc;
  407. }
  408.  
  409. static int formatPartitions(struct installState * state) {
  410.     int i;
  411.  
  412.     if (state->hints.flags & HINT_AUTOFORMAT) {
  413.     if (state->direction < 0) return INST_CANCEL;
  414.  
  415.     for (i = 0; i < state->fstab.numEntries; i++) {
  416.         if (state->fstab.entries[i].type == PART_EXT2)
  417.         state->fstab.entries[i].doFormat = 1;
  418.     }
  419.  
  420.     return 0;
  421.     }
  422.  
  423.     return queryFormatFilesystems(&state->fstab);
  424. }
  425.  
  426. static int setupSwap(struct installState * state) {
  427.     if ((state->hints.flags & HINT_AUTOSWAP) && state->direction < 0)
  428.     return INST_CANCEL;
  429.  
  430.     return activeSwapSpace(&state->table, &state->fstab, 
  431.                state->hints.flags & HINT_AUTOSWAP);
  432. }
  433.  
  434. static int choosePackages(struct installState * state) {
  435.     if (state->hints.component && (state->direction < 0)) return INST_CANCEL;
  436.     return psSelectPackages(&state->ps, &state->cs, state->hints.component, 
  437.                 0, 0);
  438. }
  439.  
  440. static void emptyErrorCallback(void) {
  441. }
  442.  
  443. static int doInstallStep(struct installState * state) {
  444.     int rc;
  445.     char * netSharedPath = NULL;
  446.     FILE * f;
  447.     int netSharedLength;
  448.     int i;
  449.     char * path;
  450.     rpmErrorCallBackType old;
  451.  
  452.     if (!state->isUpgrade) {
  453.     if (!(state->hints.flags & HINT_NOLOGMESSAGE) && !expert) {
  454.         rc = newtWinChoice(_("Install log"), _("Ok"), _("Back"), 
  455.             _("A complete log of your installation will be in "
  456.               "/tmp/install.log after rebooting your system. You "
  457.               "may want to keep this file for later reference."));
  458.         if (rc == 2) return INST_CANCEL;
  459.     }
  460.  
  461.     rc = formatFilesystems(&state->fstab);
  462.     if (rc) return rc;
  463.  
  464.     rc = mountFilesystems(&state->fstab);
  465.     if (rc) return rc;
  466.  
  467.     if (state->method->prepareMedia) {
  468.         rc = state->method->prepareMedia(state->method, &state->fstab);
  469.         if (rc) {
  470.         umountFilesystems(&state->fstab);
  471.         return rc;
  472.         }
  473.     }
  474.     } else {
  475.     do {
  476.         if (!(state->hints.flags & HINT_NOLOGMESSAGE) && !expert) {
  477.         rc = newtWinChoice(_("Upgrade log"), _("Ok"), _("Back"), 
  478.                 _("A complete log of your upgrade will be in "
  479.                   "/tmp/upgrade.log when the upgrade is finished. "
  480.                   "After rebooting, please read it to ensure "
  481.                   "configuration files are properly updated."));
  482.         if (rc == 2) return INST_CANCEL;
  483.         }
  484.  
  485.         winStatus(40, 3, _("Rebuilding"), _("Rebuilding RPM database..."));
  486.         rc = 0;
  487.         if (!testing) {
  488.             old = rpmErrorSetCallback(emptyErrorCallback);
  489.         rpmSetVerbosity(RPMMESS_QUIET);
  490.         rc = rpmdbRebuild("/mnt");
  491.         rpmErrorSetCallback(old);
  492.         rpmSetVerbosity(RPMMESS_NORMAL);
  493.         newtPopWindow();
  494.         if (rc) {
  495.             newtWinMessage(_("Error"), _("Ok"), _("Rebuild of RPM "
  496.                 "database failed. You may be out of disk space?"));
  497.             continue;
  498.         }
  499.         }
  500.     } while (rc);
  501.     }
  502.  
  503.     /* FIXME: should this read the net shared path from /etc/rpmrc
  504.        during upgrades??? Probably. */
  505.     for (i = netSharedLength = 0; i < state->fstab.numEntries; i++) 
  506.     if (state->fstab.entries[i].type == PART_NFS)
  507.         netSharedLength += 1 + strlen(state->fstab.entries[i].mntpoint);
  508.  
  509.     if (netSharedLength) {
  510.     netSharedPath = alloca(netSharedLength);
  511.     *netSharedPath = '\0';
  512.     for (i = netSharedLength = 0; i < state->fstab.numEntries; i++) {
  513.         if (state->fstab.entries[i].type == PART_NFS) {
  514.         if (*netSharedPath) strcat(netSharedPath, ":");
  515.         strcat(netSharedPath, state->fstab.entries[i].mntpoint);
  516.         }
  517.         }
  518.  
  519.     logMessage("netSharedPath is: %s\n", netSharedPath);
  520.     }
  521.  
  522.     rc = doInstall(state->method, state->rootPath, &state->ps, 
  523.            netSharedPath, state->keyboard, state->isUpgrade);
  524.  
  525.     path = alloca(strlen(state->rootPath) + 200);
  526.     sprintf(path, "%s/etc/rpmrc", state->rootPath);
  527.     if (netSharedPath && access(path, X_OK)) {
  528.     logMessage("creating /etc/rpmrc for netshared info (as none exists)");
  529.     f = fopen(path, "w");
  530.     if (!f) {
  531.         newtWinMessage(_("Error"), _("Ok"),
  532.                "error creating path: %s", path, strerror(errno));
  533.     } else {
  534.         fprintf(f, "netsharedpath: %s\n", netSharedPath);
  535.         fclose(f);
  536.     }
  537.     }
  538.  
  539.     sync();
  540.     sync();
  541.  
  542.     if (!rc) psFreeComponentSet(&state->cs);
  543.  
  544.     configPCMCIA(state->rootPath, state->pcmcia);
  545.  
  546.     return rc;
  547. }
  548.  
  549.  
  550. static char mksalt(int seed) {
  551.     int num = seed % 64;
  552.  
  553.     if (num < 26)
  554.     return 'a' + num;
  555.     else if (num < 52)
  556.     return 'A' + (num - 26);
  557.     else if (num < 62)
  558.     return '0' + (num - 52);
  559.     else if (num == 63)
  560.     return '.';
  561.     else
  562.     return '/';
  563. }
  564.  
  565. static int setRootPassword(struct installState * state) {
  566.     newtComponent form = NULL, text, pw1Entry, pw2Entry, okay, cancel, answer;
  567.     char * pw1 = NULL, * pw2;
  568.     int done = 0;
  569.     char salt[3];
  570.     char cmd[200];
  571.     struct timeval time1, time2;
  572.     char * pw;
  573.     pid_t pid;
  574.     int status, rc;
  575.     static int beenSet = 0;
  576.     char ** argv;
  577.     int argc;
  578.     poptContext optCon;
  579.     int skipCrypt = 0;
  580.     char * reflowedText;
  581.     char * path, * newpath;
  582.     int height, width;
  583.     newtGrid grid, subgrid, buttons;
  584.     struct poptOption ksOptions[] = {
  585.         { "iscrypted", '\0', POPT_ARG_NONE, &skipCrypt, 0 },
  586.         { 0, 0, 0, 0, 0 }
  587.     };
  588.  
  589.     if (kickstart) {
  590.     if (!ksGetCommand(KS_CMD_ROOTPW, NULL, &argc, &argv)) {
  591.         optCon = poptGetContext(NULL, argc, argv, ksOptions, 0);
  592.  
  593.         if ((rc = poptGetNextOpt(optCon)) < -1) {
  594.         newtWinMessage(_("rootpw command"),  _("Ok"),
  595.                _("bad argument to kickstart rootpw command %s: %s"),
  596.                poptBadOption(optCon, POPT_BADOPTION_NOALIAS), 
  597.                poptStrerror(rc));
  598.         }
  599.  
  600.         if (!(pw1 = poptGetArg(optCon))) {
  601.         newtWinMessage(_("rootpw command"),  _("Ok"),
  602.                _("Missing password"));
  603.         skipCrypt = 0;
  604.         }
  605.  
  606.         if (poptGetArg(optCon))
  607.         newtWinMessage(_("rootpw command"),  _("Ok"),
  608.                _("Unexpected arguments"));
  609.  
  610.         poptFreeContext(optCon);
  611.     }
  612.     }    
  613.  
  614.     if (!pw1) {
  615.     gettimeofday(&time1, NULL);
  616.  
  617.     subgrid = newtCreateGrid(2, 2);
  618.     newtGridSetField(subgrid, 0, 0, NEWT_GRID_COMPONENT,
  619.              newtLabel(-1, -1, _("Password:")),
  620.              0, 0, 1, 0, NEWT_ANCHOR_LEFT, 0);
  621.     newtGridSetField(subgrid, 0, 1, NEWT_GRID_COMPONENT,
  622.              newtLabel(-1, -1, _("Password (again):")),
  623.              0, 0, 1, 0, NEWT_ANCHOR_LEFT, 0);
  624.  
  625.     pw1Entry = newtEntry(-1, -1, "", 24, &pw1, NEWT_ENTRY_HIDDEN);
  626.     pw2Entry = newtEntry(-1, -1, "", 24, &pw2, NEWT_ENTRY_HIDDEN);
  627.  
  628.     newtGridSetField(subgrid, 1, 0, NEWT_GRID_COMPONENT, pw1Entry,
  629.              0, 0, 0, 0, 0, 0);
  630.     newtGridSetField(subgrid, 1, 1, NEWT_GRID_COMPONENT, pw2Entry,
  631.              0, 0, 0, 0, 0, 0);
  632.             
  633.       reflowedText = newtReflowText(
  634.       _("Pick a root password. You must type it twice to ensure you know "
  635.         "what it is and didn't make a mistake in typing. Remember that the "
  636.         "root password is a critical part of system security!"), 37,
  637.         5, 5, &width, &height);
  638.  
  639.     text = newtTextbox(1, 1, width, height, NEWT_TEXTBOX_WRAP);
  640.     newtTextboxSetText(text, reflowedText);
  641.     free(reflowedText);
  642.     buttons = newtButtonBar(_("Ok"), &okay, _("Back"), &cancel, NULL);
  643.  
  644.     grid = newtGridBasicWindow(text, subgrid, buttons);
  645.  
  646.     form = newtForm(NULL, NULL, 0);
  647.  
  648.     newtGridAddComponentsToForm(grid, form, 1);
  649.     newtGridWrappedWindow(grid, _("Root Password"));
  650.     newtGridFree(grid, 1);
  651.  
  652.     do {
  653.         newtFormSetCurrent(form, pw1Entry);
  654.         answer = newtRunForm(form);
  655.  
  656.         if (answer == cancel) {
  657.         newtPopWindow();
  658.         newtFormDestroy(form);
  659.         return INST_CANCEL;
  660.         }
  661.         
  662.         if (testing) {
  663.         done = 1;
  664.         } else if (strcmp(pw1, pw2)) {
  665.         newtWinMessage(_("Password Mismatch"), _("Ok"),
  666.               _("The passwords you entered were different. Please "
  667.               "try again."));
  668.         newtEntrySet(pw1Entry, "", 0);
  669.         newtEntrySet(pw2Entry, "", 0);
  670.         } else if (!strlen(pw1) && beenSet) {
  671.         newtFormDestroy(form);
  672.         newtPopWindow();
  673.         return INST_OKAY;
  674.         } else if (strlen(pw1) < 6)  {
  675.         newtWinMessage(_("Password Mismatch"), _("Ok"),
  676.               _("The root password must be at least 6 characters "
  677.                 "long."));
  678.         newtEntrySet(pw1Entry, "", 0);
  679.         newtEntrySet(pw2Entry, "", 0);
  680.         } else
  681.         done = 1;
  682.     } while (!done);
  683.  
  684.     newtPopWindow();
  685.  
  686.     pw2 = alloca(strlen(pw1) + 1);
  687.     strcpy(pw2, pw1);
  688.     pw1 = pw2;
  689.  
  690.     newtFormDestroy(form);
  691.     }
  692.  
  693.     if (testing) return 0;
  694.  
  695.     if (!skipCrypt) {
  696.     gettimeofday(&time2, NULL);
  697.  
  698.     salt[0] = mksalt(time1.tv_usec);
  699.     salt[1] = mksalt(time2.tv_usec);
  700.     salt[2] = '\0';
  701.  
  702.     pw = crypt(pw1, salt);
  703.     } else {
  704.     pw = pw1;
  705.     }
  706.  
  707.     sprintf(cmd, "/bin/sed 's&root:[^:]*:&root:%s:&' < /etc/passwd > "
  708.         "/etc/passwd.new", pw);
  709.  
  710.     if (!(pid = fork())) {
  711.     chroot(state->rootPath);
  712.     chdir("/");
  713.  
  714.     exit(system(cmd));
  715.     }
  716.  
  717.     waitpid(pid, &status, 0);
  718.  
  719.     path = alloca(strlen(state->rootPath) + 30);
  720.     newpath = alloca(strlen(state->rootPath) + 30);
  721.     sprintf(path, "%s/etc/passwd", state->rootPath);
  722.     sprintf(newpath, "%s/etc/passwd.new", state->rootPath);
  723.     unlink(path);
  724.     rename(newpath, path);
  725.  
  726.     beenSet = 1;
  727.  
  728.     return 0;
  729. }
  730.     
  731. static int configureTimezone(struct installState * state) {
  732.     return timeConfig(state->rootPath);
  733. }
  734.  
  735. static int configureServices(struct installState * state) {
  736.     if (state->hints.flags & HINT_SKIPNTSYSV)
  737.     return (state->direction < 0) ? INST_CANCEL : INST_OKAY;
  738.     else
  739.     return servicesConfig(state->rootPath);
  740. }
  741.  
  742. static int setupBootloader(struct installState * state) {
  743.     static int first = 1;
  744. #ifdef __alpha
  745.     int rc;
  746. #else
  747.     char * versionString;
  748.     int rc;
  749.     int append = 0;
  750.     char * version, * release;
  751.     int i;
  752. #endif
  753.  
  754.     if (!state->isUpgrade && first) {
  755.     setupSerialConsole();
  756.     }
  757.  
  758.     #ifdef __alpha__
  759.     if (first) {
  760.         first = 0;
  761.         rc = kernelCopy(state->kernel);
  762.         if (rc) return rc;
  763.     }
  764.  
  765.     return INST_NOP;
  766.     #else
  767.     first = 0;
  768.  
  769.     if (state->isUpgrade && !access("/mnt/etc/conf.modules", X_OK)) {
  770.         rc = readModuleConfPersist("/mnt/etc", state->dl);
  771.         if (rc) return rc;
  772.         append = 1;
  773.     }
  774.  
  775.     for (i = 0; i < state->ps.numPackages; i++) {
  776.         if (!strncmp(state->ps.packages[i]->name, "kernel", 6)) break;
  777.     }
  778.  
  779.     if (i == state->ps.numPackages) {
  780.         errorWindow("I couldn't find a kernel!");
  781.         return INST_ERROR;
  782.     } 
  783.  
  784.     headerGetEntry(state->ps.packages[i]->h, RPMTAG_VERSION, NULL, 
  785.                (void *) &version, NULL);
  786.     headerGetEntry(state->ps.packages[i]->h, RPMTAG_RELEASE, NULL, 
  787.                (void *) &release, NULL);
  788.     
  789.     versionString = alloca(strlen(version) + strlen(release) + 2);
  790.     sprintf(versionString, "%s-%s", version, release);
  791.  
  792.     logMessage("installed kernel version %s", versionString);
  793.  
  794.     /* installLilo installs silo on the SPARC */
  795.     return installLilo("/mnt/etc", state->table, state->fstab, 
  796.                versionString, state->hints.bootloader.flags,
  797.                state->hints.bootloader.options);
  798.     #endif
  799. }
  800.  
  801. static int finishNetworking(struct installState * state) {
  802.     int rc;
  803.     char * path = alloca(strlen(state->rootPath) + 50);
  804.  
  805.     rc = checkNetConfig(&state->intf, &state->netc, &state->intfFinal,
  806.             &state->netcFinal, &state->dl, state->direction);
  807.  
  808.     if (rc) return rc;
  809.  
  810.     sprintf(path, "%s/etc/sysconfig", state->rootPath);
  811.     writeNetConfig(path, &state->netcFinal, 
  812.            &state->intfFinal, 0);
  813.     strcat(path, "/network-scripts");
  814.     writeNetInterfaceConfig(path, &state->intfFinal);
  815.     sprintf(path, "%s/etc", state->rootPath);
  816.     writeResolvConf(path, &state->netcFinal);
  817.  
  818.     /* this is a bit of a hack */
  819.     writeHosts(path, &state->netcFinal, 
  820.            &state->intfFinal, !state->isUpgrade);
  821.  
  822.     return 0;
  823. }
  824.  
  825. static int selectPath(struct installState * state) {
  826.     int result;
  827.  
  828.     memset(state, 0, sizeof(state));
  829.  
  830.     if (kickstart) {
  831.     if (!ksGetCommand(KS_CMD_UPGRADE, NULL, NULL, NULL)) {
  832.         state->steps = upgradeSteps;
  833.         state->isUpgrade = 1;
  834.     } else {
  835.         state->steps = installSteps;
  836.     }
  837.  
  838.     return 0;
  839.     }
  840.  
  841.     result = newtWinChoice(_("Installation Path"), _("Install"), _("Upgrade"),
  842.     _("Would you like to install a new system or upgrade a system which "
  843.       "already contains Red Hat Linux 2.0 or later?"));
  844.    
  845.     if (result == 2) {
  846.     state->steps = upgradeSteps;
  847.     state->isUpgrade = 1;
  848.     } else
  849.     state->steps = installSteps;
  850.  
  851.     return 0;
  852. }
  853.  
  854. static int selectInstallClass(struct installState * state) {
  855.     int rc, i;
  856.     static int choice = 2;
  857.     char * choices[] = {
  858.     N_("Workstation"),
  859.     N_("Server"),
  860.     N_("Custom"),
  861.     NULL };
  862.     char * transChoices[sizeof(choices) / sizeof(*choices)];
  863.  
  864.     if (expert || kickstart) {
  865.     return state->direction < 0 ? INST_CANCEL : INST_OKAY;
  866.     }
  867.  
  868.     for (i = 0; choices[i]; i++) 
  869.     transChoices[i] = _(choices[i]);
  870.     transChoices[i] = NULL;
  871.  
  872.     rc = newtWinMenu(_("Installation Class"), 
  873.             _("What type of machine are you installing? For "
  874.               "maximum flexibility, choose \"Custom\"."), 30,
  875.             10, 0, 5, transChoices, &choice, _("Ok"), _("Back"), 
  876.             NULL);
  877.     if (rc == 2) return INST_CANCEL;
  878.  
  879.     memset(&state->hints, 0, sizeof(state->hints));
  880.     if (choice == 2) return 0;
  881.  
  882.     state->hints.bootloader.flags = LILO_ON_MBR | LILO_USE_LINEAR;
  883.     state->hints.flags = HINT_SKIPNTSYSV | HINT_AUTOFORMAT | 
  884.              HINT_NOLOGMESSAGE |
  885.              HINT_AUTOSWAP | HINT_SKIPBOOTLOADER | HINT_FORCEDDRUID;
  886.     state->hints.component = choices[choice];
  887.     if (choice == 1) {
  888.     /* server */
  889.     state->hints.flags |= HINT_SKIPPRINTER;
  890.     state->hints.partitioning.flags |= FSEDIT_CLEARALL; state->hints.partitioning.attempts = serverPartitioning;
  891.     } else {
  892.     /* workstation */
  893.     state->hints.flags |= HINT_AUTOSCSI;
  894. #ifdef __i386__
  895.     state->hints.partitioning.flags |= FSEDIT_CLEARLINUX;
  896. #else
  897.     state->hints.partitioning.flags |= FSEDIT_CLEARALL;
  898. #endif
  899.     }
  900.  
  901.     return INST_OKAY;
  902. }
  903.  
  904. static int upgrFindInstall(struct installState * state) {
  905.     int rc;
  906.  
  907.     /* this also turns on swap for us */
  908.     rc = readMountTable(state->table, &state->fstab);
  909.     if (rc) return rc;
  910.  
  911.     if (!testing) {
  912.     mountFilesystems(&state->fstab);
  913.  
  914.     if (state->method->prepareMedia) {
  915.         rc = state->method->prepareMedia(state->method, &state->fstab);
  916.         if (rc) {
  917.         umountFilesystems(&state->fstab);
  918.         return rc;
  919.         }
  920.     }
  921.     }
  922.  
  923.     return 0;
  924. }
  925.  
  926. static int upgrChoosePackages(struct installState * state) {
  927.     int firstTime = 1;
  928.     char * rpmconvertbin;
  929.     int rc;
  930.     char * path;
  931.     char * argv[] = { NULL, NULL };
  932.  
  933.     if (testing)
  934.     path = "/";
  935.     else
  936.     path = "/mnt";
  937.  
  938.     if (firstTime) {
  939.     if (access("/mnt/var/lib/rpm/packages.rpm", R_OK)) {
  940.         if (access("/mnt/var/lib/rpm/packages", R_OK)) {
  941.         errorWindow("No RPM database exists!");
  942.         return INST_ERROR;
  943.         }
  944.  
  945.         if (state->method->getFile(state->method, "rpmconvert", 
  946.             &rpmconvertbin)) {
  947.         return INST_ERROR;
  948.         }
  949.     
  950.         symlink("/mnt/var", "/var");
  951.         winStatus(35, 3, _("Upgrade"), _("Converting RPM database..."));
  952.         chmod(rpmconvertbin, 0755);
  953.         argv[0] = rpmconvertbin;
  954.         rc = runProgram(RUN_LOG, rpmconvertbin, argv);
  955.         if (state->method->rmFiles)
  956.         unlink(rpmconvertbin);
  957.  
  958.         newtPopWindow();
  959.         if (rc) return INST_ERROR;
  960.     }
  961.     
  962.     winStatus(35, 3, "Upgrade", _("Finding packages to upgrade..."));
  963.     rc = ugFindUpgradePackages(&state->ps, path);
  964.     newtPopWindow();
  965.     if (rc) return rc;
  966.     firstTime = 0;
  967.     psVerifyDependencies(&state->ps, 1);
  968.     }
  969.  
  970.     return psSelectPackages(&state->ps, &state->cs, NULL, 0, 1);
  971. }
  972.  
  973. #define DO_RETRY    1
  974. #define DO_NEXT        2
  975. #define DO_PREV        3
  976. #define DO_MENU        4
  977.  
  978. static int errcanChoices(char * name) {
  979.     int rc;
  980.  
  981.     rc = newtWinTernary(_("Error"), _("Previous"), _("Retry"), _("Menu"),
  982.             _("An error occured during step \"%s\" of the install.\n\n"
  983.           "You may retry that step, return to the previous step "
  984.           "in the install, or see a menu of installation steps "
  985.           "which will allow you to move around in the install "
  986.           "more freely. It is not recommended to use the menu "
  987.           "unless you are already familiar with Red Hat Linux. "
  988.           "What would you like to do?"), name);
  989.   
  990.     if (rc == 1 || !rc)
  991.     return DO_PREV;
  992.     else if (rc == 2)
  993.     return DO_RETRY;
  994.  
  995.     return DO_MENU;
  996. }
  997.  
  998. static int stepMenu(struct installState * state, int currStep) {
  999.     int firstStep = currStep;
  1000.     long i;
  1001.     int numChoices, whichStep = 0;
  1002.     char ** steps;
  1003.  
  1004.     while (state->steps[firstStep].prev != -1)
  1005.     firstStep = state->steps[firstStep].prev;
  1006.  
  1007.     i = firstStep, numChoices = 0;
  1008.     do {
  1009.     numChoices++;
  1010.     i = state->steps[i].next;
  1011.     } while (state->steps[i].prev != -1 && state->steps[i].next != STEP_DONE);
  1012.     numChoices++;
  1013.  
  1014.     steps = alloca(sizeof(char *) * (numChoices + 2));
  1015.     steps[0] = _("  Continue with install");
  1016.     for (i = firstStep; i < (firstStep + numChoices); i++) {
  1017.     steps[i - firstStep + 1] = alloca(50);
  1018.     if (state->steps[i].completed)
  1019.        strcpy(steps[i - firstStep + 1], "* ");
  1020.     else
  1021.        strcpy(steps[i - firstStep + 1], "  ");
  1022.  
  1023.     strcat(steps[i - firstStep + 1], state->steps[i].name);
  1024.     }
  1025.     steps[numChoices + 1] = NULL;
  1026.  
  1027.     newtWinMenu(_("Installation Steps"), _("What step would you like to run? "
  1028.         "Steps with a * next to them have already been completed."), 
  1029.         48, 5, 5, 6, steps, &whichStep, _("Ok"), NULL);
  1030.  
  1031.     if (whichStep == 0)
  1032.     return -1;
  1033.     else
  1034.     return (whichStep - 1) + firstStep;
  1035.  
  1036.     return i;
  1037. }
  1038.  
  1039. static int getNextStep(struct installState * state, int lastStep, int lastrc) {
  1040.     int choice;
  1041.     int nextStep;
  1042.  
  1043.     if (state->lastChoice == DO_MENU) {
  1044.     choice = DO_MENU;
  1045.     } else if (lastrc == INST_ERROR) {
  1046.     choice = errcanChoices(state->steps[lastStep].name);
  1047.     kickstart = 0;
  1048.     } else if (lastrc == INST_CANCEL) {
  1049.     choice = DO_PREV;
  1050.     } else if (lastrc == INST_NOP) {
  1051.     choice = state->lastChoice;
  1052.     } else {
  1053.     choice = DO_NEXT;
  1054.     }
  1055.  
  1056.     switch (choice) {
  1057.       case DO_PREV:
  1058.     nextStep = state->steps[lastStep].prev;
  1059.     while (nextStep != -1 && 
  1060.            (state->steps[nextStep].skipOnCancel ||
  1061.             (state->steps[nextStep].skipOnLocal && state->isLocal)) 
  1062.            && state->steps[nextStep].prev != -1)
  1063.         nextStep = state->steps[nextStep].prev;
  1064.  
  1065.     if (nextStep == -1 || nextStep == lastStep) {
  1066.         newtWinMessage(_("Cancelled"), _("Ok"), 
  1067.                _("I can't go to the previous step"
  1068.                  " from here. You will have to try again."));
  1069.         nextStep = lastStep;
  1070.     }
  1071.     state->direction = -1;
  1072.     break;
  1073.  
  1074.       case DO_RETRY:
  1075.     nextStep = lastStep;
  1076.     state->direction = -1;
  1077.     break;
  1078.  
  1079.       case DO_MENU:
  1080.     nextStep = stepMenu(state, lastStep);
  1081.     if (nextStep == -1) {
  1082.         choice = DO_NEXT;
  1083.  
  1084.         if (lastrc)
  1085.         nextStep = lastStep;
  1086.         else
  1087.         nextStep = state->steps[lastStep].next;
  1088.     }
  1089.     state->direction = 1;
  1090.     break;
  1091.  
  1092.       case DO_NEXT: default:
  1093.         nextStep = state->steps[lastStep].next;
  1094.     while (nextStep != STEP_DONE && 
  1095.            state->isLocal && state->steps[nextStep].skipOnLocal)
  1096.         nextStep = state->steps[nextStep].next;
  1097.     state->direction = 1;
  1098.     break;
  1099.     }
  1100.  
  1101.     state->lastChoice = choice;
  1102.  
  1103.     return nextStep;
  1104. }
  1105.  
  1106. void doSuspend(void) {
  1107.     pid_t pid;
  1108.     int status;
  1109.  
  1110.     if (exitOnSuspend) {
  1111.     newtFinished();
  1112.     exit(1);
  1113.     }
  1114.  
  1115.     newtSuspend();
  1116.     if (!(pid = fork())) {
  1117.     printf(_("\n\nType <exit> to return to the install program.\n\n"));
  1118.     execl("/bin/sh", "-/bin/sh", NULL);
  1119.     perror("error execing /bin/sh");
  1120.     sleep(5);
  1121.     exit(1);
  1122.     }
  1123.     waitpid(pid, &status, 0);
  1124.     newtResume();
  1125. }
  1126.  
  1127. static void setupSerialConsole(void) {
  1128.     int first = 1;
  1129.     struct stat sb;
  1130.     char * argv[10] = { "/usr/sbin/setconsole", "--speed", NULL, NULL, NULL };
  1131.     struct termios tos;
  1132.     speed_t speed;
  1133.  
  1134.     if (!first) return;
  1135.     first = 0;
  1136.  
  1137.     if (fstat(0, &sb)) {
  1138.     logMessage("error stat'ing stdin: %s", strerror(errno));
  1139.     return;
  1140.     }
  1141.  
  1142.     if (!S_ISCHR(sb.st_mode)) {
  1143.     logMessage("stdin isn't a character device!!! ack!");
  1144.     return;
  1145.     }
  1146.  
  1147.     if (major(sb.st_rdev) != 4) {
  1148.     if (minor(sb.st_rdev) == 64)
  1149.         argv[3] = "ttya";
  1150.     else
  1151.         argv[3] = "ttyb";
  1152.  
  1153.         tcgetattr(0, &tos);
  1154.     speed = cfgetospeed(&tos);
  1155.     switch (speed) {
  1156.         case B38400:    argv[2] = "38400"; break;
  1157.         case B19200:    argv[2] = "19200"; break;
  1158.         default:        argv[2] = "9600";  break;
  1159.     }
  1160.  
  1161.     if (access("/mnt/usr/sbin/setconsole", X_OK)) {
  1162.         logMessage("/mnt/usr/sbin/setconsole does not exist -- skipping");
  1163.         return;
  1164.     }
  1165.  
  1166.     logMessage("setting up %s as serial console, speed is %s", argv[3], 
  1167.             argv[2]);
  1168.     runProgramRoot(RUN_LOG, "/mnt", "/usr/sbin/setconsole", argv);
  1169.     }
  1170. }
  1171.  
  1172. static int configurePrinter(struct installState * state) {
  1173.     char * path = alloca(strlen(state->rootPath) + 50);
  1174.  
  1175.     sprintf(path, "%s/usr/bin/lpr", state->rootPath);
  1176.  
  1177.     if (state->hints.flags & HINT_SKIPPRINTER)
  1178.     return state->direction < 0 ? INST_CANCEL : INST_OKAY;
  1179.     else if (testing) {
  1180.     return doConfigurePrinters("/", state->direction);
  1181.     } else if (!access(path, X_OK)) {
  1182.     return doConfigurePrinters(state->rootPath, state->direction);
  1183.     }
  1184.  
  1185.     return INST_NOP;
  1186. }
  1187.  
  1188. static int createBootdisk(struct installState * state) {
  1189.     int rc;
  1190.     int i;
  1191.     char * version, * release;
  1192.     char * versionString;
  1193.     int stage = 1;
  1194.     static int beenHere = 0;
  1195.  
  1196.     if (!state->isUpgrade && !beenHere) {
  1197.     writeFstab(&state->fstab);
  1198.     }
  1199.     writeModuleConf("/mnt/etc", state->dl, 1);
  1200.     beenHere = 1;
  1201.  
  1202.     if (state->hints.flags & HINT_SKIPBOOTDISK) return INST_NOP;
  1203.  
  1204. #ifndef __i386__
  1205.     return INST_NOP;
  1206. #else
  1207.     if (!testing && (access("/mnt/sbin/mkbootdisk", X_OK) || 
  1208.     access("/mnt/sbin/mkinitrd", X_OK))) return INST_NOP;
  1209.  
  1210.     while (stage < 4) {
  1211.     switch (stage) {
  1212.       case 1:
  1213.         rc = newtWinTernary(_("Bootdisk"), _("Yes"), _("No"), _("Back"),
  1214.             _("A custom bootdisk provides a way of booting into your "
  1215.           "Linux system without depending on the normal bootloader. "
  1216.           "This is useful if you don't want to install lilo on your "
  1217.           "system, another operating system removes lilo, or lilo "
  1218.           "doesn't work with your hardware configuration. A custom "
  1219.           "bootdisk can also be used with the Red Hat rescue image, "
  1220.           "making is much easier to recover from severe system "
  1221.           "failures.\n\n"
  1222.           "Would you like to create a bootdisk for your system?"));
  1223.  
  1224.         if (rc == 3) return INST_CANCEL;
  1225.         if (rc == 2) return INST_OKAY;
  1226.         stage = 2;
  1227.         break;
  1228.  
  1229.       case 2:
  1230.         rc = newtWinChoice(_("Bootdisk"), _("Ok"), _("Back"),
  1231.             _("Insert a blank floppy in the first drive "
  1232.               "/dev/fd0."));
  1233.         if (rc == 2) 
  1234.         stage = 1;
  1235.         else
  1236.         stage = 3;
  1237.         break;
  1238.  
  1239.       case 3:
  1240.         for (i = 0; i < state->ps.numPackages; i++) {
  1241.         if (!strncmp(state->ps.packages[i]->name, "kernel", 6)) break;
  1242.         }
  1243.  
  1244.         if (i == state->ps.numPackages) {
  1245.         errorWindow("I couldn't find a kernel!");
  1246.         return INST_ERROR;
  1247.         } 
  1248.  
  1249.         headerGetEntry(state->ps.packages[i]->h, RPMTAG_VERSION, NULL, 
  1250.                (void *) &version, NULL);
  1251.         headerGetEntry(state->ps.packages[i]->h, RPMTAG_RELEASE, NULL, 
  1252.                (void *) &release, NULL);
  1253.         versionString = alloca(strlen(version) + strlen(release) + 2);
  1254.         sprintf(versionString, "%s-%s", version, release);
  1255.  
  1256.         rc = makeBootdisk("/mnt", versionString);
  1257.         if (rc == INST_ERROR) return INST_ERROR;
  1258.         stage++;
  1259.         break;
  1260.     }
  1261.     }
  1262.  
  1263.     return INST_OKAY;
  1264. #endif
  1265. }
  1266.  
  1267. int main(int argc, char ** argv) {
  1268.     char ** argptr;
  1269.     int step = STEP_FIRST;
  1270.     int rc = 0;
  1271.     struct installState state;
  1272.     int i;
  1273.     int isForce = 0;
  1274.     int len = strlen(argv[0]);
  1275.     char * spaces;
  1276.     DIR * dir;
  1277.     struct dirent * ent;
  1278.     char * kickstartFile = NULL;
  1279.     int localInstall = 0;
  1280.  
  1281.     spaces = strdup("                                                      ");
  1282.  
  1283.     if (!strcmp(argv[0] + len - 6, "umount")) {
  1284.     return umountCommand(argc, argv);
  1285.     } else if (!strcmp(argv[0] + len - 5, "mount")) {
  1286.     return mountCommand(argc, argv);
  1287.     } else if (!strcmp(argv[0] + len - 5, "mkdir")) {
  1288.     return mkdirCommand(argc, argv);
  1289.     } else if (!strcmp(argv[0] + len - 5, "mknod")) {
  1290.     return mknodCommand(argc, argv);
  1291.     } else if (!strcmp(argv[0] + len - 3, "cat")) {
  1292.     return catCommand(argc, argv);
  1293.     } else if (!strcmp(argv[0] + len - 2, "ls")) {
  1294.     return lsCommand(argc, argv);
  1295.     } else if (!strcmp(argv[0] + len - 2, "ln")) {
  1296.     return lnCommand(argc, argv);
  1297.     } else if (!strcmp(argv[0] + len - 2, "rm")) {
  1298.     return rmCommand(argc, argv);
  1299.     } else if (!strcmp(argv[0] + len - 5, "chmod")) {
  1300.     return chmodCommand(argc, argv);
  1301.     } else if (!strcmp(argv[0] + len - 5, "lsmod")) {
  1302.     return lsmodCommand(argc, argv);
  1303.     } else if (!strcmp(argv[0] + len - 6, "mkswap")) {
  1304.     return mkswapCommand(argc, argv);
  1305.     } else if (!strcmp(argv[0] + len - 6, "swapon")) {
  1306.     return swaponCommand(argc, argv);
  1307.     } else if (!strcmp(argv[0] + len - 6, "uncpio")) {
  1308.     return uncpioCommand(argc, argv);
  1309.     } else if (!strcmp(argv[0] + len - 6, "insmod")) {
  1310.     return ourInsmodCommand(argc, argv);
  1311.     } else if (!strcmp(argv[0] + len - 5, "rmmod")) {
  1312.     return rmmod_main(argc, argv);
  1313.     }
  1314.  
  1315.     /* if this fails, it's okay -- it might help with free space though */
  1316.     unlink("/sbin/install");
  1317.  
  1318.     memset(&state, 0, sizeof(state));
  1319.     state.steps = installSteps;            /* blind guess */
  1320.     state.rootPath = "/mnt";
  1321.  
  1322.     argptr = argv + 1;
  1323.     while (*argptr) {
  1324.     if (!strcmp(*argptr, "--method")) {
  1325.         argptr++;
  1326.         if (!*argptr) {
  1327.         fprintf(stderr, "--method requires argument\n");
  1328.         exit(1);
  1329.         }
  1330.         state.method = findInstallMethod(*argptr);
  1331.         if (!state.method) {
  1332.         fprintf(stderr, "unknown install method: %s\n", *argptr);
  1333.         exit(1);
  1334.         }
  1335.     } else if (!strcmp(*argptr, "--force")) {
  1336.         isForce = 1;
  1337.     } else if (!strcmp(*argptr, "--kickstart") || 
  1338.            !strcmp(*argptr, "--ks")) {
  1339.         argptr++;
  1340.         if (!*argptr) 
  1341.         fprintf(stderr, "--kickstart requires argument\n");
  1342.         kickstartFile = *argptr;
  1343.     } else if (!strcmp(*argptr, "--expert")) {
  1344.         expert = 1;
  1345.     } else if (!strcmp(*argptr, "--test")) {
  1346.         testing = 1;
  1347.     } else if (!strcmp(*argptr, "--pcmcia")) {
  1348.         argptr++;
  1349.         if (!*argptr) {
  1350.         fprintf(stderr, "--pcmcia requires argument\n");
  1351.         exit(1);
  1352.         }
  1353.         state.pcmcia = *argptr;
  1354.     } else if (!strcmp(*argptr, "--kernel")) {
  1355.         argptr++;
  1356.         if (!*argptr) {
  1357.         fprintf(stderr, "--kernel requires argument\n");
  1358.         exit(1);
  1359.         }
  1360.         state.kernel = *argptr;
  1361.     } else if (!strcmp(*argptr, "--rootpath")) {
  1362.         argptr++;
  1363.         if (!*argptr) {
  1364.         fprintf(stderr, "--rootpath requires argument\n");
  1365.         exit(1);
  1366.         }
  1367.         state.rootPath = *argptr;
  1368.         localInstall = 1;
  1369.     } else {
  1370.         /* skipping unknown arguments allows for future expansion */
  1371.         fprintf(stderr, "unknown argument: %s\n", *argptr);
  1372.     }
  1373.     argptr++;
  1374.     }
  1375.  
  1376.     if (!state.method) {
  1377.     fprintf(stderr, "--method argument is required\n");
  1378.     exit(1);
  1379.     }
  1380.  
  1381.     if (!testing && !localInstall && !isForce && (getpid() > 50)) {
  1382.     fprintf(stderr, "you're running me on a live system! that's ");
  1383.     fprintf(stderr, "incredibly stupid.\n");
  1384.     exit(1);
  1385.     }
  1386.  
  1387.     fprintf(stderr, "in second stage install\n");
  1388.  
  1389.     /* translate some tables */
  1390.     for (i = 0; installSteps[i].next != STEP_DONE; i++)
  1391.     installSteps[i].name = _(installSteps[i].name);
  1392.     installSteps[i].name = _(installSteps[i].name);
  1393.  
  1394.     for (i = 0; upgradeSteps[i].next != STEP_DONE; i++)
  1395.     upgradeSteps[i].name = _(upgradeSteps[i].name);
  1396.     upgradeSteps[i].name = _(upgradeSteps[i].name);
  1397.  
  1398.     state.isLocal = localInstall;
  1399.     exitOnSuspend = localInstall || testing;
  1400.  
  1401.     newtSetSuspendCallback(doSuspend);
  1402.     
  1403.     openLog(testing || localInstall);
  1404.  
  1405.     logMessage("second stage install running (version " VERSION " built "
  1406.         __DATE__ " " __TIME__ ")");
  1407.  
  1408.     logDebugMessage(("extra log messages are enabled"));
  1409.  
  1410.     spawnShell();
  1411.  
  1412.     newtInit();
  1413.     newtCls();
  1414.  
  1415.     newtDrawRootText(0, 0, "Red Hat Linux (C) 1998 Red Hat Software");
  1416.     newtPushHelpLine(_("  <Tab>/<Alt-Tab> between elements  | <Space> selects | <F12> next screen "));
  1417.  
  1418.     setDefaultLanguage(2);
  1419.  
  1420.     readNetConfig("/tmp", &state.netc);
  1421.  
  1422.     dir = opendir("/tmp");
  1423.     if (!dir) 
  1424.     logMessage("failed to open directory /tmp: %s", strerror(errno));
  1425.     else {
  1426.     errno = 0;
  1427.     while ((ent = readdir(dir))) {
  1428.         if (!strncmp("ifcfg-", ent->d_name, 6)) break;
  1429.     }
  1430.  
  1431.     if (!ent && errno) {
  1432.         logMessage("error reading directory entry: %s", strerror(errno));
  1433.     } else if (ent) {
  1434.         logMessage("found network config file %s", ent->d_name);
  1435.         readNetInterfaceConfig("/tmp", ent->d_name + 6, &state.intf);
  1436.     }
  1437.     }
  1438.     closedir(dir);
  1439.  
  1440.     logMessage("reading /usr/lib/rpmrc");
  1441.     rpmReadConfigFiles(NULL, NULL, NULL, 0);
  1442.     logMessage("\tdone");
  1443.  
  1444.     readModuleConf("/tmp", &state.dl);
  1445.  
  1446.     /* make sure we don't pick up any gunk from the outside world */
  1447.     putenv("PATH=/usr/bin:/bin:/sbin:/usr/sbin");
  1448.     putenv("LD_LIBRARY_PATH=");
  1449.  
  1450.     if (kickstartFile) {
  1451.         if (ksReadCommands(kickstartFile)) 
  1452.         kickstartFile = NULL;
  1453.     else {
  1454.         kickstart = 1;
  1455.         ksToHints(&state.hints);
  1456.     }
  1457.  
  1458.     #ifndef __sparc__ 
  1459.     setupKeyboard(&state.keyboard);
  1460.     #endif
  1461.     } else {
  1462.     #ifndef __sparc__ 
  1463.     readKbdConfig("/tmp", &state.keyboard);
  1464.     #endif
  1465.     }
  1466.  
  1467.     if (kickstart) {
  1468.     state.hints.flags = HINT_SKIPNTSYSV | HINT_AUTOFORMAT |
  1469.                 HINT_SKIPPRINTER | HINT_SKIPBOOTDISK |
  1470.                 HINT_AUTOSWAP | HINT_AUTOSCSI | HINT_NOLOGMESSAGE;
  1471.     }
  1472.  
  1473.     while (step != STEP_DONE) {
  1474.     i = strlen(state.steps[step].name);
  1475.     newtDrawRootText(0 - i, 0, state.steps[step].name);
  1476.     newtRefresh();
  1477.     rc = state.steps[step].fn(&state);
  1478.     if (!rc)
  1479.         state.steps[step].completed = 1;
  1480.  
  1481.     spaces[i] = '\0';
  1482.     newtDrawRootText(0 - i, 0, spaces);
  1483.     spaces[i] = ' ';
  1484.  
  1485.     step = getNextStep(&state, step, rc);
  1486.     }
  1487.  
  1488.     if (kickstart)
  1489.     ksRunPost();
  1490.  
  1491.     newtDrawRootText(72, 0, _("Complete"));
  1492.     newtWinMessage(_("Done"), _("Ok"), 
  1493.     _("Congratulations, installation is complete.\n\n"
  1494.       "Remove the floppy from the drive and "
  1495.       "press return to reboot. For information on fixes which are "
  1496.       "available for this release of Red Hat Linux, consult the "
  1497.       "Errata available from http://www.redhat.com.\n\n"
  1498.       "Information on configuring your system is available in the post "
  1499.       "install chapter of the Official Red Hat Linux User's Guide."));
  1500.  
  1501.     newtFinished();
  1502.  
  1503.     return 0;
  1504. }
  1505.