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