#include #include #include #include #include #include #include #include #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(" 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; }