458 lines
9.8 KiB
C
458 lines
9.8 KiB
C
/* partition 1.13 - Make a partition table Author: Kees J. Bot
|
|
* 27 Apr 1992
|
|
*/
|
|
#define nil ((void*)0)
|
|
#include <stdio.h>
|
|
#include <sys/types.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <fcntl.h>
|
|
#include <sys/stat.h>
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
#include <sys/ioctl.h>
|
|
#include <limits.h>
|
|
#include <stdint.h>
|
|
#include <assert.h>
|
|
|
|
#ifdef __minix
|
|
#include <machine/partition.h>
|
|
#include <minix/config.h>
|
|
#include <minix/const.h>
|
|
#include <minix/partition.h>
|
|
#else
|
|
#include "partition.h"
|
|
#define NR_PARTITIONS 4
|
|
#endif
|
|
|
|
#define SECTOR_SIZE 512
|
|
|
|
#define arraysize(a) (sizeof(a)/sizeof((a)[0]))
|
|
#define arraylimit(a) ((a) + arraysize(a))
|
|
|
|
char *arg0;
|
|
|
|
void report(const char *label)
|
|
{
|
|
fprintf(stderr, "%s: %s: %s\n", arg0, label, strerror(errno));
|
|
}
|
|
|
|
void fatal(const char *label)
|
|
{
|
|
report(label);
|
|
exit(1);
|
|
}
|
|
|
|
int aflag; /* Add a new partition to the current table. */
|
|
int mflag; /* Minix rules, no need for alignment. */
|
|
int rflag; /* Report current partitions. */
|
|
int fflag; /* Force making a table even if too small. */
|
|
int nflag; /* Play-act, don't really do it. */
|
|
|
|
int cylinders, heads, sectors; /* Device's geometry */
|
|
int pad; /* Partitions must be padded. */
|
|
|
|
/* Descriptions of the device to divide and the partitions to make, including
|
|
* gaps between partitions.
|
|
*/
|
|
char *device;
|
|
struct part_entry primary, table[2 * NR_PARTITIONS + 1];
|
|
int npart;
|
|
|
|
/* Extra flags at construction time. */
|
|
#define EXPAND_FLAG 0x01 /* Add the remaining sectors to this one */
|
|
#define EXIST_FLAG 0x02 /* Use existing partition */
|
|
|
|
void find_exist(struct part_entry *exist, int sysind, int nr)
|
|
{
|
|
int f;
|
|
uint16_t signature;
|
|
struct part_entry oldtable[NR_PARTITIONS];
|
|
int n, i;
|
|
uint32_t minlow, curlow;
|
|
struct part_entry *cur;
|
|
char *nr_s[] = { "", "second ", "third ", "fourth" };
|
|
|
|
if ((f= open(device, O_RDONLY)) < 0
|
|
|
|
|| lseek(f, (off_t) PART_TABLE_OFF, SEEK_SET) == -1
|
|
|
|
|| read(f, oldtable, sizeof(oldtable)) < 0
|
|
|
|
|| read(f, &signature, sizeof(signature)) < 0
|
|
|
|
|| close(f) < 0
|
|
) fatal(device);
|
|
|
|
minlow= 0;
|
|
n= 0;
|
|
for (;;) {
|
|
curlow= -1;
|
|
cur= nil;
|
|
for (i= 0; i < NR_PARTITIONS; i++) {
|
|
if (signature == 0xAA55
|
|
&& oldtable[i].sysind != NO_PART
|
|
&& oldtable[i].lowsec >= minlow
|
|
&& oldtable[i].lowsec < curlow
|
|
) {
|
|
cur= &oldtable[i];
|
|
curlow= oldtable[i].lowsec;
|
|
}
|
|
}
|
|
if (n == nr) break;
|
|
n++;
|
|
minlow= curlow+1;
|
|
}
|
|
|
|
if (cur == nil || cur->sysind != sysind) {
|
|
fprintf(stderr,
|
|
"%s: Can't find a %sexisting partition of type 0x%02X\n",
|
|
arg0, nr_s[nr], sysind);
|
|
exit(1);
|
|
}
|
|
*exist = *cur;
|
|
}
|
|
|
|
void write_table(void)
|
|
{
|
|
int f;
|
|
uint16_t signature= 0xAA55;
|
|
struct part_entry newtable[NR_PARTITIONS];
|
|
int i;
|
|
|
|
if (nflag) {
|
|
printf("(Table not written)\n");
|
|
return;
|
|
}
|
|
|
|
for (i= 0; i < NR_PARTITIONS; i++) newtable[i]= table[1 + 2*i];
|
|
|
|
/* we have a abstract struct but it must conform to a certain
|
|
* reality that will never change (in-MBR sizes and offsets).
|
|
* each partition entry is 16 bytes and there are 4 of them.
|
|
* this also determines the signature offset.
|
|
*/
|
|
assert(sizeof(struct part_entry) == 16);
|
|
assert(sizeof(newtable) == 64);
|
|
|
|
if ((f= open(device, O_WRONLY)) < 0
|
|
|
|
|| lseek(f, (off_t) PART_TABLE_OFF, SEEK_SET) == -1
|
|
|
|
|| write(f, newtable, sizeof(newtable)) < 0
|
|
|
|
|| write(f, &signature, sizeof(signature)) < 0
|
|
|
|
|| close(f) < 0
|
|
) fatal(device);
|
|
}
|
|
|
|
void sec2dos(unsigned long sec, unsigned char *dos)
|
|
/* Translate a sector number into the three bytes DOS uses. */
|
|
{
|
|
unsigned secspcyl= heads * sectors;
|
|
unsigned cyl;
|
|
|
|
cyl= sec / secspcyl;
|
|
dos[2]= cyl;
|
|
dos[1]= ((sec % sectors) + 1) | ((cyl >> 2) & 0xC0);
|
|
dos[0]= (sec % secspcyl) / sectors;
|
|
}
|
|
|
|
void show_chs(unsigned long pos)
|
|
{
|
|
int cyl, head, sec;
|
|
|
|
if (pos == -1) {
|
|
cyl= head= 0;
|
|
sec= -1;
|
|
} else {
|
|
cyl= pos / (heads * sectors);
|
|
head= (pos / sectors) - (cyl * heads);
|
|
sec= pos % sectors;
|
|
}
|
|
printf(" %4d/%03d/%02d", cyl, head, sec);
|
|
}
|
|
|
|
void show_part(struct part_entry *p)
|
|
{
|
|
static int banner= 0;
|
|
int n;
|
|
|
|
n= p - table;
|
|
if ((n % 2) == 0) return;
|
|
|
|
if (!banner) {
|
|
printf(
|
|
"Part First Last Base Size Kb\n");
|
|
banner= 1;
|
|
}
|
|
|
|
printf("%3d ", (n-1) / 2);
|
|
show_chs(p->lowsec);
|
|
show_chs(p->lowsec + p->size - 1);
|
|
printf(" %8lu %8lu %7lu\n", p->lowsec, p->size, p->size / 2);
|
|
}
|
|
|
|
void usage(void)
|
|
{
|
|
fprintf(stderr,
|
|
"Usage: partition [-mfn] device [type:]length[+*] ...\n");
|
|
exit(1);
|
|
}
|
|
|
|
#define between(a, c, z) ((unsigned) ((c) - (a)) <= ((z) - (a)))
|
|
|
|
void parse(char *descr)
|
|
{
|
|
int seen= 0, sysind, flags, c;
|
|
unsigned long lowsec, size;
|
|
|
|
lowsec= 0;
|
|
|
|
if (strchr(descr, ':') == nil) {
|
|
/* A hole. */
|
|
if ((npart % 2) != 0) {
|
|
fprintf(stderr, "%s: Two holes can't be adjacent.\n",
|
|
arg0);
|
|
exit(1);
|
|
}
|
|
sysind= NO_PART;
|
|
seen|= 1;
|
|
} else {
|
|
/* A partition. */
|
|
if ((npart % 2) == 0) {
|
|
/* Need a hole before this partition. */
|
|
if (npart == 0) {
|
|
/* First hole contains the partition table. */
|
|
table[0].size= 1;
|
|
}
|
|
npart++;
|
|
}
|
|
sysind= 0;
|
|
for (;;) {
|
|
c= *descr++;
|
|
if (between('0', c, '9'))
|
|
c= (c - '0') + 0x0;
|
|
else
|
|
if (between('a', c, 'z'))
|
|
c= (c - 'a') + 0xa;
|
|
else
|
|
if (between('A', c, 'Z'))
|
|
c= (c - 'A') + 0xA;
|
|
else
|
|
break;
|
|
sysind= 0x10 * sysind + c;
|
|
seen|= 1;
|
|
}
|
|
if (c != ':') usage();
|
|
}
|
|
|
|
flags= 0;
|
|
|
|
if (strncmp(descr, "exist", 5) == 0 && (npart % 2) == 1) {
|
|
struct part_entry exist;
|
|
|
|
find_exist(&exist, sysind, (npart - 1) / 2);
|
|
sysind= exist.sysind;
|
|
lowsec= exist.lowsec;
|
|
size= exist.size;
|
|
flags |= EXIST_FLAG;
|
|
descr += 5;
|
|
c= *descr++;
|
|
seen|= 2;
|
|
} else {
|
|
size= 0;
|
|
while (between('0', (c= *descr++), '9')) {
|
|
size= 10 * size + (c - '0');
|
|
seen|= 2;
|
|
}
|
|
}
|
|
|
|
for (;;) {
|
|
if (c == '*')
|
|
flags|= ACTIVE_FLAG;
|
|
else
|
|
if (c == '+' && !(flags & EXIST_FLAG))
|
|
flags|= EXPAND_FLAG;
|
|
else
|
|
break;
|
|
c= *descr++;
|
|
}
|
|
|
|
if (seen != 3 || c != 0) usage();
|
|
|
|
if (npart == arraysize(table)) {
|
|
fprintf(stderr, "%s: too many partitions, only %d possible.\n",
|
|
arg0, NR_PARTITIONS);
|
|
exit(1);
|
|
}
|
|
table[npart].bootind= flags;
|
|
table[npart].sysind= sysind;
|
|
table[npart].lowsec= lowsec;
|
|
table[npart].size= size;
|
|
npart++;
|
|
}
|
|
|
|
void geometry(void)
|
|
/* Get the geometry of the drive the device lives on, and the base and size
|
|
* of the device.
|
|
*/
|
|
{
|
|
int fd;
|
|
struct stat sb;
|
|
|
|
if ((fd= open(device, O_RDONLY)) < 0) fatal(device);
|
|
|
|
#ifdef __minix
|
|
struct part_geom geometry;
|
|
|
|
|
|
/* Get the geometry of the drive, and the device's base and size. */
|
|
if (ioctl(fd, DIOCGETP, &geometry) < 0)
|
|
{
|
|
/* Use the same fake geometry as part. */
|
|
if (fstat(fd, &sb) < 0)
|
|
fatal(device);
|
|
geometry.base= ((u64_t)(0));
|
|
geometry.size= ((u64_t)(sb.st_size));
|
|
geometry.sectors= 32;
|
|
geometry.heads= 64;
|
|
geometry.cylinders= (sb.st_size-1)/SECTOR_SIZE/
|
|
(geometry.sectors*geometry.heads) + 1;
|
|
}
|
|
primary.lowsec= (unsigned long)(geometry.base / SECTOR_SIZE);
|
|
primary.size = (unsigned long)(geometry.size / SECTOR_SIZE);
|
|
cylinders= geometry.cylinders;
|
|
heads= geometry.heads;
|
|
sectors= geometry.sectors;
|
|
#else
|
|
if (fstat(fd, &sb) < 0) fatal(device);
|
|
primary.lowsec= 0;
|
|
primary.size= sb.st_size / SECTOR_SIZE;
|
|
heads= 64;
|
|
sectors= 32;
|
|
cylinders= (sb.st_size-1) / SECTOR_SIZE / (sectors*heads) + 1;
|
|
#endif
|
|
|
|
close(fd);
|
|
|
|
/* Is this a primary partition table? If so then pad partitions. */
|
|
pad= (!mflag && primary.lowsec == 0);
|
|
}
|
|
|
|
void boundary(struct part_entry *pe, int exp)
|
|
/* Expand or reduce a primary partition to a track or cylinder boundary to
|
|
* avoid giving the fdisk's of simpler operating systems a fit.
|
|
*/
|
|
{
|
|
unsigned n;
|
|
|
|
n= !pad ? 1 : pe == &table[0] ? sectors : heads * sectors;
|
|
if (exp) pe->size+= n - 1;
|
|
pe->size= ((pe->lowsec + pe->size) / n * n) - pe->lowsec;
|
|
}
|
|
|
|
void distribute(void)
|
|
/* Fit the partitions onto the device. Try to start and end them on a
|
|
* cylinder boundary if so required. The first partition is to start on
|
|
* track 1, not on cylinder 1.
|
|
*/
|
|
{
|
|
struct part_entry *pe, *exp;
|
|
long count;
|
|
unsigned long base, oldbase;
|
|
|
|
do {
|
|
exp= nil;
|
|
base= primary.lowsec;
|
|
count= primary.size;
|
|
|
|
for (pe= table; pe < arraylimit(table); pe++) {
|
|
oldbase= base;
|
|
if (pe->bootind & EXIST_FLAG) {
|
|
if (base > pe->lowsec) {
|
|
fprintf(stderr,
|
|
"%s: fixed partition %ld is preceded by too big partitions/holes\n",
|
|
arg0, ((pe - table) - 1) / 2);
|
|
exit(1);
|
|
}
|
|
exp= nil; /* XXX - Extend before? */
|
|
} else {
|
|
pe->lowsec= base;
|
|
boundary(pe, 1);
|
|
if (pe->bootind & EXPAND_FLAG) exp= pe;
|
|
}
|
|
base= pe->lowsec + pe->size;
|
|
count-= base - oldbase;
|
|
}
|
|
if (count < 0) {
|
|
if (fflag) break;
|
|
fprintf(stderr, "%s: %s is %ld sectors too small\n",
|
|
arg0, device, -count);
|
|
exit(1);
|
|
}
|
|
if (exp != nil) {
|
|
/* Add leftover space to the partition marked for
|
|
* expanding.
|
|
*/
|
|
exp->size+= count;
|
|
boundary(exp, 0);
|
|
exp->bootind&= ~EXPAND_FLAG;
|
|
}
|
|
} while (exp != nil);
|
|
|
|
for (pe= table; pe < arraylimit(table); pe++) {
|
|
if (pe->sysind == NO_PART) {
|
|
memset(pe, 0, sizeof(*pe));
|
|
} else {
|
|
sec2dos(pe->lowsec, &pe->start_head);
|
|
sec2dos(pe->lowsec + pe->size - 1, &pe->last_head);
|
|
pe->bootind&= ACTIVE_FLAG;
|
|
}
|
|
show_part(pe);
|
|
}
|
|
}
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
int i;
|
|
|
|
if ((arg0= strrchr(argv[0], '/')) == nil) arg0= argv[0]; else arg0++;
|
|
|
|
i= 1;
|
|
while (i < argc && argv[i][0] == '-') {
|
|
char *opt= argv[i++] + 1;
|
|
|
|
if (opt[0] == '-' && opt[1] == 0) break;
|
|
|
|
while (*opt != 0) switch (*opt++) {
|
|
case 'a': aflag= 1; break;
|
|
case 'm': mflag= 1; break;
|
|
case 'r': rflag= 1; break;
|
|
case 'f': fflag= 1; break;
|
|
case 'n': nflag= 1; break;
|
|
default: usage();
|
|
}
|
|
}
|
|
|
|
if (rflag) {
|
|
if (aflag) usage();
|
|
if ((argc - i) != 1) usage();
|
|
fprintf(stderr, "%s: -r is not yet implemented\n", __func__);
|
|
exit(1);
|
|
} else {
|
|
if ((argc - i) < 1) usage();
|
|
if (aflag) fprintf(stderr, "%s: -a is not yet implemented\n", __func__);
|
|
|
|
device= argv[i++];
|
|
geometry();
|
|
|
|
while (i < argc) parse(argv[i++]);
|
|
|
|
distribute();
|
|
write_table();
|
|
}
|
|
exit(0);
|
|
}
|