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