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.81 2019/10/11 23:04:52 christos Exp $"); 39 #endif 40 41 #include <sys/param.h> 42 #include <sys/types.h> 43 #include <sys/stat.h> 44 #include <sys/ioctl.h> 45 #include <sys/bootblock.h> 46 47 #include <err.h> 48 #include <errno.h> 49 #include <fcntl.h> 50 #include <paths.h> 51 #include <stddef.h> 52 #include <stdarg.h> 53 #include <stdio.h> 54 #include <stdlib.h> 55 #include <string.h> 56 #include <unistd.h> 57 #include <ctype.h> 58 59 #include "map.h" 60 #include "gpt.h" 61 #include "gpt_private.h" 62 63 static uint32_t crc32_tab[] = { 64 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 65 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 66 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, 67 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 68 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 69 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 70 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, 71 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 72 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 73 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 74 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, 75 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, 76 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 77 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 78 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, 79 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 80 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 81 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 82 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 83 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, 84 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 85 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 86 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, 87 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 88 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 89 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 90 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, 91 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 92 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 93 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 94 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, 95 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 96 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 97 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 98 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, 99 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, 100 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 101 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 102 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 103 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, 104 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 105 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 106 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d 107 }; 108 109 uint32_t 110 crc32(const void *buf, size_t size) 111 { 112 const uint8_t *p; 113 uint32_t crc; 114 115 p = buf; 116 crc = ~0U; 117 118 while (size--) 119 crc = crc32_tab[(crc ^ *p++) & 0xFF] ^ (crc >> 8); 120 121 return crc ^ ~0U; 122 } 123 124 /* 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 == NULL) 594 return; 595 596 if (!(gpt->flags & GPT_MODIFIED) || !(gpt->flags & GPT_SYNC)) 597 goto out; 598 599 if (!(gpt->flags & GPT_NOSYNC)) { 600 #ifdef DIOCMWEDGES 601 int bits; 602 if (ioctl(gpt->fd, DIOCMWEDGES, &bits) == -1) 603 gpt_warn(gpt, "Can't update wedge information"); 604 else 605 goto out; 606 #endif 607 } 608 if (!(gpt->flags & GPT_FILE)) 609 gpt_msg(gpt, "You need to run \"dkctl %s makewedges\"" 610 " for the changes to take effect\n", gpt->device_name); 611 612 out: 613 close(gpt->fd); 614 } 615 616 __printflike(2, 0) 617 static void 618 gpt_vwarnx(gpt_t gpt, const char *fmt, va_list ap, const char *e) 619 { 620 if (gpt && (gpt->flags & GPT_QUIET)) 621 return; 622 fprintf(stderr, "%s: ", getprogname()); 623 if (gpt) 624 fprintf(stderr, "%s: ", gpt->device_name); 625 vfprintf(stderr, fmt, ap); 626 if (e) 627 fprintf(stderr, " (%s)\n", e); 628 else 629 fputc('\n', stderr); 630 } 631 632 void 633 gpt_warnx(gpt_t gpt, const char *fmt, ...) 634 { 635 va_list ap; 636 637 va_start(ap, fmt); 638 gpt_vwarnx(gpt, fmt, ap, NULL); 639 va_end(ap); 640 } 641 642 void 643 gpt_warn(gpt_t gpt, const char *fmt, ...) 644 { 645 va_list ap; 646 647 va_start(ap, fmt); 648 gpt_vwarnx(gpt, fmt, ap, strerror(errno)); 649 va_end(ap); 650 } 651 652 void 653 gpt_msg(gpt_t gpt, const char *fmt, ...) 654 { 655 va_list ap; 656 657 if (gpt && (gpt->flags & GPT_QUIET)) 658 return; 659 if (gpt) 660 printf("%s: ", gpt->device_name); 661 va_start(ap, fmt); 662 vprintf(fmt, ap); 663 va_end(ap); 664 printf("\n"); 665 } 666 667 struct gpt_hdr * 668 gpt_hdr(gpt_t gpt) 669 { 670 gpt->gpt = map_find(gpt, MAP_TYPE_PRI_GPT_HDR); 671 if (gpt->gpt == NULL) { 672 gpt_warnx(gpt, "No primary GPT header; run create or recover"); 673 return NULL; 674 } 675 676 gpt->tpg = map_find(gpt, MAP_TYPE_SEC_GPT_HDR); 677 if (gpt->tpg == NULL) { 678 gpt_warnx(gpt, "No secondary GPT header; run recover"); 679 return NULL; 680 } 681 682 gpt->tbl = map_find(gpt, MAP_TYPE_PRI_GPT_TBL); 683 gpt->lbt = map_find(gpt, MAP_TYPE_SEC_GPT_TBL); 684 if (gpt->tbl == NULL || gpt->lbt == NULL) { 685 gpt_warnx(gpt, "Corrupt maps, run recover"); 686 return NULL; 687 } 688 689 return gpt->gpt->map_data; 690 } 691 692 int 693 gpt_write_crc(gpt_t gpt, map_t map, map_t tbl) 694 { 695 struct gpt_hdr *hdr = map->map_data; 696 697 hdr->hdr_crc_table = htole32(crc32(tbl->map_data, 698 le32toh(hdr->hdr_entries) * le32toh(hdr->hdr_entsz))); 699 hdr->hdr_crc_self = 0; 700 hdr->hdr_crc_self = htole32(crc32(hdr, le32toh(hdr->hdr_size))); 701 702 if (gpt_write(gpt, map) == -1) { 703 gpt_warn(gpt, "Error writing crc map"); 704 return -1; 705 } 706 707 if (gpt_write(gpt, tbl) == -1) { 708 gpt_warn(gpt, "Error writing crc table"); 709 return -1; 710 } 711 712 return 0; 713 } 714 715 int 716 gpt_write_primary(gpt_t gpt) 717 { 718 return gpt_write_crc(gpt, gpt->gpt, gpt->tbl); 719 } 720 721 722 int 723 gpt_write_backup(gpt_t gpt) 724 { 725 return gpt_write_crc(gpt, gpt->tpg, gpt->lbt); 726 } 727 728 void 729 gpt_create_pmbr_part(struct mbr_part *part, off_t last, int active) 730 { 731 part->part_flag = active ? 0x80 : 0; 732 part->part_shd = 0x00; 733 part->part_ssect = 0x02; 734 part->part_scyl = 0x00; 735 part->part_typ = MBR_PTYPE_PMBR; 736 part->part_ehd = 0xfe; 737 part->part_esect = 0xff; 738 part->part_ecyl = 0xff; 739 part->part_start_lo = htole16(1); 740 if (last > 0xffffffff) { 741 part->part_size_lo = htole16(0xffff); 742 part->part_size_hi = htole16(0xffff); 743 } else { 744 part->part_size_lo = htole16((uint16_t)last); 745 part->part_size_hi = htole16((uint16_t)(last >> 16)); 746 } 747 } 748 749 struct gpt_ent * 750 gpt_ent(map_t map, map_t tbl, unsigned int i) 751 { 752 struct gpt_hdr *hdr = map->map_data; 753 return (void *)((char *)tbl->map_data + i * le32toh(hdr->hdr_entsz)); 754 } 755 756 struct gpt_ent * 757 gpt_ent_primary(gpt_t gpt, unsigned int i) 758 { 759 return gpt_ent(gpt->gpt, gpt->tbl, i); 760 } 761 762 struct gpt_ent * 763 gpt_ent_backup(gpt_t gpt, unsigned int i) 764 { 765 return gpt_ent(gpt->tpg, gpt->lbt, i); 766 } 767 768 int 769 gpt_usage(const char *prefix, const struct gpt_cmd *cmd) 770 { 771 const char **a = cmd->help; 772 size_t hlen = cmd->hlen; 773 size_t i; 774 775 if (prefix == NULL) { 776 const char *pname = getprogname(); 777 const char *d1, *d2, *d = " <device>"; 778 int len = (int)strlen(pname); 779 if (strcmp(pname, "gpt") == 0) { 780 d1 = ""; 781 d2 = d; 782 } else { 783 d2 = ""; 784 d1 = d; 785 } 786 fprintf(stderr, "Usage: %s%s %s %s%s\n", pname, 787 d1, cmd->name, a[0], d2); 788 for (i = 1; i < hlen; i++) { 789 fprintf(stderr, 790 " %*s%s %s %s%s\n", len, "", 791 d1, cmd->name, a[i], d2); 792 } 793 } else { 794 for (i = 0; i < hlen; i++) 795 fprintf(stderr, "%s%s %s\n", prefix, cmd->name, a[i]); 796 } 797 return -1; 798 } 799 800 off_t 801 gpt_last(gpt_t gpt) 802 { 803 return gpt->mediasz / gpt->secsz - 1LL; 804 } 805 806 off_t 807 gpt_create(gpt_t gpt, off_t last, u_int parts, int primary_only) 808 { 809 off_t blocks; 810 map_t map; 811 struct gpt_hdr *hdr; 812 struct gpt_ent *ent; 813 unsigned int i; 814 void *p; 815 816 if (map_find(gpt, MAP_TYPE_PRI_GPT_HDR) != NULL || 817 map_find(gpt, MAP_TYPE_SEC_GPT_HDR) != NULL) { 818 gpt_warnx(gpt, "Device already contains a GPT, " 819 "destroy it first"); 820 return -1; 821 } 822 823 /* Get the amount of free space after the MBR */ 824 blocks = map_free(gpt, 1LL, 0LL); 825 if (blocks == 0LL) { 826 gpt_warnx(gpt, "No room for the GPT header"); 827 return -1; 828 } 829 830 /* Don't create more than parts entries. */ 831 if ((uint64_t)(blocks - 1) * gpt->secsz > 832 parts * sizeof(struct gpt_ent)) { 833 blocks = (off_t)((parts * sizeof(struct gpt_ent)) / gpt->secsz); 834 if ((parts * sizeof(struct gpt_ent)) % gpt->secsz) 835 blocks++; 836 blocks++; /* Don't forget the header itself */ 837 } 838 839 /* Never cross the median of the device. */ 840 if ((blocks + 1LL) > ((last + 1LL) >> 1)) 841 blocks = ((last + 1LL) >> 1) - 1LL; 842 843 /* 844 * Get the amount of free space at the end of the device and 845 * calculate the size for the GPT structures. 846 */ 847 map = map_last(gpt); 848 if (map->map_type != MAP_TYPE_UNUSED) { 849 gpt_warnx(gpt, "No room for the backup header"); 850 return -1; 851 } 852 853 if (map->map_size < blocks) 854 blocks = map->map_size; 855 if (blocks == 1LL) { 856 gpt_warnx(gpt, "No room for the GPT table"); 857 return -1; 858 } 859 860 blocks--; /* Number of blocks in the GPT table. */ 861 862 if (gpt_add_hdr(gpt, MAP_TYPE_PRI_GPT_HDR, 1) == -1) 863 return -1; 864 865 if ((p = calloc((size_t)blocks, gpt->secsz)) == NULL) { 866 gpt_warnx(gpt, "Can't allocate the primary GPT table"); 867 return -1; 868 } 869 if ((gpt->tbl = map_add(gpt, 2LL, blocks, 870 MAP_TYPE_PRI_GPT_TBL, p, 1)) == NULL) { 871 free(p); 872 gpt_warnx(gpt, "Can't add the primary GPT table"); 873 return -1; 874 } 875 876 hdr = gpt->gpt->map_data; 877 memcpy(hdr->hdr_sig, GPT_HDR_SIG, sizeof(hdr->hdr_sig)); 878 879 /* 880 * XXX struct gpt_hdr is not a multiple of 8 bytes in size and thus 881 * contains padding we must not include in the size. 882 */ 883 hdr->hdr_revision = htole32(GPT_HDR_REVISION); 884 hdr->hdr_size = htole32(GPT_HDR_SIZE); 885 hdr->hdr_lba_self = htole64((uint64_t)gpt->gpt->map_start); 886 hdr->hdr_lba_alt = htole64((uint64_t)last); 887 hdr->hdr_lba_start = htole64((uint64_t)(gpt->tbl->map_start + blocks)); 888 hdr->hdr_lba_end = htole64((uint64_t)(last - blocks - 1LL)); 889 if (gpt_uuid_generate(gpt, hdr->hdr_guid) == -1) 890 return -1; 891 hdr->hdr_lba_table = htole64((uint64_t)(gpt->tbl->map_start)); 892 hdr->hdr_entries = htole32((uint32_t)(((uint64_t)blocks * gpt->secsz) / 893 sizeof(struct gpt_ent))); 894 if (le32toh(hdr->hdr_entries) > parts) 895 hdr->hdr_entries = htole32(parts); 896 hdr->hdr_entsz = htole32(sizeof(struct gpt_ent)); 897 898 ent = gpt->tbl->map_data; 899 for (i = 0; i < le32toh(hdr->hdr_entries); i++) { 900 if (gpt_uuid_generate(gpt, ent[i].ent_guid) == -1) 901 return -1; 902 } 903 904 /* 905 * Create backup GPT if the user didn't suppress it. 906 */ 907 if (primary_only) 908 return last; 909 910 if (gpt_add_hdr(gpt, MAP_TYPE_SEC_GPT_HDR, last) == -1) 911 return -1; 912 913 if ((gpt->lbt = map_add(gpt, last - blocks, blocks, 914 MAP_TYPE_SEC_GPT_TBL, gpt->tbl->map_data, 0)) == NULL) { 915 gpt_warnx(gpt, "Can't add the secondary GPT table"); 916 return -1; 917 } 918 919 memcpy(gpt->tpg->map_data, gpt->gpt->map_data, gpt->secsz); 920 921 hdr = gpt->tpg->map_data; 922 hdr->hdr_lba_self = htole64((uint64_t)gpt->tpg->map_start); 923 hdr->hdr_lba_alt = htole64((uint64_t)gpt->gpt->map_start); 924 hdr->hdr_lba_table = htole64((uint64_t)gpt->lbt->map_start); 925 return last; 926 } 927 928 static int 929 gpt_size_get(gpt_t gpt, off_t *size) 930 { 931 off_t sectors; 932 int64_t human_num; 933 char *p; 934 935 if (*size > 0) 936 return -1; 937 sectors = strtoll(optarg, &p, 10); 938 if (sectors < 1) 939 return -1; 940 if (*p == '\0' || ((*p == 's' || *p == 'S') && p[1] == '\0')) { 941 *size = sectors * gpt->secsz; 942 return 0; 943 } 944 if ((*p == 'b' || *p == 'B') && p[1] == '\0') { 945 *size = sectors; 946 return 0; 947 } 948 if (dehumanize_number(optarg, &human_num) < 0) 949 return -1; 950 *size = human_num; 951 return 0; 952 } 953 954 int 955 gpt_human_get(gpt_t gpt, off_t *human) 956 { 957 int64_t human_num; 958 959 if (*human > 0) { 960 gpt_warn(gpt, "Already set to %jd new `%s'", (intmax_t)*human, 961 optarg); 962 return -1; 963 } 964 if (dehumanize_number(optarg, &human_num) < 0) { 965 gpt_warn(gpt, "Bad number `%s'", optarg); 966 return -1; 967 } 968 *human = human_num; 969 if (*human < 1) { 970 gpt_warn(gpt, "Number `%s' < 1", optarg); 971 return -1; 972 } 973 return 0; 974 } 975 976 int 977 gpt_add_find(gpt_t gpt, struct gpt_find *find, int ch) 978 { 979 switch (ch) { 980 case 'a': 981 if (find->all > 0) { 982 gpt_warn(gpt, "-a is already set"); 983 return -1; 984 } 985 find->all = 1; 986 break; 987 case 'b': 988 if (gpt_human_get(gpt, &find->block) == -1) 989 return -1; 990 break; 991 case 'i': 992 if (gpt_uint_get(gpt, &find->entry) == -1) 993 return -1; 994 break; 995 case 'L': 996 if (gpt_name_get(gpt, &find->label) == -1) 997 return -1; 998 break; 999 case 's': 1000 if (gpt_size_get(gpt, &find->size) == -1) 1001 return -1; 1002 break; 1003 case 't': 1004 if (!gpt_uuid_is_nil(find->type)) 1005 return -1; 1006 if (gpt_uuid_parse(optarg, find->type) != 0) 1007 return -1; 1008 break; 1009 default: 1010 gpt_warn(gpt, "Unknown find option `%c'", ch); 1011 return -1; 1012 } 1013 return 0; 1014 } 1015 1016 int 1017 gpt_change_ent(gpt_t gpt, const struct gpt_find *find, 1018 void (*cfn)(struct gpt_ent *, void *, int), void *v) 1019 { 1020 map_t m; 1021 struct gpt_hdr *hdr; 1022 struct gpt_ent *ent; 1023 unsigned int i; 1024 uint8_t utfbuf[__arraycount(ent->ent_name) * 3 + 1]; 1025 1026 if (!find->all ^ 1027 (find->block > 0 || find->entry > 0 || find->label != NULL 1028 || find->size > 0 || !gpt_uuid_is_nil(find->type))) 1029 return -1; 1030 1031 if ((hdr = gpt_hdr(gpt)) == NULL) 1032 return -1; 1033 1034 /* Relabel all matching entries in the map. */ 1035 for (m = map_first(gpt); m != NULL; m = m->map_next) { 1036 if (m->map_type != MAP_TYPE_GPT_PART || m->map_index < 1) 1037 continue; 1038 if (find->entry > 0 && find->entry != m->map_index) 1039 continue; 1040 if (find->block > 0 && find->block != m->map_start) 1041 continue; 1042 if (find->size > 0 && find->size != m->map_size) 1043 continue; 1044 1045 i = m->map_index - 1; 1046 1047 ent = gpt_ent_primary(gpt, i); 1048 if (find->label != NULL) { 1049 utf16_to_utf8(ent->ent_name, 1050 __arraycount(ent->ent_name), 1051 utfbuf, __arraycount(utfbuf)); 1052 if (strcmp((char *)find->label, (char *)utfbuf) != 0) 1053 continue; 1054 } 1055 1056 if (!gpt_uuid_is_nil(find->type) && 1057 !gpt_uuid_equal(find->type, ent->ent_type)) 1058 continue; 1059 1060 /* Change the primary entry. */ 1061 (*cfn)(ent, v, 0); 1062 1063 if (gpt_write_primary(gpt) == -1) 1064 return -1; 1065 1066 ent = gpt_ent_backup(gpt, i); 1067 /* Change the secondary entry. */ 1068 (*cfn)(ent, v, 1); 1069 1070 if (gpt_write_backup(gpt) == -1) 1071 return -1; 1072 1073 gpt_msg(gpt, "Partition %d %s", m->map_index, find->msg); 1074 } 1075 return 0; 1076 } 1077 1078 int 1079 gpt_change_hdr(gpt_t gpt, const struct gpt_find *find, 1080 void (*cfn)(struct gpt_hdr *, void *, int), void *v) 1081 { 1082 struct gpt_hdr *hdr; 1083 1084 if ((hdr = gpt_hdr(gpt)) == NULL) 1085 return -1; 1086 1087 /* Change the primary header. */ 1088 (*cfn)(hdr, v, 0); 1089 1090 if (gpt_write_primary(gpt) == -1) 1091 return -1; 1092 1093 hdr = gpt->tpg->map_data; 1094 /* Change the secondary header. */ 1095 (*cfn)(hdr, v, 1); 1096 1097 if (gpt_write_backup(gpt) == -1) 1098 return -1; 1099 1100 gpt_msg(gpt, "Header %s", find->msg); 1101 1102 return 0; 1103 } 1104 1105 int 1106 gpt_add_ais(gpt_t gpt, off_t *alignment, u_int *entry, off_t *size, int ch) 1107 { 1108 switch (ch) { 1109 case 'a': 1110 if (gpt_human_get(gpt, alignment) == -1) 1111 return -1; 1112 return 0; 1113 case 'i': 1114 if (gpt_uint_get(gpt, entry) == -1) 1115 return -1; 1116 return 0; 1117 case 's': 1118 if (gpt_size_get(gpt, size) == -1) 1119 return -1; 1120 return 0; 1121 default: 1122 gpt_warn(gpt, "Unknown alignment/index/size option `%c'", ch); 1123 return -1; 1124 } 1125 } 1126 1127 off_t 1128 gpt_check_ais(gpt_t gpt, off_t alignment, u_int entry, off_t size) 1129 { 1130 if (entry == 0) { 1131 gpt_warnx(gpt, "Entry not specified"); 1132 return -1; 1133 } 1134 if (alignment % gpt->secsz != 0) { 1135 gpt_warnx(gpt, "Alignment (%#jx) must be a multiple of " 1136 "sector size (%#x)", (uintmax_t)alignment, gpt->secsz); 1137 return -1; 1138 } 1139 1140 if (size % gpt->secsz != 0) { 1141 gpt_warnx(gpt, "Size (%#jx) must be a multiple of " 1142 "sector size (%#x)", (uintmax_t)size, gpt->secsz); 1143 return -1; 1144 } 1145 if (size > 0) 1146 return size / gpt->secsz; 1147 return 0; 1148 } 1149 1150 static const struct nvd { 1151 const char *name; 1152 uint64_t mask; 1153 const char *description; 1154 } gpt_attr[] = { 1155 { 1156 "biosboot", 1157 GPT_ENT_ATTR_LEGACY_BIOS_BOOTABLE, 1158 "Legacy BIOS boot partition", 1159 }, 1160 { 1161 "bootme", 1162 GPT_ENT_ATTR_BOOTME, 1163 "Bootable partition", 1164 }, 1165 { 1166 "bootfailed", 1167 GPT_ENT_ATTR_BOOTFAILED, 1168 "Partition that marked bootonce failed to boot", 1169 }, 1170 { 1171 "bootonce", 1172 GPT_ENT_ATTR_BOOTONCE, 1173 "Attempt to boot this partition only once", 1174 }, 1175 { 1176 "noblockio", 1177 GPT_ENT_ATTR_NO_BLOCK_IO_PROTOCOL, 1178 "UEFI won't recognize file system for block I/O", 1179 }, 1180 { 1181 "required", 1182 GPT_ENT_ATTR_REQUIRED_PARTITION, 1183 "Partition required for platform to function", 1184 }, 1185 }; 1186 1187 int 1188 gpt_attr_get(gpt_t gpt, uint64_t *attributes) 1189 { 1190 size_t i; 1191 int rv = 0; 1192 char *ptr; 1193 1194 *attributes = 0; 1195 1196 for (ptr = strtok(optarg, ","); ptr; ptr = strtok(NULL, ",")) { 1197 for (i = 0; i < __arraycount(gpt_attr); i++) 1198 if (strcmp(gpt_attr[i].name, ptr) == 0) 1199 break; 1200 if (i == __arraycount(gpt_attr)) { 1201 gpt_warnx(gpt, "Unrecognized attribute `%s'", ptr); 1202 rv = -1; 1203 } else 1204 *attributes |= gpt_attr[i].mask; 1205 } 1206 return rv; 1207 } 1208 1209 void 1210 gpt_attr_help(const char *prefix) 1211 { 1212 size_t i; 1213 1214 for (i = 0; i < __arraycount(gpt_attr); i++) 1215 printf("%s%10.10s\t%s\n", prefix, gpt_attr[i].name, 1216 gpt_attr[i].description); 1217 } 1218 1219 const char * 1220 gpt_attr_list(char *buf, size_t len, uint64_t attributes) 1221 { 1222 size_t i; 1223 strlcpy(buf, "", len); 1224 1225 for (i = 0; i < __arraycount(gpt_attr); i++) 1226 if (attributes & gpt_attr[i].mask) { 1227 strlcat(buf, buf[0] ? ", " : "", len); 1228 strlcat(buf, gpt_attr[i].name, len); 1229 } 1230 return buf; 1231 } 1232 1233 int 1234 gpt_attr_update(gpt_t gpt, u_int entry, uint64_t set, uint64_t clr) 1235 { 1236 struct gpt_hdr *hdr; 1237 struct gpt_ent *ent; 1238 unsigned int i; 1239 1240 if (entry == 0 || (set == 0 && clr == 0)) { 1241 gpt_warnx(gpt, "Nothing to set"); 1242 return -1; 1243 } 1244 1245 if ((hdr = gpt_hdr(gpt)) == NULL) 1246 return -1; 1247 1248 if (entry > le32toh(hdr->hdr_entries)) { 1249 gpt_warnx(gpt, "Index %u out of range (%u max)", 1250 entry, le32toh(hdr->hdr_entries)); 1251 return -1; 1252 } 1253 1254 i = entry - 1; 1255 ent = gpt_ent_primary(gpt, i); 1256 if (gpt_uuid_is_nil(ent->ent_type)) { 1257 gpt_warnx(gpt, "Entry at index %u is unused", entry); 1258 return -1; 1259 } 1260 1261 ent->ent_attr &= ~clr; 1262 ent->ent_attr |= set; 1263 1264 if (gpt_write_primary(gpt) == -1) 1265 return -1; 1266 1267 ent = gpt_ent_backup(gpt, i); 1268 ent->ent_attr &= ~clr; 1269 ent->ent_attr |= set; 1270 1271 if (gpt_write_backup(gpt) == -1) 1272 return -1; 1273 gpt_msg(gpt, "Partition %d attributes updated", entry); 1274 return 0; 1275 } 1276 1277 int 1278 gpt_uint_get(gpt_t gpt, u_int *entry) 1279 { 1280 char *p; 1281 if (*entry > 0) 1282 return -1; 1283 *entry = (u_int)strtoul(optarg, &p, 10); 1284 if (*p != 0 || *entry < 1) { 1285 gpt_warn(gpt, "Bad number `%s'", optarg); 1286 return -1; 1287 } 1288 return 0; 1289 } 1290 int 1291 gpt_uuid_get(gpt_t gpt, gpt_uuid_t *uuid) 1292 { 1293 if (!gpt_uuid_is_nil(*uuid)) 1294 return -1; 1295 if (gpt_uuid_parse(optarg, *uuid) != 0) { 1296 gpt_warnx(gpt, "Can't parse uuid/type `%s'", optarg); 1297 return -1; 1298 } 1299 return 0; 1300 } 1301 1302 int 1303 gpt_name_get(gpt_t gpt, void *v) 1304 { 1305 char **name = v; 1306 if (*name != NULL) 1307 return -1; 1308 *name = strdup(optarg); 1309 if (*name == NULL) { 1310 gpt_warn(gpt, "Can't copy string"); 1311 return -1; 1312 } 1313 return 0; 1314 } 1315 1316 void 1317 gpt_show_num(const char *prompt, uintmax_t num) 1318 { 1319 #ifdef HN_AUTOSCALE 1320 char human_num[5]; 1321 if (humanize_number(human_num, 5, (int64_t)num , 1322 "", HN_AUTOSCALE, HN_NOSPACE|HN_B) < 0) 1323 human_num[0] = '\0'; 1324 #endif 1325 printf("%s: %ju", prompt, num); 1326 #ifdef HN_AUTOSCALE 1327 if (human_num[0] != '\0') 1328 printf(" (%s)", human_num); 1329 #endif 1330 printf("\n"); 1331 } 1332 1333 int 1334 gpt_add_hdr(gpt_t gpt, int type, off_t loc) 1335 { 1336 void *p; 1337 map_t *t; 1338 const char *msg; 1339 1340 switch (type) { 1341 case MAP_TYPE_PRI_GPT_HDR: 1342 t = &gpt->gpt; 1343 msg = "primary"; 1344 break; 1345 case MAP_TYPE_SEC_GPT_HDR: 1346 t = &gpt->tpg; 1347 msg = "secondary"; 1348 break; 1349 default: 1350 gpt_warnx(gpt, "Unknown GPT header type %d", type); 1351 return -1; 1352 } 1353 1354 if ((p = calloc(1, gpt->secsz)) == NULL) { 1355 gpt_warn(gpt, "Error allocating %s GPT header", msg); 1356 return -1; 1357 } 1358 1359 *t = map_add(gpt, loc, 1LL, type, p, 1); 1360 if (*t == NULL) { 1361 gpt_warn(gpt, "Error adding %s GPT header", msg); 1362 free(p); 1363 return -1; 1364 } 1365 return 0; 1366 } 1367