aboutsummaryrefslogtreecommitdiff
path: root/mpartition.c
diff options
context:
space:
mode:
Diffstat (limited to 'mpartition.c')
-rw-r--r--mpartition.c374
1 files changed, 132 insertions, 242 deletions
diff --git a/mpartition.c b/mpartition.c
index 1c50ef3..efc5d40 100644
--- a/mpartition.c
+++ b/mpartition.c
@@ -27,32 +27,20 @@
#include "plain_io.h"
#include "nameclash.h"
#include "buffer.h"
-#include "scsi.h"
#include "partition.h"
+#include "open_image.h"
+#include "lba.h"
#ifdef OS_linux
#include "linux/hdreg.h"
-
-#define _LINUX_STRING_H_
-#define kdev_t int
#include "linux/fs.h"
-#undef _LINUX_STRING_H_
-
#endif
-#define tolinear(x) \
-(sector(x)-1+(head(x)+cyl(x)*used_dev->heads)*used_dev->sectors)
-
-
-static __inline__ void print_hsc(hsc *h)
-{
- printf(" h=%d s=%d c=%d\n",
- head(*h), sector(*h), cyl(*h));
-}
-
-static void set_offset(hsc *h, unsigned long offset, int heads, int sectors)
+static void set_offset(hsc *h, unsigned long offset,
+ uint16_t heads, uint16_t sectors)
{
- int head, sector, cyl;
+ uint16_t head, sector;
+ unsigned int cyl;
if(! heads || !sectors)
head = sector = cyl = 0; /* linear mode */
@@ -61,20 +49,43 @@ static void set_offset(hsc *h, unsigned long offset, int heads, int sectors)
offset = offset / sectors;
head = offset % heads;
- cyl = offset / heads;
- if(cyl > 1023) cyl = 1023;
+ offset = offset / heads;
+ if(offset > 1023)
+ cyl = 1023;
+ else
+ cyl = (uint16_t) offset;
}
-
- h->head = head;
+ if(head > UINT8_MAX) {
+ /* sector or head out of range => linear mode */
+ head = sector = cyl = 0;
+ }
+ h->head = (uint8_t) head;
h->sector = ((sector+1) & 0x3f) | ((cyl & 0x300)>>2);
h->cyl = cyl & 0xff;
}
void setBeginEnd(struct partition *partTable,
- unsigned long begin, unsigned long end,
- unsigned int heads, unsigned int sectors,
- int activate, int type, int fat_bits)
+ uint32_t begin, uint32_t end,
+ uint16_t iheads, uint16_t isectors,
+ int activate, uint8_t type, unsigned int fat_bits)
{
+ uint8_t heads, sectors;
+
+ if(iheads > UINT8_MAX) {
+ fprintf(stderr,
+ "Too many heads for partition: %d\n",
+ iheads);
+ exit(1);
+ }
+ heads=(uint8_t) iheads;
+ if(isectors > UINT8_MAX) {
+ fprintf(stderr,
+ "Too many sectors for partition: %d\n",
+ isectors);
+ exit(1);
+ }
+ sectors=(uint8_t) isectors;
+
set_offset(&partTable->start, begin, heads, sectors);
set_offset(&partTable->end, end-1, heads, sectors);
set_dword(partTable->start_sect, begin);
@@ -125,7 +136,7 @@ void setBeginEnd(struct partition *partTable,
else if (fat_bits == 16)
/* FAT 16 partition */
type = 0x04; /* DOS FAT16, CHS */
- } else if (end < sectors * heads * 1024)
+ } else if (end < sectors * heads * 1024u)
/* FAT 12 or FAT16 partition above the 32M
* mark but below the 1024 cylinder mark.
* Indeed, there can be no CHS partition
@@ -137,83 +148,6 @@ void setBeginEnd(struct partition *partTable,
partTable->sys_ind = type;
}
-int consistencyCheck(struct partition *partTable, int doprint, int verbose,
- int *has_activated, unsigned int *last_end,
- unsigned int *j,
- struct device *used_dev, int target_partition)
-{
- int i;
- unsigned int inconsistency;
-
- *j = 0;
- *last_end = 1;
-
- /* quick consistency check */
- inconsistency = 0;
- *has_activated = 0;
- for(i=1; i<5; i++){
- if(!partTable[i].sys_ind)
- continue;
- if(partTable[i].boot_ind)
- (*has_activated)++;
- if((used_dev &&
- (used_dev->heads != head(partTable[i].end)+1 ||
- used_dev->sectors != sector(partTable[i].end))) ||
- sector(partTable[i].start) != 1){
- fprintf(stderr,
- "Partition %d is not aligned\n",
- i);
- inconsistency=1;
- }
-
- if(*j &&
- *last_end > BEGIN(partTable[i])) {
- fprintf(stderr,
- "Partitions %d and %d badly ordered or overlapping\n",
- *j,i);
- inconsistency=1;
- }
-
- *last_end = END(partTable[i]);
- *j = i;
-
- if(used_dev &&
- cyl(partTable[i].start) != 1023 &&
- tolinear(partTable[i].start) != BEGIN(partTable[i])) {
- fprintf(stderr,
- "Start position mismatch for partition %d\n",
- i);
- inconsistency=1;
- }
- if(used_dev &&
- cyl(partTable[i].end) != 1023 &&
- tolinear(partTable[i].end)+1 != END(partTable[i])) {
- fprintf(stderr,
- "End position mismatch for partition %d\n",
- i);
- inconsistency=1;
- }
-
- if(doprint && verbose) {
- if(i==target_partition)
- putchar('*');
- else
- putchar(' ');
- printf("Partition %d\n",i);
-
- printf(" active=%x\n", partTable[i].boot_ind);
- printf(" start:");
- print_hsc(&partTable[i].start);
- printf(" type=0x%x\n", partTable[i].sys_ind);
- printf(" end:");
- print_hsc(&partTable[i].end);
- printf(" start=%d\n", BEGIN(partTable[i]));
- printf(" nr=%d\n", _DWORD(partTable[i].nr_sects));
- printf("\n");
- }
- }
- return inconsistency;
-}
/* setsize function. Determines scsicam mapping if this cannot be inferred from
* any existing partitions. Shamelessly snarfed from the Linux kernel ;-) */
@@ -254,7 +188,7 @@ int consistencyCheck(struct partition *partTable, int doprint, int verbose,
static int setsize(unsigned long capacity,unsigned int *cyls,
uint16_t *hds, uint16_t *secs) {
- unsigned int rv = 0;
+ int rv = 0;
unsigned long heads, sectors, cylinders, temp;
cylinders = 1024L; /* Set number of cylinders to max */
@@ -273,15 +207,15 @@ static int setsize(unsigned long capacity,unsigned int *cyls,
cylinders = capacity / temp;/* Compute number of cylinders */
}
}
- if (cylinders == 0) rv=(unsigned)-1;/* Give error if 0 cylinders */
+ if (cylinders == 0) rv=-1;/* Give error if 0 cylinders */
*cyls = (unsigned int) cylinders; /* Stuff return values */
- *secs = (unsigned int) sectors;
- *hds = (unsigned int) heads;
+ *secs = (uint16_t) sectors;
+ *hds = (uint16_t) heads;
return(rv);
}
-static void setsize0(unsigned long capacity,unsigned int *cyls,
+static void setsize0(uint32_t capacity,unsigned int *cyls,
uint16_t *hds, uint16_t *secs)
{
int r;
@@ -325,9 +259,9 @@ void mpartition(int argc, char **argv, int dummy UNUSEDP)
Stream_t *Stream;
unsigned int dummy2;
- unsigned int i,j;
+ unsigned int i;
- int sec_per_cyl;
+ uint16_t sec_per_cyl;
int doprint = 0;
int verbose = 0;
int create = 0;
@@ -335,24 +269,26 @@ void mpartition(int argc, char **argv, int dummy UNUSEDP)
unsigned int length = 0;
int do_remove = 0;
int initialize = 0;
- unsigned int tot_sectors=0;
- int type = 0;
+
+ uint32_t tot_sectors=0;
+ /* Needs to be long due to BLKGETSIZE ioctl */
+
+ uint8_t type = 0;
int begin_set = 0;
int size_set = 0;
int end_set = 0;
- unsigned int last_end = 0;
int activate = 0;
int has_activated = 0;
int inconsistency=0;
unsigned int begin=0;
unsigned int end=0;
- int sizetest=0;
int dirty = 0;
- int open2flags = NO_OFFSET;
+ int open2flags = 0;
int c;
struct device used_dev;
- int argtracks, argheads, argsectors;
+ unsigned int argtracks;
+ uint16_t argheads, argsectors;
char drive, name[EXPAND_BUF];
unsigned char buf[512];
@@ -360,6 +296,7 @@ void mpartition(int argc, char **argv, int dummy UNUSEDP)
struct device *dev;
char errmsg[2100];
char *bootSector=0;
+ struct partition *tpartition;
argtracks = 0;
argheads = 0;
@@ -413,17 +350,17 @@ void mpartition(int argc, char **argv, int dummy UNUSEDP)
/* could be abused to "manually" create
* extended partitions */
open2flags |= NO_PRIV;
- type = strtoi(optarg, &endptr, 0);
+ type = strtou8(optarg, &endptr, 0);
break;
case 't':
- argtracks = atoi(optarg);
+ argtracks = atoui(optarg);
break;
case 'h':
- argheads = atoi(optarg);
+ argheads = atou16(optarg);
break;
case 's':
- argsectors = atoi(optarg);
+ argsectors = atou16(optarg);
break;
case 'f':
@@ -436,28 +373,19 @@ void mpartition(int argc, char **argv, int dummy UNUSEDP)
case 'v':
verbose++;
break;
- case 'S':
- /* testing only */
- /* could be abused to create partitions
- * extending beyond the actual size of the
- * device */
- open2flags |= NO_PRIV;
- tot_sectors = strtoui(optarg, &endptr, 0);
- sizetest = 1;
- break;
case 'b':
begin_set = 1;
begin = strtoui(optarg, &endptr, 0);
break;
case 'l':
size_set = 1;
- length = strtoui(optarg, &endptr, 0);
+ length = parseSize(optarg);
break;
default:
usage(1);
}
- check_number_parse_errno(c, optarg, endptr);
+ check_number_parse_errno((char)c, optarg, endptr);
}
if (argc - optind != 1 ||
@@ -497,8 +425,9 @@ void mpartition(int argc, char **argv, int dummy UNUSEDP)
#ifdef USING_NEW_VOLD
strcpy(name, getVoldName(dev, name));
#endif
- Stream = SimpleFileOpen(&used_dev, dev, name, mode,
- errmsg, open2flags, 1, 0);
+ Stream = OpenImage(&used_dev, dev, name, mode, errmsg,
+ open2flags | SKIP_PARTITION | ALWAYS_GET_GEOMETRY,
+ mode, NULL, NULL, NULL);
if (!Stream) {
#ifdef HAVE_SNPRINTF
@@ -510,36 +439,10 @@ void mpartition(int argc, char **argv, int dummy UNUSEDP)
continue;
}
-
- /* try to find out the size */
- if(!sizetest)
- tot_sectors = 0;
- if(IS_SCSI(dev)) {
- unsigned char cmd[10];
- unsigned char data[10];
- cmd[0] = SCSI_READ_CAPACITY;
- memset ((void *) &cmd[2], 0, 8);
- memset ((void *) &data[0], 137, 10);
- scsi_cmd(get_fd(Stream), cmd, 10, SCSI_IO_READ,
- data, 10, get_extra_data(Stream));
-
- tot_sectors = 1 +
- (data[0] << 24) +
- (data[1] << 16) +
- (data[2] << 8) +
- (data[3] );
- if(verbose)
- printf("%d sectors in total\n", tot_sectors);
- }
-
-#ifdef OS_linux
- if (tot_sectors == 0) {
- ioctl(get_fd(Stream), BLKGETSIZE, &tot_sectors);
- }
-#endif
+ tot_sectors = used_dev.tot_sectors;
/* read the partition table */
- if (READS(Stream, (char *) buf, 0, 512) != 512 && !initialize){
+ if (PREADS(Stream, (char *) buf, 0, 512) != 512 && !initialize){
#ifdef HAVE_SNPRINTF
snprintf(errmsg, sizeof(errmsg)-1,
"Error reading from '%s', wrong parameters?",
@@ -595,12 +498,13 @@ void mpartition(int argc, char **argv, int dummy UNUSEDP)
inconsistency = 1;
}
+ tpartition=&partTable[dev->partition];
if(do_remove){
- if(!partTable[dev->partition].sys_ind)
+ if(!tpartition->sys_ind)
fprintf(stderr,
"Partition for drive %c: does not exist\n",
drive);
- if((partTable[dev->partition].sys_ind & 0x3f) == 5) {
+ if((tpartition->sys_ind & 0x3f) == 5) {
fprintf(stderr,
"Partition for drive %c: may be an extended partition\n",
drive);
@@ -608,69 +512,59 @@ void mpartition(int argc, char **argv, int dummy UNUSEDP)
"Use the -f flag to remove it anyways\n");
inconsistency = 1;
}
- memset(&partTable[dev->partition], 0, sizeof(*partTable));
+ memset(tpartition, 0, sizeof(*tpartition));
}
- if(create && partTable[dev->partition].sys_ind) {
+ if(create && tpartition->sys_ind) {
fprintf(stderr,
"Partition for drive %c: already exists\n", drive);
fprintf(stderr,
"Use the -r flag to remove it before attempting to recreate it\n");
}
+ /* if number of heads and sectors not known yet, set "reasonable"
+ * defaults */
+ compute_lba_geom_from_tot_sectors(&used_dev);
- /* find out number of heads and sectors, and whether there is
- * any activated partition */
+ /* find out whether there is any activated partition. Moreover
+ * if no offset of a partition to be created have been
+ * specificed, find out whether it may be placed between the
+ * preceding and following partition already existing */
has_activated = 0;
for(i=1; i<5; i++){
- if(!partTable[i].sys_ind)
+ struct partition *partition=&partTable[i];
+ if(!partition->sys_ind)
continue;
- if(partTable[i].boot_ind)
+ if(partition->boot_ind)
has_activated++;
- /* set geometry from entry */
- if (!used_dev.heads)
- used_dev.heads = head(partTable[i].end)+1;
- if(!used_dev.sectors)
- used_dev.sectors = sector(partTable[i].end);
if(i<dev->partition && !begin_set)
- begin = END(partTable[i]);
+ begin = END(partition);
if(i>dev->partition && !end_set && !size_set) {
- end = BEGIN(partTable[i]);
+ end = BEGIN(partition);
end_set = 1;
}
}
-#ifdef OS_linux
- if(!used_dev.sectors && !used_dev.heads) {
- if(!IS_SCSI(dev)) {
- struct hd_geometry geom;
- if(ioctl(get_fd(Stream), HDIO_GETGEO, &geom) == 0) {
- used_dev.heads = geom.heads;
- used_dev.sectors = geom.sectors;
- }
- }
- }
-#endif
-
if(!used_dev.sectors && !used_dev.heads) {
- if(tot_sectors)
- setsize0(tot_sectors,&dummy2,&used_dev.heads,
+ if(tot_sectors) {
+ setsize0((uint32_t)tot_sectors,&dummy2,&used_dev.heads,
&used_dev.sectors);
- else {
+ } else {
used_dev.heads = 64;
used_dev.sectors = 32;
}
}
if(verbose)
- fprintf(stderr,"sectors: %d heads: %d %d\n",
+ fprintf(stderr,"sectors: %d heads: %d %u\n",
used_dev.sectors, used_dev.heads, tot_sectors);
sec_per_cyl = used_dev.sectors * used_dev.heads;
if(create) {
- if(!end_set && tot_sectors) {
+ unsigned int overlap;
+ if(!end_set && !size_set && tot_sectors) {
end = tot_sectors - tot_sectors % sec_per_cyl;
end_set = 1;
}
@@ -679,79 +573,61 @@ void mpartition(int argc, char **argv, int dummy UNUSEDP)
* the disk, keep one track unused to allow place for
* the master boot record */
if(!begin && !begin_set)
- begin = used_dev.sectors;
- if(!size_set && used_dev.tracks) {
- size_set = 2;
- length = sec_per_cyl * used_dev.tracks;
-
- /* round the size in order to take
- * into account any "hidden" sectors */
-
- /* do we anchor this at the beginning ?*/
- if(begin_set || dev->partition <= 2 || !end_set)
- length -= begin % sec_per_cyl;
- else if(end - length < begin)
- /* truncate any overlap */
- length = end - begin;
- }
+ begin = used_dev.sectors ? used_dev.sectors : 2048;
+
+ /* Do not try to align partitions (other than first) on track
+ * boundaries here: apparently this was a thing of the past */
+
if(size_set) {
- if(!begin_set && dev->partition >2 && end_set)
- begin = end - length;
- else
- end = begin + length;
+ end = begin + length;
} else if(!end_set) {
fprintf(stderr,"Unknown size\n");
exit(1);
}
- setBeginEnd(&partTable[dev->partition], begin, end,
+ /* Make sure partition boundaries are correctly ordered
+ * (end > begin) */
+ if(begin >= end) {
+ fprintf(stderr, "Begin larger than end\n");
+ exit(1);
+ }
+
+ /* Check whether new partition doesn't overlap with
+ * any of those already in place */
+ if((overlap=findOverlap(partTable, 4, begin, end))) {
+ fprintf(stderr,
+ "Partition would overlap with partition %d\n",
+ overlap);
+ exit(1);
+ }
+
+ setBeginEnd(tpartition, begin, end,
used_dev.heads, used_dev.sectors,
!has_activated, type,
- dev->fat_bits);
+ abs(dev->fat_bits));
}
if(activate) {
- if(!partTable[dev->partition].sys_ind) {
+ if(!tpartition->sys_ind) {
fprintf(stderr,
"Partition for drive %c: does not exist\n",
drive);
} else {
switch(activate) {
case 1:
- partTable[dev->partition].boot_ind=0x80;
+ tpartition->boot_ind=0x80;
break;
case -1:
- partTable[dev->partition].boot_ind=0x00;
+ tpartition->boot_ind=0x00;
break;
}
}
}
-
inconsistency |= consistencyCheck(partTable, doprint, verbose,
- &has_activated, &last_end, &j,
+ &has_activated, tot_sectors,
&used_dev, dev->partition);
- if(doprint && !inconsistency && partTable[dev->partition].sys_ind) {
- printf("The following command will recreate the partition for drive %c:\n",
- drive);
- used_dev.tracks =
- (_DWORD(partTable[dev->partition].nr_sects) +
- (BEGIN(partTable[dev->partition]) % sec_per_cyl)) /
- sec_per_cyl;
- printf("mpartition -c -t %d -h %d -s %d -b %u %c:\n",
- used_dev.tracks, used_dev.heads, used_dev.sectors,
- BEGIN(partTable[dev->partition]), drive);
- }
-
- if(tot_sectors && last_end >tot_sectors) {
- fprintf(stderr,
- "Partition %d exceeds beyond end of disk\n",
- j);
- exit(1);
- }
-
-
switch(has_activated) {
case 0:
fprintf(stderr,
@@ -771,17 +647,31 @@ void mpartition(int argc, char **argv, int dummy UNUSEDP)
if(inconsistency && !force) {
fprintf(stderr,
"inconsistency detected!\n" );
- if(dirty)
+ if(dirty) {
fprintf(stderr,
"Retry with the -f switch to go ahead anyways\n");
- exit(1);
+ exit(1);
+ }
+ }
+
+ if(doprint && tpartition->sys_ind) {
+ printf("The following command will recreate the partition for drive %c:\n",
+ drive);
+ used_dev.tracks =
+ (_DWORD(tpartition->nr_sects) +
+ (BEGIN(tpartition) % sec_per_cyl)) /
+ sec_per_cyl;
+ printf("mpartition -c -b %d -l %d -t %d -h %d -s %d -b %u %c:\n",
+ BEGIN(tpartition), PART_SIZE(tpartition),
+ used_dev.tracks, used_dev.heads, used_dev.sectors,
+ BEGIN(tpartition), drive);
}
if(dirty) {
/* write data back to the disk */
if(verbose>=2)
print_sector("Writing sector", buf, 512);
- if (WRITES(Stream, (char *) buf, 0, 512) != 512) {
+ if (PWRITES(Stream, (char *) buf, 0, 512) != 512) {
fprintf(stderr,"Error writing partition table");
exit(1);
}