/* Newt based fdisk program * * Michael Fulbright (msf@redhat.com) * * Copyright 1999 Red Hat Software * * This software may be freely redistributed under the terms of the GNU * public license. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */ #include #include #include #include #include #include #include #include #include #include #include #include #include "kickstart.h" #include "fs.h" #include "fsedit.h" #include "hd.h" #include "install.h" #include "intl.h" #include "libfdisk/libfdisk.h" #include "devices.h" #include "windows.h" #ifdef ENABLE_RESIZE #ifdef __i386__ #include "libresize/libresize.h" #endif /* __i386__ */ #endif #include #define VERSION_STR "1.00" extern int testing; struct attemptedPartition normalPartitioning[] = { #if defined(__i386__) { "/boot", 16, LINUX_NATIVE_PARTITION, 0, -1 }, #elif defined(__alpha__) { "/dos", 2, DOS_PRIMARY_lt32MEG_PARTITION, 0, 1 }, #endif { "/", 400, LINUX_NATIVE_PARTITION, 1, -1 }, { "Swap-auto", 64, LINUX_SWAP_PARTITION, 0, -1 }, { NULL, 0, 0, 0 } }; /* need to move somewhere else eventually! */ /* mostly gleamed from fdisk.[ch] */ struct parttypes { unsigned int index; char *name; }; #define SUNPARTTYPE 0x100 #define NONSUNPARTTYPE 0x200 /* this isn't const, as we have a loop which does i18n conversion on these */ static struct parttypes allparttypes[] = { {0, "Empty"}, {SUNPARTTYPE|1, "Boot"}, {SUNPARTTYPE|2, "SunOS root"}, {SUNPARTTYPE|3, "SunOS swap"}, {SUNPARTTYPE|4, "SunOS usr"}, {SUNPARTTYPE|5, "Whole disk"}, {SUNPARTTYPE|6, "SunOS stand"}, {SUNPARTTYPE|7, "SunOS var"}, {SUNPARTTYPE|8, "SunOS home"}, {NONSUNPARTTYPE|1, "DOS 12-bit FAT"}, {NONSUNPARTTYPE|2, "XENIX root"}, {NONSUNPARTTYPE|3, "XENIX usr"}, {NONSUNPARTTYPE|4, "DOS 16-bit <32M"}, {NONSUNPARTTYPE|5, "Extended"}, {NONSUNPARTTYPE|6, "DOS 16-bit >=32M"}, {NONSUNPARTTYPE|7, "OS/2 HPFS"}, /* or QNX? */ {NONSUNPARTTYPE|8, "AIX"}, {9, "AIX bootable"}, {10, "OS/2 Boot Manager"}, {0xb, "Win95 FAT32"}, {0xc, "Win95 FAT32"}, {0xe, "Win95 FAT32"}, {0x12, "Compaq setup"}, {0x40, "Venix 80286"}, {0x51, "Novell?"}, {0x52, "Microport"}, /* or CPM? */ {0x63, "GNU HURD"}, /* or System V/386? */ {0x64, "Novell Netware 286"}, {0x65, "Novell Netware 386"}, {0x75, "PC/IX"}, {0x80, "Old MINIX"}, /* Minix 1.4a and earlier */ {0x81, "Linux/MINIX"}, /* Minix 1.4b and later */ {0x82, "Linux swap"}, {0x83, "Linux native"}, {0x93, "Amoeba"}, {0x94, "Amoeba BBT"}, /* (bad block table) */ {0xa5, "BSD/386"}, {0xb7, "BSDI fs"}, {0xb8, "BSDI swap"}, {0xc7, "Syrinx"}, {0xdb, "CP/M"}, /* or Concurrent DOS? */ {0xe1, "DOS access"}, {0xe3, "DOS R/O"}, {0xf2, "DOS secondary"}, {0xff, "BBT"} /* (bad track table) */ }; int nparttypes = sizeof (allparttypes) / sizeof (struct parttypes); /* hardcoded, maybe someday we'll get these from tty ? */ int screen_width=80; int screen_height=25; #define MAX_HARDDRIVES 16 #define SECPERMEG 2048 /* clean up that string */ static void TrimWhitespace( char *s ) { char *f, *l, *p, *q; if (!(*s)) return; for (f=s; *f && isspace(*f); f++) ; if (!*f) { *s = '\0'; return; } for (l=f+strlen(f)-1; isspace(*l) ; l--) *l = '\0'; q = s, p = f; while (*p) *q++ = *p++; *q = '\0'; } /* fill in the */ /* position in the status line, up to length characters */ /* if cen=1, center it */ static void BuildTableField( char *line, char *val, int pos, int length, int cen ) { char *p, *q; int i; int c; /* lets center field value in the field */ if (cen) { c = strlen(val); c = (length-c)/2; if (c < 0) c = 0; } else c=0; /* first setup device name */ for (p=val, q=line+pos+c, i=c; *p && idrive, 1 ) || fdiskThisDriveSetIsActive( &p->drive, 2 ); /* if so, see if rest are EXCLUDED */ if (bootable) { for (i=3; idrive, i)) { bootable = 0; break; } } } if (bootable) { if (p->endcyl.active && p->endcyl.max < 1024) { bootable = 1; } else if (p->immutable) { unsigned int end, c, h, s; end = p->start.current + p->size.current - 1; fdiskSectorToCHS( hd, end, &c, &h, &s ); if (c < 1024) bootable = 1; else bootable = 0; } else { bootable = 0; } } return bootable; } #endif /* check a mount point to make sure its valid */ /* returns non-zero if bad mount point */ static int badMountPoint(unsigned int type, char * item) { char * chptr = item; if (!strncmp(item, "/dev", 4) || !strncmp(item, "/bin", 4) || !strncmp(item, "/sbin", 5) || !strncmp(item, "/etc", 4) || #ifdef __sparc__ !strncmp(item, "/boot", 5) || #endif !strncmp(item, "/lib", 4)) { newtWinMessage(_("Bad Mount Point"), _("Ok"), _("The %s directory must be on the root filesystem."), item); return 1; } if (*chptr != '/') { newtWinMessage(_("Bad Mount Point"), _("Ok"), _("The mount point %s is illegal.\n\n" "Mount points must begin with a leading /."), item); return 1; } if (*(chptr + 1) && *(chptr + strlen(chptr) - 1) == '/') { newtWinMessage(_("Bad Mount Point"), _("Ok"), _("The mount point %s is illegal.\n\n" "Mount points may not end with a /."), item); return 1; } while (*chptr && isprint(*chptr)) chptr++; if (*chptr) { newtWinMessage(_("Bad Mount Point"), _("Ok"), _("The mount point %s is illegal.\n\n" "Mount points may only printable characters."), item); return 1; } if (type != LINUX_NATIVE_PARTITION && ( !strncmp(item, "/var", 4) || !strncmp(item, "/tmp", 4) || !strncmp(item, "/boot", 4) || !strcmp(item, "/") || !strncmp(item, "/root", 4))) { newtWinMessage(_("Bad Mount Point"), _("Ok"), _("The mount point %s is illegal.\n\n" "System partitions must be on Linux Native " "partitions."), item); return 1; } if (type != LINUX_NATIVE_PARTITION && type != NFS_REMOTE_PARTITION && !strncmp(item, "/usr", 4)) { newtWinMessage(_("Bad Mount Point"), _("Ok"), _("The mount point %s is illegal.\n\n" "/usr must be on a Linux Native partition " "or an NFS volume."), item); return 1; } return 0; } /* */ /* NEWT/screen related routines */ /* */ /* handles standard fdisk type errors */ /* returns non-zero if user picked "yes" response, and zero if "no" */ static int ErrorDialog(char *title, char *errbody, char *errmsg, char *yesmsg, char *nomsg) { int retcode; char *buf; /* I don't know if this is what msf intended, but it is a whole lot easier. */ buf = alloca(strlen(errbody)+strlen(errmsg) + 10); sprintf(buf, "%s: %s", errbody, errmsg); retcode = newtWinChoice(title, yesmsg, nomsg, buf); if (retcode == 2) return 0; else return 1; } static int HandleFdiskError( int status, char *errbody, char *y, char *n ) { char errmsg[250]; char yesmsg[]="Yes"; char nomsg[] ="No"; if (status < 0) { if (errno < sys_nerr-1) strncpy(errmsg,sys_errlist[errno],sizeof(errmsg)); else snprintf(errmsg,sizeof(errmsg), _("System error %d"), errno); } else { if (status < fdisk_nerr) strcpy(errmsg, fdisk_errlist[status]); else snprintf(errmsg,sizeof(errmsg), "libfdisk error %d",errno); } if (y != NULL && n != NULL) return ErrorDialog( _("Fdisk Error"), errbody, errmsg, y, n); else return ErrorDialog( _("Fdisk Error"), errbody,errmsg,yesmsg,nomsg); } /* give summary of why partitions weren't allocated */ static void showReasons( PartitionSpec *spec ) { newtComponent tbox, form, ok, lbox; int i; for (i=0; inum; i++) if (spec->entry[i].status == REQUEST_DENIED) break; /* nothing going on here, keep moving along */ if (i == spec->num) return; /* build list of why they all failed */ newtCenteredWindow(60, 18, _("Unallocated Partitions")); form = newtForm(NULL,NULL,0); tbox = newtTextbox(5, 1, 50, 5, NEWT_FLAG_WRAP ); newtTextboxSetText(tbox, _("There are currently unallocated partition(s) " "present in the list of requested partitions. The " "unallocated partition(s) are shown below, along with " "the reason they were not allocated.")); lbox = newtListbox(10, 6, 5, NEWT_FLAG_RETURNEXIT | NEWT_FLAG_SCROLL ); for (i=0; inum; i++) if (spec->entry[i].status == REQUEST_DENIED) { char tmpstr[80]; char *pname = spec->entry[i].name; char *s, *t; memset(tmpstr, ' ', 80); if (strncmp("Exist", pname, 5) && strncmp("Swap", pname, 4) && strncmp("Dos", pname, 3)) t = pname; else t = NULL; for (s=tmpstr;t && *t; t++,s++) *s = *t; t = GetReasonString(spec->entry[i].reason); for (s=tmpstr+20;t && *t; t++,s++) *s = *t; *s = '\0'; newtListboxAddEntry(lbox, tmpstr, NULL); } ok = newtButton(25, 13, _("Ok")); newtFormAddComponents(form, tbox, lbox, ok, NULL); newtFormSetCurrent(form, ok); newtRunForm(form); newtPopWindow(); newtFormDestroy(form); } /* read in the requested drives */ /* pass an array of names of block devices, returns 0 if ok */ static int ReadDrives( char **drives, int numdrives, HardDrive **hdarr, unsigned int *numhd, int forcezero, int readOnly) { char errbody[250]; int i, done, status; char *ptr; /* loop over all specified block devices */ *numhd = 0; for (i=0; i < numdrives; ) { status = fdiskOpenDevice(drives[i], *numhd+1, &hdarr[*numhd]); if (status != FDISK_SUCCESS) { /* HORRIBLE HACK XXX*/ #ifdef __sparc__ if (status == FDISK_ERR_CORRUPT) { /* bad Sun disklabel */ snprintf(errbody, sizeof(errbody), _("A disk with a corrupt Sun disklabel has been " "found while reading block device %s. You must " "use fdisk to create and write a new label to " "this device."), drives[i]); if (newtWinChoice(_("Corrupt Sun disklabel"), _("Back"), _("Skip Drive"), errbody) == 1) return INST_CANCEL; else { i++; continue; } } #endif snprintf(errbody, sizeof(errbody), _("An error occurred reading the partition table for the " "block device %s. The error was"), drives[i]); if (HandleFdiskError( status, errbody, "Retry", "Skip Drive" )) continue; else { i++; continue; } } else { done = 0; /* set up drive prefix */ if ((ptr = (strstr(hdarr[*numhd]->name, "tmp/")))) { strcpy(hdarr[*numhd]->prefix, ptr + 4); } /* for RAID arrays of format c0d0p1 */ if (strstr(ptr + 4, "rd/") || strstr(ptr + 4, "ida/")) strcat(hdarr[*numhd]->prefix, "p"); while (!done) { status = fdiskReadPartitions( hdarr[*numhd] ); if (status != FDISK_SUCCESS) { int rc; if (status == FDISK_ERR_BADMAGIC) { if (forcezero) { if (!testing) #ifdef sparc fdiskInitSunLabel(hdarr[*numhd]); #else fdiskZeroMBR(hdarr[*numhd]); #endif fdiskCloseDevice(hdarr[*numhd]); done = 1; } else { if (kickstart) { newtWinMessage(_("Bad Partition Table"), _("Ok"), _("The partition table on device %s is " "corrupted. To create new partitions " "it must be initialized. You can " "specify \"zerombr yes\" in the " "kickstart file to have this done " "automatically"), drives[i]+5); return INST_ERROR; } rc = newtWinChoice(_("Bad Partition Table"), _("Initialize"), _("Skip Drive"), _("The partition table on device %s is " "corrupted. To create new partitions " "it must be initialized," " causing the loss of ALL DATA on " "this drive."), drives[i]+5); if (rc != 2) { if (!testing) #ifdef sparc fdiskInitSunLabel(hdarr[*numhd]); #else fdiskZeroMBR(hdarr[*numhd]); #endif fdiskCloseDevice(hdarr[*numhd]); done = 1; } else { i++; fdiskCloseDevice(hdarr[*numhd]); done = 1; } } } else { snprintf(errbody, sizeof(errbody), _("An error occurred reading the partition table " "for the block device %s. The error was"), drives[i]+5); if (HandleFdiskError(status,errbody, _("Retry"), _("Skip Drive"))){ fdiskCloseDevice(hdarr[*numhd]); done = 1; } else { i++; fdiskCloseDevice(hdarr[*numhd]); done = 1; } } /* THIS IS A HORRIBLE NASTY HACK */ #ifdef __alpha__ } else if (hdarr[i]->limits.maxPrimary > 4 && !readOnly) { newtWinMessage(_("BSD Disklabel"), _("Ok"), _("A disk with " "a BSD disklabel has been found. The Red Hat " "installation only supports BSD Disklabels in " "read-only mode, so you must use a custom install " "and fdisk (instead of Disk Druid) for " "machines with BSD Disklabels.")); return INST_CANCEL; #endif } else { *numhd += 1; i++; done = 1; } } } } return FDISK_SUCCESS; } /* see if anything really changed */ int DisksChanged( HardDrive **oldhd, HardDrive **newhd, unsigned int numhd ) { int i, j; /* see if partition tables are identical */ for (i=0; itable[j],&newhd[i]->table[j], sizeof(Partition))) return 1; if (memcmp(&oldhd[i]->eptable[j],&newhd[i]->eptable[j], sizeof(Partition))) return 1; } return 0; } /* edit an existing partition spec */ /* callback for type listbox */ struct typebox_cbstruct { newtComponent *entry; char *val; }; static char typebox_mp[100]; static int inswapentry; static void typebox_scroll(newtComponent box, struct typebox_cbstruct *s ) { int type; type = (long) newtListboxGetCurrent(box); if (type == LINUX_SWAP_PARTITION && !inswapentry) { strncpy(typebox_mp, s->val, 100); newtEntrySet(*s->entry, _("Swap Partition"), 0); inswapentry = 1; newtEntrySetFlags(*s->entry, NEWT_FLAG_DISABLED, NEWT_FLAGS_SET); } else if (inswapentry) { newtEntrySetFlags(*s->entry, NEWT_FLAG_DISABLED, NEWT_FLAGS_RESET); if (typebox_mp[0] == -1) /* just clear string if it isnt initialized */ typebox_mp[0] = '\0'; newtEntrySet(*s->entry, typebox_mp, 1); inswapentry = 0; } } struct driveentry_struct { newtComponent cb; char state; }; struct entrybox_cbstruct { newtComponent *form; char *val; unsigned char *val2; DriveSet curds, origds; int numhd; HardDrive **hdarr; struct driveentry_struct *de; int dobootable; }; static void entrybox_cb(newtComponent box, struct entrybox_cbstruct *s) { unsigned char boot; int j; if (s->dobootable) { boot = (!strcmp(s->val, "/") || !strcmp(s->val, "/boot")) ? '*' : ' '; if (boot == '*' && *(s->val2) == ' ') memcpy(&s->origds, &s->curds, sizeof(DriveSet)); *(s->val2) = boot; if (boot == '*') { fdiskDeactivateAllDriveSet( &s->curds ); fdiskActivateDriveSet( &s->curds, 1 ); fdiskActivateDriveSet( &s->curds, 2 ); } else { memcpy(&s->curds, &s->origds, sizeof(DriveSet)); } for (j=0; jnumhd; j++) s->de[j].state=fdiskThisDriveSetIsActive(&s->curds, s->hdarr[j]->num)?'*':' '; newtDrawForm(*s->form); } } #define NEW_PARTSPEC "NewPartition" static int sizeEntryFilter(newtComponent entry, void * data, int ch, int cursor) { if ((ch < ' ' || ch >= NEWT_KEY_EXTRA_BASE) || (ch >= '0' && ch <= '9')) return ch; return 0; } static int mntptEntryFilter(newtComponent entry, void * data, int ch, int cursor) { if (ch == ' ') return 0; return ch; } static int EditPartitionSpec(HardDrive **hdarr, unsigned int numhd, PartitionSpec *spec, PartitionSpecEntry *entry) { int j, l; unsigned int hdidx, tmpuint; int tmpint; char tmpstr[80]; Partition *p; newtComponent form, mntptentry; newtComponent sizeentry, growentry, bootentry, typeentry; newtComponent sb, driveform; newtComponent ok, cancel, answer; struct typebox_cbstruct cb1; struct entrybox_cbstruct cb2; struct driveentry_struct driveentry[MAX_HARDDRIVES]; char *mntpt=NULL, *size=NULL, *eptr; char titlestr[80]; unsigned char boot, grow; int row, col; int status=0; int done; int newpartition; int cval; int numfstypes = 4; char fstypesnames[][20] = { "Linux Swap", "Linux Native", "DOS 16-bit <32M", "DOS 16-bit >=32M"}; int fstypes[] = {0x82, 0x83, 0x4, 0x6}; p = (Partition *) alloca(sizeof(Partition)); memcpy(p, &entry->partition, sizeof(Partition)); newpartition = (strcmp(entry->name, NEW_PARTSPEC) == 0); if (p->immutable) cval = -2; else cval = ((numhd > 3) ? 4 : numhd); /* make title line a little more descriptive */ if (newpartition) { strcpy(titlestr, "Edit New Partition"); } else if (p->immutable) { for (hdidx=0; hdidx < numhd && hdarr[hdidx]->num != p->drive.current; hdidx++); if (hdidx != numhd) { snprintf(titlestr, 80, "%s: /dev/%s%d", _("Edit Partition"), hdarr[hdidx]->prefix, p->num.current); if (entry->name && *entry->name && strncmp(entry->name, "Exist", 5)) snprintf(titlestr+strlen(titlestr), 80-strlen(titlestr), " (%s)", entry->name); } else { strcpy(titlestr, _("Edit Partition")); } } else { if (entry->name && *entry->name) snprintf(titlestr, 80, "%s: %s", _("Edit Partition"), entry->name); else strcpy(titlestr, _("Edit Partition")); } newtCenteredWindow(70, 13+cval, titlestr ); form = newtForm(NULL,NULL,0); /* mount point goes at top and is centered */ row = 1; col = 3; newtFormAddComponent(form, newtLabel(col, row, "Mount Point:")); if (p->type.current != LINUX_SWAP_PARTITION) { if (!newpartition && strncmp("Exist", entry->name, 5) && strncmp("Dos", entry->name, 3)) { mntptentry = newtEntry(22, row, entry->name, 30, &mntpt, NEWT_FLAG_RETURNEXIT); } else { mntptentry = newtEntry(22, row, "", 30, &mntpt, NEWT_FLAG_RETURNEXIT); } } else { mntptentry = newtEntry(22, row, "Swap Partition", 30, &mntpt, NEWT_FLAG_RETURNEXIT | NEWT_FLAG_DISABLED); } newtEntrySetFilter(mntptentry, mntptEntryFilter, NULL); /* size, grow and boot flags on left under mount point */ row = 3; newtFormAddComponent(form, newtLabel(col, row, "Size (Megs):")); if (p->immutable) { sizeentry = NULL; snprintf(tmpstr,sizeof(tmpstr),"%d", p->size.current/SECPERMEG); newtFormAddComponent(form, newtLabel(22, row, tmpstr)); } else { snprintf(tmpstr,sizeof(tmpstr),"%d", p->size.min/SECPERMEG); sizeentry = newtEntry(22, row, tmpstr, 8, &size, NEWT_FLAG_RETURNEXIT); newtEntrySetFilter(sizeentry, sizeEntryFilter, NULL); } row++; if (!newpartition) { grow = p->size.min != p->size.max; } else { grow = 0; } grow = (grow) ? '*' : ' '; newtFormAddComponent(form, newtLabel(col, row, "Grow to fill disk?:")); if (p->immutable) { growentry = NULL; newtFormAddComponent(form, newtLabel(22, row, "[ ]")); } else { growentry = newtCheckbox(22, row, "", grow, NULL, &grow); } row++; /* give status */ if (!newpartition) { newtFormAddComponent(form, newtLabel(col, row, _("Allocation Status:"))); if (entry->status != REQUEST_DENIED) newtFormAddComponent(form, newtLabel(22, row, _("Successful"))); else newtFormAddComponent(form, newtLabel(22, row, _("Failed"))); row++; if (entry->status == REQUEST_DENIED) { newtFormAddComponent(form, newtLabel(col, row, _("Failure Reason:"))); newtFormAddComponent(form, newtLabel(22,row,GetReasonString(entry->reason))); } row++; } /* blow this bootable stuff for now, its confusing */ bootentry = NULL; /* type goes on right side under the mount point */ row = 3; newtFormAddComponent(form, newtLabel(43, row, "Type:")); if (p->immutable) { typeentry = NULL; l = p->type.current | NONSUNPARTTYPE; for (hdidx = 0; hdidx < numhd; hdidx++) if (hdarr[hdidx]->num == p->drive.current && hdarr[hdidx]->part_type == FDISK_PART_TYPE_SUN) l = p->type.current | SUNPARTTYPE; for (j=0; jtype.current) break; } if (j != nparttypes) snprintf(tmpstr, sizeof(tmpstr), "%s", allparttypes[j].name); else snprintf(tmpstr,sizeof(tmpstr),"%6s (0x%x)", "Unknown", p->type.current); newtFormAddComponent(form, newtLabel(48, row, tmpstr)); row++; } else { typeentry = newtListbox( 48, row, 4, NEWT_FLAG_RETURNEXIT | NEWT_FLAG_SCROLL); for (j=0; jtype.current) newtListboxSetCurrent(typeentry, j); else if (p->type.current == 0 && fstypes[j] == LINUX_NATIVE_PARTITION) newtListboxSetCurrent(typeentry, j); } } /* have to fix this later */ /* allowable drives goes in center under rest */ row = 8; driveform = NULL; if (!p->immutable) { newtFormAddComponent(form, newtLabel(col, row, "Allowable Drives:")); sb = newtVerticalScrollbar(40, row, 4, 9, 10); driveform = newtForm(sb, NULL, 0); newtFormSetBackground(driveform, NEWT_COLORSET_CHECKBOX); for (j=0; jdrive, hdarr[j]->num); driveentry[j].cb = newtCheckbox(22, row+j, hdarr[j]->name+5, (driveentry[j].state) ? '*' : ' ', NULL, &driveentry[j].state); newtFormAddComponent(driveform, driveentry[j].cb); } if (j > 4) { newtFormSetHeight(driveform, 4); newtFormAddComponent(driveform, sb); } else { newtFormSetWidth(driveform, 10); } } /* setup type box callback */ if (typeentry) { cb1.entry = &mntptentry; cb1.val = mntpt; /* yuck but it works */ typebox_mp[0] = -1; inswapentry = (p->type.current == LINUX_SWAP_PARTITION); newtComponentAddCallback(typeentry,(newtCallback) typebox_scroll,&cb1); } /* setup mount point callback */ if (!p->immutable) { cb2.form = &form; cb2.val = mntpt; cb2.val2 = &boot; memset(&cb2.curds, 0, sizeof(DriveSet)); memcpy(&cb2.origds, &p->drive, sizeof(DriveSet)); cb2.numhd = numhd; cb2.hdarr = hdarr; cb2.de = driveentry; cb2.dobootable = (fdiskIndexPartitionSpec(spec, "/boot", &j) != FDISK_SUCCESS); newtComponentAddCallback(mntptentry,(newtCallback) entrybox_cb,&cb2); } row = 9+cval; ok = newtButton( 20, row, _("Ok")); cancel = newtButton( 40, row, _("Cancel")); if (mntptentry) newtFormAddComponents( form, mntptentry, NULL ); if (sizeentry) newtFormAddComponents( form, sizeentry, NULL); if (growentry) newtFormAddComponents( form, growentry, NULL); if (typeentry) newtFormAddComponents( form, typeentry, NULL ); if (driveform) newtFormAddComponents( form, driveform, NULL ); newtFormAddComponents( form, ok, cancel, NULL); done = 0; while (!done) { answer = newtRunForm(form); if (answer != cancel) { /* modify partition request based on the entry boxes */ if (typeentry) { tmpuint = (long) newtListboxGetCurrent( typeentry ); fdiskSetConstraint(&p->type, tmpuint, tmpuint, tmpuint, 1); } /* make sure mount point is valid */ if (p->type.current != LINUX_SWAP_PARTITION) { int valid=1; int skiprest=0; TrimWhitespace(mntpt); /* see if they even gave the partition a name */ /* we will ask them if they really want to not */ /* assign the partition a name at this time if */ /* they have just created a non-ext2 partition */ if (!*mntpt && p->type.current != LINUX_NATIVE_PARTITION) { if (newtWinChoice(_("No Mount Point"), _("Yes"), _("No"), _("You have not selected a mount point " "for this partition. Are you sure you " "want to do this?")) == 2) continue; else { /* we need a name for this partition */ /* we'll name them like swap partitions */ /* except use 'DOSxxx' */ if (strncmp("Dos", entry->name, 4)) { char *t; fdiskMakeUniqSpecName( spec, "Dos", &t ); fdiskRenamePartitionSpec(spec, entry->name, t); } skiprest = 1; } } /* do old test first */ if (!skiprest) { if (entry->status != REQUEST_ORIGINAL || *mntpt) if (badMountPoint(p->type.current, mntpt)) continue; if (entry->status == REQUEST_ORIGINAL) { /* this is an original partition, should have a */ /* mount point of "" or a valid path */ if (*mntpt && (*mntpt != '/' || ((strcmp(entry->name, mntpt) && !fdiskIndexPartitionSpec(spec, mntpt, &tmpuint))))) { valid = 0; } } else if (*mntpt != '/' || (strcmp(entry->name, mntpt) && !fdiskIndexPartitionSpec(spec, mntpt, &tmpuint))) { valid = 0; } } if (!valid) { newtWinMessage(_("Mount Point Error"), _("Ok"), _("The mount point requested is either an illegal " "path or is already in use. Please select a " "valid mount point.")); continue; } } if (sizeentry) { tmpint=strtol(size, &eptr, 10); if (eptr != size && *eptr == 0 && tmpint > 0) { tmpint *= SECPERMEG; if (growentry && grow != ' ') fdiskSetConstraint(&p->size,0,tmpint,FDISK_SIZE_MAX,1); else fdiskSetConstraint(&p->size,0,tmpint,tmpint,1); } else { newtWinMessage(_("Size Error"), _("Ok"), _("The size requested is illegal. Make sure the " "size is greater than zero (0), and is specified " "int decimal (base 10) format.")); continue; } } /* The size limit is now 2 gb in kernels > 2.1.117 */ /* For 2.2.1+ kernels the size differs among */ /* different architectures. */ /* make sure swap partitions are not too large */ /* (PAGESIZE - 10)*8*PAGESIZE */ /* on the right arch's */ if (p->type.current == LINUX_SWAP_PARTITION) { #if defined(__alpha__) const unsigned long long maxswap = 128ULL*1024*1024*1024; #elif defined(__sparc__) unsigned long long maxswap = 1073741824ULL; struct utsname my_utsname; if (uname(&my_utsname) == 0) { if (!strcmp(my_utsname.machine, "sparc64")) maxswap = 3072ULL*1024*1024*1024; } #else const unsigned long long maxswap = 2147483640; #endif #if 0 /* 2.0 kernels */ #if defined(__alpha__) maxswap = (8192-10)*8*8192; #else maxswap = (4096-10)*8*4096; #endif #endif if (p->size.min > maxswap/SECTORSIZE) { newtWinMessage(_("Swap Size Error"), _("Ok"), _("You have created a swap partition which is too " "large. The maximum size of a swap partition is " "%ld Megabytes."), (long)(maxswap / 1024 / 1024)); continue; } } if (driveform) { fdiskDeactivateAllDriveSet( &p->drive ); for (j=0; jdrive, hdarr[j]->num ); } /* fdiskHandleSpecialPartitions() will do this for us */ /* so I'm taking the boot entry out for now */ if (p->type.current == LINUX_SWAP_PARTITION) { /* make sure we have a valid swap partition name */ if (strncmp("Swap", entry->name, 4)) { char *t; fdiskMakeSwapSpecName( spec, &t ); fdiskRenamePartitionSpec(spec, entry->name, t); free(t); } } /* first see if they changed the mount point */ /* we only worry about ext2 and dos partitions */ /* which have a valid mntpt */ /* LOGIC is not the word for how all this works */ if (p->type.current != LINUX_SWAP_PARTITION && strncmp("Dos", mntpt, 3)) { TrimWhitespace(mntpt); if (p->immutable) status = REQUEST_ORIGINAL; else status = REQUEST_PENDING; if (strcmp(mntpt, entry->name)) { /* if this is an original partition which we just set */ /* the name back to '' from a real name, set name back */ /* to the 'Existxxxxx' name */ if (entry->status == REQUEST_ORIGINAL && !*mntpt) { for (hdidx=0; hdidx < numhd; hdidx++) if (hdarr[hdidx]->num == p->drive.current) break; if (hdidx != numhd) sprintf(tmpstr, "Exist%03d%03d", hdarr[hdidx]->num, p->num.current); else strcpy(tmpstr,"Exist999999"); fdiskRenamePartitionSpec( spec, entry->name, tmpstr ); fdiskModifyPartitionSpec( spec, tmpstr, p, status); } else { fdiskRenamePartitionSpec( spec, entry->name, mntpt ); /* this is a big kludge! */ /* reset bootable partition handling so if we */ /* rename '/' to '/usr', we don't enforce rules */ fdiskSetConstraint(&p->endcyl, 0,FDISK_ENDCYL_MIN,FDISK_ENDCYL_MAX,0); fdiskModifyPartitionSpec( spec, mntpt, p, status); } } else { fdiskModifyPartitionSpec( spec, mntpt, p, status); } } else { fdiskModifyPartitionSpec( spec, entry->name, p, status); } fdiskHandleSpecialPartitions( spec ); status = FDISK_SUCCESS; done = 1; } else { status = FDISK_ERR_USERABORT; done = 1; } } newtPopWindow(); newtFormDestroy(form); return status; } /* add a partition spec */ static int AddPartitionSpec(HardDrive **hdarr, unsigned int numhd, PartitionSpec *spec) { Partition template; int status; unsigned int i; /* create a template partitionspec to send to editpartition */ memset(&template, 0, sizeof(Partition)); template.size.min = SECPERMEG; /* insert with a name we know to mean its a new partition */ fdiskInsertPartitionSpec(spec, NEW_PARTSPEC, &template, REQUEST_PENDING); fdiskIndexPartitionSpec( spec, NEW_PARTSPEC, &i ); status = EditPartitionSpec(hdarr, numhd, spec, &spec->entry[i]); if (status == FDISK_SUCCESS) { return FDISK_SUCCESS; } else { fdiskDeletePartitionSpec(spec, NEW_PARTSPEC); return FDISK_ERR_USERABORT; } } /* delete a partition spec */ static int DeletePartitionSpec( HardDrive **hdarr, unsigned int numhd, PartitionSpec *spec, PartitionSpecEntry *entry, int force) { Partition *p; int status; unsigned int c, l, m, n, t; char *tmpstr; p = &entry->partition; tmpstr=strdup(entry->name); if (!force && newtWinChoice(_("Delete Partition"), _("Yes"), _("No"), _("Are you sure you want to delete " "this partition?")) == 2) return FDISK_ERR_USERABORT; if (p->immutable) { fdiskGetCurrentConstraint(&p->num, &c); fdiskGetCurrentConstraint(&p->type, &t); fdiskGetCurrentDriveSet(&p->drive, &l); for (m=0; mnum == l) break; fdiskRemovePartition(hdarr[m], c); /* make it so we can delete this partition now */ p->immutable = 0; fdiskModifyPartitionSpec( spec, tmpstr, p, REQUEST_PENDING ); /* ok, see if this was the last immutable logical partition */ /* in an immutable primary extended partition */ /* we pray that fdiskCleanOriginal... will get rid of the */ /* spec entry for the pep */ if (c > 4) { if (fdiskLastLogical( hdarr[m], &n ) != FDISK_SUCCESS) { /* all logicals are gone, blow away pep */ if (hdarr[m]->pep && hdarr[m]->table[hdarr[m]->pep].immutable){ fdiskRemovePartition(hdarr[m], hdarr[m]->pep); } } } } status = fdiskDeletePartitionSpec( spec, tmpstr ); fdiskHandleSpecialPartitions( spec ); free(tmpstr); return FDISK_SUCCESS; } /* edit/add an NFS partition -> set index to -1 if adding new */ int EditNFSMount( struct fstab *remotefs, int index, struct intfInfo *intf, struct netInfo *netc, struct driversLoaded **dl ) { int rc; struct fstabEntry entry; if (!(intf->set & INTFINFO_HAS_BOOTPROTO)) { rc = bringUpNetworking(intf, netc, dl, 1); } else { rc = 0; } if (rc) return 1; if (loadFilesystem("nfs", "nfs", dl)) return INST_ERROR; if (index == -1) { initFstabEntry(&entry); entry.type = PART_NFS; entry.tagName = "NFS Mount"; entry.device = NULL; entry.mntpoint = NULL; rc = editNetMountPoint(&entry); if (!rc) addFstabEntry(remotefs, entry); } else { rc = editNetMountPoint(&remotefs->entries[index]); } return rc; } /* remote fstab entry */ int DeleteNFSMount(struct fstab *remotefs, int index) { int i; if (remotefs->numEntries < 1) return 0; for (i=index; inumEntries-1; i++) remotefs->entries[i] = remotefs->entries[i+1]; remotefs->numEntries -= 1; return 0; } /* used for each line in partbox - tells us what is on that line */ enum partbox_types {PARTBOX_COMMENT, PARTBOX_NFS, PARTBOX_PART}; struct partbox_entry { enum partbox_types type; /* what is on this line */ int index; /* index in nfs or partition arrays */ int hilite; /* element in drive window to hilight */ }; /* simple callback for scrollbox skipping non-entries */ struct partbox_struct { unsigned int len; /* total entries allocated */ unsigned int num; /* number in use */ newtComponent *dbox; /* drive box */ struct partbox_entry *entry; /* describes use of this line */ }; /* this is some ugly sh*t, don't try this at home kids */ static void partbox_scroll(newtComponent list, struct partbox_struct *status) { static int last=-1; static int dontforce=0; int sel; int i; int odir, dir; int done; int lasttry; /* get the index into the partbox_struct array */ sel = (long) newtListboxGetCurrent(list); /* see if this callback occurred because we were forcing */ /* listbox to scroll */ if (dontforce) { dontforce = 0; return; } /* if the element is ok then just return */ if (status->entry[sel].type != PARTBOX_COMMENT) { if (status->entry[sel].type == PARTBOX_PART && status->entry[sel].hilite >= 0 && status->dbox != NULL) newtListboxSetCurrent(*status->dbox, status->entry[sel].hilite); return; } /* see which direction we're heading , >0 means down, < 0 means up */ if (last == -1) dir = 1; else { if (sel > last) dir = 1; else dir = -1; } odir = dir; done = 0; lasttry = 0; while (!done) { if (dir > 0) { for (i=sel; i < status->num; i++) if (status->entry[i].type != PARTBOX_COMMENT) break; if (i!=status->num) { dontforce = 1; newtListboxSetCurrent(list, i); last = i; done = 1; if (lasttry) { /* scroll to top, since this is last try so original */ /* direction was going up */ dontforce = 1; newtListboxSetCurrent(list, 0); dontforce = 1; newtListboxSetCurrent(list,last); } } else { if (!lasttry) { dir = -1; lasttry = 1; } else { done = 1; } } } else { for (i=sel; i >= 0; i--) if (status->entry[i].type != PARTBOX_COMMENT) break; if (i >= 0) { dontforce = 1; newtListboxSetCurrent(list, i); last = i; done = 1; if (lasttry) { /* scroll to bottom, since this is last try so original */ /* direction was going up */ dontforce = 1; newtListboxSetCurrent(list, status->num-1); dontforce = 1; newtListboxSetCurrent(list,last); } } else { if (!lasttry) { dir = 1; lasttry = 1; } else { done = 1; } } } } /* if we found a valid line then move drive box selection too */ sel = (long) newtListboxGetCurrent(list); if (status->entry[sel].type == PARTBOX_PART && status->entry[sel].hilite >= 0 && status->dbox != NULL) newtListboxSetCurrent(*status->dbox, status->entry[sel].hilite); } static int MakeDriveBox( HardDrive **hdarr, unsigned int numhd, unsigned int *drvused, int dheight, newtComponent *dbox ) { int hdidx, i, per; char tmpstr[80]; *dbox = newtListbox( -1, -1, dheight, NEWT_FLAG_SCROLL ); newtComponentTakesFocus( *dbox, 0 ); for (hdidx=0; hdidx < numhd; hdidx++) { snprintf(tmpstr,sizeof(tmpstr), " %-8s [%5d/%3d/%2d] " "%6dM %6dM %6dM" " ", hdarr[hdidx]->name+5, hdarr[hdidx]->geom.cylinders, hdarr[hdidx]->geom.heads, hdarr[hdidx]->geom.sectors, hdarr[hdidx]->totalsectors/SECPERMEG, drvused[hdidx]/SECPERMEG, hdarr[hdidx]->totalsectors/SECPERMEG-drvused[hdidx]/SECPERMEG ); tmpstr[58]='['; tmpstr[69]=']'; per = (100 * (drvused[hdidx]/SECPERMEG)/(hdarr[hdidx]->totalsectors / SECPERMEG)); if (per >= 99) per = 10; else per = per/10; for (i=0; i < per; i++) tmpstr[59+i] = '#'; tmpstr[74]=0; newtListboxAddEntry(*dbox, tmpstr, (void *) 0); } return FDISK_SUCCESS; } /* given partitoins/hard drives, returns a listbox for use */ /* includes the callback function to skip over headings */ static int MakePartBox( HardDrive **hdarr, unsigned int numhd, PartitionSpec *spec, struct fstab *remotefs, int x, int y, int pheight, int dheight, newtComponent *list, struct partbox_struct *status, newtComponent *dbox) { newtComponent partbox; unsigned int drivenum; unsigned int totalused; int col; int i, k, l, hdidx; unsigned int listlen; unsigned int foundpart; char tmpstr[80]; int num; unsigned int *drvused=alloca(numhd*sizeof(unsigned int)); memset(drvused, 0, numhd*sizeof(unsigned int)); /* check if there are *any* partitions to display */ for (i = 0, num = 0; i < spec->num; i++) { if (fdiskIsExtended(spec->entry[i].partition.type.current)) continue; num++; } num += remotefs->numEntries; if (!num) { *list = NULL; MakeDriveBox( hdarr, numhd, drvused, dheight, dbox ); return FDISK_ERR_BADNUM; } partbox = newtListbox(-1, -1, pheight, NEWT_FLAG_RETURNEXIT | NEWT_FLAG_SCROLL); listlen = 0; status->entry=(struct partbox_entry *)malloc(100* sizeof(struct partbox_entry)); status->len = 100; memset(status->entry, 0, status->len*sizeof(struct partbox_entry)); status->dbox = NULL; for (hdidx=0; hdidx < numhd; hdidx++) { drivenum = hdarr[hdidx]->num; /* display all spec'd partitions for this drive */ foundpart = 0; totalused = 0; for (i=0; inum; i++) { unsigned int num, minsize, actsize, drive, totsize; char statstr[80]; char *pname, *devname; Partition *p; if (spec->entry[i].status == REQUEST_DENIED) continue; p = &spec->entry[i].partition; if ((drive = p->drive.current) != drivenum) continue; if (fdiskIsExtended(p->type.current)) continue; num = p->num.current; actsize = p->size.current; minsize = p->size.min; pname = spec->entry[i].name; devname = hdarr[hdidx]->prefix; totsize = hdarr[hdidx]->totalsectors; if (!foundpart) foundpart = 1; /* increment amount of space used */ totalused += actsize; /* mount point */ col = 3; memset(statstr, ' ', sizeof(statstr)); if (strncmp("Exist", pname, 5) && strncmp("Swap", pname, 4) && strncmp("Dos", pname, 3)) BuildTableField( statstr, pname, col, 16, 0 ); /* Block device */ snprintf(tmpstr, sizeof(tmpstr), "%s%d", devname, num ); col += 22; BuildTableField( statstr, tmpstr, col, 10, 0 ); /* Size */ snprintf(tmpstr, sizeof(tmpstr), "%5dM", minsize/SECPERMEG); col += 10; BuildTableField( statstr, tmpstr, col, 9, 1 ); snprintf(tmpstr, sizeof(tmpstr), "%5dM", actsize/SECPERMEG); col += 10; BuildTableField( statstr, tmpstr, col, 9, 1 ); /* we dont want to see all that stuff, just English label */ /* for the type */ /* Type */ col += 13; if (hdarr[hdidx]->part_type == FDISK_PART_TYPE_SUN) l = p->type.current | SUNPARTTYPE; else l = p->type.current | NONSUNPARTTYPE; for (k=0; ktype.current || allparttypes[k].index == l) break; if (k != nparttypes) snprintf(tmpstr, sizeof(tmpstr), "%s", allparttypes[k].name); else snprintf(tmpstr, sizeof(tmpstr), "0x%02x", p->type.current); BuildTableField( statstr, tmpstr, col, 18, 0); /* now stick it in listbox */ statstr[73]=0; status->entry[listlen].type = PARTBOX_PART; status->entry[listlen].index = i; status->entry[listlen].hilite = hdidx; newtListboxAddEntry(partbox, statstr,(void *) (long) listlen); listlen++; } drvused[hdidx] = totalused; } for (i=0; inumEntries; i++) { char statstr[80]; /* mount point */ col = 2; memset(statstr, ' ', sizeof(statstr)); BuildTableField( statstr, remotefs->entries[i].mntpoint, col, 16, 0 ); /* Block device */ col += 17; snprintf(tmpstr, sizeof(tmpstr), "%s:%s", remotefs->entries[i].netHost, remotefs->entries[i].netPath); BuildTableField( statstr, tmpstr, col, 40, 0 ); /* Size */ /* snprintf(tmpstr, sizeof(tmpstr), "%5dM/NA ", minsize/SECPERMEG);*/ *tmpstr=0; col += 12; BuildTableField( statstr, "", col, 15, 0 ); /* Type */ col += 27; BuildTableField( statstr, "NFS", col, 18, 0); /* now stick it in listbox */ statstr[70]=0; status->entry[listlen].type = PARTBOX_NFS; status->entry[listlen].index = i; newtListboxAddEntry(partbox, statstr,(void *) (long) (listlen)); listlen++; } /* now display any partition specs which WERE NOT allocated */ foundpart = 0; for (i=0; inum && !foundpart; i++) if (spec->entry[i].status == REQUEST_DENIED) foundpart = 1; if (foundpart) { status->entry[listlen].type = PARTBOX_COMMENT; newtListboxAddEntry(partbox,"", (void *)(long)listlen); listlen++; status->entry[listlen].type = PARTBOX_COMMENT; newtListboxAddEntry(partbox,"Unallocated requested partitions", (void *)(long)listlen); listlen++; status->entry[listlen].type = PARTBOX_COMMENT; newtListboxAddEntry(partbox,"--------------------------------", (void *)(long)listlen); listlen++; for (i=0; inum; i++) { if (spec->entry[i].status == REQUEST_DENIED) { unsigned int num, minsize, actsize; char statstr[80]; char *pname; Partition *p; foundpart = 1; p = &spec->entry[i].partition; if (fdiskIsExtended(p->type.current)) continue; num = p->num.current; minsize = p->size.min; actsize = p->size.current; pname = spec->entry[i].name; /* mount point */ col = 3; memset(statstr, ' ', sizeof(statstr)); if (strncmp("Exist", pname, 5) && strncmp("Swap", pname, 4) && strncmp("Dos", pname, 3)) BuildTableField( statstr, pname, col, 16, 0 ); /* Reasons */ col += 17; BuildTableField( statstr, GetReasonString(spec->entry[i].reason), col, 25, 0 ); /* Size */ snprintf(tmpstr, sizeof(tmpstr), "%5dM/NA ", minsize/SECPERMEG); col += 23; BuildTableField( statstr, tmpstr, col, 15, 0 ); /* we dont want to see all that stuff, just English label */ /* for the type */ /* Type */ col += 15; l = p->type.current | NONSUNPARTTYPE; for (hdidx = 0; hdidx < numhd; hdidx++) if (hdarr[hdidx]->num == p->drive.current && hdarr[hdidx]->part_type == FDISK_PART_TYPE_SUN) l = p->type.current | SUNPARTTYPE; for (k=0; ktype.current || allparttypes[k].index == l) break; if (k != nparttypes) snprintf(tmpstr, sizeof(tmpstr),"%s",allparttypes[k].name); else snprintf(tmpstr, sizeof(tmpstr),"0x%02x", p->type.current); BuildTableField( statstr, tmpstr, col, 18, 0); /* now stick it in listbox */ statstr[70]=0; status->entry[listlen].type = PARTBOX_PART; status->entry[listlen].index = i; status->entry[listlen].hilite = -1; newtListboxAddEntry(partbox, statstr,(void *)(long)(listlen)); listlen++; } } } /* mark the VERY end of listbox */ status->num = listlen; /* setup the callback for the listbox */ newtComponentAddCallback(partbox, (newtCallback) partbox_scroll, status); for (i=0; inum-1;i++) if (status->entry[i].type != PARTBOX_COMMENT) break; if (i!=status->num) newtListboxSetCurrent(partbox,i); *list = partbox; /* now make the drive box IF desired */ MakeDriveBox( hdarr, numhd, drvused, dheight, dbox ); if (partbox) status->dbox = dbox; return 0; } /* do a operation on a partition */ static int DoMenuFunction( char *function, HardDrive **orighd, unsigned int numhd, HardDrive **curhd, newtComponent partbox, struct partbox_struct *partbox_status, PartitionSpec *spec ) { unsigned int sel; int num=0; int status; int i; HardDrive *tmphdarr[MAX_HARDDRIVES]; if (partbox) { sel = (long) newtListboxGetCurrent(partbox); if (partbox_status->entry[sel].type != PARTBOX_COMMENT) num = partbox_status->entry[sel].index; else num = -1; } else { num = -1; } for (i=0; i= 0 && !strcmp("EDIT", function)) { status = EditPartitionSpec(tmphdarr, numhd, spec, &spec->entry[num]); } else if (num >= 0 && !strcmp("DEL", function)) { status = DeletePartitionSpec(orighd, numhd, spec, &spec->entry[num],0); } else { status = FDISK_ERR_BADNUM; } if (status == FDISK_SUCCESS) { fdiskAutoInsertPartitions(orighd, numhd, tmphdarr, spec ); showReasons( spec ); fdiskGrowPartitions(orighd, numhd, tmphdarr, spec); /* if any original partitions were REMOVED we have to */ /* sync up their entries in the partition spec table */ /* with their actual representation in 'orighd'. */ /* Mainly fixes up logical partition #'s which change */ /* when other logical partitions are removed */ if (!strcmp("DEL", function)) fdiskCleanOriginalSpecs( orighd, numhd, spec ); for (i=0; inum == 0 && !dontPartition) curwidget = ADD; /* set current widget if necessary */ if (partbox != NULL && curwidget == PARTBOX) newtFormSetCurrent(form, partbox); else if (curwidget == ADD) newtFormSetCurrent(form, add); else if (curwidget == EDIT) newtFormSetCurrent(form, edit); else if (curwidget == DELETE) newtFormSetCurrent(form, del); /* setup main screen */ formdone = 0; answer = NULL; while (!formdone) { newtFormRun(form, &event); /* store the current widget so we can reset it */ /* if we have to destroy and recreate form */ /* GetCurrent(), SetCurrent() use a ptr to */ /* newtcomponent, so when we recreate form it */ /* will be meaningless! */ curcomponent = newtFormGetCurrent( form ); curwidget = NONE; if (partbox != NULL && curcomponent == partbox) curwidget = PARTBOX; else if (curcomponent == add) curwidget = ADD; else if (curcomponent == addnfs) curwidget = ADDNFS; else if (curcomponent == edit) curwidget = EDIT; else if (curcomponent == del) curwidget = DELETE; else if (curcomponent == reset) curwidget = RESET; else curwidget = NONE; if (event.reason == NEWT_EXIT_HOTKEY) { event.reason = NEWT_EXIT_COMPONENT; if (event.u.key == NEWT_KEY_F12) event.u.co = ok; else if (event.u.key == NEWT_KEY_F1) event.u.co = add; else if (event.u.key == NEWT_KEY_F2) event.u.co = addnfs; else if (event.u.key == NEWT_KEY_F3) event.u.co = edit; else if (event.u.key == NEWT_KEY_F4) event.u.co = del; else if (event.u.key == NEWT_KEY_F5) event.u.co = reset; else continue; } if (event.reason == NEWT_EXIT_COMPONENT) { if (event.u.co != partbox) { if (event.u.co == ok || event.u.co == cancel) { if (event.u.co == ok) { *writeChanges = 1; /* make sure '/' is defined */ status = fdiskIndexPartitionSpec(spec, "/", &i); if (!status) if (spec->entry[i].partition.type.current != LINUX_NATIVE_PARTITION || spec->entry[i].status == REQUEST_DENIED) status = 1; if (status) { newtWinMessage(_("No Root Partition"), _("Ok"), _("You must assign a root (/) " "partition " "to a Linux native partition (ext2) " "for the install to proceed.")); continue; } /* make sure some swapspace is defined */ status = 1; for (i=0; i < spec->num; i++) if (spec->entry[i].partition.type.current == LINUX_SWAP_PARTITION && spec->entry[i].status != REQUEST_DENIED) { status = 0; break; } if (status && !expert) { newtWinMessage(_("No Swap Partition"), _("Ok"), _("You must assign a swap " "partition " "for the install to proceed.")); continue; } } /* Check to see if there is an active partition */ status = 0; for (i=0; inum; i++) if (spec->entry[i].partition.active.current) status = 1; if (!status) { status = fdiskIndexPartitionSpec(spec,"/boot", &i); if (status) status = fdiskIndexPartitionSpec(spec,"/", &i); fdiskSetFixedConstraint(&spec->entry[i].partition.active, 1); } /* make sure there are no unallocated partitions */ status = 0; for (i=0; i < spec->num; i++) if (spec->entry[i].status == REQUEST_DENIED) { status = 1; break; } if (status) { if (newtWinChoice(_("Unallocated Partitions"), _("Yes"), _("No"), _("There are unallocated partitions " "left. If you quit now they will " "not be written to the disk.\n\n" "Are you sure you want to exit?")) == 2) continue; } /* dont trust the changes made I keep up with */ /* above, compute it straight from the hd's */ changesmade = DisksChanged( prestinehdarr, newhdarr, numhd ); /* the dontPartition here isn't necessary, but it does make a reassuring sanity check */ if (changesmade && !dontPartition) { int rc; rc = newtWinTernary(_("Save Changes"), _("Yes"), _("No"), _("Cancel"), _("Save changes to " "partition table(s)?")); if (rc == 1) { retcode = FDISK_SUCCESS; *writeChanges = 1; /* copy changes */ if (changesmade) { for (i=0; ientries = malloc(sizeof(*fstab->entries) * spec->num); fstab->numEntries = 0; for (i = 0; i < spec->num; i++) { if (!spec->entry[i].name) continue; if (spec->entry[i].status != REQUEST_ORIGINAL && spec->entry[i].status != REQUEST_GRANTED) continue; /* FIXME: hack, hack, hack */ if (*spec->entry[i].name != '/' && *spec->entry[i].name != 'S') continue; for (j=0; jnum == spec->entry[i].partition.drive.current) break; if (j == numhd) continue; initFstabEntry(&entry); entry.mntpoint = strdup(spec->entry[i].name); entry.size = spec->entry[i].partition.size.current / 2; entry.device = malloc(6); sprintf(entry.device, "%s%d", hdarr[j]->prefix, spec->entry[i].partition.num.current); switch (spec->entry[i].partition.type.current) { case LINUX_NATIVE_PARTITION: entry.type = PART_EXT2; entry.tagName = "Linux native"; break; case LINUX_SWAP_PARTITION: entry.type = PART_SWAP; entry.tagName = "Linux swap"; break; case DOS_PRIMARY_lt32MEG_PARTITION: case DOS_PRIMARY_gt32MEG_PARTITION: entry.type = PART_DOS; entry.tagName = "DOS 16-bit >=32"; break; default: entry.type = PART_OTHER; entry.tagName = "Other"; break; } addFstabEntry(fstab, entry); } fstabSort(fstab); return 0; } /* merges mount point info from existing struct fstab into a PartionSpec */ /* PartitionSpec should already exist and be primed with existing partitions */ /* Note - remote fs ARE NOT stored in the PartitionSpec */ static int MergeFstabEntries( HardDrive **hdarr, int numhd, PartitionSpec *spec, struct fstab *fstab ) { int i, j, k; char device[15]; for (j = 0; j < spec->num; j++) { for (k=0; knum == spec->entry[j].partition.drive.current) break; if (k == numhd) continue; sprintf(device, "%s%d", hdarr[k]->prefix, spec->entry[j].partition.num.current); for (i = 0; i < fstab->numEntries; i++) if (!strcmp(fstab->entries[i].device, device)) break; if ( i == fstab->numEntries ) continue; /* we found a matching entry in the PartitionSpec */ /* see if the old fstab file had any info we need */ /* to use (like mount point, etc) */ if (spec->entry[j].name) free(spec->entry[j].name); spec->entry[j].name = strdup(fstab->entries[i].mntpoint); } return 0; } /* suck out just the remote fs entries from an fstab */ /* pretty much CopyFstab, with filter on type */ struct fstab copyRemoteFSFstab(struct fstab * fstab) { struct fstab newfstab; int i, j; if (!fstab->numEntries) { newfstab.numEntries = 0; newfstab.entries = malloc(1); return newfstab; } /* duplicate the current fstab */ newfstab.numEntries = fstab->numEntries; newfstab.entries = malloc(fstab->numEntries * sizeof(struct fstabEntry)); for (i = j = 0; i < newfstab.numEntries; i++) { if (fstab->entries[i].type != PART_NFS) continue; if (fstab->entries[i].mntpoint) { newfstab.entries[j] = fstab->entries[i]; newfstab.entries[j].mntpoint=nstrdup(fstab->entries[i].mntpoint); newfstab.entries[j].device = nstrdup(fstab->entries[i].device); newfstab.entries[j].netPath = nstrdup(fstab->entries[i].netPath); newfstab.entries[j].netHost = nstrdup(fstab->entries[i].netHost); j++; } } newfstab.numEntries = j; /* return the memory we don't actually need */ newfstab.entries=realloc(newfstab.entries, j * sizeof(struct fstabEntry)); return newfstab; } /* suck out just the remote fs entries from an fstab */ /* pretty much CopyFstab, with filter on type */ void MergeRemoteFSFstab(struct fstab *oldfstab, struct fstab *newfstab) { int i, j; /* copy remote fs entries */ for (i = 0; i < oldfstab->numEntries; i++) { if (oldfstab->entries[i].type != PART_NFS) continue; if (oldfstab->entries[i].mntpoint) { j = newfstab->numEntries; newfstab->entries = realloc(newfstab->entries, (j+1)*sizeof(struct fstabEntry)); newfstab->entries[j] = oldfstab->entries[i]; newfstab->entries[j].mntpoint=nstrdup(oldfstab->entries[i].mntpoint); newfstab->entries[j].device=nstrdup(oldfstab->entries[i].device); newfstab->entries[j].netPath=nstrdup(oldfstab->entries[i].netPath); newfstab->entries[j].netHost=nstrdup(oldfstab->entries[i].netHost); newfstab->numEntries = j+1; } } } static int deletePartitionClass(HardDrive ** hd, int numhd, PartitionSpec * spec, int justLinux) { int deleteit; int type; int i; i = 0; while (i < spec->num) { type = spec->entry[i].partition.type.current; deleteit = !justLinux; if (justLinux && (type == LINUX_SWAP_PARTITION || type == LINUX_NATIVE_PARTITION)) deleteit = 1; if (deleteit) { DeletePartitionSpec(hd, numhd, spec, &spec->entry[i], 1); fdiskCleanOriginalSpecs( hd, numhd, spec ); i=0; /* restart cause entries changed */ continue; } else { i++; } } return 0; } int kickstartPartitioning(struct partitionTable * parts, struct fstab * fstab, char **drives) { HardDrive *hd[MAX_HARDDRIVES]; HardDrive *tmphd[MAX_HARDDRIVES]; /* ORIGINAL HD partition data */ unsigned int numhd; /* total # of drives to consider */ Partition template; PartitionSpec spec; unsigned int i; struct fstab remotefstab; char ** deviceList; int rc; int numDrives; int size, maxsize, grow, clearall, clearlinux, zerombr; int argc; char *mntpt; char *eptr; char *sizestr, *maxsizestr; char **argv; poptContext optCon; struct poptOption ksPartOptions[] = { { "size", '\0', POPT_ARG_STRING, &sizestr, 0 }, { "maxsize", '\0', POPT_ARG_STRING, &maxsize, 0 }, { "grow", '\0', POPT_ARG_NONE, &grow, 0 }, { 0, 0, 0, 0, 0 } }; struct poptOption ksClearOptions[] = { { "linux", '\0', POPT_ARG_NONE, &clearlinux, 0}, { "all", '\0', POPT_ARG_NONE, &clearall, 0}, { 0, 0, 0, 0, 0 } }; struct poptOption ksZeroMBROptions[] = { { 0, 0, 0, 0, 0 } }; numDrives = 0; for (i = 0; drives[i]; i++, numDrives++); if (numDrives >= MAX_HARDDRIVES) { newtWinMessage(_("Too Many Drives"), _("Ok"), _("You have more drives than this program supports. " "Please use the standard fdisk program to setup your " "drives and please notify Red Hat Software that you " "saw this message.")); return INST_ERROR; } deviceList = alloca(numDrives * sizeof(char *)); for (i = 0; i < numDrives; i++) { deviceList[i] = alloca(15); strcpy(deviceList[i], "/tmp/"); strcat(deviceList[i], drives[i]); if ((rc = devMakeInode(drives[i], deviceList[i]))) return INST_ERROR; } /* see if they want bad partition tables automatically zero'd */ argv = NULL; zerombr = 0; while (1) { if (!ksGetCommand(KS_CMD_ZEROMBR, argv, &argc, &argv)) { char *t; optCon = poptGetContext(NULL, argc, argv, ksZeroMBROptions, 0); /* no options, but just a 'on' or 'off' command */ /* have to parse options anyway to make popt see the leftover? */ poptGetNextOpt(optCon); t = poptGetArg(optCon); if (t && *t && (!strcasecmp(t,"no") || !strcasecmp(t,"off") || !strcmp(t,"0"))) zerombr = 0; else if (t && *t && (!strcasecmp(t,"yes") || !strcasecmp(t,"on") || !strcmp(t,"1"))) zerombr = 1; else newtWinMessage(_("Zero Partition Table"), _("Ok"), _("bad argument to kickstart " "zerombr command: %s.\nMust be " "'on', '1', or 'yes' to enable, " "or 'off', '0', or 'no' to disable."),t); poptFreeContext(optCon); } else { break; } } /* Read in the partition tables from the requested drive(s) */ /* first clear all entries */ memset(hd, 0, MAX_HARDDRIVES*sizeof(HardDrive *)); ReadDrives(deviceList, numDrives, hd, &numhd, zerombr, 0); if (numhd <1) { newtWinMessage(_("No Drives Found"), _("Ok"), _("An error has occurred - no valid devices were found " "on which to create new filesystems. Please check " "your hardware for the cause of this problem.")); for (i = 0; i < numDrives; i++) unlink(deviceList[i]); return INST_ERROR; } /* Translate into a PartitionSpec */ memset(&spec, 0, sizeof(PartitionSpec)); fdiskSetupPartitionSpec( hd, numhd, &spec ); /* copy the fstab they passed, we'll use it until we're done */ /* if they dont cancel it will be new fstab */ remotefstab = copyRemoteFSFstab( fstab ); MergeFstabEntries( hd, numhd, &spec, fstab ); /* see if they want anything removed from disk */ argv = NULL; clearall = 0; clearlinux = 0; if (!ksGetCommand(KS_CMD_CLEARPART, argv, &argc, &argv)) { optCon = poptGetContext(NULL, argc, argv, ksClearOptions, 0); rc = poptGetNextOpt(optCon); if ( rc < -1) { newtWinMessage(_("Clear Partition Command"), _("Ok"), _("bad argument to kickstart " "clearpart command %s: %s"), poptBadOption(optCon, POPT_BADOPTION_NOALIAS), poptStrerror(rc)); for (i=0; i 0) size *= SECPERMEG; else size = 0; } else { size=0; } if (maxsizestr) { maxsize=strtol(maxsizestr,&eptr, 10); if (eptr != maxsizestr && *eptr == 0 && maxsize > 0) maxsize *= SECPERMEG; else maxsize = 0; } else { maxsize=0; } if (maxsizestr && !maxsize) newtWinMessage(_("Option Ignored"), _("Ok"), _("The --maxsize option for the partition " "%s was ignored. Check that it is larger " "than the --size option."), mntpt); /* all done with current context */ poptFreeContext(optCon); if (!mntpt || size == 0) { for (i=0; iwrite_f(hd[i]); } if ((rc = findAllPartitions(NULL, parts))) { for (i=0; inum; i++) if (spec->entry[i].status == REQUEST_DENIED) break; return (i < spec->num); } static int guessAtPartitioning(HardDrive ** hdarr, int numhd, PartitionSpec * spec, int * runDruid, int dir, int flags, struct attemptedPartition * goals) { HardDrive * tmparr[MAX_HARDDRIVES]; int i, rc; static int mayDisplay = 1; int erasedLinux = 0; int erasedAll = 0; struct newtColors colors = newtDefaultColorPalette; *runDruid = 1; if (!mayDisplay) { if (dir < 0) return INST_CANCEL; return 0; } for (i=0; inum; deletePartitionClass(hdarr, numhd, spec, flags & FSEDIT_CLEARLINUX); if (spec->num != i) { erasedLinux = flags & FSEDIT_CLEARLINUX; erasedAll = flags & FSEDIT_CLEARALL; } rc = tryGoal(hdarr, tmparr, numhd, spec, goals); if (rc && (flags & FSEDIT_CLEARALL)) { i = spec->num; deletePartitionClass(hdarr, numhd, spec, 0); if (spec->num != i) { erasedAll = 1; memset(spec, 0, sizeof(PartitionSpec)); fdiskSetupPartitionSpec( hdarr, numhd, spec ); rc = tryGoal(hdarr, tmparr, numhd, spec, goals); } } if (!rc) { char message[2000]; colors.textboxFg = "red"; newtSetColors (colors); while (1) { strcpy(message, erasedAll ? "All of the partitions on your hard drive(s) will be " "erased.\n\n" "This means that all of the data on your system will be " "destroyed.\n" "\n" "If you do not want to lose all of your partitions, " "select \"Cancel\" now, and perform a \"Custom\" install." : "All of the Linux partitions on your hard drive(s) will be " "erased.\n\n" "This means that all of your previous Linux installations " "will be destroyed.\n" "\n" "If you do not want to lose all of your Linux partitions, " "select \"Cancel\" now, and perform a \"Custom\" install." ); rc = newtWinChoice(_("Warning"), _("Cancel"), _("Ok"), message); if (rc == 1) { newtSetColors (newtDefaultColorPalette); return INST_CANCEL; } rc = newtWinChoice(_("Warning"), _("No"), _("Yes"), _("You are about to lose data! Are you sure you want " "to do this?")); if (rc != 1) break; } newtSetColors (newtDefaultColorPalette); *runDruid = 0, rc = 0; } else { newtWinMessage(_("Disk Space"), _("Ok"), _("There is not enough disk space for this type " "of installation.")); return INST_CANCEL; } } if (*runDruid) { /* Put everything back */ memset(spec, 0, sizeof(PartitionSpec)); fdiskSetupPartitionSpec( hdarr, numhd, spec ); } else { for (i=0; i= MAX_HARDDRIVES) { newtWinMessage(_("Too Many Drives"), _("Ok"), _("You have more drives than this program supports. " "Please use the standard fdisk program to setup your " "drives and please notify Red Hat Software that you " "saw this message.")); return INST_ERROR; } deviceList = alloca(numDrives * sizeof(char *)); for (i = 0; i < numDrives; i++) { deviceList[i] = alloca(15); strcpy(deviceList[i], "/tmp/"); strcat(deviceList[i], drives[i]); if ((rc = devMakeInode(drives[i], deviceList[i]))) return rc; } /* Read in the partition tables from the requested drive(s) */ /* first clear all entries */ memset(hdarr, 0, MAX_HARDDRIVES*sizeof(HardDrive *)); rc = ReadDrives(deviceList, numDrives, hdarr, &numhd, 0, FSEDIT_READONLY); if (rc) return rc; if (numhd < 1) { newtWinMessage(_("No Drives Found"), _("Ok"), _("An error has occurred - no valid devices were found " "on which to create new filesystems. Please check " "your hardware for the cause of this problem.")); for (i = 0; i < numDrives; i++) unlink(deviceList[i]); return INST_ERROR; } /* make sure there are any partitions to process */ status = 0; for (i=0; itype.current == DOS_PRIMARY_gt32MEG_PARTITION) { snprintf(device, sizeof(device), "%s%d", hdarr[i]->prefix, p->num.current); snprintf(path, sizeof(path), "%s%d", hdarr[i]->name, p->num.current); devMakeInode(device, path); if (!trimlib_init_filesystem (&filesystem, hdarr[i]->name, p->num.current)) continue; min_cluster_count = filesystem.used_cluster_count > 4084 ? filesystem.used_cluster_count : 4084; snprintf(tmpstr, sizeof(tmpstr), " /dev/%s%d %5dM %5dM ", hdarr[i]->prefix, p->num.current, p->size.current/SECPERMEG, ldiv (1023 + filesystem.cluster_offset + (min_cluster_count+2) * filesystem.cluster_size, 1048576).quot); trimlib_close_filesystem (&filesystem); newtListboxAddEntry(partbox, tmpstr, (void *) i); numDos++; } free(p); } } } for (i = 0; i < numhd; i++) fdiskCloseDevice(hdarr[i]); /* There are partitions on the disk, but none are DOS partitions. Continue to partitioning */ if (numDos == 0) { /* Heh. We didn't need the partbox after all. Someone tell me why I can't just do partbox->opts->destroy(partbox) ... */ form = newtForm(NULL, NULL, 0); newtFormAddComponent(form, partbox); newtFormDestroy(form); for (i = 0; i < numDrives; i++) unlink(deviceList[i]); return INST_OKAY; } /* Create the components */ label = newtLabel(-1, -1, " Device Current Size Required Size"); buttons = newtButtonBar(_("Edit"), &edit, _("Ok"), &ok, _("Back"), &cancel, NULL); /* Build up the form */ form = newtForm(NULL, NULL, 0); grid = newtCreateGrid(1, 3); newtGridSetField(grid, 0, 0, NEWT_GRID_COMPONENT, label, 0, 0, 0, 0, 0, 0); newtGridSetField(grid, 0, 1, NEWT_GRID_COMPONENT, partbox, 0, 0, 0, 0, 0, 0); newtGridSetField(grid, 0, 2, NEWT_GRID_SUBGRID, buttons, 0, 1, 0, 0, 0, NEWT_GRID_FLAG_GROWX); newtGridPlace(grid, 1, 0); newtGridAddComponentsToForm(grid, form, 1); newtGridFree(grid, 1); stage = RESIZE_ASK; while (stage != RESIZE_DONE) { switch (stage) { case RESIZE_ASK: /* Find out if the user wants to do this */ rc = newtWinTernary(_("Disk Setup"), _("Yes"), _("No"), _("Back"), _("There are partitions that can be " "resized nondestructively to make " "room for your Red Hat Linux " "installation. Do you want to resize " "these partitions now?")); if (rc != 1) { newtFormDestroy(form); /* unlink the devices if we don't want to resize */ for (i = 0; i < numDrives; i++) unlink(deviceList[i]); if (rc == 2) return INST_OKAY; return INST_CANCEL; } stage = RESIZE_MAIN; break; case RESIZE_MAIN: newtCenteredWindow(55, numDos + 7, _("Resize Partitions")); newtFormSetCurrent(form, partbox); do { answer = newtRunForm(form); } while (answer != cancel && answer != ok); newtPopWindow(); for (i = 0; i < numDrives; i++) unlink(deviceList[i]); if (answer == cancel) { stage = RESIZE_ASK; break; } newtFormDestroy(form); return INST_OKAY; case RESIZE_DONE: break; } } return INST_OKAY; } #endif /* __i386__ */ #endif /* not ready yet */ /* main program */ int FSEditPartitions(struct partitionTable * parts, struct fstab * fstab, char **drives, struct intfInfo * intf, struct netInfo * netc, struct driversLoaded ** dl, struct attemptedPartition * goals, int flags) { HardDrive *prestinehdarr[MAX_HARDDRIVES]; HardDrive *hdarr[MAX_HARDDRIVES]; /* ORIGINAL HD partition data */ unsigned int numhd; /* total # of drives to consider */ PartitionSpec spec; unsigned int i; struct fstab remotefstab; char ** deviceList; int rc, ourrc = 0; int numDrives; static int beenManual = 0; int runDruid = 0; int writeChanges = 0; static int where = 0; int dir; if (where == 0) dir = 1; else dir = -1; numDrives = 0; for (i = 0; drives[i]; i++, numDrives++); if (numDrives >= MAX_HARDDRIVES) { newtWinMessage(_("Too Many Drives"), _("Ok"), _("You have more drives than this program supports. " "Please use the standard fdisk program to setup your " "drives and please notify Red Hat Software that you " "saw this message.")); return INST_ERROR; } deviceList = alloca(numDrives * sizeof(char *)); for (i = 0; i < numDrives; i++) { deviceList[i] = alloca(15); strcpy(deviceList[i], "/tmp/"); strcat(deviceList[i], drives[i]); if ((rc = devMakeInode(drives[i], deviceList[i]))) return rc; } /* Read in the partition tables from the requested drive(s) */ /* first clear all entries */ memset(hdarr, 0, MAX_HARDDRIVES*sizeof(HardDrive *)); rc = ReadDrives(deviceList, numDrives, hdarr, &numhd,0, flags & FSEDIT_READONLY); if (rc) return rc; if (numhd <1) { newtWinMessage(_("No Drives Found"), _("Ok"), _("An error has occurred - no valid devices were found " "on which to create new filesystems. Please check " "your hardware for the cause of this problem.")); for (i = 0; i < numDrives; i++) unlink(deviceList[i]); return INST_ERROR; } /* make backup of hdarr before user mucked with it */ for (i=0; iwrite_f(hdarr[i]); if (rc) needReboot(); } } if ((rc = findAllPartitions(NULL, parts))) { for (i=0; i