1
0
Files
irix-657m-src/eoe/cmd/fx/pt.c
2022-09-29 17:59:04 +03:00

1178 lines
31 KiB
C

# include "fx.h"
#ident "$Revision: 1.62 $"
ITEM ptype_items[] =
{
{"volhdr", PTYPE_VOLHDR},
{"", -1}, /* was trkrepl */
{"", -1}, /* was secrepl */
{"raw", PTYPE_RAW},
{"", -1}, /* was bsd */
{"", -1}, /* was sysv */
{"volume", PTYPE_VOLUME},
{"efs", PTYPE_EFS},
{"lvol", PTYPE_LVOL},
{"rlvol", PTYPE_RLVOL},
{"xfs", PTYPE_XFS},
{"xfslog", PTYPE_XFSLOG},
{"xlv", PTYPE_XLV},
{0}
};
MENU ptype_menu = { ptype_items, "partition-types" };
MENU menu_type;
char noflopartmsg[] = "no partitions on floppy disks\n";
int majorchange = 1;
static int fstype = PTYPE_XFS;
extern int nomenus; /* see fx.c, -c and -s options */
#define LOGSIZE 4 /* Size of log partition for xlv */
/* display the partitions from the supplied volhdr struct. */
void
show_pts(struct volume_header *vp)
{
register int i, first=1, j;
char *s;
register struct partition_table *p;
j = 0;
menu_type = ptype_menu;
if( menu_type.nitems <= 0 )
menu_digest(&menu_type);
p = &PT(vp)[j];
for( i = j; i < NPARTAB; i++,p++ ) {
if(p->pt_nblks && p->pt_firstlbn >= 0) {
if(first) {
setoff("partitions");
printf(
"part type blocks "
"Megabytes (base+size)\n");
first=0;
}
s = (unsigned)p->pt_type >= menu_type.nitems
? "unknown" : menu_type.items[p->pt_type].name;
printf(
" %2d: %-7.7s%8u + %-8u %5u + %-5u\n",
i, s,
p->pt_firstlbn, p->pt_nblks,
mbytes(p->pt_firstlbn), (long)mbytes(p->pt_nblks));
}
}
}
/*
* print the partition table, very similar to dumpslice, but with a heading
*/
void
show_pt_func(void)
{
#ifdef SMFD_NUMBER
if(drivernum == SMFD_NUMBER) {
printf(noflopartmsg);
return;
}
#endif
argcheck();
show_pts((struct volume_header *)&vh);
(void)checkparts();
}
/*
* change the partition table. Note that when mb is being
* done, that we do NOT change lbn, etc if the user just pressed
* return to keep the old value, or we could change the value
* due to rounding, etc. Default to mb.
*/
void
set_pt_func(void)
{
uint slice, aslice, use;
struct partition_table p1;
unsigned firstone, lastblk;
char flags[2];
char promptmax[48];
int blkflag=0, mbyteflag=1,j;
int allstandard = 1; /* default to prompting for standard parts only while set*/
if( ptype_menu.nitems <= 0 )
menu_digest(&ptype_menu);
menu_type = ptype_menu;
j = 0;
#ifdef SMFD_NUMBER
if(drivernum == SMFD_NUMBER) {
printf(noflopartmsg);
return;
}
#endif
printf("Enter .. when done\n");
/* check for both; if both given, blocks is used */
checkflags("bm", flags);
if(flags[0])
blkflag = 1;
else if(flags[1])
mbyteflag = 1;
for( slice = j; slice < NPARTAB; slice++ )
{
if( slice == PTNUM_VOLUME)
continue; /* we don't allow users to set this */
p1 = PT(&vh)[slice];
/* only prompt for the partitions we normally create devices for,
* unless the partition appears to be valid (i.e., they changed it,
* or it was created by a 3.1 fx that created all the partitions).
* They can still specify any partition they want at the prompt. */
if (allstandard && (p1.pt_nblks <= 0 || p1.pt_firstlbn < 0)) {
switch(slice) {
case PTNUM_FSROOT:
case PTNUM_FSSWAP:
case PTNUM_FSUSR:
case PTNUM_FSALL:
case PTNUM_VOLHDR:
break;
default:
continue;
}
}
argslice(&aslice, slice, NPARTAB, "change partition");
if(aslice == PTNUM_VOLUME)
{
printf("sorry, can't change volume partition\n");
slice--;
continue;
}
p1 = PT(&vh)[aslice];
if(!p1.pt_nblks && !p1.pt_type) /* if changing a currently empty
* partition, show it as xfs by default, not volhdr (which is 0), as that
* seemed to worry some people; if it's not volhdr, it was probably set
* before and then made 0 length, so start from the older value */
p1.pt_type = PTYPE_XFS;
dumpslice(&p1, "before");
argchoice((int *)&use, p1.pt_type, &menu_type, "partition type");
p1.pt_type = use;
lastblk = PT(&vh)[PTNUM_VOLUME].pt_nblks;
firstone = p1.pt_firstlbn;
if(blkflag) {
if(firstone > lastblk)
firstone = lastblk;
argnum(&firstone, firstone, lastblk+1, "first block");
p1.pt_firstlbn = firstone;
}
else if(mbyteflag) {
unsigned lastmb = mbytes(lastblk);
firstone = mbytes(firstone);
if(firstone > lastmb)
firstone = lastmb;
if(argnum(&firstone, firstone, lastmb+1, "base in megabytes"))
p1.pt_firstlbn = mbytetoblk(firstone);
}
lastblk -= p1.pt_firstlbn; /* is now max # of blks in partition */
firstone = p1.pt_nblks;
if(blkflag) {
sprintf(promptmax, "number of blocks (max %u)", lastblk);
argnum(&firstone, firstone, lastblk+1, promptmax);
p1.pt_nblks = firstone;
}
else if(mbyteflag) {
unsigned nummb = mbytes(lastblk);
firstone = mbytes(firstone);
sprintf(promptmax, "size in megabytes (max %u)", nummb);
if(argnum(&firstone, firstone, nummb+1, promptmax))
p1.pt_nblks = mbytetoblk(firstone);
}
if(p1.pt_type != PT(&vh)[aslice].pt_type ||
p1.pt_firstlbn != PT(&vh)[aslice].pt_firstlbn ||
p1.pt_nblks != PT(&vh)[aslice].pt_nblks) {
/* only say it's changed, do the checks, etc. if they really changed
something */
PT(&vh)[aslice] = p1;
changed = 1;
switch(aslice) {
case PTNUM_FSROOT:
case PTNUM_FSSWAP:
case PTNUM_FSUSR:
case PTNUM_FSALL:
case PTNUM_VOLHDR:
break;
default:
allstandard = 0; /* show all in numerical order now */
}
dumpslice(&p1, " after");
if( partcheck(aslice, &p1) < 0 )
aslice--;
}
slice = aslice; /* do the next one after the one that they changed, not
* necessarily the next in the original sequence */
}
(void)checkparts();
}
/*
* print one entry in the partition table
*/
void
dumpslice(struct partition_table *p, char *prmpt)
{
register char *s;
size_t spaces;
menu_type = ptype_menu;
if( menu_type.nitems <= 0 )
menu_digest(&menu_type);
s = (unsigned)p->pt_type >= menu_type.nitems
? "unknown" : menu_type.items[p->pt_type].name;
spaces = strlen(prmpt) + 18;
printf("%s: type %-7.7s block %7u, %4u MB\n"
"%*.*s len: %7u blks, %4u MB\n",
prmpt, s,
p->pt_firstlbn, mbytes(p->pt_firstlbn),
spaces, spaces, "",
p->pt_nblks, mbytes(p->pt_nblks));
}
/*
* initialize default partition sizes and types. make all partitions
* be cyl-aligned; user can change later. calculate sizes of root,
* and swap partitions, based on a bounded percentage of
* the total disk size.
*
* assumptions:
* that the total disk size is greater than the sum of the minima.
*/
# define PCT 100
# define MB ((long)1<<20)
/* NOTE: in the past, the min and max were in terms of sectors;
now they are in bytes, because the sector size isn't known
at compile time! swapmin should be large enough for a miniroot,
which means 28 MB currently. rootmin should be large enough
for a normal root, which means at least 18MB.
swapmax is for the default create/part, not a real max. I've
bumped the default swap area to 128, but dropped the percent to
10, and set the min to 39 (39 instead of 40, so I don't
complain about older drives where the 40MB swap rounded down to
39), so 200-400MB drives still get 40MB. I also made swapmin
32, as we had miniroots of 30MB for a while, and may again.
rootmax changes to 50MB primarily for the high end, but rootpct
drops to 2, so we keep it smaller for the smaller disks.
rootmin is 18, we are marginal on 6.2 32 bit systems at 18, but
we make it. 64 bit systems are marginal even at 25. See the runtime
setting of rootmin to 30 below for 64 bit systems.
rootpct changes for 6.2 so we get ~21MB on 1GB
disks, and 50MB on disks > 2GB, on the split / and /usr disks,
at NSD's request. Also see PTYPE_VOLHDR_DFLTSZ in dvh.h for
volhdr size.
*/
int rootpct = 4; daddr_t rootmin = 18, rootmax = 50;
int swappct = 10; daddr_t swapmin = 39, swapmax = 128;
char whichparts[NPARTAB];
void
create_parts(void)
{
register struct partition_table *p, *q;
uint nblks, l, s;
uint logblks;
/* 64 bit systems have rootmin of 30MB now; 18 for others;
* the tuning gives a larger value for all the drives we have
* shipped on those systems; this is primarily for the warning
* check at the end (same resetting also in pt_resize_func()).
* Not worth checking to see if we've already done it; just do it. */
#if defined(_STANDALONE) && _MIPS_SIM == _AIB64
rootmin = 30;
#elif !defined(_STANDALONE)
if (sysconf(_SC_KERN_POINTERS) == 64)
rootmin = 30;
#endif
bzero((char *)PT(&vh), sizeof PT(&vh));
switch (drivernum) {
case SCSI_NUMBER:
/* because of the fixups in dksc.c to protect users from 'bad' vh's,
* we need to get the real # of cyls when creating default
* partitions. Since this is the only way the vol pt can
* be created, we don't need to worry when editting partitions */
{
struct device_parameters d;
scsiset_dp(&d);
l = 0;
}
break;
#ifdef SMFD_NUMBER
case SMFD_NUMBER:
printf(noflopartmsg);
return;
#endif /* SMFD_NUMBER */
default:
printf("Don't know how to initialize partitions for driver type %u\n",
drivernum);
return;
}
if(whichparts[PTNUM_VOLUME]) {
p = PT(&vh)+PTNUM_VOLUME;
p->pt_type = PTYPE_VOLUME;
p->pt_firstlbn = 0;
nblks = p->pt_nblks = DP(&vh)->dp_drivecap;
}
else
nblks = DP(&vh)->dp_drivecap;
if(whichparts[PTNUM_VOLHDR]) {
p = PT(&vh)+PTNUM_VOLHDR;
p->pt_type = PTYPE_VOLHDR;
p->pt_firstlbn = 0;
p->pt_nblks = PTYPE_VOLHDR_DFLTSZ;
if(p->pt_nblks > nblks)
p->pt_nblks = nblks;
nblks -= p->pt_nblks;
}
q = PT(&vh)+PTNUM_VOLHDR;
/* Number of blocks for xlv log partition. */
if (whichparts[PTNUM_XFSLOG])
logblks = mbytetoblk(LOGSIZE);
if(whichparts[PTNUM_FSALL]) {
/* entire disk except vh and badblock (if any) */
p = PT(&vh)+PTNUM_FSALL;
p->pt_type = fstype;
p->pt_firstlbn = q->pt_firstlbn + q->pt_nblks;
p->pt_nblks = nblks;
if (whichparts[PTNUM_XFSLOG] && logblks < p->pt_nblks)
p->pt_nblks -= logblks;
}
/* follows volhdr now, not root */
if(whichparts[PTNUM_FSSWAP]) {
p = PT(&vh)+VP(&vh)->vh_swappt;
p->pt_type = PTYPE_RAW;
p->pt_firstlbn = q->pt_firstlbn+q->pt_nblks;
l = (DP(&vh)->dp_drivecap / PCT) * swappct;
if( l < (s = mbytetoblk(swapmin) + 1))
l = s;
if( l > (s = mbytetoblk(swapmax)))
l = s;
if( l > nblks )
l = nblks;
p->pt_nblks = l;
if(p->pt_nblks < (mbytetoblk(swapmin) + 1))
scerrwarn("swap partition will be too small (%lld blocks)\n", l);
nblks -= l;
}
if(whichparts[PTNUM_FSROOT]) {
/* root partition */
q = PT(&vh)+VP(&vh)->vh_swappt;
p = PT(&vh)+VP(&vh)->vh_rootpt;
p->pt_type = fstype;
p->pt_firstlbn = q->pt_firstlbn + q->pt_nblks;
if(whichparts[PTNUM_FSUSR]) { /* old style (pt_root_func) */
l = (DP(&vh)->dp_drivecap / PCT) * rootpct;
if( l < (s = mbytetoblk(rootmin) + 1))
l = s;
if( l > (s = mbytetoblk(rootmax)))
l = s;
if( l > nblks)
l = nblks;
p->pt_nblks = l;
nblks -= l;
}
else { /* new style (pt_sroot_func) */
p->pt_nblks = nblks;
nblks -= p->pt_nblks;
}
if(p->pt_nblks < (mbytetoblk(rootmin) + 1))
scerrwarn("swap partition will be too small (%lld blocks)\n",
p->pt_nblks);
}
if(whichparts[PTNUM_FSUSR]) {
p = PT(&vh)+PTNUM_FSUSR;
q = PT(&vh)+VP(&vh)->vh_rootpt; /* always follows root now */
p->pt_type = fstype;
p->pt_firstlbn = q->pt_firstlbn+q->pt_nblks;
p->pt_nblks = nblks;
if (whichparts[PTNUM_XFSLOG] && p->pt_nblks > logblks)
p->pt_nblks -= logblks;
nblks -= p->pt_nblks;
}
if(whichparts[PTNUM_XFSLOG]) {
p = PT(&vh)+PTNUM_XFSLOG;
if (whichparts[PTNUM_FSUSR])
q = PT(&vh)+PTNUM_FSUSR;
else
q = PT(&vh)+PTNUM_FSALL;
p->pt_type = PTYPE_XFSLOG;
p->pt_firstlbn = q->pt_firstlbn + q->pt_nblks;
if(logblks > nblks)
logblks = nblks;
p->pt_nblks = logblks;
nblks -= logblks; /* in case we add more parts later */
q = PT(&vh)+PTNUM_XFSLOG;
}
changed = 1;
}
void
create_pt_func(void)
{
bzero(whichparts, sizeof(whichparts));
/* don't create part 7 any more, when it's brand new or when they ask
* for creat/part. Some people then make a filesystem on part 7
* otherwise, leaving what looks like valid swap, and if they then
* try to install, they can trash the filesystem. So now force them
* to use repart/option or the like, if they want that (which gets
* rid of part 1, etc. */
whichparts[PTNUM_VOLUME] = whichparts[PTNUM_VOLHDR] =
whichparts[PTNUM_FSROOT] = whichparts[PTNUM_FSSWAP] = 1;
create_parts();
printf("...created default partitions, use /repartition menu to change\n");
}
/*
* refresh partition table from disk
*/
void
readin_pt_func(void)
{
CBLOCK b;
#ifdef SMFD_NUMBER
if(drivernum == SMFD_NUMBER) {
printf(noflopartmsg);
return;
}
#endif
printf("...reading in partition table\n");
if( readinvh(VP(&b)) < 0 )
return;
bcopy((char *)PT(&b), (char *)PT(&vh), sizeof PT(&vh));
}
/*
* check each partition for legality.
* return <0 if any partition is found illegal, 0 if all OK.
* check all, because partcheck prints a message on problems
*/
int
checkparts(void)
{
register int i, illegal;
register struct partition_table *p;
p = PT(&vh);
for(illegal = i = 0; i < NPARTAB; i++ )
if(partcheck(i, p++))
illegal++;
return illegal;
}
/*
* return <0 if the given partition is found bad, 0 if all OK.
* a legal partition must:
* be of a legal size
* be of a legal type
* if root, of a FS type
* if swap, of RAW type
* if volume, must match device size.
* if fs or logv, must not intersect volhdr
*/
int
partcheck(uint n, struct partition_table *p)
{
STRBUF s;
register char *f;
int ign, isfs;
# define PARTERROR(m) (printf(f,m) , f = ", %s")
f = s.c;
isfs = isfstype(p->pt_type);
sprintf(f, "warning: partition %u %cs", n, '%');
ign = p->pt_nblks == 0 || p->pt_firstlbn == -1;
if( !ign )
{
if( isfs )
{
if( intersect(p, PT(&vh)+PTNUM_VOLHDR) )
PARTERROR("intersects volhdr partition");
}
if(p->pt_firstlbn > DP(&vh)->dp_drivecap)
PARTERROR("base out of range");
if((p->pt_firstlbn+p->pt_nblks) > DP(&vh)->dp_drivecap)
PARTERROR("size out of range");
}
/* don't complain if this isn't the root drive! */
if( VP(&vh)->vh_swappt == n && isrootdrive) {
if(p->pt_nblks == 0)
PARTERROR("(swap) is zero size");
else if( ign || (!isfs && p->pt_type != PTYPE_RAW))
PARTERROR("(swap) type must be raw, bsd, sysv, efs, xfs, lvol, rlvol, xlv, or xfslog");
}
/* don't complain if this isn't the root drive! */
if( VP(&vh)->vh_rootpt == n && isrootdrive) {
if(p->pt_nblks == 0)
PARTERROR("(root) is zero size");
else if( ign || !isfs )
PARTERROR("(root) type must be raw, bsd, sysv, efs, xfs, lvol, rlvol, xlv, or xfslog");
}
if( n == PTNUM_VOLHDR )
{
if( ign || !(p->pt_type == PTYPE_VOLHDR) )
PARTERROR("not of type volhdr");
if((p->pt_firstlbn) )
PARTERROR("volhdr doesn't start at 0");
if((p->pt_nblks <= 0) )
PARTERROR("volhdr is too small");
}
if( n == PTNUM_VOLUME )
{
if( ign || !(p->pt_type == PTYPE_VOLUME) )
PARTERROR("not of type volume");
if((p->pt_firstlbn) )
PARTERROR("doesn't start at 0");
if(p->pt_nblks > DP(&vh)->dp_drivecap)
PARTERROR("is larger than drive capacity");
}
if( f != s.c )
{
newline();
return -1;
}
return 0;
# undef PARTERROR
}
int
isfstype(int t)
{
return t==PTYPE_EFS || t==PTYPE_XFS || t==PTYPE_XFSLOG ||
t==PTYPE_LVOL || t==PTYPE_RLVOL || t==PTYPE_XLV;
}
/*
* return true if 2 partitions overlap
*/
intersect(struct partition_table *p1, struct partition_table *p2)
{
/* beginning of p1 must be after end of p2 or vice versa */
return p1->pt_nblks > 0 && p2->pt_nblks > 0
&& !(p1->pt_firstlbn >= (p2->pt_firstlbn+p2->pt_nblks)
|| p2->pt_firstlbn >= (p1->pt_firstlbn+p1->pt_nblks));
}
/* this is called whenever the repartition menu is displayed */
void
show_pt_cap(void)
{
printf("\n");
show_pt_func();
newline();
if(drivernum == SCSI_NUMBER)
showcapacity_func();
else
printf("Drive capacity is %d blocks\n",
PT(&vh)[PTNUM_VOLUME].pt_nblks);
}
static ITEM partitions[] = {
{ "root", PTNUM_FSROOT },
{ "swap", PTNUM_FSSWAP },
{ "usr", PTNUM_FSUSR },
{ "volume", PTNUM_FSALL },
{ "xfslog", PTNUM_XFSLOG },
{0}
};
static char *
ptname(uint pnum)
{
ITEM *p = partitions;
static char pname[20]; /* large enough for bad vals of pnum */
while(p->name) {
if(p->value == pnum)
return p->name;
p++;
}
sprintf(pname, "part #%d", pnum);
return pname;
}
/* check to see if a changing partition now overlaps another partition.
* If so, fix up the one that is NOT changing. Check to see if it goes
* to zero size, and ask about that special case before continuing.
* sanity checks for min part sizes are done on return, so don't bother here.
*/
checkoverlap(uint pnum, struct volume_header *tmpvh, uint chkpnum)
{
struct partition_table *pt, *chkpt;
char msg[80];
int adjust;
pt = &tmpvh->vh_pt[pnum];
chkpt = &tmpvh->vh_pt[chkpnum];
if(!intersect(pt, chkpt)) {
return 0; /* OK */
}
if(pt->pt_firstlbn <= chkpt->pt_firstlbn &&
(pt->pt_firstlbn+pt->pt_nblks) >= (chkpt->pt_firstlbn+chkpt->pt_nblks)) {
/* changing partition completely contains checked partition */
sprintf(msg, "This would remove the %s partition, is that OK",
ptname(chkpnum));
if(no(msg))
return 1;
chkpt->pt_nblks = 0;
}
else if(pt->pt_firstlbn < chkpt->pt_firstlbn) {
/* bump start of checked partition, and decrease size */
adjust = (pt->pt_firstlbn+pt->pt_nblks) - chkpt->pt_firstlbn;
chkpt->pt_firstlbn = pt->pt_firstlbn + pt->pt_nblks;
chkpt->pt_nblks -= adjust;
}
else /* just drop the block count.
* Note that this catches the (shouldn't happen) case of the
* changing partition being complete contained in the checked
* partition. We could figure out which end is bigger, but the
* user can always fix that up later. */
chkpt->pt_nblks = pt->pt_firstlbn - chkpt->pt_firstlbn;
return -1;
}
/* These 4 functions are all called from the repartition menu at the
* top level, and are primarily intended to allow SIMPLE re-partitioning
* without requiring much expertise. Reasonable defaults are
* given, and things like pt_type are set automatically.
*/
#define P_MB 0
#define P_PCT 1
#define P_BLKS 2
#define PVH PT(&vh)
void
pt_resize_func(void)
{
int pnum, method, pchanged, fixup;
unsigned maxblocks, maxvolblks=0, newval, oldval;
struct partition_table pt;
struct volume_header oldvh;
struct volume_header tmpvh;
char promptmax[48];
static ITEM how[] = {
{ "megabytes (2^20 Bytes)", P_MB },
{ "percentage", P_PCT },
{ "blocks", P_BLKS },
{0}
};
static MENU how_menu = { how, "partitioning method" };
static MENU part_menu = { partitions, "partition to change" };
/* 64 bit systems have rootmin of 30MB now; 18 for others;
* the tuning gives a larger value for all the drives we have
* shipped on those systems; this is primarily for the warning
* check at the end. same code also in create_parts().
* Not worth checking to see if we've already done it; just do it. */
#if defined(_STANDALONE) && _MIPS_SIM == _AIB64
rootmin = 30;
#elif !defined(_STANDALONE)
if (sysconf(_SC_KERN_POINTERS) == 64)
rootmin = 30;
#endif
if((PVH[PTNUM_FSALL].pt_nblks<=0 || PVH[PTNUM_FSALL].pt_firstlbn < 0) &&
(PVH[PTNUM_FSROOT].pt_nblks<=0 || PVH[PTNUM_FSROOT].pt_firstlbn < 0 ||
PVH[PTNUM_FSSWAP].pt_nblks<=0 || PVH[PTNUM_FSSWAP].pt_firstlbn < 0))
printf(
"This does not appear to be a standard root or option drive.\n"
"You should probably use either the \"rootdrive\" or the\n"
"\"optiondrive\" menu choice to create a standard drive\n"
"partition layout before using this menu\n\n");
reinst_warning();
printf("\nAfter changing the partition, the other partitions will\n"
"be adjusted around it to fit the change. The result will be\n"
"displayed and you will be asked whether it is OK, before the\n"
"change is committed to disk. Only the standard partitions may\n"
"be changed with this function. Type ? at prompts for a list\n"
"of possible choices\n\n");
/* default to swap partition, if valid, otherwise entire. CSD folks
* say most common reason to partition is to make swap larger. Next
* most common is when setting up a new non-SGI drive as an additional
* drive. argchoice takes array index, and returns array index. */
if(PVH[PTNUM_FSSWAP].pt_nblks<=0 || PVH[PTNUM_FSSWAP].pt_firstlbn<0)
pnum = 3; /* index from partition menu array */
else
pnum = 1;
argchoice(&pnum, pnum, &part_menu, part_menu.title);
pnum = partitions[pnum].value;
pt = PVH[pnum];
/* set type correctly before dumping the slice */
switch(pnum) {
case PTNUM_FSROOT:
pt.pt_type = fstype;
break;
case PTNUM_FSSWAP:
pt.pt_type = PTYPE_RAW;
break;
case PTNUM_FSUSR:
pt.pt_type = fstype;
break;
case PTNUM_FSALL:
pt.pt_type = fstype;
break;
case PTNUM_XFSLOG:
pt.pt_type = PTYPE_XFSLOG;
}
dumpslice(&pt, "current");
if(drivernum == SCSI_NUMBER &&
scsi_readcapacity((uint*)&oldval) != -1)
/* use real max for scsi, so that all blocks can be
* used for variable geometry drives or zone sparing */
maxvolblks = oldval;
else
maxvolblks = PVH[PTNUM_VOLUME].pt_nblks;
if((int)maxvolblks == -1 || !maxvolblks) {
/* defend against errors */
printf("volume size not valid, can not proceed\n");
return;
}
/* don't let the partitions creep down into the volhdr */
maxblocks = maxvolblks - (PVH[PTNUM_VOLHDR].pt_nblks -
PVH[PTNUM_VOLHDR].pt_firstlbn);
/* if the partition wasn't previously used (as adding
* a user partition on an old option drive), ensure
* that the base address is at least > than the volhdr. */
if(pt.pt_firstlbn <
(PVH[PTNUM_VOLHDR].pt_firstlbn + PVH[PTNUM_VOLHDR].pt_nblks))
pt.pt_firstlbn =
PVH[PTNUM_VOLHDR].pt_firstlbn + PVH[PTNUM_VOLHDR].pt_nblks;
argchoice(&method, P_MB, &how_menu, how_menu.title);
/* note that we need to check that the user actually changed the
* value, otherwise with the conversion, we could wind up with
* a different partition layout, even if they just accepted the current
* value */
pchanged = 0;
switch(method) {
case P_MB:
oldval = mbytes(pt.pt_nblks);
sprintf(promptmax, "size in megabytes (max %u)",
mbytes(maxblocks));
argnum(&newval, oldval, mbytes(maxblocks)+1, promptmax);
if(oldval != newval) {
newval = mbytetoblk(newval);
pchanged = 1;
}
break;
case P_PCT:
oldval = (100*pt.pt_nblks)/PVH[PTNUM_VOLUME].pt_nblks;
argnum(&newval, oldval,
(100*maxblocks)/PVH[PTNUM_VOLUME].pt_nblks+1,
"percentage of disk");
if(oldval != newval) {
newval = (newval * PVH[PTNUM_VOLUME].pt_nblks) / 100;
pchanged = 1;
}
break;
case P_BLKS:
sprintf(promptmax, "size in blocks (max %u)", maxblocks);
argnum(&newval, pt.pt_nblks, maxblocks+1, "size in blocks");
if(newval != pt.pt_nblks)
pchanged = 1;
break;
}
if(!pchanged) {
printf("\nNo change made\n");
return;
}
/* due to rounding, converted value may be > than the max */
pt.pt_nblks = newval > maxvolblks ? maxvolblks : newval;
if((pt.pt_firstlbn + pt.pt_nblks) > maxvolblks) /* bump down base ? */
pt.pt_firstlbn = maxvolblks - pt.pt_nblks;
/* want to make all changes to a copy, in case they decide
* not to use the modified version */
bcopy(&vh, &tmpvh, sizeof(tmpvh));
bcopy(&pt, &tmpvh.vh_pt[pnum], sizeof(pt));
/* check for overlaps, and fix up as needed. Check in 'correct' order,
* as a fixup in the first may require a fixup in the second also.
* No check for entire, since we assume they are using the
* whole disk, or are using the leftover for some special
* purpose, but still set type. If any checkoverlap made changes,
* except the first we have to iterate through again.
* we needlessly check the first one a second time, if it was
* the one with a fixup, but that is cheap, and it's cleaner
* to code this way. */
do {
switch(pnum) {
case PTNUM_FSROOT:
if(fixup=checkoverlap(pnum, &tmpvh, PTNUM_FSSWAP) == 1)
break;
if((fixup = checkoverlap(pnum, &tmpvh, PTNUM_FSUSR)))
break;
fixup = checkoverlap(pnum, &tmpvh, PTNUM_XFSLOG);
break;
case PTNUM_FSSWAP:
if((fixup = checkoverlap(pnum, &tmpvh, PTNUM_FSUSR)) == 1)
break;
if((fixup = checkoverlap(pnum, &tmpvh, PTNUM_XFSLOG)))
break;
fixup = checkoverlap(pnum, &tmpvh, PTNUM_FSROOT);
break;
case PTNUM_FSUSR:
if(fixup=checkoverlap(pnum, &tmpvh, PTNUM_FSSWAP) == 1)
break;
if((fixup = checkoverlap(pnum, &tmpvh, PTNUM_FSROOT)))
break;
fixup = checkoverlap(pnum, &tmpvh, PTNUM_XFSLOG);
break;
case PTNUM_XFSLOG:
if((fixup = checkoverlap(pnum, &tmpvh, PTNUM_FSUSR)) == 1)
break;
if((fixup = checkoverlap(pnum, &tmpvh, PTNUM_FSALL)))
break;
if((fixup = checkoverlap(pnum, &tmpvh, PTNUM_FSSWAP)))
break;
fixup = checkoverlap(pnum, &tmpvh, PTNUM_FSROOT);
break;
case PTNUM_FSALL:
fixup = checkoverlap(pnum, &tmpvh, PTNUM_XFSLOG);
break;
}
} while(fixup == -1);
if(fixup == 1)
return;
/* this can happen with SCSI drives where some of the capacity
* was unused, or sometimes when going from vh's done by older
* versions of fx. It looks weird if a partition goes past the
* end of the whole vol, and may upset some drivers or programs
* like prtvtoc, so fix it up.
*/
if((tmpvh.vh_pt[pnum].pt_firstlbn + tmpvh.vh_pt[pnum].pt_nblks) >
tmpvh.vh_pt[PTNUM_VOLUME].pt_nblks)
tmpvh.vh_pt[PTNUM_VOLUME].pt_nblks =
tmpvh.vh_pt[pnum].pt_firstlbn + tmpvh.vh_pt[pnum].pt_nblks;
show_pts(&tmpvh);
/* check validity as root drive. Don't check if FSALL.
* if root is very large, don't check for usr partition, since they
* probably made a single large partition, rather than a seperate
* root and user partition. 4*rootmax is a MINIMAL realistic
* value for this, it will probably be much larger */
if((pnum != PTNUM_FSALL && tmpvh.vh_pt[PTNUM_FSALL].pt_nblks == 0) &&
(tmpvh.vh_pt[PTNUM_FSROOT].pt_nblks < mbytetoblk(rootmin) ||
tmpvh.vh_pt[PTNUM_FSSWAP].pt_nblks < mbytetoblk(swapmin) ||
(tmpvh.vh_pt[PTNUM_FSROOT].pt_nblks < mbytetoblk(4*rootmax) &&
tmpvh.vh_pt[PTNUM_FSUSR].pt_nblks < mbytetoblk(4*rootmax))))
printf("\nNotice: if this partition layout is used, the drive\n"
" may only be usable as a non-root drive due to small\n"
" partitions\n\n");
if(no("Use the new partition layout"))
return;
bcopy(&vh, &oldvh, sizeof(vh)); /* Keep one in case of error */
bcopy(&tmpvh, &vh, sizeof(tmpvh));
if (update() != 0) {
scerrwarn("label write failed!\n");
bcopy(&oldvh, &vh, sizeof(vh)); /* Restore original */
} else {
/* suppress further partition warnings until exit or change
* to a new drive */
majorchange = 1;
}
}
#define PSROOT 0
#define PROOT 1
#define POPT 2
#define EXTERNAL 0
#define INTERNAL 1
static ITEM fstypes[] = {
{ "xfs", PTYPE_XFS },
{ "efs", PTYPE_EFS },
{0}
};
static MENU fstype_menu = { fstypes, "type of data partition" };
/*
* Ask enough questions of the user to sufficiently determine partition
* option. xfs or efs partition type? External xfslog partition required?
*/
void
select_options(int partition_option)
{
int onum = 0;
argchoice(&onum, onum, &fstype_menu, fstype_menu.title);
fstype = fstypes[onum].value;
switch (partition_option) {
case PSROOT:
pt_sroot_func();
break;
case PROOT:
pt_root_func();
break;
case POPT:
pt_optdrive_func();
break;
}
}
void
root_select_func(void)
{
int partition_option = PROOT;
select_options(partition_option);
}
void
sroot_select_func(void)
{
int partition_option = PSROOT;
select_options(partition_option);
}
void
option_select_func(void)
{
int partition_option = POPT;
select_options(partition_option);
}
void
pt_optdrive_func(void)
{
struct volume_header oldvh;
reinst_warning();
bcopy(&vh, &oldvh, sizeof(vh)); /* Keep one in case of error */
bzero(whichparts, sizeof(whichparts));
whichparts[PTNUM_VOLUME] = whichparts[PTNUM_VOLHDR] =
whichparts[PTNUM_FSALL] = 1;
create_parts();
/* suppress further partition warnings until exit or change
* to a new drive */
if(changed) {
if (update() != 0) {
scerrwarn("label write failed!\n");
bcopy(&oldvh, &vh, sizeof(vh)); /* Restore original */
changed = 0;
} else {
majorchange = 1;
}
}
}
/* makes the new style system disk (vh swap root) layout
* as of irix6.5, swap moves ahead of root, so miniroot can
* be copied to swap, and disk repartitioned while leaving the
* miniroot intact. For 5.3-6.4, it was "vh root swap"
*/
void
pt_sroot_func(void)
{
struct volume_header oldvh;
reinst_warning();
bcopy(&vh, &oldvh, sizeof(vh)); /* Keep one in case of error */
bzero(whichparts, sizeof(whichparts));
whichparts[PTNUM_VOLUME] = whichparts[PTNUM_VOLHDR] =
whichparts[PTNUM_FSROOT] = whichparts[PTNUM_FSSWAP] = 1;
/* when creating a 'root' drive, force root and swap to
* the 'normal' locations; this is done primarily in case
* drive was in the middle of an install, when root is
* set to the swap partition. */
VP(&vh)->vh_rootpt = PTNUM_FSROOT;
VP(&vh)->vh_swappt = PTNUM_FSSWAP;
create_parts();
/* suppress further partition warnings until exit or change
* to a new drive */
if(changed) {
if (update() != 0) {
scerrwarn("label write failed!\n");
bcopy(&oldvh, &vh, sizeof(vh)); /* Restore original */
changed = 0;
} else {
majorchange = 1;
}
}
}
/* makes the old style system disk (vh swap root usr) layout.
* As of irix6.5, swap moves ahead of root, so miniroot can
* be copied to swap, and disk repartitioned while leaving the
* miniroot intact. For 5.3-6.4, it was "vh root swap usr"
*/
void
pt_root_func(void)
{
struct volume_header oldvh;
reinst_warning();
bcopy(&vh, &oldvh, sizeof(vh)); /* Keep one in case of error */
bzero(whichparts, sizeof(whichparts));
whichparts[PTNUM_VOLUME] = whichparts[PTNUM_VOLHDR] =
whichparts[PTNUM_FSROOT] = whichparts[PTNUM_FSSWAP] =
whichparts[PTNUM_FSUSR] = 1;
/* when creating a 'root' drive, force root and swap to
* the 'normal' locations; this is done primarily in case
* drive was in the middle of an install, when root is
* set to the swap partition. */
VP(&vh)->vh_rootpt = PTNUM_FSROOT;
VP(&vh)->vh_swappt = PTNUM_FSSWAP;
create_parts();
/* suppress further partition warnings until exit or change
* to a new drive */
if(changed) {
if (update() != 0) {
scerrwarn("label write failed!\n");
bcopy(&oldvh, &vh, sizeof(vh)); /* Restore original */
changed = 0;
} else {
majorchange = 1;
}
}
}
void
pt_expert_func(void)
{
struct volume_header oldvh;
reinst_warning();
bcopy(&vh, &oldvh, sizeof(vh)); /* Keep one in case of error */
set_pt_func(); /* same as /label/set/partition, but warn them first */
/* suppress further partition warnings until exit or change
* to a new drive */
if(changed) {
if (update() != 0) {
scerrwarn("label write failed!\n");
bcopy(&oldvh, &vh, sizeof(vh)); /* Restore original */
changed = 0;
} else {
majorchange = 1;
}
}
}
void
reinst_warning(void)
{
/* If they are already committed, repeated warnings are annoying */
if(majorchange || nomenus)
return;
if(!yesno(-1,
"Warning: you will need to re-install all software and restore user data\n"
"from backups after changing the partition layout. Changing partitions\n"
"will cause all data on the drive to be lost. Be sure you have the drive\n"
"backed up if it contains any user data. Continue" ))
mpop();
}