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 #if HAVE_NBTOOL_CONFIG_H 30 #include "nbtool_config.h" 31 #endif 32 33 #include <sys/cdefs.h> 34 #ifdef __FBSDID 35 __FBSDID("$FreeBSD: src/sbin/gpt/gpt.c,v 1.16 2006/07/07 02:44:23 marcel Exp $"); 36 #endif 37 #ifdef __RCSID 38 __RCSID("$NetBSD: gpt.c,v 1.64 2015/12/06 00:39:26 christos Exp $"); 39 #endif 40 41 #include <sys/param.h> 42 #include <sys/types.h> 43 #include <sys/stat.h> 44 #include <sys/ioctl.h> 45 #include <sys/bootblock.h> 46 47 #include <err.h> 48 #include <errno.h> 49 #include <fcntl.h> 50 #include <paths.h> 51 #include <stddef.h> 52 #include <stdarg.h> 53 #include <stdio.h> 54 #include <stdlib.h> 55 #include <string.h> 56 #include <unistd.h> 57 #include <ctype.h> 58 59 #include "map.h" 60 #include "gpt.h" 61 #include "gpt_private.h" 62 63 static uint32_t crc32_tab[] = { 64 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 65 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 66 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, 67 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 68 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 69 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 70 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, 71 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 72 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 73 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 74 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, 75 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, 76 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 77 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 78 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, 79 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 80 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 81 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 82 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 83 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, 84 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 85 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 86 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, 87 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 88 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 89 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 90 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, 91 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 92 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 93 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 94 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, 95 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 96 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 97 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 98 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, 99 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, 100 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 101 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 102 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 103 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, 104 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 105 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 106 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d 107 }; 108 109 uint32_t 110 crc32(const void *buf, size_t size) 111 { 112 const uint8_t *p; 113 uint32_t crc; 114 115 p = buf; 116 crc = ~0U; 117 118 while (size--) 119 crc = crc32_tab[(crc ^ *p++) & 0xFF] ^ (crc >> 8); 120 121 return crc ^ ~0U; 122 } 123 124 void 125 utf16_to_utf8(const uint16_t *s16, uint8_t *s8, size_t s8len) 126 { 127 size_t s8idx, s16idx, s16len; 128 uint32_t utfchar; 129 unsigned int c; 130 131 s16len = 0; 132 while (s16[s16len++] != 0) 133 continue; 134 s8idx = s16idx = 0; 135 while (s16idx < s16len) { 136 utfchar = le16toh(s16[s16idx++]); 137 if ((utfchar & 0xf800) == 0xd800) { 138 c = le16toh(s16[s16idx]); 139 if ((utfchar & 0x400) != 0 || (c & 0xfc00) != 0xdc00) 140 utfchar = 0xfffd; 141 else 142 s16idx++; 143 } 144 if (utfchar < 0x80) { 145 if (s8idx + 1 >= s8len) 146 break; 147 s8[s8idx++] = (uint8_t)utfchar; 148 } else if (utfchar < 0x800) { 149 if (s8idx + 2 >= s8len) 150 break; 151 s8[s8idx++] = (uint8_t)(0xc0 | (utfchar >> 6)); 152 s8[s8idx++] = (uint8_t)(0x80 | (utfchar & 0x3f)); 153 } else if (utfchar < 0x10000) { 154 if (s8idx + 3 >= s8len) 155 break; 156 s8[s8idx++] = (uint8_t)(0xe0 | (utfchar >> 12)); 157 s8[s8idx++] = (uint8_t)(0x80 | ((utfchar >> 6) & 0x3f)); 158 s8[s8idx++] = (uint8_t)(0x80 | (utfchar & 0x3f)); 159 } else if (utfchar < 0x200000) { 160 if (s8idx + 4 >= s8len) 161 break; 162 s8[s8idx++] = (uint8_t)(0xf0 | (utfchar >> 18)); 163 s8[s8idx++] = (uint8_t)(0x80 | ((utfchar >> 12) & 0x3f)); 164 s8[s8idx++] = (uint8_t)(0x80 | ((utfchar >> 6) & 0x3f)); 165 s8[s8idx++] = (uint8_t)(0x80 | (utfchar & 0x3f)); 166 } 167 } 168 s8[s8idx] = 0; 169 } 170 171 void 172 utf8_to_utf16(const uint8_t *s8, uint16_t *s16, size_t s16len) 173 { 174 size_t s16idx, s8idx, s8len; 175 uint32_t utfchar = 0; 176 unsigned int c, utfbytes; 177 178 s8len = 0; 179 while (s8[s8len++] != 0) 180 ; 181 s8idx = s16idx = 0; 182 utfbytes = 0; 183 do { 184 c = s8[s8idx++]; 185 if ((c & 0xc0) != 0x80) { 186 /* Initial characters. */ 187 if (utfbytes != 0) { 188 /* Incomplete encoding. */ 189 s16[s16idx++] = htole16(0xfffd); 190 if (s16idx == s16len) { 191 s16[--s16idx] = 0; 192 return; 193 } 194 } 195 if ((c & 0xf8) == 0xf0) { 196 utfchar = c & 0x07; 197 utfbytes = 3; 198 } else if ((c & 0xf0) == 0xe0) { 199 utfchar = c & 0x0f; 200 utfbytes = 2; 201 } else if ((c & 0xe0) == 0xc0) { 202 utfchar = c & 0x1f; 203 utfbytes = 1; 204 } else { 205 utfchar = c & 0x7f; 206 utfbytes = 0; 207 } 208 } else { 209 /* Followup characters. */ 210 if (utfbytes > 0) { 211 utfchar = (utfchar << 6) + (c & 0x3f); 212 utfbytes--; 213 } else if (utfbytes == 0) 214 utfbytes = (u_int)~0; 215 } 216 if (utfbytes == 0) { 217 if (utfchar >= 0x10000 && s16idx + 2 >= s16len) 218 utfchar = 0xfffd; 219 if (utfchar >= 0x10000) { 220 s16[s16idx++] = htole16((uint16_t) 221 (0xd800 | ((utfchar>>10) - 0x40))); 222 s16[s16idx++] = htole16((uint16_t) 223 (0xdc00 | (utfchar & 0x3ff))); 224 } else 225 s16[s16idx++] = htole16((uint16_t)utfchar); 226 if (s16idx == s16len) { 227 s16[--s16idx] = 0; 228 return; 229 } 230 } 231 } while (c != 0); 232 } 233 234 void * 235 gpt_read(gpt_t gpt, off_t lba, size_t count) 236 { 237 off_t ofs; 238 void *buf; 239 240 count *= gpt->secsz; 241 buf = malloc(count); 242 if (buf == NULL) 243 return NULL; 244 245 ofs = lba * gpt->secsz; 246 if (lseek(gpt->fd, ofs, SEEK_SET) == ofs && 247 read(gpt->fd, buf, count) == (ssize_t)count) 248 return buf; 249 250 free(buf); 251 return NULL; 252 } 253 254 int 255 gpt_write(gpt_t gpt, map_t map) 256 { 257 off_t ofs; 258 size_t count; 259 260 count = (size_t)(map->map_size * gpt->secsz); 261 ofs = map->map_start * gpt->secsz; 262 if (lseek(gpt->fd, ofs, SEEK_SET) != ofs || 263 write(gpt->fd, map->map_data, count) != (ssize_t)count) 264 return -1; 265 gpt->flags |= GPT_MODIFIED; 266 return 0; 267 } 268 269 static int 270 gpt_mbr(gpt_t gpt, off_t lba) 271 { 272 struct mbr *mbr; 273 map_t m, p; 274 off_t size, start; 275 unsigned int i, pmbr; 276 277 mbr = gpt_read(gpt, lba, 1); 278 if (mbr == NULL) { 279 gpt_warn(gpt, "Read failed"); 280 return -1; 281 } 282 283 if (mbr->mbr_sig != htole16(MBR_SIG)) { 284 if (gpt->verbose) 285 gpt_msg(gpt, 286 "MBR not found at sector %ju", (uintmax_t)lba); 287 free(mbr); 288 return 0; 289 } 290 291 /* 292 * Differentiate between a regular MBR and a PMBR. This is more 293 * convenient in general. A PMBR is one with a single partition 294 * of type 0xee. 295 */ 296 pmbr = 0; 297 for (i = 0; i < 4; i++) { 298 if (mbr->mbr_part[i].part_typ == MBR_PTYPE_UNUSED) 299 continue; 300 if (mbr->mbr_part[i].part_typ == MBR_PTYPE_PMBR) 301 pmbr++; 302 else 303 break; 304 } 305 if (pmbr && i == 4 && lba == 0) { 306 if (pmbr != 1) 307 gpt_warnx(gpt, "Suspicious PMBR at sector %ju", 308 (uintmax_t)lba); 309 else if (gpt->verbose > 1) 310 gpt_msg(gpt, "PMBR at sector %ju", (uintmax_t)lba); 311 p = map_add(gpt, lba, 1LL, MAP_TYPE_PMBR, mbr, 1); 312 goto out; 313 } 314 if (pmbr) 315 gpt_warnx(gpt, "Suspicious MBR at sector %ju", (uintmax_t)lba); 316 else if (gpt->verbose > 1) 317 gpt_msg(gpt, "MBR at sector %ju", (uintmax_t)lba); 318 319 p = map_add(gpt, lba, 1LL, MAP_TYPE_MBR, mbr, 1); 320 if (p == NULL) 321 goto out; 322 323 for (i = 0; i < 4; i++) { 324 if (mbr->mbr_part[i].part_typ == MBR_PTYPE_UNUSED || 325 mbr->mbr_part[i].part_typ == MBR_PTYPE_PMBR) 326 continue; 327 start = le16toh(mbr->mbr_part[i].part_start_hi); 328 start = (start << 16) + le16toh(mbr->mbr_part[i].part_start_lo); 329 size = le16toh(mbr->mbr_part[i].part_size_hi); 330 size = (size << 16) + le16toh(mbr->mbr_part[i].part_size_lo); 331 if (start == 0 && size == 0) { 332 gpt_warnx(gpt, "Malformed MBR at sector %ju", 333 (uintmax_t)lba); 334 continue; 335 } 336 /* start is relative to the offset of the MBR itself. */ 337 start += lba; 338 if (gpt->verbose > 2) 339 gpt_msg(gpt, "MBR part: type=%d, start=%ju, size=%ju", 340 mbr->mbr_part[i].part_typ, 341 (uintmax_t)start, (uintmax_t)size); 342 if (mbr->mbr_part[i].part_typ != MBR_PTYPE_EXT_LBA) { 343 m = map_add(gpt, start, size, MAP_TYPE_MBR_PART, p, 0); 344 if (m == NULL) 345 return -1; 346 m->map_index = i + 1; 347 } else { 348 if (gpt_mbr(gpt, start) == -1) 349 return -1; 350 } 351 } 352 return 0; 353 out: 354 if (p == NULL) { 355 free(mbr); 356 return -1; 357 } 358 return 0; 359 } 360 361 int 362 gpt_gpt(gpt_t gpt, off_t lba, int found) 363 { 364 off_t size; 365 struct gpt_ent *ent; 366 struct gpt_hdr *hdr; 367 char *p; 368 map_t m; 369 size_t blocks, tblsz; 370 unsigned int i; 371 uint32_t crc; 372 373 hdr = gpt_read(gpt, lba, 1); 374 if (hdr == NULL) 375 return -1; 376 377 if (memcmp(hdr->hdr_sig, GPT_HDR_SIG, sizeof(hdr->hdr_sig))) 378 goto fail_hdr; 379 380 crc = le32toh(hdr->hdr_crc_self); 381 hdr->hdr_crc_self = 0; 382 if (crc32(hdr, le32toh(hdr->hdr_size)) != crc) { 383 if (gpt->verbose) 384 gpt_msg(gpt, "Bad CRC in GPT header at sector %ju", 385 (uintmax_t)lba); 386 goto fail_hdr; 387 } 388 389 tblsz = le32toh(hdr->hdr_entries) * le32toh(hdr->hdr_entsz); 390 blocks = tblsz / gpt->secsz + ((tblsz % gpt->secsz) ? 1 : 0); 391 392 /* Use generic pointer to deal with hdr->hdr_entsz != sizeof(*ent). */ 393 p = gpt_read(gpt, (off_t)le64toh((uint64_t)hdr->hdr_lba_table), blocks); 394 if (p == NULL) { 395 if (found) { 396 if (gpt->verbose) 397 gpt_msg(gpt, 398 "Cannot read LBA table at sector %ju", 399 (uintmax_t)le64toh(hdr->hdr_lba_table)); 400 return -1; 401 } 402 goto fail_hdr; 403 } 404 405 if (crc32(p, tblsz) != le32toh(hdr->hdr_crc_table)) { 406 if (gpt->verbose) 407 gpt_msg(gpt, "Bad CRC in GPT table at sector %ju", 408 (uintmax_t)le64toh(hdr->hdr_lba_table)); 409 goto fail_ent; 410 } 411 412 if (gpt->verbose > 1) 413 gpt_msg(gpt, "%s GPT at sector %ju", 414 (lba == 1) ? "Pri" : "Sec", (uintmax_t)lba); 415 416 m = map_add(gpt, lba, 1, (lba == 1) 417 ? MAP_TYPE_PRI_GPT_HDR : MAP_TYPE_SEC_GPT_HDR, hdr, 1); 418 if (m == NULL) 419 return (-1); 420 421 m = map_add(gpt, (off_t)le64toh((uint64_t)hdr->hdr_lba_table), 422 (off_t)blocks, 423 lba == 1 ? MAP_TYPE_PRI_GPT_TBL : MAP_TYPE_SEC_GPT_TBL, p, 1); 424 if (m == NULL) 425 return (-1); 426 427 if (lba != 1) 428 return (1); 429 430 for (i = 0; i < le32toh(hdr->hdr_entries); i++) { 431 ent = (void*)(p + i * le32toh(hdr->hdr_entsz)); 432 if (gpt_uuid_is_nil(ent->ent_type)) 433 continue; 434 435 size = (off_t)(le64toh((uint64_t)ent->ent_lba_end) - 436 le64toh((uint64_t)ent->ent_lba_start) + 1LL); 437 if (gpt->verbose > 2) { 438 char buf[128]; 439 gpt_uuid_snprintf(buf, sizeof(buf), "%s", 440 ent->ent_type); 441 gpt_msg(gpt, "GPT partition: type=%s, start=%ju, " 442 "size=%ju", buf, 443 (uintmax_t)le64toh(ent->ent_lba_start), 444 (uintmax_t)size); 445 } 446 m = map_add(gpt, (off_t)le64toh((uint64_t)ent->ent_lba_start), 447 size, MAP_TYPE_GPT_PART, ent, 0); 448 if (m == NULL) 449 return (-1); 450 m->map_index = i + 1; 451 } 452 return (1); 453 454 fail_ent: 455 free(p); 456 457 fail_hdr: 458 free(hdr); 459 return (0); 460 } 461 462 gpt_t 463 gpt_open(const char *dev, int flags, int verbose, off_t mediasz, u_int secsz) 464 { 465 int mode, found; 466 off_t devsz; 467 gpt_t gpt; 468 469 470 if ((gpt = calloc(1, sizeof(*gpt))) == NULL) { 471 if (!(flags & GPT_QUIET)) 472 warn("Cannot allocate `%s'", dev); 473 return NULL; 474 } 475 gpt->flags = flags; 476 gpt->verbose = verbose; 477 gpt->mediasz = mediasz; 478 gpt->secsz = secsz; 479 480 mode = (gpt->flags & GPT_READONLY) ? O_RDONLY : O_RDWR|O_EXCL; 481 482 gpt->fd = opendisk(dev, mode, gpt->device_name, 483 sizeof(gpt->device_name), 0); 484 if (gpt->fd == -1) { 485 strlcpy(gpt->device_name, dev, sizeof(gpt->device_name)); 486 gpt_warn(gpt, "Cannot open"); 487 goto close; 488 } 489 490 if (fstat(gpt->fd, &gpt->sb) == -1) { 491 gpt_warn(gpt, "Cannot stat"); 492 goto close; 493 } 494 495 if ((gpt->sb.st_mode & S_IFMT) != S_IFREG) { 496 if (gpt->secsz == 0) { 497 #ifdef DIOCGSECTORSIZE 498 if (ioctl(gpt->fd, DIOCGSECTORSIZE, &gpt->secsz) == -1) { 499 gpt_warn(gpt, "Cannot get sector size"); 500 goto close; 501 } 502 #endif 503 if (gpt->secsz == 0) { 504 gpt_warnx(gpt, "Sector size can't be 0"); 505 goto close; 506 } 507 } 508 if (gpt->mediasz == 0) { 509 #ifdef DIOCGMEDIASIZE 510 if (ioctl(gpt->fd, DIOCGMEDIASIZE, &gpt->mediasz) == -1) { 511 gpt_warn(gpt, "Cannot get media size"); 512 goto close; 513 } 514 #endif 515 if (gpt->mediasz == 0) { 516 gpt_warnx(gpt, "Media size can't be 0"); 517 goto close; 518 } 519 } 520 } else { 521 gpt->flags |= GPT_FILE; 522 if (gpt->secsz == 0) 523 gpt->secsz = 512; /* Fixed size for files. */ 524 if (gpt->mediasz == 0) { 525 if (gpt->sb.st_size % gpt->secsz) { 526 errno = EINVAL; 527 goto close; 528 } 529 gpt->mediasz = gpt->sb.st_size; 530 } 531 gpt->flags |= GPT_NOSYNC; 532 } 533 534 /* 535 * We require an absolute minimum of 6 sectors. One for the MBR, 536 * 2 for the GPT header, 2 for the GPT table and one to hold some 537 * user data. Let's catch this extreme border case here so that 538 * we don't have to worry about it later. 539 */ 540 devsz = gpt->mediasz / gpt->secsz; 541 if (devsz < 6) { 542 gpt_warnx(gpt, "Need 6 sectors, we have %ju", 543 (uintmax_t)devsz); 544 goto close; 545 } 546 547 if (gpt->verbose) { 548 gpt_msg(gpt, "mediasize=%ju; sectorsize=%u; blocks=%ju", 549 (uintmax_t)gpt->mediasz, gpt->secsz, (uintmax_t)devsz); 550 } 551 552 if (map_init(gpt, devsz) == -1) 553 goto close; 554 555 if (gpt_mbr(gpt, 0LL) == -1) 556 goto close; 557 if ((found = gpt_gpt(gpt, 1LL, 1)) == -1) 558 goto close; 559 if (gpt_gpt(gpt, devsz - 1LL, found) == -1) 560 goto close; 561 562 return gpt; 563 564 close: 565 if (gpt->fd != -1) 566 close(gpt->fd); 567 free(gpt); 568 return NULL; 569 } 570 571 void 572 gpt_close(gpt_t gpt) 573 { 574 575 if (!(gpt->flags & GPT_MODIFIED)) 576 goto out; 577 578 if (!(gpt->flags & GPT_NOSYNC)) { 579 #ifdef DIOCMWEDGES 580 int bits; 581 if (ioctl(gpt->fd, DIOCMWEDGES, &bits) == -1) 582 gpt_warn(gpt, "Can't update wedge information"); 583 else 584 goto out; 585 #endif 586 } 587 if (!(gpt->flags & GPT_FILE)) 588 gpt_msg(gpt, "You need to run \"dkctl %s makewedges\"" 589 " for the changes to take effect\n", gpt->device_name); 590 591 out: 592 close(gpt->fd); 593 } 594 595 void 596 gpt_warnx(gpt_t gpt, const char *fmt, ...) 597 { 598 va_list ap; 599 600 if (gpt->flags & GPT_QUIET) 601 return; 602 fprintf(stderr, "%s: %s: ", getprogname(), gpt->device_name); 603 va_start(ap, fmt); 604 vfprintf(stderr, fmt, ap); 605 va_end(ap); 606 fprintf(stderr, "\n"); 607 } 608 609 void 610 gpt_warn(gpt_t gpt, const char *fmt, ...) 611 { 612 va_list ap; 613 int e = errno; 614 615 if (gpt->flags & GPT_QUIET) 616 return; 617 fprintf(stderr, "%s: %s: ", getprogname(), gpt->device_name); 618 va_start(ap, fmt); 619 vfprintf(stderr, fmt, ap); 620 va_end(ap); 621 fprintf(stderr, " (%s)\n", strerror(e)); 622 errno = e; 623 } 624 625 void 626 gpt_msg(gpt_t gpt, const char *fmt, ...) 627 { 628 va_list ap; 629 630 if (gpt->flags & GPT_QUIET) 631 return; 632 printf("%s: ", gpt->device_name); 633 va_start(ap, fmt); 634 vprintf(fmt, ap); 635 va_end(ap); 636 printf("\n"); 637 } 638 639 struct gpt_hdr * 640 gpt_hdr(gpt_t gpt) 641 { 642 gpt->gpt = map_find(gpt, MAP_TYPE_PRI_GPT_HDR); 643 if (gpt->gpt == NULL) { 644 gpt_warnx(gpt, "No primary GPT header; run create or recover"); 645 return NULL; 646 } 647 648 gpt->tpg = map_find(gpt, MAP_TYPE_SEC_GPT_HDR); 649 if (gpt->tpg == NULL) { 650 gpt_warnx(gpt, "No secondary GPT header; run recover"); 651 return NULL; 652 } 653 654 gpt->tbl = map_find(gpt, MAP_TYPE_PRI_GPT_TBL); 655 gpt->lbt = map_find(gpt, MAP_TYPE_SEC_GPT_TBL); 656 if (gpt->tbl == NULL || gpt->lbt == NULL) { 657 gpt_warnx(gpt, "Corrupt maps, run recover"); 658 return NULL; 659 } 660 661 return gpt->gpt->map_data; 662 } 663 664 int 665 gpt_write_crc(gpt_t gpt, map_t map, map_t tbl) 666 { 667 struct gpt_hdr *hdr = map->map_data; 668 669 hdr->hdr_crc_table = htole32(crc32(tbl->map_data, 670 le32toh(hdr->hdr_entries) * le32toh(hdr->hdr_entsz))); 671 hdr->hdr_crc_self = 0; 672 hdr->hdr_crc_self = htole32(crc32(hdr, le32toh(hdr->hdr_size))); 673 674 if (gpt_write(gpt, map) == -1) { 675 gpt_warn(gpt, "Error writing crc map"); 676 return -1; 677 } 678 679 if (gpt_write(gpt, tbl) == -1) { 680 gpt_warn(gpt, "Error writing crc table"); 681 return -1; 682 } 683 684 return 0; 685 } 686 687 int 688 gpt_write_primary(gpt_t gpt) 689 { 690 return gpt_write_crc(gpt, gpt->gpt, gpt->tbl); 691 } 692 693 694 int 695 gpt_write_backup(gpt_t gpt) 696 { 697 return gpt_write_crc(gpt, gpt->tpg, gpt->lbt); 698 } 699 700 void 701 gpt_create_pmbr_part(struct mbr_part *part, off_t last) 702 { 703 part->part_shd = 0x00; 704 part->part_ssect = 0x02; 705 part->part_scyl = 0x00; 706 part->part_typ = MBR_PTYPE_PMBR; 707 part->part_ehd = 0xfe; 708 part->part_esect = 0xff; 709 part->part_ecyl = 0xff; 710 part->part_start_lo = htole16(1); 711 if (last > 0xffffffff) { 712 part->part_size_lo = htole16(0xffff); 713 part->part_size_hi = htole16(0xffff); 714 } else { 715 part->part_size_lo = htole16((uint16_t)last); 716 part->part_size_hi = htole16((uint16_t)(last >> 16)); 717 } 718 } 719 720 struct gpt_ent * 721 gpt_ent(map_t map, map_t tbl, unsigned int i) 722 { 723 struct gpt_hdr *hdr = map->map_data; 724 return (void *)((char *)tbl->map_data + i * le32toh(hdr->hdr_entsz)); 725 } 726 727 struct gpt_ent * 728 gpt_ent_primary(gpt_t gpt, unsigned int i) 729 { 730 return gpt_ent(gpt->gpt, gpt->tbl, i); 731 } 732 733 struct gpt_ent * 734 gpt_ent_backup(gpt_t gpt, unsigned int i) 735 { 736 return gpt_ent(gpt->tpg, gpt->lbt, i); 737 } 738 739 int 740 gpt_usage(const char *prefix, const struct gpt_cmd *cmd) 741 { 742 const char **a = cmd->help; 743 size_t hlen = cmd->hlen; 744 size_t i; 745 746 if (prefix == NULL) { 747 const char *pname = getprogname(); 748 const char *d1, *d2, *d = " <device>"; 749 int len = (int)strlen(pname); 750 if (strcmp(pname, "gpt") == 0) { 751 d1 = ""; 752 d2 = d; 753 } else { 754 d2 = ""; 755 d1 = d; 756 } 757 fprintf(stderr, "Usage: %s%s %s %s%s\n", pname, 758 d1, cmd->name, a[0], d2); 759 for (i = 1; i < hlen; i++) { 760 fprintf(stderr, 761 " %*s%s %s %s%s\n", len, "", 762 d1, cmd->name, a[i], d2); 763 } 764 } else { 765 for (i = 0; i < hlen; i++) 766 fprintf(stderr, "%s%s %s\n", prefix, cmd->name, a[i]); 767 } 768 return -1; 769 } 770 771 off_t 772 gpt_last(gpt_t gpt) 773 { 774 return gpt->mediasz / gpt->secsz - 1LL; 775 } 776 777 off_t 778 gpt_create(gpt_t gpt, off_t last, u_int parts, int primary_only) 779 { 780 off_t blocks; 781 map_t map; 782 struct gpt_hdr *hdr; 783 struct gpt_ent *ent; 784 unsigned int i; 785 void *p; 786 787 if (map_find(gpt, MAP_TYPE_PRI_GPT_HDR) != NULL || 788 map_find(gpt, MAP_TYPE_SEC_GPT_HDR) != NULL) { 789 gpt_warnx(gpt, "Device already contains a GPT"); 790 return -1; 791 } 792 793 /* Get the amount of free space after the MBR */ 794 blocks = map_free(gpt, 1LL, 0LL); 795 if (blocks == 0LL) { 796 gpt_warnx(gpt, "No room for the GPT header"); 797 return -1; 798 } 799 800 /* Don't create more than parts entries. */ 801 if ((uint64_t)(blocks - 1) * gpt->secsz > 802 parts * sizeof(struct gpt_ent)) { 803 blocks = (off_t)((parts * sizeof(struct gpt_ent)) / gpt->secsz); 804 if ((parts * sizeof(struct gpt_ent)) % gpt->secsz) 805 blocks++; 806 blocks++; /* Don't forget the header itself */ 807 } 808 809 /* Never cross the median of the device. */ 810 if ((blocks + 1LL) > ((last + 1LL) >> 1)) 811 blocks = ((last + 1LL) >> 1) - 1LL; 812 813 /* 814 * Get the amount of free space at the end of the device and 815 * calculate the size for the GPT structures. 816 */ 817 map = map_last(gpt); 818 if (map->map_type != MAP_TYPE_UNUSED) { 819 gpt_warnx(gpt, "No room for the backup header"); 820 return -1; 821 } 822 823 if (map->map_size < blocks) 824 blocks = map->map_size; 825 if (blocks == 1LL) { 826 gpt_warnx(gpt, "No room for the GPT table"); 827 return -1; 828 } 829 830 blocks--; /* Number of blocks in the GPT table. */ 831 832 if (gpt_add_hdr(gpt, MAP_TYPE_PRI_GPT_HDR, 1) == -1) 833 return -1; 834 835 if ((p = calloc((size_t)blocks, gpt->secsz)) == NULL) { 836 gpt_warnx(gpt, "Can't allocate the primary GPT table"); 837 return -1; 838 } 839 if ((gpt->tbl = map_add(gpt, 2LL, blocks, 840 MAP_TYPE_PRI_GPT_TBL, p, 1)) == NULL) { 841 free(p); 842 gpt_warnx(gpt, "Can't add the primary GPT table"); 843 return -1; 844 } 845 846 hdr = gpt->gpt->map_data; 847 memcpy(hdr->hdr_sig, GPT_HDR_SIG, sizeof(hdr->hdr_sig)); 848 849 /* 850 * XXX struct gpt_hdr is not a multiple of 8 bytes in size and thus 851 * contains padding we must not include in the size. 852 */ 853 hdr->hdr_revision = htole32(GPT_HDR_REVISION); 854 hdr->hdr_size = htole32(GPT_HDR_SIZE); 855 hdr->hdr_lba_self = htole64((uint64_t)gpt->gpt->map_start); 856 hdr->hdr_lba_alt = htole64((uint64_t)last); 857 hdr->hdr_lba_start = htole64((uint64_t)(gpt->tbl->map_start + blocks)); 858 hdr->hdr_lba_end = htole64((uint64_t)(last - blocks - 1LL)); 859 if (gpt_uuid_generate(gpt, hdr->hdr_guid) == -1) 860 return -1; 861 hdr->hdr_lba_table = htole64((uint64_t)(gpt->tbl->map_start)); 862 hdr->hdr_entries = htole32((uint32_t)(((uint64_t)blocks * gpt->secsz) / 863 sizeof(struct gpt_ent))); 864 if (le32toh(hdr->hdr_entries) > parts) 865 hdr->hdr_entries = htole32(parts); 866 hdr->hdr_entsz = htole32(sizeof(struct gpt_ent)); 867 868 ent = gpt->tbl->map_data; 869 for (i = 0; i < le32toh(hdr->hdr_entries); i++) { 870 if (gpt_uuid_generate(gpt, ent[i].ent_guid) == -1) 871 return -1; 872 } 873 874 /* 875 * Create backup GPT if the user didn't suppress it. 876 */ 877 if (primary_only) 878 return last; 879 880 if (gpt_add_hdr(gpt, MAP_TYPE_SEC_GPT_HDR, last) == -1) 881 return -1; 882 883 if ((gpt->lbt = map_add(gpt, last - blocks, blocks, 884 MAP_TYPE_SEC_GPT_TBL, gpt->tbl->map_data, 0)) == NULL) { 885 gpt_warnx(gpt, "Can't add the secondary GPT table"); 886 return -1; 887 } 888 889 memcpy(gpt->tpg->map_data, gpt->gpt->map_data, gpt->secsz); 890 891 hdr = gpt->tpg->map_data; 892 hdr->hdr_lba_self = htole64((uint64_t)gpt->tpg->map_start); 893 hdr->hdr_lba_alt = htole64((uint64_t)gpt->gpt->map_start); 894 hdr->hdr_lba_table = htole64((uint64_t)gpt->lbt->map_start); 895 return last; 896 } 897 898 static int 899 gpt_size_get(gpt_t gpt, off_t *size) 900 { 901 off_t sectors; 902 int64_t human_num; 903 char *p; 904 905 if (*size > 0) 906 return -1; 907 sectors = strtoll(optarg, &p, 10); 908 if (sectors < 1) 909 return -1; 910 if (*p == '\0' || ((*p == 's' || *p == 'S') && p[1] == '\0')) { 911 *size = sectors * gpt->secsz; 912 return 0; 913 } 914 if ((*p == 'b' || *p == 'B') && p[1] == '\0') { 915 *size = sectors; 916 return 0; 917 } 918 if (dehumanize_number(optarg, &human_num) < 0) 919 return -1; 920 *size = human_num; 921 return 0; 922 } 923 924 int 925 gpt_human_get(off_t *human) 926 { 927 int64_t human_num; 928 929 if (*human > 0) 930 return -1; 931 if (dehumanize_number(optarg, &human_num) < 0) 932 return -1; 933 *human = human_num; 934 if (*human < 1) 935 return -1; 936 return 0; 937 } 938 939 int 940 gpt_add_find(gpt_t gpt, struct gpt_find *find, int ch) 941 { 942 switch (ch) { 943 case 'a': 944 if (find->all > 0) 945 return -1; 946 find->all = 1; 947 break; 948 case 'b': 949 if (gpt_human_get(&find->block) == -1) 950 return -1; 951 break; 952 case 'i': 953 if (gpt_uint_get(&find->entry) == -1) 954 return -1; 955 break; 956 case 'L': 957 if (gpt_name_get(gpt, &find->label) == -1) 958 return -1; 959 break; 960 case 's': 961 if (gpt_size_get(gpt, &find->size) == -1) 962 return -1; 963 break; 964 case 't': 965 if (!gpt_uuid_is_nil(find->type)) 966 return -1; 967 if (gpt_uuid_parse(optarg, find->type) != 0) 968 return -1; 969 break; 970 default: 971 return -1; 972 } 973 return 0; 974 } 975 976 int 977 gpt_change_ent(gpt_t gpt, const struct gpt_find *find, 978 void (*cfn)(struct gpt_ent *, void *), void *v) 979 { 980 map_t m; 981 struct gpt_hdr *hdr; 982 struct gpt_ent *ent; 983 unsigned int i; 984 uint8_t utfbuf[__arraycount(ent->ent_name) * 3 + 1]; 985 986 if (!find->all ^ 987 (find->block > 0 || find->entry > 0 || find->label != NULL 988 || find->size > 0 || !gpt_uuid_is_nil(find->type))) 989 return -1; 990 991 if ((hdr = gpt_hdr(gpt)) == NULL) 992 return -1; 993 994 /* Relabel all matching entries in the map. */ 995 for (m = map_first(gpt); m != NULL; m = m->map_next) { 996 if (m->map_type != MAP_TYPE_GPT_PART || m->map_index < 1) 997 continue; 998 if (find->entry > 0 && find->entry != m->map_index) 999 continue; 1000 if (find->block > 0 && find->block != m->map_start) 1001 continue; 1002 if (find->size > 0 && find->size != m->map_size) 1003 continue; 1004 1005 i = m->map_index - 1; 1006 1007 ent = gpt_ent_primary(gpt, i); 1008 if (find->label != NULL) { 1009 utf16_to_utf8(ent->ent_name, utfbuf, sizeof(utfbuf)); 1010 if (strcmp((char *)find->label, (char *)utfbuf) == 0) 1011 continue; 1012 } 1013 1014 if (!gpt_uuid_is_nil(find->type) && 1015 !gpt_uuid_equal(find->type, ent->ent_type)) 1016 continue; 1017 1018 /* Change the primary entry. */ 1019 (*cfn)(ent, v); 1020 1021 if (gpt_write_primary(gpt) == -1) 1022 return -1; 1023 1024 ent = gpt_ent_backup(gpt, i); 1025 /* Change the secondary entry. */ 1026 (*cfn)(ent, v); 1027 1028 if (gpt_write_backup(gpt) == -1) 1029 return -1; 1030 1031 gpt_msg(gpt, "Partition %d %s", m->map_index, find->msg); 1032 } 1033 return 0; 1034 } 1035 1036 int 1037 gpt_add_ais(gpt_t gpt, off_t *alignment, u_int *entry, off_t *size, int ch) 1038 { 1039 switch (ch) { 1040 case 'a': 1041 if (gpt_human_get(alignment) == -1) 1042 return -1; 1043 return 0; 1044 case 'i': 1045 if (gpt_uint_get(entry) == -1) 1046 return -1; 1047 return 0; 1048 case 's': 1049 if (gpt_size_get(gpt, size) == -1) 1050 return -1; 1051 return 0; 1052 default: 1053 return -1; 1054 } 1055 } 1056 1057 off_t 1058 gpt_check_ais(gpt_t gpt, off_t alignment, u_int entry, off_t size) 1059 { 1060 if (entry == 0) { 1061 gpt_warnx(gpt, "Entry not specified"); 1062 return -1; 1063 } 1064 if (alignment % gpt->secsz != 0) { 1065 gpt_warnx(gpt, "Alignment (%#jx) must be a multiple of " 1066 "sector size (%#x)", (uintmax_t)alignment, gpt->secsz); 1067 return -1; 1068 } 1069 1070 if (size % gpt->secsz != 0) { 1071 gpt_warnx(gpt, "Size (%#jx) must be a multiple of " 1072 "sector size (%#x)", (uintmax_t)size, gpt->secsz); 1073 return -1; 1074 } 1075 if (size > 0) 1076 return size / gpt->secsz; 1077 return 0; 1078 } 1079 1080 static const struct nvd { 1081 const char *name; 1082 uint64_t mask; 1083 const char *description; 1084 } gpt_attr[] = { 1085 { 1086 "biosboot", 1087 GPT_ENT_ATTR_LEGACY_BIOS_BOOTABLE, 1088 "Legacy BIOS boot partition", 1089 }, 1090 { 1091 "bootme", 1092 GPT_ENT_ATTR_BOOTME, 1093 "Bootable partition", 1094 }, 1095 { 1096 "bootfailed", 1097 GPT_ENT_ATTR_BOOTFAILED, 1098 "Partition that marked bootonce failed to boot", 1099 }, 1100 { 1101 "bootonce", 1102 GPT_ENT_ATTR_BOOTONCE, 1103 "Attempt to boot this partition only once", 1104 }, 1105 { 1106 "noblockio", 1107 GPT_ENT_ATTR_NO_BLOCK_IO_PROTOCOL, 1108 "UEFI won't recognize file system for block I/O", 1109 }, 1110 { 1111 "required", 1112 GPT_ENT_ATTR_REQUIRED_PARTITION, 1113 "Partition required for platform to function", 1114 }, 1115 }; 1116 1117 int 1118 gpt_attr_get(gpt_t gpt, uint64_t *attributes) 1119 { 1120 size_t i; 1121 int rv = 0; 1122 char *ptr; 1123 1124 *attributes = 0; 1125 1126 for (ptr = strtok(optarg, ","); ptr; ptr = strtok(NULL, ",")) { 1127 for (i = 0; i < __arraycount(gpt_attr); i++) 1128 if (strcmp(gpt_attr[i].name, ptr) == 0) 1129 break; 1130 if (i == __arraycount(gpt_attr)) { 1131 gpt_warnx(gpt, "Unregognized attribute `%s'", ptr); 1132 rv = -1; 1133 } else 1134 *attributes |= gpt_attr[i].mask; 1135 } 1136 return rv; 1137 } 1138 1139 void 1140 gpt_attr_help(const char *prefix) 1141 { 1142 size_t i; 1143 1144 for (i = 0; i < __arraycount(gpt_attr); i++) 1145 printf("%s%10.10s\t%s\n", prefix, gpt_attr[i].name, 1146 gpt_attr[i].description); 1147 } 1148 1149 const char * 1150 gpt_attr_list(char *buf, size_t len, uint64_t attributes) 1151 { 1152 size_t i; 1153 strlcpy(buf, "", len); 1154 1155 for (i = 0; i < __arraycount(gpt_attr); i++) 1156 if (attributes & gpt_attr[i].mask) { 1157 strlcat(buf, buf[0] ? "," : "", len); 1158 strlcat(buf, gpt_attr[i].name, len); 1159 } 1160 return buf; 1161 } 1162 1163 int 1164 gpt_attr_update(gpt_t gpt, u_int entry, uint64_t set, uint64_t clr) 1165 { 1166 struct gpt_hdr *hdr; 1167 struct gpt_ent *ent; 1168 unsigned int i; 1169 1170 if (entry == 0 || (set == 0 && clr == 0)) 1171 return -1; 1172 1173 if ((hdr = gpt_hdr(gpt)) == NULL) 1174 return -1; 1175 1176 if (entry > le32toh(hdr->hdr_entries)) { 1177 gpt_warnx(gpt, "Index %u out of range (%u max)", 1178 entry, le32toh(hdr->hdr_entries)); 1179 return -1; 1180 } 1181 1182 i = entry - 1; 1183 ent = gpt_ent_primary(gpt, i); 1184 if (gpt_uuid_is_nil(ent->ent_type)) { 1185 gpt_warnx(gpt, "Entry at index %u is unused", entry); 1186 return -1; 1187 } 1188 1189 ent->ent_attr &= ~clr; 1190 ent->ent_attr |= set; 1191 1192 if (gpt_write_primary(gpt) == -1) 1193 return -1; 1194 1195 ent = gpt_ent_backup(gpt, i); 1196 ent->ent_attr &= ~clr; 1197 ent->ent_attr |= set; 1198 1199 if (gpt_write_backup(gpt) == -1) 1200 return -1; 1201 gpt_msg(gpt, "Partition %d attributes updated", entry); 1202 return 0; 1203 } 1204 1205 int 1206 gpt_uint_get(u_int *entry) 1207 { 1208 char *p; 1209 if (*entry > 0) 1210 return -1; 1211 *entry = (u_int)strtoul(optarg, &p, 10); 1212 if (*p != 0 || *entry < 1) 1213 return -1; 1214 return 0; 1215 } 1216 int 1217 gpt_uuid_get(gpt_t gpt, gpt_uuid_t *uuid) 1218 { 1219 if (!gpt_uuid_is_nil(*uuid)) 1220 return -1; 1221 if (gpt_uuid_parse(optarg, *uuid) != 0) { 1222 gpt_warn(gpt, "Can't parse uuid"); 1223 return -1; 1224 } 1225 return 0; 1226 } 1227 1228 int 1229 gpt_name_get(gpt_t gpt, void *v) 1230 { 1231 char **name = v; 1232 if (*name != NULL) 1233 return -1; 1234 *name = strdup(optarg); 1235 if (*name == NULL) { 1236 gpt_warn(gpt, "Can't copy string"); 1237 return -1; 1238 } 1239 return 0; 1240 } 1241 1242 void 1243 gpt_show_num(const char *prompt, uintmax_t num) 1244 { 1245 #ifdef HN_AUTOSCALE 1246 char human_num[5]; 1247 if (humanize_number(human_num, 5, (int64_t)num , 1248 "", HN_AUTOSCALE, HN_NOSPACE|HN_B) < 0) 1249 human_num[0] = '\0'; 1250 #endif 1251 printf("%s: %ju", prompt, num); 1252 #ifdef HN_AUTOSCALE 1253 if (human_num[0] != '\0') 1254 printf(" (%s)", human_num); 1255 #endif 1256 printf("\n"); 1257 } 1258 1259 int 1260 gpt_add_hdr(gpt_t gpt, int type, off_t loc) 1261 { 1262 void *p; 1263 map_t *t; 1264 const char *msg; 1265 1266 switch (type) { 1267 case MAP_TYPE_PRI_GPT_HDR: 1268 t = &gpt->gpt; 1269 msg = "primary"; 1270 break; 1271 case MAP_TYPE_SEC_GPT_HDR: 1272 t = &gpt->tpg; 1273 msg = "secondary"; 1274 break; 1275 default: 1276 gpt_warnx(gpt, "Unknown GPT header type %d", type); 1277 return -1; 1278 } 1279 1280 if ((p = calloc(1, gpt->secsz)) == NULL) { 1281 gpt_warn(gpt, "Error allocating %s GPT header", msg); 1282 return -1; 1283 } 1284 1285 *t = map_add(gpt, loc, 1LL, type, p, 1); 1286 if (*t == NULL) { 1287 gpt_warn(gpt, "Error adding %s GPT header", msg); 1288 free(p); 1289 return -1; 1290 } 1291 return 0; 1292 } 1293