home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Chip 1998 February
/
CHIP_2_98.iso
/
misc
/
src
/
install
/
install2.c
< prev
next >
Wrap
C/C++ Source or Header
|
1997-11-10
|
31KB
|
1,205 lines
/*
* 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 <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <newt.h>
#include <popt.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/sysmacros.h>
#include <sys/time.h>
#include <sys/wait.h>
#include <termios.h>
#include <unistd.h>
#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 <exit> 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;
}