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