• source navigation  • diff markup  • identifier search  • freetext search  • 

Sources/firmware-utils/src/ptgen.c

  1 // SPDX-License-Identifier: GPL-2.0-or-later
  2 /*
  3  * ptgen - partition table generator
  4  * Copyright (C) 2006 by Felix Fietkau <nbd@nbd.name>
  5  *
  6  * uses parts of afdisk
  7  * Copyright (C) 2002 by David Roetzel <david@roetzel.de>
  8  *
  9  * UUID/GUID definition stolen from kernel/include/uapi/linux/uuid.h
 10  * Copyright (C) 2010, Intel Corp. Huang Ying <ying.huang@intel.com>
 11  */
 12 
 13 #include <byteswap.h>
 14 #include <sys/types.h>
 15 #include <sys/stat.h>
 16 #include <string.h>
 17 #include <unistd.h>
 18 #include <stdlib.h>
 19 #include <stdio.h>
 20 #include <stdint.h>
 21 #include <stdbool.h>
 22 #include <ctype.h>
 23 #include <inttypes.h>
 24 #include <fcntl.h>
 25 #include <stdint.h>
 26 #include <getopt.h>
 27 #include "cyg_crc.h"
 28 
 29 #if __BYTE_ORDER == __BIG_ENDIAN
 30 #define cpu_to_le16(x) bswap_16(x)
 31 #define cpu_to_le32(x) bswap_32(x)
 32 #define cpu_to_le64(x) bswap_64(x)
 33 #elif __BYTE_ORDER == __LITTLE_ENDIAN
 34 #define cpu_to_le16(x) (x)
 35 #define cpu_to_le32(x) (x)
 36 #define cpu_to_le64(x) (x)
 37 #else
 38 #error unknown endianness!
 39 #endif
 40 
 41 #define swap(a, b) \
 42         do { typeof(a) __tmp = (a); (a) = (b); (b) = __tmp; } while (0)
 43 
 44 #define BIT(_x)         (1UL << (_x))
 45 
 46 typedef struct {
 47         uint8_t b[16];
 48 } guid_t;
 49 
 50 #define GUID_INIT(a, b, c, d0, d1, d2, d3, d4, d5, d6, d7)                      \
 51 ((guid_t)                                                               \
 52 {{ (a) & 0xff, ((a) >> 8) & 0xff, ((a) >> 16) & 0xff, ((a) >> 24) & 0xff, \
 53    (b) & 0xff, ((b) >> 8) & 0xff,                                       \
 54    (c) & 0xff, ((c) >> 8) & 0xff,                                       \
 55    (d0), (d1), (d2), (d3), (d4), (d5), (d6), (d7) }})
 56 
 57 #define GUID_STRING_LENGTH      36
 58 
 59 #define GPT_SIGNATURE 0x5452415020494645ULL
 60 #define GPT_REVISION 0x00010000
 61 
 62 #define GUID_PARTITION_SYSTEM \
 63         GUID_INIT( 0xC12A7328, 0xF81F, 0x11d2, \
 64                         0xBA, 0x4B, 0x00, 0xA0, 0xC9, 0x3E, 0xC9, 0x3B)
 65 
 66 #define GUID_PARTITION_BASIC_DATA \
 67         GUID_INIT( 0xEBD0A0A2, 0xB9E5, 0x4433, \
 68                         0x87, 0xC0, 0x68, 0xB6, 0xB7, 0x26, 0x99, 0xC7)
 69 
 70 #define GUID_PARTITION_BIOS_BOOT \
 71         GUID_INIT( 0x21686148, 0x6449, 0x6E6F, \
 72                         0x74, 0x4E, 0x65, 0x65, 0x64, 0x45, 0x46, 0x49)
 73 
 74 #define GUID_PARTITION_CHROME_OS_KERNEL \
 75         GUID_INIT( 0xFE3A2A5D, 0x4F32, 0x41A7, \
 76                         0xB7, 0x25, 0xAC, 0xCC, 0x32, 0x85, 0xA3, 0x09)
 77 
 78 #define GUID_PARTITION_LINUX_FIT_GUID \
 79         GUID_INIT( 0xcae9be83, 0xb15f, 0x49cc, \
 80                         0x86, 0x3f, 0x08, 0x1b, 0x74, 0x4a, 0x2d, 0x93)
 81 
 82 #define GUID_PARTITION_LINUX_FS_GUID \
 83         GUID_INIT( 0x0fc63daf, 0x8483, 0x4772, \
 84                         0x8e, 0x79, 0x3d, 0x69, 0xd8, 0x47, 0x7d, 0xe4)
 85 
 86 #define GUID_PARTITION_SIFIVE_SPL \
 87         GUID_INIT( 0x5b193300, 0xfc78, 0x40cd, \
 88                         0x80, 0x02, 0xe8, 0x6c, 0x45, 0x58, 0x0b, 0x47)
 89 
 90 #define GUID_PARTITION_SIFIVE_UBOOT \
 91         GUID_INIT( 0x2e54b353, 0x1271, 0x4842, \
 92                         0x80, 0x6f, 0xe4, 0x36, 0xd6, 0xaf, 0x69, 0x85)
 93 
 94 #define GPT_HEADER_SIZE         92
 95 #define GPT_ENTRY_SIZE          128
 96 #define GPT_ENTRY_MAX           128
 97 #define GPT_ENTRY_NAME_SIZE     72
 98 #define GPT_SIZE                GPT_ENTRY_SIZE * GPT_ENTRY_MAX / DISK_SECTOR_SIZE
 99 
100 #define GPT_ATTR_PLAT_REQUIRED  BIT(0)
101 #define GPT_ATTR_EFI_IGNORE     BIT(1)
102 #define GPT_ATTR_LEGACY_BOOT    BIT(2)
103 
104 #define GPT_HEADER_SECTOR       1
105 #define GPT_FIRST_ENTRY_SECTOR  2
106 
107 #define MBR_ENTRY_MAX           4
108 #define MBR_DISK_SIGNATURE_OFFSET  440
109 #define MBR_PARTITION_ENTRY_OFFSET 446
110 #define MBR_BOOT_SIGNATURE_OFFSET  510
111 
112 #define DISK_SECTOR_SIZE        512
113 
114 /* Partition table entry */
115 struct pte {
116         uint8_t active;
117         uint8_t chs_start[3];
118         uint8_t type;
119         uint8_t chs_end[3];
120         uint32_t start;
121         uint32_t length;
122 };
123 
124 struct partinfo {
125         unsigned long long actual_start;
126         unsigned long long start;
127         unsigned long long size;
128         int type;
129         int hybrid;
130         char *name;
131         short int required;
132         short int bootable;
133         bool has_guid;
134         guid_t guid;
135         uint64_t gattr;  /* GPT partition attributes */
136         unsigned part_index; /* index of GPT entry to be used */
137 };
138 
139 /* GPT Partition table header */
140 struct gpth {
141         uint64_t signature;
142         uint32_t revision;
143         uint32_t size;
144         uint32_t crc32;
145         uint32_t reserved;
146         uint64_t self;
147         uint64_t alternate;
148         uint64_t first_usable;
149         uint64_t last_usable;
150         guid_t disk_guid;
151         uint64_t first_entry;
152         uint32_t entry_num;
153         uint32_t entry_size;
154         uint32_t entry_crc32;
155 } __attribute__((packed));
156 
157 /* GPT Partition table entry */
158 struct gpte {
159         guid_t type;
160         guid_t guid;
161         uint64_t start;
162         uint64_t end;
163         uint64_t attr;
164         char name[GPT_ENTRY_NAME_SIZE];
165 } __attribute__((packed));
166 
167 
168 int verbose = 0;
169 int active = 1;
170 int heads = -1;
171 int sectors = -1;
172 int kb_align = 0;
173 bool ignore_null_sized_partition = false;
174 bool use_guid_partition_table = false;
175 bool allow_stub_partition = true;
176 struct partinfo parts[GPT_ENTRY_MAX];
177 bool entry_used[GPT_ENTRY_MAX] = { false };
178 char *filename = NULL;
179 
180 int gpt_split_image = false;
181 int gpt_alternate = false;
182 uint64_t gpt_first_entry_sector = GPT_FIRST_ENTRY_SECTOR;
183 uint64_t gpt_last_usable_sector = 0;
184 
185 /*
186  * parse the size argument, which is either
187  * a simple number (K assumed) or
188  * K, M or G
189  *
190  * returns the size in KByte
191  */
192 static long long to_kbytes(const char *string)
193 {
194         int exp = 0;
195         long long result;
196         char *end;
197 
198         result = strtoull(string, &end, 0);
199         switch (tolower(*end)) {
200                 case 'k' :
201                 case '\0' : exp = 0; break;
202                 case 'm' : exp = 1; break;
203                 case 'g' : exp = 2; break;
204                 default: return 0;
205         }
206 
207         if (*end)
208                 end++;
209 
210         if (*end) {
211                 fputs("garbage after end of number\n", stderr);
212                 return 0;
213         }
214 
215         /* result: number * 1024^(exp) */
216         return result * (1 << (10 * exp));
217 }
218 
219 /* convert the sector number into a CHS value for the partition table */
220 static void to_chs(long sect, unsigned char chs[3])
221 {
222         int c,h,s;
223 
224         s = (sect % sectors) + 1;
225         sect = sect / sectors;
226         h = sect % heads;
227         sect = sect / heads;
228         c = sect;
229 
230         chs[0] = h;
231         chs[1] = s | ((c >> 2) & 0xC0);
232         chs[2] = c & 0xFF;
233 
234         return;
235 }
236 
237 /* round the sector number up to the next cylinder */
238 static inline unsigned long round_to_cyl(long sect)
239 {
240         int cyl_size = heads * sectors;
241 
242         return sect + cyl_size - (sect % cyl_size);
243 }
244 
245 /* round the sector number up to the kb_align boundary */
246 static inline unsigned long round_to_kb(long sect) {
247         return ((sect - 1) / kb_align + 1) * kb_align;
248 }
249 
250 /* Compute a CRC for guid partition table */
251 static inline unsigned long gpt_crc32(void *buf, unsigned long len)
252 {
253         return cyg_crc32_accumulate(~0L, buf, len) ^ ~0L;
254 }
255 
256 /* Parse a guid string to guid_t struct */
257 static inline int guid_parse(char *buf, guid_t *guid)
258 {
259         char b[4] = {0};
260         char *p = buf;
261         unsigned i = 0;
262         if (strnlen(buf, GUID_STRING_LENGTH) != GUID_STRING_LENGTH)
263                 return -1;
264         for (i = 0; i < sizeof(guid_t); i++) {
265                 if (*p == '-')
266                         p++;
267                 if (*p == '\0')
268                         return -1;
269                 memcpy(b, p, 2);
270                 guid->b[i] = strtol(b, 0, 16);
271                 p += 2;
272         }
273         swap(guid->b[0], guid->b[3]);
274         swap(guid->b[1], guid->b[2]);
275         swap(guid->b[4], guid->b[5]);
276         swap(guid->b[6], guid->b[7]);
277         return 0;
278 }
279 
280 /*
281  * Map GPT partition types to partition GUIDs.
282  * NB: not all GPT partition types have an equivalent MBR type.
283  */
284 static inline bool parse_gpt_parttype(const char *type, struct partinfo *part)
285 {
286         if (!strcmp(type, "cros_kernel")) {
287                 part->has_guid = true;
288                 part->guid = GUID_PARTITION_CHROME_OS_KERNEL;
289                 /* Default attributes: bootable kernel. */
290                 part->gattr = (1ULL << 48) |  /* priority=1 */
291                               (1ULL << 56);  /* success=1 */
292                 return true;
293         }
294 
295         if (!strcmp(type, "sifiveu_spl")) {
296                 part->has_guid = true;
297                 part->guid = GUID_PARTITION_SIFIVE_SPL;
298                 return true;
299         }
300 
301         if (!strcmp(type, "sifiveu_uboot")) {
302                 part->has_guid = true;
303                 part->guid = GUID_PARTITION_SIFIVE_UBOOT;
304                 return true;
305         }
306 
307         return false;
308 }
309 
310 /* init an utf-16 string from utf-8 string */
311 static inline void init_utf16(char *str, uint16_t *buf, unsigned bufsize)
312 {
313         unsigned i, n = 0;
314         for (i = 0; i < bufsize; i++) {
315                 if (str[n] == 0x00) {
316                         buf[i] = 0x00;
317                         return ;
318                 } else if ((str[n] & 0x80) == 0x00) {//0xxxxxxx
319                         buf[i] = cpu_to_le16(str[n++]);
320                 } else if ((str[n] & 0xE0) == 0xC0) {//110xxxxx
321                         buf[i] = cpu_to_le16((str[n] & 0x1F) << 6 | (str[n + 1] & 0x3F));
322                         n += 2;
323                 } else if ((str[n] & 0xF0) == 0xE0) {//1110xxxx
324                         buf[i] = cpu_to_le16((str[n] & 0x0F) << 12 | (str[n + 1] & 0x3F) << 6 | (str[n + 2] & 0x3F));
325                         n += 3;
326                 } else {
327                         buf[i] = cpu_to_le16('?');
328                         n++;
329                 }
330         }
331 }
332 
333 /* check the partition sizes and write the partition table */
334 static int gen_ptable(uint32_t signature, int nr)
335 {
336         struct pte pte[MBR_ENTRY_MAX];
337         unsigned long long start, len, sect = 0;
338         int i, fd, ret = -1;
339 
340         memset(pte, 0, sizeof(struct pte) * MBR_ENTRY_MAX);
341         for (i = 0; i < nr; i++) {
342                 if (!parts[i].size) {
343                         if (ignore_null_sized_partition)
344                                 continue;
345                         fprintf(stderr, "Invalid size in partition %d!\n", i);
346                         return ret;
347                 }
348 
349                 pte[i].active = ((i + 1) == active) ? 0x80 : 0;
350                 pte[i].type = parts[i].type;
351 
352                 start = sect + sectors;
353                 if (parts[i].start != 0) {
354                         if (parts[i].start * 2 < start) {
355                                 fprintf(stderr, "Invalid start %lld for partition %d!\n",
356                                         parts[i].start, i);
357                                 return ret;
358                         }
359                         start = parts[i].start * 2;
360                 } else if (kb_align != 0) {
361                         start = round_to_kb(start);
362                 }
363                 pte[i].start = cpu_to_le32(start);
364 
365                 sect = start + parts[i].size * 2;
366                 if (kb_align == 0)
367                         sect = round_to_cyl(sect);
368                 pte[i].length = cpu_to_le32(len = sect - start);
369 
370                 to_chs(start, pte[i].chs_start);
371                 to_chs(start + len - 1, pte[i].chs_end);
372 
373                 if (verbose)
374                         fprintf(stderr, "Partition %d: start=%lld, end=%lld, size=%lld\n",
375                                         i,
376                                         start * DISK_SECTOR_SIZE,
377                                         (start + len) * DISK_SECTOR_SIZE,
378                                         len * DISK_SECTOR_SIZE);
379                 printf("%lld\n", start * DISK_SECTOR_SIZE);
380                 printf("%lld\n", len * DISK_SECTOR_SIZE);
381         }
382 
383         if ((fd = open(filename, O_WRONLY|O_CREAT|O_TRUNC, 0644)) < 0) {
384                 fprintf(stderr, "Can't open output file '%s'\n",filename);
385                 return ret;
386         }
387 
388         lseek(fd, MBR_DISK_SIGNATURE_OFFSET, SEEK_SET);
389         if (write(fd, &signature, sizeof(signature)) != sizeof(signature)) {
390                 fputs("write failed.\n", stderr);
391                 goto fail;
392         }
393 
394         lseek(fd, MBR_PARTITION_ENTRY_OFFSET, SEEK_SET);
395         if (write(fd, pte, sizeof(struct pte) * MBR_ENTRY_MAX) != sizeof(struct pte) * MBR_ENTRY_MAX) {
396                 fputs("write failed.\n", stderr);
397                 goto fail;
398         }
399         lseek(fd, MBR_BOOT_SIGNATURE_OFFSET, SEEK_SET);
400         if (write(fd, "\x55\xaa", 2) != 2) {
401                 fputs("write failed.\n", stderr);
402                 goto fail;
403         }
404 
405         ret = 0;
406 fail:
407         close(fd);
408         return ret;
409 }
410 
411 /* check the partition sizes and write the guid partition table */
412 static int gen_gptable(uint32_t signature, guid_t guid, unsigned nr)
413 {
414         struct pte pte[MBR_ENTRY_MAX];
415         struct gpth gpth = {
416                 .signature = cpu_to_le64(GPT_SIGNATURE),
417                 .revision = cpu_to_le32(GPT_REVISION),
418                 .size = cpu_to_le32(GPT_HEADER_SIZE),
419                 .self = cpu_to_le64(GPT_HEADER_SECTOR),
420                 .first_usable = cpu_to_le64(gpt_first_entry_sector + GPT_SIZE),
421                 .first_entry = cpu_to_le64(gpt_first_entry_sector),
422                 .disk_guid = guid,
423                 .entry_num = cpu_to_le32(GPT_ENTRY_MAX),
424                 .entry_size = cpu_to_le32(GPT_ENTRY_SIZE),
425         };
426         struct gpte  gpte[GPT_ENTRY_MAX];
427         uint64_t start, end;
428         uint64_t sect = GPT_SIZE + gpt_first_entry_sector;
429         int fd, ret = -1;
430         unsigned i, index, pmbr = 1;
431         char img_name[strlen(filename) + 20];
432 
433         memset(pte, 0, sizeof(struct pte) * MBR_ENTRY_MAX);
434         memset(gpte, 0, GPT_ENTRY_SIZE * GPT_ENTRY_MAX);
435         for (i = 0; i < nr; i++) {
436                 if (!parts[i].size) {
437                         if (ignore_null_sized_partition)
438                                 continue;
439                         fprintf(stderr, "Invalid size in partition %d!\n", i);
440                         return ret;
441                 }
442                 start = sect;
443                 if (parts[i].start != 0) {
444                         if (parts[i].start * 2 < start) {
445                                 fprintf(stderr, "Invalid start %lld for partition %d!\n",
446                                         parts[i].start, i);
447                                 return ret;
448                         }
449                         start = parts[i].start * 2;
450                 } else if (kb_align != 0) {
451                         start = round_to_kb(start);
452                 }
453                 if ((gpt_last_usable_sector > 0) &&
454                     (start + parts[i].size * 2 > gpt_last_usable_sector + 1)) {
455                                 fprintf(stderr, "Partition %d ends after last usable sector %ld\n",
456                                         i, gpt_last_usable_sector);
457                                 return ret;
458                 }
459                 parts[i].actual_start = start;
460 
461                 index = parts[i].part_index;
462                 gpte[index].start = cpu_to_le64(start);
463 
464                 sect = start + parts[i].size * 2;
465                 gpte[index].end = cpu_to_le64(sect -1);
466                 gpte[index].guid = guid;
467                 gpte[index].guid.b[sizeof(guid_t) -1] += i + 1;
468                 gpte[index].type = parts[i].guid;
469 
470                 if (parts[i].hybrid && pmbr < MBR_ENTRY_MAX) {
471                         pte[pmbr].active = ((i + 1) == active) ? 0x80 : 0;
472                         pte[pmbr].type = parts[i].type;
473                         pte[pmbr].start = cpu_to_le32(start);
474                         pte[pmbr].length = cpu_to_le32(sect - start);
475                         to_chs(start, pte[1].chs_start);
476                         to_chs(sect - 1, pte[1].chs_end);
477                         pmbr++;
478                 }
479                 gpte[index].attr = parts[i].gattr;
480 
481                 if (parts[i].name)
482                         init_utf16(parts[i].name, (uint16_t *)gpte[index].name, GPT_ENTRY_NAME_SIZE / sizeof(uint16_t));
483 
484                 if ((i + 1) == (unsigned)active || parts[i].bootable)
485                         gpte[index].attr |= GPT_ATTR_LEGACY_BOOT;
486 
487                 if (parts[i].required)
488                         gpte[index].attr |= GPT_ATTR_PLAT_REQUIRED;
489 
490                 if (verbose)
491                         fprintf(stderr, "Partition %d: start=%" PRIu64 ", end=%" PRIu64 ", size=%"  PRIu64 "\n",
492                                         i,
493                                         start * DISK_SECTOR_SIZE, sect * DISK_SECTOR_SIZE,
494                                         (sect - start) * DISK_SECTOR_SIZE);
495                 printf("%" PRIu64 "\n", start * DISK_SECTOR_SIZE);
496                 printf("%" PRIu64 "\n", (sect - start) * DISK_SECTOR_SIZE);
497         }
498 
499         if (parts[0].actual_start > gpt_first_entry_sector + GPT_SIZE &&
500             allow_stub_partition && !entry_used[GPT_ENTRY_MAX - 1]) {
501                 gpte[GPT_ENTRY_MAX - 1].start = cpu_to_le64(gpt_first_entry_sector + GPT_SIZE);
502                 gpte[GPT_ENTRY_MAX - 1].end = cpu_to_le64(parts[0].actual_start - 1);
503                 gpte[GPT_ENTRY_MAX - 1].type = GUID_PARTITION_BIOS_BOOT;
504                 gpte[GPT_ENTRY_MAX - 1].guid = guid;
505                 gpte[GPT_ENTRY_MAX - 1].guid.b[sizeof(guid_t) -1] += GPT_ENTRY_MAX;
506         }
507 
508         if (gpt_last_usable_sector == 0)
509                 gpt_last_usable_sector = sect - 1;
510 
511         end = gpt_last_usable_sector + GPT_SIZE + 1;
512 
513         pte[0].type = 0xEE;
514         pte[0].start = cpu_to_le32(GPT_HEADER_SECTOR);
515         pte[0].length = cpu_to_le32(end + 1 - GPT_HEADER_SECTOR);
516         to_chs(GPT_HEADER_SECTOR, pte[0].chs_start);
517         to_chs(end, pte[0].chs_end);
518 
519         gpth.last_usable = cpu_to_le64(gpt_last_usable_sector);
520         gpth.alternate = cpu_to_le64(end);
521         gpth.entry_crc32 = cpu_to_le32(gpt_crc32(gpte, GPT_ENTRY_SIZE * GPT_ENTRY_MAX));
522         gpth.crc32 = cpu_to_le32(gpt_crc32((char *)&gpth, GPT_HEADER_SIZE));
523 
524         if (verbose)
525                 fprintf(stderr, "PartitionEntryLBA=%" PRIu64 ", FirstUsableLBA=%" PRIu64 ", LastUsableLBA=%" PRIu64 "\n",
526                         gpt_first_entry_sector, gpt_first_entry_sector + GPT_SIZE, gpt_last_usable_sector);
527 
528         if (!gpt_split_image)
529                 strcpy(img_name, filename);
530         else
531                 snprintf(img_name, sizeof(img_name), "%s.start", filename);
532 
533         if ((fd = open(img_name, O_WRONLY|O_CREAT|O_TRUNC, 0644)) < 0) {
534                 fprintf(stderr, "Can't open output file '%s'\n",img_name);
535                 return ret;
536         }
537 
538         lseek(fd, MBR_DISK_SIGNATURE_OFFSET, SEEK_SET);
539         if (write(fd, &signature, sizeof(signature)) != sizeof(signature)) {
540                 fputs("write failed.\n", stderr);
541                 goto fail;
542         }
543 
544         lseek(fd, MBR_PARTITION_ENTRY_OFFSET, SEEK_SET);
545         if (write(fd, pte, sizeof(struct pte) * MBR_ENTRY_MAX) != sizeof(struct pte) * MBR_ENTRY_MAX) {
546                 fputs("write failed.\n", stderr);
547                 goto fail;
548         }
549 
550         lseek(fd, MBR_BOOT_SIGNATURE_OFFSET, SEEK_SET);
551         if (write(fd, "\x55\xaa", 2) != 2) {
552                 fputs("write failed.\n", stderr);
553                 goto fail;
554         }
555 
556         if (write(fd, &gpth, GPT_HEADER_SIZE) != GPT_HEADER_SIZE) {
557                 fputs("write failed.\n", stderr);
558                 goto fail;
559         }
560 
561         lseek(fd, 2 * DISK_SECTOR_SIZE - 1, SEEK_SET);
562         if (write(fd, "\x00", 1) != 1) {
563                 fputs("write failed.\n", stderr);
564                 goto fail;
565         }
566 
567         if (!gpt_split_image || (gpt_first_entry_sector == GPT_FIRST_ENTRY_SECTOR)) {
568                 lseek(fd, gpt_first_entry_sector * DISK_SECTOR_SIZE, SEEK_SET);
569         } else {
570                 close(fd);
571 
572                 snprintf(img_name, sizeof(img_name), "%s.entry", filename);
573                 if ((fd = open(img_name, O_WRONLY|O_CREAT|O_TRUNC, 0644)) < 0) {
574                         fprintf(stderr, "Can't open output file '%s'\n",img_name);
575                         return ret;
576                 }
577         }
578 
579         if (write(fd, &gpte, GPT_ENTRY_SIZE * GPT_ENTRY_MAX) != GPT_ENTRY_SIZE * GPT_ENTRY_MAX) {
580                 fputs("write failed.\n", stderr);
581                 goto fail;
582         }
583 
584         if (gpt_alternate) {
585                 /* The alternate partition table (We omit it by default) */
586                 swap(gpth.self, gpth.alternate);
587                 gpth.first_entry = cpu_to_le64(end - GPT_ENTRY_SIZE * GPT_ENTRY_MAX / DISK_SECTOR_SIZE),
588                 gpth.crc32 = 0;
589                 gpth.crc32 = cpu_to_le32(gpt_crc32(&gpth, GPT_HEADER_SIZE));
590 
591                 if (!gpt_split_image) {
592                         lseek(fd, end * DISK_SECTOR_SIZE - GPT_ENTRY_SIZE * GPT_ENTRY_MAX, SEEK_SET);
593                 } else {
594                         close(fd);
595 
596                         end = GPT_SIZE;
597                         snprintf(img_name, sizeof(img_name), "%s.end", filename);
598                         if ((fd = open(img_name, O_WRONLY|O_CREAT|O_TRUNC, 0644)) < 0) {
599                                 fprintf(stderr, "Can't open output file '%s'\n",img_name);
600                                 return ret;
601                         }
602                 }
603 
604                 if (write(fd, &gpte, GPT_ENTRY_SIZE * GPT_ENTRY_MAX) != GPT_ENTRY_SIZE * GPT_ENTRY_MAX) {
605                         fputs("write failed.\n", stderr);
606                         goto fail;
607                 }
608 
609                 lseek(fd, end * DISK_SECTOR_SIZE, SEEK_SET);
610                 if (write(fd, &gpth, GPT_HEADER_SIZE) != GPT_HEADER_SIZE) {
611                         fputs("write failed.\n", stderr);
612                         goto fail;
613                 }
614                 lseek(fd, (end + 1) * DISK_SECTOR_SIZE -1, SEEK_SET);
615                 if (write(fd, "\x00", 1) != 1) {
616                         fputs("write failed.\n", stderr);
617                         goto fail;
618                 }
619         }
620 
621         ret = 0;
622 fail:
623         close(fd);
624         return ret;
625 }
626 
627 static void usage(char *prog)
628 {
629         fprintf(stderr, "Usage: %s [OPTION]...\n"
630                         "Generate hard drive image with predefined partitions\n"
631                         "\n"
632                         "Mandatory arguments to long options are mandatory for short options too.\n"
633                         "  -?, --help                      display this help and exit\n"
634                         "  -v, --verbose                   enable vervose output\n"
635                         "  -l, --alignment=SIZE            align partition boundaries to SIZE Kbytes\n"
636                         "  -n, --ignore-null-sized-parts   do not create null sized partitions\n"
637                         "  -D, --disable-gpt-stub-part     do not fill a gap before 1-st GPT partition\n"
638                         "  -o, --output=FILENAME           write an image to a file FILENAME\n"
639                         "  -h, --heads=COUNT               use CHS scheme, defines heads number\n"
640                         "  -s, --sectors=COUNT             use CHS scheme, defines sectors count\n"
641                         "  -S, --mbr-disk-signature=VALUE  defines MBR disk signature [default: 0x5452574F ('OWRT')]\n"
642                         "  -a, --active-part=PART_NUMBER   defines active (boot) partition\n"
643                         "  -g, --gpt                       use GPT instead of MBR\n"
644                         "  -G, --gpt-guid=GUID             defines custom GPT GUID\n"
645                         "  -e, --gpt-entry-offset=OFFSET   defines custom placement of GPT Entry table (default: 1K)\n"
646                         "  -d, --gpt-disk-size=SIZE        defines total size of disk image (used for ALT GPT headers)\n"
647                         "  -b, --gpt-split-images          generate 2 or 3 images (depends on entry table placement):\n"
648                         "                                    GPT header + GPT Entry Table, Alt Entry Table + ALT Header\n"
649                         "                                    GPT header,  GPT Entry Table, Alt Entry Table + ALT Header\n"
650                         "  -p, --part=SIZE[@START]         defines partition of size SIZE, started at offset START\n"
651                         "  -t, --mbr-part-type=TYPE        defines partition type by MBR partition type\n"
652                         "  -T, --gpt-part-type=TYPE_NAME   defines partinion type by GPT type name\n"
653                         "  -N, --gpt-part-name=NAME        defines GPT partition name\n"
654                         "  -r, --gpt-part-attr-required    mark partition with GPT required attribute\n"
655                         "  -B, --gpt-part-attr-bootable    mark partition with GPT bootable attribute\n"
656                         "  -H, --gpt-part-hybrid           put GPT partition to the MBR as well\n"
657                         "  -i, --gpt-part-index=INDEX      use custom INDEX for the partition in the GPT Entry Table\n",
658                         prog);
659 
660         exit(EXIT_FAILURE);
661 }
662 
663 static guid_t type_to_guid_and_name(unsigned char type, char **name)
664 {
665         guid_t guid = GUID_PARTITION_BASIC_DATA;
666 
667         switch (type) {
668                 case 0xef:
669                         if(*name == NULL)
670                                 *name = "EFI System Partition";
671                         guid = GUID_PARTITION_SYSTEM;
672                         break;
673                 case 0x83:
674                         guid = GUID_PARTITION_LINUX_FS_GUID;
675                         break;
676                 case 0x2e:
677                         guid = GUID_PARTITION_LINUX_FIT_GUID;
678                         break;
679         }
680 
681         return guid;
682 }
683 
684 int main (int argc, char **argv)
685 {
686         unsigned char type = 0x83;
687         char *p;
688         int ch;
689         int part = 0;
690         unsigned part_index = 0;
691         char *name = NULL;
692         unsigned short int hybrid = 0, required = 0, bootable = 0;
693         uint64_t total_sectors;
694         uint32_t signature = 0x5452574F; /* 'OWRT' */
695         guid_t guid = GUID_INIT( signature, 0x2211, 0x4433, \
696                         0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0x00);
697 
698         while (1) {
699                 int option_index = 0;
700                 static struct option long_options[] = {
701                         {"help",                        no_argument,            0,      '?'},
702                         {"verbose",                     no_argument,            0,      'v'},
703                         {"kb_alignment",                required_argument,      0,      'l'},
704                         {"ignore-null-sized-parts",     no_argument,            0,      'n'},
705                         {"disable-gpt-stub-part",       no_argument,            0,      'D'},
706                         {"output",                      required_argument,      0,      'o'},
707                         {"heads",                       required_argument,      0,      'h'},
708                         {"sectors",                     required_argument,      0,      's'},
709                         {"mbr-disk-signature",          required_argument,      0,      'S'},
710                         {"active-part",                 required_argument,      0,      'a'},
711                         {"gpt",                         no_argument,            0,      'g'},
712                         {"gpt-guid",                    required_argument,      0,      'G'},
713                         {"gpt-entry-offset",            required_argument,      0,      'e'},
714                         {"gpt-disk-size",               required_argument,      0,      'd'},
715                         {"gpt-split-images",            no_argument,            0,      'b'},
716                         {"part",                        required_argument,      0,      'p'},
717                         {"mbr-part-type",               required_argument,      0,      't'},
718                         {"gpt-part-type",               required_argument,      0,      'T'},
719                         {"gpt-part-name",               required_argument,      0,      'N'},
720                         {"gpt-part-attr-required",      no_argument,            0,      'r'},
721                         {"gpt-part-attr-bootable",      no_argument,            0,      'B'},
722                         {"gpt-part-hybrid",             no_argument,            0,      'H'},
723                         {"gpt-part-index",              required_argument,      0,      'i'},
724                         {NULL,                          0,                      0,       0 },
725                 };
726 
727                 ch = getopt_long(argc, argv, "?h:s:p:a:t:T:o:DvnbHN:gl:rBS:G:e:d:i:",
728                                  long_options, &option_index);
729                 if (ch == -1)
730                         break;
731 
732                 switch (ch) {
733                 case 'o':
734                         filename = optarg;
735                         break;
736                 case 'v':
737                         verbose++;
738                         break;
739                 case 'D':
740                         allow_stub_partition = false;
741                         break;
742                 case 'n':
743                         ignore_null_sized_partition = true;
744                         break;
745                 case 'g':
746                         use_guid_partition_table = 1;
747                         break;
748                 case 'H':
749                         hybrid = 1;
750                         break;
751                 case 'e':
752                         /* based on DISK_SECTOR_SIZE = 512 */
753                         gpt_first_entry_sector = 2 * to_kbytes(optarg);
754                         if (gpt_first_entry_sector < GPT_FIRST_ENTRY_SECTOR) {
755                                 fprintf(stderr, "GPT First Entry offset must not be smaller than %d KBytes\n",
756                                         GPT_FIRST_ENTRY_SECTOR / 2);
757                                 exit(EXIT_FAILURE);
758                         }
759                         break;
760                 case 'd':
761                         /*
762                          * Zero disk_size is specially allowed. It means: find a disk size
763                          * on the base of provided partitions list.
764                          *
765                          * based on DISK_SECTOR_SIZE = 512
766                          */
767                         gpt_alternate = true;
768                         total_sectors = 2 * to_kbytes(optarg);
769                         if (total_sectors != 0) {
770                                 if (total_sectors <= 2 * GPT_SIZE + 3) {
771                                         fprintf(stderr, "GPT disk size must be larger than %d KBytes\n",
772                                                 (2 * GPT_SIZE + 3) * DISK_SECTOR_SIZE / 1024);
773                                         exit(EXIT_FAILURE);
774                                 }
775                                 gpt_last_usable_sector = total_sectors - GPT_SIZE - 2;
776                         }
777                         break;
778                 case 'b':
779                         gpt_alternate = true;
780                         gpt_split_image = true;
781                         break;
782                 case 'h':
783                         heads = (int)strtoul(optarg, NULL, 0);
784                         break;
785                 case 's':
786                         sectors = (int)strtoul(optarg, NULL, 0);
787                         break;
788                 case 'p':
789                         if (part > GPT_ENTRY_MAX - 1 || (!use_guid_partition_table && part > 3)) {
790                                 fputs("Too many partitions\n", stderr);
791                                 exit(EXIT_FAILURE);
792                         }
793                         if (entry_used[part_index]) {
794                                 fprintf(stderr, "Partition entry with index %d already defined\n", part_index);
795                                 exit(EXIT_FAILURE);
796                         }
797 
798                         p = strchr(optarg, '@');
799                         if (p) {
800                                 *(p++) = 0;
801                                 parts[part].start = to_kbytes(p);
802                         }
803                         if (!parts[part].has_guid)
804                                 parts[part].guid = type_to_guid_and_name(type, &name);
805 
806                         parts[part].size = to_kbytes(optarg);
807                         parts[part].required = required;
808                         parts[part].bootable = bootable;
809                         parts[part].name = name;
810                         parts[part].hybrid = hybrid;
811                         parts[part].part_index = part_index;
812                         fprintf(stderr, "part %lld %lld\n", parts[part].start, parts[part].size);
813                         parts[part++].type = type;
814                         /*
815                          * reset 'name','required' and 'hybrid'
816                          * 'type' is deliberately inherited from the previous delcaration
817                          */
818                         name = NULL;
819                         required = 0;
820                         bootable = 0;
821                         hybrid = 0;
822 
823                         /* mark index as used, switch to next index */
824                         entry_used[part_index++] = true;
825                         if (part_index > GPT_ENTRY_MAX - 1 ||
826                             (!use_guid_partition_table && part_index > 3))
827                                 part_index = 0;
828 
829                         break;
830                 case 'N':
831                         name = optarg;
832                         break;
833                 case 'r':
834                         required = 1;
835                         break;
836                 case 'i':
837                         part_index = (int)strtoul(optarg, NULL, 0);
838                         if (part_index > GPT_ENTRY_MAX - 1 ||
839                             (!use_guid_partition_table && part_index > 3)) {
840                                 fprintf(stderr, "Too big GPT/MBR entry index %d\n", part_index);
841                                 exit(EXIT_FAILURE);
842                         }
843                         break;
844                 case 't':
845                         type = (char)strtoul(optarg, NULL, 16);
846                         break;
847                 case 'a':
848                         active = (int)strtoul(optarg, NULL, 0);
849                         break;
850                 case 'l':
851                         kb_align = (int)strtoul(optarg, NULL, 0) * 2;
852                         break;
853                 case 'S':
854                         signature = strtoul(optarg, NULL, 0);
855                         break;
856                 case 'T':
857                         if (!parse_gpt_parttype(optarg, &parts[part])) {
858                                 fprintf(stderr,
859                                         "Invalid GPT partition type \"%s\"\n",
860                                         optarg);
861                                 exit(EXIT_FAILURE);
862                         }
863                         break;
864                 case 'G':
865                         if (guid_parse(optarg, &guid)) {
866                                 fputs("Invalid guid string\n", stderr);
867                                 exit(EXIT_FAILURE);
868                         }
869                         break;
870                 case 'B':
871                         bootable = 1;
872                         break;
873                 case '?':
874                 default:
875                         usage(argv[0]);
876                 }
877         }
878         argc -= optind;
879         if (argc || (!use_guid_partition_table && ((heads <= 0) || (sectors <= 0))) || !filename)
880                 usage(argv[0]);
881 
882         if ((use_guid_partition_table && active > GPT_ENTRY_MAX) ||
883             (!use_guid_partition_table && active > MBR_ENTRY_MAX) ||
884             active < 0)
885                 active  = 0;
886 
887         if (use_guid_partition_table) {
888                 heads = 254;
889                 sectors = 63;
890                 return gen_gptable(signature, guid, part) ? EXIT_FAILURE : EXIT_SUCCESS;
891         }
892 
893         return gen_ptable(signature, part) ? EXIT_FAILURE : EXIT_SUCCESS;
894 }
895 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt