1/* See LICENSE file for copyright and license details. */
2#include "diskutil.h"
3#include "util.h"
4
5#include <fcntl.h>
6#include <stdio.h>
7#include <stdlib.h>
8#include <string.h>
9#include <unistd.h>
10
11struct MbrPartition {
12 uint8_t boot;
13 uint8_t start_chs[3];
14 uint8_t type;
15 uint8_t end_chs[3];
16 uint32_t start_lba;
17 uint32_t size;
18} __attribute__((packed));
19
20struct MbrHeader {
21 uint8_t code[446];
22 struct MbrPartition parts[4];
23 uint8_t sig[2];
24} __attribute__((packed));
25
26struct GptHeader {
27 uint8_t sig[8];
28 uint32_t rev;
29 uint32_t size;
30 uint32_t crc;
31 uint32_t reserved;
32 uint64_t current_lba;
33 uint64_t backup_lba;
34 uint64_t first_usable;
35 uint64_t last_usable;
36 uint8_t disk_guid[16];
37 uint64_t partition_lba;
38 uint32_t num_parts;
39 uint32_t part_size;
40 uint32_t parts_crc;
41} __attribute__((packed));
42
43struct GptPartition {
44 uint8_t type_guid[16];
45 uint8_t part_guid[16];
46 uint64_t start_lba;
47 uint64_t end_lba;
48 uint64_t flags;
49 uint16_t name[36];
50} __attribute__((packed));
51
52struct BsdPartition {
53 uint32_t size;
54 uint32_t offset;
55 uint16_t offset_h;
56 uint16_t size_h;
57 uint8_t fstype;
58 uint8_t fragblock;
59 uint16_t cpg;
60} __attribute__((packed));
61
62struct BsdDisklabel {
63 uint32_t d_magic;
64 uint16_t d_type;
65 uint16_t d_subtype;
66 char d_typename[16];
67 char d_packname[16];
68 uint32_t d_secsize;
69 uint32_t d_nsectors;
70 uint32_t d_ntracks;
71 uint32_t d_ncylinders;
72 uint32_t d_secpercyl;
73 uint32_t d_secperunit;
74 uint8_t d_uid[8];
75 uint32_t d_acylinders;
76 uint16_t d_bstarth;
77 uint16_t d_bendh;
78 uint32_t d_bstart;
79 uint32_t d_bend;
80 uint32_t d_flags;
81 uint32_t d_spare4[5];
82 uint16_t d_secperunith;
83 uint16_t d_version;
84 uint32_t d_spare[4];
85 uint32_t d_magic2;
86 uint16_t d_checksum;
87 uint16_t d_npartitions;
88 uint32_t d_spare2;
89 uint32_t d_spare3;
90 struct BsdPartition d_partitions[16];
91} __attribute__((packed));
92
93static uint32_t crc32_table[256];
94static int crc32_table_initialized = 0;
95
96static void
97init_crc32_table(void)
98{
99 uint32_t i, j, c;
100 for (i = 0; i < 256; i++) {
101 c = i;
102 for (j = 0; j < 8; j++) {
103 if (c & 1)
104 c = 0xedb88320U ^ (c >> 1);
105 else
106 c = c >> 1;
107 }
108 crc32_table[i] = c;
109 }
110 crc32_table_initialized = 1;
111}
112
113static uint32_t
114crc32(uint32_t crc, const void *buf, size_t len)
115{
116 const uint8_t *p = buf;
117 if (!crc32_table_initialized)
118 init_crc32_table();
119 while (len--)
120 crc = (crc >> 8) ^ crc32_table[(crc ^ *p++) & 0xFF];
121 return crc;
122}
123
124static int opt_list = 0;
125static int opt_print = 0;
126static int opt_init_gpt = 0;
127static int opt_init_mbr = 0;
128static int opt_init_bsd = 0;
129static int opt_add = 0;
130static int opt_del = 0;
131static int opt_part_idx = -1;
132static int opt_part_is_letter = 0;
133static uint64_t opt_start = 0;
134static uint64_t opt_end = 0;
135static const char *opt_type = NULL;
136
137static void
138usage(void)
139{
140 eprintf(
141 "usage: %s [-l] [-p] [-g] [-m] [-s] [-a] [-d] [-n index] [-b "
142 "start] [-e end] [-t type] [device]\n",
143 argv0
144 );
145}
146
147static void
148mbr_print(struct MbrHeader *mbr, const char *path)
149{
150 int i;
151 printf("Disk: %s\n", path);
152 printf("Partition table (MBR/dos):\n");
153 printf("%-5s %-4s %-12s %-12s %-4s\n", "Index", "Boot", "Start", "Size", "Type");
154 for (i = 0; i < 4; i++) {
155 struct MbrPartition *p = &mbr->parts[i];
156 if (p->size == 0)
157 continue;
158 printf(
159 "%-5d %-4s %-12u %-12u 0x%02x\n",
160 i + 1,
161 p->boot == 0x80 ? "Yes" : "No",
162 p->start_lba,
163 p->size,
164 p->type
165 );
166 }
167}
168
169static void
170gpt_print(struct GptHeader *hdr, struct GptPartition *parts, const char *path)
171{
172 uint32_t i;
173 char guid[37];
174 printf("Disk: %s\n", path);
175 printf("Partition table (GPT):\n");
176 printf("%-5s %-12s %-12s %-36s\n", "Index", "Start", "End", "Type GUID");
177 for (i = 0; i < hdr->num_parts; i++) {
178 struct GptPartition *p = &parts[i];
179 if (p->start_lba == 0 && p->end_lba == 0)
180 continue;
181
182 snprintf(
183 guid,
184 sizeof(guid),
185 "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%"
186 "02x%02x%02x%02x",
187 p->type_guid[3],
188 p->type_guid[2],
189 p->type_guid[1],
190 p->type_guid[0],
191 p->type_guid[5],
192 p->type_guid[4],
193 p->type_guid[7],
194 p->type_guid[6],
195 p->type_guid[8],
196 p->type_guid[9],
197 p->type_guid[10],
198 p->type_guid[11],
199 p->type_guid[12],
200 p->type_guid[13],
201 p->type_guid[14],
202 p->type_guid[15]
203 );
204
205 printf(
206 "%-5d %-12llu %-12llu %-36s\n",
207 i + 1,
208 (unsigned long long)p->start_lba,
209 (unsigned long long)p->end_lba,
210 guid
211 );
212 }
213}
214
215static int
216gpt_read(struct BlockDev *dev, struct GptHeader *hdr, struct GptPartition *parts)
217{
218 unsigned char sector[512];
219 size_t part_sectors;
220
221 if (blockdev_read(dev, 1, sector, 1) < 0)
222 return -1;
223
224 memcpy(hdr, sector, sizeof(*hdr));
225
226 if (memcmp(hdr->sig, "EFI PART", 8) != 0)
227 return -1;
228
229 part_sectors = (hdr->num_parts * hdr->part_size + dev->sec_size - 1) / dev->sec_size;
230 if (blockdev_read(dev, hdr->partition_lba, parts, part_sectors) < 0)
231 return -1;
232
233 return 0;
234}
235
236static int
237gpt_write(struct BlockDev *dev, struct GptHeader *hdr, struct GptPartition *parts)
238{
239 unsigned char sector[512];
240 struct MbrHeader pmbr;
241 struct GptHeader backup_hdr;
242 uint64_t limit;
243 size_t part_sectors;
244
245 part_sectors = (hdr->num_parts * hdr->part_size + dev->sec_size - 1) / dev->sec_size;
246
247 hdr->parts_crc = crc32(~0U, parts, hdr->num_parts * hdr->part_size) ^ ~0U;
248
249 hdr->crc = 0;
250 hdr->crc = crc32(~0U, hdr, hdr->size) ^ ~0U;
251
252 memset(&pmbr, 0, sizeof(pmbr));
253 pmbr.parts[0].type = 0xEE;
254 pmbr.parts[0].start_lba = 1;
255 limit = dev->size / dev->sec_size - 1;
256 pmbr.parts[0].size = limit > 0xFFFFFFFFU ? 0xFFFFFFFFU : (uint32_t)limit;
257 pmbr.sig[0] = 0x55;
258 pmbr.sig[1] = 0xAA;
259 if (blockdev_write(dev, 0, &pmbr, 1) < 0)
260 return -1;
261
262 memset(sector, 0, sizeof(sector));
263 memcpy(sector, hdr, sizeof(*hdr));
264 if (blockdev_write(dev, 1, sector, 1) < 0)
265 return -1;
266 if (blockdev_write(dev, hdr->partition_lba, parts, part_sectors) < 0)
267 return -1;
268
269 backup_hdr = *hdr;
270 backup_hdr.current_lba = hdr->backup_lba;
271 backup_hdr.backup_lba = hdr->current_lba;
272 backup_hdr.partition_lba = backup_hdr.current_lba - part_sectors;
273
274 backup_hdr.crc = 0;
275 backup_hdr.crc = crc32(~0U, &backup_hdr, backup_hdr.size) ^ ~0U;
276
277 if (blockdev_write(dev, backup_hdr.partition_lba, parts, part_sectors) < 0)
278 return -1;
279
280 memset(sector, 0, sizeof(sector));
281 memcpy(sector, &backup_hdr, sizeof(backup_hdr));
282 if (blockdev_write(dev, backup_hdr.current_lba, sector, 1) < 0)
283 return -1;
284
285 return 0;
286}
287
288static uint16_t
289bsd_dkcksum(void *lp, size_t nparts)
290{
291 uint16_t *start;
292 uint16_t *end;
293 uint16_t sum = 0;
294
295 start = (uint16_t *)lp;
296 end = (uint16_t *)((char *)lp + 148 + nparts * 16);
297 while (start < end)
298 sum ^= *start++;
299 return sum;
300}
301
302static int
303bsd_is_partition_type(uint8_t type)
304{
305 return type == 0xa5 || type == 0xa6 || type == 0xa9;
306}
307
308static int
309bsd_read(struct BlockDev *dev, uint64_t base_sec, struct BsdDisklabel *lp)
310{
311 unsigned char sector[512];
312 if (blockdev_read(dev, base_sec + 1, sector, 1) < 0)
313 return -1;
314 memcpy(lp, sector, sizeof(*lp));
315 if (lp->d_magic != 0x82564557U || lp->d_magic2 != 0x82564557U)
316 return -1;
317 return 0;
318}
319
320static int
321bsd_write(struct BlockDev *dev, uint64_t base_sec, struct BsdDisklabel *lp)
322{
323 unsigned char sector[512];
324 memset(sector, 0, sizeof(sector));
325 lp->d_checksum = 0;
326 lp->d_checksum = bsd_dkcksum(lp, lp->d_npartitions);
327 memcpy(sector, lp, sizeof(*lp));
328 if (blockdev_write(dev, base_sec + 1, sector, 1) < 0)
329 return -1;
330 return 0;
331}
332
333static void
334bsd_print(struct BsdDisklabel *lp, const char *path, uint64_t base_sec)
335{
336 uint64_t start, size;
337 int i;
338
339 printf("Disk: %s (at sector %llu)\n", path, (unsigned long long)base_sec);
340 printf("Partition table (BSD disklabel):\n");
341 printf("%-5s %-12s %-12s %-10s\n", "Index", "Start", "Size", "Type");
342 for (i = 0; i < lp->d_npartitions; i++) {
343 struct BsdPartition *p = &lp->d_partitions[i];
344 start = ((uint64_t)p->offset_h << 32) | p->offset;
345 size = ((uint64_t)p->size_h << 32) | p->size;
346 if (size == 0)
347 continue;
348 printf(
349 "%-5c %-12llu %-12llu 0x%02x\n",
350 'a' + i,
351 (unsigned long long)start,
352 (unsigned long long)size,
353 p->fstype
354 );
355 }
356}
357
358static int
359bsd_find_label(struct BlockDev *dev, uint64_t *base_sec, struct BsdDisklabel *lp)
360{
361 struct MbrHeader mbr;
362 int i;
363
364 if (bsd_read(dev, 0, lp) == 0) {
365 *base_sec = 0;
366 return 0;
367 }
368
369 if (blockdev_read(dev, 0, &mbr, 1) == 0 && mbr.sig[0] == 0x55 && mbr.sig[1] == 0xAA) {
370 for (i = 0; i < 4; i++) {
371 if (mbr.parts[i].size > 0 && bsd_is_partition_type(mbr.parts[i].type)) {
372 if (bsd_read(dev, mbr.parts[i].start_lba, lp) == 0) {
373 *base_sec = mbr.parts[i].start_lba;
374 return 0;
375 }
376 }
377 }
378 }
379
380 return -1;
381}
382
383static int
384do_print(const char *path)
385{
386 struct BlockDev dev;
387 struct MbrHeader mbr;
388 struct GptHeader gpt_hdr;
389 struct GptPartition gpt_parts[128];
390 struct BsdDisklabel bsd_lp;
391 int i;
392 int found_bsd = 0;
393
394 if (blockdev_open(&dev, path, 0) < 0) {
395 weprintf("cannot open %s:", path);
396 return -1;
397 }
398
399 if (gpt_read(&dev, &gpt_hdr, gpt_parts) == 0) {
400 gpt_print(&gpt_hdr, gpt_parts, path);
401 } else if (blockdev_read(&dev, 0, &mbr, 1) == 0 && mbr.sig[0] == 0x55 && mbr.sig[1] == 0xAA) {
402 for (i = 0; i < 4; i++) {
403 if (mbr.parts[i].size > 0 && bsd_is_partition_type(mbr.parts[i].type)) {
404 if (bsd_read(&dev, mbr.parts[i].start_lba, &bsd_lp) == 0) {
405 bsd_print(&bsd_lp, path, mbr.parts[i].start_lba);
406 found_bsd = 1;
407 }
408 }
409 }
410 if (!found_bsd) {
411 if (bsd_read(&dev, 0, &bsd_lp) == 0) {
412 bsd_print(&bsd_lp, path, 0);
413 } else {
414 mbr_print(&mbr, path);
415 }
416 }
417 } else {
418 if (bsd_read(&dev, 0, &bsd_lp) == 0) {
419 bsd_print(&bsd_lp, path, 0);
420 } else {
421 printf("Disk %s: unpartitioned or unknown format\n", path);
422 }
423 }
424
425 blockdev_close(&dev);
426 return 0;
427}
428
429static int
430do_fdisk(const char *path)
431{
432 struct BlockDev dev;
433 struct MbrHeader mbr;
434 struct GptHeader gpt_hdr;
435 struct GptPartition gpt_parts[128];
436 struct BsdDisklabel lp;
437 struct BsdDisklabel bsd_lp;
438 struct GptPartition *gp;
439 struct BsdPartition *bp;
440 struct MbrPartition *mp;
441 uint64_t base_sec;
442 uint64_t limit;
443 uint64_t bsd_base;
444 uint64_t size;
445 int idx;
446 int has_gpt = 0;
447 int has_bsd = 0;
448
449 if (blockdev_open(&dev, path, 1) < 0) {
450 weprintf("cannot open %s:", path);
451 return -1;
452 }
453
454 has_gpt = (gpt_read(&dev, &gpt_hdr, gpt_parts) == 0);
455
456 if (opt_init_mbr) {
457 memset(&mbr, 0, sizeof(mbr));
458 mbr.sig[0] = 0x55;
459 mbr.sig[1] = 0xAA;
460 if (blockdev_write(&dev, 0, &mbr, 1) < 0) {
461 weprintf("cannot write MBR to %s:", path);
462 blockdev_close(&dev);
463 return -1;
464 }
465 printf("Initialized MBR partition table on %s\n", path);
466 blockdev_close(&dev);
467 return 0;
468 }
469
470 if (opt_init_gpt) {
471 memset(&gpt_hdr, 0, sizeof(gpt_hdr));
472 memcpy(gpt_hdr.sig, "EFI PART", 8);
473 gpt_hdr.rev = 0x00010000;
474 gpt_hdr.size = 92;
475 gpt_hdr.current_lba = 1;
476 gpt_hdr.backup_lba = dev.size / dev.sec_size - 1;
477 gpt_hdr.first_usable = 34;
478 gpt_hdr.last_usable = gpt_hdr.backup_lba - 34;
479 gpt_hdr.partition_lba = 2;
480 gpt_hdr.num_parts = 128;
481 gpt_hdr.part_size = 128;
482 memset(gpt_parts, 0, sizeof(gpt_parts));
483
484 if (gpt_write(&dev, &gpt_hdr, gpt_parts) < 0) {
485 weprintf("cannot write GPT to %s:", path);
486 blockdev_close(&dev);
487 return -1;
488 }
489 printf("Initialized GPT partition table on %s\n", path);
490 blockdev_close(&dev);
491 return 0;
492 }
493
494 if (opt_init_bsd) {
495 base_sec = 0;
496 limit = dev.size / dev.sec_size;
497
498 if (blockdev_read(&dev, 0, &mbr, 1) == 0 && mbr.sig[0] == 0x55 && mbr.sig[1] == 0xAA) {
499 if (!opt_part_is_letter && opt_part_idx >= 1 && opt_part_idx <= 4) {
500 mp = &mbr.parts[opt_part_idx - 1];
501 if (mp->size > 0) {
502 base_sec = mp->start_lba;
503 limit = base_sec + mp->size;
504 }
505 }
506 }
507
508 memset(&lp, 0, sizeof(lp));
509 lp.d_magic = 0x82564557U;
510 lp.d_magic2 = 0x82564557U;
511 lp.d_secsize = dev.sec_size;
512 lp.d_npartitions = 8;
513 lp.d_partitions[2].offset = (uint32_t)base_sec;
514 lp.d_partitions[2].offset_h = (uint16_t)(base_sec >> 32);
515 size = limit - base_sec;
516 lp.d_partitions[2].size = (uint32_t)size;
517 lp.d_partitions[2].size_h = (uint16_t)(size >> 32);
518 lp.d_partitions[2].fstype = 0;
519
520 if (bsd_write(&dev, base_sec, &lp) < 0) {
521 weprintf("cannot write BSD disklabel to %s:", path);
522 blockdev_close(&dev);
523 return -1;
524 }
525 printf(
526 "Initialized BSD disklabel on %s (at sector %llu)\n", path, (unsigned long long)base_sec
527 );
528 blockdev_close(&dev);
529 return 0;
530 }
531
532 if (opt_add) {
533 if (opt_part_idx < 1) {
534 weprintf("add requires partition index (-n)\n");
535 blockdev_close(&dev);
536 return -1;
537 }
538
539 if (has_gpt) {
540 if (opt_part_idx > 128) {
541 weprintf("GPT partition index must be 1-128\n");
542 blockdev_close(&dev);
543 return -1;
544 }
545 gp = &gpt_parts[opt_part_idx - 1];
546 gp->start_lba = opt_start;
547 gp->end_lba = opt_end;
548 gp->type_guid[0] = 0xAF;
549 gp->type_guid[1] = 0x3D;
550 gp->type_guid[2] = 0xC6;
551 gp->type_guid[3] = 0x0F;
552 gp->type_guid[4] = 0x83;
553 gp->type_guid[5] = 0x84;
554 gp->type_guid[6] = 0x72;
555 gp->type_guid[7] = 0x47;
556 gp->type_guid[8] = 0x8E;
557 gp->type_guid[9] = 0x79;
558 gp->type_guid[10] = 0x3D;
559 gp->type_guid[11] = 0x69;
560 gp->type_guid[12] = 0xD8;
561 gp->type_guid[13] = 0x47;
562 gp->type_guid[14] = 0x7D;
563 gp->type_guid[15] = 0xE4;
564
565 if (gpt_write(&dev, &gpt_hdr, gpt_parts) < 0) {
566 weprintf("cannot update GPT on %s:", path);
567 blockdev_close(&dev);
568 return -1;
569 }
570 printf("Added GPT partition %d to %s\n", opt_part_idx, path);
571 } else {
572 has_bsd = (bsd_find_label(&dev, &bsd_base, &bsd_lp) == 0);
573 if (opt_part_is_letter || has_bsd) {
574 if (!has_bsd) {
575 weprintf(
576 "BSD disklabel not found on "
577 "%s\n",
578 path
579 );
580 blockdev_close(&dev);
581 return -1;
582 }
583 idx = opt_part_idx - 1;
584 if (idx >= 16) {
585 weprintf(
586 "BSD partition index must be "
587 "a-p\n"
588 );
589 blockdev_close(&dev);
590 return -1;
591 }
592 bp = &bsd_lp.d_partitions[idx];
593 bp->offset = (uint32_t)opt_start;
594 bp->offset_h = (uint16_t)(opt_start >> 32);
595 size = opt_end - opt_start + 1;
596 bp->size = (uint32_t)size;
597 bp->size_h = (uint16_t)(size >> 32);
598 bp->fstype = opt_type ? (uint8_t)strtoul(opt_type, NULL, 0) : 7;
599 if (idx >= bsd_lp.d_npartitions)
600 bsd_lp.d_npartitions = idx + 1;
601
602 if (bsd_write(&dev, bsd_base, &bsd_lp) < 0) {
603 weprintf(
604 "cannot update BSD disklabel "
605 "on %s:",
606 path
607 );
608 blockdev_close(&dev);
609 return -1;
610 }
611 printf("Added BSD partition %c to %s\n", 'a' + idx, path);
612 } else {
613 if (blockdev_read(&dev, 0, &mbr, 1) < 0) {
614 weprintf("cannot read MBR from %s:", path);
615 blockdev_close(&dev);
616 return -1;
617 }
618 if (opt_part_idx > 4) {
619 weprintf(
620 "MBR partition index must be "
621 "1-4\n"
622 );
623 blockdev_close(&dev);
624 return -1;
625 }
626 mp = &mbr.parts[opt_part_idx - 1];
627 mp->start_lba = (uint32_t)opt_start;
628 mp->size = (uint32_t)(opt_end - opt_start + 1);
629 mp->type = opt_type ? (uint8_t)strtoul(opt_type, NULL, 0) : 0x83;
630 mbr.sig[0] = 0x55;
631 mbr.sig[1] = 0xAA;
632
633 if (blockdev_write(&dev, 0, &mbr, 1) < 0) {
634 weprintf("cannot update MBR on %s:", path);
635 blockdev_close(&dev);
636 return -1;
637 }
638 printf("Added MBR partition %d to %s\n", opt_part_idx, path);
639 }
640 }
641 }
642
643 if (opt_del) {
644 if (opt_part_idx < 1) {
645 weprintf("delete requires partition index (-n)\n");
646 blockdev_close(&dev);
647 return -1;
648 }
649
650 if (has_gpt) {
651 if (opt_part_idx > 128) {
652 weprintf("GPT partition index must be 1-128\n");
653 blockdev_close(&dev);
654 return -1;
655 }
656 memset(&gpt_parts[opt_part_idx - 1], 0, sizeof(struct GptPartition));
657 if (gpt_write(&dev, &gpt_hdr, gpt_parts) < 0) {
658 weprintf("cannot update GPT on %s:", path);
659 blockdev_close(&dev);
660 return -1;
661 }
662 printf("Deleted GPT partition %d from %s\n", opt_part_idx, path);
663 } else {
664 has_bsd = (bsd_find_label(&dev, &bsd_base, &bsd_lp) == 0);
665 if (opt_part_is_letter || has_bsd) {
666 if (!has_bsd) {
667 weprintf(
668 "BSD disklabel not found on "
669 "%s\n",
670 path
671 );
672 blockdev_close(&dev);
673 return -1;
674 }
675 idx = opt_part_idx - 1;
676 if (idx >= 16) {
677 weprintf(
678 "BSD partition index must be "
679 "a-p\n"
680 );
681 blockdev_close(&dev);
682 return -1;
683 }
684 memset(&bsd_lp.d_partitions[idx], 0, sizeof(struct BsdPartition));
685 if (bsd_write(&dev, bsd_base, &bsd_lp) < 0) {
686 weprintf(
687 "cannot update BSD disklabel "
688 "on %s:",
689 path
690 );
691 blockdev_close(&dev);
692 return -1;
693 }
694 printf("Deleted BSD partition %c from %s\n", 'a' + idx, path);
695 } else {
696 if (blockdev_read(&dev, 0, &mbr, 1) < 0) {
697 weprintf("cannot read MBR from %s:", path);
698 blockdev_close(&dev);
699 return -1;
700 }
701 if (opt_part_idx > 4) {
702 weprintf(
703 "MBR partition index must be "
704 "1-4\n"
705 );
706 blockdev_close(&dev);
707 return -1;
708 }
709 mp = &mbr.parts[opt_part_idx - 1];
710 memset(mp, 0, sizeof(struct MbrPartition));
711 if (blockdev_write(&dev, 0, &mbr, 1) < 0) {
712 weprintf("cannot update MBR on %s:", path);
713 blockdev_close(&dev);
714 return -1;
715 }
716 printf("Deleted MBR partition %d from %s\n", opt_part_idx, path);
717 }
718 }
719 }
720
721 blockdev_close(&dev);
722 return 0;
723}
724
725// ?man fdisk: partition table manipulator
726// ?man arguments: [-l] [-p] [-g] [-m] [-s] [-a] [-d] [-n index] [-b start] [-e
727// end] [-t type] [device] ?man fdisk performs partition table operations for
728// MBR, GPT and BSD disklabels
729int
730main(int argc, char *argv[])
731{
732 int ret = 0;
733
734 ARGBEGIN
735 {
736 // ?man -l:list partitions of all devices
737 case 'l':
738 opt_list = 1;
739 break;
740 // ?man -p:print partition table of specified device
741 case 'p':
742 opt_print = 1;
743 break;
744 // ?man -g:initialize disk with GPT
745 case 'g':
746 opt_init_gpt = 1;
747 break;
748 // ?man -m:initialize disk with MBR
749 case 'm':
750 opt_init_mbr = 1;
751 break;
752 // ?man -s:initialize disk with BSD disklabel
753 case 's':
754 opt_init_bsd = 1;
755 break;
756 // ?man -a:add partition
757 case 'a':
758 opt_add = 1;
759 break;
760 // ?man -d:delete partition
761 case 'd':
762 opt_del = 1;
763 break;
764 // ?man -n:partition index or letter
765 case 'n': {
766 char *arg = EARGF(usage());
767 if (arg[0] >= 'a' && arg[0] <= 'p' && arg[1] == '\0') {
768 opt_part_idx = arg[0] - 'a' + 1;
769 opt_part_is_letter = 1;
770 } else {
771 opt_part_idx = (int)estrtol(arg, 10);
772 opt_part_is_letter = 0;
773 }
774 break;
775 }
776 // ?man -b:starting sector LBA
777 case 'b':
778 opt_start = (uint64_t)estrtoul(EARGF(usage()), 10);
779 break;
780 // ?man -e:ending sector LBA
781 case 'e':
782 opt_end = (uint64_t)estrtoul(EARGF(usage()), 10);
783 break;
784 // ?man -t:partition type (MBR/BSD hex or GPT string)
785 case 't':
786 opt_type = EARGF(usage());
787 break;
788 default:
789 usage();
790 }
791 ARGEND
792
793 if (opt_list) {
794 struct BlockDevInfo *list = blockdev_get_list();
795 struct BlockDevInfo *curr;
796 if (!list)
797 return 1;
798 for (curr = list; curr; curr = curr->next) {
799 do_print(curr->path);
800 }
801 blockdev_free_list(list);
802 if (fshut(stdin, "<stdin>") | fshut(stdout, "<stdout>"))
803 ret = 2;
804 return ret;
805 }
806
807 if (argc != 1)
808 usage();
809
810 if (opt_print) {
811 ret = do_print(argv[0]) < 0 ? 1 : 0;
812 } else {
813 ret = do_fdisk(argv[0]) < 0 ? 1 : 0;
814 }
815
816 if (fshut(stdin, "<stdin>") | fshut(stdout, "<stdout>"))
817 ret = 2;
818 return ret;
819}