home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Chip 1998 February
/
CHIP_2_98.iso
/
misc
/
src
/
install
/
libfdisk
/
partspec.c
< prev
next >
Wrap
C/C++ Source or Header
|
1997-10-09
|
12KB
|
494 lines
/* handles the PartitionSpec type and operations we do on them */
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#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",
"Requested Cylinder",
"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; i<spec->num-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; j<spec->num && !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; j<spec->num && !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; j<spec->num && !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; i<spec->num; 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; j<spec->num; )
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; l<numhd; l++)
if (hdarr[l]->num == 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; i<numhd; i++)
if (fdiskFirstPartition(hdarr[i], &first ) == FDISK_SUCCESS) {
status = 1;
break;
}
/* no partitions to process */
if (status == 0)
return FDISK_SUCCESS;
/* go thru all drives and insert all pre-existing partitions */
for (i=0; i<numhd; i++) {
if (fdiskFirstPartition(hdarr[i], &first ) != FDISK_SUCCESS)
continue;
fdiskLastPartition(hdarr[i], &last );
/* insert existing partitions using a temporary name */
for (j=first; j <= last; j++) {
status = fdiskGetAttrPartition(hdarr[i], j, &p);
if (status == FDISK_SUCCESS) {
if (p->type.current == LINUX_SWAP_PARTITION)
fdiskMakeSwapSpecName( 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; j<spec->num && !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; j<spec->num && !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; j<spec->num && !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;
}