home *** CD-ROM | disk | FTP | other *** search
/ PC Plus SuperCD (UK) 1999 May / pcp151c.iso / misc / src / install / lilo.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-10-14  |  17.5 KB  |  678 lines

  1. #include <alloca.h>
  2. #include <newt.h>
  3. #include <popt.h>
  4. #include <stdio.h>
  5. #include <string.h>
  6. #include <stdlib.h>
  7. #include <sys/stat.h>
  8. #include <unistd.h>
  9.  
  10. #include "devices.h"
  11. #include "install.h"
  12. #include "intl.h"
  13. #include "lilo.h"
  14. #include "log.h"
  15. #include "run.h"
  16. #include "windows.h"
  17.  
  18. #define KERNEL_IMAGE "/boot/vmlinuz-%s"
  19.  
  20. static int mkinitrd(char * kernelVersion, char * initrdImage) {
  21.     char * argv[] = { "/sbin/mkinitrd", "-f", initrdImage, "--ifneeded", 
  22.             kernelVersion, NULL };
  23.     int rc;
  24.     static alreadyHappened = 0;
  25.  
  26.     #ifdef __sparc__
  27.     return 0;
  28.     #endif
  29.  
  30.     if (alreadyHappened) return 0;
  31.  
  32.     if (loadModule("loop", DRIVER_OTHER, DRIVER_MINOR_NONE, NULL)) 
  33.     return INST_ERROR;
  34.  
  35.     winStatus(32, 3, _("LILO"), _("Creating initial ramdisk..."));
  36.     rc = runProgramRoot(RUN_LOG, "/mnt", "/sbin/mkinitrd", argv);
  37.     newtPopWindow();
  38.  
  39.     removeModule("loop");
  40.  
  41.     if (rc) {
  42.     unlink("/mnt/boot/initrd");
  43.     } else {
  44.     alreadyHappened = 1;
  45.     }
  46.  
  47.     return rc;
  48. }
  49.  
  50. static int noSpaceFilter(newtComponent entry, void * data, int ch, int cursor) {
  51.     if (ch == ' ')
  52.     return 0;
  53.     return ch;
  54. }
  55.  
  56. #define SKIP_LILO 1000
  57.  
  58. #if defined(__i386__)
  59. static int liloWhere(char * hdName, char * bootDevice, char ** where) {
  60.     char * format = "/dev/%-7s    %s";
  61.     char ** items;
  62.     int which = 0, rc;
  63.  
  64.     items = alloca(sizeof(*items) * 3);
  65.     items[0] = alloca(80);
  66.     items[1] = alloca(80);
  67.     items[2] = NULL;
  68.  
  69.     sprintf(items[0], format, hdName, _("Master Boot Record"));
  70.     sprintf(items[1], format, bootDevice, _("First sector of boot partition"));
  71.  
  72.     rc = newtWinMenu(_("Lilo Installation"), _("Where do you want to install "
  73.                "the bootloader?"), 50, 5, 5, 4, items, &which,
  74.              _("Ok"), _("Skip"), _("Back"), NULL);
  75.  
  76.     if (rc == 3) return INST_CANCEL;
  77.     if (rc == 2) return SKIP_LILO;
  78.  
  79.     switch (which) {
  80.       case 0:         *where = hdName; break;
  81.       case 1:         *where = bootDevice; break;
  82.     }
  83.  
  84.     return 0;
  85. }
  86. #elif defined(__sparc__)
  87. static int liloWhere(char * hdName, char * bootDevice, char ** where) {
  88.     newtComponent text, yes, no, cancel, f, answer;
  89.     int rc;
  90.  
  91.     rc = newtWinTernary(_("SILO Installation"), _("Yes"), _("No"), 
  92.             _("Back"),
  93.         _("Would you like to install or configure the SILO bootloader on "
  94.           "your system?"));
  95.  
  96.     if (rc == 0 || rc == 1) {
  97.         *where = bootDevice; 
  98.     rc = 0;
  99.     } else if (rc == 3) {
  100.     rc = INST_CANCEL;
  101.     } else {
  102.     rc = SKIP_LILO;
  103.     }
  104.  
  105.     return rc;
  106. }
  107. #endif
  108.  
  109. static void editBootLabel(struct partition * item) {
  110.     newtComponent form, entry, okay, cancel, clear, answer;
  111.     char buf[50];
  112.     char * entryValue;
  113.     newtGrid subgrid, grid, buttons;
  114.  
  115.     form = newtForm(NULL, NULL, 0);
  116.  
  117.     strcpy(buf, "/dev/");
  118.     strcat(buf, item->device);
  119.  
  120.     entry = newtEntry(-1, -1, item->bootLabel, 20, &entryValue, 
  121.               NEWT_ENTRY_SCROLL | NEWT_ENTRY_RETURNEXIT);
  122.     newtEntrySetFilter(entry, noSpaceFilter, NULL);
  123.  
  124.  
  125.     subgrid = newtCreateGrid(2, 2);
  126.     newtGridSetField(subgrid, 0, 0, NEWT_GRID_COMPONENT,
  127.              newtLabel(-1, -1, _("Device:")),
  128.              0, 0, 0, 0, NEWT_ANCHOR_LEFT, 0);
  129.     newtGridSetField(subgrid, 1, 0, NEWT_GRID_COMPONENT,
  130.              newtLabel(-1, -1, buf),
  131.              1, 0, 0, 0, NEWT_ANCHOR_LEFT, 0);
  132.     newtGridSetField(subgrid, 0, 1, NEWT_GRID_COMPONENT,
  133.              newtLabel(-1, -1, _("Boot label:")),
  134.              0, 0, 0, 0, NEWT_ANCHOR_LEFT, 0);
  135.     newtGridSetField(subgrid, 1, 1, NEWT_GRID_COMPONENT, entry,
  136.              1, 0, 0, 0, NEWT_ANCHOR_LEFT, 0);
  137.  
  138.     buttons = newtButtonBar(_("Ok"), &okay, _("Clear"), &clear,
  139.                 _("Cancel"), &cancel, NULL);
  140.  
  141.     grid = newtCreateGrid(1, 2);
  142.     newtGridSetField(grid, 0, 0, NEWT_GRID_SUBGRID, subgrid,
  143.              0, 0, 0, 0, 0, 0);
  144.     newtGridSetField(grid, 0, 1, NEWT_GRID_SUBGRID, buttons,
  145.              0, 1, 0, 0, 0, NEWT_GRID_FLAG_GROWX);
  146.  
  147.     newtGridAddComponentsToForm(grid, form, 1);
  148.     newtGridWrappedWindow(grid, _("Edit Boot Label"));
  149.     newtGridFree(grid, 1);
  150.  
  151.     do {
  152.     answer = newtRunForm(form);
  153.  
  154.     if (answer == clear)
  155.         newtEntrySet(entry, "", 1);
  156.     } while (answer == clear);
  157.  
  158.     if (answer != cancel) {
  159.     if (item->bootLabel) free(item->bootLabel);
  160.  
  161.     if (strlen(entryValue))
  162.         item->bootLabel = strdup(entryValue);
  163.     else
  164.         item->bootLabel = NULL;
  165.     }
  166.  
  167.     newtPopWindow();
  168. }        
  169.  
  170. static int doinstallLilo(char * prefix, char * dev, char * rootdev,
  171.              char * bootdev,
  172.              struct partitionTable table,
  173.              char * append, char * kernelVersion, 
  174.              char * hdname, int linear) {
  175.     char filename[100];
  176.     FILE * f;
  177.     char * argv[] = { "/mnt/sbin/lilo", NULL };
  178.     int i;
  179.     int rc;
  180.     struct stat sb;
  181.     int useInitrd = 0;
  182.     char relinitrdImage[50], absinitrdImage[55];
  183.     int pass;
  184.     static int firstTime = 1;
  185.  
  186.     sprintf(relinitrdImage, "/boot/initrd-%s.img", kernelVersion);
  187.     strcpy(absinitrdImage, "/mnt");
  188.     strcat(absinitrdImage, relinitrdImage);
  189.  
  190.     if (mkinitrd(kernelVersion, relinitrdImage))
  191.     return INST_ERROR;
  192.  
  193.     if (testing) return 0;
  194.  
  195.     if (!stat(absinitrdImage, &sb))
  196.     useInitrd = 1;
  197.  
  198.     #ifdef __sparc__
  199.     sprintf(filename, "%s/silo.conf", prefix);
  200.     #else
  201.     sprintf(filename, "%s/lilo.conf", prefix);
  202.     #endif
  203.  
  204.     /* why not? */
  205.     if (firstTime) {
  206.     rename("/mnt/etc/lilo.conf", "/mnt/etc/lilo.conf.rpmsave");
  207.     rename("/mnt/etc/silo.conf", "/mnt/etc/silo.conf.rpmsave");
  208.     firstTime = 0;
  209.     }
  210.     
  211.     f = fopen(filename, "w");
  212.     if (!f) {
  213.     errorWindow("cannot create [ls]ilo config file: %s");
  214.     return INST_ERROR;
  215.     }
  216.  
  217.     logMessage("writing [sl]ilo config to %s", filename);
  218.  
  219.     #ifdef __i386__
  220.     fprintf(f, "boot=/dev/%s\n", dev);
  221.     fprintf(f, "map=/boot/map\n");
  222.     fprintf(f, "install=/boot/boot.b\n");
  223.     fprintf(f, "prompt\n");
  224.     if (linear) fprintf(f, "linear\n");
  225.     fprintf(f, "timeout=50\n");
  226.     #elif __sparc__
  227.     fprintf(f, "timeout=50\n");
  228.     fprintf(f, "partition=%s\n", rootdev + 3);
  229.     fprintf(f, "root=/dev/%s\n", rootdev);
  230.     #else
  231.     #error "unsupported architecture";
  232.     #endif
  233.  
  234.     for (pass = 0; pass < 2; pass++) {
  235.     for (i = 0; i < table.count; i++) {
  236.         if (!table.parts[i].bootLabel) continue;
  237.         if (pass == 0 && !table.parts[i].defaultBoot) continue;
  238.         if (pass == 1 && table.parts[i].defaultBoot) continue;
  239.  
  240.         if (table.parts[i].type == PART_EXT2) {
  241.         fprintf(f, "image=" KERNEL_IMAGE "\n", kernelVersion);
  242.         fprintf(f, "\tlabel=%s\n", table.parts[i].bootLabel);
  243.  
  244.         /* remap /boot to root=/, but make sure we set up booting
  245.            from old root partitions as well */
  246.         if (!strcmp(bootdev, table.parts[i].device))
  247.             fprintf(f, "\troot=/dev/%s\n", rootdev);
  248.         else
  249.             fprintf(f, "\troot=/dev/%s\n", table.parts[i].device);
  250.  
  251.         if (useInitrd)
  252.             fprintf(f, "\tinitrd=%s\n", relinitrdImage);
  253.         if (append) fprintf(f, "\tappend=\"%s\"\n", append);
  254.         fprintf(f, "\tread-only\n");
  255.       #ifdef __i386__
  256.         } else {
  257.         fprintf(f, "other=/dev/%s\n", table.parts[i].device);
  258.         fprintf(f, "\tlabel=%s\n", table.parts[i].bootLabel);
  259.         fprintf(f, "\ttable=/dev/%.3s\n", table.parts[i].device);
  260.  
  261.         if (strncmp(table.parts[i].device, hdname, 3)) {
  262.             /* boot off the second drive, so reverse the BIOS maps */
  263.             fprintf(f, "\tmap-drive=0x80\n");
  264.             fprintf(f, "\t   to = 0x81\n");
  265.             fprintf(f, "\tmap-drive=0x81\n");
  266.             fprintf(f, "\t   to = 0x80\n");
  267.         }
  268.       #endif
  269.         }
  270.     }
  271.     }
  272.  
  273.     fclose(f);
  274.  
  275.     winStatus(35, 3, _("Running"), _("Installing boot loader..."));
  276.  
  277.     #ifdef __i386__
  278.     rc = runProgramRoot(RUN_LOG, "/mnt", "sbin/lilo", argv);
  279.     #elif __sparc__ 
  280.     rc = doMount("/proc", "/mnt/proc", "proc", 0, 0);
  281.     if (rc) {
  282.         newtPopWindow();
  283.         return rc;
  284.     }
  285.     rc = runProgramRoot(RUN_LOG, "/mnt", "sbin/silo", argv);
  286.     umount("/mnt/proc");
  287.     #else
  288.     #error unsupported architectures
  289.     #endif
  290.  
  291.     newtPopWindow();
  292.  
  293.     if (rc)
  294.     return INST_ERROR;
  295.  
  296.     return 0;
  297. }
  298.  
  299. static void formatEntry(char * buf, struct partition * part) {
  300.     sprintf(buf, "/dev/%-5s  %-25s %-7s %-10s", part->device, 
  301.         part->tagName, 
  302.         part->defaultBoot ? "   *" : "",
  303.         part->bootLabel ? part->bootLabel : "");
  304. }
  305.  
  306. static int getBootLabels(struct partitionTable table, struct fstab fstab) {
  307.     newtComponent f, okay, text, listbox, label, cancel, edit;
  308.     struct newtExitStruct answer;
  309.     char buf[80];
  310.     int i, j;
  311.     int foundDos = 0;
  312.     int mustAsk = 0;
  313.     int * map;
  314.     struct partition * curr;
  315.     int * currNum;
  316.     int count;
  317.     int done;
  318.     int defaultBootPart = 0;
  319.     char * reflowedText;
  320.     int width, height;
  321.     newtGrid buttons, grid;
  322.  
  323.     reflowedText = newtReflowText(
  324.                _("The boot manager Red Hat uses can boot other " 
  325.                          "operating systems as well. You need to tell me " 
  326.                          "what partitions you would like to be able to boot " 
  327.                          "and what label you want to use for each of them."),
  328.              60, -5, -5, &width, &height);
  329.     text = newtTextbox(-1, -1, width, height, NEWT_TEXTBOX_WRAP);
  330.     newtTextboxSetText(text, reflowedText);
  331.     free(reflowedText);
  332.  
  333.     f = newtForm(NULL, NULL, 0);
  334.  
  335.     sprintf(buf, "%-10s  %-25s %-7s %-10s", _("Device"), _("Partition type"), 
  336.             _("Default"), _("Boot label"));
  337.     label = newtLabel(-1, -1, buf);
  338.  
  339.     listbox = newtListbox(-1, -1, 10 - height, 
  340.               NEWT_LISTBOX_RETURNEXIT | NEWT_FLAG_SCROLL);
  341.     map = alloca(sizeof(int) * table.count);
  342.     
  343.     for (i = 0, count = 0; i < table.count; i++) {
  344.     if (table.parts[i].type != PART_SWAP && 
  345.         table.parts[i].type != PART_IGNORE &&
  346. #ifdef __sparc__
  347.         table.parts[i].type != PART_OTHER &&
  348. #endif
  349.         (table.parts[i].type != PART_FAT32 || !foundDos) &&
  350.         (table.parts[i].type != PART_DOS || !foundDos)) {
  351.  
  352.         if (table.parts[i].type == PART_DOS || 
  353.             table.parts[i].type == PART_FAT32) {
  354.         foundDos = 1;
  355.         }
  356.  
  357.         if (table.parts[i].type == PART_EXT2) {
  358.         for (j = 0; j < fstab.numEntries; j++) {
  359.             if (!strcmp(table.parts[i].device, fstab.entries[j].device))
  360.             break;
  361.         }
  362.  
  363.         if (j < fstab.numEntries && !table.parts[i].bootLabel) 
  364.             continue;
  365.         }
  366.  
  367.         if (!table.parts[i].bootLabel ||
  368.         strcmp(table.parts[i].bootLabel, "linux")) mustAsk = 1;
  369.  
  370.         if (table.parts[i].defaultBoot)
  371.         defaultBootPart = count;
  372.  
  373.         map[count] = i;
  374.         formatEntry(buf, table.parts + i);
  375.         newtListboxAddEntry(listbox, buf, map + count++);
  376.     } 
  377.     }
  378.  
  379.     /* we add stuff to the form here so we can actually destroy it if
  380.        we don't need this window after all */
  381.     newtFormAddComponents(f, text, label, listbox, NULL);
  382.  
  383.     if (!mustAsk) {
  384.     newtFormDestroy(f);
  385.     return 0;
  386.     }
  387.  
  388.     newtPushHelpLine("<F2> Selects the default partition");
  389.  
  390.     buttons = newtButtonBar(_("Ok"), &okay, _("Edit"), &edit,
  391.                 _("Back"), &cancel, NULL);
  392.  
  393.     newtFormAddComponents(f, okay, edit, cancel, NULL);
  394.  
  395.     newtFormAddHotKey(f, NEWT_KEY_F2);
  396.  
  397.     grid = newtCreateGrid(1, 4);
  398.  
  399.     newtGridSetField(grid, 0, 0, NEWT_GRID_COMPONENT, text,
  400.              0, 0, 0, 1, NEWT_ANCHOR_LEFT, 0);
  401.     newtGridSetField(grid, 0, 1, NEWT_GRID_COMPONENT, label,
  402.              0, 0, 0, 0, NEWT_ANCHOR_LEFT, 0);
  403.     newtGridSetField(grid, 0, 2, NEWT_GRID_COMPONENT, listbox,
  404.              0, 0, 0, 0, NEWT_ANCHOR_LEFT, 0);
  405.     newtGridSetField(grid, 0, 3,  NEWT_GRID_SUBGRID, buttons,
  406.              0, 1, 0, 0, 0, NEWT_GRID_FLAG_GROWX);
  407.  
  408.     newtGridWrappedWindow(grid, _("Bootable Partitions"));
  409.     newtGridFree(grid, 1);
  410.  
  411.     done = 0;
  412.     while (!done) {
  413.     newtFormRun(f, &answer);
  414.  
  415.     if (answer.reason == NEWT_EXIT_HOTKEY) {
  416.         if (answer.u.key == NEWT_KEY_F12) {
  417.         done = 1;
  418.         } else if (answer.u.key == NEWT_KEY_F2) {
  419.         currNum = newtListboxGetCurrent(listbox);
  420.         curr = table.parts + *currNum;
  421.  
  422.         if (!curr->bootLabel) {
  423.             newtWinMessage("Boot Partition", "Ok", "You cannot mark a "
  424.                   "partition as the default partition to "
  425.                   "boot from unless that partition has "
  426.                   "been assigned a boot label.");
  427.         } else{
  428.             for (i = 0; i < count; i++) {
  429.             if (table.parts[map[i]].defaultBoot) {
  430.                 table.parts[map[i]].defaultBoot = 0;
  431.                 formatEntry(buf, table.parts + map[i]);
  432.                 newtListboxSetEntry(listbox, i, buf);
  433.                 break;
  434.             }
  435.             }
  436.  
  437.             curr->defaultBoot = 1;
  438.             formatEntry(buf, curr);
  439.             newtListboxSetEntry(listbox, currNum - map, buf);
  440.         }
  441.         }
  442.     } else {
  443.         if (answer.u.co == edit || answer.u.co== listbox) {
  444.         currNum = newtListboxGetCurrent(listbox);
  445.         curr = table.parts + *currNum;
  446.         editBootLabel(curr);
  447.  
  448.         if (!curr->bootLabel && curr->defaultBoot) {
  449.             curr->defaultBoot = 0;
  450.             if (table.parts[map[defaultBootPart]].bootLabel) {
  451.             table.parts[map[defaultBootPart]].defaultBoot = 1;
  452.  
  453.             formatEntry(buf, table.parts + map[defaultBootPart]);
  454.             newtListboxSetEntry(listbox, defaultBootPart, buf);
  455.             }
  456.         }
  457.  
  458.         formatEntry(buf, curr);
  459.         newtListboxSetEntry(listbox, currNum - map, buf);
  460.         } else 
  461.         done = 1;
  462.     }
  463.     }
  464.  
  465.     newtPopHelpLine();
  466.  
  467.     newtFormDestroy(f);
  468.     newtPopWindow();
  469.  
  470.     if (answer.reason == NEWT_EXIT_COMPONENT && answer.u.co == cancel)
  471.     return INST_CANCEL;
  472.     else
  473.     return 0;
  474. }
  475.  
  476. static int getAppendLine(char ** line, int * linear) {
  477.     newtComponent form, text, entry, okay, cancel, answer;
  478.     newtComponent linearCheck;
  479.     char * result = NULL;
  480.     char linearChar = (*linear) ? '*' : ' ';
  481.     newtGrid grid, buttons, subgrid;
  482.  
  483.     text = newtTextboxReflowed(0, 0,
  484.              _("A few systems will need to pass special options "
  485.                "to the kernel at boot time for the system to function "
  486.                "properly. If you need to pass boot options to the "
  487.                "kernel, enter them now. If you don't need any or "
  488.                "aren't sure, leave this blank."), 53, 10, 0, 0);
  489.  
  490.     form = newtForm(NULL, NULL, 0);
  491.  
  492.     entry = newtEntry(-1, -1, *line, 48, &result, 
  493.             NEWT_ENTRY_SCROLL | NEWT_ENTRY_RETURNEXIT);
  494.  
  495.     #ifndef __sparc__
  496.     linearCheck = newtCheckbox(-1, -1, 
  497.                  _("Use linear mode (needed for some SCSI drives)"),
  498.                  linearChar, NULL, &linearChar);
  499.     #endif
  500.  
  501.     buttons = newtButtonBar(_("Ok"), &okay, _("Back"), &cancel, NULL);
  502.     subgrid = newtGridVStacked(NEWT_GRID_COMPONENT, entry,
  503.                    #ifndef __sparc__
  504.                   NEWT_GRID_COMPONENT, linearCheck,
  505.                    #endif
  506.                    NULL);
  507.     grid = newtGridBasicWindow(text, subgrid, buttons);
  508.  
  509.     newtGridAddComponentsToForm(grid, form, 1);
  510.     newtFormSetCurrent(form, okay);
  511.  
  512.     #ifdef __sparc__
  513.     newtGridWrappedWindow(grid, _("Silo Installation"));
  514.     #else
  515.     newtGridWrappedWindow(grid, _("Lilo Installation"));
  516.     #endif
  517.  
  518.     newtGridFree(grid, 1);
  519.  
  520.     answer = newtRunForm(form);
  521.  
  522.     newtPopWindow();
  523.  
  524.     if (answer == cancel) {
  525.     newtFormDestroy(form);
  526.     return INST_CANCEL;
  527.     }
  528.  
  529.     *linear = linearChar != ' ';
  530.  
  531.     if (!strlen(result)) 
  532.     *line = NULL;
  533.     else 
  534.     *line = strdup(result);
  535.  
  536.     newtFormDestroy(form);
  537.  
  538.     return 0;
  539. }
  540.  
  541. #define LILO_WHERE 2
  542. #define LILO_LABELS 3
  543. #define LILO_INSTALL 4
  544. #define LILO_APPEND 5
  545. #define LILO_DONE 20
  546.     
  547. int installLilo(char * prefix, struct partitionTable table, struct fstab fstab,
  548.         char * kernelVersion, int flags, char * options) {
  549.     char * rootDevice, * bootDevice = NULL;
  550.     char * hdName;
  551.     char * where = NULL;
  552.     char * append = NULL;
  553.     char * chptr = NULL;
  554.     int i;
  555.     int rc;
  556.     int stage = LILO_WHERE;
  557.     static int linear = 0;
  558.     int foundDos = 0;
  559.  
  560.     hdName = alloca(4);
  561.     strncpy(hdName, table.parts[0].device, 3);
  562.     hdName[3] = '\0';
  563.     
  564.     for (i = 0; i < fstab.numEntries; i++) {
  565.     if (!strcmp(fstab.entries[i].mntpoint, "/boot")) break;
  566.     }
  567.  
  568.     if (i < fstab.numEntries) 
  569.     bootDevice = fstab.entries[i].device;
  570.  
  571.     for (i = 0; i < fstab.numEntries; i++) {
  572.     if (!strcmp(fstab.entries[i].mntpoint, "/")) break;
  573.     }
  574.  
  575.     rootDevice = fstab.entries[i].device;
  576.     if (!bootDevice) {
  577.     bootDevice = rootDevice;
  578.     }
  579.  
  580.     for (i = 0; i < table.count; i++) {
  581.     if (!strcmp(table.parts[i].device, bootDevice)) {
  582.         table.parts[i].bootLabel = strdup("linux");
  583.         table.parts[i].defaultBoot = 1;
  584.     } else if ((table.parts[i].type == PART_DOS || 
  585.         table.parts[i].type == PART_FAT32) && !foundDos) {
  586.         table.parts[i].bootLabel = strdup("dos");
  587.         foundDos = 1;
  588.     }
  589.     }
  590.  
  591.     if (flags & LILO_ON_MBR)
  592.     where = hdName;
  593.     else if (flags & LILO_ON_PARTITION)
  594.     where = bootDevice;
  595.  
  596.     if (flags & LILO_USE_OPTIONS)
  597.     append = options;
  598.  
  599.     if (where) {
  600.     rc = doinstallLilo(prefix, where, rootDevice, bootDevice, table, 
  601.                 append, kernelVersion, hdName, linear);
  602.     if (rc == INST_ERROR) return INST_ERROR;
  603.     stage = LILO_DONE;
  604.     }
  605.  
  606.     while (stage != LILO_DONE) {
  607.     switch (stage) {
  608.       case LILO_WHERE:
  609.         rc = liloWhere(hdName, bootDevice, &where);
  610.             if (rc == SKIP_LILO ) return 0;
  611.         if (rc) return rc;
  612.         stage = LILO_APPEND;
  613.         break;
  614.  
  615.       case LILO_APPEND:
  616.         chptr = append;
  617.         rc = getAppendLine(&chptr, &linear);
  618.  
  619.         if (rc == INST_ERROR) return INST_ERROR;
  620.         if (rc == INST_CANCEL)
  621.         stage = LILO_WHERE;
  622.         else {
  623.         stage = LILO_LABELS;
  624.  
  625.         if (append) free(append);
  626.         if (chptr) {
  627.             append = alloca(strlen(chptr) + 1);
  628.             strcpy(append, chptr);
  629.             free(chptr);
  630.         } else {
  631.             append = NULL;
  632.         }
  633.         }
  634.  
  635.         break;
  636.  
  637.       case LILO_LABELS:
  638.         rc = getBootLabels(table, fstab);
  639.         if (rc == INST_ERROR) return INST_ERROR;
  640.         if (rc == INST_CANCEL)
  641.         stage = LILO_APPEND;
  642.         else
  643.         stage = LILO_INSTALL;
  644.         break;
  645.  
  646.       case LILO_INSTALL:
  647.         rc = doinstallLilo(prefix, where, rootDevice, bootDevice,
  648.                 table, append, 
  649.                 kernelVersion, hdName, linear);
  650.         if (rc == INST_ERROR) return INST_ERROR;
  651.         stage = LILO_DONE;
  652.         break;
  653.     }
  654.     }
  655.  
  656.     return 0;
  657. }
  658.  
  659. int makeBootdisk(char * prefix, char * kernelVersion) {
  660.     char * argv[] = { "/sbin/mkbootdisk", "--noprompt", kernelVersion, NULL };
  661.     int rc;
  662.  
  663.     #ifdef __sparc__
  664.     return 0;
  665.     #endif
  666.  
  667.     if (loadModule("loop", DRIVER_OTHER, DRIVER_MINOR_NONE, NULL)) 
  668.     return INST_ERROR;
  669.  
  670.     winStatus(32, 3, _("Bootdisk"), _("Creating bootdisk..."));
  671.     rc = runProgramRoot(RUN_LOG, "/mnt", "/sbin/mkbootdisk", argv);
  672.     newtPopWindow();
  673.  
  674.     removeModule("loop");
  675.  
  676.     return rc;
  677. }
  678.