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.68 2016/06/09 15:12:54 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 return -1; 800 } 801 802 /* Get the amount of free space after the MBR */ 803 blocks = map_free(gpt, 1LL, 0LL); 804 if (blocks == 0LL) { 805 gpt_warnx(gpt, "No room for the GPT header"); 806 return -1; 807 } 808 809 /* Don't create more than parts entries. */ 810 if ((uint64_t)(blocks - 1) * gpt->secsz > 811 parts * sizeof(struct gpt_ent)) { 812 blocks = (off_t)((parts * sizeof(struct gpt_ent)) / gpt->secsz); 813 if ((parts * sizeof(struct gpt_ent)) % gpt->secsz) 814 blocks++; 815 blocks++; /* Don't forget the header itself */ 816 } 817 818 /* Never cross the median of the device. */ 819 if ((blocks + 1LL) > ((last + 1LL) >> 1)) 820 blocks = ((last + 1LL) >> 1) - 1LL; 821 822 /* 823 * Get the amount of free space at the end of the device and 824 * calculate the size for the GPT structures. 825 */ 826 map = map_last(gpt); 827 if (map->map_type != MAP_TYPE_UNUSED) { 828 gpt_warnx(gpt, "No room for the backup header"); 829 return -1; 830 } 831 832 if (map->map_size < blocks) 833 blocks = map->map_size; 834 if (blocks == 1LL) { 835 gpt_warnx(gpt, "No room for the GPT table"); 836 return -1; 837 } 838 839 blocks--; /* Number of blocks in the GPT table. */ 840 841 if (gpt_add_hdr(gpt, MAP_TYPE_PRI_GPT_HDR, 1) == -1) 842 return -1; 843 844 if ((p = calloc((size_t)blocks, gpt->secsz)) == NULL) { 845 gpt_warnx(gpt, "Can't allocate the primary GPT table"); 846 return -1; 847 } 848 if ((gpt->tbl = map_add(gpt, 2LL, blocks, 849 MAP_TYPE_PRI_GPT_TBL, p, 1)) == NULL) { 850 free(p); 851 gpt_warnx(gpt, "Can't add the primary GPT table"); 852 return -1; 853 } 854 855 hdr = gpt->gpt->map_data; 856 memcpy(hdr->hdr_sig, GPT_HDR_SIG, sizeof(hdr->hdr_sig)); 857 858 /* 859 * XXX struct gpt_hdr is not a multiple of 8 bytes in size and thus 860 * contains padding we must not include in the size. 861 */ 862 hdr->hdr_revision = htole32(GPT_HDR_REVISION); 863 hdr->hdr_size = htole32(GPT_HDR_SIZE); 864 hdr->hdr_lba_self = htole64((uint64_t)gpt->gpt->map_start); 865 hdr->hdr_lba_alt = htole64((uint64_t)last); 866 hdr->hdr_lba_start = htole64((uint64_t)(gpt->tbl->map_start + blocks)); 867 hdr->hdr_lba_end = htole64((uint64_t)(last - blocks - 1LL)); 868 if (gpt_uuid_generate(gpt, hdr->hdr_guid) == -1) 869 return -1; 870 hdr->hdr_lba_table = htole64((uint64_t)(gpt->tbl->map_start)); 871 hdr->hdr_entries = htole32((uint32_t)(((uint64_t)blocks * gpt->secsz) / 872 sizeof(struct gpt_ent))); 873 if (le32toh(hdr->hdr_entries) > parts) 874 hdr->hdr_entries = htole32(parts); 875 hdr->hdr_entsz = htole32(sizeof(struct gpt_ent)); 876 877 ent = gpt->tbl->map_data; 878 for (i = 0; i < le32toh(hdr->hdr_entries); i++) { 879 if (gpt_uuid_generate(gpt, ent[i].ent_guid) == -1) 880 return -1; 881 } 882 883 /* 884 * Create backup GPT if the user didn't suppress it. 885 */ 886 if (primary_only) 887 return last; 888 889 if (gpt_add_hdr(gpt, MAP_TYPE_SEC_GPT_HDR, last) == -1) 890 return -1; 891 892 if ((gpt->lbt = map_add(gpt, last - blocks, blocks, 893 MAP_TYPE_SEC_GPT_TBL, gpt->tbl->map_data, 0)) == NULL) { 894 gpt_warnx(gpt, "Can't add the secondary GPT table"); 895 return -1; 896 } 897 898 memcpy(gpt->tpg->map_data, gpt->gpt->map_data, gpt->secsz); 899 900 hdr = gpt->tpg->map_data; 901 hdr->hdr_lba_self = htole64((uint64_t)gpt->tpg->map_start); 902 hdr->hdr_lba_alt = htole64((uint64_t)gpt->gpt->map_start); 903 hdr->hdr_lba_table = htole64((uint64_t)gpt->lbt->map_start); 904 return last; 905 } 906 907 static int 908 gpt_size_get(gpt_t gpt, off_t *size) 909 { 910 off_t sectors; 911 int64_t human_num; 912 char *p; 913 914 if (*size > 0) 915 return -1; 916 sectors = strtoll(optarg, &p, 10); 917 if (sectors < 1) 918 return -1; 919 if (*p == '\0' || ((*p == 's' || *p == 'S') && p[1] == '\0')) { 920 *size = sectors * gpt->secsz; 921 return 0; 922 } 923 if ((*p == 'b' || *p == 'B') && p[1] == '\0') { 924 *size = sectors; 925 return 0; 926 } 927 if (dehumanize_number(optarg, &human_num) < 0) 928 return -1; 929 *size = human_num; 930 return 0; 931 } 932 933 int 934 gpt_human_get(gpt_t gpt, off_t *human) 935 { 936 int64_t human_num; 937 938 if (*human > 0) { 939 gpt_warn(gpt, "Already set to %jd new `%s'", (intmax_t)*human, 940 optarg); 941 return -1; 942 } 943 if (dehumanize_number(optarg, &human_num) < 0) { 944 gpt_warn(gpt, "Bad number `%s'", optarg); 945 return -1; 946 } 947 *human = human_num; 948 if (*human < 1) { 949 gpt_warn(gpt, "Number `%s' < 1", optarg); 950 return -1; 951 } 952 return 0; 953 } 954 955 int 956 gpt_add_find(gpt_t gpt, struct gpt_find *find, int ch) 957 { 958 switch (ch) { 959 case 'a': 960 if (find->all > 0) { 961 gpt_warn(gpt, "-a is already set"); 962 return -1; 963 } 964 find->all = 1; 965 break; 966 case 'b': 967 if (gpt_human_get(gpt, &find->block) == -1) 968 return -1; 969 break; 970 case 'i': 971 if (gpt_uint_get(gpt, &find->entry) == -1) 972 return -1; 973 break; 974 case 'L': 975 if (gpt_name_get(gpt, &find->label) == -1) 976 return -1; 977 break; 978 case 's': 979 if (gpt_size_get(gpt, &find->size) == -1) 980 return -1; 981 break; 982 case 't': 983 if (!gpt_uuid_is_nil(find->type)) 984 return -1; 985 if (gpt_uuid_parse(optarg, find->type) != 0) 986 return -1; 987 break; 988 default: 989 gpt_warn(gpt, "Unknown find option `%c'", ch); 990 return -1; 991 } 992 return 0; 993 } 994 995 int 996 gpt_change_ent(gpt_t gpt, const struct gpt_find *find, 997 void (*cfn)(struct gpt_ent *, void *), void *v) 998 { 999 map_t m; 1000 struct gpt_hdr *hdr; 1001 struct gpt_ent *ent; 1002 unsigned int i; 1003 uint8_t utfbuf[__arraycount(ent->ent_name) * 3 + 1]; 1004 1005 if (!find->all ^ 1006 (find->block > 0 || find->entry > 0 || find->label != NULL 1007 || find->size > 0 || !gpt_uuid_is_nil(find->type))) 1008 return -1; 1009 1010 if ((hdr = gpt_hdr(gpt)) == NULL) 1011 return -1; 1012 1013 /* Relabel all matching entries in the map. */ 1014 for (m = map_first(gpt); m != NULL; m = m->map_next) { 1015 if (m->map_type != MAP_TYPE_GPT_PART || m->map_index < 1) 1016 continue; 1017 if (find->entry > 0 && find->entry != m->map_index) 1018 continue; 1019 if (find->block > 0 && find->block != m->map_start) 1020 continue; 1021 if (find->size > 0 && find->size != m->map_size) 1022 continue; 1023 1024 i = m->map_index - 1; 1025 1026 ent = gpt_ent_primary(gpt, i); 1027 if (find->label != NULL) { 1028 utf16_to_utf8(ent->ent_name, utfbuf, sizeof(utfbuf)); 1029 if (strcmp((char *)find->label, (char *)utfbuf) == 0) 1030 continue; 1031 } 1032 1033 if (!gpt_uuid_is_nil(find->type) && 1034 !gpt_uuid_equal(find->type, ent->ent_type)) 1035 continue; 1036 1037 /* Change the primary entry. */ 1038 (*cfn)(ent, v); 1039 1040 if (gpt_write_primary(gpt) == -1) 1041 return -1; 1042 1043 ent = gpt_ent_backup(gpt, i); 1044 /* Change the secondary entry. */ 1045 (*cfn)(ent, v); 1046 1047 if (gpt_write_backup(gpt) == -1) 1048 return -1; 1049 1050 gpt_msg(gpt, "Partition %d %s", m->map_index, find->msg); 1051 } 1052 return 0; 1053 } 1054 1055 int 1056 gpt_add_ais(gpt_t gpt, off_t *alignment, u_int *entry, off_t *size, int ch) 1057 { 1058 switch (ch) { 1059 case 'a': 1060 if (gpt_human_get(gpt, alignment) == -1) 1061 return -1; 1062 return 0; 1063 case 'i': 1064 if (gpt_uint_get(gpt, entry) == -1) 1065 return -1; 1066 return 0; 1067 case 's': 1068 if (gpt_size_get(gpt, size) == -1) 1069 return -1; 1070 return 0; 1071 default: 1072 gpt_warn(gpt, "Unknown alignment/index/size option `%c'", ch); 1073 return -1; 1074 } 1075 } 1076 1077 off_t 1078 gpt_check_ais(gpt_t gpt, off_t alignment, u_int entry, off_t size) 1079 { 1080 if (entry == 0) { 1081 gpt_warnx(gpt, "Entry not specified"); 1082 return -1; 1083 } 1084 if (alignment % gpt->secsz != 0) { 1085 gpt_warnx(gpt, "Alignment (%#jx) must be a multiple of " 1086 "sector size (%#x)", (uintmax_t)alignment, gpt->secsz); 1087 return -1; 1088 } 1089 1090 if (size % gpt->secsz != 0) { 1091 gpt_warnx(gpt, "Size (%#jx) must be a multiple of " 1092 "sector size (%#x)", (uintmax_t)size, gpt->secsz); 1093 return -1; 1094 } 1095 if (size > 0) 1096 return size / gpt->secsz; 1097 return 0; 1098 } 1099 1100 static const struct nvd { 1101 const char *name; 1102 uint64_t mask; 1103 const char *description; 1104 } gpt_attr[] = { 1105 { 1106 "biosboot", 1107 GPT_ENT_ATTR_LEGACY_BIOS_BOOTABLE, 1108 "Legacy BIOS boot partition", 1109 }, 1110 { 1111 "bootme", 1112 GPT_ENT_ATTR_BOOTME, 1113 "Bootable partition", 1114 }, 1115 { 1116 "bootfailed", 1117 GPT_ENT_ATTR_BOOTFAILED, 1118 "Partition that marked bootonce failed to boot", 1119 }, 1120 { 1121 "bootonce", 1122 GPT_ENT_ATTR_BOOTONCE, 1123 "Attempt to boot this partition only once", 1124 }, 1125 { 1126 "noblockio", 1127 GPT_ENT_ATTR_NO_BLOCK_IO_PROTOCOL, 1128 "UEFI won't recognize file system for block I/O", 1129 }, 1130 { 1131 "required", 1132 GPT_ENT_ATTR_REQUIRED_PARTITION, 1133 "Partition required for platform to function", 1134 }, 1135 }; 1136 1137 int 1138 gpt_attr_get(gpt_t gpt, uint64_t *attributes) 1139 { 1140 size_t i; 1141 int rv = 0; 1142 char *ptr; 1143 1144 *attributes = 0; 1145 1146 for (ptr = strtok(optarg, ","); ptr; ptr = strtok(NULL, ",")) { 1147 for (i = 0; i < __arraycount(gpt_attr); i++) 1148 if (strcmp(gpt_attr[i].name, ptr) == 0) 1149 break; 1150 if (i == __arraycount(gpt_attr)) { 1151 gpt_warnx(gpt, "Unregognized attribute `%s'", ptr); 1152 rv = -1; 1153 } else 1154 *attributes |= gpt_attr[i].mask; 1155 } 1156 return rv; 1157 } 1158 1159 void 1160 gpt_attr_help(const char *prefix) 1161 { 1162 size_t i; 1163 1164 for (i = 0; i < __arraycount(gpt_attr); i++) 1165 printf("%s%10.10s\t%s\n", prefix, gpt_attr[i].name, 1166 gpt_attr[i].description); 1167 } 1168 1169 const char * 1170 gpt_attr_list(char *buf, size_t len, uint64_t attributes) 1171 { 1172 size_t i; 1173 strlcpy(buf, "", len); 1174 1175 for (i = 0; i < __arraycount(gpt_attr); i++) 1176 if (attributes & gpt_attr[i].mask) { 1177 strlcat(buf, buf[0] ? ", " : "", len); 1178 strlcat(buf, gpt_attr[i].name, len); 1179 } 1180 return buf; 1181 } 1182 1183 int 1184 gpt_attr_update(gpt_t gpt, u_int entry, uint64_t set, uint64_t clr) 1185 { 1186 struct gpt_hdr *hdr; 1187 struct gpt_ent *ent; 1188 unsigned int i; 1189 1190 if (entry == 0 || (set == 0 && clr == 0)) { 1191 gpt_warnx(gpt, "Nothing to set"); 1192 return -1; 1193 } 1194 1195 if ((hdr = gpt_hdr(gpt)) == NULL) 1196 return -1; 1197 1198 if (entry > le32toh(hdr->hdr_entries)) { 1199 gpt_warnx(gpt, "Index %u out of range (%u max)", 1200 entry, le32toh(hdr->hdr_entries)); 1201 return -1; 1202 } 1203 1204 i = entry - 1; 1205 ent = gpt_ent_primary(gpt, i); 1206 if (gpt_uuid_is_nil(ent->ent_type)) { 1207 gpt_warnx(gpt, "Entry at index %u is unused", entry); 1208 return -1; 1209 } 1210 1211 ent->ent_attr &= ~clr; 1212 ent->ent_attr |= set; 1213 1214 if (gpt_write_primary(gpt) == -1) 1215 return -1; 1216 1217 ent = gpt_ent_backup(gpt, i); 1218 ent->ent_attr &= ~clr; 1219 ent->ent_attr |= set; 1220 1221 if (gpt_write_backup(gpt) == -1) 1222 return -1; 1223 gpt_msg(gpt, "Partition %d attributes updated", entry); 1224 return 0; 1225 } 1226 1227 int 1228 gpt_uint_get(gpt_t gpt, u_int *entry) 1229 { 1230 char *p; 1231 if (*entry > 0) 1232 return -1; 1233 *entry = (u_int)strtoul(optarg, &p, 10); 1234 if (*p != 0 || *entry < 1) { 1235 gpt_warn(gpt, "Bad number `%s'", optarg); 1236 return -1; 1237 } 1238 return 0; 1239 } 1240 int 1241 gpt_uuid_get(gpt_t gpt, gpt_uuid_t *uuid) 1242 { 1243 if (!gpt_uuid_is_nil(*uuid)) 1244 return -1; 1245 if (gpt_uuid_parse(optarg, *uuid) != 0) { 1246 gpt_warn(gpt, "Can't parse uuid"); 1247 return -1; 1248 } 1249 return 0; 1250 } 1251 1252 int 1253 gpt_name_get(gpt_t gpt, void *v) 1254 { 1255 char **name = v; 1256 if (*name != NULL) 1257 return -1; 1258 *name = strdup(optarg); 1259 if (*name == NULL) { 1260 gpt_warn(gpt, "Can't copy string"); 1261 return -1; 1262 } 1263 return 0; 1264 } 1265 1266 void 1267 gpt_show_num(const char *prompt, uintmax_t num) 1268 { 1269 #ifdef HN_AUTOSCALE 1270 char human_num[5]; 1271 if (humanize_number(human_num, 5, (int64_t)num , 1272 "", HN_AUTOSCALE, HN_NOSPACE|HN_B) < 0) 1273 human_num[0] = '\0'; 1274 #endif 1275 printf("%s: %ju", prompt, num); 1276 #ifdef HN_AUTOSCALE 1277 if (human_num[0] != '\0') 1278 printf(" (%s)", human_num); 1279 #endif 1280 printf("\n"); 1281 } 1282 1283 int 1284 gpt_add_hdr(gpt_t gpt, int type, off_t loc) 1285 { 1286 void *p; 1287 map_t *t; 1288 const char *msg; 1289 1290 switch (type) { 1291 case MAP_TYPE_PRI_GPT_HDR: 1292 t = &gpt->gpt; 1293 msg = "primary"; 1294 break; 1295 case MAP_TYPE_SEC_GPT_HDR: 1296 t = &gpt->tpg; 1297 msg = "secondary"; 1298 break; 1299 default: 1300 gpt_warnx(gpt, "Unknown GPT header type %d", type); 1301 return -1; 1302 } 1303 1304 if ((p = calloc(1, gpt->secsz)) == NULL) { 1305 gpt_warn(gpt, "Error allocating %s GPT header", msg); 1306 return -1; 1307 } 1308 1309 *t = map_add(gpt, loc, 1LL, type, p, 1); 1310 if (*t == NULL) { 1311 gpt_warn(gpt, "Error adding %s GPT header", msg); 1312 free(p); 1313 return -1; 1314 } 1315 return 0; 1316 } 1317