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