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