home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Chip 1998 February
/
CHIP_2_98.iso
/
misc
/
src
/
install
/
lilo.c
< prev
next >
Wrap
C/C++ Source or Header
|
1997-11-03
|
16KB
|
636 lines
#include <alloca.h>
#include <newt.h>
#include <popt.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <unistd.h>
#include "devices.h"
#include "install.h"
#include "kickstart.h"
#include "lilo.h"
#include "log.h"
#include "run.h"
#include "windows.h"
#ifdef __i386__
#define KERNEL_IMAGE "/boot/vmlinuz-%s"
#elif __sparc__
#define KERNEL_IMAGE "/boot/vmlinux-%s.gz"
#else
#error unsupported architecture
#endif
static int mkinitrd(char * kernelVersion, char * initrdImage) {
char * argv[] = { "/sbin/mkinitrd", "-f", initrdImage, "--ifneeded",
kernelVersion, NULL };
int rc;
static alreadyHappened = 0;
#ifdef __sparc__
return 0;
#endif
if (alreadyHappened) return 0;
if (loadModule("loop", DRIVER_OTHER, DRIVER_MINOR_NONE, NULL))
return INST_ERROR;
winStatus(32, 3, "LILO", "Creating initial ramdisk...");
rc = runProgramRoot(RUN_LOG, "/mnt", "/sbin/mkinitrd", argv);
newtPopWindow();
removeModule("loop");
if (rc) {
unlink("/mnt/boot/initrd");
} else {
alreadyHappened = 1;
}
return rc;
}
#define SKIP_LILO 1000
#if defined(__i386__)
static int liloWhere(char * hdName, char * bootDevice, char ** where) {
newtComponent form, okay, listbox, cancel, answer, skip;
char * format = "/dev/%-7s %s";
char buf[200];
void * which;
newtCenteredWindow(55, 11, "Lilo Installation");
form = newtForm(NULL, NULL, 0);
newtFormAddComponent(form,
newtLabel(1, 1, "Where do you want to install "
"the bootloader?"));
listbox = newtListbox(2, 3, 3, NEWT_LISTBOX_RETURNEXIT);
sprintf(buf, format, hdName,
"Master Boot Record");
newtListboxAddEntry(listbox, buf, (void *) 1);
sprintf(buf, format, bootDevice,
"First sector of boot partition");
newtListboxAddEntry(listbox, buf, (void *) 2);
okay = newtButton(6, 7, "Ok");
skip = newtButton(22, 7, "Skip");
cancel = newtButton(38, 7, "Cancel");
newtFormAddComponents(form, listbox, okay, skip, cancel, NULL);
answer = newtRunForm(form);
which = newtListboxGetCurrent(listbox);
newtFormDestroy(form);
newtPopWindow();
if (answer == cancel) return INST_CANCEL;
if (answer == skip) return SKIP_LILO;
switch ((int) which) {
case 1: *where = hdName; break;
case 2: *where = bootDevice; break;
}
return 0;
}
#elif defined(__sparc__)
static int liloWhere(char * hdName, char * bootDevice, char ** where) {
newtComponent text, yes, no, cancel, f, answer;
int rc;
rc = newtWinTernary("SILO Installation", "Yes", "No", "Cancel",
"Would you like to install or configure the SILO bootloader on "
"your system?");
if (rc == 0 || rc == 1) {
*where = bootDevice;
rc = 0;
} else if (rc == 3) {
rc = INST_CANCEL;
} else {
rc = SKIP_LILO;
}
return rc;
}
#endif
static void editBootLabel(struct partition * item) {
newtComponent form, entry, okay, cancel, clear, answer;
char buf[50];
char * entryValue;
newtCenteredWindow(50, 10, "Edit Boot Label");
form = newtForm(NULL, NULL, 0);
strcpy(buf,"Device : /dev/");
strcat(buf, item->device);
newtFormAddComponent(form, newtLabel(1, 1, buf));
newtFormAddComponent(form, newtLabel(1, 3, "Boot label :"));
entry = newtEntry(17, 3, item->bootLabel, 20, &entryValue,
NEWT_ENTRY_SCROLL | NEWT_ENTRY_RETURNEXIT);
okay = newtButton(5, 6, "Ok");
clear = newtButton(20, 6, "Clear");
cancel = newtButton(35, 6, "Cancel");
newtFormAddComponents(form, entry, okay, clear, cancel, NULL);
do {
answer = newtRunForm(form);
if (answer == clear)
newtEntrySet(entry, "", 1);
} while (answer == clear);
if (answer != cancel) {
if (item->bootLabel) free(item->bootLabel);
if (strlen(entryValue))
item->bootLabel = strdup(entryValue);
else
item->bootLabel = NULL;
}
newtPopWindow();
}
static int doinstallLilo(char * prefix, char * dev, char * rootdev,
struct partitionTable table,
char * append, char * kernelVersion,
char * hdname, int linear) {
char filename[100];
FILE * f;
char * argv[] = { "/mnt/sbin/lilo", NULL };
int i;
int rc;
struct stat sb;
int useInitrd = 0;
char relinitrdImage[50], absinitrdImage[55];
int pass;
sprintf(relinitrdImage, "/boot/initrd-%s.img", kernelVersion);
strcpy(absinitrdImage, "/mnt");
strcat(absinitrdImage, relinitrdImage);
if (mkinitrd(kernelVersion, relinitrdImage))
return INST_ERROR;
if (testing) return 0;
if (!stat(absinitrdImage, &sb))
useInitrd = 1;
#ifdef __sparc__
sprintf(filename, "%s/silo.conf", prefix);
#else
sprintf(filename, "%s/lilo.conf", prefix);
#endif
/* why not? */
rename("/mnt/etc/lilo.conf", "/mnt/etc/lilo.conf.orig");
rename("/mnt/etc/silo.conf", "/mnt/etc/silo.conf.orig");
f = fopen(filename, "w");
if (!f) {
errorWindow("cannot create [ls]ilo config file: %s");
return INST_ERROR;
}
logMessage("writing [sl]ilo config to %s", filename);
#ifdef __i386__
fprintf(f, "boot=/dev/%s\n", dev);
fprintf(f, "map=/boot/map\n");
fprintf(f, "install=/boot/boot.b\n");
fprintf(f, "prompt\n");
if (linear) fprintf(f, "linear\n");
fprintf(f, "timeout=50\n");
#elif __sparc__
fprintf(f, "timeout=50\n");
fprintf(f, "partition=%s\n", rootdev + 3);
fprintf(f, "root=/dev/%s\n", rootdev);
#else
#error "unsupported architecture";
#endif
for (pass = 0; pass < 2; pass++) {
for (i = 0; i < table.count; i++) {
if (!table.parts[i].bootLabel) continue;
if (pass == 0 && !table.parts[i].defaultBoot) continue;
if (pass == 1 && table.parts[i].defaultBoot) continue;
if (table.parts[i].type == PART_EXT2) {
fprintf(f, "image=" KERNEL_IMAGE "\n", kernelVersion);
fprintf(f, "\tlabel=%s\n", table.parts[i].bootLabel);
fprintf(f, "\troot=/dev/%s\n", rootdev);
if (useInitrd)
fprintf(f, "\tinitrd=%s\n", relinitrdImage);
if (append) fprintf(f, "\tappend=\"%s\"\n", append);
fprintf(f, "\tread-only\n");
#ifdef __i386__
} else {
fprintf(f, "other=/dev/%s\n", table.parts[i].device);
fprintf(f, "\tlabel=%s\n", table.parts[i].bootLabel);
fprintf(f, "\ttable=/dev/%.3s\n", table.parts[i].device);
if (strncmp(table.parts[i].device, hdname, 3))
fprintf(f, "\tloader=/boot/any_d.b\n");
#endif
}
}
}
fclose(f);
winStatus(35, 3, "Running", "Installing boot loader...");
#ifdef __i386__
rc = runProgramRoot(RUN_LOG, "/mnt", "sbin/lilo", argv);
#elif __sparc__
rc = doMount("/proc", "/mnt/proc", "proc", 0, 0);
if (rc) {
newtPopWindow();
return rc;
}
rc = runProgramRoot(RUN_LOG, "/mnt", "sbin/silo", argv);
umount("/mnt/proc");
#else
#error unsupported architectures
#endif
newtPopWindow();
if (rc)
return INST_ERROR;
return 0;
}
static void formatEntry(char * buf, struct partition * part) {
sprintf(buf, "/dev/%-5s %-25s %-7s %-10s", part->device,
part->tagName,
part->defaultBoot ? " *" : "",
part->bootLabel ? part->bootLabel : "");
}
static int getBootLabels(struct partitionTable table, struct fstab fstab) {
newtComponent f, okay, text, listbox, label, cancel, edit;
struct newtExitStruct answer;
char buf[80];
int i, j;
int foundDos = 0;
int mustAsk = 0;
int * map;
struct partition * curr;
int * currNum;
int count;
int done;
int defaultBootPart = 0;
f = newtForm(NULL, NULL, 0);
text = newtTextbox(1, 1, 60, 4, NEWT_TEXTBOX_WRAP);
newtTextboxSetText(text,
"The boot manager Red Hat uses can boot other "
"operating systems as well. You need to tell me "
"what partitions you would like to be able to boot "
"and what label you want to use for each of them.");
sprintf(buf, "%-10s %-25s %-7s %-10s", "Device", "Partition type",
"Default", "Boot label");
label = newtLabel(1, 6, buf);
listbox = newtListbox(0, 7, 7, NEWT_LISTBOX_RETURNEXIT);
map = alloca(sizeof(int) * table.count);
for (i = 0, count = 0; i < table.count; i++) {
if (table.parts[i].type != PART_SWAP &&
table.parts[i].type != PART_IGNORE &&
#ifdef __sparc__
table.parts[i].type != PART_OTHER &&
#endif
(table.parts[i].type != PART_FAT32 || !foundDos) &&
(table.parts[i].type != PART_DOS || !foundDos)) {
if (table.parts[i].type == PART_DOS ||
table.parts[i].type == PART_FAT32) {
table.parts[i].bootLabel = strdup("dos");
foundDos = 1;
}
if (table.parts[i].type == PART_EXT2) {
for (j = 0; j < fstab.numEntries; j++) {
if (!strcmp(table.parts[i].device, fstab.entries[j].device))
break;
}
if (j < fstab.numEntries && !table.parts[i].bootLabel)
continue;
}
if (!table.parts[i].bootLabel ||
strcmp(table.parts[i].bootLabel, "linux")) mustAsk = 1;
if (table.parts[i].defaultBoot)
defaultBootPart = count;
map[count] = i;
formatEntry(buf, table.parts + i);
newtListboxAddEntry(listbox, buf, map + count++);
}
}
newtFormAddComponents(f, text, label, listbox, NULL);
if (!mustAsk) {
newtFormDestroy(f);
return 0;
}
newtCenteredWindow(64, 19, "Bootable Partitions");
newtPushHelpLine("<F2> Selects the default partition");
okay = newtButton(8, 15, "Ok");
edit = newtButton(26, 15, "Edit");
cancel = newtButton(44, 15, "Cancel");
newtFormAddComponents(f, okay, edit, cancel, NULL);
newtFormAddHotKey(f, NEWT_KEY_F2);
done = 0;
while (!done) {
newtFormRun(f, &answer);
if (answer.reason == NEWT_EXIT_HOTKEY) {
if (answer.u.key == NEWT_KEY_F12) {
done = 1;
} else if (answer.u.key == NEWT_KEY_F2) {
currNum = newtListboxGetCurrent(listbox);
curr = table.parts + *currNum;
if (!curr->bootLabel) {
newtWinMessage("Boot Partition", "Ok", "You cannot mark a "
"partition as the default partition to "
"boot from unless that partition has "
"been assigned a boot label.");
} else{
for (i = 0; i < count; i++) {
if (table.parts[map[i]].defaultBoot) {
table.parts[map[i]].defaultBoot = 0;
formatEntry(buf, table.parts + map[i]);
newtListboxSetEntry(listbox, i, buf);
break;
}
}
curr->defaultBoot = 1;
formatEntry(buf, curr);
newtListboxSetEntry(listbox, currNum - map, buf);
}
}
} else {
if (answer.u.co == edit || answer.u.co== listbox) {
currNum = newtListboxGetCurrent(listbox);
curr = table.parts + *currNum;
editBootLabel(curr);
if (!curr->bootLabel && curr->defaultBoot) {
curr->defaultBoot = 0;
if (table.parts[map[defaultBootPart]].bootLabel) {
table.parts[map[defaultBootPart]].defaultBoot = 1;
formatEntry(buf, table.parts + map[defaultBootPart]);
newtListboxSetEntry(listbox, defaultBootPart, buf);
}
}
formatEntry(buf, curr);
newtListboxSetEntry(listbox, currNum - map, buf);
} else
done = 1;
}
}
newtPopHelpLine();
newtFormDestroy(f);
newtPopWindow();
if (answer.reason == NEWT_EXIT_COMPONENT && answer.u.co == cancel)
return INST_CANCEL;
else
return 0;
}
static int getAppendLine(char ** line, int * linear) {
newtComponent form, text, entry, okay, cancel, answer;
newtComponent linearCheck;
char * result = NULL;
char linearChar = (*linear) ? '*' : ' ';
int buttonLine = 9;
#ifdef __sparc__
newtCenteredWindow(55, 13, "Silo Installation");
#else
/* this is bigger on the Intel to leave room for the linear checkbox */
newtCenteredWindow(55, 15, "Lilo Installation");
#endif
form = newtForm(NULL, NULL, 0);
text = newtTextbox(1, 1, 53, 5, NEWT_TEXTBOX_WRAP);
newtTextboxSetText(text,
"A few systems will need to pass special options "
"to the kernel at boot time for the system to function "
"properly. If you need to pass boot options to the "
"kernel, enter them now. If you don't need any or "
"aren't sure, leave this blank.");
entry = newtEntry(1, 7, *line, 48, &result,
NEWT_ENTRY_SCROLL | NEWT_ENTRY_RETURNEXIT);
#ifndef __sparc__
buttonLine = 11;
linearCheck = newtCheckbox(1, 9,
"Use linear mode (needed for some SCSI drives)",
linearChar, NULL, &linearChar);
#endif
okay = newtButton(12, buttonLine, "Ok");
cancel = newtButton(35, buttonLine, "Cancel");
newtFormAddComponents(form, text, entry, NULL);
#ifndef __sparc__
newtFormAddComponent(form, linearCheck);
#endif
newtFormAddComponents(form, okay, cancel, NULL);
newtFormSetCurrent(form, okay);
answer = newtRunForm(form);
newtPopWindow();
if (answer == cancel) {
newtFormDestroy(form);
return INST_CANCEL;
}
*linear = linearChar != ' ';
if (!strlen(result))
*line = NULL;
else
*line = strdup(result);
newtFormDestroy(form);
return 0;
}
#define LILO_WHERE 2
#define LILO_LABELS 3
#define LILO_INSTALL 4
#define LILO_APPEND 5
#define LILO_DONE 20
int installLilo(char * prefix, struct partitionTable table,
struct fstab fstab, char * kernelVersion) {
char * rootDevice, * bootDevice = NULL;
char * hdName;
char * where = NULL;
char * append = NULL;
char * chptr = NULL;
int i;
int rc;
int stage = LILO_WHERE;
static int linear = 0;
char ** argv;
int argc;
char * location = NULL;
poptContext optCon;
struct poptOption ksOptions[] = {
{ "append", '\0', POPT_ARG_STRING, &append, 0 },
#ifdef __i386__
{ "linear", '\0', 0, &linear, 0 },
{ "location", '\0', POPT_ARG_STRING, &location, 0 },
#endif
{ 0, 0, 0, 0, 0 }
};
hdName = alloca(4);
strncpy(hdName, table.parts[0].device, 3);
hdName[3] = '\0';
for (i = 0; i < fstab.numEntries; i++) {
if (!strcmp(fstab.entries[i].mntpoint, "/boot")) break;
}
if (i < fstab.numEntries)
bootDevice = fstab.entries[i].device;
for (i = 0; i < fstab.numEntries; i++) {
if (!strcmp(fstab.entries[i].mntpoint, "/")) break;
}
rootDevice = fstab.entries[i].device;
if (!bootDevice) {
bootDevice = rootDevice;
}
for (i = 0; i < table.count; i++) {
if (!strcmp(table.parts[i].device, bootDevice)) {
table.parts[i].bootLabel = strdup("linux");
table.parts[i].defaultBoot = 1;
break;
}
}
if (kickstart) {
if (!ksGetCommand(KS_CMD_LILO, NULL, &argc, &argv)) {
optCon = poptGetContext(NULL, argc, argv, ksOptions, 0);
if ((rc = poptGetNextOpt(optCon)) < -1) {
newtWinMessage("lilo command", "Ok",
"bad argument to kickstart lilo command %s: %s",
poptBadOption(optCon, POPT_BADOPTION_NOALIAS),
poptStrerror(rc));
}
}
if (!location || !strcmp(location, "mbr"))
where = hdName;
else if (!strcmp(location, "partition"))
where = bootDevice;
else if (!strcmp(location, "none"))
return 0;
if (where) {
rc = doinstallLilo(prefix, where, rootDevice, table, append,
kernelVersion, hdName, linear);
if (rc == INST_ERROR) return INST_ERROR;
stage = LILO_DONE;
}
}
while (stage != LILO_DONE) {
switch (stage) {
case LILO_WHERE:
rc = liloWhere(hdName, bootDevice, &where);
if (rc == SKIP_LILO ) return 0;
if (rc) return rc;
stage = LILO_APPEND;
break;
case LILO_APPEND:
chptr = append;
rc = getAppendLine(&chptr, &linear);
if (rc == INST_ERROR) return INST_ERROR;
if (rc == INST_CANCEL)
stage = LILO_WHERE;
else {
stage = LILO_LABELS;
if (append) free(append);
if (chptr) {
append = alloca(strlen(chptr) + 1);
strcpy(append, chptr);
free(chptr);
} else {
append = NULL;
}
}
break;
case LILO_LABELS:
rc = getBootLabels(table, fstab);
if (rc == INST_ERROR) return INST_ERROR;
if (rc == INST_CANCEL)
stage = LILO_APPEND;
else
stage = LILO_INSTALL;
break;
case LILO_INSTALL:
rc = doinstallLilo(prefix, where, rootDevice, table, append,
kernelVersion, hdName, linear);
if (rc == INST_ERROR) return INST_ERROR;
stage = LILO_DONE;
break;
}
}
return 0;
}