diff --git a/src/ptgen.c b/src/ptgen.c index d480908..61cf830 100644 --- a/src/ptgen.c +++ b/src/ptgen.c @@ -23,6 +23,7 @@ #include #include #include +#include #include "cyg_crc.h" #if __BYTE_ORDER == __BIG_ENDIAN @@ -131,6 +132,7 @@ struct partinfo { bool has_guid; guid_t guid; uint64_t gattr; /* GPT partition attributes */ + unsigned part_index; /* index of GPT entry to be used */ }; /* GPT Partition table header */ @@ -169,7 +171,9 @@ int sectors = -1; int kb_align = 0; bool ignore_null_sized_partition = false; bool use_guid_partition_table = false; +bool allow_stub_partition = true; struct partinfo parts[GPT_ENTRY_MAX]; +bool entry_used[GPT_ENTRY_MAX] = { false }; char *filename = NULL; int gpt_split_image = false; @@ -422,7 +426,7 @@ static int gen_gptable(uint32_t signature, guid_t guid, unsigned nr) uint64_t start, end; uint64_t sect = GPT_SIZE + gpt_first_entry_sector; int fd, ret = -1; - unsigned i, pmbr = 1; + unsigned i, index, pmbr = 1; char img_name[strlen(filename) + 20]; memset(pte, 0, sizeof(struct pte) * MBR_ENTRY_MAX); @@ -452,13 +456,15 @@ static int gen_gptable(uint32_t signature, guid_t guid, unsigned nr) return ret; } parts[i].actual_start = start; - gpte[i].start = cpu_to_le64(start); + + index = parts[i].part_index; + gpte[index].start = cpu_to_le64(start); sect = start + parts[i].size * 2; - gpte[i].end = cpu_to_le64(sect -1); - gpte[i].guid = guid; - gpte[i].guid.b[sizeof(guid_t) -1] += i + 1; - gpte[i].type = parts[i].guid; + gpte[index].end = cpu_to_le64(sect -1); + gpte[index].guid = guid; + gpte[index].guid.b[sizeof(guid_t) -1] += i + 1; + gpte[index].type = parts[i].guid; if (parts[i].hybrid && pmbr < MBR_ENTRY_MAX) { pte[pmbr].active = ((i + 1) == active) ? 0x80 : 0; @@ -469,16 +475,16 @@ static int gen_gptable(uint32_t signature, guid_t guid, unsigned nr) to_chs(sect - 1, pte[1].chs_end); pmbr++; } - gpte[i].attr = parts[i].gattr; + gpte[index].attr = parts[i].gattr; if (parts[i].name) - init_utf16(parts[i].name, (uint16_t *)gpte[i].name, GPT_ENTRY_NAME_SIZE / sizeof(uint16_t)); + init_utf16(parts[i].name, (uint16_t *)gpte[index].name, GPT_ENTRY_NAME_SIZE / sizeof(uint16_t)); if ((i + 1) == (unsigned)active) - gpte[i].attr |= GPT_ATTR_LEGACY_BOOT; + gpte[index].attr |= GPT_ATTR_LEGACY_BOOT; if (parts[i].required) - gpte[i].attr |= GPT_ATTR_PLAT_REQUIRED; + gpte[index].attr |= GPT_ATTR_PLAT_REQUIRED; if (verbose) fprintf(stderr, "Partition %d: start=%" PRIu64 ", end=%" PRIu64 ", size=%" PRIu64 "\n", @@ -489,7 +495,8 @@ static int gen_gptable(uint32_t signature, guid_t guid, unsigned nr) printf("%" PRIu64 "\n", (sect - start) * DISK_SECTOR_SIZE); } - if (parts[0].actual_start > GPT_FIRST_ENTRY_SECTOR + GPT_SIZE) { + if (parts[0].actual_start > gpt_first_entry_sector + GPT_SIZE && + allow_stub_partition && !entry_used[GPT_ENTRY_MAX - 1]) { gpte[GPT_ENTRY_MAX - 1].start = cpu_to_le64(gpt_first_entry_sector + GPT_SIZE); gpte[GPT_ENTRY_MAX - 1].end = cpu_to_le64(parts[0].actual_start - 1); gpte[GPT_ENTRY_MAX - 1].type = GUID_PARTITION_BIOS_BOOT; @@ -618,10 +625,35 @@ static int gen_gptable(uint32_t signature, guid_t guid, unsigned nr) static void usage(char *prog) { - fprintf(stderr, "Usage: %s [-v] [-n] [-b] [-g] -h -s -o \n" - " [-a ] [-l ] [-G ]\n" - " [-e ] [-d ]\n" - " [[-t | -T ] [-r] [-N ] -p [@]...] \n", prog); + fprintf(stderr, "Usage: %s [OPTION]...\n" + "Generate hard drive image with predefined partitions\n" + "\n" + "Mandatory arguments to long options are mandatory for short options too.\n" + " -?, --help display this help and exit\n" + " -v, --verbose enable vervose output\n" + " -l, --alignment=SIZE align partition boundaries to SIZE Kbytes\n" + " -n, --ignore-null-sized-parts do not create null sized partitions\n" + " -D, --disable-gpt-stub-part do not fill a gap before 1-st GPT partition\n" + " -o, --output=FILENAME write an image to a file FILENAME\n" + " -h, --heads=COUNT use CHS scheme, defines heads number\n" + " -s, --sectors=COUNT use CHS scheme, defines sectors count\n" + " -S, --mbr-disk-signature=VALUE defines MBR disk signature [default: 0x5452574F ('OWRT')]\n" + " -a, --active-part=PART_NUMBER defines active (boot) partition\n" + " -g, --gpt use GPT instead of MBR\n" + " -G, --gpt-guid=GUID defines custom GPT GUID\n" + " -e, --gpt-entry-offset=OFFSET defines custom placement of GPT Entry table (default: 1K)\n" + " -d, --gpt-disk-size=SIZE defines total size of disk image (used for ALT GPT headers)\n" + " -b, --gpt-split-images generate 2 or 3 images (depends on entry table placement):\n" + " GPT header + GPT Entry Table, Alt Entry Table + ALT Header\n" + " GPT header, GPT Entry Table, Alt Entry Table + ALT Header\n" + " -p, --part=SIZE[@START] defines partition of size SIZE, started at offset START\n" + " -t, --mbr-part-type=TYPE defines partition type by MBR partition type\n" + " -T, --gpt-part-type=TYPE_NAME defines partinion type by GPT type name\n" + " -N, --gpt-part-name=NAME defines GPT partition name\n" + " -r, --gpt-part-attr-required mark partition with GPT required attribute\n" + " -H, --gpt-part-hybrid put GPT partition to the MBR as well\n" + " -i, --gpt-part-index=INDEX use custom INDEX for the partition in the GPT Entry Table\n", + prog); exit(EXIT_FAILURE); } @@ -653,6 +685,7 @@ int main (int argc, char **argv) char *p; int ch; int part = 0; + unsigned part_index = 0; char *name = NULL; unsigned short int hybrid = 0, required = 0; uint64_t total_sectors; @@ -660,7 +693,39 @@ int main (int argc, char **argv) guid_t guid = GUID_INIT( signature, 0x2211, 0x4433, \ 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0x00); - while ((ch = getopt(argc, argv, "h:s:p:a:t:T:o:vnbHN:gl:rS:G:e:d:")) != -1) { + while (1) { + int option_index = 0; + static struct option long_options[] = { + {"help", no_argument, 0, '?'}, + {"verbose", no_argument, 0, 'v'}, + {"kb_alignment", required_argument, 0, 'l'}, + {"ignore-null-sized-parts", no_argument, 0, 'n'}, + {"disable-gpt-stub-part", no_argument, 0, 'D'}, + {"output", required_argument, 0, 'o'}, + {"heads", required_argument, 0, 'h'}, + {"sectors", required_argument, 0, 's'}, + {"mbr-disk-signature", required_argument, 0, 'S'}, + {"active-part", required_argument, 0, 'a'}, + {"gpt", no_argument, 0, 'g'}, + {"gpt-guid", required_argument, 0, 'G'}, + {"gpt-entry-offset", required_argument, 0, 'e'}, + {"gpt-disk-size", required_argument, 0, 'd'}, + {"gpt-split-images", no_argument, 0, 'b'}, + {"part", required_argument, 0, 'p'}, + {"mbr-part-type", required_argument, 0, 't'}, + {"gpt-part-type", required_argument, 0, 'T'}, + {"gpt-part-name", required_argument, 0, 'N'}, + {"gpt-part-attr-required", no_argument, 0, 'r'}, + {"gpt-part-hybrid", no_argument, 0, 'H'}, + {"gpt-part-index", required_argument, 0, 'i'}, + {NULL, 0, 0, 0 }, + }; + + ch = getopt_long(argc, argv, "?h:s:p:a:t:T:o:DvnbHN:gl:rS:G:e:d:i:", + long_options, &option_index); + if (ch == -1) + break; + switch (ch) { case 'o': filename = optarg; @@ -668,6 +733,9 @@ int main (int argc, char **argv) case 'v': verbose++; break; + case 'D': + allow_stub_partition = false; + break; case 'n': ignore_null_sized_partition = true; break; @@ -719,6 +787,11 @@ int main (int argc, char **argv) fputs("Too many partitions\n", stderr); exit(EXIT_FAILURE); } + if (entry_used[part_index]) { + fprintf(stderr, "Partition entry with index %d already defined\n", part_index); + exit(EXIT_FAILURE); + } + p = strchr(optarg, '@'); if (p) { *(p++) = 0; @@ -731,6 +804,7 @@ int main (int argc, char **argv) parts[part].required = required; parts[part].name = name; parts[part].hybrid = hybrid; + parts[part].part_index = part_index; fprintf(stderr, "part %lld %lld\n", parts[part].start, parts[part].size); parts[part++].type = type; /* @@ -740,6 +814,13 @@ int main (int argc, char **argv) name = NULL; required = 0; hybrid = 0; + + /* mark index as used, switch to next index */ + entry_used[part_index++] = true; + if (part_index > GPT_ENTRY_MAX - 1 || + (!use_guid_partition_table && part_index > 3)) + part_index = 0; + break; case 'N': name = optarg; @@ -747,6 +828,14 @@ int main (int argc, char **argv) case 'r': required = 1; break; + case 'i': + part_index = (int)strtoul(optarg, NULL, 0); + if (part_index > GPT_ENTRY_MAX - 1 || + (!use_guid_partition_table && part_index > 3)) { + fprintf(stderr, "Too big GPT/MBR entry index %d\n", part_index); + exit(EXIT_FAILURE); + } + break; case 't': type = (char)strtoul(optarg, NULL, 16); break;