#include #include #include #include #include #include #include #include #include #include #include "devices.h" #include "install.h" #include "intl.h" #include "lilo.h" #include "log.h" #include "run.h" #include "windows.h" #include "smp.h" #define KERNEL_IMAGE "/boot/vmlinuz-%s" #define KERNEL_SMPIMAGE "/boot/vmlinuz-%ssmp" #ifdef __sparc__ #define LILO_BINARY "/mnt/sbin/silo" #else #define LILO_BINARY "/mnt/sbin/lilo" #endif static int mkinitrd(char * kernelVersion, char * initrdImage, int issmp) { char * argv[] = { "/sbin/mkinitrd", "-f", initrdImage, "--ifneeded", kernelVersion, NULL }; int rc = 0; static int alreadyHappened[2] = { 0, 0 }; char ver[60]; if (alreadyHappened[issmp]) return 0; if (issmp) sprintf(ver, "%ssmp", kernelVersion); else sprintf(ver, "%s", kernelVersion); argv[4] = ver; if (loadModule("loop", DRIVER_OTHER, DRIVER_MINOR_NONE, NULL)) return INST_ERROR; winStatus(32, 3, #ifdef __sparc__ _("SILO"), #else _("LILO"), #endif _("Creating initial ramdisk...")); rc = runProgramRoot(RUN_LOG, "/mnt", "/sbin/mkinitrd", argv); newtPopWindow(); removeModule("loop"); if (rc) { unlink("/mnt/boot/initrd"); } else { alreadyHappened[issmp] = 1; } return rc; } static int noSpaceFilter(newtComponent entry, void * data, int ch, int cursor) { if (ch == ' ') return 0; return ch; } #define SKIP_LILO 1000 static int liloWhere(char * hdName, char * bootDevice, char ** where) { char * format = "/dev/%-11s %s"; char ** items; int which = 0, rc; items = alloca(sizeof(*items) * 3); items[0] = alloca(80); items[1] = alloca(80); items[2] = NULL; sprintf(items[0], format, hdName, _("Master Boot Record")); sprintf(items[1], format, bootDevice, _("First sector of boot partition")); #ifdef __i386__ rc = newtWinMenu(_("Lilo Installation"), _("Where do you want to install " "the bootloader?"), 50, 5, 5, 4, items, &which, _("Ok"), _("Skip"), _("Back"), NULL); #elif defined(__sparc__) rc = newtWinMenu(_("SILO Installation"), _("Where do you want to install " "the bootloader?"), 50, 5, 5, 4, items, &which, _("Ok"), _("Skip"), _("Back"), NULL); #endif if (rc == 3) return INST_CANCEL; if (rc == 2) return SKIP_LILO; switch (which) { case 0: *where = hdName; break; case 1: *where = bootDevice; break; } return 0; } static void editBootLabel(struct partition * item) { newtComponent form, entry, okay, cancel, clear, answer; char buf[50]; char * entryValue; newtGrid subgrid, grid, buttons; form = newtForm(NULL, NULL, 0); strcpy(buf, "/dev/"); strcat(buf, item->device); entry = newtEntry(-1, -1, item->bootLabel, 20, &entryValue, NEWT_ENTRY_SCROLL | NEWT_ENTRY_RETURNEXIT); newtEntrySetFilter(entry, noSpaceFilter, NULL); subgrid = newtCreateGrid(2, 2); newtGridSetField(subgrid, 0, 0, NEWT_GRID_COMPONENT, newtLabel(-1, -1, _("Device:")), 0, 0, 0, 0, NEWT_ANCHOR_LEFT, 0); newtGridSetField(subgrid, 1, 0, NEWT_GRID_COMPONENT, newtLabel(-1, -1, buf), 1, 0, 0, 0, NEWT_ANCHOR_LEFT, 0); newtGridSetField(subgrid, 0, 1, NEWT_GRID_COMPONENT, newtLabel(-1, -1, _("Boot label:")), 0, 0, 0, 0, NEWT_ANCHOR_LEFT, 0); newtGridSetField(subgrid, 1, 1, NEWT_GRID_COMPONENT, entry, 1, 0, 0, 0, NEWT_ANCHOR_LEFT, 0); buttons = newtButtonBar(_("Ok"), &okay, _("Clear"), &clear, _("Cancel"), &cancel, NULL); grid = newtCreateGrid(1, 2); newtGridSetField(grid, 0, 0, NEWT_GRID_SUBGRID, subgrid, 0, 0, 0, 0, 0, 0); newtGridSetField(grid, 0, 1, NEWT_GRID_SUBGRID, buttons, 0, 1, 0, 0, 0, NEWT_GRID_FLAG_GROWX); newtGridAddComponentsToForm(grid, form, 1); newtGridWrappedWindow(grid, _("Edit Boot Label")); newtGridFree(grid, 1); 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, char * bootdev, struct partitionTable table, char * append, char * kernelVersion, char * hdname, int linear) { char filename[100]; FILE * f; char * argv[] = { LILO_BINARY, NULL, NULL }; int i; int rc; struct stat sb; int useInitrd = 0; char relinitrdImage[50], absinitrdImage[55]; char buff[1024]; int pass; static int firstTime = 1; static int issmp = 0; char relsmpinitrdImage[50]; int usesmpInitrd = 0; sprintf(relinitrdImage, "/boot/initrd-%s.img", kernelVersion); strcpy(absinitrdImage, "/mnt"); strcat(absinitrdImage, relinitrdImage); if (mkinitrd(kernelVersion, relinitrdImage, 0)) return INST_ERROR; if (testing) return 0; if (!stat(absinitrdImage, &sb)) useInitrd = 1; if ((issmp = detectSMP()) == -1) { logMessage("Error trying to detect SMP machine"); issmp = 0; } if (issmp) { sprintf(buff, "/mnt" KERNEL_SMPIMAGE, kernelVersion); if (stat(buff, &sb)) { logMessage("SMP machine, but no SMP kernel found"); issmp = 0; } } if (issmp) { char abssmpinitrdImage[55]; sprintf(relsmpinitrdImage, "/boot/initrd-%ssmp.img", kernelVersion); if (mkinitrd(kernelVersion, relsmpinitrdImage, 1)) issmp = 0; else { strcpy(abssmpinitrdImage, "/mnt"); strcat(abssmpinitrdImage, relsmpinitrdImage); if (!stat (abssmpinitrdImage, &sb)) usesmpInitrd = 1; } } #ifdef __sparc__ sprintf(filename, "%s/silo.conf", prefix); #else /* !__sparc__ */ sprintf(filename, "%s/lilo.conf", prefix); #endif /* __sparc__ */ /* why not? */ if (firstTime) { rename("/mnt/etc/lilo.conf", "/mnt/etc/lilo.conf.rpmsave"); rename("/mnt/etc/silo.conf", "/mnt/etc/silo.conf.rpmsave"); firstTime = 0; } 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 /* !__sparc__ && !__i386__ */ #error "unsupported architecture"; #endif /* __sparc__ */ 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) { if (issmp) { fprintf(f, "image=" KERNEL_SMPIMAGE "\n", kernelVersion); fprintf(f, "\tlabel=%s\n", table.parts[i].bootLabel); /* remap /boot to root=/, but make sure we set up booting from old root partitions as well */ if (strcmp(bootdev, table.parts[i].device)) fprintf(f, "\troot=/dev/%s\n", table.parts[i].device); #ifndef __sparc__ else fprintf(f, "\troot=/dev/%s\n", rootdev); #endif if (usesmpInitrd) fprintf(f, "\tinitrd=%s\n", relsmpinitrdImage); if (append) fprintf(f, "\tappend=\"%s\"\n", append); fprintf(f, "\tread-only\n"); } fprintf(f, "image=" KERNEL_IMAGE "\n", kernelVersion); if (issmp) fprintf(f, "\tlabel=linux-up\n"); else fprintf(f, "\tlabel=%s\n", table.parts[i].bootLabel); /* remap /boot to root=/, but make sure we set up booting from old root partitions as well */ if (strcmp(bootdev, table.parts[i].device)) fprintf(f, "\troot=/dev/%s\n", table.parts[i].device); #ifndef __sparc__ else fprintf(f, "\troot=/dev/%s\n", rootdev); #endif 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)) { /* boot off the second drive, so reverse the BIOS maps */ fprintf(f, "\tmap-drive=0x80\n"); fprintf(f, "\t to = 0x81\n"); fprintf(f, "\tmap-drive=0x81\n"); fprintf(f, "\t to = 0x80\n"); } #endif } } } fclose(f); winStatus(35, 3, _("Running"), _("Installing boot loader...")); #ifdef __i386__ rc = runProgramRoot(RUN_LOG, "/mnt", "sbin/lilo", argv); #elif __sparc__ if (strcmp(hdname, dev)) argv[1] = "-t"; umount("/mnt/proc"); 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; char * reflowedText; int width, height; newtGrid buttons, grid; reflowedText = newtReflowText( _("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."), 60, -5, -5, &width, &height); text = newtTextbox(-1, -1, width, height, NEWT_TEXTBOX_WRAP); newtTextboxSetText(text, reflowedText); free(reflowedText); f = newtForm(NULL, NULL, 0); sprintf(buf, "%-10s %-25s %-7s %-10s", _("Device"), _("Partition type"), _("Default"), _("Boot label")); label = newtLabel(-1, -1, buf); listbox = newtListbox(-1, -1, 10 - height, NEWT_LISTBOX_RETURNEXIT | NEWT_FLAG_SCROLL); 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) { 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++); } } /* we add stuff to the form here so we can actually destroy it if we don't need this window after all */ newtFormAddComponents(f, text, label, listbox, NULL); if (!mustAsk) { newtFormDestroy(f); return 0; } newtPushHelpLine(" Selects the default partition"); buttons = newtButtonBar(_("Ok"), &okay, _("Edit"), &edit, _("Back"), &cancel, NULL); newtFormAddComponents(f, okay, edit, cancel, NULL); newtFormAddHotKey(f, NEWT_KEY_F2); grid = newtCreateGrid(1, 4); newtGridSetField(grid, 0, 0, NEWT_GRID_COMPONENT, text, 0, 0, 0, 1, NEWT_ANCHOR_LEFT, 0); newtGridSetField(grid, 0, 1, NEWT_GRID_COMPONENT, label, 0, 0, 0, 0, NEWT_ANCHOR_LEFT, 0); newtGridSetField(grid, 0, 2, NEWT_GRID_COMPONENT, listbox, 0, 0, 0, 0, NEWT_ANCHOR_LEFT, 0); newtGridSetField(grid, 0, 3, NEWT_GRID_SUBGRID, buttons, 0, 1, 0, 0, 0, NEWT_GRID_FLAG_GROWX); newtGridWrappedWindow(grid, _("Bootable Partitions")); newtGridFree(grid, 1); 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) ? '*' : ' '; newtGrid grid, buttons, subgrid; text = newtTextboxReflowed(0, 0, _("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."), 53, 10, 0, 0); form = newtForm(NULL, NULL, 0); entry = newtEntry(-1, -1, *line, 48, &result, NEWT_ENTRY_SCROLL | NEWT_ENTRY_RETURNEXIT); #ifndef __sparc__ linearCheck = newtCheckbox(-1, -1, _("Use linear mode (needed for some SCSI drives)"), linearChar, NULL, &linearChar); #endif buttons = newtButtonBar(_("Ok"), &okay, _("Back"), &cancel, NULL); subgrid = newtGridVStacked(NEWT_GRID_COMPONENT, entry, #ifndef __sparc__ NEWT_GRID_COMPONENT, linearCheck, #endif NULL); grid = newtGridBasicWindow(text, subgrid, buttons); newtGridAddComponentsToForm(grid, form, 1); newtFormSetCurrent(form, okay); #ifdef __sparc__ newtGridWrappedWindow(grid, _("Silo Installation")); #else newtGridWrappedWindow(grid, _("Lilo Installation")); #endif newtGridFree(grid, 1); 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, int flags, char * options) { 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; int foundDos = 0; hdName = default_boot_hd; 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; } else if ((table.parts[i].type == PART_DOS || table.parts[i].type == PART_FAT32) && !foundDos) { table.parts[i].bootLabel = strdup("dos"); foundDos = 1; } } if (flags & LILO_ON_MBR) where = hdName; else if (flags & LILO_ON_PARTITION) where = bootDevice; if (flags & LILO_USE_OPTIONS) append = options; if (where) { rc = doinstallLilo(prefix, where, rootDevice, bootDevice, 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, bootDevice, table, append, kernelVersion, hdName, linear); if (rc == INST_ERROR) return INST_ERROR; stage = LILO_DONE; break; } } return 0; } int makeBootdisk(char * prefix, char * kernelVersion) { char * argv[] = { "/sbin/mkbootdisk", "--noprompt", "--device", "/dev/fd0", kernelVersion, NULL }; int rc; #ifdef __sparc__ if (loadModule("romfs", DRIVER_OTHER, DRIVER_MINOR_NONE, NULL)) return INST_ERROR; /* Find out if the only floppy in the system is /dev/fd1 */ rc = open("/mnt/dev/fd0", O_RDONLY); if (rc < 0 && errno == ENXIO) argv[3] = "/dev/fd1"; else if (rc >= 0) close(rc); #endif if (loadModule("loop", DRIVER_OTHER, DRIVER_MINOR_NONE, NULL)) return INST_ERROR; winStatus(32, 3, _("Bootdisk"), _("Creating bootdisk...")); #ifdef __sparc__ umount("/mnt/proc"); rc = doMount("/proc", "/mnt/proc", "proc", 0, 0); if (rc) { newtPopWindow(); removeModule("romfs"); removeModule("loop"); return rc; } #endif rc = runProgramRoot(RUN_LOG, "/mnt", "/sbin/mkbootdisk", argv); newtPopWindow(); #ifdef __sparc__ umount("/mnt/proc"); #endif removeModule("loop"); return rc; }