/* * install2.c * * This is the second half of the install. It is exec'd from the first half * once the secondary media has been mounted. It does a bunch of argv * processing to figure out what the first half did. It's a bit of a hack, but * it gives us a nice install as far as the user can see. * * Erik Troan (ewt@redhat.com) * * Copyright 1997 Red Hat Software * * This software may be freely redistributed under the terms of the GNU * public license. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */ /* * We assume the following: * * /usr/bin -> any binaries we might need * * it's up to the first stage installer to make sure this happens. * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "commands.h" #include "config.h" #include "devices.h" #include "doit.h" #include "fs.h" #include "fsedit.h" #include "hd.h" #include "install.h" #include "kbd.h" #include "kernel.h" #include "kickstart.h" #include "lilo.h" #include "log.h" #include "methods.h" #include "mkswap.h" #include "net.h" #include "perror.h" #include "pkgs.h" #include "printercfg.h" #include "run.h" #include "scsi.h" #include "upgrade.h" #include "windows.h" int testing = 0; int expert = 0; int kickstart = 0; #define STEP_FIRST 0 #define STEP_PATH 0 #define STEP_SCSI 1 #define STEP_FDISKMTAB 2 #define STEP_SWAP 3 #define STEP_FINDPKGS 4 #define STEP_FORMAT 5 #define STEP_PICKPKGS 6 #define STEP_DOIT 7 #define STEP_FINISHNET 8 #define STEP_TIMECONFIG 9 #define STEP_SERVICES 10 #define STEP_PRINTER 11 #define STEP_ROOTPW 12 #define STEP_LILO 13 #define STEP_UPG_SCSI 1 #define STEP_UPG_PKGS 2 #define STEP_UPG_MTAB 3 #define STEP_UPG_FFILES 4 #define STEP_UPG_DOIT 5 #define STEP_UPG_FINISHNET 6 #define STEP_UPG_LILO 7 #define STEP_DONE 1000 struct installState { int isUpgrade, lastChoice; char * pcmcia, * kernel, * keyboard; struct partitionTable table; struct fstab fstab; struct pkgSet ps; struct componentSet cs; struct installMethod * method; struct netInterface intf; struct netConfig netc; struct driversLoaded * dl; struct installStep * steps; } ; typedef int (*installStepFn)(struct installState * state); static int setupSCSI(struct installState * state); static int partitionDisks(struct installState * state); static int setupSwap(struct installState * state); static int findInstallFiles(struct installState * state); static int formatPartitions(struct installState * state); static int choosePackages(struct installState * state); static int doInstallStep(struct installState * state); static int setRootPassword(struct installState * state); static int configureTimezone(struct installState * state); static int configureServices(struct installState * state); static int configurePrinter(struct installState * state); static int setupBootloader(struct installState * state); static int finishNetworking(struct installState * state); static int selectPath(struct installState * state); static int upgrChoosePackages(struct installState * state); static int upgrFindInstall(struct installState * state); static void setupSerialConsole(void); struct installStep { char * name; int prev, next; installStepFn fn; int skipOnCancel; int completed; }; struct installStep installSteps[] = { { "Select installation path", -1, STEP_SCSI, selectPath, 0, 0 }, { "Setup SCSI", STEP_PATH, STEP_FDISKMTAB, setupSCSI, 0, 0 }, { "Setup filesystems", STEP_PATH, STEP_SWAP, partitionDisks, 0, 0 }, { "Setup swap space", STEP_FDISKMTAB, STEP_FINDPKGS, setupSwap, 0, 0 }, { "Find installation files", STEP_SWAP, STEP_FORMAT, findInstallFiles, 1, 0 }, { "Choose partitions to format", STEP_SWAP, STEP_PICKPKGS, formatPartitions, 0, 0 }, { "Choose packages to install", STEP_FORMAT, STEP_DOIT, choosePackages, 0, 0 }, { "Install system", STEP_PICKPKGS, STEP_FINISHNET, doInstallStep, 0, 0 }, { "Configure networking", -1, STEP_TIMECONFIG, finishNetworking, 0, 0 }, { "Configure timezone", STEP_FINISHNET, STEP_SERVICES, configureTimezone, 0, 0 }, { "Configure services", STEP_TIMECONFIG,STEP_PRINTER, configureServices, 0, 0 }, { "Configure printer", STEP_SERVICES, STEP_ROOTPW, configurePrinter, 0, 0 }, { "Set root password", STEP_PRINTER, STEP_LILO, setRootPassword, 0, 0 }, { "Install bootloader", STEP_ROOTPW, STEP_DONE, setupBootloader, 0, 0 }, }; struct installStep upgradeSteps[] = { { "Select installation path", -1, STEP_UPG_SCSI, selectPath, 0, 0 }, { "Setup SCSI", STEP_PATH, STEP_UPG_PKGS, setupSCSI, 0, 0 }, { "Find installation files", STEP_PATH, STEP_UPG_MTAB, findInstallFiles, 1, 0 }, { "Find current installation", STEP_UPG_PKGS, STEP_UPG_FFILES, upgrFindInstall, 0, 0 }, { "Choose packages to upgrade", STEP_UPG_FFILES,STEP_UPG_DOIT, upgrChoosePackages, 0, 0 }, { "Upgrade system", -1, STEP_UPG_FINISHNET, doInstallStep, 0, 0 }, { "Install bootloader", STEP_UPG_FINISHNET, STEP_DONE, setupBootloader, 0, 0 }, }; void spawnShell(void) { pid_t pid; int fd; if (!testing) { fd = open("/dev/tty2", O_RDWR); if (fd < 0) { logMessage("cannot open /dev/tty2 -- no shell will be provided"); return; } else if (access("/usr/bin/sh", X_OK)) { logMessage("cannot open shell - /usr/bin/sh doesn't exist"); return; } if (!(pid = fork())) { dup2(fd, 0); dup2(fd, 1); dup2(fd, 2); close(fd); setsid(); execl("/bin/sh", "-/bin/sh", NULL); logMessage(perrorstr("exec of /bin/sh failed")); } close(fd); } } static int setupSCSI(struct installState * state) { return setupSCSIInterfaces(0, &state->dl); } static int useNewFdisk(int * useNew) { int rc; rc = newtWinTernary("Disk Setup", "Disk Druid", "fdisk", "Cancel", "Disk Druid is a tool for partitioning and setting up mount " "points. It is designed to be easier to use than Linux's " "traditional disk partitioning sofware, fdisk, as well " "as more powerful. However, there are some cases where fdisk " "may be preferred.\n\n" "Which tool would you like to use?"); if (rc == 3) return INST_CANCEL; if (rc == 0 || rc == 1) *useNew = 1; else *useNew = 0; return 0; } static int partitionDisks(struct installState * state) { int rc = 0; char ** drives; int useNew; int numDrives; if (state->isUpgrade) return findAllPartitions(NULL, &state->table); #if defined(__i386__) || defined(__alpha__) if (kickstart) { if ((rc = getDriveList(&drives, &numDrives))) return rc; return kickstartPartitioning(&state->table, &state->fstab, drives); } #endif do { #if defined(__i386__) || defined(__alpha__) if ((rc = useNewFdisk(&useNew))) return rc; #else useNew = 0; #endif if (useNew) { #if defined(__i386__) || defined(__alpha__) if ((rc = getDriveList(&drives, &numDrives))) return rc; if ((rc = FSEditPartitions(&state->table, &state->fstab, drives, &state->intf, &state->netc, &state->dl))) return rc; #endif } else { do { if ((rc = partitionDrives())) return rc; if ((rc = findAllPartitions(NULL, &state->table))) return rc; rc = setupMountTable(state->table, &state->fstab, &state->intf, &state->netc, &state->dl); if (rc) return rc; } while (rc); } } while (rc); return rc; } static int findInstallFiles(struct installState * state) { int rc; if (!state->table.parts) { rc = findAllPartitions(NULL, &state->table); if (rc) return rc; } if (state->method->prepareRoot) { rc = state->method->prepareRoot(state->method, state->table, &state->netc, &state->intf, &state->dl); if (rc) return rc; } if ((rc = state->method->getPackageSet(state->method, &state->ps))) return rc; if ((state->method->getComponentSet(state->method, &state->ps, &state->cs)) ) return rc; return 0; } static int formatPartitions(struct installState * state) { int i; if (kickstart) { for (i = 0; i < state->fstab.numEntries; i++) { if (state->fstab.entries[i].type == PART_EXT2) state->fstab.entries[i].doFormat = 1; } return 0; } return queryFormatFilesystems(&state->fstab); } static int setupSwap(struct installState * state) { return activeSwapSpace(&state->table, &state->fstab); } static int choosePackages(struct installState * state) { return psSelectPackages(&state->ps, &state->cs, 0, 0); } static int doInstallStep(struct installState * state) { int rc; char * netSharedPath = NULL; FILE * f; int netSharedLength; int i; if (!state->isUpgrade) { if (!kickstart) { rc = newtWinChoice("Install log", "Ok", "Cancel", "A complete log " "of your installation will be in /tmp/install.log " "after rebooting your system. You may want to keep " "this file for later reference."); if (rc == 1) return INST_CANCEL; } rc = formatFilesystems(&state->fstab); if (rc) return rc; rc = mountFilesystems(&state->fstab); if (rc) return rc; if (state->method->prepareMedia) { rc = state->method->prepareMedia(state->method, &state->fstab); if (rc) { umountFilesystems(&state->fstab); return rc; } } } else { if (!kickstart) { rc = newtWinChoice("Upgrade log", "Ok", "Cancel", "A complete log " "of your upgrade will be in /tmp/upgrade.log when " "the upgrade is finished. After rebooting, please " "read it to ensure configuration files are properly " "updated."); if (rc == 1) return INST_CANCEL; } } /* FIXME: should this read the net shared path from /etc/rpmrc during upgrades??? Probably. */ for (i = netSharedLength = 0; i < state->fstab.numEntries; i++) if (state->fstab.entries[i].type == PART_NFS) netSharedLength += 1 + strlen(state->fstab.entries[i].mntpoint); if (netSharedLength) { netSharedPath = alloca(netSharedLength); *netSharedPath = '\0'; for (i = netSharedLength = 0; i < state->fstab.numEntries; i++) { if (state->fstab.entries[i].type == PART_NFS) { if (*netSharedPath) strcat(netSharedPath, ":"); strcat(netSharedPath, state->fstab.entries[i].mntpoint); } } logMessage("netSharedPath is: %s\n", netSharedPath); } rc = doInstall(state->method, &state->ps, netSharedPath, state->keyboard, state->isUpgrade); if (netSharedPath && access("/mnt/etc/rpmrc", X_OK)) { logMessage("creating /etc/rpmrc for netshared info (as none exists)"); f = fopen("/mnt/etc/rpmrc", "w"); if (!f) { errorWindow("error creating /mnt/etc/rpmrc: %s"); } else { fprintf(f, "netsharedpath: %s\n", netSharedPath); fclose(f); } } sync(); sync(); if (!rc) psFreeComponentSet(&state->cs); configPCMCIA(state->pcmcia); return rc; } static char mksalt(int seed) { int num = seed % 64; if (num < 26) return 'a' + num; else if (num < 52) return 'A' + (num - 26); else if (num < 62) return '0' + (num - 52); else if (num == 63) return '.'; else return '/'; } static int setRootPassword(struct installState * state) { newtComponent form = NULL, text, pw1Entry, pw2Entry; char * pw1 = NULL, * pw2; int done = 0; char salt[3]; char cmd[200]; struct timeval time1, time2; char * pw; pid_t pid; int status, rc; char ** argv; int argc; poptContext optCon; int skipCrypt = 0; struct poptOption ksOptions[] = { { "iscrypted", '\0', POPT_ARG_NONE, &skipCrypt, 0 }, { 0, 0, 0, 0, 0 } }; if (kickstart) { if (!ksGetCommand(KS_CMD_ROOTPW, NULL, &argc, &argv)) { optCon = poptGetContext(NULL, argc, argv, ksOptions, 0); if ((rc = poptGetNextOpt(optCon)) < -1) { newtWinMessage("rootpw command", "Ok", "bad argument to kickstart rootpw command %s: %s", poptBadOption(optCon, POPT_BADOPTION_NOALIAS), poptStrerror(rc)); } if (!(pw1 = poptGetArg(optCon))) { newtWinMessage("rootpw command", "Ok", "Missing password"); skipCrypt = 0; } if (poptGetArg(optCon)) newtWinMessage("rootpw command", "Ok", "Unexpected arguments"); poptFreeContext(optCon); } } if (!pw1) { gettimeofday(&time1, NULL); newtCenteredWindow(50, 14, "Root Password"); form = newtForm(NULL, NULL, 0); text = newtTextbox(1, 1, 47, 5, NEWT_TEXTBOX_WRAP); newtTextboxSetText(text, "Pick a root password. You must type it twice to ensure you know " "what it is and didn't make a mistake in typing. Remember that the " "root password is a critical part of system security!"); newtFormAddComponent(form, newtLabel(3, 7, "Password :")); newtFormAddComponent(form, newtLabel(3, 8, "Password (again):")); pw1Entry = newtEntry(21, 7, "", 24, &pw1, NEWT_ENTRY_HIDDEN); pw2Entry = newtEntry(21, 8, "", 24, &pw2, NEWT_ENTRY_HIDDEN); newtFormAddComponents(form, text, pw1Entry, pw2Entry, NULL); newtFormAddComponent(form, newtButton(20, 10, "Ok")); do { newtFormSetCurrent(form, pw1Entry); newtRunForm(form); if (testing) { done = 1; } else if (strcmp(pw1, pw2)) { newtWinMessage("Password Mismatch", "Ok", "The passwords you entered were different. Please " "try again."); newtEntrySet(pw1Entry, "", 0); newtEntrySet(pw2Entry, "", 0); } else if (strlen(pw1) < 6) { newtWinMessage("Password Mismatch", "Ok", "The root password must be at least 6 characters " "long."); newtEntrySet(pw1Entry, "", 0); newtEntrySet(pw2Entry, "", 0); } else done = 1; } while (!done); newtPopWindow(); } if (testing) return 0; if (!skipCrypt) { gettimeofday(&time2, NULL); salt[0] = mksalt(time1.tv_usec); salt[1] = mksalt(time2.tv_usec); salt[2] = '\0'; pw = crypt(pw1, salt); } else { pw = pw1; } sprintf(cmd, "/bin/sed 's&root::&root:%s:&' < /etc/passwd > " "/etc/passwd.new", pw); if (!kickstart) newtFormDestroy(form); if (!(pid = fork())) { chroot("/mnt"); chdir("/mnt"); exit(system(cmd)); } waitpid(pid, &status, 0); unlink("/mnt/etc/passwd"); rename("/mnt/etc/passwd.new", "/mnt/etc/passwd"); return 0; } static int configureTimezone(struct installState * state) { return timeConfig(); } static int configureServices(struct installState * state) { return servicesConfig(); } static int setupBootloader(struct installState * state) { static int first = 1; #ifdef __alpha int rc; #else int rc; int append = 0; char * version; int i; #endif if (!state->isUpgrade && first) { writeFstab(&state->fstab); setupSerialConsole(); } #ifdef __alpha__ if (first) { first = 0; rc = kernelCopy(state->kernel); if (rc) return rc; } return INST_NOP; #else first = 0; if (state->isUpgrade && !access("/mnt/etc/conf.modules", X_OK)) { rc = readModuleConfPersist("/mnt/etc", state->dl); if (rc) return rc; append = 1; } writeModuleConf("/mnt/etc", state->dl, 1); for (i = 0; i < state->ps.numPackages; i++) { if (!strncmp(state->ps.packages[i]->name, "kernel", 6)) break; } if (i == state->ps.numPackages) { errorWindow("I couldn't find a kernel!"); return INST_ERROR; } headerGetEntry(state->ps.packages[i]->h, RPMTAG_VERSION, NULL, (void *) &version, NULL); logMessage("installed kernel version %s", version); /* installLilo installs silo on the SPARC */ return installLilo("/mnt/etc", state->table, state->fstab, version); #endif } static int finishNetworking(struct installState * state) { int rc; rc = checkNetConfig(&state->intf, &state->netc, &state->dl); if (rc) return rc; writeNetConfig("/mnt/etc/sysconfig", &state->netc, &state->intf, 0); writeNetInterfaceConfig("/mnt/etc/sysconfig/network-scripts", &state->intf); writeResolvConf("/mnt/etc", &state->netc); writeHosts("/mnt/etc", &state->netc, &state->intf); return 0; } static int selectPath(struct installState * state) { int result; memset(state, 0, sizeof(state)); if (kickstart) { if (!ksGetCommand(KS_CMD_UPGRADE, NULL, NULL, NULL)) { state->steps = upgradeSteps; state->isUpgrade = 1; } else { state->steps = installSteps; } return 0; } result = newtWinChoice("Installation Path", "Install", "Upgrade", "Would you like to install a new system or upgrade a system which " "already contains Red Hat 2.0 or later?"); if (result == 1) { state->steps = upgradeSteps; state->isUpgrade = 1; } else state->steps = installSteps; return 0; } static int upgrFindInstall(struct installState * state) { int rc; /* this also turns on swap for us */ rc = readMountTable(state->table, &state->fstab); if (rc) return rc; if (!testing) { mountFilesystems(&state->fstab); if (state->method->prepareMedia) { rc = state->method->prepareMedia(state->method, &state->fstab); if (rc) { umountFilesystems(&state->fstab); return rc; } } } return 0; } static int upgrChoosePackages(struct installState * state) { int firstTime = 1; char * rpmconvertbin; int rc; char * path; char * argv[] = { NULL, NULL }; if (testing) path = "/"; else path = "/mnt"; if (firstTime) { if (access("/mnt/var/lib/rpm/packages.rpm", R_OK)) { if (access("/mnt/var/lib/rpm/packages", R_OK)) { errorWindow("No RPM database exists!"); return INST_ERROR; } if (state->method->getFile(state->method, "rpmconvert", &rpmconvertbin, 1)) { return INST_ERROR; } symlink("/mnt/var", "/var"); winStatus(35, 3, "Upgrade", "Converting RPM database..."); chmod(rpmconvertbin, 0755); argv[0] = rpmconvertbin; rc = runProgram(RUN_LOG, rpmconvertbin, argv); if (state->method->rmFiles) unlink(rpmconvertbin); newtPopWindow(); if (rc) return INST_ERROR; } winStatus(35, 3, "Upgrade", "Finding packages to upgrade..."); rc = ugFindUpgradePackages(&state->ps, path); newtPopWindow(); if (rc) return rc; firstTime = 0; psVerifyDependencies(&state->ps, 1); } return psSelectPackages(&state->ps, &state->cs, 0, 1); } #define DO_RETRY 1 #define DO_NEXT 2 #define DO_PREV 3 #define DO_MENU 4 static int errcanChoices(char * name, int wasCancelled) { newtComponent form, retry, previous, menu, text, exitb, answer; char textBuf[1000]; if (wasCancelled) { sprintf(textBuf, "You cancelled step \"%s\".\n\n", name); newtCenteredWindow(50, 16, "Cancelled"); } else { sprintf(textBuf, "An error occured during step \"%s\" of the " "install.\n\n", name); newtCenteredWindow(50, 16, "Error"); } form = newtForm(NULL, NULL, 0); strcat(textBuf, "You may retry that step, return to the previous step " "in the install, or see a menu of installation steps " "which will allow you to move around in the install " "more freely. It is not recommended to use the menu " "unless you are already familiar with Red Hat Linux. " "What would you like to do?"); text = newtTextbox(1, 1, 48, 10, NEWT_TEXTBOX_WRAP); newtTextboxSetText(text, textBuf); if (testing) { previous = newtButton(1, 12, "Previous"); retry = newtButton(15, 12, "Retry"); menu = newtButton(28, 12, "Menu"); exitb = newtButton(39, 12, "Exit"); newtFormAddComponents(form, text, previous, retry, menu, exitb, NULL); } else { previous = newtButton(5, 12, "Previous"); retry = newtButton(20, 12, "Retry"); menu = newtButton(38, 12, "Menu"); newtFormAddComponents(form, text, previous, retry, menu, NULL); } answer = newtRunForm(form); newtPopWindow(); newtFormDestroy(form); if (answer == previous) return DO_PREV; else if (answer == retry) return DO_RETRY; else if (answer == menu) return DO_MENU; newtFinished(); exit(0); } static int stepMenu(struct installState * state, int currStep) { newtComponent form, listbox, okay, text; int firstStep = currStep; long i; int numChoices, listHeight; char buf[200]; newtCenteredWindow(50, 16, "Installation Steps"); while (state->steps[firstStep].prev != -1) firstStep = state->steps[firstStep].prev; form = newtForm(NULL, NULL, 0); i = firstStep, numChoices = 0; do { numChoices++; i = state->steps[i].next; } while (state->steps[i].prev != -1 && state->steps[i].next != STEP_DONE); numChoices++; if (numChoices > 6) listHeight = 6; else listHeight = 0; listbox = newtListbox(10, 4, listHeight, NEWT_LISTBOX_RETURNEXIT); text = newtTextbox(1, 1, 48, 3, NEWT_TEXTBOX_WRAP); newtTextboxSetText(text, "What step would you like to run? Steps with a * next " "to them have already been completed."); newtListboxAddEntry(listbox, " Continue with install", (void *) STEP_DONE + 1); for (i = firstStep; i < (firstStep + numChoices); i++) { if (state->steps[i].completed) strcpy(buf, "* "); else strcpy(buf, " "); strcat(buf, state->steps[i].name); newtListboxAddEntry(listbox, buf, (void *) i); } okay = newtButton(23, 11, "Ok"); newtFormAddComponents(form, text, listbox, okay, NULL); newtRunForm(form); i = (long) newtListboxGetCurrent(listbox); newtFormDestroy(form); newtPopWindow(); if (i == STEP_DONE + 1) return -1; return i; } static int getNextStep(struct installState * state, int lastStep, int lastrc) { int choice; int nextStep; if (state->lastChoice == DO_MENU) choice = DO_MENU; else if (lastrc == INST_ERROR) { choice = errcanChoices(state->steps[lastStep].name, 0); kickstart = 0; } else if (lastrc == INST_CANCEL) { choice = errcanChoices(state->steps[lastStep].name, 1); } else if (lastrc == INST_NOP) { choice = state->lastChoice; } else { choice = DO_NEXT; } switch (choice) { case DO_PREV: nextStep = state->steps[lastStep].prev; while (nextStep != -1 && state->steps[nextStep].skipOnCancel && state->steps[nextStep].prev != -1) nextStep = state->steps[nextStep].prev; if (nextStep == -1 || nextStep == lastStep) { newtWinMessage("Cancelled", "Ok", "I can't go to the previous step" " from here. You will have to try again."); nextStep = lastStep; } break; case DO_RETRY: nextStep = lastStep; break; case DO_MENU: nextStep = stepMenu(state, lastStep); if (nextStep == -1) { choice = DO_NEXT; if (lastrc) nextStep = lastStep; else nextStep = state->steps[lastStep].next; } break; case DO_NEXT: default: nextStep = state->steps[lastStep].next; break; } state->lastChoice = choice; return nextStep; } void doSuspend(void) { pid_t pid; int status; if (testing) { newtFinished(); exit(1); } newtSuspend(); if (!(pid = fork())) { printf("\n\nType to return to the install program.\n\n"); execl("/bin/sh", "-/bin/sh", NULL); perror("error execing /bin/sh"); sleep(5); exit(1); } waitpid(pid, &status, 0); newtResume(); } static void setupSerialConsole(void) { int first = 1; struct stat sb; char * argv[10] = { "/usr/sbin/setconsole", "--speed", NULL, NULL, NULL }; struct termios tos; speed_t speed; if (!first) return; first = 0; if (fstat(0, &sb)) { logMessage("error stat'ing stdin: %s", strerror(errno)); return; } if (!S_ISCHR(sb.st_mode)) { logMessage("stdin isn't a character device!!! ack!"); return; } if (major(sb.st_rdev) != 4) { if (minor(sb.st_rdev) == 64) argv[3] = "ttya"; else argv[3] = "ttyb"; tcgetattr(0, &tos); speed = cfgetospeed(&tos); switch (speed) { case B38400: argv[2] = "38400"; break; case B19200: argv[2] = "19200"; break; default: argv[2] = "9600"; break; } if (access("/mnt/usr/sbin/setconsole", X_OK)) { logMessage("/mnt/usr/sbin/setconsole does not exist -- skipping"); return; } logMessage("setting up %s as serial console, speed is %s", argv[3], argv[2]); runProgramRoot(RUN_LOG, "/mnt", "/usr/sbin/setconsole", argv); } } static int configurePrinter(struct installState * state) { if (kickstart) return 0; else if (testing) { return doConfigurePrinters("/"); } else if (!access("/mnt/usr/bin/lpr", X_OK)) { return doConfigurePrinters("/mnt"); } return INST_NOP; } int main(int argc, char ** argv) { char ** argptr; int step = STEP_FIRST; int rc = 0; struct installState state; int i; int isForce = 0; int len = strlen(argv[0]); char * spaces; int isRescue = 0; DIR * dir; struct dirent * ent; char * kickstartFile = NULL; spaces = strdup(" "); if (!strcmp(argv[0] + len - 6, "umount")) { return umountCommand(argc, argv); } else if (!strcmp(argv[0] + len - 5, "mount")) { return mountCommand(argc, argv); } else if (!strcmp(argv[0] + len - 5, "mkdir")) { return mkdirCommand(argc, argv); } else if (!strcmp(argv[0] + len - 5, "mknod")) { return mknodCommand(argc, argv); } else if (!strcmp(argv[0] + len - 3, "cat")) { return catCommand(argc, argv); } else if (!strcmp(argv[0] + len - 2, "rm")) { return rmCommand(argc, argv); } else if (!strcmp(argv[0] + len - 5, "chmod")) { return chmodCommand(argc, argv); } else if (!strcmp(argv[0] + len - 5, "lsmod")) { return lsmodCommand(argc, argv); } else if (!strcmp(argv[0] + len - 6, "mkswap")) { return mkswapCommand(argc, argv); } else if (!strcmp(argv[0] + len - 6, "swapon")) { return swaponCommand(argc, argv); } /* if this fails, it's okay -- it might help with free space though */ unlink("/sbin/install"); newtSetSuspendCallback(doSuspend); memset(&state, 0, sizeof(state)); state.steps = installSteps; /* blind guess */ argptr = argv + 1; while (*argptr) { if (!strcmp(*argptr, "--method")) { argptr++; if (!*argptr) { fprintf(stderr, "--method requires argument\n"); exit(1); } state.method = findInstallMethod(*argptr); if (!state.method) { fprintf(stderr, "unknown install method: %s\n", *argptr); exit(1); } } else if (!strcmp(*argptr, "--force")) { isForce = 1; } else if (!strcmp(*argptr, "--kickstart") || !strcmp(*argptr, "--ks")) { argptr++; if (!*argptr) fprintf(stderr, "--kickstart requires argument\n"); kickstartFile = *argptr; } else if (!strcmp(*argptr, "--rescue")) { isRescue = 1; } else if (!strcmp(*argptr, "--expert")) { expert = 1; } else if (!strcmp(*argptr, "--test")) { testing = 1; } else if (!strcmp(*argptr, "--pcmcia")) { argptr++; if (!*argptr) { fprintf(stderr, "--pcmcia requires argument\n"); exit(1); } state.pcmcia = *argptr; } else if (!strcmp(*argptr, "--kernel")) { argptr++; if (!*argptr) { fprintf(stderr, "--kernel requires argument\n"); exit(1); } state.kernel = *argptr; } else { /* skipping unknown arguments allows for future expansion */ fprintf(stderr, "unknown argument: %s\n", *argptr); } argptr++; } if (!isRescue && !state.method) { fprintf(stderr, "--method argument is required\n"); exit(1); } if (!testing && !isForce && (getpid() > 50)) { fprintf(stderr, "you're running me on a live system! that's "); fprintf(stderr, "incredibly stupid.\n"); exit(1); } fprintf(stderr, "in second stage install\n"); openLog(); logMessage("second stage install running (version " VERSION " built " __DATE__ " " __TIME__ ")"); logDebugMessage(("extra log messages are enabled")); spawnShell(); newtInit(); newtCls(); newtDrawRootText(0, 0, "Red Hat Linux (C) 1997 Red Hat Software"); newtPushHelpLine(NULL); if (isRescue) { do { rc = setupSCSIInterfaces(0, &state.dl); } while (rc); /* cut! we're out of here */ newtFinished(); execl("/bin/sh", "-/bin/sh", NULL); fprintf(stderr, "ack! I couldn't manage to execl() /bin/sh: %s", strerror(errno)); while (1); } readNetConfig("/tmp", &state.netc); dir = opendir("/tmp"); if (!dir) logMessage("failed to open directory /tmp: %s", strerror(errno)); else { errno = 0; while ((ent = readdir(dir))) { if (!strncmp("ifcfg-", ent->d_name, 6)) break; } if (!ent && errno) { logMessage("error reading directory entry: %s", strerror(errno)); } else if (ent) { logMessage("found network config file %s", ent->d_name); readNetInterfaceConfig("/tmp", ent->d_name + 6, &state.intf); } } closedir(dir); readModuleConf("/tmp", &state.dl); /* make sure we don't pick up any gunk from the outside world */ putenv("PATH=/usr/bin:/bin:/sbin:/usr/sbin"); putenv("LD_LIBRARY_PATH="); if (kickstartFile) { if (ksReadCommands(kickstartFile)) kickstartFile = NULL; else kickstart = 1; #ifndef __sparc__ setupKeyboard(&state.keyboard); #endif } else { #ifndef __sparc__ readKbdConfig("/tmp", &state.keyboard); #endif } while (step != STEP_DONE) { i = strlen(state.steps[step].name); newtDrawRootText(0, 0 - i, state.steps[step].name); newtRefresh(); rc = state.steps[step].fn(&state); if (!rc) state.steps[step].completed = 1; spaces[i] = '\0'; newtDrawRootText(0, 0 - i, spaces); spaces[i] = ' '; step = getNextStep(&state, step, rc); } if (kickstart) ksRunPost(); newtDrawRootText(0, 72, "Complete"); newtWinMessage("Done", "Ok", "Congratulations, installation is complete.\n\n" "Remove the floppy from the drive and " "press return to reboot. For information on fixes which are " "available for this release of Red Hat Linux, consult the " "Errata available from http://www.redhat.com.\n\n" "Information on configuring your system is available in the post " "install chapter of the Official Red Hat Linux User's Guide."); umountFilesystems(&state.fstab); newtFinished(); return 0; }