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.4 2007/06/11 04:22:00 dyoung 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 warn("%s: /dev/drvctl", __func__); 461 return -1; 462 } 463 464 command_dict = prop_dictionary_create(); 465 args_dict = prop_dictionary_create(); 466 467 string = prop_string_create_cstring_nocopy("get-properties"); 468 prop_dictionary_set(command_dict, "drvctl-command", string); 469 prop_object_release(string); 470 471 if ((dname = strdup(name[0] == 'r' ? name + 1 : name)) == NULL) { 472 (void)close(dfd); 473 return -1; 474 } 475 for (p = dname; *p; p++) 476 continue; 477 for (--p; p >= dname && !isdigit((unsigned char)*p); *p-- = '\0') 478 continue; 479 480 string = prop_string_create_cstring(dname); 481 free(dname); 482 prop_dictionary_set(args_dict, "device-name", string); 483 prop_object_release(string); 484 485 prop_dictionary_set(command_dict, "drvctl-arguments", args_dict); 486 prop_object_release(args_dict); 487 488 res = prop_dictionary_sendrecv_ioctl(command_dict, dfd, DRVCTLCOMMAND, 489 &results_dict); 490 (void)close(dfd); 491 prop_object_release(command_dict); 492 if (res) { 493 warn("%s: prop_dictionary_sendrecv_ioctl", __func__); 494 errno = res; 495 return -1; 496 } 497 498 number = prop_dictionary_get(results_dict, "drvctl-error"); 499 if ((errno = prop_number_integer_value(number)) != 0) 500 return -1; 501 502 data_dict = prop_dictionary_get(results_dict, "drvctl-result-data"); 503 if (data_dict == NULL) 504 goto out; 505 506 disk_info = prop_dictionary_get(data_dict, "disk-info"); 507 if (disk_info == NULL) 508 goto out; 509 510 geometry = prop_dictionary_get(disk_info, "geometry"); 511 if (geometry == NULL) 512 goto out; 513 514 number = prop_dictionary_get(geometry, "sector-size"); 515 if (number == NULL) 516 goto out; 517 518 *sector_size = prop_number_integer_value(number); 519 520 number = prop_dictionary_get(geometry, "sectors-per-unit"); 521 if (number == NULL) 522 goto out; 523 524 *media_size = prop_number_integer_value(number) * *sector_size; 525 526 return 0; 527 out: 528 errno = EINVAL; 529 return -1; 530 } 531 #endif 532 533 static int 534 gpt_gpt(int fd, off_t lba) 535 { 536 uuid_t type; 537 off_t size; 538 struct gpt_ent *ent; 539 struct gpt_hdr *hdr; 540 char *p, *s; 541 map_t *m; 542 size_t blocks, tblsz; 543 unsigned int i; 544 uint32_t crc; 545 546 hdr = gpt_read(fd, lba, 1); 547 if (hdr == NULL) 548 return (-1); 549 550 if (memcmp(hdr->hdr_sig, GPT_HDR_SIG, sizeof(hdr->hdr_sig))) 551 goto fail_hdr; 552 553 crc = le32toh(hdr->hdr_crc_self); 554 hdr->hdr_crc_self = 0; 555 if (crc32(hdr, le32toh(hdr->hdr_size)) != crc) { 556 if (verbose) 557 warnx("%s: Bad CRC in GPT header at sector %llu", 558 device_name, (long long)lba); 559 goto fail_hdr; 560 } 561 562 tblsz = le32toh(hdr->hdr_entries) * le32toh(hdr->hdr_entsz); 563 blocks = tblsz / secsz + ((tblsz % secsz) ? 1 : 0); 564 565 /* Use generic pointer to deal with hdr->hdr_entsz != sizeof(*ent). */ 566 p = gpt_read(fd, le64toh(hdr->hdr_lba_table), blocks); 567 if (p == NULL) 568 return (-1); 569 570 if (crc32(p, tblsz) != le32toh(hdr->hdr_crc_table)) { 571 if (verbose) 572 warnx("%s: Bad CRC in GPT table at sector %llu", 573 device_name, 574 (long long)le64toh(hdr->hdr_lba_table)); 575 goto fail_ent; 576 } 577 578 if (verbose > 1) 579 warnx("%s: %s GPT at sector %llu", device_name, 580 (lba == 1) ? "Pri" : "Sec", (long long)lba); 581 582 m = map_add(lba, 1, (lba == 1) 583 ? MAP_TYPE_PRI_GPT_HDR : MAP_TYPE_SEC_GPT_HDR, hdr); 584 if (m == NULL) 585 return (-1); 586 587 m = map_add(le64toh(hdr->hdr_lba_table), blocks, (lba == 1) 588 ? MAP_TYPE_PRI_GPT_TBL : MAP_TYPE_SEC_GPT_TBL, p); 589 if (m == NULL) 590 return (-1); 591 592 if (lba != 1) 593 return (0); 594 595 for (i = 0; i < le32toh(hdr->hdr_entries); i++) { 596 ent = (void*)(p + i * le32toh(hdr->hdr_entsz)); 597 if (uuid_is_nil((uuid_t *)&ent->ent_type, NULL)) 598 continue; 599 600 size = le64toh(ent->ent_lba_end) - le64toh(ent->ent_lba_start) + 601 1LL; 602 if (verbose > 2) { 603 le_uuid_dec(&ent->ent_type, &type); 604 uuid_to_string(&type, &s, NULL); 605 warnx( 606 "%s: GPT partition: type=%s, start=%llu, size=%llu", device_name, s, 607 (long long)le64toh(ent->ent_lba_start), 608 (long long)size); 609 free(s); 610 } 611 m = map_add(le64toh(ent->ent_lba_start), size, 612 MAP_TYPE_GPT_PART, ent); 613 if (m == NULL) 614 return (-1); 615 m->map_index = i + 1; 616 } 617 return (0); 618 619 fail_ent: 620 free(p); 621 622 fail_hdr: 623 free(hdr); 624 return (0); 625 } 626 627 int 628 gpt_open(const char *dev) 629 { 630 struct stat sb; 631 int fd, mode; 632 633 mode = readonly ? O_RDONLY : O_RDWR|O_EXCL; 634 635 device_name = device_path; 636 #ifdef __FreeBSD__ 637 strlcpy(device_path, dev, sizeof(device_path)); 638 if ((fd = open(device_path, mode)) != -1) 639 goto found; 640 641 snprintf(device_path, sizeof(device_path), "%s%s", _PATH_DEV, dev); 642 device_name = device_path + strlen(_PATH_DEV); 643 if ((fd = open(device_path, mode)) != -1) 644 goto found; 645 return (-1); 646 found: 647 #endif 648 #ifdef __NetBSD__ 649 fd = opendisk(dev, mode, device_path, sizeof(device_path), 0); 650 if (fd == -1) 651 return -1; 652 device_name = device_path + strlen(_PATH_DEV); 653 #endif 654 655 if (fstat(fd, &sb) == -1) 656 goto close; 657 658 if ((sb.st_mode & S_IFMT) != S_IFREG) { 659 #ifdef DIOCGSECTORSIZE 660 if (ioctl(fd, DIOCGSECTORSIZE, &secsz) == -1 || 661 ioctl(fd, DIOCGMEDIASIZE, &mediasz) == -1) 662 goto close; 663 #endif 664 #ifdef __NetBSD__ 665 if (drvctl(device_name, &secsz, &mediasz) == -1) 666 goto close; 667 #endif 668 } else { 669 secsz = 512; /* Fixed size for files. */ 670 if (sb.st_size % secsz) { 671 errno = EINVAL; 672 goto close; 673 } 674 mediasz = sb.st_size; 675 } 676 677 /* 678 * We require an absolute minimum of 6 sectors. One for the MBR, 679 * 2 for the GPT header, 2 for the GPT table and one to hold some 680 * user data. Let's catch this extreme border case here so that 681 * we don't have to worry about it later. 682 */ 683 if (mediasz / secsz < 6) { 684 errno = ENODEV; 685 goto close; 686 } 687 688 if (verbose) 689 warnx("%s: mediasize=%llu; sectorsize=%u; blocks=%llu", 690 device_name, (long long)mediasz, secsz, 691 (long long)(mediasz / secsz)); 692 693 map_init(mediasz / secsz); 694 695 if (gpt_mbr(fd, 0LL) == -1) 696 goto close; 697 if (gpt_gpt(fd, 1LL) == -1) 698 goto close; 699 if (gpt_gpt(fd, mediasz / secsz - 1LL) == -1) 700 goto close; 701 702 return (fd); 703 704 close: 705 close(fd); 706 return (-1); 707 } 708 709 void 710 gpt_close(int fd) 711 { 712 /* XXX post processing? */ 713 close(fd); 714 } 715 716 static struct { 717 int (*fptr)(int, char *[]); 718 const char *name; 719 } cmdsw[] = { 720 { cmd_add, "add" }, 721 { cmd_create, "create" }, 722 { cmd_destroy, "destroy" }, 723 { NULL, "help" }, 724 { cmd_label, "label" }, 725 { cmd_migrate, "migrate" }, 726 { cmd_recover, "recover" }, 727 { cmd_remove, "remove" }, 728 { NULL, "rename" }, 729 { cmd_show, "show" }, 730 { NULL, "verify" }, 731 { NULL, NULL } 732 }; 733 734 static void 735 usage(void) 736 { 737 738 fprintf(stderr, 739 "usage: %s [-rv] [-p nparts] command [options] device ...\n", 740 getprogname()); 741 exit(1); 742 } 743 744 static void 745 prefix(const char *cmd) 746 { 747 char *pfx; 748 const char *prg; 749 750 prg = getprogname(); 751 pfx = malloc(strlen(prg) + strlen(cmd) + 2); 752 /* Don't bother failing. It's not important */ 753 if (pfx == NULL) 754 return; 755 756 sprintf(pfx, "%s %s", prg, cmd); 757 setprogname(pfx); 758 } 759 760 int 761 main(int argc, char *argv[]) 762 { 763 char *cmd, *p; 764 int ch, i; 765 766 /* Get the generic options */ 767 while ((ch = getopt(argc, argv, "p:rv")) != -1) { 768 switch(ch) { 769 case 'p': 770 if (parts > 0) 771 usage(); 772 parts = strtoul(optarg, &p, 10); 773 if (*p != 0 || parts < 1) 774 usage(); 775 break; 776 case 'r': 777 readonly = 1; 778 break; 779 case 'v': 780 verbose++; 781 break; 782 default: 783 usage(); 784 } 785 } 786 if (!parts) 787 parts = 128; 788 789 if (argc == optind) 790 usage(); 791 792 cmd = argv[optind++]; 793 for (i = 0; cmdsw[i].name != NULL && strcmp(cmd, cmdsw[i].name); i++); 794 795 if (cmdsw[i].fptr == NULL) 796 errx(1, "unknown command: %s", cmd); 797 798 prefix(cmd); 799 return ((*cmdsw[i].fptr)(argc, argv)); 800 } 801