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