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