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.14 2011/01/06 16:30:40 jakllsch 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 const char *device_arg; 64 char *device_name; 65 66 off_t mediasz; 67 68 u_int parts; 69 u_int secsz; 70 71 int readonly, verbose; 72 73 static 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 119 uint32_t 120 crc32(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 134 uint8_t * 135 utf16_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 181 void 182 utf8_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++] = 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++] = 0xd800 | ((utfchar>>10)-0x40); 231 s16[s16idx++] = 0xdc00 | (utfchar & 0x3ff); 232 } else 233 s16[s16idx++] = utfchar; 234 if (s16idx == s16len) { 235 s16[--s16idx] = 0; 236 return; 237 } 238 } 239 } while (c != 0); 240 } 241 242 void 243 le_uuid_dec(void const *buf, uuid_t *uuid) 244 { 245 u_char const *p; 246 int i; 247 248 p = buf; 249 uuid->time_low = le32dec(p); 250 uuid->time_mid = le16dec(p + 4); 251 uuid->time_hi_and_version = le16dec(p + 6); 252 uuid->clock_seq_hi_and_reserved = p[8]; 253 uuid->clock_seq_low = p[9]; 254 for (i = 0; i < _UUID_NODE_LEN; i++) 255 uuid->node[i] = p[10 + i]; 256 } 257 258 void 259 le_uuid_enc(void *buf, uuid_t const *uuid) 260 { 261 u_char *p; 262 int i; 263 264 p = buf; 265 le32enc(p, uuid->time_low); 266 le16enc(p + 4, uuid->time_mid); 267 le16enc(p + 6, uuid->time_hi_and_version); 268 p[8] = uuid->clock_seq_hi_and_reserved; 269 p[9] = uuid->clock_seq_low; 270 for (i = 0; i < _UUID_NODE_LEN; i++) 271 p[10 + i] = uuid->node[i]; 272 } 273 274 int 275 parse_uuid(const char *s, uuid_t *uuid) 276 { 277 uint32_t status; 278 279 uuid_from_string(s, uuid, &status); 280 if (status == uuid_s_ok) 281 return (0); 282 283 switch (*s) { 284 case 'b': 285 if (strcmp(s, "bios") == 0) { 286 uuid_t bios = GPT_ENT_TYPE_BIOS; 287 *uuid = bios; 288 return (0); 289 } 290 break; 291 case 'c': 292 if (strcmp(s, "ccd") == 0) { 293 uuid_t ccd = GPT_ENT_TYPE_NETBSD_CCD; 294 *uuid = ccd; 295 return (0); 296 } else if (strcmp(s, "cgd") == 0) { 297 uuid_t cgd = GPT_ENT_TYPE_NETBSD_CGD; 298 *uuid = cgd; 299 return (0); 300 } 301 break; 302 case 'e': 303 if (strcmp(s, "efi") == 0) { 304 uuid_t efi = GPT_ENT_TYPE_EFI; 305 *uuid = efi; 306 return (0); 307 } 308 break; 309 case 'f': 310 if (strcmp(s, "ffs") == 0) { 311 uuid_t nb_ffs = GPT_ENT_TYPE_NETBSD_FFS; 312 *uuid = nb_ffs; 313 return (0); 314 } 315 break; 316 case 'h': 317 if (strcmp(s, "hfs") == 0) { 318 uuid_t hfs = GPT_ENT_TYPE_APPLE_HFS; 319 *uuid = hfs; 320 return (0); 321 } 322 break; 323 case 'l': 324 if (strcmp(s, "lfs") == 0) { 325 uuid_t lfs = GPT_ENT_TYPE_NETBSD_LFS; 326 *uuid = lfs; 327 return (0); 328 } else if (strcmp(s, "linux") == 0) { 329 uuid_t lnx = GPT_ENT_TYPE_MS_BASIC_DATA; 330 *uuid = lnx; 331 return (0); 332 } 333 break; 334 case 'r': 335 if (strcmp(s, "raid") == 0) { 336 uuid_t raid = GPT_ENT_TYPE_NETBSD_RAIDFRAME; 337 *uuid = raid; 338 return (0); 339 } 340 break; 341 case 's': 342 if (strcmp(s, "swap") == 0) { 343 uuid_t sw = GPT_ENT_TYPE_NETBSD_SWAP; 344 *uuid = sw; 345 return (0); 346 } 347 break; 348 case 'u': 349 if (strcmp(s, "ufs") == 0) { 350 uuid_t ufs = GPT_ENT_TYPE_NETBSD_FFS; 351 *uuid = ufs; 352 return (0); 353 } 354 break; 355 case 'w': 356 if (strcmp(s, "windows") == 0) { 357 uuid_t win = GPT_ENT_TYPE_MS_BASIC_DATA; 358 *uuid = win; 359 return (0); 360 } 361 break; 362 } 363 return (EINVAL); 364 } 365 366 void* 367 gpt_read(int fd, off_t lba, size_t count) 368 { 369 off_t ofs; 370 void *buf; 371 372 count *= secsz; 373 buf = malloc(count); 374 if (buf == NULL) 375 return (NULL); 376 377 ofs = lba * secsz; 378 if (lseek(fd, ofs, SEEK_SET) == ofs && 379 read(fd, buf, count) == (ssize_t)count) 380 return (buf); 381 382 free(buf); 383 return (NULL); 384 } 385 386 int 387 gpt_write(int fd, map_t *map) 388 { 389 off_t ofs; 390 size_t count; 391 392 count = map->map_size * secsz; 393 ofs = map->map_start * secsz; 394 if (lseek(fd, ofs, SEEK_SET) == ofs && 395 write(fd, map->map_data, count) == (ssize_t)count) 396 return (0); 397 return (-1); 398 } 399 400 static int 401 gpt_mbr(int fd, off_t lba) 402 { 403 struct mbr *mbr; 404 map_t *m, *p; 405 off_t size, start; 406 unsigned int i, pmbr; 407 408 mbr = gpt_read(fd, lba, 1); 409 if (mbr == NULL) 410 return (-1); 411 412 if (mbr->mbr_sig != htole16(MBR_SIG)) { 413 if (verbose) 414 warnx("%s: MBR not found at sector %llu", device_name, 415 (long long)lba); 416 free(mbr); 417 return (0); 418 } 419 420 /* 421 * Differentiate between a regular MBR and a PMBR. This is more 422 * convenient in general. A PMBR is one with a single partition 423 * of type 0xee. 424 */ 425 pmbr = 0; 426 for (i = 0; i < 4; i++) { 427 if (mbr->mbr_part[i].part_typ == 0) 428 continue; 429 if (mbr->mbr_part[i].part_typ == 0xee) 430 pmbr++; 431 else 432 break; 433 } 434 if (pmbr && i == 4 && lba == 0) { 435 if (pmbr != 1) 436 warnx("%s: Suspicious PMBR at sector %llu", 437 device_name, (long long)lba); 438 else if (verbose > 1) 439 warnx("%s: PMBR at sector %llu", device_name, 440 (long long)lba); 441 p = map_add(lba, 1LL, MAP_TYPE_PMBR, mbr); 442 return ((p == NULL) ? -1 : 0); 443 } 444 if (pmbr) 445 warnx("%s: Suspicious MBR at sector %llu", device_name, 446 (long long)lba); 447 else if (verbose > 1) 448 warnx("%s: MBR at sector %llu", device_name, (long long)lba); 449 450 p = map_add(lba, 1LL, MAP_TYPE_MBR, mbr); 451 if (p == NULL) 452 return (-1); 453 for (i = 0; i < 4; i++) { 454 if (mbr->mbr_part[i].part_typ == 0 || 455 mbr->mbr_part[i].part_typ == 0xee) 456 continue; 457 start = le16toh(mbr->mbr_part[i].part_start_hi); 458 start = (start << 16) + le16toh(mbr->mbr_part[i].part_start_lo); 459 size = le16toh(mbr->mbr_part[i].part_size_hi); 460 size = (size << 16) + le16toh(mbr->mbr_part[i].part_size_lo); 461 if (start == 0 && size == 0) { 462 warnx("%s: Malformed MBR at sector %llu", device_name, 463 (long long)lba); 464 continue; 465 } 466 /* start is relative to the offset of the MBR itself. */ 467 start += lba; 468 if (verbose > 2) 469 warnx("%s: MBR part: type=%d, start=%llu, size=%llu", 470 device_name, mbr->mbr_part[i].part_typ, 471 (long long)start, (long long)size); 472 if (mbr->mbr_part[i].part_typ != 15) { 473 m = map_add(start, size, MAP_TYPE_MBR_PART, p); 474 if (m == NULL) 475 return (-1); 476 m->map_index = i + 1; 477 } else { 478 if (gpt_mbr(fd, start) == -1) 479 return (-1); 480 } 481 } 482 return (0); 483 } 484 485 #ifdef __NetBSD__ 486 static int 487 drvctl(const char *name, u_int *sector_size, off_t *media_size) 488 { 489 prop_dictionary_t command_dict, args_dict, results_dict, data_dict, 490 disk_info, geometry; 491 prop_string_t string; 492 prop_number_t number; 493 int dfd, res; 494 char *dname, *p; 495 496 if ((dfd = open("/dev/drvctl", O_RDONLY)) == -1) { 497 warn("%s: /dev/drvctl", __func__); 498 return -1; 499 } 500 501 command_dict = prop_dictionary_create(); 502 args_dict = prop_dictionary_create(); 503 504 string = prop_string_create_cstring_nocopy("get-properties"); 505 prop_dictionary_set(command_dict, "drvctl-command", string); 506 prop_object_release(string); 507 508 if ((dname = strdup(name[0] == 'r' ? name + 1 : name)) == NULL) { 509 (void)close(dfd); 510 return -1; 511 } 512 for (p = dname; *p; p++) 513 continue; 514 for (--p; p >= dname && !isdigit((unsigned char)*p); *p-- = '\0') 515 continue; 516 517 string = prop_string_create_cstring(dname); 518 free(dname); 519 prop_dictionary_set(args_dict, "device-name", string); 520 prop_object_release(string); 521 522 prop_dictionary_set(command_dict, "drvctl-arguments", args_dict); 523 prop_object_release(args_dict); 524 525 res = prop_dictionary_sendrecv_ioctl(command_dict, dfd, DRVCTLCOMMAND, 526 &results_dict); 527 (void)close(dfd); 528 prop_object_release(command_dict); 529 if (res) { 530 warn("%s: prop_dictionary_sendrecv_ioctl", __func__); 531 errno = res; 532 return -1; 533 } 534 535 number = prop_dictionary_get(results_dict, "drvctl-error"); 536 if ((errno = prop_number_integer_value(number)) != 0) 537 return -1; 538 539 data_dict = prop_dictionary_get(results_dict, "drvctl-result-data"); 540 if (data_dict == NULL) 541 goto out; 542 543 disk_info = prop_dictionary_get(data_dict, "disk-info"); 544 if (disk_info == NULL) 545 goto out; 546 547 geometry = prop_dictionary_get(disk_info, "geometry"); 548 if (geometry == NULL) 549 goto out; 550 551 number = prop_dictionary_get(geometry, "sector-size"); 552 if (number == NULL) 553 goto out; 554 555 *sector_size = prop_number_integer_value(number); 556 557 number = prop_dictionary_get(geometry, "sectors-per-unit"); 558 if (number == NULL) 559 goto out; 560 561 *media_size = prop_number_integer_value(number) * *sector_size; 562 563 return 0; 564 out: 565 errno = EINVAL; 566 return -1; 567 } 568 #endif 569 570 static int 571 gpt_gpt(int fd, off_t lba, int found) 572 { 573 uuid_t type; 574 off_t size; 575 struct gpt_ent *ent; 576 struct gpt_hdr *hdr; 577 char *p, *s; 578 map_t *m; 579 size_t blocks, tblsz; 580 unsigned int i; 581 uint32_t crc; 582 583 hdr = gpt_read(fd, lba, 1); 584 if (hdr == NULL) 585 return (-1); 586 587 if (memcmp(hdr->hdr_sig, GPT_HDR_SIG, sizeof(hdr->hdr_sig))) 588 goto fail_hdr; 589 590 crc = le32toh(hdr->hdr_crc_self); 591 hdr->hdr_crc_self = 0; 592 if (crc32(hdr, le32toh(hdr->hdr_size)) != crc) { 593 if (verbose) 594 warnx("%s: Bad CRC in GPT header at sector %llu", 595 device_name, (long long)lba); 596 goto fail_hdr; 597 } 598 599 tblsz = le32toh(hdr->hdr_entries) * le32toh(hdr->hdr_entsz); 600 blocks = tblsz / secsz + ((tblsz % secsz) ? 1 : 0); 601 602 /* Use generic pointer to deal with hdr->hdr_entsz != sizeof(*ent). */ 603 p = gpt_read(fd, le64toh(hdr->hdr_lba_table), blocks); 604 if (p == NULL) { 605 if (found) { 606 if (verbose) 607 warn("%s: Cannot read LBA table at sector %llu", 608 device_name, (unsigned long long) 609 le64toh(hdr->hdr_lba_table)); 610 return (-1); 611 } 612 goto fail_hdr; 613 } 614 615 if (crc32(p, tblsz) != le32toh(hdr->hdr_crc_table)) { 616 if (verbose) 617 warnx("%s: Bad CRC in GPT table at sector %llu", 618 device_name, 619 (long long)le64toh(hdr->hdr_lba_table)); 620 goto fail_ent; 621 } 622 623 if (verbose > 1) 624 warnx("%s: %s GPT at sector %llu", device_name, 625 (lba == 1) ? "Pri" : "Sec", (long long)lba); 626 627 m = map_add(lba, 1, (lba == 1) 628 ? MAP_TYPE_PRI_GPT_HDR : MAP_TYPE_SEC_GPT_HDR, hdr); 629 if (m == NULL) 630 return (-1); 631 632 m = map_add(le64toh(hdr->hdr_lba_table), blocks, (lba == 1) 633 ? MAP_TYPE_PRI_GPT_TBL : MAP_TYPE_SEC_GPT_TBL, p); 634 if (m == NULL) 635 return (-1); 636 637 if (lba != 1) 638 return (1); 639 640 for (i = 0; i < le32toh(hdr->hdr_entries); i++) { 641 ent = (void*)(p + i * le32toh(hdr->hdr_entsz)); 642 if (uuid_is_nil((uuid_t *)&ent->ent_type, NULL)) 643 continue; 644 645 size = le64toh(ent->ent_lba_end) - le64toh(ent->ent_lba_start) + 646 1LL; 647 if (verbose > 2) { 648 le_uuid_dec(&ent->ent_type, &type); 649 uuid_to_string(&type, &s, NULL); 650 warnx( 651 "%s: GPT partition: type=%s, start=%llu, size=%llu", device_name, s, 652 (long long)le64toh(ent->ent_lba_start), 653 (long long)size); 654 free(s); 655 } 656 m = map_add(le64toh(ent->ent_lba_start), size, 657 MAP_TYPE_GPT_PART, ent); 658 if (m == NULL) 659 return (-1); 660 m->map_index = i + 1; 661 } 662 return (1); 663 664 fail_ent: 665 free(p); 666 667 fail_hdr: 668 free(hdr); 669 return (0); 670 } 671 672 int 673 gpt_open(const char *dev) 674 { 675 struct stat sb; 676 int fd, mode, found; 677 678 mode = readonly ? O_RDONLY : O_RDWR|O_EXCL; 679 680 device_arg = dev; 681 #ifdef __FreeBSD__ 682 strlcpy(device_path, dev, sizeof(device_path)); 683 if ((fd = open(device_path, mode)) != -1) 684 goto found; 685 686 snprintf(device_path, sizeof(device_path), "%s%s", _PATH_DEV, dev); 687 device_name = device_path + strlen(_PATH_DEV); 688 if ((fd = open(device_path, mode)) != -1) 689 goto found; 690 return (-1); 691 found: 692 #endif 693 #ifdef __NetBSD__ 694 device_name = device_path + strlen(_PATH_DEV); 695 fd = opendisk(dev, mode, device_path, sizeof(device_path), 0); 696 if (fd == -1) 697 return -1; 698 #endif 699 700 if (fstat(fd, &sb) == -1) 701 goto close; 702 703 if ((sb.st_mode & S_IFMT) != S_IFREG) { 704 #ifdef DIOCGSECTORSIZE 705 if (ioctl(fd, DIOCGSECTORSIZE, &secsz) == -1 || 706 ioctl(fd, DIOCGMEDIASIZE, &mediasz) == -1) 707 goto close; 708 #endif 709 #ifdef __NetBSD__ 710 if (drvctl(device_name, &secsz, &mediasz) == -1) 711 goto close; 712 #endif 713 } else { 714 secsz = 512; /* Fixed size for files. */ 715 if (sb.st_size % secsz) { 716 errno = EINVAL; 717 goto close; 718 } 719 mediasz = sb.st_size; 720 } 721 722 /* 723 * We require an absolute minimum of 6 sectors. One for the MBR, 724 * 2 for the GPT header, 2 for the GPT table and one to hold some 725 * user data. Let's catch this extreme border case here so that 726 * we don't have to worry about it later. 727 */ 728 if (mediasz / secsz < 6) { 729 errno = ENODEV; 730 goto close; 731 } 732 733 if (verbose) 734 warnx("%s: mediasize=%llu; sectorsize=%u; blocks=%llu", 735 device_name, (long long)mediasz, secsz, 736 (long long)(mediasz / secsz)); 737 738 map_init(mediasz / secsz); 739 740 if (gpt_mbr(fd, 0LL) == -1) 741 goto close; 742 if ((found = gpt_gpt(fd, 1LL, 1)) == -1) 743 goto close; 744 if (gpt_gpt(fd, mediasz / secsz - 1LL, found) == -1) 745 goto close; 746 747 return (fd); 748 749 close: 750 close(fd); 751 return (-1); 752 } 753 754 void 755 gpt_close(int fd) 756 { 757 /* XXX post processing? */ 758 close(fd); 759 } 760 761 static struct { 762 int (*fptr)(int, char *[]); 763 const char *name; 764 } cmdsw[] = { 765 { cmd_add, "add" }, 766 { cmd_biosboot, "biosboot" }, 767 { cmd_create, "create" }, 768 { cmd_destroy, "destroy" }, 769 { NULL, "help" }, 770 { cmd_label, "label" }, 771 { cmd_migrate, "migrate" }, 772 { cmd_recover, "recover" }, 773 { cmd_remove, "remove" }, 774 { NULL, "rename" }, 775 { cmd_show, "show" }, 776 { NULL, "verify" }, 777 { NULL, NULL } 778 }; 779 780 static void 781 usage(void) 782 { 783 extern const char addmsg[], biosbootmsg[], createmsg[], destroymsg[]; 784 extern const char labelmsg1[], labelmsg2[], labelmsg3[]; 785 extern const char migratemsg[], recovermsg[], removemsg1[]; 786 extern const char removemsg2[], showmsg[]; 787 788 fprintf(stderr, 789 "usage: %s %s\n" 790 " %s %s\n" 791 " %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 getprogname(), addmsg, 802 getprogname(), biosbootmsg, 803 getprogname(), createmsg, 804 getprogname(), destroymsg, 805 getprogname(), labelmsg1, 806 getprogname(), labelmsg2, 807 (int)strlen(getprogname()), "", labelmsg3, 808 getprogname(), migratemsg, 809 getprogname(), recovermsg, 810 getprogname(), removemsg1, 811 getprogname(), removemsg2, 812 getprogname(), showmsg); 813 exit(1); 814 } 815 816 static void 817 prefix(const char *cmd) 818 { 819 char *pfx; 820 const char *prg; 821 822 prg = getprogname(); 823 pfx = malloc(strlen(prg) + strlen(cmd) + 2); 824 /* Don't bother failing. It's not important */ 825 if (pfx == NULL) 826 return; 827 828 sprintf(pfx, "%s %s", prg, cmd); 829 setprogname(pfx); 830 } 831 832 int 833 main(int argc, char *argv[]) 834 { 835 char *cmd, *p; 836 int ch, i; 837 838 /* Get the generic options */ 839 while ((ch = getopt(argc, argv, "p:rv")) != -1) { 840 switch(ch) { 841 case 'p': 842 if (parts > 0) 843 usage(); 844 parts = strtoul(optarg, &p, 10); 845 if (*p != 0 || parts < 1) 846 usage(); 847 break; 848 case 'r': 849 readonly = 1; 850 break; 851 case 'v': 852 verbose++; 853 break; 854 default: 855 usage(); 856 } 857 } 858 if (!parts) 859 parts = 128; 860 861 if (argc == optind) 862 usage(); 863 864 cmd = argv[optind++]; 865 for (i = 0; cmdsw[i].name != NULL && strcmp(cmd, cmdsw[i].name); i++); 866 867 if (cmdsw[i].fptr == NULL) 868 errx(1, "unknown command: %s", cmd); 869 870 prefix(cmd); 871 return ((*cmdsw[i].fptr)(argc, argv)); 872 } 873