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