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.67 2016/01/08 18:59:01 joerg 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 __printflike(2, 0) 596 static void 597 gpt_vwarnx(gpt_t gpt, const char *fmt, va_list ap, const char *e) 598 { 599 if (gpt && (gpt->flags & GPT_QUIET)) 600 return; 601 fprintf(stderr, "%s: ", getprogname()); 602 if (gpt) 603 fprintf(stderr, "%s: ", gpt->device_name); 604 vfprintf(stderr, fmt, ap); 605 if (e) 606 fprintf(stderr, " (%s)\n", e); 607 else 608 fputc('\n', stderr); 609 } 610 611 void 612 gpt_warnx(gpt_t gpt, const char *fmt, ...) 613 { 614 va_list ap; 615 616 va_start(ap, fmt); 617 gpt_vwarnx(gpt, fmt, ap, NULL); 618 va_end(ap); 619 } 620 621 void 622 gpt_warn(gpt_t gpt, const char *fmt, ...) 623 { 624 va_list ap; 625 626 va_start(ap, fmt); 627 gpt_vwarnx(gpt, fmt, ap, strerror(errno)); 628 va_end(ap); 629 } 630 631 void 632 gpt_msg(gpt_t gpt, const char *fmt, ...) 633 { 634 va_list ap; 635 636 if (gpt && (gpt->flags & GPT_QUIET)) 637 return; 638 if (gpt) 639 printf("%s: ", gpt->device_name); 640 va_start(ap, fmt); 641 vprintf(fmt, ap); 642 va_end(ap); 643 printf("\n"); 644 } 645 646 struct gpt_hdr * 647 gpt_hdr(gpt_t gpt) 648 { 649 gpt->gpt = map_find(gpt, MAP_TYPE_PRI_GPT_HDR); 650 if (gpt->gpt == NULL) { 651 gpt_warnx(gpt, "No primary GPT header; run create or recover"); 652 return NULL; 653 } 654 655 gpt->tpg = map_find(gpt, MAP_TYPE_SEC_GPT_HDR); 656 if (gpt->tpg == NULL) { 657 gpt_warnx(gpt, "No secondary GPT header; run recover"); 658 return NULL; 659 } 660 661 gpt->tbl = map_find(gpt, MAP_TYPE_PRI_GPT_TBL); 662 gpt->lbt = map_find(gpt, MAP_TYPE_SEC_GPT_TBL); 663 if (gpt->tbl == NULL || gpt->lbt == NULL) { 664 gpt_warnx(gpt, "Corrupt maps, run recover"); 665 return NULL; 666 } 667 668 return gpt->gpt->map_data; 669 } 670 671 int 672 gpt_write_crc(gpt_t gpt, map_t map, map_t tbl) 673 { 674 struct gpt_hdr *hdr = map->map_data; 675 676 hdr->hdr_crc_table = htole32(crc32(tbl->map_data, 677 le32toh(hdr->hdr_entries) * le32toh(hdr->hdr_entsz))); 678 hdr->hdr_crc_self = 0; 679 hdr->hdr_crc_self = htole32(crc32(hdr, le32toh(hdr->hdr_size))); 680 681 if (gpt_write(gpt, map) == -1) { 682 gpt_warn(gpt, "Error writing crc map"); 683 return -1; 684 } 685 686 if (gpt_write(gpt, tbl) == -1) { 687 gpt_warn(gpt, "Error writing crc table"); 688 return -1; 689 } 690 691 return 0; 692 } 693 694 int 695 gpt_write_primary(gpt_t gpt) 696 { 697 return gpt_write_crc(gpt, gpt->gpt, gpt->tbl); 698 } 699 700 701 int 702 gpt_write_backup(gpt_t gpt) 703 { 704 return gpt_write_crc(gpt, gpt->tpg, gpt->lbt); 705 } 706 707 void 708 gpt_create_pmbr_part(struct mbr_part *part, off_t last) 709 { 710 part->part_shd = 0x00; 711 part->part_ssect = 0x02; 712 part->part_scyl = 0x00; 713 part->part_typ = MBR_PTYPE_PMBR; 714 part->part_ehd = 0xfe; 715 part->part_esect = 0xff; 716 part->part_ecyl = 0xff; 717 part->part_start_lo = htole16(1); 718 if (last > 0xffffffff) { 719 part->part_size_lo = htole16(0xffff); 720 part->part_size_hi = htole16(0xffff); 721 } else { 722 part->part_size_lo = htole16((uint16_t)last); 723 part->part_size_hi = htole16((uint16_t)(last >> 16)); 724 } 725 } 726 727 struct gpt_ent * 728 gpt_ent(map_t map, map_t tbl, unsigned int i) 729 { 730 struct gpt_hdr *hdr = map->map_data; 731 return (void *)((char *)tbl->map_data + i * le32toh(hdr->hdr_entsz)); 732 } 733 734 struct gpt_ent * 735 gpt_ent_primary(gpt_t gpt, unsigned int i) 736 { 737 return gpt_ent(gpt->gpt, gpt->tbl, i); 738 } 739 740 struct gpt_ent * 741 gpt_ent_backup(gpt_t gpt, unsigned int i) 742 { 743 return gpt_ent(gpt->tpg, gpt->lbt, i); 744 } 745 746 int 747 gpt_usage(const char *prefix, const struct gpt_cmd *cmd) 748 { 749 const char **a = cmd->help; 750 size_t hlen = cmd->hlen; 751 size_t i; 752 753 if (prefix == NULL) { 754 const char *pname = getprogname(); 755 const char *d1, *d2, *d = " <device>"; 756 int len = (int)strlen(pname); 757 if (strcmp(pname, "gpt") == 0) { 758 d1 = ""; 759 d2 = d; 760 } else { 761 d2 = ""; 762 d1 = d; 763 } 764 fprintf(stderr, "Usage: %s%s %s %s%s\n", pname, 765 d1, cmd->name, a[0], d2); 766 for (i = 1; i < hlen; i++) { 767 fprintf(stderr, 768 " %*s%s %s %s%s\n", len, "", 769 d1, cmd->name, a[i], d2); 770 } 771 } else { 772 for (i = 0; i < hlen; i++) 773 fprintf(stderr, "%s%s %s\n", prefix, cmd->name, a[i]); 774 } 775 return -1; 776 } 777 778 off_t 779 gpt_last(gpt_t gpt) 780 { 781 return gpt->mediasz / gpt->secsz - 1LL; 782 } 783 784 off_t 785 gpt_create(gpt_t gpt, off_t last, u_int parts, int primary_only) 786 { 787 off_t blocks; 788 map_t map; 789 struct gpt_hdr *hdr; 790 struct gpt_ent *ent; 791 unsigned int i; 792 void *p; 793 794 if (map_find(gpt, MAP_TYPE_PRI_GPT_HDR) != NULL || 795 map_find(gpt, MAP_TYPE_SEC_GPT_HDR) != NULL) { 796 gpt_warnx(gpt, "Device already contains a GPT"); 797 return -1; 798 } 799 800 /* Get the amount of free space after the MBR */ 801 blocks = map_free(gpt, 1LL, 0LL); 802 if (blocks == 0LL) { 803 gpt_warnx(gpt, "No room for the GPT header"); 804 return -1; 805 } 806 807 /* Don't create more than parts entries. */ 808 if ((uint64_t)(blocks - 1) * gpt->secsz > 809 parts * sizeof(struct gpt_ent)) { 810 blocks = (off_t)((parts * sizeof(struct gpt_ent)) / gpt->secsz); 811 if ((parts * sizeof(struct gpt_ent)) % gpt->secsz) 812 blocks++; 813 blocks++; /* Don't forget the header itself */ 814 } 815 816 /* Never cross the median of the device. */ 817 if ((blocks + 1LL) > ((last + 1LL) >> 1)) 818 blocks = ((last + 1LL) >> 1) - 1LL; 819 820 /* 821 * Get the amount of free space at the end of the device and 822 * calculate the size for the GPT structures. 823 */ 824 map = map_last(gpt); 825 if (map->map_type != MAP_TYPE_UNUSED) { 826 gpt_warnx(gpt, "No room for the backup header"); 827 return -1; 828 } 829 830 if (map->map_size < blocks) 831 blocks = map->map_size; 832 if (blocks == 1LL) { 833 gpt_warnx(gpt, "No room for the GPT table"); 834 return -1; 835 } 836 837 blocks--; /* Number of blocks in the GPT table. */ 838 839 if (gpt_add_hdr(gpt, MAP_TYPE_PRI_GPT_HDR, 1) == -1) 840 return -1; 841 842 if ((p = calloc((size_t)blocks, gpt->secsz)) == NULL) { 843 gpt_warnx(gpt, "Can't allocate the primary GPT table"); 844 return -1; 845 } 846 if ((gpt->tbl = map_add(gpt, 2LL, blocks, 847 MAP_TYPE_PRI_GPT_TBL, p, 1)) == NULL) { 848 free(p); 849 gpt_warnx(gpt, "Can't add the primary GPT table"); 850 return -1; 851 } 852 853 hdr = gpt->gpt->map_data; 854 memcpy(hdr->hdr_sig, GPT_HDR_SIG, sizeof(hdr->hdr_sig)); 855 856 /* 857 * XXX struct gpt_hdr is not a multiple of 8 bytes in size and thus 858 * contains padding we must not include in the size. 859 */ 860 hdr->hdr_revision = htole32(GPT_HDR_REVISION); 861 hdr->hdr_size = htole32(GPT_HDR_SIZE); 862 hdr->hdr_lba_self = htole64((uint64_t)gpt->gpt->map_start); 863 hdr->hdr_lba_alt = htole64((uint64_t)last); 864 hdr->hdr_lba_start = htole64((uint64_t)(gpt->tbl->map_start + blocks)); 865 hdr->hdr_lba_end = htole64((uint64_t)(last - blocks - 1LL)); 866 if (gpt_uuid_generate(gpt, hdr->hdr_guid) == -1) 867 return -1; 868 hdr->hdr_lba_table = htole64((uint64_t)(gpt->tbl->map_start)); 869 hdr->hdr_entries = htole32((uint32_t)(((uint64_t)blocks * gpt->secsz) / 870 sizeof(struct gpt_ent))); 871 if (le32toh(hdr->hdr_entries) > parts) 872 hdr->hdr_entries = htole32(parts); 873 hdr->hdr_entsz = htole32(sizeof(struct gpt_ent)); 874 875 ent = gpt->tbl->map_data; 876 for (i = 0; i < le32toh(hdr->hdr_entries); i++) { 877 if (gpt_uuid_generate(gpt, ent[i].ent_guid) == -1) 878 return -1; 879 } 880 881 /* 882 * Create backup GPT if the user didn't suppress it. 883 */ 884 if (primary_only) 885 return last; 886 887 if (gpt_add_hdr(gpt, MAP_TYPE_SEC_GPT_HDR, last) == -1) 888 return -1; 889 890 if ((gpt->lbt = map_add(gpt, last - blocks, blocks, 891 MAP_TYPE_SEC_GPT_TBL, gpt->tbl->map_data, 0)) == NULL) { 892 gpt_warnx(gpt, "Can't add the secondary GPT table"); 893 return -1; 894 } 895 896 memcpy(gpt->tpg->map_data, gpt->gpt->map_data, gpt->secsz); 897 898 hdr = gpt->tpg->map_data; 899 hdr->hdr_lba_self = htole64((uint64_t)gpt->tpg->map_start); 900 hdr->hdr_lba_alt = htole64((uint64_t)gpt->gpt->map_start); 901 hdr->hdr_lba_table = htole64((uint64_t)gpt->lbt->map_start); 902 return last; 903 } 904 905 static int 906 gpt_size_get(gpt_t gpt, off_t *size) 907 { 908 off_t sectors; 909 int64_t human_num; 910 char *p; 911 912 if (*size > 0) 913 return -1; 914 sectors = strtoll(optarg, &p, 10); 915 if (sectors < 1) 916 return -1; 917 if (*p == '\0' || ((*p == 's' || *p == 'S') && p[1] == '\0')) { 918 *size = sectors * gpt->secsz; 919 return 0; 920 } 921 if ((*p == 'b' || *p == 'B') && p[1] == '\0') { 922 *size = sectors; 923 return 0; 924 } 925 if (dehumanize_number(optarg, &human_num) < 0) 926 return -1; 927 *size = human_num; 928 return 0; 929 } 930 931 int 932 gpt_human_get(gpt_t gpt, off_t *human) 933 { 934 int64_t human_num; 935 936 if (*human > 0) { 937 gpt_warn(gpt, "Already set to %jd new `%s'", (intmax_t)*human, 938 optarg); 939 return -1; 940 } 941 if (dehumanize_number(optarg, &human_num) < 0) { 942 gpt_warn(gpt, "Bad number `%s'", optarg); 943 return -1; 944 } 945 *human = human_num; 946 if (*human < 1) { 947 gpt_warn(gpt, "Number `%s' < 1", optarg); 948 return -1; 949 } 950 return 0; 951 } 952 953 int 954 gpt_add_find(gpt_t gpt, struct gpt_find *find, int ch) 955 { 956 switch (ch) { 957 case 'a': 958 if (find->all > 0) { 959 gpt_warn(gpt, "-a is already set"); 960 return -1; 961 } 962 find->all = 1; 963 break; 964 case 'b': 965 if (gpt_human_get(gpt, &find->block) == -1) 966 return -1; 967 break; 968 case 'i': 969 if (gpt_uint_get(gpt, &find->entry) == -1) 970 return -1; 971 break; 972 case 'L': 973 if (gpt_name_get(gpt, &find->label) == -1) 974 return -1; 975 break; 976 case 's': 977 if (gpt_size_get(gpt, &find->size) == -1) 978 return -1; 979 break; 980 case 't': 981 if (!gpt_uuid_is_nil(find->type)) 982 return -1; 983 if (gpt_uuid_parse(optarg, find->type) != 0) 984 return -1; 985 break; 986 default: 987 gpt_warn(gpt, "Unknown find option `%c'", ch); 988 return -1; 989 } 990 return 0; 991 } 992 993 int 994 gpt_change_ent(gpt_t gpt, const struct gpt_find *find, 995 void (*cfn)(struct gpt_ent *, void *), void *v) 996 { 997 map_t m; 998 struct gpt_hdr *hdr; 999 struct gpt_ent *ent; 1000 unsigned int i; 1001 uint8_t utfbuf[__arraycount(ent->ent_name) * 3 + 1]; 1002 1003 if (!find->all ^ 1004 (find->block > 0 || find->entry > 0 || find->label != NULL 1005 || find->size > 0 || !gpt_uuid_is_nil(find->type))) 1006 return -1; 1007 1008 if ((hdr = gpt_hdr(gpt)) == NULL) 1009 return -1; 1010 1011 /* Relabel all matching entries in the map. */ 1012 for (m = map_first(gpt); m != NULL; m = m->map_next) { 1013 if (m->map_type != MAP_TYPE_GPT_PART || m->map_index < 1) 1014 continue; 1015 if (find->entry > 0 && find->entry != m->map_index) 1016 continue; 1017 if (find->block > 0 && find->block != m->map_start) 1018 continue; 1019 if (find->size > 0 && find->size != m->map_size) 1020 continue; 1021 1022 i = m->map_index - 1; 1023 1024 ent = gpt_ent_primary(gpt, i); 1025 if (find->label != NULL) { 1026 utf16_to_utf8(ent->ent_name, utfbuf, sizeof(utfbuf)); 1027 if (strcmp((char *)find->label, (char *)utfbuf) == 0) 1028 continue; 1029 } 1030 1031 if (!gpt_uuid_is_nil(find->type) && 1032 !gpt_uuid_equal(find->type, ent->ent_type)) 1033 continue; 1034 1035 /* Change the primary entry. */ 1036 (*cfn)(ent, v); 1037 1038 if (gpt_write_primary(gpt) == -1) 1039 return -1; 1040 1041 ent = gpt_ent_backup(gpt, i); 1042 /* Change the secondary entry. */ 1043 (*cfn)(ent, v); 1044 1045 if (gpt_write_backup(gpt) == -1) 1046 return -1; 1047 1048 gpt_msg(gpt, "Partition %d %s", m->map_index, find->msg); 1049 } 1050 return 0; 1051 } 1052 1053 int 1054 gpt_add_ais(gpt_t gpt, off_t *alignment, u_int *entry, off_t *size, int ch) 1055 { 1056 switch (ch) { 1057 case 'a': 1058 if (gpt_human_get(gpt, alignment) == -1) 1059 return -1; 1060 return 0; 1061 case 'i': 1062 if (gpt_uint_get(gpt, entry) == -1) 1063 return -1; 1064 return 0; 1065 case 's': 1066 if (gpt_size_get(gpt, size) == -1) 1067 return -1; 1068 return 0; 1069 default: 1070 gpt_warn(gpt, "Unknown alignment/index/size option `%c'", ch); 1071 return -1; 1072 } 1073 } 1074 1075 off_t 1076 gpt_check_ais(gpt_t gpt, off_t alignment, u_int entry, off_t size) 1077 { 1078 if (entry == 0) { 1079 gpt_warnx(gpt, "Entry not specified"); 1080 return -1; 1081 } 1082 if (alignment % gpt->secsz != 0) { 1083 gpt_warnx(gpt, "Alignment (%#jx) must be a multiple of " 1084 "sector size (%#x)", (uintmax_t)alignment, gpt->secsz); 1085 return -1; 1086 } 1087 1088 if (size % gpt->secsz != 0) { 1089 gpt_warnx(gpt, "Size (%#jx) must be a multiple of " 1090 "sector size (%#x)", (uintmax_t)size, gpt->secsz); 1091 return -1; 1092 } 1093 if (size > 0) 1094 return size / gpt->secsz; 1095 return 0; 1096 } 1097 1098 static const struct nvd { 1099 const char *name; 1100 uint64_t mask; 1101 const char *description; 1102 } gpt_attr[] = { 1103 { 1104 "biosboot", 1105 GPT_ENT_ATTR_LEGACY_BIOS_BOOTABLE, 1106 "Legacy BIOS boot partition", 1107 }, 1108 { 1109 "bootme", 1110 GPT_ENT_ATTR_BOOTME, 1111 "Bootable partition", 1112 }, 1113 { 1114 "bootfailed", 1115 GPT_ENT_ATTR_BOOTFAILED, 1116 "Partition that marked bootonce failed to boot", 1117 }, 1118 { 1119 "bootonce", 1120 GPT_ENT_ATTR_BOOTONCE, 1121 "Attempt to boot this partition only once", 1122 }, 1123 { 1124 "noblockio", 1125 GPT_ENT_ATTR_NO_BLOCK_IO_PROTOCOL, 1126 "UEFI won't recognize file system for block I/O", 1127 }, 1128 { 1129 "required", 1130 GPT_ENT_ATTR_REQUIRED_PARTITION, 1131 "Partition required for platform to function", 1132 }, 1133 }; 1134 1135 int 1136 gpt_attr_get(gpt_t gpt, uint64_t *attributes) 1137 { 1138 size_t i; 1139 int rv = 0; 1140 char *ptr; 1141 1142 *attributes = 0; 1143 1144 for (ptr = strtok(optarg, ","); ptr; ptr = strtok(NULL, ",")) { 1145 for (i = 0; i < __arraycount(gpt_attr); i++) 1146 if (strcmp(gpt_attr[i].name, ptr) == 0) 1147 break; 1148 if (i == __arraycount(gpt_attr)) { 1149 gpt_warnx(gpt, "Unregognized attribute `%s'", ptr); 1150 rv = -1; 1151 } else 1152 *attributes |= gpt_attr[i].mask; 1153 } 1154 return rv; 1155 } 1156 1157 void 1158 gpt_attr_help(const char *prefix) 1159 { 1160 size_t i; 1161 1162 for (i = 0; i < __arraycount(gpt_attr); i++) 1163 printf("%s%10.10s\t%s\n", prefix, gpt_attr[i].name, 1164 gpt_attr[i].description); 1165 } 1166 1167 const char * 1168 gpt_attr_list(char *buf, size_t len, uint64_t attributes) 1169 { 1170 size_t i; 1171 strlcpy(buf, "", len); 1172 1173 for (i = 0; i < __arraycount(gpt_attr); i++) 1174 if (attributes & gpt_attr[i].mask) { 1175 strlcat(buf, buf[0] ? ", " : "", len); 1176 strlcat(buf, gpt_attr[i].name, len); 1177 } 1178 return buf; 1179 } 1180 1181 int 1182 gpt_attr_update(gpt_t gpt, u_int entry, uint64_t set, uint64_t clr) 1183 { 1184 struct gpt_hdr *hdr; 1185 struct gpt_ent *ent; 1186 unsigned int i; 1187 1188 if (entry == 0 || (set == 0 && clr == 0)) { 1189 gpt_warnx(gpt, "Nothing to set"); 1190 return -1; 1191 } 1192 1193 if ((hdr = gpt_hdr(gpt)) == NULL) 1194 return -1; 1195 1196 if (entry > le32toh(hdr->hdr_entries)) { 1197 gpt_warnx(gpt, "Index %u out of range (%u max)", 1198 entry, le32toh(hdr->hdr_entries)); 1199 return -1; 1200 } 1201 1202 i = entry - 1; 1203 ent = gpt_ent_primary(gpt, i); 1204 if (gpt_uuid_is_nil(ent->ent_type)) { 1205 gpt_warnx(gpt, "Entry at index %u is unused", entry); 1206 return -1; 1207 } 1208 1209 ent->ent_attr &= ~clr; 1210 ent->ent_attr |= set; 1211 1212 if (gpt_write_primary(gpt) == -1) 1213 return -1; 1214 1215 ent = gpt_ent_backup(gpt, i); 1216 ent->ent_attr &= ~clr; 1217 ent->ent_attr |= set; 1218 1219 if (gpt_write_backup(gpt) == -1) 1220 return -1; 1221 gpt_msg(gpt, "Partition %d attributes updated", entry); 1222 return 0; 1223 } 1224 1225 int 1226 gpt_uint_get(gpt_t gpt, u_int *entry) 1227 { 1228 char *p; 1229 if (*entry > 0) 1230 return -1; 1231 *entry = (u_int)strtoul(optarg, &p, 10); 1232 if (*p != 0 || *entry < 1) { 1233 gpt_warn(gpt, "Bad number `%s'", optarg); 1234 return -1; 1235 } 1236 return 0; 1237 } 1238 int 1239 gpt_uuid_get(gpt_t gpt, gpt_uuid_t *uuid) 1240 { 1241 if (!gpt_uuid_is_nil(*uuid)) 1242 return -1; 1243 if (gpt_uuid_parse(optarg, *uuid) != 0) { 1244 gpt_warn(gpt, "Can't parse uuid"); 1245 return -1; 1246 } 1247 return 0; 1248 } 1249 1250 int 1251 gpt_name_get(gpt_t gpt, void *v) 1252 { 1253 char **name = v; 1254 if (*name != NULL) 1255 return -1; 1256 *name = strdup(optarg); 1257 if (*name == NULL) { 1258 gpt_warn(gpt, "Can't copy string"); 1259 return -1; 1260 } 1261 return 0; 1262 } 1263 1264 void 1265 gpt_show_num(const char *prompt, uintmax_t num) 1266 { 1267 #ifdef HN_AUTOSCALE 1268 char human_num[5]; 1269 if (humanize_number(human_num, 5, (int64_t)num , 1270 "", HN_AUTOSCALE, HN_NOSPACE|HN_B) < 0) 1271 human_num[0] = '\0'; 1272 #endif 1273 printf("%s: %ju", prompt, num); 1274 #ifdef HN_AUTOSCALE 1275 if (human_num[0] != '\0') 1276 printf(" (%s)", human_num); 1277 #endif 1278 printf("\n"); 1279 } 1280 1281 int 1282 gpt_add_hdr(gpt_t gpt, int type, off_t loc) 1283 { 1284 void *p; 1285 map_t *t; 1286 const char *msg; 1287 1288 switch (type) { 1289 case MAP_TYPE_PRI_GPT_HDR: 1290 t = &gpt->gpt; 1291 msg = "primary"; 1292 break; 1293 case MAP_TYPE_SEC_GPT_HDR: 1294 t = &gpt->tpg; 1295 msg = "secondary"; 1296 break; 1297 default: 1298 gpt_warnx(gpt, "Unknown GPT header type %d", type); 1299 return -1; 1300 } 1301 1302 if ((p = calloc(1, gpt->secsz)) == NULL) { 1303 gpt_warn(gpt, "Error allocating %s GPT header", msg); 1304 return -1; 1305 } 1306 1307 *t = map_add(gpt, loc, 1LL, type, p, 1); 1308 if (*t == NULL) { 1309 gpt_warn(gpt, "Error adding %s GPT header", msg); 1310 free(p); 1311 return -1; 1312 } 1313 return 0; 1314 } 1315