aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/libbb.h7
-rw-r--r--libbb/human_readable.c4
-rw-r--r--util-linux/Config.src8
-rw-r--r--util-linux/fdisk.c79
-rw-r--r--util-linux/fdisk_gpt.c203
5 files changed, 275 insertions, 26 deletions
diff --git a/include/libbb.h b/include/libbb.h
index bd1d586c7..d14728ed0 100644
--- a/include/libbb.h
+++ b/include/libbb.h
@@ -746,7 +746,7 @@ char *itoa(int n) FAST_FUNC;
746char *utoa_to_buf(unsigned n, char *buf, unsigned buflen) FAST_FUNC; 746char *utoa_to_buf(unsigned n, char *buf, unsigned buflen) FAST_FUNC;
747char *itoa_to_buf(int n, char *buf, unsigned buflen) FAST_FUNC; 747char *itoa_to_buf(int n, char *buf, unsigned buflen) FAST_FUNC;
748/* Intelligent formatters of bignums */ 748/* Intelligent formatters of bignums */
749void smart_ulltoa4(unsigned long long ul, char buf[5], const char *scale) FAST_FUNC; 749void smart_ulltoa4(unsigned long long ul, char buf[4], const char *scale) FAST_FUNC;
750void smart_ulltoa5(unsigned long long ul, char buf[5], const char *scale) FAST_FUNC; 750void smart_ulltoa5(unsigned long long ul, char buf[5], const char *scale) FAST_FUNC;
751/* If block_size == 0, display size without fractional part, 751/* If block_size == 0, display size without fractional part,
752 * else display (size * block_size) with one decimal digit. 752 * else display (size * block_size) with one decimal digit.
@@ -1543,7 +1543,10 @@ void sha512_begin(sha512_ctx_t *ctx) FAST_FUNC;
1543void sha512_hash(sha512_ctx_t *ctx, const void *buffer, size_t len) FAST_FUNC; 1543void sha512_hash(sha512_ctx_t *ctx, const void *buffer, size_t len) FAST_FUNC;
1544void sha512_end(sha512_ctx_t *ctx, void *resbuf) FAST_FUNC; 1544void sha512_end(sha512_ctx_t *ctx, void *resbuf) FAST_FUNC;
1545 1545
1546 1546/* TODO: add global crc32_table pointer and create
1547 * LE and BE functions to calculate crc32 over given bytes.
1548 * Currently we have about five reimplementations...
1549 */
1547uint32_t *crc32_filltable(uint32_t *tbl256, int endian) FAST_FUNC; 1550uint32_t *crc32_filltable(uint32_t *tbl256, int endian) FAST_FUNC;
1548 1551
1549typedef struct masks_labels_t { 1552typedef struct masks_labels_t {
diff --git a/libbb/human_readable.c b/libbb/human_readable.c
index 22dc5d23f..50cbe41bb 100644
--- a/libbb/human_readable.c
+++ b/libbb/human_readable.c
@@ -94,7 +94,7 @@ const char* FAST_FUNC make_human_readable_str(unsigned long long val,
94 94
95/* Convert unsigned long long value into compact 5-char representation. 95/* Convert unsigned long long value into compact 5-char representation.
96 * String is not terminated (buf[5] is untouched) */ 96 * String is not terminated (buf[5] is untouched) */
97void FAST_FUNC smart_ulltoa5(unsigned long long ul, char buf[6], const char *scale) 97void FAST_FUNC smart_ulltoa5(unsigned long long ul, char buf[5], const char *scale)
98{ 98{
99 const char *fmt; 99 const char *fmt;
100 char c; 100 char c;
@@ -150,7 +150,7 @@ void FAST_FUNC smart_ulltoa5(unsigned long long ul, char buf[6], const char *sca
150/* Convert unsigned long long value into compact 4-char 150/* Convert unsigned long long value into compact 4-char
151 * representation. Examples: "1234", "1.2k", " 27M", "123T" 151 * representation. Examples: "1234", "1.2k", " 27M", "123T"
152 * String is not terminated (buf[4] is untouched) */ 152 * String is not terminated (buf[4] is untouched) */
153void FAST_FUNC smart_ulltoa4(unsigned long long ul, char buf[5], const char *scale) 153void FAST_FUNC smart_ulltoa4(unsigned long long ul, char buf[4], const char *scale)
154{ 154{
155 const char *fmt; 155 const char *fmt;
156 char c; 156 char c;
diff --git a/util-linux/Config.src b/util-linux/Config.src
index afa30923b..19b309e57 100644
--- a/util-linux/Config.src
+++ b/util-linux/Config.src
@@ -181,6 +181,14 @@ config FEATURE_OSF_LABEL
181 Enabling this option allows you to create or change BSD disklabels 181 Enabling this option allows you to create or change BSD disklabels
182 and define and edit BSD disk slices. 182 and define and edit BSD disk slices.
183 183
184config FEATURE_GPT_LABEL
185 bool "Support GPT disklabels"
186 default n
187 depends on FDISK && FEATURE_FDISK_WRITABLE
188 help
189 Enabling this option allows you to view GUID Partition Table
190 disklabels.
191
184config FEATURE_FDISK_ADVANCED 192config FEATURE_FDISK_ADVANCED
185 bool "Support expert mode" 193 bool "Support expert mode"
186 default y 194 default y
diff --git a/util-linux/fdisk.c b/util-linux/fdisk.c
index b6417a355..3f2e0d3ae 100644
--- a/util-linux/fdisk.c
+++ b/util-linux/fdisk.c
@@ -107,12 +107,30 @@ struct partition {
107 unsigned char size4[4]; /* nr of sectors in partition */ 107 unsigned char size4[4]; /* nr of sectors in partition */
108} PACKED; 108} PACKED;
109 109
110/*
111 * per partition table entry data
112 *
113 * The four primary partitions have the same sectorbuffer (MBRbuffer)
114 * and have NULL ext_pointer.
115 * Each logical partition table entry has two pointers, one for the
116 * partition and one link to the next one.
117 */
118struct pte {
119 struct partition *part_table; /* points into sectorbuffer */
120 struct partition *ext_pointer; /* points into sectorbuffer */
121 sector_t offset_from_dev_start; /* disk sector number */
122 char *sectorbuffer; /* disk sector contents */
123#if ENABLE_FEATURE_FDISK_WRITABLE
124 char changed; /* boolean */
125#endif
126};
127
110#define unable_to_open "can't open '%s'" 128#define unable_to_open "can't open '%s'"
111#define unable_to_read "can't read from %s" 129#define unable_to_read "can't read from %s"
112#define unable_to_seek "can't seek on %s" 130#define unable_to_seek "can't seek on %s"
113 131
114enum label_type { 132enum label_type {
115 LABEL_DOS, LABEL_SUN, LABEL_SGI, LABEL_AIX, LABEL_OSF 133 LABEL_DOS, LABEL_SUN, LABEL_SGI, LABEL_AIX, LABEL_OSF, LABEL_GPT
116}; 134};
117 135
118#define LABEL_IS_DOS (LABEL_DOS == current_label_type) 136#define LABEL_IS_DOS (LABEL_DOS == current_label_type)
@@ -149,6 +167,14 @@ enum label_type {
149#define STATIC_OSF extern 167#define STATIC_OSF extern
150#endif 168#endif
151 169
170#if ENABLE_FEATURE_GPT_LABEL
171#define LABEL_IS_GPT (LABEL_GPT == current_label_type)
172#define STATIC_GPT static
173#else
174#define LABEL_IS_GPT 0
175#define STATIC_GPT extern
176#endif
177
152enum action { OPEN_MAIN, TRY_ONLY, CREATE_EMPTY_DOS, CREATE_EMPTY_SUN }; 178enum action { OPEN_MAIN, TRY_ONLY, CREATE_EMPTY_DOS, CREATE_EMPTY_SUN };
153 179
154static void update_units(void); 180static void update_units(void);
@@ -162,6 +188,7 @@ static sector_t read_int(sector_t low, sector_t dflt, sector_t high, sector_t ba
162#endif 188#endif
163static const char *partition_type(unsigned char type); 189static const char *partition_type(unsigned char type);
164static void get_geometry(void); 190static void get_geometry(void);
191static void read_pte(struct pte *pe, sector_t offset);
165#if ENABLE_FEATURE_SUN_LABEL || ENABLE_FEATURE_FDISK_WRITABLE 192#if ENABLE_FEATURE_SUN_LABEL || ENABLE_FEATURE_FDISK_WRITABLE
166static int get_boot(enum action what); 193static int get_boot(enum action what);
167#else 194#else
@@ -174,24 +201,6 @@ static int get_boot(void);
174static sector_t get_start_sect(const struct partition *p); 201static sector_t get_start_sect(const struct partition *p);
175static sector_t get_nr_sects(const struct partition *p); 202static sector_t get_nr_sects(const struct partition *p);
176 203
177/*
178 * per partition table entry data
179 *
180 * The four primary partitions have the same sectorbuffer (MBRbuffer)
181 * and have NULL ext_pointer.
182 * Each logical partition table entry has two pointers, one for the
183 * partition and one link to the next one.
184 */
185struct pte {
186 struct partition *part_table; /* points into sectorbuffer */
187 struct partition *ext_pointer; /* points into sectorbuffer */
188 sector_t offset_from_dev_start; /* disk sector number */
189 char *sectorbuffer; /* disk sector contents */
190#if ENABLE_FEATURE_FDISK_WRITABLE
191 char changed; /* boolean */
192#endif
193};
194
195/* DOS partition types */ 204/* DOS partition types */
196 205
197static const char *const i386_sys_types[] = { 206static const char *const i386_sys_types[] = {
@@ -653,6 +662,8 @@ STATIC_OSF void bsd_select(void);
653STATIC_OSF void xbsd_print_disklabel(int); 662STATIC_OSF void xbsd_print_disklabel(int);
654#include "fdisk_osf.c" 663#include "fdisk_osf.c"
655 664
665#include "fdisk_gpt.c"
666
656#if ENABLE_FEATURE_SGI_LABEL || ENABLE_FEATURE_SUN_LABEL 667#if ENABLE_FEATURE_SGI_LABEL || ENABLE_FEATURE_SUN_LABEL
657static uint16_t 668static uint16_t
658fdisk_swap16(uint16_t x) 669fdisk_swap16(uint16_t x)
@@ -833,6 +844,11 @@ menu(void)
833 puts("o\tcreate a new empty DOS partition table"); 844 puts("o\tcreate a new empty DOS partition table");
834 puts("q\tquit without saving changes"); 845 puts("q\tquit without saving changes");
835 puts("s\tcreate a new empty Sun disklabel"); /* sun */ 846 puts("s\tcreate a new empty Sun disklabel"); /* sun */
847 } else if (LABEL_IS_GPT) {
848 puts("o\tcreate a new empty DOS partition table");
849 puts("p\tprint the partition table");
850 puts("q\tquit without saving changes");
851 puts("s\tcreate a new empty Sun disklabel"); /* sun */
836 } else { 852 } else {
837 puts("a\ttoggle a bootable flag"); 853 puts("a\ttoggle a bootable flag");
838 puts("b\tedit bsd disklabel"); 854 puts("b\tedit bsd disklabel");
@@ -1308,7 +1324,18 @@ get_geometry(void)
1308 1324
1309/* 1325/*
1310 * Opens disk_device and optionally reads MBR. 1326 * Opens disk_device and optionally reads MBR.
1311 * FIXME: document what each 'what' value will do! 1327 * If what == OPEN_MAIN:
1328 * Open device, read MBR. Abort program on short read. Create empty
1329 * disklabel if the on-disk structure is invalid (WRITABLE mode).
1330 * If what == TRY_ONLY:
1331 * Open device, read MBR. Return an error if anything is out of place.
1332 * Do not create an empty disklabel. This is used for the "list"
1333 * operations: "fdisk -l /dev/sda" and "fdisk -l" (all devices).
1334 * If what == CREATE_EMPTY_*:
1335 * This means that get_boot() was called recursively from create_*label().
1336 * Do not re-open the device; just set up the ptes array and print
1337 * geometry warnings.
1338 *
1312 * Returns: 1339 * Returns:
1313 * -1: no 0xaa55 flag present (possibly entire disk BSD) 1340 * -1: no 0xaa55 flag present (possibly entire disk BSD)
1314 * 0: found or created label 1341 * 0: found or created label
@@ -1390,6 +1417,10 @@ static int get_boot(void)
1390 if (check_aix_label()) 1417 if (check_aix_label())
1391 return 0; 1418 return 0;
1392#endif 1419#endif
1420#if ENABLE_FEATURE_GPT_LABEL
1421 if (check_gpt_label())
1422 return 0;
1423#endif
1393#if ENABLE_FEATURE_OSF_LABEL 1424#if ENABLE_FEATURE_OSF_LABEL
1394 if (check_osf_label()) { 1425 if (check_osf_label()) {
1395 possibly_osf_label = 1; 1426 possibly_osf_label = 1;
@@ -1409,7 +1440,7 @@ static int get_boot(void)
1409 if (!valid_part_table_flag(MBRbuffer)) { 1440 if (!valid_part_table_flag(MBRbuffer)) {
1410 if (what == OPEN_MAIN) { 1441 if (what == OPEN_MAIN) {
1411 printf("Device contains neither a valid DOS " 1442 printf("Device contains neither a valid DOS "
1412 "partition table, nor Sun, SGI or OSF " 1443 "partition table, nor Sun, SGI, OSF or GPT "
1413 "disklabel\n"); 1444 "disklabel\n");
1414#ifdef __sparc__ 1445#ifdef __sparc__
1415 IF_FEATURE_SUN_LABEL(create_sunlabel();) 1446 IF_FEATURE_SUN_LABEL(create_sunlabel();)
@@ -2056,10 +2087,14 @@ list_table(int xtra)
2056 sun_list_table(xtra); 2087 sun_list_table(xtra);
2057 return; 2088 return;
2058 } 2089 }
2059 if (LABEL_IS_SUN) { 2090 if (LABEL_IS_SGI) {
2060 sgi_list_table(xtra); 2091 sgi_list_table(xtra);
2061 return; 2092 return;
2062 } 2093 }
2094 if (LABEL_IS_GPT) {
2095 gpt_list_table(xtra);
2096 return;
2097 }
2063 2098
2064 list_disk_geometry(); 2099 list_disk_geometry();
2065 2100
diff --git a/util-linux/fdisk_gpt.c b/util-linux/fdisk_gpt.c
new file mode 100644
index 000000000..98803ec88
--- /dev/null
+++ b/util-linux/fdisk_gpt.c
@@ -0,0 +1,203 @@
1#if ENABLE_FEATURE_GPT_LABEL
2/*
3 * Copyright (C) 2010 Kevin Cernekee <cernekee@gmail.com>
4 *
5 * Licensed under GPLv2, see file LICENSE in this source tree.
6 */
7
8#define GPT_MAGIC 0x5452415020494645ULL
9enum {
10 LEGACY_GPT_TYPE = 0xee,
11 GPT_MAX_PARTS = 256,
12 GPT_MAX_PART_ENTRY_LEN = 4096,
13 GUID_LEN = 16,
14};
15
16typedef struct {
17 uint64_t magic;
18 uint32_t revision;
19 uint32_t hdr_size;
20 uint32_t hdr_crc32;
21 uint32_t reserved;
22 uint64_t current_lba;
23 uint64_t backup_lba;
24 uint64_t first_usable_lba;
25 uint64_t last_usable_lba;
26 uint8_t disk_guid[GUID_LEN];
27 uint64_t first_part_lba;
28 uint32_t n_parts;
29 uint32_t part_entry_len;
30 uint32_t part_array_crc32;
31} gpt_header;
32
33typedef struct {
34 uint8_t type_guid[GUID_LEN];
35 uint8_t part_guid[GUID_LEN];
36 uint64_t lba_start;
37 uint64_t lba_end;
38 uint64_t flags;
39 uint16_t name[36];
40} gpt_partition;
41
42static gpt_header *gpt_hdr;
43
44static char *part_array;
45static unsigned int n_parts;
46static unsigned int part_array_len;
47static unsigned int part_entry_len;
48
49static uint32_t *crc32_table;
50
51static inline gpt_partition *
52gpt_part(int i)
53{
54 if (i >= n_parts) {
55 return NULL;
56 }
57 return (gpt_partition *)&part_array[i * part_entry_len];
58}
59
60/* TODO: move to libbb */
61static uint32_t
62gpt_crc32(void *buf, int len)
63{
64 uint32_t crc = 0xffffffff;
65
66 for (; len > 0; len--, buf++) {
67 crc = crc32_table[(crc ^ *((char *)buf)) & 0xff] ^ (crc >> 8);
68 }
69 return crc ^ 0xffffffff;
70}
71
72static void
73gpt_print_guid(uint8_t *buf)
74{
75 printf(
76 "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
77 buf[3], buf[2], buf[1], buf[0],
78 buf[5], buf[4],
79 buf[7], buf[6],
80 buf[8], buf[9],
81 buf[10], buf[11], buf[12], buf[13], buf[14], buf[15]);
82}
83
84/* TODO: real unicode support */
85static void
86gpt_print_wide(uint16_t *s, int max_len)
87{
88 int i = 0;
89
90 while (i < max_len) {
91 if (*s == 0)
92 return;
93 fputc(*s, stdout);
94 s++;
95 }
96}
97
98static void
99gpt_list_table(int xtra UNUSED_PARAM)
100{
101 int i;
102 char numstr6[6];
103
104 numstr6[5] = '\0';
105
106 smart_ulltoa5(total_number_of_sectors, numstr6, " KMGTPEZY");
107 printf("Disk %s: %llu sectors, %s\n", disk_device,
108 (unsigned long long)total_number_of_sectors,
109 numstr6);
110 printf("Logical sector size: %u\n", sector_size);
111 printf("Disk identifier (GUID): ");
112 gpt_print_guid(gpt_hdr->disk_guid);
113 printf("\nPartition table holds up to %u entries\n",
114 (int)SWAP_LE32(gpt_hdr->n_parts));
115 printf("First usable sector is %llu, last usable sector is %llu\n\n",
116 (unsigned long long)SWAP_LE64(gpt_hdr->first_usable_lba),
117 (unsigned long long)SWAP_LE64(gpt_hdr->last_usable_lba));
118
119 printf("Number Start (sector) End (sector) Size Code Name\n");
120 for (i = 0; i < n_parts; i++) {
121 gpt_partition *p = gpt_part(i);
122 if (p->lba_start) {
123 smart_ulltoa5(1 + SWAP_LE64(p->lba_end) - SWAP_LE64(p->lba_start),
124 numstr6, " KMGTPEZY");
125 printf("%4u %15llu %15llu %11s %04x ",
126 i + 1,
127 (unsigned long long)SWAP_LE64(p->lba_start),
128 (unsigned long long)SWAP_LE64(p->lba_end),
129 numstr6,
130 0x0700 /* FIXME */);
131 gpt_print_wide(p->name, 18);
132 printf("\n");
133 }
134 }
135}
136
137static int
138check_gpt_label(void)
139{
140 struct partition *first = pt_offset(MBRbuffer, 0);
141 struct pte pe;
142 uint32_t crc;
143
144 /* LBA 0 contains the legacy MBR */
145
146 if (!valid_part_table_flag(MBRbuffer)
147 || first->sys_ind != LEGACY_GPT_TYPE
148 ) {
149 current_label_type = 0;
150 return 0;
151 }
152
153 /* LBA 1 contains the GPT header */
154
155 read_pte(&pe, 1);
156 gpt_hdr = (void *)pe.sectorbuffer;
157
158 if (gpt_hdr->magic != SWAP_LE64(GPT_MAGIC)) {
159 current_label_type = 0;
160 return 0;
161 }
162
163 if (!crc32_table) {
164 crc32_table = crc32_filltable(NULL, 0);
165 }
166
167 crc = SWAP_LE32(gpt_hdr->hdr_crc32);
168 gpt_hdr->hdr_crc32 = 0;
169 if (gpt_crc32(gpt_hdr, SWAP_LE32(gpt_hdr->hdr_size)) != crc) {
170 /* FIXME: read the backup table */
171 puts("\nwarning: GPT header CRC is invalid\n");
172 }
173
174 n_parts = SWAP_LE32(gpt_hdr->n_parts);
175 part_entry_len = SWAP_LE32(gpt_hdr->part_entry_len);
176 if (n_parts > GPT_MAX_PARTS
177 || part_entry_len > GPT_MAX_PART_ENTRY_LEN
178 || SWAP_LE32(gpt_hdr->hdr_size) > sector_size
179 ) {
180 puts("\nwarning: unable to parse GPT disklabel\n");
181 current_label_type = 0;
182 return 0;
183 }
184
185 part_array_len = n_parts * part_entry_len;
186 part_array = xmalloc(part_array_len);
187 seek_sector(SWAP_LE64(gpt_hdr->first_part_lba));
188 if (full_read(dev_fd, part_array, part_array_len) != part_array_len) {
189 fdisk_fatal(unable_to_read);
190 }
191
192 if (gpt_crc32(part_array, part_array_len) != gpt_hdr->part_array_crc32) {
193 /* FIXME: read the backup table */
194 puts("\nwarning: GPT array CRC is invalid\n");
195 }
196
197 puts("Found valid GPT with protective MBR; using GPT\n");
198
199 current_label_type = LABEL_GPT;
200 return 1;
201}
202
203#endif /* GPT_LABEL */