gpt.c revision 1.2 1 /*-
2 * Copyright (c) 2002 Marcel Moolenaar
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 *
26 * CRC32 code derived from work by Gary S. Brown.
27 */
28
29 #include <sys/cdefs.h>
30 #ifdef __FBSDID
31 __FBSDID("$FreeBSD: src/sbin/gpt/gpt.c,v 1.16 2006/07/07 02:44:23 marcel Exp $");
32 #endif
33 #ifdef __RCSID
34 __RCSID("$NetBSD: gpt.c,v 1.2 2006/10/15 22:36:29 christos Exp $");
35 #endif
36
37 #include <sys/param.h>
38 #include <sys/types.h>
39 #include <sys/disk.h>
40 #include <sys/stat.h>
41 #include <sys/ioctl.h>
42
43 #include <err.h>
44 #include <errno.h>
45 #include <fcntl.h>
46 #include <paths.h>
47 #include <stddef.h>
48 #include <stdio.h>
49 #include <stdlib.h>
50 #include <string.h>
51 #include <unistd.h>
52 #ifdef __NetBSD__
53 #include <util.h>
54 #include <ctype.h>
55 #include <prop/proplib.h>
56 #include <sys/drvctlio.h>
57 #endif
58
59 #include "map.h"
60 #include "gpt.h"
61
62 char device_path[MAXPATHLEN];
63 char *device_name;
64
65 off_t mediasz;
66
67 u_int parts;
68 u_int secsz;
69
70 int readonly, verbose;
71
72 static uint32_t crc32_tab[] = {
73 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
74 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
75 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
76 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
77 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
78 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
79 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
80 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
81 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
82 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
83 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
84 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
85 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
86 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
87 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
88 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
89 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
90 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
91 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
92 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
93 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
94 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
95 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
96 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
97 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
98 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
99 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
100 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
101 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
102 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
103 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
104 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
105 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
106 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
107 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
108 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
109 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
110 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
111 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
112 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
113 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
114 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
115 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
116 };
117
118 uint32_t
119 crc32(const void *buf, size_t size)
120 {
121 const uint8_t *p;
122 uint32_t crc;
123
124 p = buf;
125 crc = ~0U;
126
127 while (size--)
128 crc = crc32_tab[(crc ^ *p++) & 0xFF] ^ (crc >> 8);
129
130 return crc ^ ~0U;
131 }
132
133 uint8_t *
134 utf16_to_utf8(uint16_t *s16)
135 {
136 static uint8_t *s8 = NULL;
137 static size_t s8len = 0;
138 size_t s8idx, s16idx, s16len;
139 uint32_t utfchar;
140 unsigned int c;
141
142 s16len = 0;
143 while (s16[s16len++] != 0)
144 ;
145 if (s8len < s16len * 3) {
146 if (s8 != NULL)
147 free(s8);
148 s8len = s16len * 3;
149 s8 = calloc(s16len, 3);
150 }
151 s8idx = s16idx = 0;
152 while (s16idx < s16len) {
153 utfchar = le16toh(s16[s16idx++]);
154 if ((utfchar & 0xf800) == 0xd800) {
155 c = le16toh(s16[s16idx]);
156 if ((utfchar & 0x400) != 0 || (c & 0xfc00) != 0xdc00)
157 utfchar = 0xfffd;
158 else
159 s16idx++;
160 }
161 if (utfchar < 0x80) {
162 s8[s8idx++] = utfchar;
163 } else if (utfchar < 0x800) {
164 s8[s8idx++] = 0xc0 | (utfchar >> 6);
165 s8[s8idx++] = 0x80 | (utfchar & 0x3f);
166 } else if (utfchar < 0x10000) {
167 s8[s8idx++] = 0xe0 | (utfchar >> 12);
168 s8[s8idx++] = 0x80 | ((utfchar >> 6) & 0x3f);
169 s8[s8idx++] = 0x80 | (utfchar & 0x3f);
170 } else if (utfchar < 0x200000) {
171 s8[s8idx++] = 0xf0 | (utfchar >> 18);
172 s8[s8idx++] = 0x80 | ((utfchar >> 12) & 0x3f);
173 s8[s8idx++] = 0x80 | ((utfchar >> 6) & 0x3f);
174 s8[s8idx++] = 0x80 | (utfchar & 0x3f);
175 }
176 }
177 return (s8);
178 }
179
180 void
181 utf8_to_utf16(const uint8_t *s8, uint16_t *s16, size_t s16len)
182 {
183 size_t s16idx, s8idx, s8len;
184 uint32_t utfchar = 0;
185 unsigned int c, utfbytes;
186
187 s8len = 0;
188 while (s8[s8len++] != 0)
189 ;
190 s8idx = s16idx = 0;
191 utfbytes = 0;
192 do {
193 c = s8[s8idx++];
194 if ((c & 0xc0) != 0x80) {
195 /* Initial characters. */
196 if (utfbytes != 0) {
197 /* Incomplete encoding. */
198 s16[s16idx++] = 0xfffd;
199 if (s16idx == s16len) {
200 s16[--s16idx] = 0;
201 return;
202 }
203 }
204 if ((c & 0xf8) == 0xf0) {
205 utfchar = c & 0x07;
206 utfbytes = 3;
207 } else if ((c & 0xf0) == 0xe0) {
208 utfchar = c & 0x0f;
209 utfbytes = 2;
210 } else if ((c & 0xe0) == 0xc0) {
211 utfchar = c & 0x1f;
212 utfbytes = 1;
213 } else {
214 utfchar = c & 0x7f;
215 utfbytes = 0;
216 }
217 } else {
218 /* Followup characters. */
219 if (utfbytes > 0) {
220 utfchar = (utfchar << 6) + (c & 0x3f);
221 utfbytes--;
222 } else if (utfbytes == 0)
223 utfbytes = -1;
224 }
225 if (utfbytes == 0) {
226 if (utfchar >= 0x10000 && s16idx + 2 >= s16len)
227 utfchar = 0xfffd;
228 if (utfchar >= 0x10000) {
229 s16[s16idx++] = 0xd800 | ((utfchar>>10)-0x40);
230 s16[s16idx++] = 0xdc00 | (utfchar & 0x3ff);
231 } else
232 s16[s16idx++] = utfchar;
233 if (s16idx == s16len) {
234 s16[--s16idx] = 0;
235 return;
236 }
237 }
238 } while (c != 0);
239 }
240
241 void
242 le_uuid_dec(void const *buf, uuid_t *uuid)
243 {
244 u_char const *p;
245 int i;
246
247 p = buf;
248 uuid->time_low = le32dec(p);
249 uuid->time_mid = le16dec(p + 4);
250 uuid->time_hi_and_version = le16dec(p + 6);
251 uuid->clock_seq_hi_and_reserved = p[8];
252 uuid->clock_seq_low = p[9];
253 for (i = 0; i < _UUID_NODE_LEN; i++)
254 uuid->node[i] = p[10 + i];
255 }
256
257 void
258 le_uuid_enc(void *buf, uuid_t const *uuid)
259 {
260 u_char *p;
261 int i;
262
263 p = buf;
264 le32enc(p, uuid->time_low);
265 le16enc(p + 4, uuid->time_mid);
266 le16enc(p + 6, uuid->time_hi_and_version);
267 p[8] = uuid->clock_seq_hi_and_reserved;
268 p[9] = uuid->clock_seq_low;
269 for (i = 0; i < _UUID_NODE_LEN; i++)
270 p[10 + i] = uuid->node[i];
271 }
272
273 int
274 parse_uuid(const char *s, uuid_t *uuid)
275 {
276 uint32_t status;
277
278 uuid_from_string(s, uuid, &status);
279 if (status == uuid_s_ok)
280 return (0);
281
282 switch (*s) {
283 case 'e':
284 if (strcmp(s, "efi") == 0) {
285 uuid_t efi = GPT_ENT_TYPE_EFI;
286 *uuid = efi;
287 return (0);
288 }
289 break;
290 case 'h':
291 if (strcmp(s, "hfs") == 0) {
292 uuid_t hfs = GPT_ENT_TYPE_APPLE_HFS;
293 *uuid = hfs;
294 return (0);
295 }
296 break;
297 case 'l':
298 if (strcmp(s, "linux") == 0) {
299 uuid_t lnx = GPT_ENT_TYPE_MS_BASIC_DATA;
300 *uuid = lnx;
301 return (0);
302 }
303 break;
304 case 's':
305 if (strcmp(s, "swap") == 0) {
306 uuid_t sw = GPT_ENT_TYPE_FREEBSD_SWAP;
307 *uuid = sw;
308 return (0);
309 }
310 break;
311 case 'u':
312 if (strcmp(s, "ufs") == 0) {
313 uuid_t ufs = GPT_ENT_TYPE_FREEBSD_UFS;
314 *uuid = ufs;
315 return (0);
316 }
317 break;
318 case 'w':
319 if (strcmp(s, "windows") == 0) {
320 uuid_t win = GPT_ENT_TYPE_MS_BASIC_DATA;
321 *uuid = win;
322 return (0);
323 }
324 break;
325 }
326 return (EINVAL);
327 }
328
329 void*
330 gpt_read(int fd, off_t lba, size_t count)
331 {
332 off_t ofs;
333 void *buf;
334
335 count *= secsz;
336 buf = malloc(count);
337 if (buf == NULL)
338 return (NULL);
339
340 ofs = lba * secsz;
341 if (lseek(fd, ofs, SEEK_SET) == ofs &&
342 read(fd, buf, count) == (ssize_t)count)
343 return (buf);
344
345 free(buf);
346 return (NULL);
347 }
348
349 int
350 gpt_write(int fd, map_t *map)
351 {
352 off_t ofs;
353 size_t count;
354
355 count = map->map_size * secsz;
356 ofs = map->map_start * secsz;
357 if (lseek(fd, ofs, SEEK_SET) == ofs &&
358 write(fd, map->map_data, count) == (ssize_t)count)
359 return (0);
360 return (-1);
361 }
362
363 static int
364 gpt_mbr(int fd, off_t lba)
365 {
366 struct mbr *mbr;
367 map_t *m, *p;
368 off_t size, start;
369 unsigned int i, pmbr;
370
371 mbr = gpt_read(fd, lba, 1);
372 if (mbr == NULL)
373 return (-1);
374
375 if (mbr->mbr_sig != htole16(MBR_SIG)) {
376 if (verbose)
377 warnx("%s: MBR not found at sector %llu", device_name,
378 (long long)lba);
379 free(mbr);
380 return (0);
381 }
382
383 /*
384 * Differentiate between a regular MBR and a PMBR. This is more
385 * convenient in general. A PMBR is one with a single partition
386 * of type 0xee.
387 */
388 pmbr = 0;
389 for (i = 0; i < 4; i++) {
390 if (mbr->mbr_part[i].part_typ == 0)
391 continue;
392 if (mbr->mbr_part[i].part_typ == 0xee)
393 pmbr++;
394 else
395 break;
396 }
397 if (pmbr && i == 4 && lba == 0) {
398 if (pmbr != 1)
399 warnx("%s: Suspicious PMBR at sector %llu",
400 device_name, (long long)lba);
401 else if (verbose > 1)
402 warnx("%s: PMBR at sector %llu", device_name,
403 (long long)lba);
404 p = map_add(lba, 1LL, MAP_TYPE_PMBR, mbr);
405 return ((p == NULL) ? -1 : 0);
406 }
407 if (pmbr)
408 warnx("%s: Suspicious MBR at sector %llu", device_name,
409 (long long)lba);
410 else if (verbose > 1)
411 warnx("%s: MBR at sector %llu", device_name, (long long)lba);
412
413 p = map_add(lba, 1LL, MAP_TYPE_MBR, mbr);
414 if (p == NULL)
415 return (-1);
416 for (i = 0; i < 4; i++) {
417 if (mbr->mbr_part[i].part_typ == 0 ||
418 mbr->mbr_part[i].part_typ == 0xee)
419 continue;
420 start = le16toh(mbr->mbr_part[i].part_start_hi);
421 start = (start << 16) + le16toh(mbr->mbr_part[i].part_start_lo);
422 size = le16toh(mbr->mbr_part[i].part_size_hi);
423 size = (size << 16) + le16toh(mbr->mbr_part[i].part_size_lo);
424 if (start == 0 && size == 0) {
425 warnx("%s: Malformed MBR at sector %llu", device_name,
426 (long long)lba);
427 continue;
428 }
429 /* start is relative to the offset of the MBR itself. */
430 start += lba;
431 if (verbose > 2)
432 warnx("%s: MBR part: type=%d, start=%llu, size=%llu",
433 device_name, mbr->mbr_part[i].part_typ,
434 (long long)start, (long long)size);
435 if (mbr->mbr_part[i].part_typ != 15) {
436 m = map_add(start, size, MAP_TYPE_MBR_PART, p);
437 if (m == NULL)
438 return (-1);
439 m->map_index = i + 1;
440 } else {
441 if (gpt_mbr(fd, start) == -1)
442 return (-1);
443 }
444 }
445 return (0);
446 }
447
448 #ifdef __NetBSD__
449 static int
450 drvctl(const char *name, u_int *sector_size, off_t *media_size)
451 {
452 prop_dictionary_t command_dict, args_dict, results_dict, data_dict,
453 disk_info, geometry;
454 prop_string_t string;
455 prop_number_t number;
456 int dfd, res;
457 char *dname, *p;
458
459 if ((dfd = open("/dev/drvctl", O_RDONLY)) == -1)
460 return -1;
461
462 command_dict = prop_dictionary_create();
463 args_dict = prop_dictionary_create();
464
465 string = prop_string_create_cstring_nocopy("get-properties");
466 prop_dictionary_set(command_dict, "drvctl-command", string);
467 prop_object_release(string);
468
469 if ((dname = strdup(name[0] == 'r' ? name + 1 : name)) == NULL) {
470 (void)close(dfd);
471 return -1;
472 }
473 for (p = dname; *p; p++)
474 continue;
475 for (--p; p >= dname && !isdigit((unsigned char)*p); *p-- = '\0')
476 continue;
477
478 string = prop_string_create_cstring(dname);
479 free(dname);
480 prop_dictionary_set(args_dict, "device-name", string);
481 prop_object_release(string);
482
483 prop_dictionary_set(command_dict, "drvctl-arguments", args_dict);
484 prop_object_release(args_dict);
485
486 res = prop_dictionary_sendrecv_ioctl(command_dict, dfd, DRVCTLCOMMAND,
487 &results_dict);
488 (void)close(dfd);
489 prop_object_release(command_dict);
490 if (res) {
491 errno = res;
492 return -1;
493 }
494
495 number = prop_dictionary_get(results_dict, "drvctl-error");
496 if ((errno = prop_number_integer_value(number)) != 0)
497 return -1;
498
499 data_dict = prop_dictionary_get(results_dict, "drvctl-result-data");
500 if (data_dict == NULL)
501 goto out;
502
503 disk_info = prop_dictionary_get(data_dict, "disk-info");
504 if (disk_info == NULL)
505 goto out;
506
507 geometry = prop_dictionary_get(disk_info, "geometry");
508 if (geometry == NULL)
509 goto out;
510
511 number = prop_dictionary_get(geometry, "sector-size");
512 if (number == NULL)
513 goto out;
514
515 *sector_size = prop_number_integer_value(number);
516
517 number = prop_dictionary_get(geometry, "sectors-per-unit");
518 if (number == NULL)
519 goto out;
520
521 *media_size = prop_number_integer_value(number) * *sector_size;
522
523 return 0;
524 out:
525 errno = EINVAL;
526 return -1;
527 }
528 #endif
529
530 static int
531 gpt_gpt(int fd, off_t lba)
532 {
533 uuid_t type;
534 off_t size;
535 struct gpt_ent *ent;
536 struct gpt_hdr *hdr;
537 char *p, *s;
538 map_t *m;
539 size_t blocks, tblsz;
540 unsigned int i;
541 uint32_t crc;
542
543 hdr = gpt_read(fd, lba, 1);
544 if (hdr == NULL)
545 return (-1);
546
547 if (memcmp(hdr->hdr_sig, GPT_HDR_SIG, sizeof(hdr->hdr_sig)))
548 goto fail_hdr;
549
550 crc = le32toh(hdr->hdr_crc_self);
551 hdr->hdr_crc_self = 0;
552 if (crc32(hdr, le32toh(hdr->hdr_size)) != crc) {
553 if (verbose)
554 warnx("%s: Bad CRC in GPT header at sector %llu",
555 device_name, (long long)lba);
556 goto fail_hdr;
557 }
558
559 tblsz = le32toh(hdr->hdr_entries) * le32toh(hdr->hdr_entsz);
560 blocks = tblsz / secsz + ((tblsz % secsz) ? 1 : 0);
561
562 /* Use generic pointer to deal with hdr->hdr_entsz != sizeof(*ent). */
563 p = gpt_read(fd, le64toh(hdr->hdr_lba_table), blocks);
564 if (p == NULL)
565 return (-1);
566
567 if (crc32(p, tblsz) != le32toh(hdr->hdr_crc_table)) {
568 if (verbose)
569 warnx("%s: Bad CRC in GPT table at sector %llu",
570 device_name,
571 (long long)le64toh(hdr->hdr_lba_table));
572 goto fail_ent;
573 }
574
575 if (verbose > 1)
576 warnx("%s: %s GPT at sector %llu", device_name,
577 (lba == 1) ? "Pri" : "Sec", (long long)lba);
578
579 m = map_add(lba, 1, (lba == 1)
580 ? MAP_TYPE_PRI_GPT_HDR : MAP_TYPE_SEC_GPT_HDR, hdr);
581 if (m == NULL)
582 return (-1);
583
584 m = map_add(le64toh(hdr->hdr_lba_table), blocks, (lba == 1)
585 ? MAP_TYPE_PRI_GPT_TBL : MAP_TYPE_SEC_GPT_TBL, p);
586 if (m == NULL)
587 return (-1);
588
589 if (lba != 1)
590 return (0);
591
592 for (i = 0; i < le32toh(hdr->hdr_entries); i++) {
593 ent = (void*)(p + i * le32toh(hdr->hdr_entsz));
594 if (uuid_is_nil((uuid_t *)&ent->ent_type, NULL))
595 continue;
596
597 size = le64toh(ent->ent_lba_end) - le64toh(ent->ent_lba_start) +
598 1LL;
599 if (verbose > 2) {
600 le_uuid_dec(&ent->ent_type, &type);
601 uuid_to_string(&type, &s, NULL);
602 warnx(
603 "%s: GPT partition: type=%s, start=%llu, size=%llu", device_name, s,
604 (long long)le64toh(ent->ent_lba_start),
605 (long long)size);
606 free(s);
607 }
608 m = map_add(le64toh(ent->ent_lba_start), size,
609 MAP_TYPE_GPT_PART, ent);
610 if (m == NULL)
611 return (-1);
612 m->map_index = i + 1;
613 }
614 return (0);
615
616 fail_ent:
617 free(p);
618
619 fail_hdr:
620 free(hdr);
621 return (0);
622 }
623
624 int
625 gpt_open(const char *dev)
626 {
627 struct stat sb;
628 int fd, mode;
629
630 mode = readonly ? O_RDONLY : O_RDWR|O_EXCL;
631
632 device_name = device_path;
633 #ifdef __FreeBSD__
634 strlcpy(device_path, dev, sizeof(device_path));
635 if ((fd = open(device_path, mode)) != -1)
636 goto found;
637
638 snprintf(device_path, sizeof(device_path), "%s%s", _PATH_DEV, dev);
639 device_name = device_path + strlen(_PATH_DEV);
640 if ((fd = open(device_path, mode)) != -1)
641 goto found;
642 return (-1);
643 found:
644 #endif
645 #ifdef __NetBSD__
646 fd = opendisk(dev, mode, device_path, sizeof(device_path), 0);
647 if (fd == -1)
648 return -1;
649 device_name = device_path + strlen(_PATH_DEV);
650 #endif
651
652 if (fstat(fd, &sb) == -1)
653 goto close;
654
655 if ((sb.st_mode & S_IFMT) != S_IFREG) {
656 #ifdef DIOCGSECTORSIZE
657 if (ioctl(fd, DIOCGSECTORSIZE, &secsz) == -1 ||
658 ioctl(fd, DIOCGMEDIASIZE, &mediasz) == -1)
659 goto close;
660 #endif
661 #ifdef __NetBSD__
662 if (drvctl(device_name, &secsz, &mediasz) == -1)
663 goto close;
664 #endif
665 } else {
666 secsz = 512; /* Fixed size for files. */
667 if (sb.st_size % secsz) {
668 errno = EINVAL;
669 goto close;
670 }
671 mediasz = sb.st_size;
672 }
673
674 /*
675 * We require an absolute minimum of 6 sectors. One for the MBR,
676 * 2 for the GPT header, 2 for the GPT table and one to hold some
677 * user data. Let's catch this extreme border case here so that
678 * we don't have to worry about it later.
679 */
680 if (mediasz / secsz < 6) {
681 errno = ENODEV;
682 goto close;
683 }
684
685 if (verbose)
686 warnx("%s: mediasize=%llu; sectorsize=%u; blocks=%llu",
687 device_name, (long long)mediasz, secsz,
688 (long long)(mediasz / secsz));
689
690 map_init(mediasz / secsz);
691
692 if (gpt_mbr(fd, 0LL) == -1)
693 goto close;
694 if (gpt_gpt(fd, 1LL) == -1)
695 goto close;
696 if (gpt_gpt(fd, mediasz / secsz - 1LL) == -1)
697 goto close;
698
699 return (fd);
700
701 close:
702 close(fd);
703 return (-1);
704 }
705
706 void
707 gpt_close(int fd)
708 {
709 /* XXX post processing? */
710 close(fd);
711 }
712
713 static struct {
714 int (*fptr)(int, char *[]);
715 const char *name;
716 } cmdsw[] = {
717 { cmd_add, "add" },
718 { cmd_create, "create" },
719 { cmd_destroy, "destroy" },
720 { NULL, "help" },
721 { cmd_label, "label" },
722 { cmd_migrate, "migrate" },
723 { cmd_recover, "recover" },
724 { cmd_remove, "remove" },
725 { NULL, "rename" },
726 { cmd_show, "show" },
727 { NULL, "verify" },
728 { NULL, NULL }
729 };
730
731 static void
732 usage(void)
733 {
734
735 fprintf(stderr,
736 "usage: %s [-rv] [-p nparts] command [options] device ...\n",
737 getprogname());
738 exit(1);
739 }
740
741 static void
742 prefix(const char *cmd)
743 {
744 char *pfx;
745 const char *prg;
746
747 prg = getprogname();
748 pfx = malloc(strlen(prg) + strlen(cmd) + 2);
749 /* Don't bother failing. It's not important */
750 if (pfx == NULL)
751 return;
752
753 sprintf(pfx, "%s %s", prg, cmd);
754 setprogname(pfx);
755 }
756
757 int
758 main(int argc, char *argv[])
759 {
760 char *cmd, *p;
761 int ch, i;
762
763 /* Get the generic options */
764 while ((ch = getopt(argc, argv, "p:rv")) != -1) {
765 switch(ch) {
766 case 'p':
767 if (parts > 0)
768 usage();
769 parts = strtol(optarg, &p, 10);
770 if (*p != 0 || parts < 1)
771 usage();
772 break;
773 case 'r':
774 readonly = 1;
775 break;
776 case 'v':
777 verbose++;
778 break;
779 default:
780 usage();
781 }
782 }
783 if (!parts)
784 parts = 128;
785
786 if (argc == optind)
787 usage();
788
789 cmd = argv[optind++];
790 for (i = 0; cmdsw[i].name != NULL && strcmp(cmd, cmdsw[i].name); i++);
791
792 if (cmdsw[i].fptr == NULL)
793 errx(1, "unknown command: %s", cmd);
794
795 prefix(cmd);
796 return ((*cmdsw[i].fptr)(argc, argv));
797 }
798