home *** CD-ROM | disk | FTP | other *** search
/ CD Actual 13 / CDA13.ISO / MISC / SRC / INSTALL / FS.C < prev    next >
Encoding:
C/C++ Source or Header  |  1996-12-23  |  29.3 KB  |  1,144 lines

  1. #include <alloca.h>
  2. #include <ctype.h>
  3. #include <errno.h>
  4. #include <linux/fs.h>
  5. #include <newt.h>
  6. #include <stdlib.h>
  7. #include <stdio.h>
  8. #include <string.h>
  9. #include <sys/mount.h>
  10. #include <sys/stat.h>
  11. #include <unistd.h>
  12.  
  13. #include "devices.h"
  14. #include "fs.h"
  15. #include "install.h"
  16. #include "log.h"
  17. #include "mkswap.h"
  18. #include "perror.h"
  19. #include "run.h"
  20. #include "windows.h"
  21.  
  22. int nfsmount(const char *spec, const char *node, int *flags,
  23.          char **extra_opts, char **mount_opts);
  24.  
  25. static int selectRootPartition(struct partitionTable table, int * rootPartNum);
  26. static int fstabCmp(const void * a, const void * b);
  27. static int mkdirChain(char * chain);
  28. static int mkdirIfNone(char * directory);
  29. static char * nstrdup(const char * foo);
  30. static void initFstabEntry(struct fstabEntry * e);
  31.  
  32. int canEnableSwap = 1;
  33. int badBlocks = 0;
  34.  
  35. struct nfsMountCallbackInfo {
  36.     newtComponent server, mntpoint, netpath;
  37.     char * serverVal, * netpathVal, * mntpointVal;
  38. } ;
  39.  
  40. static char * nstrdup(const char * foo) {
  41.     return foo ? strdup(foo) : NULL;
  42. }
  43.  
  44. static int fstabCmp(const void * a, const void * b) {
  45.     const struct fstabEntry * first = a;
  46.     const struct fstabEntry * second = b;
  47.  
  48.     if (first->type != second->type) {
  49.     if (first->type == PART_NFS)
  50.         return 1;
  51.     else if (second->type == PART_NFS)
  52.         return -1;
  53.     }
  54.  
  55.     return strcmp(first->mntpoint, second->mntpoint);
  56. }
  57.  
  58. static void initFstabEntry(struct fstabEntry * e) {
  59.     e->device = NULL;
  60.     e->netHost = NULL;
  61.     e->netPath = NULL;
  62.     e->mntpoint = NULL;
  63.     e->tagName = NULL;
  64.     e->size = 0;
  65.     e->type = PART_OTHER;
  66.     e->isMounted = 0;
  67.     e->doFormat = 0;
  68. }
  69.  
  70. newtComponent addPartitionListbox(struct partitionTable table,
  71.                      newtComponent form, int left, int top, 
  72.                      int height, int type) {
  73.     newtComponent listbox, label;
  74.     int i;
  75.     char buf[80];
  76.  
  77.     listbox = newtListbox(left, top + 1, height, NEWT_LISTBOX_RETURNEXIT);
  78.  
  79.     label = newtLabel(left, top, "Device          Begin        End   "
  80.             "Size (k)");
  81.  
  82.     for (i = 0; i < table.count; i++) {
  83.     if (table.parts[i].type == type) {
  84.         sprintf(buf, "/dev/%-5s  %9d  %9d  %9d", table.parts[i].device, 
  85.             table.parts[i].begin, table.parts[i].end, 
  86.             table.parts[i].size);
  87.         newtListboxAddEntry(listbox, buf, &table.parts[i]);
  88.     }
  89.     }
  90.  
  91.     newtFormAddComponents(form, label, listbox, NULL);
  92.  
  93.     return listbox;
  94. }
  95.  
  96. static int selectRootPartition(struct partitionTable table, int * rootPartNum) {
  97.     newtComponent okay, cancel, form, text, listbox, answer;
  98.     int i;
  99.     struct partition * rootPart = NULL;
  100.  
  101.     for (i = 0; i < table.count; i++) 
  102.     if (table.parts[i].type == PART_EXT2) break;
  103.  
  104.     if (i == table.count) {
  105.     newtOpenWindow(18, 6, 44, 11, "Setup Swap");
  106.     text = newtTextbox(1, 1, 42, 4, NEWT_TEXTBOX_WRAP);
  107.     newtTextboxSetText(text, "You don't have any Linux native partitions "
  108.                  "defined. You must return to repartition "
  109.                  "your hard drive.");
  110.     
  111.     okay = newtButton(17, 7, "Ok");
  112.  
  113.     form = newtForm(NULL, NULL, 0);
  114.     newtFormAddComponents(form, text, okay, NULL);
  115.     
  116.     newtRunForm(form);
  117.     newtFormDestroy(form);
  118.     newtPopWindow();
  119.  
  120.         return INST_CANCEL;
  121.     }
  122.  
  123.     *rootPartNum = i;
  124.  
  125.     newtOpenWindow(10, 2, 64, 19, "Select Root Partition");
  126.     text = newtTextbox(1, 1, 62, 4, NEWT_TEXTBOX_WRAP);
  127.     newtTextboxSetText(text, "The root partition forms the base of your Linux "
  128.                "filesystem. It must hold everything necessary for "
  129.                "booting and initializing your system. What partition "
  130.                "would you like to use for the root filesystem?");
  131.     okay = newtButton(15, 15, "Ok");
  132.     cancel = newtButton(38, 15, "Cancel");
  133.  
  134.     form = newtForm(NULL, NULL, 0);
  135.     listbox = addPartitionListbox(table, form, 7, 6, 7, PART_EXT2);
  136.  
  137.     newtFormAddComponents(form, text, okay, cancel, NULL);
  138.     answer = newtRunForm(form);
  139.             
  140.     if (answer != cancel) {
  141.     rootPart = newtListboxGetCurrent(listbox);
  142.     }
  143.  
  144.     newtFormDestroy(form);
  145.     newtPopWindow();
  146.  
  147.     *rootPartNum = (rootPart - table.parts);
  148.     if (!rootPart)
  149.     return INST_CANCEL;
  150.     else
  151.     return 0;
  152. }
  153.  
  154. static int badMountPoint(enum partitionTypes type, char * item) {
  155.     char * chptr = item;
  156.  
  157.     if (*chptr != '/') {
  158.     winMessage(33, 12, 30, 8, "Bad Mount Point",
  159.             "Mount points must begin with a leading /.");
  160.     return INST_ERROR;
  161.     } 
  162.  
  163.     if (*(chptr + 1) && *(chptr + strlen(chptr) - 1) == '/') {
  164.     winMessage(33, 12, 30, 8, "Bad Mount Point",
  165.             "Mount points may not end with a /.");
  166.     return INST_ERROR;
  167.     } 
  168.  
  169.     while (*chptr && isprint(*chptr)) chptr++;
  170.  
  171.     if (*chptr) {
  172.     winMessage(30, 10, 30, 10, "Bad Mount Point",
  173.             "Mount points may only printable characters.");
  174.     return INST_ERROR;
  175.     }
  176.  
  177.     if (type != PART_EXT2 && (
  178.      !strncmp(item, "/var", 4) ||
  179.      !strncmp(item, "/tmp", 4) ||
  180.      !strncmp(item, "/bin", 4) ||
  181.      !strncmp(item, "/sbin", 4) ||
  182.      !strncmp(item, "/etc", 4) ||
  183.      !strncmp(item, "/boot", 4) ||
  184.      !strncmp(item, "/dev", 4) ||
  185.      !strncmp(item, "/root", 4) ||
  186.      !strncmp(item, "/lib", 4))) {
  187.     winMessage(30, 10, 30, 10, "Bad Mount Point",
  188.             "System partitions must be on Linux Native "
  189.             "partitions.");
  190.     return INST_ERROR;
  191.     }
  192.  
  193.     if (type != PART_EXT2 && type != PART_NFS &&
  194.     !strncmp(item, "/usr", 4)) {
  195.     winMessage(25, 10, 30, 10, "Bad Mount Point",
  196.             "/usr must be on a Linux Native partition "
  197.             "or an NFS volume.");
  198.     return INST_ERROR;
  199.     }
  200.  
  201.     return 0;
  202. }
  203.  
  204. static char * restrdup(char * old, char * new) {
  205.     if (old) free(old);
  206.     if (new) return strdup(new); else return NULL;
  207. }
  208.  
  209. static void nfsMountCallback(newtComponent co, void * arg) {
  210.     struct nfsMountCallbackInfo * nfsinfo = arg;
  211.     char * chptr;
  212.     char * copy;
  213.  
  214.     if (!strlen(nfsinfo->netpathVal)) {
  215.     if (strchr(nfsinfo->serverVal, ':')) {
  216.         chptr = copy = alloca(strlen(nfsinfo->serverVal) + 1);
  217.         strcpy(copy, nfsinfo->serverVal);
  218.         chptr = strchr(copy, ':');
  219.         *chptr = '\0';
  220.         chptr++;
  221.         newtEntrySet(nfsinfo->server, copy, 1);
  222.         newtEntrySet(nfsinfo->netpath, chptr, 1);
  223.     }
  224.     }
  225.  
  226.     if (strlen(nfsinfo->netpathVal) && !strlen(nfsinfo->mntpointVal)) {
  227.     newtEntrySet(nfsinfo->mntpoint, nfsinfo->netpathVal, 1);
  228.     }
  229. }
  230.  
  231. static int editNetMountPoint(struct fstabEntry * item) {
  232.     newtComponent form, server, path, point, okay, cancel, answer;
  233.     char * pointValue, * pathValue, * serverValue;
  234.     int done = 0;
  235.     struct nfsMountCallbackInfo nfsinfo;
  236.  
  237.     newtOpenWindow(10, 7, 50, 10, "Edit Network Mount Point");
  238.  
  239.     form = newtForm(NULL, NULL, 0);
  240.  
  241.     newtFormAddComponent(form, newtLabel(1, 1, "NFS Server  :"));
  242.     newtFormAddComponent(form, newtLabel(1, 2, "NFS Path    :"));
  243.     newtFormAddComponent(form, newtLabel(1, 3, "Mount point :"));
  244.  
  245.     server = newtEntry(17, 1, item->mntpoint, 20, &serverValue, 
  246.               NEWT_ENTRY_SCROLL | NEWT_ENTRY_RETURNEXIT);
  247.     path = newtEntry(17, 2, item->mntpoint, 20, &pathValue, 
  248.               NEWT_ENTRY_SCROLL | NEWT_ENTRY_RETURNEXIT);
  249.     point = newtEntry(17, 3, item->mntpoint, 20, &pointValue, 
  250.               NEWT_ENTRY_SCROLL | NEWT_ENTRY_RETURNEXIT);
  251.  
  252.     nfsinfo.server = server;
  253.     nfsinfo.mntpoint = point;
  254.     nfsinfo.netpath = path;
  255.  
  256.     nfsinfo.serverVal = serverValue;
  257.     nfsinfo.netpathVal = pathValue;
  258.     nfsinfo.mntpointVal = pointValue;
  259.  
  260.     newtComponentAddCallback(server, nfsMountCallback, &nfsinfo);
  261.     newtComponentAddCallback(path, nfsMountCallback, &nfsinfo);
  262.  
  263.     okay = newtButton(10, 6, "Ok");
  264.     cancel = newtButton(30, 6, "Cancel");
  265.  
  266.     newtFormAddComponents(form, server, path, point, okay, cancel, NULL);
  267.  
  268.     do {
  269.     answer = newtRunForm(form);
  270.  
  271.     if (answer == cancel) {
  272.         done = 1;
  273.     } else if (*pointValue) {
  274.         if (!badMountPoint(item->type, pointValue)) 
  275.         done = 1;
  276.     }
  277.     } while (!done);
  278.  
  279.     if (answer != cancel) {
  280.     item->mntpoint = restrdup(item->mntpoint, pointValue);
  281.     item->netPath = restrdup(item->netPath, pathValue);
  282.     item->netHost = restrdup(item->netHost, serverValue);
  283.  
  284.     if (item->device) free(item->device);
  285.     item->device = malloc(strlen(pathValue) + strlen(serverValue) + 5);
  286.     sprintf(item->device, "%s:%s", serverValue, pathValue);
  287.     }
  288.  
  289.     newtPopWindow();
  290.  
  291.     if (answer == cancel)
  292.     return INST_CANCEL;
  293.     return 0;
  294. }        
  295.  
  296. static void editDeviceMountPoint(struct fstabEntry * item) {
  297.     newtComponent form, entry, okay, cancel, clear, answer;
  298.     char buf[50];
  299.     char * entryValue;
  300.     int done = 0;
  301.  
  302.     newtOpenWindow(10, 7, 50, 10, "Edit Mount Point");
  303.  
  304.     form = newtForm(NULL, NULL, 0);
  305.  
  306.     strcpy(buf,"Device      : /dev/");
  307.     strcat(buf, item->device);
  308.     newtFormAddComponent(form, newtLabel(1, 1, buf));
  309.     newtFormAddComponent(form, newtLabel(1, 3, "Mount point :"));
  310.  
  311.     entry = newtEntry(17, 3, item->mntpoint, 20, &entryValue, 
  312.               NEWT_ENTRY_SCROLL | NEWT_ENTRY_RETURNEXIT);
  313.  
  314.     okay = newtButton(5, 6, "Ok");
  315.     clear = newtButton(20, 6, "Clear");
  316.     cancel = newtButton(35, 6, "Cancel");
  317.  
  318.     newtFormAddComponents(form, entry, okay, clear, cancel, NULL);
  319.  
  320.     do {
  321.     newtFormSetCurrent(form, entry);
  322.     answer = newtRunForm(form);
  323.  
  324.     if (answer == clear)
  325.         newtEntrySet(entry, "", 1);
  326.     else if (answer == cancel || !*entryValue) {
  327.         done = 1;
  328.     } else if (*entryValue) {
  329.         if (!badMountPoint(item->type, entryValue)) 
  330.         done = 1;
  331.     }
  332.     } while (!done);
  333.  
  334.     if (answer != cancel) {
  335.     item->mntpoint = restrdup(item->mntpoint, entryValue);
  336.     }
  337.  
  338.     newtPopWindow();
  339. }        
  340.  
  341. void freeFstab(struct fstab fstab) {
  342.     int i;
  343.  
  344.     for (i = 0; i < fstab.numEntries; i++) {
  345.     if (fstab.entries[i].mntpoint) free(fstab.entries[i].mntpoint);
  346.     if (fstab.entries[i].device) free(fstab.entries[i].device);
  347.     if (fstab.entries[i].netPath) free(fstab.entries[i].netPath);
  348.     if (fstab.entries[i].netHost) free(fstab.entries[i].netHost);
  349.     }
  350.  
  351.     if (fstab.numEntries) free(fstab.entries);
  352. }
  353.  
  354. struct fstab copyFstab(struct fstab * fstab) {
  355.     struct fstab newfstab;
  356.     int i, j;
  357.  
  358.     if (!fstab->numEntries) {
  359.     newfstab.numEntries = 0;
  360.     newfstab.entries = malloc(1);
  361.     return newfstab;
  362.     }
  363.  
  364.     /* duplicate the current fstab */
  365.     newfstab.numEntries = fstab->numEntries;
  366.     newfstab.entries = malloc(fstab->numEntries * sizeof(struct fstabEntry));
  367.     for (i = j = 0; i < newfstab.numEntries; i++) {
  368.     if (fstab->entries[i].mntpoint) {
  369.         newfstab.entries[j] = fstab->entries[i];
  370.         newfstab.entries[j].mntpoint = nstrdup(fstab->entries[i].mntpoint);
  371.         newfstab.entries[j].device = nstrdup(fstab->entries[i].device);
  372.         newfstab.entries[j].netPath = nstrdup(fstab->entries[i].netPath);
  373.         newfstab.entries[j].netHost = nstrdup(fstab->entries[i].netHost);
  374.         j++;
  375.     }
  376.     }
  377.  
  378.     newfstab.numEntries = j;
  379.  
  380.     /* return the memory we don't actually need */
  381.     newfstab.entries = realloc(newfstab.entries, j * sizeof(struct fstabEntry));
  382.  
  383.     return newfstab;
  384. }
  385.  
  386. int setupMountTable(struct partitionTable table, struct fstab * finalFstab,
  387.             struct netInterface * intf, struct netConfig * netc,
  388.             struct driversLoaded ** dl) {
  389.     int rootPartNum = -1;
  390.     int rc, hasdups;
  391.     newtComponent f, okay, text, listbox, label, cancel, edit, answer;
  392.     newtComponent addnfs;
  393.     char buf[80];
  394.     int i, j, numMountable, numLinux;
  395.     int partNum;
  396.     struct fstab fstab;
  397.     int fstabNum;
  398.     struct fstabEntry entry, * curr;
  399.     int * fstabEntNum, * numptr;
  400.     static int firstTime = 1;
  401.     const char * basicFormat = "%-10s  %14s  %-20s %-18s";
  402.     const char * devFormat = "/dev/%-5s  %14d  %-20s %-18s";
  403.     const char * nfsFormat = "%-27s %-20s %-18s";
  404.  
  405.     fstab = copyFstab(finalFstab);
  406.  
  407.     if (firstTime) {
  408.     /* First, make them pick a root partition */
  409.     if ((rc = selectRootPartition(table, &rootPartNum))) {
  410.         freeFstab(fstab);
  411.         return rc;
  412.     }
  413.     firstTime = 0;
  414.  
  415.     for (i = partNum = 0; i < table.count; i++) {
  416.         if (i == rootPartNum) {
  417.         initFstabEntry(&entry);
  418.         entry.device = strdup(table.parts[i].device);
  419.         entry.size = table.parts[i].size;
  420.         entry.type = table.parts[i].type;
  421.         entry.tagName = table.parts[i].tagName;
  422.         entry.mntpoint = strdup("/");
  423.         addFstabEntry(&fstab, entry);
  424.         break;
  425.         }
  426.     }
  427.  
  428.     freeFstab(*finalFstab);
  429.     *finalFstab = copyFstab(&fstab);
  430.     }    
  431.  
  432.     /* If only one mountable partition exists, it would have been set up
  433.        as root above so we can stop here */
  434.     numLinux = numMountable = 0;
  435.     for (i = partNum = 0; i < table.count; i++) {
  436.     if (table.parts[i].type == PART_EXT2)
  437.         numMountable++, numLinux++;
  438.     else if (table.parts[i].type == PART_DOS ||
  439.              table.parts[i].type == PART_HPFS)
  440.         numMountable++;
  441.     }
  442.     if (!numMountable) {
  443.     errorWindow("You don't have any mountable partitions!");
  444.     return INST_ERROR;
  445.     } else if (!numLinux) {
  446.     errorWindow("You don't have any Linux partitions available!");
  447.     return INST_ERROR;
  448.     } else if (numMountable == 1)
  449.     return 0;
  450.  
  451.     newtOpenWindow(2, 2, 75, 19, "Partition Disk");
  452.  
  453.     f = newtForm(NULL, NULL, 0);
  454.     text = newtTextbox(1, 1, 72, 4, NEWT_TEXTBOX_WRAP);
  455.     newtTextboxSetText(text, "You may now mount other partitions within "
  456.                "your filesystem. Many users like to use separate "
  457.                "partitions for /usr and /home for example. You may "
  458.                "also mount your DOS or OS/2 partitions to make them "
  459.                "visible to Linux.");
  460.  
  461.     okay = newtButton(6, 15, "Ok");
  462.     addnfs = newtButton(20, 15, "Add NFS");
  463.     edit = newtButton(38, 15, "Edit");
  464.     cancel = newtButton(54, 15, "Cancel");
  465.  
  466.     sprintf(buf, basicFormat, "Device", "Size", "Partition type", 
  467.         "Mount point");
  468.     label = newtLabel(1, 5, buf);
  469.  
  470.     listbox = newtListbox(1, 6, 8, NEWT_LISTBOX_RETURNEXIT);
  471.  
  472.     fstabEntNum = malloc(table.count * sizeof(*fstabEntNum));
  473.  
  474.     for (i = partNum = 0; i < table.count; i++) {
  475.     if (table.parts[i].type == PART_EXT2 || 
  476.         table.parts[i].type == PART_DOS ||
  477.         table.parts[i].type == PART_HPFS) {
  478.  
  479.         for (j = 0; j < fstab.numEntries; j++) 
  480.         if (!strcmp(table.parts[i].device, fstab.entries[j].device))
  481.             break;
  482.  
  483.         if (j < fstab.numEntries) {
  484.         fstabNum = j;
  485.         } else {
  486.         initFstabEntry(&entry);
  487.         entry.device = strdup(table.parts[i].device);
  488.         entry.size = table.parts[i].size;
  489.         entry.type = table.parts[i].type;
  490.         entry.tagName = table.parts[i].tagName;
  491.         fstabNum = addFstabEntry(&fstab, entry);
  492.         }
  493.  
  494.         sprintf(buf, devFormat, table.parts[i].device, 
  495.             table.parts[i].size, table.parts[i].tagName, 
  496.             fstab.entries[fstabNum].mntpoint ? 
  497.             fstab.entries[fstabNum].mntpoint : "");
  498.         fstabEntNum[partNum] = fstabNum;
  499.         newtListboxAddEntry(listbox, buf, fstabEntNum + partNum);
  500.         partNum++;
  501.     } 
  502.     }
  503.  
  504.     newtFormAddComponents(f, text, label, listbox, okay, addnfs, edit, cancel, 
  505.                 NULL);
  506.  
  507.     do { 
  508.     answer = newtRunForm(f);
  509.     if (answer == listbox || answer == edit) {
  510.         numptr = newtListboxGetCurrent(listbox);
  511.         curr = fstab.entries + *numptr;
  512.  
  513.         if (curr->type == PART_NFS) {
  514.         editNetMountPoint(curr);
  515.         sprintf(buf, nfsFormat, curr->device, curr->tagName,
  516.             curr->mntpoint);
  517.         } else {
  518.         editDeviceMountPoint(curr);
  519.         sprintf(buf, devFormat, curr->device, curr->size, 
  520.             curr->tagName, curr->mntpoint ? curr->mntpoint : "");
  521.         }
  522.  
  523.         newtListboxSetEntry(listbox, numptr - fstabEntNum, buf);
  524.     } else if (answer == addnfs) {
  525.         initFstabEntry(&entry);
  526.         entry.type = PART_NFS;
  527.         entry.tagName = "NFS Mount";
  528.         entry.device = NULL;
  529.         entry.mntpoint = NULL;
  530.  
  531.         if (!intf->isConfigured) {
  532.         rc = bringUpNetworking(intf, netc, dl);
  533.         } else {
  534.         rc = 0;
  535.         }
  536.  
  537.         if (!rc && !editNetMountPoint(&entry)) {
  538.         fstabNum = addFstabEntry(&fstab, entry);
  539.         fstabEntNum = realloc(fstabEntNum, 
  540.                       sizeof(*fstabEntNum) * fstabNum);
  541.  
  542.         sprintf(buf, nfsFormat, entry.device, entry.tagName,
  543.             entry.mntpoint);
  544.  
  545.         newtListboxAddEntry(listbox, buf, fstabEntNum + fstabNum);
  546.         /*newtListboxSetCurrent(listbox, fstabNum);*/
  547.         }
  548.     } else if (answer != cancel) {
  549.         answer = okay;
  550.         for (i = 0; i < fstab.numEntries; i++) 
  551.         if (fstab.entries[i].mntpoint &&
  552.             !strcmp(fstab.entries[i].mntpoint, "/")) break;
  553.  
  554.         if (i == fstab.numEntries) {
  555.         winMessage(30, 7, 30, 10, "No Root Partition",
  556.                 "You must assign a root (/) partition for the "
  557.                 "install to proceed.");
  558.         answer = NULL;
  559.         continue;
  560.         }
  561.  
  562.         hasdups = 0;
  563.         for (i = 0; i < fstab.numEntries; i++) 
  564.         for (j = i + 1; j < fstab.numEntries; j++) 
  565.             if (fstab.entries[i].type != PART_SWAP &&
  566.             fstab.entries[i].mntpoint &&
  567.                 fstab.entries[j].mntpoint &&
  568.             !strcmp(fstab.entries[i].mntpoint,
  569.                         fstab.entries[j].mntpoint))
  570.             hasdups = 1;
  571.  
  572.         if (hasdups) {
  573.         winMessage(30, 7, 30, 10, "Duplicate Mounts",
  574.                 "You may not use the same mount point multiple "
  575.                 "times.");
  576.         answer = NULL;
  577.         }
  578.     }
  579.     } while (answer != okay && answer != cancel);
  580.  
  581.     newtFormDestroy(f);
  582.     newtPopWindow();
  583.  
  584.     free(fstabEntNum);
  585.  
  586.     if (answer == cancel) { 
  587.     freeFstab(fstab);
  588.     return INST_CANCEL;
  589.     }
  590.  
  591.     freeFstab(*finalFstab);
  592.     *finalFstab = copyFstab(&fstab);
  593.     freeFstab(fstab);
  594.  
  595.     /* Sort by mount point. This makes mounting everything in the proper
  596.        order trivial */
  597.  
  598.     qsort(finalFstab->entries, finalFstab->numEntries, 
  599.       sizeof(*finalFstab->entries), fstabCmp);
  600.  
  601.     return 0;
  602. }
  603.  
  604. static int mkExt2Filesystem(char * dev) {
  605.     char * mke2fsargs[] = { "mke2fs", NULL, NULL, NULL};
  606.     int rc;
  607.     char message[80];
  608.  
  609.     mke2fsargs[1] = alloca(strlen(dev) + 6);
  610.     strcpy(mke2fsargs[1], "/tmp/");
  611.     strcat(mke2fsargs[1], dev);
  612.  
  613.     if (badBlocks)
  614.     mke2fsargs[2] = "-c";
  615.  
  616.     sprintf(message, "Making ext2 filesystem on /dev/%s...", dev);
  617.     winStatus(45, 3, "Running", message);
  618.  
  619.     devMakeInode(dev, mke2fsargs[1]);
  620.     rc = runProgram(RUN_LOG, "/usr/bin/mke2fs", mke2fsargs);
  621.     devRemoveInode(mke2fsargs[1]);
  622.  
  623.     newtPopWindow();
  624.  
  625.     if (rc)
  626.     return INST_ERROR;
  627.     else
  628.     return 0;
  629. }
  630.  
  631. int queryFormatFilesystems(struct fstab * fstab) {
  632.     newtComponent form, checkList, okay, cancel, sb, text, answer;
  633.     newtComponent checkbox;
  634.     char * states;
  635.     char doCheck = ' ';
  636.     newtComponent * checks;
  637.     char buf[80];
  638.     int i, top;
  639.  
  640.     newtOpenWindow(11, 2, 57, 19, "Format Partitions");
  641.  
  642.     form = newtForm(NULL, NULL, 0);
  643.  
  644.     if (fstab->numEntries > 4) 
  645.     sb = newtVerticalScrollbar(47, 7, 4, 9, 10);
  646.     else
  647.     sb = NULL;
  648.  
  649.     checkList = newtForm(sb, NULL, 0);
  650.     newtFormSetHeight(checkList, 4);
  651.  
  652.     if (sb)
  653.     newtFormAddComponent(checkList, sb);
  654.  
  655.     text = newtTextbox(1, 1, 55, 6, NEWT_TEXTBOX_WRAP);
  656.     newtTextboxSetText(text, "What partitions would you like to "
  657.                "format? We strongly suggest formatting all of the "
  658.                "system partitions, including /, /usr, and /var. There "
  659.                "is no need to format /home or /usr/local if they "
  660.                "have already been configured during a previous "
  661.                "install.");
  662.  
  663.     checks = alloca(sizeof(newtComponent) * fstab->numEntries);
  664.     states = alloca(sizeof(char) * fstab->numEntries);
  665.     for (i = 0, top = 0; i < fstab->numEntries; i++) {
  666.     if (fstab->entries[i].doFormat)
  667.         states[i] = '*';
  668.     else
  669.         states[i] = ' ';
  670.  
  671.     if (fstab->entries[i].type == PART_EXT2) {
  672.         sprintf(buf, "/dev/%-5s  %-33s", fstab->entries[i].device, 
  673.            fstab->entries[i].mntpoint);
  674.         checks[i] = newtCheckbox(3, 7 + top++, buf, states[i], NULL, 
  675.                      &states[i]);
  676.         newtFormAddComponent(checkList, checks[i]);
  677.     } else {
  678.         checks[i] = NULL;
  679.     }
  680.     }
  681.  
  682.     okay = newtButton(12, 14, "Ok");
  683.     cancel = newtButton(34, 14, "Cancel");
  684.     checkbox = newtCheckbox(10, 12, "Check for bad blocks during format",
  685.                 badBlocks ? '*' : ' ', NULL, &doCheck);
  686.     
  687.     newtFormAddComponents(form, text, checkList, checkbox, okay, cancel, NULL);
  688.  
  689.     answer = newtRunForm(form);
  690.  
  691.     newtFormDestroy(form);
  692.     newtPopWindow();
  693.  
  694.     if (answer == cancel) return INST_CANCEL;
  695.  
  696.     for (i = 0; i < fstab->numEntries; i++) {
  697.         if (states[i] != ' ') 
  698.         fstab->entries[i].doFormat = 1; 
  699.     }
  700.  
  701.     if (doCheck == ' ')
  702.     badBlocks = 0;
  703.     else
  704.     badBlocks = 1;
  705.  
  706.     return 0;
  707. }
  708.  
  709. int formatFilesystems(struct fstab * fstab) {
  710.     int i;
  711.  
  712.     for (i = 0; i < fstab->numEntries; i++) {
  713.         if (fstab->entries[i].doFormat)
  714.         mkExt2Filesystem(fstab->entries[i].device);
  715.     }
  716.  
  717.     return 0;
  718. }
  719.  
  720. int doMount(char * dev, char * where, char * fs, int rdonly, int istty) {
  721.     char * buf = NULL;
  722.     int isnfs = 0;
  723.     char * mount_opt = NULL;
  724.     long int flag;
  725.  
  726.     if (!strcmp(fs, "nfs")) isnfs = 1;
  727.  
  728.     logMessage("mounting %s on %s as type %s", dev, where, fs);
  729.  
  730.     if (testing) {
  731.     messageWindow("Test mount", "I would mount /dev/%s on %s",
  732.         "using a(n) %s filesystem.", dev, where, fs);
  733.     } else {
  734.     mkdirChain(where);
  735.  
  736.       if (!isnfs && *dev == '/') {
  737.         buf = dev;
  738.     } else if (!isnfs) {
  739.         buf = alloca(200);
  740.         strcpy(buf, "/tmp/");
  741.         strcat(buf, dev);
  742.  
  743.         if (devMakeInode(dev, buf)) return 1;
  744.     } else {
  745.         char * junk = NULL;
  746.         int morejunk = 0;
  747.  
  748.         buf = dev;
  749.         logMessage("calling nfsmount(%s, %s, &morejunk, &junk, &mount_opt)",
  750.             buf, where);
  751.  
  752.         if (nfsmount(buf, where, &morejunk, &junk, &mount_opt))
  753.         logMessage("\tnfsmount returned non-zero");
  754.     }
  755.  
  756.     flag = MS_MGC_VAL;
  757.     if (rdonly)
  758.         flag |= MS_RDONLY;
  759.     
  760.     logMessage("calling mount(%s, %s, %s, %ld, %p)", buf, where, fs, 
  761.             flag, mount_opt);
  762.  
  763.     if (mount(buf, where, fs, flag, mount_opt)) {
  764.         if (istty) {
  765.         fprintf(stderr, "mount failed: %s\n", strerror(errno));
  766.         } else {
  767.         messageWindow("Error", perrorstr("mount failed"));
  768.         }
  769.         return 1;
  770.     }
  771.  
  772.     if (!isnfs) devRemoveInode(buf);
  773.     }
  774.  
  775.     return 0;
  776. }
  777.  
  778. int mountFilesystems(struct fstab * fstab) {
  779.     int i;
  780.     char buf[1000];
  781.  
  782.     /* don't bother mounting odd (non-ext2) filesystems - we don't need
  783.        them for installs */
  784.  
  785.     /* what about NFS? we should probably mount them to check mount integrity,
  786.        but we don't know if networking is working well enough for us to do
  787.        this */
  788.    
  789.     chdir("/");
  790.  
  791.     for (i = 0; i < fstab->numEntries; i++) {
  792.     strcpy(buf, "/mnt");
  793.     strcat(buf, fstab->entries[i].mntpoint);
  794.  
  795.     if (fstab->entries[i].type == PART_EXT2 ||
  796.         fstab->entries[i].type == PART_NFS ) {
  797.         if (fstab->entries[i].type == PART_EXT2 &&
  798.         !doMount(fstab->entries[i].device, buf, "ext2", 0, 0))
  799.         fstab->entries[i].isMounted = 1;
  800.         else if (fstab->entries[i].type == PART_NFS &&
  801.         !doMount(fstab->entries[i].device, buf, "nfs", 0, 0))
  802.         fstab->entries[i].isMounted = 1;
  803.         else {
  804.         logMessage("unmounting all filesystems due to mount error");
  805.         umountFilesystems(fstab);
  806.         return INST_ERROR;
  807.         }
  808.     } else {
  809.         logMessage("creating directory %s", buf);
  810.         mkdirChain(buf);
  811.     }
  812.     }
  813.  
  814.     return 0;
  815. }
  816.  
  817. int umountFilesystems(struct fstab * fstab) {
  818.     char buf[1000];
  819.     int i;
  820.     int olderrno;
  821.  
  822.     logMessage("unmounting all filesystems");
  823.  
  824.     chdir("/");
  825.  
  826.     if (testing) return 0;
  827.  
  828.     for (i = fstab->numEntries - 1; i >= 0; i--) {
  829.     if (fstab->entries[i].isMounted) {
  830.         strcpy(buf, "/mnt");
  831.         strcat(buf, fstab->entries[i].mntpoint);
  832.  
  833.         fstab->entries[i].isMounted = 0;
  834.         if (umount(buf)) {
  835.         olderrno = errno;
  836.         logMessage("error unmounting %s: %s\n", buf, strerror(errno));
  837.         errno = olderrno;
  838.         errorWindow("error unmounting filesystem: %s");
  839.         }
  840.     }    
  841.     }
  842.  
  843.     return 0;
  844. }
  845.  
  846. static int mkdirChain(char * origChain) {
  847.     char * chain;
  848.     char * chptr;
  849.  
  850.     chain = alloca(strlen(origChain) + 1);
  851.     strcpy(chain, origChain);
  852.     chptr = chain;
  853.  
  854.     if (testing) return 0;
  855.  
  856.     while ((chptr = strchr(chptr, '/'))) {
  857.     *chptr = '\0';
  858.     if (mkdirIfNone(chain)) {
  859.         *chptr = '/';
  860.         return INST_ERROR;
  861.     }
  862.  
  863.     *chptr = '/';
  864.     chptr++;
  865.     }
  866.  
  867.     if (mkdirIfNone(chain))
  868.     return INST_ERROR;
  869.  
  870.     return 0;
  871. }
  872.  
  873. static int mkdirIfNone(char * directory) {
  874.     int rc, mkerr;
  875.     char * chptr;
  876.  
  877.     /* If the file exists it *better* be a directory -- I'm not going to
  878.        actually check or anything */
  879.     if (!access(directory, X_OK)) return 0;
  880.  
  881.     /* if the path is '/' we get ENOFILE not found" from mkdir, rather
  882.        then EEXIST which is weird */
  883.     for (chptr = directory; *chptr; chptr++)
  884.         if (*chptr != '/') break;
  885.     if (!*chptr) return 0;
  886.  
  887.     rc = mkdir(directory, 0755);
  888.     mkerr = errno;
  889.  
  890.     logMessage("creating directory %s rc = %d", directory, rc);
  891.  
  892.     if (!rc || mkerr == EEXIST) return 0;
  893.  
  894.     logMessage("    error: %s", strerror(mkerr));
  895.  
  896.     return INST_ERROR;
  897. }
  898.  
  899. int writeFstab(struct fstab * fstab) {
  900.     int i;
  901.     FILE * f;
  902.     char * fs = NULL;
  903.     int freq = 0;
  904.     int passno = 0;
  905.     int bad;
  906.     char * devFormat = "/dev/%-18s %-23s %-7s %-15s %d %d\n";
  907.     char * nfsFormat = "%-23s %-23s %-7s %-15s %d %d\n";
  908.     char * procFormat = "%-23s %-23s %-7s %-15s %d %d\n";
  909.     char * options;
  910.     char * format;
  911.  
  912.     if (testing)
  913.     return 0;
  914.  
  915.     logMessage("creating /etc/fstab");
  916.  
  917.     f = fopen("/mnt/etc/fstab", "w");
  918.     if (!f) {
  919.     errorWindow("error creating /mnt/etc/fstab");
  920.     return INST_ERROR;
  921.     }
  922.  
  923.     for (i = 0; i < fstab->numEntries; i++) {
  924.     if (!fstab->entries[i].mntpoint) continue;
  925.  
  926.     passno = 0;
  927.     freq = 0;
  928.     format = devFormat;
  929.         options = "defaults";
  930.  
  931.     bad = 0;
  932.     switch (fstab->entries[i].type) {
  933.       case PART_EXT2:
  934.         freq = 1;
  935.         fs = "ext2";
  936.         if (!strcmp(fstab->entries[i].mntpoint, "/"))
  937.         passno = 1;
  938.         else
  939.         passno = 2;
  940.       
  941.         break;
  942.  
  943.       case PART_NFS:
  944.         fs = "nfs";
  945.         options = "ro";
  946.         format = nfsFormat;
  947.         break;
  948.  
  949.       case PART_SWAP:
  950.         fs = "swap";
  951.         break;
  952.  
  953.       case PART_DOS:
  954.         fs = "msdos";
  955.         break;
  956.  
  957.       case PART_HPFS:
  958.         fs = "hpfs";
  959.         break;
  960.  
  961.       default:
  962.         bad = 1;
  963.     }
  964.  
  965.     if (!bad)
  966.         fprintf(f, format, fstab->entries[i].device, 
  967.             fstab->entries[i].mntpoint, fs, options, freq, passno);
  968.     }
  969.  
  970.     fprintf(f, devFormat, "fd0", "/mnt/floppy", "ext2", "noauto", 0, 0);
  971.     fprintf(f, procFormat, "none", "/proc", "proc", "defaults", 0, 0);
  972.  
  973.     fclose(f);
  974.  
  975.     return 0;
  976. }
  977.  
  978. int addFstabEntry(struct fstab * fstab, struct fstabEntry entry) {
  979.     int i;
  980.  
  981.     for (i = 0; i < fstab->numEntries; i++) 
  982.     if (!strcmp(entry.device, fstab->entries[i].device))
  983.         break;
  984.  
  985.     if (i == fstab->numEntries) {
  986.     fstab->numEntries++;
  987.     if (fstab->numEntries > 1)
  988.         fstab->entries = realloc(fstab->entries, 
  989.                 sizeof(entry) * fstab->numEntries);
  990.     else
  991.         fstab->entries = malloc(sizeof(entry));
  992.     }
  993.  
  994.     fstab->entries[i] = entry;
  995.  
  996.     return i;
  997. }
  998.  
  999. int activeSwapSpace(struct partitionTable * table, struct fstab * finalFstab) {
  1000.     newtComponent form, checkList, okay, cancel, sb, text, answer, label;
  1001.     newtComponent check, partition, cont;
  1002.     char * states;
  1003.     char buf[80];
  1004.     int i, top, j;
  1005.     struct fstabEntry entry;
  1006.     struct fstabEntry ** entries;
  1007.     struct fstab fstab;
  1008.     static int firstTime = 1;
  1009.  
  1010.     fstab = copyFstab(finalFstab);    
  1011.  
  1012.     form = newtForm(NULL, NULL, 0);
  1013.  
  1014.     for (i = j = 0; i < table->count; i++)
  1015.     if (table->parts[i].type == PART_SWAP)
  1016.         j++;
  1017.  
  1018.     if (!j) {
  1019.     newtOpenWindow(18, 6, 44, 10, "Setup Swap");
  1020.     text = newtTextbox(1, 1, 42, 3, NEWT_TEXTBOX_WRAP);
  1021.     newtTextboxSetText(text, "You don't have any swap space defined. Would "
  1022.                  "you like to continue, or repartition your disk?");
  1023.     
  1024.     cont = newtButton(6, 6, "Continue");
  1025.     partition = newtButton(25, 6, "Cancel");
  1026.  
  1027.     form = newtForm(NULL, NULL, 0);
  1028.     newtFormAddComponents(form, text, cont, partition, NULL);
  1029.     
  1030.     answer = newtRunForm(form);
  1031.     newtFormDestroy(form);
  1032.     newtPopWindow();
  1033.  
  1034.     if (answer == partition)
  1035.        return INST_CANCEL;
  1036.     
  1037.     return 0;
  1038.     }
  1039.  
  1040.     newtOpenWindow(15, 4, 54, 14, "Active Swap Space");
  1041.     
  1042.     if (j > 3)
  1043.     sb = newtVerticalScrollbar(47, 7, 3, 9, 10);
  1044.     else
  1045.     sb = NULL;
  1046.  
  1047.     checkList = newtForm(sb, NULL, 0);
  1048.     newtFormSetHeight(checkList, 3);
  1049.  
  1050.     if (sb)
  1051.     newtFormAddComponent(checkList, sb);
  1052.  
  1053.     text = newtTextbox(1, 1, 52, 4, NEWT_TEXTBOX_WRAP);
  1054.     newtTextboxSetText(text, "What partitions would you like to "
  1055.                "use for swap space? This will destroy any "
  1056.                "information already on the partition.");
  1057.  
  1058.     label = newtLabel(4, 5, "  Device          Begin        End   Size (k)");
  1059.  
  1060.     states = alloca(sizeof(char) * table->count);
  1061.     entries = alloca(sizeof(*entries) * table->count);
  1062.  
  1063.     for (i = 0, top = 0; i < table->count; i++) {
  1064.     if (table->parts[i].type != PART_SWAP) continue;
  1065.  
  1066.     for (j = 0; j < fstab.numEntries; j++) 
  1067.         if (!strcmp(table->parts[i].device, fstab.entries[j].device))
  1068.         break;
  1069.  
  1070.     if ((j < fstab.numEntries && fstab.entries[j].mntpoint) || 
  1071.         (firstTime && !testing))
  1072.         states[i] = '*';
  1073.     else
  1074.         states[i] = ' ';
  1075.  
  1076.     if (j < fstab.numEntries) 
  1077.         entries[i] = fstab.entries + j;
  1078.     else
  1079.         entries[i] = NULL;
  1080.  
  1081.     sprintf(buf, "/dev/%-5s  %9d  %9d  %9d", table->parts[i].device, 
  1082.         table->parts[i].begin, table->parts[i].end, 
  1083.         table->parts[i].size);
  1084.     check = newtCheckbox(2, 6 + top++, buf, states[i], NULL, 
  1085.                  &states[i]);
  1086.     newtFormAddComponent(checkList, check);
  1087.     }
  1088.  
  1089.     firstTime = 0;
  1090.  
  1091.     okay = newtButton(9, 10, "Ok");
  1092.     cancel = newtButton(28, 10, "Cancel");
  1093.     
  1094.     newtFormAddComponents(form, text, label, checkList, okay, cancel, NULL);
  1095.  
  1096.     answer = newtRunForm(form);
  1097.  
  1098.     newtFormDestroy(form);
  1099.     newtPopWindow();
  1100.  
  1101.     if (answer == cancel) {
  1102.     freeFstab(fstab);
  1103.     return INST_CANCEL;
  1104.     }
  1105.  
  1106.     for (i = 0; i < table->count; i++) {
  1107.     if (table->parts[i].type != PART_SWAP) continue;
  1108.  
  1109.         if (states[i] != ' ') {
  1110.         if (entries[i])
  1111.         entries[i]->mntpoint = strdup("swap");
  1112.         else {
  1113.         initFstabEntry(&entry);
  1114.         entry.device = strdup(table->parts[i].device);
  1115.         entry.size = table->parts[i].size;
  1116.         entry.type = table->parts[i].type;
  1117.         entry.tagName = table->parts[i].tagName;
  1118.         entry.mntpoint = strdup("swap");
  1119.  
  1120.         addFstabEntry(&fstab, entry);
  1121.         }
  1122.     } else if (entries[i]) {
  1123.         free(entries[i]->mntpoint);
  1124.         entries[i]->mntpoint = NULL;
  1125.     }
  1126.     }
  1127.  
  1128.     if (canEnableSwap) {
  1129.     for (i = 0; i < fstab.numEntries; i++) {
  1130.         if (fstab.entries[i].type == PART_SWAP &&
  1131.         fstab.entries[i].mntpoint) {
  1132.         enableswap(fstab.entries[i].device, 0, 1);
  1133.         canEnableSwap = 0;
  1134.         }
  1135.     }
  1136.     }
  1137.  
  1138.     freeFstab(*finalFstab);
  1139.     *finalFstab = copyFstab(&fstab);
  1140.     freeFstab(fstab);
  1141.  
  1142.     return 0;
  1143. }
  1144.