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.69 2016/09/24 13:40:55 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: flag=%#x type=%d, start=%ju, " 340 "size=%ju", mbr->mbr_part[i].part_flag, 341 mbr->mbr_part[i].part_typ, 342 (uintmax_t)start, (uintmax_t)size); 343 if (mbr->mbr_part[i].part_typ != MBR_PTYPE_EXT_LBA) { 344 m = map_add(gpt, start, size, MAP_TYPE_MBR_PART, p, 0); 345 if (m == NULL) 346 return -1; 347 m->map_index = i + 1; 348 } else { 349 if (gpt_mbr(gpt, start) == -1) 350 return -1; 351 } 352 } 353 return 0; 354 out: 355 if (p == NULL) { 356 free(mbr); 357 return -1; 358 } 359 return 0; 360 } 361 362 int 363 gpt_gpt(gpt_t gpt, off_t lba, int found) 364 { 365 off_t size; 366 struct gpt_ent *ent; 367 struct gpt_hdr *hdr; 368 char *p; 369 map_t m; 370 size_t blocks, tblsz; 371 unsigned int i; 372 uint32_t crc; 373 374 hdr = gpt_read(gpt, lba, 1); 375 if (hdr == NULL) 376 return -1; 377 378 if (memcmp(hdr->hdr_sig, GPT_HDR_SIG, sizeof(hdr->hdr_sig))) 379 goto fail_hdr; 380 381 crc = le32toh(hdr->hdr_crc_self); 382 hdr->hdr_crc_self = 0; 383 if (crc32(hdr, le32toh(hdr->hdr_size)) != crc) { 384 if (gpt->verbose) 385 gpt_msg(gpt, "Bad CRC in GPT header at sector %ju", 386 (uintmax_t)lba); 387 goto fail_hdr; 388 } 389 390 tblsz = le32toh(hdr->hdr_entries) * le32toh(hdr->hdr_entsz); 391 blocks = tblsz / gpt->secsz + ((tblsz % gpt->secsz) ? 1 : 0); 392 393 /* Use generic pointer to deal with hdr->hdr_entsz != sizeof(*ent). */ 394 p = gpt_read(gpt, (off_t)le64toh((uint64_t)hdr->hdr_lba_table), blocks); 395 if (p == NULL) { 396 if (found) { 397 if (gpt->verbose) 398 gpt_msg(gpt, 399 "Cannot read LBA table at sector %ju", 400 (uintmax_t)le64toh(hdr->hdr_lba_table)); 401 return -1; 402 } 403 goto fail_hdr; 404 } 405 406 if (crc32(p, tblsz) != le32toh(hdr->hdr_crc_table)) { 407 if (gpt->verbose) 408 gpt_msg(gpt, "Bad CRC in GPT table at sector %ju", 409 (uintmax_t)le64toh(hdr->hdr_lba_table)); 410 goto fail_ent; 411 } 412 413 if (gpt->verbose > 1) 414 gpt_msg(gpt, "%s GPT at sector %ju", 415 (lba == 1) ? "Pri" : "Sec", (uintmax_t)lba); 416 417 m = map_add(gpt, lba, 1, (lba == 1) 418 ? MAP_TYPE_PRI_GPT_HDR : MAP_TYPE_SEC_GPT_HDR, hdr, 1); 419 if (m == NULL) 420 return (-1); 421 422 m = map_add(gpt, (off_t)le64toh((uint64_t)hdr->hdr_lba_table), 423 (off_t)blocks, 424 lba == 1 ? MAP_TYPE_PRI_GPT_TBL : MAP_TYPE_SEC_GPT_TBL, p, 1); 425 if (m == NULL) 426 return (-1); 427 428 if (lba != 1) 429 return (1); 430 431 for (i = 0; i < le32toh(hdr->hdr_entries); i++) { 432 ent = (void*)(p + i * le32toh(hdr->hdr_entsz)); 433 if (gpt_uuid_is_nil(ent->ent_type)) 434 continue; 435 436 size = (off_t)(le64toh((uint64_t)ent->ent_lba_end) - 437 le64toh((uint64_t)ent->ent_lba_start) + 1LL); 438 if (gpt->verbose > 2) { 439 char buf[128]; 440 gpt_uuid_snprintf(buf, sizeof(buf), "%s", 441 ent->ent_type); 442 gpt_msg(gpt, "GPT partition: type=%s, start=%ju, " 443 "size=%ju", buf, 444 (uintmax_t)le64toh(ent->ent_lba_start), 445 (uintmax_t)size); 446 } 447 m = map_add(gpt, (off_t)le64toh((uint64_t)ent->ent_lba_start), 448 size, MAP_TYPE_GPT_PART, ent, 0); 449 if (m == NULL) 450 return (-1); 451 m->map_index = i + 1; 452 } 453 return (1); 454 455 fail_ent: 456 free(p); 457 458 fail_hdr: 459 free(hdr); 460 return (0); 461 } 462 463 gpt_t 464 gpt_open(const char *dev, int flags, int verbose, off_t mediasz, u_int secsz) 465 { 466 int mode, found; 467 off_t devsz; 468 gpt_t gpt; 469 470 471 if ((gpt = calloc(1, sizeof(*gpt))) == NULL) { 472 if (!(flags & GPT_QUIET)) 473 warn("Cannot allocate `%s'", dev); 474 return NULL; 475 } 476 gpt->flags = flags; 477 gpt->verbose = verbose; 478 gpt->mediasz = mediasz; 479 gpt->secsz = secsz; 480 481 mode = (gpt->flags & GPT_READONLY) ? O_RDONLY : O_RDWR|O_EXCL; 482 483 gpt->fd = opendisk(dev, mode, gpt->device_name, 484 sizeof(gpt->device_name), 0); 485 if (gpt->fd == -1) { 486 strlcpy(gpt->device_name, dev, sizeof(gpt->device_name)); 487 gpt_warn(gpt, "Cannot open"); 488 goto close; 489 } 490 491 if (fstat(gpt->fd, &gpt->sb) == -1) { 492 gpt_warn(gpt, "Cannot stat"); 493 goto close; 494 } 495 496 if ((gpt->sb.st_mode & S_IFMT) != S_IFREG) { 497 if (gpt->secsz == 0) { 498 #ifdef DIOCGSECTORSIZE 499 if (ioctl(gpt->fd, DIOCGSECTORSIZE, &gpt->secsz) == -1) { 500 gpt_warn(gpt, "Cannot get sector size"); 501 goto close; 502 } 503 #endif 504 if (gpt->secsz == 0) { 505 gpt_warnx(gpt, "Sector size can't be 0"); 506 goto close; 507 } 508 } 509 if (gpt->mediasz == 0) { 510 #ifdef DIOCGMEDIASIZE 511 if (ioctl(gpt->fd, DIOCGMEDIASIZE, &gpt->mediasz) == -1) { 512 gpt_warn(gpt, "Cannot get media size"); 513 goto close; 514 } 515 #endif 516 if (gpt->mediasz == 0) { 517 gpt_warnx(gpt, "Media size can't be 0"); 518 goto close; 519 } 520 } 521 } else { 522 gpt->flags |= GPT_FILE; 523 if (gpt->secsz == 0) 524 gpt->secsz = 512; /* Fixed size for files. */ 525 if (gpt->mediasz == 0) { 526 if (gpt->sb.st_size % gpt->secsz) { 527 errno = EINVAL; 528 goto close; 529 } 530 gpt->mediasz = gpt->sb.st_size; 531 } 532 gpt->flags |= GPT_NOSYNC; 533 } 534 535 /* 536 * We require an absolute minimum of 6 sectors. One for the MBR, 537 * 2 for the GPT header, 2 for the GPT table and one to hold some 538 * user data. Let's catch this extreme border case here so that 539 * we don't have to worry about it later. 540 */ 541 devsz = gpt->mediasz / gpt->secsz; 542 if (devsz < 6) { 543 gpt_warnx(gpt, "Need 6 sectors, we have %ju", 544 (uintmax_t)devsz); 545 goto close; 546 } 547 548 if (gpt->verbose) { 549 gpt_msg(gpt, "mediasize=%ju; sectorsize=%u; blocks=%ju", 550 (uintmax_t)gpt->mediasz, gpt->secsz, (uintmax_t)devsz); 551 } 552 553 if (map_init(gpt, devsz) == -1) 554 goto close; 555 556 if (gpt_mbr(gpt, 0LL) == -1) 557 goto close; 558 if ((found = gpt_gpt(gpt, 1LL, 1)) == -1) 559 goto close; 560 if (gpt_gpt(gpt, devsz - 1LL, found) == -1) 561 goto close; 562 563 return gpt; 564 565 close: 566 if (gpt->fd != -1) 567 close(gpt->fd); 568 free(gpt); 569 return NULL; 570 } 571 572 void 573 gpt_close(gpt_t gpt) 574 { 575 576 if (!(gpt->flags & GPT_MODIFIED)) 577 goto out; 578 579 if (!(gpt->flags & GPT_NOSYNC)) { 580 #ifdef DIOCMWEDGES 581 int bits; 582 if (ioctl(gpt->fd, DIOCMWEDGES, &bits) == -1) 583 gpt_warn(gpt, "Can't update wedge information"); 584 else 585 goto out; 586 #endif 587 } 588 if (!(gpt->flags & GPT_FILE)) 589 gpt_msg(gpt, "You need to run \"dkctl %s makewedges\"" 590 " for the changes to take effect\n", gpt->device_name); 591 592 out: 593 close(gpt->fd); 594 } 595 596 __printflike(2, 0) 597 static void 598 gpt_vwarnx(gpt_t gpt, const char *fmt, va_list ap, const char *e) 599 { 600 if (gpt && (gpt->flags & GPT_QUIET)) 601 return; 602 fprintf(stderr, "%s: ", getprogname()); 603 if (gpt) 604 fprintf(stderr, "%s: ", gpt->device_name); 605 vfprintf(stderr, fmt, ap); 606 if (e) 607 fprintf(stderr, " (%s)\n", e); 608 else 609 fputc('\n', stderr); 610 } 611 612 void 613 gpt_warnx(gpt_t gpt, const char *fmt, ...) 614 { 615 va_list ap; 616 617 va_start(ap, fmt); 618 gpt_vwarnx(gpt, fmt, ap, NULL); 619 va_end(ap); 620 } 621 622 void 623 gpt_warn(gpt_t gpt, const char *fmt, ...) 624 { 625 va_list ap; 626 627 va_start(ap, fmt); 628 gpt_vwarnx(gpt, fmt, ap, strerror(errno)); 629 va_end(ap); 630 } 631 632 void 633 gpt_msg(gpt_t gpt, const char *fmt, ...) 634 { 635 va_list ap; 636 637 if (gpt && (gpt->flags & GPT_QUIET)) 638 return; 639 if (gpt) 640 printf("%s: ", gpt->device_name); 641 va_start(ap, fmt); 642 vprintf(fmt, ap); 643 va_end(ap); 644 printf("\n"); 645 } 646 647 struct gpt_hdr * 648 gpt_hdr(gpt_t gpt) 649 { 650 gpt->gpt = map_find(gpt, MAP_TYPE_PRI_GPT_HDR); 651 if (gpt->gpt == NULL) { 652 gpt_warnx(gpt, "No primary GPT header; run create or recover"); 653 return NULL; 654 } 655 656 gpt->tpg = map_find(gpt, MAP_TYPE_SEC_GPT_HDR); 657 if (gpt->tpg == NULL) { 658 gpt_warnx(gpt, "No secondary GPT header; run recover"); 659 return NULL; 660 } 661 662 gpt->tbl = map_find(gpt, MAP_TYPE_PRI_GPT_TBL); 663 gpt->lbt = map_find(gpt, MAP_TYPE_SEC_GPT_TBL); 664 if (gpt->tbl == NULL || gpt->lbt == NULL) { 665 gpt_warnx(gpt, "Corrupt maps, run recover"); 666 return NULL; 667 } 668 669 return gpt->gpt->map_data; 670 } 671 672 int 673 gpt_write_crc(gpt_t gpt, map_t map, map_t tbl) 674 { 675 struct gpt_hdr *hdr = map->map_data; 676 677 hdr->hdr_crc_table = htole32(crc32(tbl->map_data, 678 le32toh(hdr->hdr_entries) * le32toh(hdr->hdr_entsz))); 679 hdr->hdr_crc_self = 0; 680 hdr->hdr_crc_self = htole32(crc32(hdr, le32toh(hdr->hdr_size))); 681 682 if (gpt_write(gpt, map) == -1) { 683 gpt_warn(gpt, "Error writing crc map"); 684 return -1; 685 } 686 687 if (gpt_write(gpt, tbl) == -1) { 688 gpt_warn(gpt, "Error writing crc table"); 689 return -1; 690 } 691 692 return 0; 693 } 694 695 int 696 gpt_write_primary(gpt_t gpt) 697 { 698 return gpt_write_crc(gpt, gpt->gpt, gpt->tbl); 699 } 700 701 702 int 703 gpt_write_backup(gpt_t gpt) 704 { 705 return gpt_write_crc(gpt, gpt->tpg, gpt->lbt); 706 } 707 708 void 709 gpt_create_pmbr_part(struct mbr_part *part, off_t last, int active) 710 { 711 part->part_flag = active ? 0x80 : 0; 712 part->part_shd = 0x00; 713 part->part_ssect = 0x02; 714 part->part_scyl = 0x00; 715 part->part_typ = MBR_PTYPE_PMBR; 716 part->part_ehd = 0xfe; 717 part->part_esect = 0xff; 718 part->part_ecyl = 0xff; 719 part->part_start_lo = htole16(1); 720 if (last > 0xffffffff) { 721 part->part_size_lo = htole16(0xffff); 722 part->part_size_hi = htole16(0xffff); 723 } else { 724 part->part_size_lo = htole16((uint16_t)last); 725 part->part_size_hi = htole16((uint16_t)(last >> 16)); 726 } 727 } 728 729 struct gpt_ent * 730 gpt_ent(map_t map, map_t tbl, unsigned int i) 731 { 732 struct gpt_hdr *hdr = map->map_data; 733 return (void *)((char *)tbl->map_data + i * le32toh(hdr->hdr_entsz)); 734 } 735 736 struct gpt_ent * 737 gpt_ent_primary(gpt_t gpt, unsigned int i) 738 { 739 return gpt_ent(gpt->gpt, gpt->tbl, i); 740 } 741 742 struct gpt_ent * 743 gpt_ent_backup(gpt_t gpt, unsigned int i) 744 { 745 return gpt_ent(gpt->tpg, gpt->lbt, i); 746 } 747 748 int 749 gpt_usage(const char *prefix, const struct gpt_cmd *cmd) 750 { 751 const char **a = cmd->help; 752 size_t hlen = cmd->hlen; 753 size_t i; 754 755 if (prefix == NULL) { 756 const char *pname = getprogname(); 757 const char *d1, *d2, *d = " <device>"; 758 int len = (int)strlen(pname); 759 if (strcmp(pname, "gpt") == 0) { 760 d1 = ""; 761 d2 = d; 762 } else { 763 d2 = ""; 764 d1 = d; 765 } 766 fprintf(stderr, "Usage: %s%s %s %s%s\n", pname, 767 d1, cmd->name, a[0], d2); 768 for (i = 1; i < hlen; i++) { 769 fprintf(stderr, 770 " %*s%s %s %s%s\n", len, "", 771 d1, cmd->name, a[i], d2); 772 } 773 } else { 774 for (i = 0; i < hlen; i++) 775 fprintf(stderr, "%s%s %s\n", prefix, cmd->name, a[i]); 776 } 777 return -1; 778 } 779 780 off_t 781 gpt_last(gpt_t gpt) 782 { 783 return gpt->mediasz / gpt->secsz - 1LL; 784 } 785 786 off_t 787 gpt_create(gpt_t gpt, off_t last, u_int parts, int primary_only) 788 { 789 off_t blocks; 790 map_t map; 791 struct gpt_hdr *hdr; 792 struct gpt_ent *ent; 793 unsigned int i; 794 void *p; 795 796 if (map_find(gpt, MAP_TYPE_PRI_GPT_HDR) != NULL || 797 map_find(gpt, MAP_TYPE_SEC_GPT_HDR) != NULL) { 798 gpt_warnx(gpt, "Device already contains a GPT, " 799 "destroy it first"); 800 return -1; 801 } 802 803 /* Get the amount of free space after the MBR */ 804 blocks = map_free(gpt, 1LL, 0LL); 805 if (blocks == 0LL) { 806 gpt_warnx(gpt, "No room for the GPT header"); 807 return -1; 808 } 809 810 /* Don't create more than parts entries. */ 811 if ((uint64_t)(blocks - 1) * gpt->secsz > 812 parts * sizeof(struct gpt_ent)) { 813 blocks = (off_t)((parts * sizeof(struct gpt_ent)) / gpt->secsz); 814 if ((parts * sizeof(struct gpt_ent)) % gpt->secsz) 815 blocks++; 816 blocks++; /* Don't forget the header itself */ 817 } 818 819 /* Never cross the median of the device. */ 820 if ((blocks + 1LL) > ((last + 1LL) >> 1)) 821 blocks = ((last + 1LL) >> 1) - 1LL; 822 823 /* 824 * Get the amount of free space at the end of the device and 825 * calculate the size for the GPT structures. 826 */ 827 map = map_last(gpt); 828 if (map->map_type != MAP_TYPE_UNUSED) { 829 gpt_warnx(gpt, "No room for the backup header"); 830 return -1; 831 } 832 833 if (map->map_size < blocks) 834 blocks = map->map_size; 835 if (blocks == 1LL) { 836 gpt_warnx(gpt, "No room for the GPT table"); 837 return -1; 838 } 839 840 blocks--; /* Number of blocks in the GPT table. */ 841 842 if (gpt_add_hdr(gpt, MAP_TYPE_PRI_GPT_HDR, 1) == -1) 843 return -1; 844 845 if ((p = calloc((size_t)blocks, gpt->secsz)) == NULL) { 846 gpt_warnx(gpt, "Can't allocate the primary GPT table"); 847 return -1; 848 } 849 if ((gpt->tbl = map_add(gpt, 2LL, blocks, 850 MAP_TYPE_PRI_GPT_TBL, p, 1)) == NULL) { 851 free(p); 852 gpt_warnx(gpt, "Can't add the primary GPT table"); 853 return -1; 854 } 855 856 hdr = gpt->gpt->map_data; 857 memcpy(hdr->hdr_sig, GPT_HDR_SIG, sizeof(hdr->hdr_sig)); 858 859 /* 860 * XXX struct gpt_hdr is not a multiple of 8 bytes in size and thus 861 * contains padding we must not include in the size. 862 */ 863 hdr->hdr_revision = htole32(GPT_HDR_REVISION); 864 hdr->hdr_size = htole32(GPT_HDR_SIZE); 865 hdr->hdr_lba_self = htole64((uint64_t)gpt->gpt->map_start); 866 hdr->hdr_lba_alt = htole64((uint64_t)last); 867 hdr->hdr_lba_start = htole64((uint64_t)(gpt->tbl->map_start + blocks)); 868 hdr->hdr_lba_end = htole64((uint64_t)(last - blocks - 1LL)); 869 if (gpt_uuid_generate(gpt, hdr->hdr_guid) == -1) 870 return -1; 871 hdr->hdr_lba_table = htole64((uint64_t)(gpt->tbl->map_start)); 872 hdr->hdr_entries = htole32((uint32_t)(((uint64_t)blocks * gpt->secsz) / 873 sizeof(struct gpt_ent))); 874 if (le32toh(hdr->hdr_entries) > parts) 875 hdr->hdr_entries = htole32(parts); 876 hdr->hdr_entsz = htole32(sizeof(struct gpt_ent)); 877 878 ent = gpt->tbl->map_data; 879 for (i = 0; i < le32toh(hdr->hdr_entries); i++) { 880 if (gpt_uuid_generate(gpt, ent[i].ent_guid) == -1) 881 return -1; 882 } 883 884 /* 885 * Create backup GPT if the user didn't suppress it. 886 */ 887 if (primary_only) 888 return last; 889 890 if (gpt_add_hdr(gpt, MAP_TYPE_SEC_GPT_HDR, last) == -1) 891 return -1; 892 893 if ((gpt->lbt = map_add(gpt, last - blocks, blocks, 894 MAP_TYPE_SEC_GPT_TBL, gpt->tbl->map_data, 0)) == NULL) { 895 gpt_warnx(gpt, "Can't add the secondary GPT table"); 896 return -1; 897 } 898 899 memcpy(gpt->tpg->map_data, gpt->gpt->map_data, gpt->secsz); 900 901 hdr = gpt->tpg->map_data; 902 hdr->hdr_lba_self = htole64((uint64_t)gpt->tpg->map_start); 903 hdr->hdr_lba_alt = htole64((uint64_t)gpt->gpt->map_start); 904 hdr->hdr_lba_table = htole64((uint64_t)gpt->lbt->map_start); 905 return last; 906 } 907 908 static int 909 gpt_size_get(gpt_t gpt, off_t *size) 910 { 911 off_t sectors; 912 int64_t human_num; 913 char *p; 914 915 if (*size > 0) 916 return -1; 917 sectors = strtoll(optarg, &p, 10); 918 if (sectors < 1) 919 return -1; 920 if (*p == '\0' || ((*p == 's' || *p == 'S') && p[1] == '\0')) { 921 *size = sectors * gpt->secsz; 922 return 0; 923 } 924 if ((*p == 'b' || *p == 'B') && p[1] == '\0') { 925 *size = sectors; 926 return 0; 927 } 928 if (dehumanize_number(optarg, &human_num) < 0) 929 return -1; 930 *size = human_num; 931 return 0; 932 } 933 934 int 935 gpt_human_get(gpt_t gpt, off_t *human) 936 { 937 int64_t human_num; 938 939 if (*human > 0) { 940 gpt_warn(gpt, "Already set to %jd new `%s'", (intmax_t)*human, 941 optarg); 942 return -1; 943 } 944 if (dehumanize_number(optarg, &human_num) < 0) { 945 gpt_warn(gpt, "Bad number `%s'", optarg); 946 return -1; 947 } 948 *human = human_num; 949 if (*human < 1) { 950 gpt_warn(gpt, "Number `%s' < 1", optarg); 951 return -1; 952 } 953 return 0; 954 } 955 956 int 957 gpt_add_find(gpt_t gpt, struct gpt_find *find, int ch) 958 { 959 switch (ch) { 960 case 'a': 961 if (find->all > 0) { 962 gpt_warn(gpt, "-a is already set"); 963 return -1; 964 } 965 find->all = 1; 966 break; 967 case 'b': 968 if (gpt_human_get(gpt, &find->block) == -1) 969 return -1; 970 break; 971 case 'i': 972 if (gpt_uint_get(gpt, &find->entry) == -1) 973 return -1; 974 break; 975 case 'L': 976 if (gpt_name_get(gpt, &find->label) == -1) 977 return -1; 978 break; 979 case 's': 980 if (gpt_size_get(gpt, &find->size) == -1) 981 return -1; 982 break; 983 case 't': 984 if (!gpt_uuid_is_nil(find->type)) 985 return -1; 986 if (gpt_uuid_parse(optarg, find->type) != 0) 987 return -1; 988 break; 989 default: 990 gpt_warn(gpt, "Unknown find option `%c'", ch); 991 return -1; 992 } 993 return 0; 994 } 995 996 int 997 gpt_change_ent(gpt_t gpt, const struct gpt_find *find, 998 void (*cfn)(struct gpt_ent *, void *), void *v) 999 { 1000 map_t m; 1001 struct gpt_hdr *hdr; 1002 struct gpt_ent *ent; 1003 unsigned int i; 1004 uint8_t utfbuf[__arraycount(ent->ent_name) * 3 + 1]; 1005 1006 if (!find->all ^ 1007 (find->block > 0 || find->entry > 0 || find->label != NULL 1008 || find->size > 0 || !gpt_uuid_is_nil(find->type))) 1009 return -1; 1010 1011 if ((hdr = gpt_hdr(gpt)) == NULL) 1012 return -1; 1013 1014 /* Relabel all matching entries in the map. */ 1015 for (m = map_first(gpt); m != NULL; m = m->map_next) { 1016 if (m->map_type != MAP_TYPE_GPT_PART || m->map_index < 1) 1017 continue; 1018 if (find->entry > 0 && find->entry != m->map_index) 1019 continue; 1020 if (find->block > 0 && find->block != m->map_start) 1021 continue; 1022 if (find->size > 0 && find->size != m->map_size) 1023 continue; 1024 1025 i = m->map_index - 1; 1026 1027 ent = gpt_ent_primary(gpt, i); 1028 if (find->label != NULL) { 1029 utf16_to_utf8(ent->ent_name, utfbuf, sizeof(utfbuf)); 1030 if (strcmp((char *)find->label, (char *)utfbuf) == 0) 1031 continue; 1032 } 1033 1034 if (!gpt_uuid_is_nil(find->type) && 1035 !gpt_uuid_equal(find->type, ent->ent_type)) 1036 continue; 1037 1038 /* Change the primary entry. */ 1039 (*cfn)(ent, v); 1040 1041 if (gpt_write_primary(gpt) == -1) 1042 return -1; 1043 1044 ent = gpt_ent_backup(gpt, i); 1045 /* Change the secondary entry. */ 1046 (*cfn)(ent, v); 1047 1048 if (gpt_write_backup(gpt) == -1) 1049 return -1; 1050 1051 gpt_msg(gpt, "Partition %d %s", m->map_index, find->msg); 1052 } 1053 return 0; 1054 } 1055 1056 int 1057 gpt_add_ais(gpt_t gpt, off_t *alignment, u_int *entry, off_t *size, int ch) 1058 { 1059 switch (ch) { 1060 case 'a': 1061 if (gpt_human_get(gpt, alignment) == -1) 1062 return -1; 1063 return 0; 1064 case 'i': 1065 if (gpt_uint_get(gpt, entry) == -1) 1066 return -1; 1067 return 0; 1068 case 's': 1069 if (gpt_size_get(gpt, size) == -1) 1070 return -1; 1071 return 0; 1072 default: 1073 gpt_warn(gpt, "Unknown alignment/index/size option `%c'", ch); 1074 return -1; 1075 } 1076 } 1077 1078 off_t 1079 gpt_check_ais(gpt_t gpt, off_t alignment, u_int entry, off_t size) 1080 { 1081 if (entry == 0) { 1082 gpt_warnx(gpt, "Entry not specified"); 1083 return -1; 1084 } 1085 if (alignment % gpt->secsz != 0) { 1086 gpt_warnx(gpt, "Alignment (%#jx) must be a multiple of " 1087 "sector size (%#x)", (uintmax_t)alignment, gpt->secsz); 1088 return -1; 1089 } 1090 1091 if (size % gpt->secsz != 0) { 1092 gpt_warnx(gpt, "Size (%#jx) must be a multiple of " 1093 "sector size (%#x)", (uintmax_t)size, gpt->secsz); 1094 return -1; 1095 } 1096 if (size > 0) 1097 return size / gpt->secsz; 1098 return 0; 1099 } 1100 1101 static const struct nvd { 1102 const char *name; 1103 uint64_t mask; 1104 const char *description; 1105 } gpt_attr[] = { 1106 { 1107 "biosboot", 1108 GPT_ENT_ATTR_LEGACY_BIOS_BOOTABLE, 1109 "Legacy BIOS boot partition", 1110 }, 1111 { 1112 "bootme", 1113 GPT_ENT_ATTR_BOOTME, 1114 "Bootable partition", 1115 }, 1116 { 1117 "bootfailed", 1118 GPT_ENT_ATTR_BOOTFAILED, 1119 "Partition that marked bootonce failed to boot", 1120 }, 1121 { 1122 "bootonce", 1123 GPT_ENT_ATTR_BOOTONCE, 1124 "Attempt to boot this partition only once", 1125 }, 1126 { 1127 "noblockio", 1128 GPT_ENT_ATTR_NO_BLOCK_IO_PROTOCOL, 1129 "UEFI won't recognize file system for block I/O", 1130 }, 1131 { 1132 "required", 1133 GPT_ENT_ATTR_REQUIRED_PARTITION, 1134 "Partition required for platform to function", 1135 }, 1136 }; 1137 1138 int 1139 gpt_attr_get(gpt_t gpt, uint64_t *attributes) 1140 { 1141 size_t i; 1142 int rv = 0; 1143 char *ptr; 1144 1145 *attributes = 0; 1146 1147 for (ptr = strtok(optarg, ","); ptr; ptr = strtok(NULL, ",")) { 1148 for (i = 0; i < __arraycount(gpt_attr); i++) 1149 if (strcmp(gpt_attr[i].name, ptr) == 0) 1150 break; 1151 if (i == __arraycount(gpt_attr)) { 1152 gpt_warnx(gpt, "Unregognized attribute `%s'", ptr); 1153 rv = -1; 1154 } else 1155 *attributes |= gpt_attr[i].mask; 1156 } 1157 return rv; 1158 } 1159 1160 void 1161 gpt_attr_help(const char *prefix) 1162 { 1163 size_t i; 1164 1165 for (i = 0; i < __arraycount(gpt_attr); i++) 1166 printf("%s%10.10s\t%s\n", prefix, gpt_attr[i].name, 1167 gpt_attr[i].description); 1168 } 1169 1170 const char * 1171 gpt_attr_list(char *buf, size_t len, uint64_t attributes) 1172 { 1173 size_t i; 1174 strlcpy(buf, "", len); 1175 1176 for (i = 0; i < __arraycount(gpt_attr); i++) 1177 if (attributes & gpt_attr[i].mask) { 1178 strlcat(buf, buf[0] ? ", " : "", len); 1179 strlcat(buf, gpt_attr[i].name, len); 1180 } 1181 return buf; 1182 } 1183 1184 int 1185 gpt_attr_update(gpt_t gpt, u_int entry, uint64_t set, uint64_t clr) 1186 { 1187 struct gpt_hdr *hdr; 1188 struct gpt_ent *ent; 1189 unsigned int i; 1190 1191 if (entry == 0 || (set == 0 && clr == 0)) { 1192 gpt_warnx(gpt, "Nothing to set"); 1193 return -1; 1194 } 1195 1196 if ((hdr = gpt_hdr(gpt)) == NULL) 1197 return -1; 1198 1199 if (entry > le32toh(hdr->hdr_entries)) { 1200 gpt_warnx(gpt, "Index %u out of range (%u max)", 1201 entry, le32toh(hdr->hdr_entries)); 1202 return -1; 1203 } 1204 1205 i = entry - 1; 1206 ent = gpt_ent_primary(gpt, i); 1207 if (gpt_uuid_is_nil(ent->ent_type)) { 1208 gpt_warnx(gpt, "Entry at index %u is unused", entry); 1209 return -1; 1210 } 1211 1212 ent->ent_attr &= ~clr; 1213 ent->ent_attr |= set; 1214 1215 if (gpt_write_primary(gpt) == -1) 1216 return -1; 1217 1218 ent = gpt_ent_backup(gpt, i); 1219 ent->ent_attr &= ~clr; 1220 ent->ent_attr |= set; 1221 1222 if (gpt_write_backup(gpt) == -1) 1223 return -1; 1224 gpt_msg(gpt, "Partition %d attributes updated", entry); 1225 return 0; 1226 } 1227 1228 int 1229 gpt_uint_get(gpt_t gpt, u_int *entry) 1230 { 1231 char *p; 1232 if (*entry > 0) 1233 return -1; 1234 *entry = (u_int)strtoul(optarg, &p, 10); 1235 if (*p != 0 || *entry < 1) { 1236 gpt_warn(gpt, "Bad number `%s'", optarg); 1237 return -1; 1238 } 1239 return 0; 1240 } 1241 int 1242 gpt_uuid_get(gpt_t gpt, gpt_uuid_t *uuid) 1243 { 1244 if (!gpt_uuid_is_nil(*uuid)) 1245 return -1; 1246 if (gpt_uuid_parse(optarg, *uuid) != 0) { 1247 gpt_warn(gpt, "Can't parse uuid"); 1248 return -1; 1249 } 1250 return 0; 1251 } 1252 1253 int 1254 gpt_name_get(gpt_t gpt, void *v) 1255 { 1256 char **name = v; 1257 if (*name != NULL) 1258 return -1; 1259 *name = strdup(optarg); 1260 if (*name == NULL) { 1261 gpt_warn(gpt, "Can't copy string"); 1262 return -1; 1263 } 1264 return 0; 1265 } 1266 1267 void 1268 gpt_show_num(const char *prompt, uintmax_t num) 1269 { 1270 #ifdef HN_AUTOSCALE 1271 char human_num[5]; 1272 if (humanize_number(human_num, 5, (int64_t)num , 1273 "", HN_AUTOSCALE, HN_NOSPACE|HN_B) < 0) 1274 human_num[0] = '\0'; 1275 #endif 1276 printf("%s: %ju", prompt, num); 1277 #ifdef HN_AUTOSCALE 1278 if (human_num[0] != '\0') 1279 printf(" (%s)", human_num); 1280 #endif 1281 printf("\n"); 1282 } 1283 1284 int 1285 gpt_add_hdr(gpt_t gpt, int type, off_t loc) 1286 { 1287 void *p; 1288 map_t *t; 1289 const char *msg; 1290 1291 switch (type) { 1292 case MAP_TYPE_PRI_GPT_HDR: 1293 t = &gpt->gpt; 1294 msg = "primary"; 1295 break; 1296 case MAP_TYPE_SEC_GPT_HDR: 1297 t = &gpt->tpg; 1298 msg = "secondary"; 1299 break; 1300 default: 1301 gpt_warnx(gpt, "Unknown GPT header type %d", type); 1302 return -1; 1303 } 1304 1305 if ((p = calloc(1, gpt->secsz)) == NULL) { 1306 gpt_warn(gpt, "Error allocating %s GPT header", msg); 1307 return -1; 1308 } 1309 1310 *t = map_add(gpt, loc, 1LL, type, p, 1); 1311 if (*t == NULL) { 1312 gpt_warn(gpt, "Error adding %s GPT header", msg); 1313 free(p); 1314 return -1; 1315 } 1316 return 0; 1317 } 1318