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