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

  1. /* Newt based fdisk program
  2.  *
  3.  * Michael Fulbright (msf@redhat.com)
  4.  *
  5.  * Copyright 1998 Red Hat Software 
  6.  *
  7.  * This software may be freely redistributed under the terms of the GNU
  8.  * public license.
  9.  *
  10.  * You should have received a copy of the GNU General Public License
  11.  * along with this program; if not, write to the Free Software
  12.  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  13.  *
  14.  */
  15.  
  16. #include <alloca.h>
  17. #include <stdio.h>
  18. #include <unistd.h>
  19. #include <stdlib.h>
  20. #include <errno.h>
  21. #include <string.h>
  22. #include <malloc.h>
  23. #include <ctype.h>
  24. #include <fcntl.h>
  25. #include <errno.h>
  26.  
  27. #include <newt.h>
  28.  
  29. #include "kickstart.h"
  30. #include "fs.h"
  31. #include "fsedit.h"
  32. #include "hd.h"
  33. #include "install.h"
  34. #include "intl.h"
  35. #include "libfdisk/libfdisk.h"
  36. #include "devices.h"
  37. #include "windows.h"
  38.  
  39. #include <popt.h>
  40.  
  41. #define VERSION_STR "1.00"
  42.  
  43. extern int testing;
  44.  
  45. /* static char version[] = "0.01"; */
  46.  
  47. struct attemptedPartition normalPartitioning[] = {
  48. #if defined(__i386__)
  49.     { "/boot",    16,    LINUX_NATIVE_PARTITION,    0, -1 },
  50. #elif defined(__alpha__)
  51.     { "/dos",    2,    DOS_PRIMARY_lt32MEG_PARTITION,    0, 1 },
  52. #endif
  53.     { "/",        400,    LINUX_NATIVE_PARTITION,    1, -1 },
  54.     { "Swap-auto",    32,    LINUX_SWAP_PARTITION,    0, -1 },
  55.     { NULL, 0, 0, 0 }
  56. };
  57.  
  58. /* need to move somewhere else eventually! */
  59. /* mostly gleamed from fdisk.[ch]          */
  60. struct parttypes {
  61.       unsigned char index;
  62.       char *name;
  63. };
  64.  
  65. /* this isn't const, as we have a loop which does i18n conversion on these */
  66. static struct parttypes allparttypes[] = {
  67.     {0, "Empty"},
  68.     {1, "DOS 12-bit FAT"},
  69.     {2, "XENIX root"},
  70.     {3, "XENIX usr"},
  71.     {4, "DOS 16-bit <32M"},
  72.     {5, "Extended"},
  73.     {6, "DOS 16-bit >=32M"},
  74.     {7, "OS/2 HPFS"},               /* or QNX? */
  75.     {8, "AIX"},
  76.     {9, "AIX bootable"},
  77.     {10, "OS/2 Boot Manager"},
  78.     {0xb, "Win95 FAT32"},
  79.     {0xc, "Win95 FAT32"},
  80.     {0xe, "Win95 FAT32"},
  81.     {0x40, "Venix 80286"},
  82.     {0x51, "Novell?"},
  83.     {0x52, "Microport"},            /* or CPM? */
  84.     {0x63, "GNU HURD"},             /* or System V/386? */
  85.     {0x64, "Novell Netware 286"},
  86.     {0x65, "Novell Netware 386"},
  87.     {0x75, "PC/IX"},
  88.     {0x80, "Old MINIX"},            /* Minix 1.4a and earlier */
  89.  
  90.     {0x81, "Linux/MINIX"}, /* Minix 1.4b and later */
  91.     {0x82, "Linux swap"},
  92.     {0x83, "Linux native"},
  93.  
  94.     {0x93, "Amoeba"},
  95.     {0x94, "Amoeba BBT"},           /* (bad block table) */
  96.     {0xa5, "BSD/386"},
  97.     {0xb7, "BSDI fs"},
  98.     {0xb8, "BSDI swap"},
  99.     {0xc7, "Syrinx"},
  100.     {0xdb, "CP/M"},                 /* or Concurrent DOS? */
  101.     {0xe1, "DOS access"},
  102.     {0xe3, "DOS R/O"},
  103.     {0xf2, "DOS secondary"},
  104.     {0xff, "BBT"}                   /* (bad track table) */
  105. };
  106.  
  107. int nparttypes = sizeof (allparttypes) / sizeof (struct parttypes);
  108.  
  109.  
  110. /* hardcoded, maybe someday we'll get these from tty ? */
  111. int screen_width=80;
  112. int screen_height=25;
  113.  
  114. #define MAX_HARDDRIVES  16
  115.  
  116. #define SECPERMEG 2048
  117.  
  118. /* clean up that string */
  119. static void TrimWhitespace( char *s ) {
  120.     char *f, *l, *p, *q;
  121.  
  122.     if (!(*s))
  123.         return;
  124.     
  125.     for (f=s; *f && isspace(*f); f++) ;
  126.  
  127.     if (!*f) {
  128.         *s = '\0';
  129.         return;
  130.     }
  131.     
  132.     for (l=f+strlen(f)-1; isspace(*l) ; l--)
  133.     *l = '\0';
  134.         
  135.     q = s, p = f;
  136.     while (*p)
  137.         *q++ = *p++;
  138.     
  139.     *q = '\0';
  140. }
  141.  
  142. /* fill in the                                          */
  143. /* position in the status line, up to length characters */
  144. /* if cen=1, center it                                    */
  145. static void BuildTableField( char *line, char *val,
  146.                  int pos, int length, int cen ) {
  147.     char *p, *q;
  148.     int i;
  149.     int c;
  150.  
  151.     /* lets center field value in the field */
  152.     if (cen) {
  153.     c = strlen(val);
  154.     c = (length-c)/2;
  155.     if (c < 0)
  156.         c = 0;
  157.     } else
  158.     c=0;
  159.  
  160.     /* first setup device name */
  161.     for (p=val, q=line+pos+c, i=c; *p && i<length; p++, q++, i++)
  162.     *q = *p;
  163. }
  164.  
  165. #if 0
  166. /* some fdisk functions which don't have homes yet */
  167. static int fdiskPartitionIsBootable( HardDrive *hd, Partition *p ) {
  168.     unsigned int i, bootable;
  169.  
  170.     /* see if drive #1 or #2 is a possible drive for partition */
  171.     bootable = fdiskThisDriveSetIsActive( &p->drive, 1 ) ||
  172.     fdiskThisDriveSetIsActive( &p->drive, 2 );
  173.  
  174.     /* if so, see if rest are EXCLUDED */
  175.     if (bootable) {
  176.     for (i=3; i<MAX_DRIVESET_NUM; i++) {
  177.         if (fdiskThisDriveSetIsActive( &p->drive, i)) {
  178.         bootable = 0;
  179.         break;
  180.         }
  181.     }
  182.     }
  183.     
  184.     if (bootable) {
  185.     if (p->endcyl.active && p->endcyl.max < 1024) {
  186.         bootable = 1;
  187.     } else if (p->immutable) {
  188.         unsigned int end, c, h, s;
  189.         end = p->start.current + p->size.current - 1;
  190.         fdiskSectorToCHS( hd, end, &c, &h, &s );
  191.         if (c < 1024)
  192.         bootable = 1;
  193.         else
  194.         bootable = 0;
  195.     } else {
  196.         bootable = 0;
  197.     }
  198.     }
  199.  
  200.     return bootable;
  201. }
  202. #endif
  203.  
  204. /* check a mount point to make sure its valid */
  205. /* returns non-zero if bad mount point        */
  206. static int badMountPoint(unsigned int type, char * item) {
  207.     char * chptr = item;
  208.  
  209.     if (!strncmp(item, "/dev", 4) ||
  210.         !strncmp(item, "/bin", 4) ||
  211.         !strncmp(item, "/sbin", 5) ||
  212.         !strncmp(item, "/etc", 4) ||
  213. #ifdef __sparc__
  214.         !strncmp(item, "/boot", 5) ||
  215. #endif
  216.         !strncmp(item, "/lib", 4)) {
  217.         newtWinMessage(_("Bad Mount Point"), _("Ok"),
  218.                     _("The %s directory must be on the root filesystem."),
  219.             item);
  220.     return 1;
  221.     }
  222.  
  223.     if (*chptr != '/') {
  224.         newtWinMessage(_("Bad Mount Point"), _("Ok"),
  225.                     _("The mount point %s is illegal.\n\n"
  226.             "Mount points must begin with a leading /."), item);
  227.         return 1;
  228.     } 
  229.  
  230.     if (*(chptr + 1) && *(chptr + strlen(chptr) - 1) == '/') {
  231.         newtWinMessage(_("Bad Mount Point"), _("Ok"),
  232.                     _("The mount point %s is illegal.\n\n"
  233.                       "Mount points may not end with a /."), item);
  234.         return 1;
  235.     } 
  236.  
  237.     while (*chptr && isprint(*chptr)) chptr++;
  238.  
  239.     if (*chptr) {
  240.         newtWinMessage(_("Bad Mount Point"), _("Ok"),
  241.                     _("The mount point %s is illegal.\n\n"
  242.                     "Mount points may only printable characters."), item);
  243.         return 1;
  244.     }
  245.  
  246.     if (type != LINUX_NATIVE_PARTITION && (
  247.          !strncmp(item, "/var", 4) ||
  248.          !strncmp(item, "/tmp", 4) ||
  249.          !strncmp(item, "/boot", 4) ||
  250.          !strcmp(item, "/") ||
  251.          !strncmp(item, "/root", 4))) {
  252.         newtWinMessage(_("Bad Mount Point"), _("Ok"),
  253.                     _("The mount point %s is illegal.\n\n"
  254.                       "System partitions must be on Linux Native "
  255.                       "partitions."), item);
  256.         return 1;
  257.     }
  258.  
  259.     if (type != LINUX_NATIVE_PARTITION &&
  260.     type != NFS_REMOTE_PARTITION &&
  261.         !strncmp(item, "/usr", 4)) {
  262.         newtWinMessage(_("Bad Mount Point"), _("Ok"),
  263.                     _("The mount point %s is illegal.\n\n"
  264.                       "/usr must be on a Linux Native partition "
  265.                       "or an NFS volume."), item);
  266.         return 1;
  267.     }
  268.  
  269.     return 0;
  270. }
  271.  
  272. /*                              */
  273. /* NEWT/screen related routines */
  274. /*                              */
  275.  
  276. /* handles standard fdisk type errors */
  277. /* returns non-zero if user picked "yes" response, and zero if "no" */
  278. static int ErrorDialog(char *title, char *errbody, char *errmsg,
  279.                char *yesmsg, char *nomsg) {
  280.  
  281.     int retcode;
  282.     char *buf;
  283.  
  284.  
  285.     /* I don't know if this is what msf intended, but it is a whole lot 
  286.        easier. */
  287.     buf = alloca(strlen(errbody)+strlen(errmsg) + 10);
  288.     sprintf(buf, "%s: %s", errbody, errmsg);
  289.     retcode = newtWinChoice(title, yesmsg, nomsg, buf);
  290.  
  291.     if (retcode == 2) return 0; else return 1;
  292. }
  293.  
  294. static int HandleFdiskError( int status, char *errbody, char *y, char *n ) {
  295.     char errmsg[250];
  296.     char yesmsg[]="Yes";
  297.     char nomsg[] ="No";
  298.     
  299.     if (status < 0) {
  300.     if (errno < sys_nerr-1)
  301.         strncpy(errmsg,sys_errlist[errno],sizeof(errmsg));
  302.     else
  303.         snprintf(errmsg,sizeof(errmsg), _("System error %d"), errno);
  304.     } else {
  305.     if (status < fdisk_nerr)
  306.         strcpy(errmsg, fdisk_errlist[status]);
  307.     else
  308.         snprintf(errmsg,sizeof(errmsg), "libfdisk error %d",errno);
  309.     }
  310.  
  311.     if (y != NULL && n != NULL)
  312.     return ErrorDialog( _("Fdisk Error"), errbody, errmsg, y, n);
  313.     else
  314.     return ErrorDialog( _("Fdisk Error"), errbody,errmsg,yesmsg,nomsg);
  315. }
  316.  
  317. /* give summary of why partitions weren't allocated */
  318. static void showReasons( PartitionSpec *spec ) {
  319.     newtComponent tbox, form, ok, lbox;
  320.     int i;
  321.     
  322.     for (i=0; i<spec->num; i++)
  323.     if (spec->entry[i].status == REQUEST_DENIED)
  324.         break;
  325.  
  326.     /* nothing going on here, keep moving along */
  327.     if (i == spec->num)
  328.     return;
  329.     
  330.     /* build list of why they all failed */
  331.     newtCenteredWindow(60, 18, _("Unallocated Partitions"));
  332.     form = newtForm(NULL,NULL,0);
  333.  
  334.     tbox = newtTextbox(5, 1, 50, 5, NEWT_FLAG_WRAP );
  335.     newtTextboxSetText(tbox, _("There are currently unallocated partition(s) "
  336.                "present in the list of requested partitions. The "
  337.                "unallocated partition(s) are shown below, along with "
  338.                "the reason they were not allocated."));
  339.  
  340.     lbox = newtListbox(10, 6, 5, NEWT_FLAG_RETURNEXIT | NEWT_FLAG_SCROLL );
  341.     for (i=0; i<spec->num; i++)
  342.     if (spec->entry[i].status == REQUEST_DENIED) {
  343.         char tmpstr[80];
  344.         char *pname = spec->entry[i].name;
  345.         char *s, *t;
  346.         
  347.         memset(tmpstr, ' ', 80);
  348.         if (strncmp("Exist", pname, 5) && strncmp("Swap", pname, 4) &&
  349.         strncmp("Dos", pname, 3))
  350.         t = pname;
  351.         else
  352.         t = NULL;
  353.         for (s=tmpstr;t && *t; t++,s++)
  354.         *s = *t;
  355.         
  356.         t = GetReasonString(spec->entry[i].reason);
  357.         for (s=tmpstr+20;t && *t; t++,s++)
  358.         *s = *t;
  359.         *s = '\0';
  360.         newtListboxAddEntry(lbox, tmpstr, NULL);
  361.     }
  362.  
  363.     ok = newtButton(25, 13, _("Ok"));
  364.     newtFormAddComponents(form, tbox, lbox, ok, NULL);
  365.     newtFormSetCurrent(form, ok);
  366.  
  367.     newtRunForm(form);
  368.  
  369.     newtPopWindow();
  370.     newtFormDestroy(form);
  371. }
  372.  
  373. /* read in the requested drives                                 */
  374. /* pass an array of names of block devices, returns 0 if ok     */
  375. static int ReadDrives( char **drives, int numdrives,
  376.                HardDrive **hdarr, unsigned int *numhd,
  377.                int forcezero, int readOnly) {
  378.  
  379.     char errbody[250];
  380.     int  i, done, status;
  381.     
  382.     /* loop over all specified block devices */
  383.     *numhd = 0;
  384.     for (i=0; i < numdrives; ) {
  385.     status = fdiskOpenDevice(drives[i], *numhd+1, &hdarr[*numhd]);
  386.     if (status != FDISK_SUCCESS) {
  387.  
  388.       /* HORRIBLE HACK               XXX*/
  389.  
  390. #ifdef __sparc__
  391.       if (status == FDISK_ERR_CORRUPT) { /* bad Sun disklabel */
  392.         snprintf(errbody, sizeof(errbody),
  393.              _("A disk with a corrupt Sun disklabel has been "
  394.                "found while reading block device %s.  You must "
  395.                        "use fdisk to create and write a new label to "
  396.                "this device."), drives[i]);
  397.         if (newtWinChoice(_("Corrupt Sun disklabel"),
  398.                   _("Back"), _("Skip Drive"), errbody) == 1)
  399.           return INST_CANCEL;
  400.         else {
  401.           i++;
  402.         continue;
  403.         }
  404.       }
  405. #endif
  406.         snprintf(errbody, sizeof(errbody),
  407.              _("An error occurred reading the partition table for the "
  408.                "block device %s.  The error was:"), drives[i]);
  409.         if (HandleFdiskError( status, errbody, "Retry", "Skip Drive" ))
  410.         continue;
  411.         else {
  412.         i++;
  413.         continue;
  414.         }
  415.     } else {
  416.         done = 0;
  417.         while (!done) {
  418.         status = fdiskReadPartitions( hdarr[*numhd] );
  419.         if (status != FDISK_SUCCESS) {
  420.             int rc;
  421.             
  422.             if (status == FDISK_ERR_BADMAGIC) {
  423.             if (forcezero) {
  424.                 if (!testing)
  425.                 #ifdef sparc
  426.                     fdiskInitSunLabel(hdarr[*numhd]);
  427.                 #else
  428.                     fdiskZeroMBR(hdarr[*numhd]);
  429.                 #endif
  430.                 fdiskCloseDevice(hdarr[*numhd]);
  431.                 done = 1;
  432.             } else {
  433.                 if (kickstart) {
  434.                 newtWinMessage(_("Bad Partition Table"), 
  435.                        _("Ok"),
  436.                        _("The partition table on device %s is "
  437.                          "corrupted.  To create new partitions "
  438.                          "it must be initialized. You can "
  439.                          "specify \"zerombr yes\" in the "
  440.                          "kickstart file to have this done "
  441.                          "automatically"), drives[i]+5);
  442.                 return INST_ERROR;
  443.                 }
  444.                 
  445.                 rc = newtWinChoice(_("Bad Partition Table"),
  446.                            _("Initialize"), _("Skip Drive"),
  447.                        _("The partition table on device %s is "
  448.                          "corrupted.  To create new partitions "
  449.                          "it must be initialized,"
  450.                          " causing the loss of ALL DATA on "
  451.                          "this drive."), drives[i]+5);
  452.                 
  453.                 if (rc != 2) {
  454.                 if (!testing)
  455.                     #ifdef sparc
  456.                     fdiskInitSunLabel(hdarr[*numhd]);
  457.                     #else
  458.                     fdiskZeroMBR(hdarr[*numhd]);
  459.                     #endif
  460.                 fdiskCloseDevice(hdarr[*numhd]);
  461.                 done = 1;
  462.                 } else {
  463.                 i++;
  464.                 fdiskCloseDevice(hdarr[*numhd]);
  465.                 done = 1;
  466.                 }
  467.             }
  468.             } else {            
  469.             snprintf(errbody, sizeof(errbody),
  470.              _("An error occurred reading the partition table "
  471.                "for the block device %s.  The error was:"),
  472.                  drives[i]+5);
  473.             if (HandleFdiskError(status,errbody,
  474.                          _("Retry"), _("Skip Drive"))){
  475.                 fdiskCloseDevice(hdarr[*numhd]);
  476.                 done = 1;
  477.             } else {
  478.                 i++;
  479.                 fdiskCloseDevice(hdarr[*numhd]);
  480.                 done = 1;
  481.             }
  482.             }
  483.         /* THIS IS A HORRIBLE NASTY HACK */
  484.         #ifdef __alpha__
  485.         } else if (hdarr[i]->limits.maxPrimary > 4 && !readOnly) {
  486.             newtWinMessage(_("BSD Disklabel"), _("Ok"), _("A disk with "
  487.                 "a BSD disklabel has been found. The Red Hat "
  488.                 "installation only supports BSD Disklabels in "
  489.                 "read-only mode, so you must use a custom install "
  490.                 "and fdisk (instead of Disk Druid) for "
  491.                 "machines with BSD Disklabels."));
  492.             return INST_CANCEL;
  493.         #endif
  494.         } else {
  495.             *numhd += 1;
  496.             i++;
  497.             done = 1;
  498.         }
  499.         }
  500.     }
  501.     }
  502.  
  503.     return FDISK_SUCCESS;
  504.     
  505. }
  506.  
  507. /* see if anything really changed */
  508. int DisksChanged( HardDrive **oldhd, HardDrive **newhd, unsigned int numhd ) {
  509.  
  510.     int i, j;
  511.     
  512.     /* see if partition tables are identical */
  513.     for (i=0; i<numhd; i++)
  514.     for (j=0; j<MAX_PARTITIONS; j++) {
  515.         if (memcmp(&oldhd[i]->table[j],&newhd[i]->table[j],
  516.                sizeof(Partition)))
  517.         return 1;
  518.         if (memcmp(&oldhd[i]->eptable[j],&newhd[i]->eptable[j],
  519.                sizeof(Partition)))
  520.         return 1;
  521.     }
  522.  
  523.     return 0;
  524. }
  525.         
  526.         
  527. /* edit an existing partition spec */
  528. /* callback for type listbox */
  529. struct typebox_cbstruct {
  530.     newtComponent *entry;
  531.     char          *val;
  532. };
  533.  
  534. static char typebox_mp[100];
  535. static int  inswapentry;
  536.  
  537. static void typebox_scroll(newtComponent box, struct typebox_cbstruct *s ) {
  538.     int type;
  539.     
  540.     type = (long) newtListboxGetCurrent(box);
  541.     if (type == LINUX_SWAP_PARTITION && !inswapentry) {
  542.     strncpy(typebox_mp, s->val, 100);
  543.     newtEntrySetFlags(*s->entry, _("Swap Partition"), 0);
  544.     inswapentry = 1;
  545.     newtEntrySetFlags(*s->entry, NEWT_FLAG_DISABLED, NEWT_FLAGS_SET);
  546.     } else if (inswapentry) {
  547.     newtEntrySetFlags(*s->entry, NEWT_FLAG_DISABLED, NEWT_FLAGS_RESET);
  548.     if (typebox_mp[0] == -1) /* just clear string if it isnt initialized */
  549.         typebox_mp[0] = '\0';
  550.     newtEntrySet(*s->entry, typebox_mp, 1);
  551.     inswapentry = 0;
  552.     }
  553. }
  554.  
  555. struct driveentry_struct {
  556.     newtComponent cb;
  557.     char          state;
  558. };
  559.  
  560. struct entrybox_cbstruct {
  561.     newtComponent *form;
  562.     char          *val;
  563.     unsigned char *val2;
  564.     DriveSet      curds, origds;
  565.     int           numhd;
  566.     HardDrive     **hdarr;
  567.     struct driveentry_struct *de;
  568.     int           dobootable;
  569. };
  570.  
  571. static void entrybox_cb(newtComponent box, struct entrybox_cbstruct *s) {
  572.     unsigned char boot;
  573.     int           j;
  574.     
  575.     if (s->dobootable) {
  576.     boot = (!strcmp(s->val, "/") || !strcmp(s->val, "/boot")) ? '*' : ' ';
  577.     if (boot == '*' && *(s->val2) == ' ')
  578.         memcpy(&s->origds, &s->curds, sizeof(DriveSet));
  579.         *(s->val2) = boot;
  580.     if (boot == '*') {
  581.         fdiskDeactivateAllDriveSet( &s->curds );
  582.         fdiskActivateDriveSet( &s->curds, 1 );
  583.         fdiskActivateDriveSet( &s->curds, 2 );
  584.     } else {
  585.         memcpy(&s->curds, &s->origds, sizeof(DriveSet));
  586.     }
  587.  
  588.     for (j=0; j<s->numhd; j++)
  589.         s->de[j].state=fdiskThisDriveSetIsActive(&s->curds,
  590.                              s->hdarr[j]->num)?'*':' ';
  591.     
  592.     newtDrawForm(*s->form);
  593.     }
  594. }    
  595.  
  596. #define NEW_PARTSPEC "NewPartition"
  597.  
  598. static int EditPartitionSpec(HardDrive **hdarr, unsigned int numhd,
  599.               PartitionSpec      *spec, 
  600.               PartitionSpecEntry *entry) {
  601.     int j;
  602.     unsigned int hdidx, tmpuint;
  603.     int          tmpint;
  604.     char tmpstr[80];
  605.     
  606.     Partition *p;
  607.     newtComponent form, mntptentry;
  608.     newtComponent sizeentry, growentry, bootentry, typeentry;
  609.     newtComponent sb, driveform;
  610.     newtComponent ok, cancel, answer;
  611.  
  612.     struct typebox_cbstruct  cb1;
  613.     struct entrybox_cbstruct cb2;
  614.     struct driveentry_struct driveentry[MAX_HARDDRIVES];
  615.     
  616.     char *mntpt=NULL, *size=NULL, *eptr;
  617.     char titlestr[80];
  618.     unsigned char boot, grow;
  619.  
  620.     int row, col;
  621.     int status=0;
  622.     int done;
  623.     int newpartition;
  624.     int cval;
  625.     int   numfstypes   = 4;
  626.     char  fstypesnames[][20] = { "Linux Swap", "Linux Native",
  627.                              "DOS 16-bit <32M", "DOS 16-bit >=32M"};
  628.     int   fstypes[] = {0x82, 0x83, 0x4, 0x6};
  629.  
  630.     p = (Partition *) alloca(sizeof(Partition));
  631.     memcpy(p, &entry->partition, sizeof(Partition));
  632.  
  633.     newpartition = (strcmp(entry->name, NEW_PARTSPEC) == 0);
  634.  
  635.     if (p->immutable)
  636.     cval = -2;
  637.     else
  638.     cval = ((numhd > 3) ? 4 : numhd);
  639.  
  640.     /* make title line a little more descriptive */
  641.     if (newpartition) {
  642.     strcpy(titlestr, "Edit New Partition");
  643.     } else if (p->immutable) {
  644.     for (hdidx=0; hdidx < numhd &&
  645.          hdarr[hdidx]->num != p->drive.current; hdidx++);
  646.     if (hdidx != numhd) {
  647.         snprintf(titlestr, 80, "%s: /dev/%s%d", _("Edit Partition"),
  648.              hdarr[hdidx]->name+5, p->num.current);
  649.         if (entry->name && *entry->name && strncmp(entry->name, "Exist", 5))
  650.         snprintf(titlestr+strlen(titlestr), 80-strlen(titlestr),
  651.              " (%s)", entry->name);
  652.     } else {
  653.         strcpy(titlestr, _("Edit Partition"));
  654.     }
  655.     } else {
  656.     if (entry->name && *entry->name)
  657.         snprintf(titlestr, 80, "%s: %s", _("Edit Partition"), entry->name);
  658.     else
  659.         strcpy(titlestr, _("Edit Partition"));
  660.     }        
  661.     
  662.     newtCenteredWindow(70, 13+cval, titlestr );
  663.     form = newtForm(NULL,NULL,0);
  664.  
  665.     /* mount point goes at top and is centered */
  666.     row = 1;
  667.     col = 3;
  668.     newtFormAddComponent(form, newtLabel(col, row, "Mount Point:"));
  669.     if (p->type.current != LINUX_SWAP_PARTITION) {
  670.     if (!newpartition && strncmp("Exist", entry->name, 5) &&
  671.         strncmp("Dos", entry->name, 3)) {
  672.         mntptentry = newtEntry(22, row, entry->name, 30,
  673.                    &mntpt, NEWT_FLAG_RETURNEXIT);
  674.     } else {
  675.         mntptentry = newtEntry(22, row, "", 30,
  676.                    &mntpt, NEWT_FLAG_RETURNEXIT);
  677.     }
  678.     } else {
  679.     mntptentry = newtEntry(22, row, "Swap Partition", 30, &mntpt,
  680.                    NEWT_FLAG_RETURNEXIT | NEWT_FLAG_DISABLED);
  681.     }
  682.  
  683.     /* size, grow and boot flags on left under mount point */
  684.     row = 3;
  685.     newtFormAddComponent(form, newtLabel(col, row, "Size (Megs):"));
  686.     if (p->immutable) {
  687.     sizeentry = NULL;
  688.     snprintf(tmpstr,sizeof(tmpstr),"%d", p->size.current/SECPERMEG);
  689.     newtFormAddComponent(form, newtLabel(22, row, tmpstr));
  690.     } else {
  691.     snprintf(tmpstr,sizeof(tmpstr),"%d", p->size.min/SECPERMEG);
  692.     sizeentry = newtEntry(22, row, tmpstr, 8,
  693.               &size, NEWT_FLAG_RETURNEXIT);
  694.     }
  695.     row++;
  696.     
  697.     if (!newpartition) {
  698.     grow = p->size.min != p->size.max;
  699.     } else {
  700.     grow = 0;
  701.     }
  702.     grow = (grow) ? '*' : ' ';
  703.     
  704.     newtFormAddComponent(form, newtLabel(col, row, "Growable?:"));
  705.     if (p->immutable) {
  706.     growentry = NULL;
  707.     newtFormAddComponent(form, newtLabel(22, row, "[ ]"));
  708.     } else {
  709.     growentry = newtCheckbox(22, row, "", grow, NULL, &grow);
  710.     }
  711.     row++;
  712.  
  713.     /* give status */
  714.     if (!newpartition) {
  715.     newtFormAddComponent(form, newtLabel(col, row, 
  716.                 _("Allocation Status:")));
  717.     if (entry->status != REQUEST_DENIED)
  718.         newtFormAddComponent(form, newtLabel(22, row, _("Successful")));
  719.     else
  720.         newtFormAddComponent(form, newtLabel(22, row, _("Failed")));
  721.     row++;
  722.  
  723.     if (entry->status == REQUEST_DENIED) {
  724.         newtFormAddComponent(form, newtLabel(col, row, 
  725.                  _("Failure Reason:")));
  726.         newtFormAddComponent(form,
  727.              newtLabel(22,row,GetReasonString(entry->reason)));
  728.     }
  729.     row++;
  730.     }
  731.     
  732.     /* blow this bootable stuff for now, its confusing */
  733.     bootentry = NULL;
  734.  
  735.     /* type goes on right side under the mount point */
  736.     row = 3;
  737.     newtFormAddComponent(form, newtLabel(43, row, "Type:"));
  738.     if (p->immutable) {
  739.     typeentry = NULL;
  740.  
  741.     for (j=0; j<nparttypes; j++)
  742.         if (allparttypes[j].index == p->type.current)
  743.         break;
  744.  
  745.     if (j != nparttypes)
  746.         snprintf(tmpstr, sizeof(tmpstr), "%s", allparttypes[j].name);
  747.     else
  748.         snprintf(tmpstr,sizeof(tmpstr),"%6s (0x%x)",
  749.              "Unknown", p->type.current);
  750.         
  751.     newtFormAddComponent(form, newtLabel(48, row, tmpstr));
  752.     row++;
  753.     } else {
  754.     typeentry = newtListbox( 48, row, 4, 
  755.                  NEWT_FLAG_RETURNEXIT | NEWT_FLAG_SCROLL);
  756.     for (j=0; j<numfstypes; j++) {
  757.         snprintf(tmpstr,sizeof(tmpstr),"%s", fstypesnames[j]);
  758.         newtListboxAddEntry(typeentry, tmpstr,
  759.                 (void *) (long)fstypes[j]);
  760.         if (fstypes[j] == p->type.current)
  761.         newtListboxSetCurrent(typeentry, j);
  762.         else if (p->type.current == 0 &&
  763.              fstypes[j] == LINUX_NATIVE_PARTITION)
  764.         newtListboxSetCurrent(typeentry, j);
  765.     }
  766.     }
  767.  
  768.     /* have to fix this later */
  769.     /* allowable drives goes in center under rest */
  770.     row = 8;
  771.     driveform = NULL;
  772.     if (!p->immutable) {
  773.     newtFormAddComponent(form, newtLabel(col, row, "Allowable Drives:"));
  774.  
  775.     sb = newtVerticalScrollbar(40, row, 4, 9, 10);
  776.     driveform = newtForm(sb, NULL, 0);
  777.         newtFormSetBackground(driveform, NEWT_COLORSET_CHECKBOX);
  778.  
  779.     for (j=0; j<numhd; j++) {
  780.         driveentry[j].state = fdiskThisDriveSetIsActive(&p->drive,
  781.                                  hdarr[j]->num);
  782.         driveentry[j].cb = newtCheckbox(22, row+j, hdarr[j]->name+5,
  783.                         (driveentry[j].state) ? '*' : ' ',
  784.                         NULL,
  785.                         &driveentry[j].state);
  786.         newtFormAddComponent(driveform, driveentry[j].cb);
  787.     }
  788.     if (j > 4) {
  789.         newtFormSetHeight(driveform, 4);
  790.         newtFormAddComponent(driveform, sb);
  791.     } else {
  792.         newtFormSetWidth(driveform, 10);
  793.     }
  794.     }
  795.     
  796.     /* setup type box callback */
  797.     if (typeentry) {
  798.     cb1.entry = &mntptentry;
  799.     cb1.val   = mntpt;
  800.  
  801.     /* yuck but it works */
  802.     typebox_mp[0] = -1;
  803.     inswapentry = (p->type.current == LINUX_SWAP_PARTITION);
  804.     newtComponentAddCallback(typeentry,(newtCallback) typebox_scroll,&cb1);
  805.     }
  806.  
  807.     /* setup mount point callback */
  808.     if (!p->immutable) {
  809.     cb2.form      = &form;
  810.     cb2.val       = mntpt;
  811.     cb2.val2      = &boot;
  812.     memset(&cb2.curds, 0, sizeof(DriveSet));
  813.     memcpy(&cb2.origds, &p->drive, sizeof(DriveSet));
  814.     cb2.numhd     = numhd;
  815.     cb2.hdarr     = hdarr;
  816.     cb2.de        = driveentry;
  817.     cb2.dobootable = (fdiskIndexPartitionSpec(spec, "/boot", &j) !=
  818.               FDISK_SUCCESS);
  819.     
  820.     newtComponentAddCallback(mntptentry,(newtCallback) entrybox_cb,&cb2);
  821.     }
  822.                  
  823.     row = 9+cval;
  824.     ok = newtButton( 20, row, _("Ok"));
  825.     cancel  = newtButton( 40, row, _("Cancel"));
  826.     if (mntptentry)
  827.     newtFormAddComponents( form,  mntptentry, NULL );
  828.     if (sizeentry)
  829.     newtFormAddComponents( form, sizeentry, NULL);
  830.     if (growentry)
  831.     newtFormAddComponents( form, growentry, NULL);
  832.     if (typeentry)
  833.     newtFormAddComponents( form, typeentry, NULL );
  834.     if (driveform)
  835.     newtFormAddComponents( form, driveform, NULL );
  836.     newtFormAddComponents( form, ok, cancel, NULL);
  837.  
  838.     done = 0;
  839.     while (!done) {
  840.     answer = newtRunForm(form);
  841.  
  842.     if (answer != cancel) {
  843.         /* modify partition request based on the entry boxes */
  844.         if (typeentry) {
  845.         tmpuint = (long) newtListboxGetCurrent( typeentry );
  846.         fdiskSetConstraint(&p->type, tmpuint, tmpuint, tmpuint, 1);
  847.         }
  848.         
  849.         /* make sure mount point is valid */
  850.         if (p->type.current != LINUX_SWAP_PARTITION) {
  851.         int valid=1;
  852.         int skiprest=0;
  853.  
  854.         TrimWhitespace(mntpt);
  855.         
  856.         /* see if they even gave the partition a name  */
  857.         /* we will ask them if they really want to not */
  858.         /* assign the partition a name at this time if */
  859.         /* they have just created a non-ext2 partition */
  860.         if (!*mntpt && p->type.current != LINUX_NATIVE_PARTITION) {
  861.             if (newtWinChoice(_("No Mount Point"), _("Yes"), _("No"),
  862.                       _("You have not selected a mount point "
  863.                         "for this partition. Are you sure you "
  864.                         "want to do this?")) == 2)
  865.             continue;
  866.             else {
  867.             /* we need a name for this partition    */
  868.             /* we'll name them like swap partitions */
  869.             /* except use 'DOSxxx'                  */
  870.             if (strncmp("Dos", entry->name, 4)) {
  871.                 char *t;
  872.                 fdiskMakeUniqSpecName( spec, "Dos", &t );
  873.                 fdiskRenamePartitionSpec(spec, entry->name, t);
  874.             }
  875.             skiprest = 1;
  876.             }
  877.         }
  878.             
  879.         
  880.         /* do old test first */
  881.         if (!skiprest) {
  882.             if (entry->status != REQUEST_ORIGINAL || *mntpt)
  883.             if (badMountPoint(p->type.current, mntpt))
  884.                 continue;
  885.             
  886.         
  887.             if (entry->status == REQUEST_ORIGINAL) {
  888.             /* this is an original partition, should have a */
  889.             /* mount point of "" or a valid path            */
  890.             if (*mntpt && 
  891.                 (*mntpt != '/' || ((strcmp(entry->name, mntpt) &&
  892.             !fdiskIndexPartitionSpec(spec, mntpt, &tmpuint))))) {
  893.                 valid = 0;
  894.             }
  895.             } else if (*mntpt != '/' || (strcmp(entry->name, mntpt) &&
  896.              !fdiskIndexPartitionSpec(spec, mntpt, &tmpuint))) {
  897.             valid = 0;
  898.             }
  899.         }
  900.  
  901.         if (!valid) {
  902.             newtWinMessage(_("Mount Point Error"), _("Ok"),
  903.                _("The mount point requested is either an illegal "
  904.                  "path or is already in use. Please select a "
  905.                  "valid mount point."));
  906.             
  907.             continue;
  908.         }
  909.         }
  910.  
  911.         if (sizeentry) {
  912.         tmpint=strtol(size, &eptr, 10);
  913.         if (eptr != size && *eptr == 0 && tmpint > 0) {
  914.             tmpint *= SECPERMEG;
  915.             if (growentry && grow != ' ')
  916.             fdiskSetConstraint(&p->size,0,tmpint,FDISK_SIZE_MAX,1);
  917.             else
  918.             fdiskSetConstraint(&p->size,0,tmpint,tmpint,1);
  919.         } else {
  920.             newtWinMessage(_("Size Error"), _("Ok"),
  921.                _("The size requested is illegal. Make sure the "
  922.                  "size is greater and zero (0), and is specified "
  923.                  "int decimal (base 10) format."));
  924.             continue;
  925.         }
  926.         }
  927.         
  928.         /* make sure swap partitions are not too large */
  929.         /* (PAGESIZE - 10)*8*PAGESIZE                  */
  930.         /* on the right arch's                                */
  931.         if (p->type.current == LINUX_SWAP_PARTITION) {
  932.         unsigned int maxswap;
  933. #if defined(__alpha__)
  934.         maxswap = (8192-10)*8*8192;
  935. #else
  936.         maxswap = (4096-10)*8*4096;
  937. #endif
  938.  
  939.         if (p->size.min*SECTORSIZE > maxswap) {
  940.             newtWinMessage(_("Swap Size Error"), _("Ok"),
  941.                _("You have created a swap partition which is too "
  942.             "large. The maximum size of a swap partition is "
  943.             "%d Megabytes."), maxswap / 1024 / 1024);
  944.             continue;
  945.         }
  946.         }
  947.  
  948.         if (driveform) {
  949.         fdiskDeactivateAllDriveSet( &p->drive );
  950.         for (j=0; j<numhd; j++)
  951.             if (driveentry[j].state == '*')
  952.             fdiskActivateDriveSet( &p->drive, hdarr[j]->num );
  953.         }
  954.         
  955.         /* fdiskHandleSpecialPartitions() will do this for us */
  956.         /* so I'm taking the boot entry out for now           */
  957.  
  958.         if (p->type.current == LINUX_SWAP_PARTITION) {
  959.         /* make sure we have a valid swap partition name */
  960.         if (strncmp("Swap", entry->name, 4)) {
  961.             char *t;
  962.             fdiskMakeSwapSpecName( spec, &t );
  963.             fdiskRenamePartitionSpec(spec, entry->name, t);
  964.             free(t);
  965.         }
  966.         }
  967.         
  968.         /* first see if they changed the mount point    */
  969.         /* we only worry about ext2 and dos partitions  */
  970.         /* which have a valid mntpt                     */
  971.         /* LOGIC is not the word for how all this works */
  972.         if (p->type.current != LINUX_SWAP_PARTITION &&
  973.         strncmp("Dos", mntpt, 3)) {
  974.         TrimWhitespace(mntpt);
  975.         if (p->immutable)
  976.             status = REQUEST_ORIGINAL;
  977.         else
  978.             status = REQUEST_PENDING;
  979.         
  980.         if (strcmp(mntpt, entry->name)) {
  981.             /* if this is an original partition which we just set  */
  982.             /* the name back to '' from a real name, set name back */
  983.             /* to the 'Existxxxxx' name                            */
  984.             if (entry->status == REQUEST_ORIGINAL && !*mntpt) {
  985.             for (hdidx=0; hdidx < numhd; hdidx++) 
  986.                 if (hdarr[hdidx]->num == p->drive.current)
  987.                 break;
  988.             
  989.             if (hdidx != numhd)
  990.                 sprintf(tmpstr, "Exist%03d%03d",
  991.                     hdarr[hdidx]->num, p->num.current);
  992.             else
  993.                 strcpy(tmpstr,"Exist999999");
  994.             
  995.             fdiskRenamePartitionSpec( spec, entry->name, tmpstr );
  996.             fdiskModifyPartitionSpec( spec, tmpstr, p, status);
  997.             } else {
  998.             fdiskRenamePartitionSpec( spec, entry->name, mntpt );
  999.  
  1000.             /*  this is a big kludge! */
  1001.             /* reset bootable partition handling so if we   */
  1002.             /* rename '/' to '/usr', we don't enforce rules */
  1003.             fdiskSetConstraint(&p->endcyl,
  1004.                    0,FDISK_ENDCYL_MIN,FDISK_ENDCYL_MAX,0);
  1005.             fdiskModifyPartitionSpec( spec, mntpt, p, status);
  1006.             }
  1007.         } else {
  1008.             fdiskModifyPartitionSpec( spec, mntpt, p, status);
  1009.         }        
  1010.         } else {
  1011.         fdiskModifyPartitionSpec( spec, entry->name, p, status);
  1012.         }
  1013.  
  1014.         fdiskHandleSpecialPartitions( spec );
  1015.         status = FDISK_SUCCESS;
  1016.         done = 1;
  1017.     } else {
  1018.         status = FDISK_ERR_USERABORT;
  1019.         done = 1;
  1020.     }
  1021.     }
  1022.     
  1023.     newtPopWindow();
  1024.     newtFormDestroy(form);
  1025.  
  1026.     return status;
  1027. }
  1028.  
  1029. /* add a partition spec */
  1030. static int AddPartitionSpec(HardDrive **hdarr, unsigned int numhd,
  1031.              PartitionSpec *spec) {
  1032.  
  1033.     Partition template;
  1034.     int      status;
  1035.     unsigned int i;
  1036.     
  1037.     /* create a template partitionspec to send to editpartition */
  1038.     memset(&template, 0, sizeof(Partition));
  1039.     template.size.min = SECPERMEG;
  1040.  
  1041.     /* insert with a name we know to mean its a new partition */
  1042.     fdiskInsertPartitionSpec(spec, NEW_PARTSPEC, &template, REQUEST_PENDING);
  1043.     fdiskIndexPartitionSpec( spec, NEW_PARTSPEC, &i );
  1044.     status = EditPartitionSpec(hdarr, numhd, spec, &spec->entry[i]);
  1045.     if (status == FDISK_SUCCESS) {
  1046.     return FDISK_SUCCESS;
  1047.     } else {
  1048.     fdiskDeletePartitionSpec(spec, NEW_PARTSPEC);
  1049.     return FDISK_ERR_USERABORT;
  1050.     }
  1051. }
  1052.  
  1053.  
  1054. /* delete a partition spec */
  1055. static int DeletePartitionSpec( HardDrive **hdarr, unsigned int numhd,
  1056.              PartitionSpec *spec, PartitionSpecEntry *entry,
  1057.                 int force) {
  1058.  
  1059.     Partition *p;
  1060.     int      status;
  1061.     unsigned int c, l, m, n, t;
  1062.     char     *tmpstr;
  1063.  
  1064.     p = &entry->partition;
  1065.  
  1066.     tmpstr=strdup(entry->name);
  1067.     
  1068.     if (!force && newtWinChoice(_("Delete Partition"), _("Yes"), _("No"),
  1069.                     _("Are you sure you want to delete "
  1070.                       "this partiton?")) == 2)
  1071.     return FDISK_ERR_USERABORT;
  1072.     
  1073.     if (p->immutable) {
  1074.     fdiskGetCurrentConstraint(&p->num, &c);
  1075.     fdiskGetCurrentConstraint(&p->type, &t);
  1076.     fdiskGetCurrentDriveSet(&p->drive, &l);
  1077.     for (m=0; m<numhd; m++)
  1078.         if (hdarr[m]->num == l)
  1079.         break;
  1080.     
  1081.     fdiskRemovePartition(hdarr[m], c);
  1082.  
  1083.     /* make it so we can delete this partition now */
  1084.     p->immutable = 0;
  1085.     fdiskModifyPartitionSpec( spec, tmpstr, p, REQUEST_PENDING );
  1086.  
  1087.     /* ok, see if this was the last immutable logical partition */
  1088.     /* in an immutable primary extended partition               */
  1089.     /* we pray that fdiskCleanOriginal... will get rid of the   */
  1090.     /* spec entry for the pep                                   */
  1091.     if (c > 4) {
  1092.         if (fdiskLastLogical( hdarr[m], &n ) != FDISK_SUCCESS) {
  1093.         /* all logicals are gone, blow away pep */
  1094.         if (hdarr[m]->pep && hdarr[m]->table[hdarr[m]->pep].immutable){
  1095.             fdiskRemovePartition(hdarr[m], hdarr[m]->pep);
  1096.         }
  1097.         }
  1098.     }
  1099.     }
  1100.     
  1101.     status = fdiskDeletePartitionSpec( spec, tmpstr );
  1102.     fdiskHandleSpecialPartitions( spec );
  1103.     free(tmpstr);
  1104.  
  1105.     return FDISK_SUCCESS;
  1106. }
  1107.  
  1108. /* edit/add an NFS partition -> set index to -1 if adding new */
  1109. int EditNFSMount( struct fstab *remotefs, int index, 
  1110.           struct intfInfo *intf, struct netInfo *netc,
  1111.           struct driversLoaded **dl ) {
  1112.  
  1113.     int rc;
  1114.     struct fstabEntry entry;
  1115.  
  1116.     if (!(intf->set & INTFINFO_HAS_BOOTPROTO)) { 
  1117.     rc = bringUpNetworking(intf, netc, dl, 1);
  1118.     } else {
  1119.     rc = 0;
  1120.     }
  1121.  
  1122.     if (rc)
  1123.     return 1;
  1124.  
  1125.     if (index == -1) {
  1126.     initFstabEntry(&entry);
  1127.     entry.type = PART_NFS;
  1128.     entry.tagName = "NFS Mount";
  1129.     entry.device = NULL;
  1130.     entry.mntpoint = NULL;
  1131.     rc = editNetMountPoint(&entry);
  1132.     if (!rc)
  1133.         addFstabEntry(remotefs, entry);
  1134.     } else {
  1135.     rc = editNetMountPoint(&remotefs->entries[index]);
  1136.     }
  1137.  
  1138.     return rc;
  1139. }
  1140.  
  1141.  
  1142. /* remote fstab entry */
  1143. int DeleteNFSMount(struct fstab *remotefs, int index) {
  1144.     int i;
  1145.  
  1146.     if (remotefs->numEntries < 1)
  1147.     return 0;
  1148.     
  1149.     for (i=index; i<remotefs->numEntries-1; i++)
  1150.     remotefs->entries[i] = remotefs->entries[i+1];
  1151.  
  1152.     remotefs->numEntries -= 1;
  1153.     return 0;
  1154. }
  1155.  
  1156. /* used for each line in partbox - tells us what is on that line */
  1157. enum partbox_types {PARTBOX_COMMENT, PARTBOX_NFS, PARTBOX_PART};
  1158. struct partbox_entry {
  1159.     enum partbox_types type;    /* what is on this line */
  1160.     int                index;   /* index in nfs or partition arrays */
  1161.     int               hilite;   /* element in drive window to hilight */
  1162. };
  1163.  
  1164. /* simple callback for scrollbox skipping non-entries */
  1165. struct partbox_struct {
  1166.     unsigned int  len;       /* total entries allocated */
  1167.     unsigned int  num;       /* number in use           */
  1168.     newtComponent *dbox;     /* drive box */
  1169.     struct partbox_entry *entry; /* describes use of this line */
  1170. };
  1171.  
  1172. /* this is some ugly sh*t, don't try this at home kids */
  1173. static void partbox_scroll(newtComponent list, struct partbox_struct *status) {
  1174.  
  1175.     static int last=-1;
  1176.     static int dontforce=0;
  1177.     int sel;
  1178.     int i;
  1179.     int odir, dir;
  1180.     int done;
  1181.     int lasttry;
  1182.  
  1183.     /* get the index into the partbox_struct array */
  1184.     sel = (long) newtListboxGetCurrent(list);
  1185.  
  1186.     /* see if this callback occurred because we were forcing */
  1187.     /* listbox to scroll                                     */
  1188.     if (dontforce) {
  1189.     dontforce = 0;
  1190.     return;
  1191.     }
  1192.  
  1193.     /* if the element is ok then just return */
  1194.     if (status->entry[sel].type != PARTBOX_COMMENT) {
  1195.     if (status->entry[sel].type == PARTBOX_PART &&
  1196.         status->entry[sel].hilite >= 0 && status->dbox != NULL)
  1197.         newtListboxSetCurrent(*status->dbox, status->entry[sel].hilite);
  1198.     return;
  1199.     }
  1200.  
  1201.     /* see which direction we're heading , >0 means down, < 0 means up */
  1202.     if (last == -1)
  1203.     dir = 1;
  1204.     else {
  1205.     if (sel > last)
  1206.         dir = 1;
  1207.     else
  1208.         dir = -1;
  1209.     }
  1210.  
  1211.     odir    = dir;
  1212.     done    = 0;
  1213.     lasttry = 0;
  1214.     while (!done) {
  1215.     if (dir > 0) {
  1216.         for (i=sel; i < status->num; i++)
  1217.         if (status->entry[i].type != PARTBOX_COMMENT)
  1218.             break;
  1219.  
  1220.         if (i!=status->num) {
  1221.         dontforce = 1;
  1222.         newtListboxSetCurrent(list, i);
  1223.         last = i;
  1224.         done = 1;
  1225.  
  1226.         if (lasttry) {
  1227.             /* scroll to top, since this is last try so original */
  1228.             /* direction was going up                            */
  1229.             dontforce = 1;
  1230.             newtListboxSetCurrent(list, 0);
  1231.             dontforce = 1;
  1232.             newtListboxSetCurrent(list,last);
  1233.         }
  1234.         } else {
  1235.         if (!lasttry) {
  1236.             dir = -1;
  1237.             lasttry = 1;
  1238.         } else {
  1239.             done = 1;
  1240.         }
  1241.         }
  1242.     } else {
  1243.         for (i=sel; i >= 0; i--)
  1244.         if (status->entry[i].type != PARTBOX_COMMENT)
  1245.             break;
  1246.  
  1247.         if (i >= 0) {
  1248.         dontforce = 1;
  1249.         newtListboxSetCurrent(list, i);
  1250.         last = i;
  1251.         done = 1;
  1252.  
  1253.         if (lasttry) {
  1254.             /* scroll to bottom, since this is last try so original */
  1255.             /* direction was going up                               */
  1256.             dontforce = 1;
  1257.             newtListboxSetCurrent(list, status->num-1);
  1258.             dontforce = 1;
  1259.             newtListboxSetCurrent(list,last);
  1260.         }
  1261.         } else {
  1262.         if (!lasttry) {
  1263.             dir = 1;
  1264.             lasttry = 1;
  1265.         } else {
  1266.             done = 1;
  1267.         }
  1268.         }
  1269.     }
  1270.     }
  1271.  
  1272.     /* if we found a valid line then move drive box selection too */
  1273.     sel = (long) newtListboxGetCurrent(list);
  1274.     if (status->entry[sel].type == PARTBOX_PART &&
  1275.     status->entry[sel].hilite >= 0 && status->dbox != NULL)
  1276.     newtListboxSetCurrent(*status->dbox, status->entry[sel].hilite);
  1277. }
  1278.  
  1279.  
  1280. static int MakeDriveBox( HardDrive **hdarr, unsigned int numhd,
  1281.              unsigned int *drvused, int dheight,
  1282.              newtComponent *dbox ) {
  1283.     int hdidx, i, per;
  1284.     char tmpstr[80];
  1285.     
  1286.     *dbox = newtListbox( -1, -1, dheight, NEWT_FLAG_SCROLL );
  1287.     newtComponentTakesFocus( *dbox, 0 );
  1288.     for (hdidx=0; hdidx < numhd; hdidx++) {
  1289.     snprintf(tmpstr,sizeof(tmpstr),
  1290.          "   %s      [%5d/%3d/%2d]   "
  1291.          "%6dM %6dM %6dM"
  1292.          "                       ",
  1293.          hdarr[hdidx]->name+5,
  1294.          hdarr[hdidx]->geom.cylinders,
  1295.          hdarr[hdidx]->geom.heads,
  1296.          hdarr[hdidx]->geom.sectors,
  1297.          hdarr[hdidx]->totalsectors/SECPERMEG,
  1298.          drvused[hdidx]/SECPERMEG,
  1299.          hdarr[hdidx]->totalsectors/SECPERMEG-drvused[hdidx]/SECPERMEG
  1300.          );
  1301.     
  1302.     tmpstr[58]='[';
  1303.     tmpstr[69]=']';
  1304.     per = (100*drvused[hdidx])/hdarr[hdidx]->totalsectors;
  1305.     if (per >= 99)
  1306.         per = 10;
  1307.     else
  1308.         per = per/10;
  1309.     
  1310.     for (i=0; i < per; i++)
  1311.         tmpstr[59+i] = '#';
  1312.  
  1313.     tmpstr[74]=0;
  1314.     newtListboxAddEntry(*dbox, tmpstr, (void *) 0);
  1315.     }
  1316.  
  1317.     return FDISK_SUCCESS;
  1318. }             
  1319.  
  1320. /* given partitoins/hard drives, returns a listbox for use */
  1321. /* includes the callback function to skip over headings    */
  1322. static int MakePartBox( HardDrive **hdarr, unsigned int numhd,
  1323.             PartitionSpec *spec, struct fstab *remotefs,
  1324.             int x, int y, int pheight, int dheight,
  1325.             newtComponent *list, struct partbox_struct *status,
  1326.             newtComponent *dbox) {
  1327.     
  1328.     newtComponent partbox;
  1329.  
  1330.     unsigned int drivenum;
  1331.     unsigned int totalused;
  1332.     int col;
  1333.     int i, k,  hdidx;
  1334.     
  1335.     unsigned int listlen;
  1336.     unsigned int foundpart;
  1337.     char         tmpstr[80];
  1338.     int         num;
  1339.  
  1340.     unsigned int *drvused=alloca(numhd*sizeof(unsigned int));
  1341.  
  1342.     memset(drvused, 0, numhd*sizeof(unsigned int));
  1343.     
  1344.     /* check if there are *any* partitions to display */
  1345.     for (i = 0, num = 0; i < spec->num; i++) {
  1346.     if (fdiskIsExtended(spec->entry[i].partition.type.current))
  1347.         continue;
  1348.     num++;
  1349.     }
  1350.     num += remotefs->numEntries;
  1351.     if (!num) {
  1352.     *list = NULL;
  1353.     MakeDriveBox( hdarr, numhd, drvused, dheight, dbox );
  1354.     return FDISK_ERR_BADNUM;
  1355.     }
  1356.  
  1357.     partbox = newtListbox(-1, -1, pheight, 
  1358.               NEWT_FLAG_RETURNEXIT  | NEWT_FLAG_SCROLL);
  1359.     
  1360.     listlen = 0;
  1361.     status->entry=(struct partbox_entry *)malloc(100*
  1362.                          sizeof(struct partbox_entry));
  1363.     status->len   = 100;
  1364.     memset(status->entry, 0, status->len*sizeof(struct partbox_entry));
  1365.  
  1366.     status->dbox = NULL;
  1367.     for (hdidx=0; hdidx < numhd; hdidx++) {
  1368.     drivenum = hdarr[hdidx]->num;
  1369.  
  1370.     /* display all spec'd partitions for this drive */
  1371.     foundpart = 0;
  1372.     totalused = 0;
  1373.     for (i=0; i<spec->num; i++) {
  1374.         unsigned int num, minsize, actsize, drive, totsize;
  1375.         char         statstr[80];
  1376.         char         *pname, *devname;
  1377.         Partition    *p;
  1378.  
  1379.         if (spec->entry[i].status == REQUEST_DENIED)
  1380.         continue;
  1381.         
  1382.         p = &spec->entry[i].partition;
  1383.         if ((drive = p->drive.current) != drivenum)
  1384.         continue;
  1385.  
  1386.         if (fdiskIsExtended(p->type.current))
  1387.         continue;
  1388.         
  1389.         num     = p->num.current;
  1390.         actsize = p->size.current;
  1391.         minsize = p->size.min;
  1392.         pname   = spec->entry[i].name;
  1393.         devname = hdarr[hdidx]->name;
  1394.         totsize = hdarr[hdidx]->totalsectors;
  1395.         
  1396.         if (!foundpart)
  1397.         foundpart = 1;
  1398.  
  1399.         /* increment amount of space used */
  1400.         totalused += actsize;
  1401.         
  1402.         /* mount point  */
  1403.         col = 3;
  1404.         memset(statstr, ' ', sizeof(statstr));
  1405.         if (strncmp("Exist", pname, 5) && strncmp("Swap", pname, 4) &&
  1406.         strncmp("Dos", pname, 3))
  1407.         BuildTableField( statstr, pname, col, 16, 0 );
  1408.         
  1409.         /* Block device */
  1410.         snprintf(tmpstr, sizeof(tmpstr), "%s%d", devname+5, num );
  1411.         col += 22;
  1412.         BuildTableField( statstr, tmpstr, col, 10, 0 );
  1413.         
  1414.         /* Size */
  1415.         snprintf(tmpstr, sizeof(tmpstr), "%5dM", minsize/SECPERMEG);
  1416.         col += 10;
  1417.         BuildTableField( statstr, tmpstr, col, 9, 1 );
  1418.  
  1419.         snprintf(tmpstr, sizeof(tmpstr), "%5dM", actsize/SECPERMEG);
  1420.         col += 10;
  1421.         BuildTableField( statstr, tmpstr, col, 9, 1 );
  1422.  
  1423.         /* we dont want to see all that stuff, just English label */
  1424.         /* for the type                                           */
  1425.         /* Type */
  1426.         col += 13;
  1427.         for (k=0; k<nparttypes; k++)
  1428.         if (allparttypes[k].index == p->type.current)
  1429.             break;
  1430.  
  1431.         if (k != nparttypes)
  1432.         snprintf(tmpstr, sizeof(tmpstr), "%s", allparttypes[k].name);
  1433.         else
  1434.         snprintf(tmpstr, sizeof(tmpstr), "0x%02x", p->type.current);
  1435.         
  1436.         BuildTableField( statstr, tmpstr, col, 18, 0);
  1437.  
  1438.         /* now stick it in listbox */
  1439.         statstr[73]=0;
  1440.         status->entry[listlen].type = PARTBOX_PART;
  1441.         status->entry[listlen].index = i;
  1442.         status->entry[listlen].hilite = hdidx;
  1443.         newtListboxAddEntry(partbox, statstr,(void *) (long) listlen);
  1444.         listlen++;
  1445.     }
  1446.  
  1447.     drvused[hdidx] = totalused;
  1448.     }
  1449.  
  1450.     for (i=0; i<remotefs->numEntries; i++) {
  1451.     char         statstr[80];
  1452.  
  1453.     /* mount point  */
  1454.     col = 2;
  1455.     memset(statstr, ' ', sizeof(statstr));
  1456.     BuildTableField( statstr, remotefs->entries[i].mntpoint, col, 16, 0 );
  1457.         
  1458.     /* Block device */
  1459.     col += 17;
  1460.     snprintf(tmpstr, sizeof(tmpstr), "%s:%s",
  1461.          remotefs->entries[i].netHost, remotefs->entries[i].netPath);
  1462.     BuildTableField( statstr, tmpstr, col, 40, 0 );
  1463.         
  1464.     /* Size */
  1465. /* snprintf(tmpstr, sizeof(tmpstr), "%5dM/NA           ", minsize/SECPERMEG);*/
  1466.     *tmpstr=0;
  1467.     col += 12;
  1468.     BuildTableField( statstr, "", col, 15, 0 );
  1469.  
  1470.     /* Type */
  1471.     col += 27;
  1472.     BuildTableField( statstr, "NFS", col, 18, 0);
  1473.     
  1474.     /* now stick it in listbox */
  1475.     statstr[70]=0;
  1476.     status->entry[listlen].type  = PARTBOX_NFS;
  1477.     status->entry[listlen].index = i;
  1478.     newtListboxAddEntry(partbox, statstr,(void *) (long) (listlen));
  1479.     listlen++;
  1480.     }
  1481.     
  1482.     
  1483.     /* now display any partition specs which WERE NOT allocated */
  1484.     foundpart = 0;
  1485.     for (i=0; i<spec->num && !foundpart; i++)
  1486.     if (spec->entry[i].status == REQUEST_DENIED)
  1487.         foundpart = 1;
  1488.  
  1489.     if (foundpart) {
  1490.     status->entry[listlen].type = PARTBOX_COMMENT;
  1491.     newtListboxAddEntry(partbox,"", (void *)(long)listlen);
  1492.     listlen++;
  1493.     status->entry[listlen].type = PARTBOX_COMMENT;
  1494.     newtListboxAddEntry(partbox,"Unallocated requested partitions",
  1495.                 (void *)(long)listlen);
  1496.     listlen++;
  1497.     status->entry[listlen].type = PARTBOX_COMMENT;
  1498.     newtListboxAddEntry(partbox,"--------------------------------",
  1499.                 (void *)(long)listlen);
  1500.     listlen++;
  1501.  
  1502.     for (i=0; i<spec->num; i++) {
  1503.         if (spec->entry[i].status == REQUEST_DENIED) {
  1504.         unsigned int num, minsize, actsize;
  1505.         char         statstr[80];
  1506.         char         *pname;
  1507.         Partition    *p;
  1508.         
  1509.         foundpart = 1;
  1510.         p = &spec->entry[i].partition;
  1511.         if (fdiskIsExtended(p->type.current))
  1512.             continue;
  1513.         
  1514.         num     = p->num.current;
  1515.         minsize = p->size.min;
  1516.         actsize = p->size.current;  
  1517.         pname   = spec->entry[i].name;
  1518.         
  1519.         /* mount point  */
  1520.         col = 3;
  1521.         memset(statstr, ' ', sizeof(statstr));
  1522.         if (strncmp("Exist", pname, 5) && strncmp("Swap", pname, 4) &&
  1523.             strncmp("Dos", pname, 3))
  1524.             BuildTableField( statstr, pname, col, 16, 0 );
  1525.         
  1526.         /* Reasons */
  1527.         col += 17;
  1528.         BuildTableField( statstr, 
  1529.                 GetReasonString(spec->entry[i].reason),
  1530.                 col, 25, 0 );
  1531.         
  1532.         /* Size */
  1533.         snprintf(tmpstr, sizeof(tmpstr), "%5dM/NA           ",
  1534.              minsize/SECPERMEG);
  1535.         col += 23;
  1536.         BuildTableField( statstr, tmpstr, col, 15, 0 );
  1537.         
  1538.         /* we dont want to see all that stuff, just English label */
  1539.         /* for the type                                           */
  1540.         /* Type */
  1541.         col += 15;
  1542.         for (k=0; k<nparttypes; k++)
  1543.             if (allparttypes[k].index == p->type.current)
  1544.             break;
  1545.         
  1546.         if (k != nparttypes)
  1547.             snprintf(tmpstr, sizeof(tmpstr),"%s",allparttypes[k].name);
  1548.         else
  1549.             snprintf(tmpstr, sizeof(tmpstr),"0x%02x", p->type.current);
  1550.         
  1551.         BuildTableField( statstr, tmpstr, col, 18, 0);
  1552.         
  1553.         /* now stick it in listbox */
  1554.         statstr[70]=0;
  1555.         status->entry[listlen].type  = PARTBOX_PART;
  1556.         status->entry[listlen].index = i;
  1557.         status->entry[listlen].hilite = -1;
  1558.         newtListboxAddEntry(partbox, statstr,(void *)(long)(listlen));
  1559.         listlen++;
  1560.         }
  1561.     }
  1562.     }
  1563.     
  1564.     /* mark the VERY end of listbox */
  1565.     status->num = listlen;
  1566.     
  1567.     /* setup the callback for the listbox */
  1568.     newtComponentAddCallback(partbox, (newtCallback) partbox_scroll, status);
  1569.     for (i=0; i<status->num-1;i++)
  1570.     if (status->entry[i].type != PARTBOX_COMMENT)
  1571.         break;
  1572.  
  1573.     if (i!=status->num)
  1574.     newtListboxSetCurrent(partbox,i);
  1575.  
  1576.     *list = partbox;
  1577.  
  1578.     /* now make the drive box IF desired */
  1579.     MakeDriveBox( hdarr, numhd, drvused, dheight, dbox );
  1580.     
  1581.     if (partbox)
  1582.     status->dbox = dbox;
  1583.  
  1584.     
  1585.     return 0;
  1586. }
  1587.  
  1588.  
  1589.  
  1590. /* do a operation on a partition */
  1591. static int  DoMenuFunction( char *function,
  1592.                 HardDrive **orighd, unsigned int numhd,
  1593.                 HardDrive **curhd,
  1594.                 newtComponent partbox,
  1595.                 struct partbox_struct *partbox_status,
  1596.                 PartitionSpec *spec ) {
  1597.     
  1598.     unsigned int sel;
  1599.     int          num=0;
  1600.     int          status;
  1601.     int          i;
  1602.     HardDrive    *tmphdarr[MAX_HARDDRIVES];
  1603.     
  1604.     if (partbox) {
  1605.     sel = (long) newtListboxGetCurrent(partbox);
  1606.     if (partbox_status->entry[sel].type != PARTBOX_COMMENT)
  1607.         num = partbox_status->entry[sel].index;
  1608.     else
  1609.         num = -1;
  1610.     } else {
  1611.     num = -1;
  1612.     }
  1613.     
  1614.     for (i=0; i<numhd; i++) {
  1615.     tmphdarr[i] = (HardDrive *) alloca(sizeof(HardDrive));
  1616.     memcpy(tmphdarr[i], orighd[i], sizeof(HardDrive));
  1617.     }
  1618.     
  1619.     if (!strcmp("ADD", function)) {
  1620.     status = AddPartitionSpec(tmphdarr, numhd, spec);
  1621.     } else if (num >= 0 && !strcmp("EDIT", function)) {
  1622.     status = EditPartitionSpec(tmphdarr, numhd, spec, &spec->entry[num]);
  1623.     } else if (num >= 0 && !strcmp("DEL", function)) {
  1624.     status = DeletePartitionSpec(orighd, numhd, spec, &spec->entry[num],0);
  1625.     } else {
  1626.     status = FDISK_ERR_BADNUM;
  1627.     }
  1628.  
  1629.     if (status == FDISK_SUCCESS) {
  1630.     fdiskAutoInsertPartitions(orighd, numhd, tmphdarr, spec );
  1631.     showReasons( spec );
  1632.     fdiskGrowPartitions(orighd, numhd, tmphdarr, spec);
  1633.  
  1634.     /* if any original partitions were REMOVED we have to */
  1635.     /* sync up their entries in the partition spec table  */
  1636.     /* with their actual representation in 'orighd'.      */
  1637.     /* Mainly fixes up logical partition #'s which change */
  1638.     /* when other logical partitions are removed          */
  1639.     if (!strcmp("DEL", function))
  1640.         fdiskCleanOriginalSpecs( orighd, numhd, spec );
  1641.     
  1642.     for (i=0; i<numhd; i++)
  1643.         memcpy(curhd[i],tmphdarr[i], sizeof(HardDrive));
  1644.                 
  1645.     return FDISK_SUCCESS;
  1646.     } else {
  1647.     return FDISK_ERR_BADNUM;
  1648.     }
  1649.     
  1650. }
  1651.  
  1652. /* main loop of the program, builds the display of all drives/partitions */
  1653. static int StartMaster( HardDrive **hdarr, unsigned int numhd,
  1654.             PartitionSpec *spec,
  1655.             struct fstab *remotefs,
  1656.             struct intfInfo *intf, struct netInfo *netc,
  1657.             struct driversLoaded **dl,
  1658.             int dontPartition,
  1659.             int *writeChanges) {
  1660.     newtComponent form, add, addnfs, del, edit, reset, ok, cancel, answer;
  1661.     newtComponent partbox, curcomponent;
  1662.     newtGrid buttons, grid;
  1663.     newtComponent dbox, partlabel, drivelabel, driveinfolabel;
  1664.     HardDrive *newhdarr[MAX_HARDDRIVES];
  1665.     HardDrive *prestinehdarr[MAX_HARDDRIVES];
  1666.     int formdone, totallydone, i, status;
  1667.     int currentselection;
  1668.     struct newtExitStruct event;
  1669.     char tmpstr[80];
  1670.     unsigned int width, height;
  1671.     int          changesmade=0;
  1672.     int retcode = FDISK_SUCCESS; /* i'm optimistic */
  1673.     struct partbox_struct partbox_status;
  1674.     enum mywidgets {PARTBOX, ADD, ADDNFS, EDIT, DELETE,
  1675.             RESET, OK, CANCEL, NONE};
  1676.     enum mywidgets curwidget;
  1677.     
  1678.     width  = 78;
  1679.     height = 20;
  1680.  
  1681.     /* FIXME: hack! */
  1682.     addnfs = (void *) 1;
  1683.     reset = (void *) 2;
  1684.  
  1685.     /* copy original hard drive configurations into work spaces */
  1686.     for (i=0; i<numhd; i++) {
  1687.     newhdarr[i] = (HardDrive *) alloca(sizeof(HardDrive));
  1688.     memcpy(newhdarr[i], hdarr[i], sizeof(HardDrive));
  1689.     prestinehdarr[i] = (HardDrive *) alloca(sizeof(HardDrive));
  1690.     memcpy(prestinehdarr[i], hdarr[i], sizeof(HardDrive));
  1691.     }
  1692.  
  1693.     /* build the main list of installed/probed devices */
  1694.     totallydone = 0;
  1695.     currentselection = -1;
  1696.     curwidget = NONE;
  1697.  
  1698.     newtCenteredWindow(width, height, _("Current Disk Partitions"));
  1699.  
  1700.     while (!totallydone) {
  1701.     /* are there ANY defined partitions ? */
  1702.     partlabel = newtLabel(-1, -1,
  1703.          "   Mount Point          Device     Requested   Actual         Type");
  1704.     MakePartBox(newhdarr, numhd, spec, remotefs,
  1705.             1, 2, height-12, 4,
  1706.             &partbox, &partbox_status, &dbox);
  1707.  
  1708.     form = newtForm(NULL, NULL, 0);
  1709.  
  1710.     if (dontPartition) {
  1711.         buttons = newtButtonBar(
  1712.             _("Edit"), &edit, _("Delete"), &del, 
  1713.             _("Ok"), &ok, _("Back"), &cancel, NULL);
  1714.         add = reset = NULL;
  1715.         snprintf(tmpstr, sizeof(tmpstr),
  1716.              "    F2-Add NFS    F3-Edit    F4-Delete"
  1717.              "    F12-Ok   v%5s", VERSION_STR);
  1718.     } else {
  1719.         buttons = newtButtonBar(_("Add"), &add, 
  1720.             _("Edit"), &edit, _("Delete"), &del,
  1721.             _("Ok"), &ok, _("Back"), &cancel, NULL);
  1722.  
  1723.         newtFormAddHotKey(form, NEWT_KEY_F1);
  1724.         newtFormAddHotKey(form, NEWT_KEY_F5);
  1725.  
  1726.         snprintf(tmpstr, sizeof(tmpstr),
  1727.              "    F1-Add    F2-Add NFS    F3-Edit   "
  1728.              "F4-Delete    F5-Reset    F12-Ok   v%5s", VERSION_STR);
  1729.     }
  1730.  
  1731.     drivelabel = newtLabel(-1, -1, _("Drive Summaries"));
  1732.     driveinfolabel = newtLabel(-1, -1,
  1733.            "  Drive      Geom [C/H/S]      Total    Used    Free");
  1734.  
  1735.  
  1736.     grid = newtCreateGrid(1, 6);
  1737.     newtGridSetField(grid, 0, 0, NEWT_GRID_COMPONENT, partlabel,
  1738.              0, 0, 0, 0, NEWT_ANCHOR_LEFT, 0);
  1739.     if (partbox)
  1740.         newtGridSetField(grid, 0, 1, NEWT_GRID_COMPONENT, partbox,
  1741.                  0, 0, 0, 0, NEWT_ANCHOR_LEFT, 0);
  1742.     newtGridSetField(grid, 0, 2, NEWT_GRID_COMPONENT, drivelabel,
  1743.              0, partbox ? 0 : 8, 0, 0, NEWT_ANCHOR_LEFT, 0);
  1744.     newtGridSetField(grid, 0, 3, NEWT_GRID_COMPONENT, driveinfolabel,
  1745.              0, 0, 0, 0, NEWT_ANCHOR_LEFT, 0);
  1746.     newtGridSetField(grid, 0, 4, NEWT_GRID_COMPONENT, dbox,
  1747.              0, 0, 0, 0, 0, 0);
  1748.     newtGridSetField(grid, 0, 5, NEWT_GRID_SUBGRID, buttons,
  1749.              0, 1, 0, 0, 0, NEWT_GRID_FLAG_GROWX);
  1750.  
  1751.     newtGridPlace(grid, 1, 0);
  1752.     newtGridAddComponentsToForm(grid, form, 1);
  1753.     newtGridFree(grid, 1);
  1754.  
  1755.     /* and the hotkeys */
  1756.     newtFormAddHotKey(form, NEWT_KEY_F2);
  1757.     newtFormAddHotKey(form, NEWT_KEY_F3);
  1758.     newtFormAddHotKey(form, NEWT_KEY_F4);
  1759.  
  1760.     /* and how to use this plus info on version */
  1761.     newtPushHelpLine(tmpstr);
  1762.     
  1763.     if (partbox) {
  1764.         if (currentselection < 0)
  1765.         currentselection = (long) newtListboxGetCurrent(partbox);
  1766.         else
  1767.         newtListboxSetCurrent(partbox, currentselection);
  1768.     }
  1769.  
  1770.     /* see if no partitions are present */
  1771.     /* we can't Add if we are in Read Only mode! */
  1772.     if (spec->num == 0 && !dontPartition)
  1773.         curwidget = ADD;
  1774.     
  1775.     /* set current widget if necessary */
  1776.  
  1777.     if (partbox != NULL && curwidget == PARTBOX)
  1778.         newtFormSetCurrent(form, partbox);
  1779.     else if (curwidget == ADD)
  1780.         newtFormSetCurrent(form, add);
  1781.     else if (curwidget == EDIT)
  1782.         newtFormSetCurrent(form, edit);
  1783.     else if (curwidget == DELETE)
  1784.         newtFormSetCurrent(form, del);
  1785.     
  1786.     /* setup main screen */
  1787.     formdone = 0;
  1788.     answer = NULL;
  1789.     while (!formdone) {
  1790.         newtFormRun(form, &event);
  1791.  
  1792.         /* store the current widget so we can reset it */
  1793.         /* if we have to destroy and recreate form     */
  1794.         /* GetCurrent(), SetCurrent() use a ptr to     */
  1795.         /* newtcomponent, so when we recreate form it  */
  1796.         /* will be meaningless!                        */
  1797.         curcomponent = newtFormGetCurrent( form );
  1798.         curwidget = NONE;
  1799.         if (partbox != NULL && curcomponent == partbox)
  1800.         curwidget = PARTBOX;
  1801.         else if (curcomponent == add)
  1802.         curwidget = ADD;
  1803.         else if (curcomponent == addnfs)
  1804.         curwidget = ADDNFS;
  1805.         else if (curcomponent == edit)
  1806.         curwidget = EDIT;
  1807.         else if (curcomponent == del)
  1808.         curwidget = DELETE;
  1809.         else if (curcomponent == reset)
  1810.         curwidget = RESET;
  1811.         else
  1812.         curwidget = NONE;
  1813.         
  1814.         if (event.reason == NEWT_EXIT_HOTKEY) {
  1815.         event.reason = NEWT_EXIT_COMPONENT;
  1816.         if (event.u.key == NEWT_KEY_F12)
  1817.             event.u.co = ok;
  1818.         else if (event.u.key == NEWT_KEY_F1)
  1819.             event.u.co = add;
  1820.         else if (event.u.key == NEWT_KEY_F2)
  1821.             event.u.co = addnfs;
  1822.         else if (event.u.key == NEWT_KEY_F3)
  1823.             event.u.co = edit;
  1824.         else if (event.u.key == NEWT_KEY_F4)
  1825.             event.u.co = del;
  1826.         else if (event.u.key == NEWT_KEY_F5)
  1827.             event.u.co = reset;
  1828.         else
  1829.             continue;
  1830.         }
  1831.  
  1832.         if (event.reason == NEWT_EXIT_COMPONENT) {
  1833.         if (event.u.co != partbox) {
  1834.             if (event.u.co == ok || event.u.co == cancel) {
  1835.             if (event.u.co == ok) {
  1836.                 *writeChanges = 1;
  1837.                 /* make sure '/' is defined */
  1838.                 status = fdiskIndexPartitionSpec(spec, "/", &i);
  1839.                 if (!status)
  1840.                 if (spec->entry[i].partition.type.current !=
  1841.                     LINUX_NATIVE_PARTITION ||
  1842.                     spec->entry[i].status == REQUEST_DENIED)
  1843.                     status = 1;
  1844.                 
  1845.                 if (status) {
  1846.                 newtWinMessage(_("No Root Partition"), _("Ok"),
  1847.                       _("You must assign a root (/) "
  1848.                     "partition "
  1849.                     "to a Linux native partition (ext2) "
  1850.                     "for the install to proceed."));
  1851.                 continue;
  1852.                 }
  1853.  
  1854.                 /* make sure some swapspace is defined */
  1855.                 status = 1;
  1856.                 for (i=0; i < spec->num; i++)
  1857.                 if (spec->entry[i].partition.type.current ==
  1858.                     LINUX_SWAP_PARTITION &&
  1859.                     spec->entry[i].status != REQUEST_DENIED) {
  1860.                     status = 0;
  1861.                     break;
  1862.                 }
  1863.  
  1864.                 if (status) {
  1865.                 newtWinMessage(_("No Swap Partition"), _("Ok"),
  1866.                       _("You must assign a swap "
  1867.                         "partition "
  1868.                         "for the install to proceed."));
  1869.                 continue;
  1870.                 }
  1871.             }
  1872.  
  1873.             /* make sure there are no unallocated partitions */
  1874.             status = 0;
  1875.             for (i=0; i < spec->num; i++)
  1876.                 if (spec->entry[i].status == REQUEST_DENIED) {
  1877.                 status = 1;
  1878.                 break;
  1879.                 }
  1880.             
  1881.             if (status) {
  1882.                 if (newtWinChoice(_("Unallocated Partitions"),
  1883.                           _("Yes"), _("No"),
  1884.                    _("There are unallocated partitions "
  1885.                      "left. If you quit now they will "
  1886.                      "not be written to the disk.\n\n"
  1887.                      "Are you sure you want to exit?")) == 2)
  1888.                 continue;
  1889.             }
  1890.  
  1891.             /* dont trust the changes made I keep up with */
  1892.             /* above, compute it straight from the hd's   */
  1893.             changesmade = DisksChanged( prestinehdarr,
  1894.                            newhdarr,
  1895.                            numhd );
  1896.             /* the dontPartition here isn't necessary, but it
  1897.                does make a reassuring sanity check */
  1898.             if (changesmade && !dontPartition) {
  1899.                 int rc;
  1900.                 rc =  newtWinTernary(_("Save Changes"),
  1901.                          _("Yes"), _("No"), _("Cancel"),
  1902.                          _("Save changes to "
  1903.                            "partition table(s)?"));
  1904.                 if (rc == 1) {
  1905.                 retcode = FDISK_SUCCESS;
  1906.                 *writeChanges = 1;
  1907.  
  1908.                 /* copy changes */
  1909.                 if (changesmade) {
  1910.                     for (i=0; i<numhd; i++) {
  1911.                     memcpy(hdarr[i],
  1912.                            newhdarr[i],
  1913.                            sizeof(HardDrive));
  1914.                     }
  1915.                 }
  1916.                 } else if (rc == 2) {
  1917.                 retcode = FDISK_ERR_USERABORT;
  1918.                 *writeChanges = 0;
  1919.                 } else {
  1920.                 continue;
  1921.                 }
  1922.             } else {
  1923.                 retcode = FDISK_SUCCESS; /* no changes made */
  1924.             }
  1925.  
  1926.             /* make sure we indicate they canceled */
  1927.             if (event.u.co == cancel)
  1928.                 retcode = FDISK_ERR_USERABORT;
  1929.  
  1930.             formdone = 1;
  1931.             totallydone = 1;
  1932.             } else if (event.u.co == add) {
  1933.             status=DoMenuFunction("ADD", hdarr, numhd, newhdarr,
  1934.                        partbox, &partbox_status, spec );
  1935.             if (status == FDISK_SUCCESS) {
  1936.                 formdone = 1;
  1937.                 changesmade = 1;
  1938.             }
  1939.             } else if (event.u.co == del && partbox != NULL) {
  1940.             /* see if its NFS or local mount */
  1941.             int sel;
  1942.             sel = (long) newtListboxGetCurrent(partbox);
  1943.             if (partbox_status.entry[sel].type == PARTBOX_PART)
  1944.                 if (dontPartition) 
  1945.                 newtWinMessage(_("Error"), _("Ok"),
  1946.                     _("You may only delete NFS mounts."));
  1947.                 else 
  1948.                 status=DoMenuFunction("DEL", hdarr, numhd,
  1949.                               newhdarr,
  1950.                               partbox, &partbox_status,
  1951.                               spec );
  1952.             else
  1953.                 status=DeleteNFSMount(remotefs, 
  1954.                     partbox_status.entry[sel].index);
  1955.             
  1956.             if (status == FDISK_SUCCESS) {
  1957.                 formdone = 1;
  1958.                 changesmade = 1;
  1959.             }
  1960.             } else if (event.u.co == edit && partbox != NULL) {
  1961.             /* see if its NFS or local mount */
  1962.             int sel;
  1963.             sel = (long) newtListboxGetCurrent(partbox);
  1964.             if (partbox_status.entry[sel].type == PARTBOX_PART)
  1965.                 status=DoMenuFunction("EDIT", hdarr, numhd,
  1966.                           newhdarr,
  1967.                           partbox, &partbox_status,
  1968.                           spec );
  1969.             else
  1970.                 status=EditNFSMount(remotefs,
  1971.                     partbox_status.entry[sel].index,
  1972.                         intf, netc, dl);
  1973.             
  1974.                 
  1975.             if (status == FDISK_SUCCESS) {
  1976.                 formdone = 1;
  1977.                 changesmade = 1;
  1978.             }
  1979.             } else if (event.u.co == reset) {
  1980.             if (newtWinChoice(_("Reset Partition Table"),
  1981.                       _("Yes"), _("No"),
  1982.                     _("Reset partition table to original "
  1983.                       "contents? ")) != 2) {
  1984.                 for (i=0; i<numhd; i++)
  1985.                 memcpy(hdarr[i],prestinehdarr[i],
  1986.                        sizeof(HardDrive));
  1987.  
  1988.                 fdiskWipePartitionSpec(spec);
  1989.                 fdiskSetupPartitionSpec( hdarr, numhd, spec );
  1990.  
  1991.                 changesmade = 0;
  1992.                 formdone = 1;
  1993.             }
  1994.             } else if (event.u.co == addnfs) {
  1995.             status=EditNFSMount(remotefs, -1, intf, netc, dl);
  1996.  
  1997.             if (status == FDISK_SUCCESS) {
  1998.                 formdone = 1;
  1999.                 changesmade = 1;
  2000.             }
  2001.             }
  2002.         } else {
  2003.             /* see if its NFS or local mount */
  2004.             int sel;
  2005.             sel = (long) newtListboxGetCurrent(partbox);
  2006.             if (partbox_status.entry[sel].type == PARTBOX_PART)
  2007.             status=DoMenuFunction("EDIT", hdarr, numhd, newhdarr,
  2008.                           partbox, &partbox_status, spec );
  2009.             else
  2010.             status=EditNFSMount(remotefs,
  2011.                         partbox_status.entry[sel].index,
  2012.                         intf, netc, dl);
  2013.             
  2014.             if (status == FDISK_SUCCESS) {
  2015.             formdone = 1;
  2016.             changesmade = 1;
  2017.             }
  2018.         }
  2019.         }
  2020.  
  2021.         /* save current line if leaving */
  2022.         if (partbox)
  2023.         currentselection = (long) newtListboxGetCurrent(partbox);
  2024.     }
  2025.  
  2026.     newtPopHelpLine();
  2027.     if (partbox)
  2028.         free(partbox_status.entry);
  2029.     newtFormDestroy(form);
  2030.     }
  2031.  
  2032.     newtPopWindow();
  2033.  
  2034.     return retcode;
  2035. }
  2036.  
  2037. /* converts a PartionSpec to an equivalent struct fstab */
  2038. /* Creates fstab from scratch                           */
  2039. static int PartitionSpecToFstab( HardDrive **hdarr, int numhd,
  2040.               PartitionSpec *spec, struct fstab *fstab ) {
  2041.  
  2042.     int i, j;
  2043.     struct fstabEntry entry;
  2044.     
  2045.     fstab->entries = malloc(sizeof(*fstab->entries) * spec->num);
  2046.     fstab->numEntries = 0;
  2047.     for (i = 0; i < spec->num; i++) {
  2048.     if (!spec->entry[i].name) continue;
  2049.     
  2050.     if (spec->entry[i].status != REQUEST_ORIGINAL &&
  2051.         spec->entry[i].status != REQUEST_GRANTED)
  2052.         continue;
  2053.     
  2054.     /* FIXME: hack, hack, hack */
  2055.     if (*spec->entry[i].name != '/' &&
  2056.         *spec->entry[i].name != 'S') continue;
  2057.     
  2058.     for (j=0; j<numhd; j++)
  2059.         if (hdarr[j]->num == spec->entry[i].partition.drive.current)
  2060.         break;
  2061.     
  2062.     if (j == numhd)
  2063.         continue;
  2064.  
  2065.     initFstabEntry(&entry);
  2066.     entry.mntpoint = strdup(spec->entry[i].name);
  2067.     entry.size = spec->entry[i].partition.size.current / 2;
  2068.  
  2069.     entry.device = malloc(6);
  2070.     sprintf(entry.device, "%s%d",
  2071.         hdarr[j]->name + 5, spec->entry[i].partition.num.current);
  2072.     
  2073.     switch (spec->entry[i].partition.type.current) {
  2074.       case LINUX_NATIVE_PARTITION:
  2075.         entry.type = PART_EXT2;
  2076.         entry.tagName = "Linux native";
  2077.         break;
  2078.         
  2079.       case LINUX_SWAP_PARTITION:
  2080.         entry.type = PART_SWAP;
  2081.         entry.tagName = "Linux swap";
  2082.         break;
  2083.         
  2084.       case DOS_PRIMARY_lt32MEG_PARTITION:
  2085.       case DOS_PRIMARY_gt32MEG_PARTITION:
  2086.         entry.type = PART_DOS;
  2087.         entry.tagName = "DOS 16-bit >=32";
  2088.         break;
  2089.         
  2090.       default:
  2091.         entry.type = PART_OTHER;
  2092.         entry.tagName = "Other";
  2093.         break;
  2094.     }
  2095.  
  2096.     addFstabEntry(fstab, entry);
  2097.     }
  2098.     
  2099.     fstabSort(fstab);
  2100.     return 0;
  2101. }
  2102.  
  2103.  
  2104. /* merges mount point info from existing struct fstab into a PartionSpec     */
  2105. /* PartitionSpec should already exist and be primed with existing partitions */
  2106. /* Note - remote fs ARE NOT stored in the PartitionSpec                      */
  2107. static int MergeFstabEntries( HardDrive **hdarr, int numhd,
  2108.                   PartitionSpec *spec, struct fstab *fstab ) {
  2109.  
  2110.     int i, j, k;
  2111.     char device[6];
  2112.     
  2113.     for (j = 0; j < spec->num; j++) {
  2114.     for (k=0; k<numhd; k++)
  2115.         if (hdarr[k]->num == spec->entry[j].partition.drive.current)
  2116.         break;
  2117.     
  2118.     if (k == numhd)
  2119.         continue;
  2120.  
  2121.     sprintf(device, "%s%d",
  2122.         hdarr[k]->name + 5, spec->entry[j].partition.num.current);
  2123.     
  2124.     for (i = 0; i < fstab->numEntries; i++)
  2125.         if (!strcmp(fstab->entries[i].device, device))
  2126.         break;
  2127.  
  2128.     if ( i == fstab->numEntries )
  2129.         continue;
  2130.  
  2131.     /* we found a matching entry in the PartitionSpec */
  2132.     /* see if the old fstab file had any info we need */
  2133.     /* to use (like mount point, etc)                 */
  2134.     if (spec->entry[j].name)
  2135.         free(spec->entry[j].name);
  2136.  
  2137.     spec->entry[j].name = strdup(fstab->entries[i].mntpoint);
  2138.     }
  2139.  
  2140.     return 0;
  2141. }
  2142.  
  2143. /* suck out just the remote fs entries from an fstab */
  2144. /* pretty much CopyFstab, with filter on type        */
  2145. struct fstab copyRemoteFSFstab(struct fstab * fstab) {
  2146.     struct fstab newfstab;
  2147.     int i, j;
  2148.  
  2149.     if (!fstab->numEntries) {
  2150.         newfstab.numEntries = 0;
  2151.         newfstab.entries = malloc(1);
  2152.         return newfstab;
  2153.     }
  2154.  
  2155.     /* duplicate the current fstab */
  2156.     newfstab.numEntries = fstab->numEntries;
  2157.     newfstab.entries = malloc(fstab->numEntries * sizeof(struct fstabEntry));
  2158.     for (i = j = 0; i < newfstab.numEntries; i++) {
  2159.     if (fstab->entries[i].type != PART_NFS)
  2160.         continue;
  2161.     
  2162.         if (fstab->entries[i].mntpoint) {
  2163.             newfstab.entries[j] = fstab->entries[i];
  2164.             newfstab.entries[j].mntpoint=nstrdup(fstab->entries[i].mntpoint);
  2165.             newfstab.entries[j].device = nstrdup(fstab->entries[i].device);
  2166.             newfstab.entries[j].netPath = nstrdup(fstab->entries[i].netPath);
  2167.             newfstab.entries[j].netHost = nstrdup(fstab->entries[i].netHost);
  2168.             j++;
  2169.         }
  2170.     }
  2171.  
  2172.     newfstab.numEntries = j;
  2173.  
  2174.     /* return the memory we don't actually need */
  2175.     newfstab.entries=realloc(newfstab.entries, j * sizeof(struct fstabEntry));
  2176.  
  2177.     return newfstab;
  2178. }
  2179.  
  2180.  
  2181. /* suck out just the remote fs entries from an fstab */
  2182. /* pretty much CopyFstab, with filter on type        */
  2183. void MergeRemoteFSFstab(struct fstab *oldfstab, struct fstab *newfstab) {
  2184.     int i, j;
  2185.  
  2186.     /* copy remote fs entries */
  2187.     for (i = 0; i < oldfstab->numEntries; i++) {
  2188.     if (oldfstab->entries[i].type != PART_NFS)
  2189.         continue;
  2190.     
  2191.         if (oldfstab->entries[i].mntpoint) {
  2192.         j = newfstab->numEntries;
  2193.         newfstab->entries = realloc(newfstab->entries,
  2194.                      (j+1)*sizeof(struct fstabEntry));
  2195.         newfstab->entries[j] = oldfstab->entries[i];
  2196.             newfstab->entries[j].mntpoint=nstrdup(oldfstab->entries[i].mntpoint);
  2197.             newfstab->entries[j].device=nstrdup(oldfstab->entries[i].device);
  2198.             newfstab->entries[j].netPath=nstrdup(oldfstab->entries[i].netPath);
  2199.             newfstab->entries[j].netHost=nstrdup(oldfstab->entries[i].netHost);
  2200.         newfstab->numEntries = j+1;
  2201.         }
  2202.     }
  2203. }
  2204.  
  2205. static int deletePartitionClass(HardDrive ** hd, int numhd, 
  2206.                 PartitionSpec * spec, int justLinux) {
  2207.     int deleteit;
  2208.     int type;
  2209.     int i;
  2210.  
  2211.     i = 0;
  2212.     while (i < spec->num) {
  2213.     type = spec->entry[i].partition.type.current;
  2214.  
  2215.     deleteit = !justLinux;
  2216.     if (justLinux && (type == LINUX_SWAP_PARTITION || 
  2217.               type == LINUX_NATIVE_PARTITION))
  2218.         deleteit = 1;
  2219.  
  2220.     if (deleteit) {
  2221.         DeletePartitionSpec(hd, numhd, spec, &spec->entry[i], 1);
  2222.         fdiskCleanOriginalSpecs( hd, numhd, spec );
  2223.         i=0; /* restart cause entries changed */
  2224.         continue;
  2225.     } else {
  2226.         i++;
  2227.     }
  2228.     }
  2229.  
  2230.     return 0;
  2231. }
  2232.  
  2233. int kickstartPartitioning(struct partitionTable * parts, struct fstab * fstab, 
  2234.               char **drives) {
  2235.  
  2236.     HardDrive     *hd[MAX_HARDDRIVES];
  2237.     HardDrive     *tmphd[MAX_HARDDRIVES]; /* ORIGINAL HD partition data    */
  2238.     unsigned int  numhd;                  /* total # of drives to consider */
  2239.     Partition     template;
  2240.     PartitionSpec spec;
  2241.     unsigned int  i;
  2242.     struct fstab  remotefstab;
  2243.     char ** deviceList;
  2244.     int rc;
  2245.     int numDrives;
  2246.  
  2247.     int size, maxsize, grow, clearall, clearlinux, zerombr;
  2248.     int argc;
  2249.     char *mntpt;
  2250.     char *eptr;
  2251.     char *sizestr, *maxsizestr;
  2252.     char **argv;
  2253.     poptContext optCon;
  2254.     struct poptOption ksPartOptions[] = {
  2255.     { "size", '\0', POPT_ARG_STRING, &sizestr, 0 },
  2256.     { "maxsize",  '\0', POPT_ARG_STRING, &maxsize, 0 },
  2257.     { "grow", '\0', POPT_ARG_NONE, &grow, 0 },
  2258.     { 0, 0, 0, 0, 0 }
  2259.     };
  2260.  
  2261.     struct poptOption ksClearOptions[] = {
  2262.     { "linux", '\0', POPT_ARG_NONE, &clearlinux, 0},
  2263.     { "all", '\0', POPT_ARG_NONE, &clearall, 0},
  2264.     { 0, 0, 0, 0, 0 }
  2265.     };
  2266.  
  2267.     struct poptOption ksZeroMBROptions[] = {
  2268.     { 0, 0, 0, 0, 0 }
  2269.     };
  2270.  
  2271.     numDrives = 0;
  2272.     for (i = 0; drives[i]; i++, numDrives++);
  2273.  
  2274.     if (numDrives >= MAX_HARDDRIVES) {
  2275.     newtWinMessage(_("Too Many Drives"), _("Ok"),
  2276.           _("You have more drives than this program supports. "
  2277.             "Please use the standard fdisk program to setup your "
  2278.             "drives and please notify Red Hat Software that you "
  2279.             "saw this message."));
  2280.     return INST_ERROR;
  2281.     }
  2282.     
  2283.     deviceList = alloca(numDrives * sizeof(char *));
  2284.  
  2285.     for (i = 0; i < numDrives; i++) {
  2286.     deviceList[i] = alloca(15);
  2287.     strcpy(deviceList[i], "/tmp/");
  2288.     strcat(deviceList[i], drives[i]);
  2289.  
  2290.     if ((rc = devMakeInode(drives[i], deviceList[i]))) return INST_ERROR;
  2291.     }
  2292.     
  2293.     /* see if they want bad partition tables automatically zero'd */
  2294.     argv = NULL;
  2295.     zerombr = 0;
  2296.     while (1) {
  2297.     if (!ksGetCommand(KS_CMD_ZEROMBR, argv, &argc, &argv)) {
  2298.         char *t;
  2299.         
  2300.         optCon = poptGetContext(NULL, argc, argv, ksZeroMBROptions, 0);
  2301.  
  2302.         /* no options, but just a 'on' or 'off' command */
  2303.         /* have to parse options anyway to make popt see the leftover? */
  2304.         poptGetNextOpt(optCon);
  2305.         t = poptGetArg(optCon);
  2306.         if (*t && (!strcasecmp(t,"no") || !strcasecmp(t,"off") || !strcmp(t,"0")))
  2307.         zerombr = 0;
  2308.         else if (*t && (!strcasecmp(t,"yes") || !strcasecmp(t,"on") || !strcmp(t,"1")))
  2309.         zerombr = 1;
  2310.         else
  2311.         newtWinMessage(_("Zero Partition Table"), _("Ok"),
  2312.                    _("bad argument to kickstart "
  2313.                      "zerombr command: %s.\nMust be "
  2314.                                  "'on', '1', or 'yes' to enable, "
  2315.                      "or 'off', '0', or 'no' to disable."),t);
  2316.  
  2317.         poptFreeContext(optCon);
  2318.     } else {
  2319.         break;
  2320.     }
  2321.     }
  2322.  
  2323.     /* Read in the partition tables from the requested drive(s) */
  2324.     /* first clear all entries                                  */
  2325.     memset(hd, 0, MAX_HARDDRIVES*sizeof(HardDrive *));
  2326.     ReadDrives(deviceList, numDrives, hd, &numhd, zerombr, 0);
  2327.  
  2328.     if (numhd <1) {
  2329.     newtWinMessage(_("No Drives Found"), _("Ok"),
  2330.           _("An error has occurred - no valid devices were found "
  2331.             "on which to create new filesystems.  Please check "
  2332.             "your hardware for the cause of this problem."));
  2333.  
  2334.     for (i = 0; i < numDrives; i++)
  2335.         unlink(deviceList[i]);
  2336.     return INST_ERROR;
  2337.     }
  2338.  
  2339.    
  2340.     /* Translate into a PartitionSpec */
  2341.     memset(&spec, 0, sizeof(PartitionSpec));
  2342.     fdiskSetupPartitionSpec( hd, numhd, &spec );
  2343.  
  2344.     /* copy the fstab they passed, we'll use it until we're done */
  2345.     /* if they dont cancel it will be new fstab                  */
  2346.     remotefstab = copyRemoteFSFstab( fstab );
  2347.     MergeFstabEntries( hd, numhd, &spec, fstab );
  2348.  
  2349.     /* see if they want anything removed from disk */
  2350.     argv = NULL;
  2351.     clearall   = 0;
  2352.     clearlinux = 0;
  2353.     if (!ksGetCommand(KS_CMD_CLEARPART, argv, &argc, &argv)) {
  2354.     optCon = poptGetContext(NULL, argc, argv, ksClearOptions, 0);
  2355.     
  2356.     rc = poptGetNextOpt(optCon);
  2357.     if ( rc < -1) {
  2358.         newtWinMessage(_("Clear Partition Command"), _("Ok"),
  2359.                _("bad argument to kickstart "
  2360.                  "clearpart command %s: %s"),
  2361.                poptBadOption(optCon, POPT_BADOPTION_NOALIAS), 
  2362.                poptStrerror(rc));
  2363.  
  2364.         for (i=0; i<numhd; i++)
  2365.         fdiskCloseDevice(hd[i]);
  2366.         
  2367.         for (i = 0; i < numDrives; i++)
  2368.         unlink(deviceList[i]);
  2369.  
  2370.         return INST_ERROR; /* may not clear what they intended */
  2371.     }
  2372.  
  2373.     if (clearall || clearlinux) 
  2374.         deletePartitionClass(hd, numhd, &spec, clearlinux);
  2375.     poptFreeContext(optCon);
  2376.     }        
  2377.     
  2378.     /* copy original hard drive configurations into work spaces */
  2379.     for (i=0; i<numhd; i++) {
  2380.     tmphd[i] = (HardDrive *) alloca(sizeof(HardDrive));
  2381.     memcpy(tmphd[i], hd[i], sizeof(HardDrive));
  2382.     }
  2383.  
  2384.     
  2385.     /* now stick their requests into the partition spec and allocate */
  2386.     /* the partitions                                                */
  2387.     argv = NULL;
  2388.     while (1) {
  2389.     sizestr = NULL;
  2390.     maxsizestr = NULL;
  2391.     grow = 0;
  2392.     if (!ksGetCommand(KS_CMD_PART, argv, &argc, &argv)) {
  2393.         optCon = poptGetContext(NULL, argc, argv, ksPartOptions, 0);
  2394.  
  2395.         rc = poptGetNextOpt(optCon);
  2396.         if ( rc < -1) {
  2397.         newtWinMessage(_("Partition Command"), _("Ok"),
  2398.                    _("bad argument to kickstart "
  2399.                      "part command %s: %s"),
  2400.                    poptBadOption(optCon, POPT_BADOPTION_NOALIAS), 
  2401.                    poptStrerror(rc));
  2402.         }
  2403.  
  2404.         mntpt  = poptGetArg(optCon);
  2405.  
  2406.         if (sizestr) {
  2407.         size=strtol(sizestr,&eptr, 10);
  2408.         if (eptr != sizestr && *eptr == 0 && size > 0)
  2409.             size *= SECPERMEG;
  2410.         else
  2411.             size = 0;
  2412.         } else {
  2413.         size=0;
  2414.         }
  2415.  
  2416.         if (maxsizestr) {
  2417.         maxsize=strtol(maxsizestr,&eptr, 10);
  2418.         if (eptr != maxsizestr && *eptr == 0 && maxsize > 0)
  2419.             maxsize *= SECPERMEG;
  2420.         else
  2421.             maxsize = 0;
  2422.         } else {
  2423.         maxsize=0;
  2424.         }
  2425.  
  2426.         if (maxsizestr && !maxsize)
  2427.         newtWinMessage(_("Option Ignored"), _("Ok"),
  2428.                    _("The --maxsize option for the partition "
  2429.                      "%s was ignored. Check that it is larger "
  2430.                      "than the --size option."), mntpt);
  2431.         
  2432.         /* all done with current context */
  2433.         poptFreeContext(optCon);
  2434.         
  2435.         if (!mntpt || size == 0) {
  2436.         for (i=0; i<numhd; i++)
  2437.             fdiskCloseDevice(hd[i]);
  2438.         
  2439.         for (i = 0; i < numDrives; i++)
  2440.             unlink(deviceList[i]);
  2441.         return INST_ERROR;
  2442.         }
  2443.  
  2444.         /* fill in the requested partition */
  2445.         memset(&template, 0, sizeof(Partition));
  2446.  
  2447.         /* set the size */
  2448.         if (grow)
  2449.         fdiskSetConstraint(&template.size,
  2450.                    0,
  2451.                    size,
  2452.                    (maxsize) ? maxsize : FDISK_SIZE_MAX,
  2453.                    1);
  2454.         else
  2455.         fdiskSetConstraint(&template.size,
  2456.                    0,
  2457.                    size,
  2458.                    size,
  2459.                    1);
  2460.  
  2461.         /* set the type */
  2462.         if (!strcasecmp(mntpt, "swap"))
  2463.         fdiskSetConstraint(&template.type,
  2464.                    LINUX_SWAP_PARTITION,
  2465.                    LINUX_SWAP_PARTITION,
  2466.                    LINUX_SWAP_PARTITION,
  2467.                    1);
  2468.         else {
  2469.         fdiskSetConstraint(&template.type,
  2470.                    LINUX_NATIVE_PARTITION,
  2471.                    LINUX_NATIVE_PARTITION,
  2472.                    LINUX_NATIVE_PARTITION,
  2473.                    1);
  2474.         /* test mntpt */
  2475.         if (badMountPoint(template.type.current, mntpt)) {
  2476.             for (i=0; i<numhd; i++)
  2477.             fdiskCloseDevice(hd[i]);
  2478.             
  2479.             for (i = 0; i < numDrives; i++)
  2480.             unlink(deviceList[i]);
  2481.  
  2482.             return INST_ERROR;
  2483.         }
  2484.         
  2485.         if (!fdiskIndexPartitionSpec(&spec, mntpt, &rc)) {
  2486.             newtWinMessage(_("Mount Point Error"), _("Ok"),
  2487.                _("The mount point %s is already in use."), mntpt);
  2488.             for (i=0; i<numhd; i++)
  2489.             fdiskCloseDevice(hd[i]);
  2490.             
  2491.             for (i = 0; i < numDrives; i++)
  2492.             unlink(deviceList[i]);
  2493.             return INST_ERROR;
  2494.         }
  2495.  
  2496.         }
  2497.  
  2498.         /* make sure we have a valid swap partition name */
  2499.         if (template.type.current == LINUX_SWAP_PARTITION) {
  2500.         if (strcasecmp("swap", mntpt)) {
  2501.             fdiskMakeSwapSpecName( &spec, &mntpt );
  2502.         }
  2503.         }
  2504.  
  2505.         /* make an entry */
  2506.         fdiskInsertPartitionSpec(&spec, mntpt,&template, REQUEST_PENDING);
  2507.         fdiskHandleSpecialPartitions( &spec );
  2508.     } else {
  2509.         break;
  2510.     }
  2511.     }
  2512.  
  2513.     /* insert the new partition spec */
  2514.     fdiskAutoInsertPartitions(hd, numhd, tmphd, &spec);
  2515.     showReasons( &spec );
  2516.     fdiskGrowPartitions(hd, numhd, tmphd, &spec);
  2517.  
  2518.     rc = REQUEST_GRANTED;
  2519.     for (i=0; i<spec.num; i++)
  2520.     if (spec.entry[i].status == REQUEST_DENIED) {
  2521.         rc = REQUEST_DENIED;
  2522.         newtWinMessage(_("Failed Allocation"), _("Ok"),
  2523.                _("The partition %s could not be allocated."),
  2524.                spec.entry[i].name);
  2525.     }
  2526.  
  2527.  
  2528.     if (rc == REQUEST_DENIED) {
  2529.     for (i=0; i<numhd; i++)
  2530.         fdiskCloseDevice(hd[i]);
  2531.     
  2532.     for (i = 0; i < numDrives; i++)
  2533.         unlink(deviceList[i]);
  2534.  
  2535.     return INST_ERROR;
  2536.     }
  2537.  
  2538.     /* Write partitions to disk */
  2539.     for (i=0; i<numhd; i++)
  2540.     memcpy(hd[i], tmphd[i], sizeof(HardDrive));
  2541.     
  2542.     if (!testing) {
  2543.     for (i=0; i<numhd; i++)
  2544.         hd[i]->write_f(hd[i]);
  2545.     }
  2546.     
  2547.     if ((rc = findAllPartitions(NULL, parts))) {
  2548.     for (i=0; i<numhd; i++)
  2549.         fdiskCloseDevice(hd[i]);
  2550.     
  2551.     for (i = 0; i < numDrives; i++)
  2552.         unlink(deviceList[i]);
  2553.  
  2554.     return INST_ERROR;
  2555.     }
  2556.     
  2557.     /* free up old fstab */
  2558.     if (fstab)
  2559.     freeFstab(*fstab);
  2560.     PartitionSpecToFstab( hd, numhd, &spec, fstab );
  2561.     MergeRemoteFSFstab( &remotefstab, fstab );
  2562.     freeFstab(remotefstab);
  2563.     
  2564.     for (i=0; i<numhd; i++)
  2565.     fdiskCloseDevice(hd[i]);
  2566.  
  2567.     for (i = 0; i < numDrives; i++)
  2568.     unlink(deviceList[i]);
  2569.  
  2570.     return 0;
  2571. }
  2572.  
  2573. static int addNewPartition(PartitionSpec * spec, 
  2574.                    char * where, int megs, int grow, int bootable, 
  2575.                    unsigned char type, int startCyl) {
  2576.     Partition template;
  2577.     
  2578.     /* create a template partitionspec to send to editpartition */
  2579.     memset(&template, 0, sizeof(Partition));
  2580.     fdiskSetFixedConstraint(&template.type, type);
  2581.  
  2582.     if (bootable) {
  2583.     fdiskDeactivateAllDriveSet( &template.drive );
  2584.     fdiskActivateDriveSet(&template.drive, 1);
  2585.     fdiskActivateDriveSet(&template.drive, 2);
  2586.     fdiskSetConstraint(&template.endcyl, 0, 0, 1023, 1);
  2587.     }
  2588.  
  2589. /*  For now we'll make this alpha only code  */
  2590. #ifdef __alpha__
  2591.  
  2592.     if (startCyl != -1) {
  2593.     /* XXX HACK */
  2594.     /* Add a little buffer in case we need to skip a head */
  2595.     fdiskSetConstraint(&template.start, 0, startCyl, startCyl + 100, 1);
  2596.     }
  2597.  
  2598. #endif
  2599.  
  2600.     fdiskSetConstraint(&template.size, SECPERMEG * megs, SECPERMEG * megs,
  2601.             grow ? FDISK_SIZE_MAX : SECPERMEG * megs, 1);
  2602.  
  2603.     /* insert with a name we know to mean its a new partition */
  2604.     fdiskInsertPartitionSpec(spec, where, &template, 
  2605.                   REQUEST_PENDING);
  2606.     
  2607.     return 0;
  2608. }
  2609.  
  2610. static int tryGoal(HardDrive ** hdarr, HardDrive ** tmphdarr, int numhd, 
  2611.            PartitionSpec * spec, struct attemptedPartition * goals) {
  2612.     int i;
  2613.  
  2614.     for (i = 0; goals[i].mount; i++)
  2615.     addNewPartition(spec, goals[i].mount, goals[i].size, 
  2616.             goals[i].grow, !strcmp(goals[i].mount, "/boot"),
  2617.             goals[i].type, goals[i].start);
  2618.  
  2619.     /* insert the new partition spec */
  2620.     fdiskAutoInsertPartitions(hdarr, numhd, tmphdarr, spec );
  2621.     fdiskGrowPartitions(hdarr, numhd, tmphdarr, spec);
  2622.  
  2623.     for (i = 0; i < spec->num; i++)
  2624.     if (spec->entry[i].status == REQUEST_DENIED)
  2625.         break;
  2626.  
  2627.     return (i < spec->num);
  2628. }
  2629.  
  2630. static int guessAtPartitioning(HardDrive ** hdarr, int numhd,
  2631.                    PartitionSpec * spec, int * runDruid,
  2632.                    int dir, int flags,
  2633.                    struct attemptedPartition * goals) {
  2634.     HardDrive * tmparr[MAX_HARDDRIVES];
  2635.     int i, rc;
  2636.     static int mayDisplay = 1;
  2637.     int erasedLinux = 0;
  2638.     int erasedAll = 0;
  2639.  
  2640.     *runDruid = 1;
  2641.  
  2642.     if (!mayDisplay) {
  2643.     if (dir < 0) return INST_CANCEL;
  2644.     return 0;
  2645.     }
  2646.  
  2647.     for (i=0; i<numhd; i++) {
  2648.     tmparr[i] = (HardDrive *) alloca(sizeof(HardDrive));
  2649.     memcpy(tmparr[i], hdarr[i], sizeof(HardDrive));
  2650.     }
  2651.  
  2652.     if (fdiskIndexPartitionSpec(spec, "/", &i ) == FDISK_SUCCESS) {
  2653.     return 0;
  2654.     } else if (flags & (FSEDIT_CLEARLINUX | FSEDIT_CLEARALL)) {
  2655.     i = spec->num;
  2656.     deletePartitionClass(hdarr, numhd, spec, 
  2657.                  flags & FSEDIT_CLEARLINUX);
  2658.     if (spec->num != i) {
  2659.         erasedLinux = flags & FSEDIT_CLEARLINUX;
  2660.         erasedAll = flags & FSEDIT_CLEARALL;
  2661.     }
  2662.  
  2663.     rc = tryGoal(hdarr, tmparr, numhd, spec, goals);
  2664.     if (rc && (flags & FSEDIT_CLEARALL)) {
  2665.         i = spec->num;
  2666.         deletePartitionClass(hdarr, numhd, spec, 0);
  2667.         if (spec->num != i) {
  2668.         erasedAll = 1;
  2669.         memset(spec, 0, sizeof(PartitionSpec));
  2670.         fdiskSetupPartitionSpec( hdarr, numhd, spec );
  2671.         rc = tryGoal(hdarr, tmparr, numhd, spec, goals);
  2672.         }
  2673.     }
  2674.  
  2675.     if (!rc) {
  2676.         char message[2000];
  2677.  
  2678.         while (1) {
  2679.         strcpy(message, erasedAll ?
  2680.             "All of the partitions on your hard drive(s) will be "
  2681.             "erased.\n\n"
  2682.             "This means that all of the data on your system will be "
  2683.             "destroyed.\n"
  2684.             "\n"
  2685.             "If you do not want to lose all of your partitions, "
  2686.             "select \"Cancel\" now, and perform a \"Custom\" install."
  2687.             :
  2688.             "All of the Linux partitions on your hard drive(s) will be "
  2689.             "erased.\n\n"
  2690.             "This means that all of your previous Linux installations "
  2691.             "will be destroyed.\n"
  2692.             "\n"
  2693.             "If you do not want to lose all of your Linux partitions, "
  2694.             "select \"Cancel\" now, and perform a \"Custom\" install."
  2695.         );
  2696.             
  2697.         rc = newtWinChoice(_("Warning"), _("Ok"), _("Cancel"), message);
  2698.         if (rc == 2) return INST_CANCEL;
  2699.  
  2700.         rc = newtWinChoice(_("Warning"), _("Yes"), _("No"),
  2701.             _("You are about to lose data! Are you sure you want "
  2702.               "to do this?"));
  2703.         if (rc != 2) break;
  2704.         }
  2705.  
  2706.         *runDruid = 0, rc = 0;
  2707.     } else {
  2708.         newtWinMessage(_("Disk Space"), _("Ok"),
  2709.                 _("There is not enough disk space for this type "
  2710.                 "of installation."));
  2711.         return INST_CANCEL;
  2712.     }
  2713.     }
  2714.  
  2715.     if (*runDruid) {
  2716.     /* Put everything back */
  2717.     memset(spec, 0, sizeof(PartitionSpec));
  2718.     fdiskSetupPartitionSpec( hdarr, numhd, spec );
  2719.     } else {
  2720.     for (i=0; i<numhd; i++) {
  2721.         *hdarr[i] = *tmparr[i];
  2722.     }
  2723.     }
  2724.  
  2725.     mayDisplay = !(*runDruid);
  2726.  
  2727.     return 0;
  2728. }
  2729.     
  2730. /* main program */
  2731. int FSEditPartitions(struct partitionTable * parts, struct fstab * fstab, 
  2732.              char **drives,
  2733.              struct intfInfo * intf, struct netInfo * netc,
  2734.              struct driversLoaded ** dl, 
  2735.              struct attemptedPartition * goals,
  2736.              int flags) {
  2737.     HardDrive     *prestinehdarr[MAX_HARDDRIVES];
  2738.     HardDrive     *hdarr[MAX_HARDDRIVES]; /* ORIGINAL HD partition data    */
  2739.     unsigned int  numhd;                  /* total # of drives to consider */
  2740.     PartitionSpec spec;
  2741.     unsigned int  i;
  2742.     struct fstab  remotefstab;
  2743.     char ** deviceList;
  2744.     int rc, ourrc = 0;
  2745.     int numDrives;
  2746.     static int beenManual = 0;
  2747.     int runDruid = 0;
  2748.     int writeChanges = 0;
  2749.     static int where = 0;
  2750.     int done = 0;
  2751.     int dir;
  2752.  
  2753.     if (where == 0)
  2754.     dir = 1;
  2755.     else
  2756.     dir = -1;
  2757.  
  2758.     numDrives = 0;
  2759.     for (i = 0; drives[i]; i++, numDrives++);
  2760.  
  2761.     if (numDrives >= MAX_HARDDRIVES) {
  2762.     newtWinMessage(_("Too Many Drives"), _("Ok"),
  2763.           _("You have more drives than this program supports. "
  2764.             "Please use the standard fdisk program to setup your "
  2765.             "drives and please notify Red Hat Software that you "
  2766.             "saw this message."));
  2767.     return INST_ERROR;
  2768.     }
  2769.     
  2770.     deviceList = alloca(numDrives * sizeof(char *));
  2771.  
  2772.     for (i = 0; i < numDrives; i++) {
  2773.     deviceList[i] = alloca(15);
  2774.     strcpy(deviceList[i], "/tmp/");
  2775.     strcat(deviceList[i], drives[i]);
  2776.  
  2777.     if ((rc = devMakeInode(drives[i], deviceList[i]))) return rc;
  2778.     }
  2779.     
  2780.     /* Read in the partition tables from the requested drive(s) */
  2781.     /* first clear all entries                                  */
  2782.     memset(hdarr, 0, MAX_HARDDRIVES*sizeof(HardDrive *));
  2783.     rc = ReadDrives(deviceList, numDrives, hdarr, &numhd,0, 
  2784.             flags & FSEDIT_READONLY);
  2785.     if (rc) return rc;
  2786.  
  2787.     if (numhd <1) {
  2788.     newtWinMessage(_("No Drives Found"), _("Ok"),
  2789.           _("An error has occurred - no valid devices were found "
  2790.             "on which to create new filesystems.  Please check "
  2791.             "your hardware for the cause of this problem."));
  2792.  
  2793.     for (i = 0; i < numDrives; i++)
  2794.         unlink(deviceList[i]);
  2795.     return INST_ERROR;
  2796.     }
  2797.  
  2798.     /* make backup of hdarr before user mucked with it */
  2799.     for (i=0; i<numhd; i++) {
  2800.     prestinehdarr[i] = (HardDrive *) alloca(sizeof(HardDrive));
  2801.     *prestinehdarr[i] = *hdarr[i];
  2802.     }
  2803.     
  2804.     /* Translate into a PartitionSpec */
  2805.     memset(&spec, 0, sizeof(PartitionSpec));
  2806.     fdiskSetupPartitionSpec( hdarr, numhd, &spec );
  2807.  
  2808.     /* copy the fstab they passed, we'll use it until we're done */
  2809.     /* if they dont cancel it will be new fstab                  */
  2810.     remotefstab = copyRemoteFSFstab( fstab );
  2811.     MergeFstabEntries( hdarr, numhd, &spec, fstab );
  2812.  
  2813.     if (flags & (FSEDIT_CLEARLINUX | FSEDIT_CLEARALL) && !beenManual) {
  2814.  
  2815.     if ((flags & FSEDIT_READONLY) || (!where && expert)) where = 1;
  2816.     rc = guessAtPartitioning(hdarr, numhd, &spec, &runDruid, dir, 
  2817.                 flags, goals ? goals : normalPartitioning);
  2818.     if (runDruid) 
  2819.         return INST_CANCEL;
  2820.     else
  2821.         writeChanges = 1;
  2822.     } else 
  2823.     beenManual = 1;
  2824.  
  2825.     if (beenManual) {
  2826.     /* Goto master screen */
  2827.     rc = StartMaster(hdarr, numhd, &spec,
  2828.                   &remotefstab, intf, netc, dl,
  2829.                   flags & FSEDIT_READONLY,
  2830.                   &writeChanges);
  2831.     if (rc == FDISK_ERR_USERABORT)
  2832.         ourrc = INST_CANCEL;
  2833.     else if (rc) 
  2834.         ourrc = INST_ERROR;
  2835.     else
  2836.         ourrc = 0;
  2837.     }
  2838.  
  2839.     if (writeChanges) {
  2840.  
  2841.     /* Write partitions to disk */
  2842.     if (!testing) {
  2843.         if (DisksChanged(prestinehdarr, hdarr, numhd)) {
  2844.         rc = 0;
  2845.         for (i=0; i<numhd; i++)
  2846.             rc |= hdarr[i]->write_f(hdarr[i]);
  2847.         if (rc) needReboot();
  2848.         }
  2849.     }
  2850.  
  2851.     if ((rc = findAllPartitions(NULL, parts))) {
  2852.         
  2853.         for (i=0; i<numhd; i++)
  2854.         fdiskCloseDevice(hdarr[i]);
  2855.         
  2856.         for (i = 0; i < numDrives; i++)
  2857.         unlink(deviceList[i]);
  2858.  
  2859.         return INST_ERROR;
  2860.     }
  2861.  
  2862.     /* free up old fstab */
  2863.     if (fstab)
  2864.         freeFstab(*fstab);
  2865.     PartitionSpecToFstab( hdarr, numhd, &spec, fstab );
  2866.     MergeRemoteFSFstab( &remotefstab, fstab );
  2867.     freeFstab(remotefstab);
  2868.     }
  2869.  
  2870.     for (i=0; i<numhd; i++)
  2871.     fdiskCloseDevice(hdarr[i]);
  2872.  
  2873.     for (i = 0; i < numDrives; i++)
  2874.     unlink(deviceList[i]);
  2875.  
  2876.     return ourrc;
  2877. }
  2878.