/*
|
/*
|
* mkpart.c -- make partitions on a disk
|
* mkpart.c -- make partitions on a disk
|
*/
|
*/
|
|
|
|
|
#include <stdio.h>
|
#include <stdio.h>
|
#include <stdlib.h>
|
#include <stdlib.h>
|
#include <string.h>
|
#include <string.h>
|
#include <stdarg.h>
|
#include <stdarg.h>
|
|
|
|
|
#define SECTOR_SIZE 512
|
#define SECTOR_SIZE 512
|
#define NPE (SECTOR_SIZE / sizeof(PartEntry))
|
#define NPE (SECTOR_SIZE / sizeof(PartEntry))
|
#define DESCR_SIZE 20
|
#define DESCR_SIZE 20
|
|
|
#define LINE_SIZE 100
|
#define LINE_SIZE 100
|
|
|
|
|
unsigned char buf[32 * SECTOR_SIZE];
|
unsigned char buf[32 * SECTOR_SIZE];
|
|
|
|
|
typedef struct {
|
typedef struct {
|
unsigned int type;
|
unsigned int type;
|
unsigned int start;
|
unsigned int start;
|
unsigned int size;
|
unsigned int size;
|
char descr[DESCR_SIZE];
|
char descr[DESCR_SIZE];
|
} PartEntry;
|
} PartEntry;
|
|
|
PartEntry ptr[NPE];
|
PartEntry ptr[NPE];
|
|
|
|
|
/**************************************************************/
|
/**************************************************************/
|
|
|
|
|
void error(char *fmt, ...) {
|
void error(char *fmt, ...) {
|
va_list ap;
|
va_list ap;
|
|
|
va_start(ap, fmt);
|
va_start(ap, fmt);
|
printf("Error: ");
|
printf("Error: ");
|
vprintf(fmt, ap);
|
vprintf(fmt, ap);
|
printf("\n");
|
printf("\n");
|
va_end(ap);
|
va_end(ap);
|
exit(1);
|
exit(1);
|
}
|
}
|
|
|
|
|
/**************************************************************/
|
/**************************************************************/
|
|
|
|
|
void convertNumber(unsigned char *p, unsigned int val) {
|
void convertNumber(unsigned char *p, unsigned int val) {
|
*(p + 0) = val >> 24;
|
*(p + 0) = val >> 24;
|
*(p + 1) = val >> 16;
|
*(p + 1) = val >> 16;
|
*(p + 2) = val >> 8;
|
*(p + 2) = val >> 8;
|
*(p + 3) = val >> 0;
|
*(p + 3) = val >> 0;
|
}
|
}
|
|
|
|
|
void convertPartitionTable(PartEntry *e, int n) {
|
void convertPartitionTable(PartEntry *e, int n) {
|
int i;
|
int i;
|
unsigned char *p;
|
unsigned char *p;
|
|
|
for (i = 0; i < n; i++) {
|
for (i = 0; i < n; i++) {
|
p = (unsigned char *) &e[i];
|
p = (unsigned char *) &e[i];
|
convertNumber(p + 0, e[i].type);
|
convertNumber(p + 0, e[i].type);
|
convertNumber(p + 4, e[i].start);
|
convertNumber(p + 4, e[i].start);
|
convertNumber(p + 8, e[i].size);
|
convertNumber(p + 8, e[i].size);
|
}
|
}
|
}
|
}
|
|
|
|
|
/**************************************************************/
|
/**************************************************************/
|
|
|
|
|
int parseNumber(char **pc, unsigned int *pi) {
|
int parseNumber(char **pc, unsigned int *pi) {
|
char *p;
|
char *p;
|
unsigned int base, dval;
|
unsigned int base, dval;
|
unsigned int n;
|
unsigned int n;
|
|
|
p = *pc;
|
p = *pc;
|
while (*p == ' ' || *p == '\t') {
|
while (*p == ' ' || *p == '\t') {
|
p++;
|
p++;
|
}
|
}
|
if (*p == '\0' || *p == '\n') {
|
if (*p == '\0' || *p == '\n') {
|
printf("Error: number is missing!\n");
|
printf("Error: number is missing!\n");
|
return 0;
|
return 0;
|
}
|
}
|
base = 10;
|
base = 10;
|
if (*p == '0') {
|
if (*p == '0') {
|
p++;
|
p++;
|
if (*p != '\0' && *p != '\n') {
|
if (*p != '\0' && *p != '\n') {
|
if (*p == 'x' || *p == 'X') {
|
if (*p == 'x' || *p == 'X') {
|
base = 16;
|
base = 16;
|
p++;
|
p++;
|
} else {
|
} else {
|
base = 8;
|
base = 8;
|
}
|
}
|
}
|
}
|
}
|
}
|
n = 0;
|
n = 0;
|
while ((*p >= '0' && *p <= '9') ||
|
while ((*p >= '0' && *p <= '9') ||
|
(*p >= 'a' && *p <= 'f') ||
|
(*p >= 'a' && *p <= 'f') ||
|
(*p >= 'A' && *p <= 'F')) {
|
(*p >= 'A' && *p <= 'F')) {
|
if (*p >= '0' && *p <= '9') {
|
if (*p >= '0' && *p <= '9') {
|
dval = (*p - '0');
|
dval = (*p - '0');
|
} else
|
} else
|
if (*p >= 'a' && *p <= 'f') {
|
if (*p >= 'a' && *p <= 'f') {
|
dval = (*p - 'a' + 10);
|
dval = (*p - 'a' + 10);
|
} else
|
} else
|
if (*p >= 'A' && *p <= 'F') {
|
if (*p >= 'A' && *p <= 'F') {
|
dval = (*p - 'A' + 10);
|
dval = (*p - 'A' + 10);
|
}
|
}
|
if (dval >= base) {
|
if (dval >= base) {
|
printf("Error: digit value %d is illegal in number base %d\n",
|
printf("Error: digit value %d is illegal in number base %d\n",
|
dval, base);
|
dval, base);
|
return 0;
|
return 0;
|
}
|
}
|
n *= base;
|
n *= base;
|
n += dval;
|
n += dval;
|
p++;
|
p++;
|
}
|
}
|
while (*p == ' ' || *p == '\t') {
|
while (*p == ' ' || *p == '\t') {
|
p++;
|
p++;
|
}
|
}
|
*pc = p;
|
*pc = p;
|
*pi = n;
|
*pi = n;
|
return 1;
|
return 1;
|
}
|
}
|
|
|
|
|
int parseString(char **pc, char *dst) {
|
int parseString(char **pc, char *dst) {
|
char *p;
|
char *p;
|
|
|
p = *pc;
|
p = *pc;
|
while (*p == ' ' || *p == '\t') {
|
while (*p == ' ' || *p == '\t') {
|
p++;
|
p++;
|
}
|
}
|
if (*p != '\"') {
|
if (*p != '\"') {
|
return 0;
|
return 0;
|
}
|
}
|
p++;
|
p++;
|
while (*p != '\"' && *p != '\0' && *p != '\n') {
|
while (*p != '\"' && *p != '\0' && *p != '\n') {
|
*dst++ = *p++;
|
*dst++ = *p++;
|
}
|
}
|
if (*p != '\"') {
|
if (*p != '\"') {
|
return 0;
|
return 0;
|
}
|
}
|
p++;
|
p++;
|
while (*p == ' ' || *p == '\t') {
|
while (*p == ' ' || *p == '\t') {
|
p++;
|
p++;
|
}
|
}
|
*pc = p;
|
*pc = p;
|
*dst = '\0';
|
*dst = '\0';
|
return 1;
|
return 1;
|
}
|
}
|
|
|
|
|
/**************************************************************/
|
/**************************************************************/
|
|
|
|
|
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
char *diskName;
|
char *diskName;
|
char *confName;
|
char *confName;
|
FILE *disk;
|
FILE *disk;
|
FILE *conf;
|
FILE *conf;
|
unsigned long diskSize;
|
unsigned long diskSize;
|
unsigned int numSectors;
|
unsigned int numSectors;
|
char line[LINE_SIZE];
|
char line[LINE_SIZE];
|
char *p, *q;
|
char *p, *q;
|
int lineNumber;
|
int lineNumber;
|
FILE *mbootblk;
|
FILE *mbootblk;
|
long mbootblkSize;
|
unsigned long mbootblkSize;
|
int i;
|
int i;
|
unsigned int partNum;
|
unsigned int partNum;
|
unsigned int bootable;
|
unsigned int bootable;
|
unsigned int partType;
|
unsigned int partType;
|
unsigned int partStart;
|
unsigned int partStart;
|
unsigned int partLast;
|
unsigned int partLast;
|
unsigned int partSize;
|
unsigned int partSize;
|
char descr[LINE_SIZE];
|
char descr[LINE_SIZE];
|
|
|
/* check command line arguments */
|
/* check command line arguments */
|
if (argc != 3) {
|
if (argc != 3) {
|
printf("Usage: %s <disk image file> <configuration file>\n", argv[0]);
|
printf("Usage: %s <disk image file> <configuration file>\n", argv[0]);
|
exit(1);
|
exit(1);
|
}
|
}
|
diskName = argv[1];
|
diskName = argv[1];
|
confName = argv[2];
|
confName = argv[2];
|
/* determine disk size */
|
/* determine disk size */
|
disk = fopen(diskName, "rb");
|
disk = fopen(diskName, "rb");
|
if (disk == NULL) {
|
if (disk == NULL) {
|
error("cannot open disk image '%s'", diskName);
|
error("cannot open disk image '%s'", diskName);
|
}
|
}
|
fseek(disk, 0, SEEK_END);
|
fseek(disk, 0, SEEK_END);
|
diskSize = ftell(disk);
|
diskSize = ftell(disk);
|
numSectors = diskSize / SECTOR_SIZE;
|
numSectors = diskSize / SECTOR_SIZE;
|
fclose(disk);
|
fclose(disk);
|
printf("Disk '%s' has %u (0x%X) sectors.\n",
|
printf("Disk '%s' has %u (0x%X) sectors.\n",
|
diskName, numSectors, numSectors);
|
diskName, numSectors, numSectors);
|
if (numSectors < 32) {
|
if (numSectors < 32) {
|
error("disk is too small");
|
error("disk is too small");
|
}
|
}
|
if (diskSize % SECTOR_SIZE != 0) {
|
if (diskSize % SECTOR_SIZE != 0) {
|
printf("Warning: disk size is not a multiple of sector size!\n");
|
printf("Warning: disk size is not a multiple of sector size!\n");
|
}
|
}
|
/* create partition table */
|
/* create partition table */
|
conf = fopen(confName, "rt");
|
conf = fopen(confName, "rt");
|
if (conf == NULL) {
|
if (conf == NULL) {
|
error("cannot open configuration file '%s'", confName);
|
error("cannot open configuration file '%s'", confName);
|
}
|
}
|
lineNumber = 0;
|
lineNumber = 0;
|
/* first, handle master boot block specification */
|
/* first, handle master boot block specification */
|
while (fgets(line, LINE_SIZE, conf) != NULL) {
|
while (fgets(line, LINE_SIZE, conf) != NULL) {
|
lineNumber++;
|
lineNumber++;
|
p = line;
|
p = line;
|
while (*p == ' ' || *p == '\t') {
|
while (*p == ' ' || *p == '\t') {
|
p++;
|
p++;
|
}
|
}
|
if (*p == '\0' || *p == '\n' || *p == '#') {
|
if (*p == '\0' || *p == '\n' || *p == '#') {
|
continue;
|
continue;
|
}
|
}
|
q = p;
|
q = p;
|
while (*q > 0x20 && *q < 0x7F) {
|
while (*q > 0x20 && *q < 0x7F) {
|
q++;
|
q++;
|
}
|
}
|
*q = '\0';
|
*q = '\0';
|
if (strcmp(p, "-noboot-") == 0) {
|
if (strcmp(p, "-noboot-") == 0) {
|
/* master boot block not wanted */
|
/* master boot block not wanted */
|
} else {
|
} else {
|
/* p points to name of master boot block file */
|
/* p points to name of master boot block file */
|
mbootblk = fopen(p, "rb");
|
mbootblk = fopen(p, "rb");
|
if (mbootblk == NULL) {
|
if (mbootblk == NULL) {
|
error("cannot open master boot block file '%s'", p);
|
error("cannot open master boot block file '%s'", p);
|
}
|
}
|
fseek(mbootblk, 0, SEEK_END);
|
fseek(mbootblk, 0, SEEK_END);
|
mbootblkSize = ftell(mbootblk);
|
mbootblkSize = ftell(mbootblk);
|
fseek(mbootblk, 0, SEEK_SET);
|
fseek(mbootblk, 0, SEEK_SET);
|
if (mbootblkSize > 32 * SECTOR_SIZE) {
|
if (mbootblkSize > 32 * SECTOR_SIZE) {
|
error("master boot block file '%s' is bigger than 32 sectors", p);
|
error("master boot block file '%s' is bigger than 32 sectors", p);
|
}
|
}
|
for (i = 0; i < 32 * SECTOR_SIZE; i++) {
|
for (i = 0; i < 32 * SECTOR_SIZE; i++) {
|
buf[i] = '\0';
|
buf[i] = '\0';
|
}
|
}
|
if (fread(buf, 1, mbootblkSize, mbootblk) != mbootblkSize) {
|
if (fread(buf, 1, mbootblkSize, mbootblk) != mbootblkSize) {
|
error("cannot read master boot block file '%s'", p);
|
error("cannot read master boot block file '%s'", p);
|
}
|
}
|
fclose(mbootblk);
|
fclose(mbootblk);
|
disk = fopen(diskName, "r+b");
|
disk = fopen(diskName, "r+b");
|
if (disk == NULL) {
|
if (disk == NULL) {
|
error("cannot open disk image '%s'", diskName);
|
error("cannot open disk image '%s'", diskName);
|
}
|
}
|
if (fwrite(buf, 1, 32 * SECTOR_SIZE, disk) != 32 * SECTOR_SIZE) {
|
if (fwrite(buf, 1, 32 * SECTOR_SIZE, disk) != 32 * SECTOR_SIZE) {
|
error("cannot write master boot block to disk image '%s'", diskName);
|
error("cannot write master boot block to disk image '%s'", diskName);
|
}
|
}
|
fclose(disk);
|
fclose(disk);
|
}
|
}
|
break;
|
break;
|
}
|
}
|
/* then, handle partition table entries */
|
/* then, handle partition table entries */
|
while (fgets(line, LINE_SIZE, conf) != NULL) {
|
while (fgets(line, LINE_SIZE, conf) != NULL) {
|
lineNumber++;
|
lineNumber++;
|
p = line;
|
p = line;
|
while (*p == ' ' || *p == '\t') {
|
while (*p == ' ' || *p == '\t') {
|
p++;
|
p++;
|
}
|
}
|
if (*p == '\0' || *p == '\n' || *p == '#') {
|
if (*p == '\0' || *p == '\n' || *p == '#') {
|
continue;
|
continue;
|
}
|
}
|
if (!parseNumber(&p, &partNum)) {
|
if (!parseNumber(&p, &partNum)) {
|
error("cannot read partition number in config file '%s', line %d",
|
error("cannot read partition number in config file '%s', line %d",
|
confName, lineNumber);
|
confName, lineNumber);
|
}
|
}
|
if (partNum >= 16) {
|
if (partNum >= 16) {
|
error("illegal partition number in config file '%s', line %d",
|
error("illegal partition number in config file '%s', line %d",
|
confName, lineNumber);
|
confName, lineNumber);
|
}
|
}
|
if (*p == '*') {
|
if (*p == '*') {
|
p++;
|
p++;
|
bootable = 0x80000000;
|
bootable = 0x80000000;
|
} else {
|
} else {
|
bootable = 0x00000000;
|
bootable = 0x00000000;
|
}
|
}
|
if (!parseNumber(&p, &partType)) {
|
if (!parseNumber(&p, &partType)) {
|
error("cannot read partition type in config file '%s', line %d",
|
error("cannot read partition type in config file '%s', line %d",
|
confName, lineNumber);
|
confName, lineNumber);
|
}
|
}
|
if ((partType & 0x80000000) != 0) {
|
if ((partType & 0x80000000) != 0) {
|
error("illegal partition type in config file '%s', line %d",
|
error("illegal partition type in config file '%s', line %d",
|
confName, lineNumber);
|
confName, lineNumber);
|
}
|
}
|
if (!parseNumber(&p, &partStart)) {
|
if (!parseNumber(&p, &partStart)) {
|
error("cannot read start sector in config file '%s', line %d",
|
error("cannot read start sector in config file '%s', line %d",
|
confName, lineNumber);
|
confName, lineNumber);
|
}
|
}
|
if (partStart < 32 || partStart >= numSectors) {
|
if (partStart < 32 || partStart >= numSectors) {
|
error("illegal start sector in config file '%s', line %d",
|
error("illegal start sector in config file '%s', line %d",
|
confName, lineNumber);
|
confName, lineNumber);
|
}
|
}
|
if (!parseNumber(&p, &partLast)) {
|
if (!parseNumber(&p, &partLast)) {
|
error("cannot read last sector in config file '%s', line %d",
|
error("cannot read last sector in config file '%s', line %d",
|
confName, lineNumber);
|
confName, lineNumber);
|
}
|
}
|
if (partLast < partStart || partLast >= numSectors) {
|
if (partLast < partStart || partLast >= numSectors) {
|
error("illegal last sector in config file '%s', line %d",
|
error("illegal last sector in config file '%s', line %d",
|
confName, lineNumber);
|
confName, lineNumber);
|
}
|
}
|
partSize = partLast - partStart + 1;
|
partSize = partLast - partStart + 1;
|
if (!parseString(&p, descr)) {
|
if (!parseString(&p, descr)) {
|
error("cannot read description in config file '%s', line %d",
|
error("cannot read description in config file '%s', line %d",
|
confName, lineNumber);
|
confName, lineNumber);
|
}
|
}
|
if (strlen(descr) >= DESCR_SIZE) {
|
if (strlen(descr) >= DESCR_SIZE) {
|
error("description too long in config file '%s', line %d",
|
error("description too long in config file '%s', line %d",
|
confName, lineNumber);
|
confName, lineNumber);
|
}
|
}
|
if (partType != 0) {
|
if (partType != 0) {
|
ptr[partNum].type = bootable | partType;
|
ptr[partNum].type = bootable | partType;
|
ptr[partNum].start = partStart;
|
ptr[partNum].start = partStart;
|
ptr[partNum].size = partSize;
|
ptr[partNum].size = partSize;
|
memset(ptr[partNum].descr, 0, DESCR_SIZE);
|
memset(ptr[partNum].descr, 0, DESCR_SIZE);
|
strcpy(ptr[partNum].descr, descr);
|
strcpy(ptr[partNum].descr, descr);
|
} else {
|
} else {
|
ptr[partNum].type = 0;
|
ptr[partNum].type = 0;
|
ptr[partNum].start = 0;
|
ptr[partNum].start = 0;
|
ptr[partNum].size = 0;
|
ptr[partNum].size = 0;
|
memset(ptr[partNum].descr, 0, DESCR_SIZE);
|
memset(ptr[partNum].descr, 0, DESCR_SIZE);
|
}
|
}
|
}
|
}
|
fclose(conf);
|
fclose(conf);
|
/* next, show partition table */
|
/* next, show partition table */
|
printf("Partitions:\n");
|
printf("Partitions:\n");
|
printf(" # b type start last size description\n");
|
printf(" # b type start last size description\n");
|
for (partNum = 0; partNum < NPE; partNum++) {
|
for (partNum = 0; partNum < NPE; partNum++) {
|
if (ptr[partNum].type != 0) {
|
if (ptr[partNum].type != 0) {
|
partLast = ptr[partNum].start + ptr[partNum].size - 1;
|
partLast = ptr[partNum].start + ptr[partNum].size - 1;
|
} else {
|
} else {
|
partLast = 0;
|
partLast = 0;
|
}
|
}
|
printf("%2u %s 0x%08X 0x%08X 0x%08X 0x%08X %s\n",
|
printf("%2u %s 0x%08X 0x%08X 0x%08X 0x%08X %s\n",
|
partNum,
|
partNum,
|
ptr[partNum].type & 0x80000000 ? "*" : " ",
|
ptr[partNum].type & 0x80000000 ? "*" : " ",
|
ptr[partNum].type & 0x7FFFFFFF,
|
ptr[partNum].type & 0x7FFFFFFF,
|
ptr[partNum].start,
|
ptr[partNum].start,
|
partLast,
|
partLast,
|
ptr[partNum].size,
|
ptr[partNum].size,
|
ptr[partNum].descr);
|
ptr[partNum].descr);
|
}
|
}
|
/* finally, write partition table record */
|
/* finally, write partition table record */
|
convertPartitionTable(ptr, NPE);
|
convertPartitionTable(ptr, NPE);
|
disk = fopen(diskName, "r+b");
|
disk = fopen(diskName, "r+b");
|
if (disk == NULL) {
|
if (disk == NULL) {
|
error("cannot open disk image '%s'", diskName);
|
error("cannot open disk image '%s'", diskName);
|
}
|
}
|
fseek(disk, 1 * SECTOR_SIZE, SEEK_SET);
|
fseek(disk, 1 * SECTOR_SIZE, SEEK_SET);
|
if (fwrite(ptr, 1, SECTOR_SIZE, disk) != SECTOR_SIZE) {
|
if (fwrite(ptr, 1, SECTOR_SIZE, disk) != SECTOR_SIZE) {
|
error("cannot write partition table to disk image '%s'", diskName);
|
error("cannot write partition table to disk image '%s'", diskName);
|
}
|
}
|
fclose(disk);
|
fclose(disk);
|
/* done */
|
/* done */
|
return 0;
|
return 0;
|
}
|
}
|
|
|