/* handles the PartitionSpec type and operations we do on them */ #include #include #include #include #include "libfdisk.h" /* some globals used to keep up with last allocation error (sortof like errno) */ enum allocReason LastAllocStat = ALLOC_UNDEF; static char *reasons[] = { "Reason Undefined", "Allocation Succeeded", "Not enough free space", "Requested Start", "Boot partition too big", "Requested drive(s)", "No free primary", "Extended Failed", "No free slots", NULL }; /* returns pointers to a const char string of why */ char *GetReasonString( enum allocReason reason ) { int i; for (i=0; i < (int) reason && reasons[i]; i++); if (!reasons[i]) return "Unknown reason"; else return reasons[i]; } /* give priority to the constraints of a partition */ /* if priority is < 0 then there was an error */ int fdiskGetConstraintPriority( Partition *p ) { int pri; pri = 0; if (p->immutable) pri += 16384; if (fdiskDriveSetIsActive( &p->drive )) pri += 128; if (fdiskConstraintIsActive( &p->endcyl)) pri += 64; if (fdiskConstraintIsActive( &p->start)) pri += 32; if (fdiskConstraintIsActive( &p->size)) pri += 16; return pri; } /* sort in order of priority */ /* we now worry about <1024 cyl contraints if necessary */ int fdiskSortPartitionSpec( PartitionSpec *spec ) { unsigned int i, j; int f; unsigned int pri1, pri2; unsigned int lsize1, lsize2; unsigned int msize1, msize2; unsigned int csize1, csize2; unsigned int act1, act2; Partition *p1, *p2; PartitionSpecEntry tmpe; /* now see if there is anything to sort */ if (spec->num < 2) return FDISK_SUCCESS; for (i=0; inum-1; i++) { p1 = &spec->entry[i].partition; #if 0 if (p1->immutable) continue; #endif pri1 = fdiskGetConstraintPriority(p1); fdiskGetConstraint(&p1->size,&csize1,&lsize1,&msize1,&act1 ); for (j=i+1; j < spec->num; j++) { p2 = &spec->entry[j].partition; /* we dont want to reorder immutable specs */ /* but we want to bubble them to top over */ /* user specifified partitions */ if (p1->immutable && p2->immutable) continue; pri2 = fdiskGetConstraintPriority(p2); if (pri1 < pri2) f = 1; else if (pri1 > pri2) f = -1; else { fdiskGetConstraint(&p2->size,&csize2,&lsize2,&msize2,&act2 ); f = (lsize1 < lsize2); } if (f > 0) { memcpy(&tmpe, &spec->entry[i], sizeof(PartitionSpecEntry)); memcpy(&spec->entry[i], &spec->entry[j], sizeof(PartitionSpecEntry)); memcpy(&spec->entry[j], &tmpe, sizeof(PartitionSpecEntry)); } } } return FDISK_SUCCESS; } /* check for special partitions and setup constraints if they exist */ int fdiskHandleSpecialPartitions( PartitionSpec *spec ) { unsigned int i, j; Partition *p1, *p2; /* oh man are PCs braindead */ #if defined(__i386__) /* see if we have any special partitions (like bootable) */ i = fdiskReturnPartitionSpec( spec, "/", &p1 ); j = fdiskReturnPartitionSpec( spec, "/boot", &p2 ); if (j == FDISK_SUCCESS) { /* if "/" exists make it a normal partition again */ if (i==FDISK_SUCCESS) { fdiskSetConstraint(&p1->endcyl, 0,FDISK_ENDCYL_MIN,FDISK_ENDCYL_MAX,0); fdiskActivateAllDriveSet( &p1->drive ); fdiskModifyPartitionSpec( spec, "/", p1, REQUEST_PENDING ); free(p1); } /* set "/boot" as bootable partition */ fdiskSetConstraint(&p2->endcyl, 0,0,1023,1); fdiskDeactivateAllDriveSet( &p2->drive ); fdiskActivateDriveSet( &p2->drive, 1 ); fdiskActivateDriveSet( &p2->drive, 2 ); fdiskModifyPartitionSpec( spec, "/boot", p2, REQUEST_PENDING ); free(p2); } else if (i == FDISK_SUCCESS) { /* make "/" bootable */ fdiskSetConstraint(&p1->endcyl,0,0,1023,1); fdiskDeactivateAllDriveSet( &p1->drive ); fdiskActivateDriveSet( &p1->drive, 1 ); fdiskActivateDriveSet( &p1->drive, 2 ); fdiskModifyPartitionSpec( spec, "/", p1, REQUEST_PENDING ); free(p1); } fdiskSortPartitionSpec( spec ); #endif return FDISK_SUCCESS; } /* get index of partition spec requested */ /* return value is non-zero if not found */ int fdiskIndexPartitionSpec(PartitionSpec *spec, char *name, unsigned int *index ) { unsigned int j, found; /* see if it already exists */ found = 0; for (j=0; jnum && !found;) if (!strcmp(spec->entry[j].name, name)) found = 1; else j++; if (found) { *index = j; return FDISK_SUCCESS; } else { return FDISK_ERR_BADNUM; } } /* insert new specification into existing PartitionSpec */ int fdiskInsertPartitionSpec( PartitionSpec *spec, char *name, Partition *p, unsigned int status) { unsigned int num; unsigned int j, found; if ((num=spec->num) >=MAX_PARTITION_SPEC) return FDISK_ERR_NOFREE; /* see if it already exists */ found = 0; for (j=0; jnum && !found;) if (!strcmp(spec->entry[j].name, name)) found = 1; else j++; if (found) return FDISK_ERR_INUSE; /* Ok insert the bugger */ spec->entry[num].name = strdup(name); memcpy(&spec->entry[num].partition, p, sizeof(Partition)); spec->entry[num].status = status; spec->num++; fdiskSortPartitionSpec( spec ); return FDISK_SUCCESS; } /* delete specification based on mount point */ int fdiskDeletePartitionSpec( PartitionSpec *spec, char *name ) { unsigned int j, k, found; found = 0; for (j=0; jnum && !found;) if (!strcmp(spec->entry[j].name, name)) found = 1; else j++; if (!found) return FDISK_ERR_BADNUM; else { /* cant delete immutable partitions */ if (spec->entry[j].partition.immutable) return FDISK_ERR_BADNUM; if (spec->entry[j].name) free(spec->entry[j].name); for (k=j; k < spec->num-1; k++) memcpy(&spec->entry[k], &spec->entry[k+1], sizeof(PartitionSpecEntry)); memset(&spec->entry[spec->num-1], 0, sizeof(PartitionSpecEntry)); spec->num--; } return FDISK_SUCCESS; } /* complete erase contents of a PartitionSpec - frees up names */ int fdiskWipePartitionSpec( PartitionSpec *spec ) { unsigned int i; for (i=0; inum; i++) free(spec->entry[i].name); memset(spec, 0, sizeof(PartitionSpec)); spec->num = 0; return FDISK_SUCCESS; } /* update 'original' drives in partitionspec, in case any were removed */ /* leave specs the user has added since we started alone */ int fdiskCleanOriginalSpecs( HardDrive **hdarr, unsigned int numhd, PartitionSpec *spec ) { unsigned int j, k, l; unsigned int drive, start, size; unsigned int tsize, tstart; unsigned int first, last; unsigned int remove; unsigned int found; Partition *p; for (j=0; jnum; ) if (spec->entry[j].status != REQUEST_ORIGINAL) { j++; continue; } else { p = &spec->entry[j].partition; fdiskGetCurrentDriveSet(&p->drive, &drive ); fdiskGetCurrentConstraint(&p->size , &size ); fdiskGetCurrentConstraint(&p->start, &start ); /* find the HardDrive containing the drive we want */ for ( l=0; lnum == drive) break; /* shouldnt happen */ if (l == numhd) return FDISK_ERR_BADNUM; else drive = l; /* see if the partition still exists */ remove = 0; found = 0; if (fdiskFirstPartition(hdarr[drive], &first)) { remove = 1; } else { fdiskLastPartition(hdarr[drive], &last); for (l=first; l <=last && !found; l++) { if (fdiskGetAttrPartition(hdarr[drive], l, &p) == FDISK_SUCCESS) { fdiskGetCurrentConstraint(&p->size , &tsize ); fdiskGetCurrentConstraint(&p->start, &tstart ); if (tstart == start && tsize == size) { found = 1; /* lets update partition info */ memcpy(&spec->entry[j].partition, p, sizeof(Partition)); } free(p); } } if (!found) remove = 1; } if (remove) { if (spec->entry[j].name) free(spec->entry[j].name); for (k=j; k < spec->num-1; k++) memcpy(&spec->entry[k], &spec->entry[k+1], sizeof(PartitionSpecEntry)); memset(&spec->entry[spec->num-1],0,sizeof(PartitionSpecEntry)); spec->num--; } else { j++; } } fdiskSortPartitionSpec( spec ); return FDISK_SUCCESS; } /* given a hard drive with original partitions, add to partition spec */ /* any user added partition specs are untouched */ int fdiskSetupPartitionSpec( HardDrive **hdarr, unsigned int numhd, PartitionSpec *spec ) { unsigned int first, last, i, j; int status; Partition *p; char *name; /* make sure there are any partitions to process */ status = 0; for (i=0; itype.current == LINUX_SWAP_PARTITION) fdiskMakeSwapSpecName( spec, &name); else if (p->type.current == LINUX_RAID_PARTITION) fdiskMakeRaidSpecName( spec, &name); else { name = malloc(16); sprintf(name, "Exist%03d%03d", hdarr[i]->num, j); } fdiskInsertPartitionSpec( spec, name, p, REQUEST_ORIGINAL ); free(name); free(p); } } } fdiskSortPartitionSpec( spec ); return FDISK_SUCCESS; } /* return specification based on mount point */ int fdiskReturnPartitionSpec( PartitionSpec *spec, char *name, Partition **p) { unsigned int j, found; found = 0; for (j=0; jnum && !found;) if (!strcmp(spec->entry[j].name, name)) found = 1; else j++; if (!found) return FDISK_ERR_BADNUM; else { *p = (Partition *) malloc( sizeof(Partition) ); memcpy(*p, &spec->entry[j].partition, sizeof(Partition)); return FDISK_SUCCESS; } } /* rename a spec */ int fdiskRenamePartitionSpec( PartitionSpec *spec, char *name, char *newname ) { unsigned int j, found; found = 0; for (j=0; jnum && !found;) if (!strcmp(spec->entry[j].name, name)) found = 1; else j++; if (!found) return FDISK_ERR_BADNUM; else { free(spec->entry[j].name); spec->entry[j].name = strdup(newname); return FDISK_SUCCESS; } } /* return specification based on mount point */ int fdiskModifyPartitionSpec( PartitionSpec *spec, char *name, Partition *p, unsigned int status) { unsigned int j, found; found = 0; for (j=0; jnum && !found;) if (!strcmp(spec->entry[j].name, name)) found = 1; else j++; if (!found) return FDISK_ERR_BADNUM; else { /* dont change immutable partitions! */ if (p->immutable) return FDISK_ERR_BADNUM; else { memcpy(&spec->entry[j].partition, p, sizeof(Partition)); spec->entry[j].status = status; fdiskSortPartitionSpec( spec ); return FDISK_SUCCESS; } } } /* make a unique name for a partition spec */ int fdiskMakeUniqSpecName( PartitionSpec *spec, char *base, char **name ) { int i; char *s; unsigned int j; s = malloc(4+strlen(base)); for (i=0; i < 1000; i++) { snprintf(s, 4+strlen(base), "%s%03d", base, i); if (fdiskIndexPartitionSpec(spec, s, &j) != FDISK_SUCCESS) break; } *name = s; return FDISK_SUCCESS; } /* make a unique name for a swap partition spec */ int fdiskMakeSwapSpecName( PartitionSpec *spec, char **name ) { int rc; rc = fdiskMakeUniqSpecName( spec, "Swap", name ); return rc; } /* make a unique name for a raid partition spec */ int fdiskMakeRaidSpecName( PartitionSpec *spec, char **name ) { int rc; rc = fdiskMakeUniqSpecName( spec, "Raid", name ); return rc; }