home *** CD-ROM | disk | FTP | other *** search
/ Chip 1998 February / CHIP_2_98.iso / misc / src / install / fsedit.c < prev    next >
C/C++ Source or Header  |  1997-11-03  |  75KB  |  2,717 lines

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