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