Home | History | Annotate | Line # | Download | only in gpt
gpt.c revision 1.56
      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.56 2015/12/02 12:20: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 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 (!(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 		gpt->flags |= GPT_NOSYNC;
    530 	}
    531 
    532 	/*
    533 	 * We require an absolute minimum of 6 sectors. One for the MBR,
    534 	 * 2 for the GPT header, 2 for the GPT table and one to hold some
    535 	 * user data. Let's catch this extreme border case here so that
    536 	 * we don't have to worry about it later.
    537 	 */
    538 	devsz = gpt->mediasz / gpt->secsz;
    539 	if (devsz < 6) {
    540 		gpt_warnx(gpt, "Need 6 sectorso, we have %ju",
    541 		    (uintmax_t)devsz);
    542 		goto close;
    543 	}
    544 
    545 	if (gpt->verbose) {
    546 		gpt_msg(gpt, "mediasize=%ju; sectorsize=%u; blocks=%ju",
    547 		    (uintmax_t)gpt->mediasz, gpt->secsz, (uintmax_t)devsz);
    548 	}
    549 
    550 	map_init(gpt, devsz);
    551 
    552 	if (gpt_mbr(gpt, 0LL) == -1)
    553 		goto close;
    554 	if ((found = gpt_gpt(gpt, 1LL, 1)) == -1)
    555 		goto close;
    556 	if (gpt_gpt(gpt, devsz - 1LL, found) == -1)
    557 		goto close;
    558 
    559 	return gpt;
    560 
    561  close:
    562 	if (gpt->fd != -1)
    563 		close(gpt->fd);
    564 	free(gpt);
    565 	return NULL;
    566 }
    567 
    568 void
    569 gpt_close(gpt_t gpt)
    570 {
    571 
    572 	if (!(gpt->flags & GPT_MODIFIED))
    573 		goto out;
    574 
    575 	if (!(gpt->flags & GPT_NOSYNC)) {
    576 #ifdef DIOCMWEDGES
    577 		int bits;
    578 		if (ioctl(gpt->fd, DIOCMWEDGES, &bits) == -1)
    579 			gpt_warn(gpt, "Can't update wedge information");
    580 		else
    581 			goto out;
    582 #endif
    583 	}
    584 	gpt_msg(gpt, "You need to run \"dkctl %s makewedges\""
    585 	    " for the changes to take effect\n", gpt->device_name);
    586 
    587 out:
    588 	close(gpt->fd);
    589 }
    590 
    591 void
    592 gpt_warnx(gpt_t gpt, const char *fmt, ...)
    593 {
    594 	va_list ap;
    595 
    596 	if (gpt->flags & GPT_QUIET)
    597 		return;
    598 	fprintf(stderr, "%s: %s: ", getprogname(), gpt->device_name);
    599 	va_start(ap, fmt);
    600 	vfprintf(stderr, fmt, ap);
    601 	va_end(ap);
    602 	fprintf(stderr, "\n");
    603 }
    604 
    605 void
    606 gpt_warn(gpt_t gpt, const char *fmt, ...)
    607 {
    608 	va_list ap;
    609 	int e = errno;
    610 
    611 	if (gpt->flags & GPT_QUIET)
    612 		return;
    613 	fprintf(stderr, "%s: %s: ", getprogname(), gpt->device_name);
    614 	va_start(ap, fmt);
    615 	vfprintf(stderr, fmt, ap);
    616 	va_end(ap);
    617 	fprintf(stderr, " (%s)\n", strerror(e));
    618 	errno = e;
    619 }
    620 
    621 void
    622 gpt_msg(gpt_t gpt, const char *fmt, ...)
    623 {
    624 	va_list ap;
    625 
    626 	if (gpt->flags & GPT_QUIET)
    627 		return;
    628 	printf("%s: ", gpt->device_name);
    629 	va_start(ap, fmt);
    630 	vprintf(fmt, ap);
    631 	va_end(ap);
    632 	printf("\n");
    633 }
    634 
    635 struct gpt_hdr *
    636 gpt_hdr(gpt_t gpt)
    637 {
    638 	gpt->gpt = map_find(gpt, MAP_TYPE_PRI_GPT_HDR);
    639 	if (gpt->gpt == NULL) {
    640 		gpt_warnx(gpt, "No primary GPT header; run create or recover");
    641 		return NULL;
    642 	}
    643 
    644 	gpt->tpg = map_find(gpt, MAP_TYPE_SEC_GPT_HDR);
    645 	if (gpt->tpg == NULL) {
    646 		gpt_warnx(gpt, "No secondary GPT header; run recover");
    647 		return NULL;
    648 	}
    649 
    650 	gpt->tbl = map_find(gpt, MAP_TYPE_PRI_GPT_TBL);
    651 	gpt->lbt = map_find(gpt, MAP_TYPE_SEC_GPT_TBL);
    652 	if (gpt->tbl == NULL || gpt->lbt == NULL) {
    653 		gpt_warnx(gpt, "Corrupt maps, run recover");
    654 		return NULL;
    655 	}
    656 
    657 	return gpt->gpt->map_data;
    658 }
    659 
    660 int
    661 gpt_write_crc(gpt_t gpt, map_t map, map_t tbl)
    662 {
    663 	struct gpt_hdr *hdr = map->map_data;
    664 
    665 	hdr->hdr_crc_table = htole32(crc32(tbl->map_data,
    666 	    le32toh(hdr->hdr_entries) * le32toh(hdr->hdr_entsz)));
    667 	hdr->hdr_crc_self = 0;
    668 	hdr->hdr_crc_self = htole32(crc32(hdr, le32toh(hdr->hdr_size)));
    669 
    670 	if (gpt_write(gpt, map) == -1) {
    671 		gpt_warn(gpt, "Error writing crc map");
    672 		return -1;
    673 	}
    674 
    675 	if (gpt_write(gpt, tbl) == -1) {
    676 		gpt_warn(gpt, "Error writing crc table");
    677 		return -1;
    678 	}
    679 
    680 	return 0;
    681 }
    682 
    683 int
    684 gpt_write_primary(gpt_t gpt)
    685 {
    686 	return gpt_write_crc(gpt, gpt->gpt, gpt->tbl);
    687 }
    688 
    689 
    690 int
    691 gpt_write_backup(gpt_t gpt)
    692 {
    693 	return gpt_write_crc(gpt, gpt->tpg, gpt->lbt);
    694 }
    695 
    696 void
    697 gpt_create_pmbr_part(struct mbr_part *part, off_t last)
    698 {
    699 	part->part_shd = 0x00;
    700 	part->part_ssect = 0x02;
    701 	part->part_scyl = 0x00;
    702 	part->part_typ = MBR_PTYPE_PMBR;
    703 	part->part_ehd = 0xfe;
    704 	part->part_esect = 0xff;
    705 	part->part_ecyl = 0xff;
    706 	part->part_start_lo = htole16(1);
    707 	if (last > 0xffffffff) {
    708 		part->part_size_lo = htole16(0xffff);
    709 		part->part_size_hi = htole16(0xffff);
    710 	} else {
    711 		part->part_size_lo = htole16(last);
    712 		part->part_size_hi = htole16(last >> 16);
    713 	}
    714 }
    715 
    716 
    717 struct gpt_ent *
    718 gpt_ent(map_t map, map_t tbl, unsigned int i)
    719 {
    720 	struct gpt_hdr *hdr = map->map_data;
    721 	return (void *)((char *)tbl->map_data + i * le32toh(hdr->hdr_entsz));
    722 }
    723 
    724 struct gpt_ent *
    725 gpt_ent_primary(gpt_t gpt, unsigned int i)
    726 {
    727 	return gpt_ent(gpt->gpt, gpt->tbl, i);
    728 }
    729 
    730 struct gpt_ent *
    731 gpt_ent_backup(gpt_t gpt, unsigned int i)
    732 {
    733 	return gpt_ent(gpt->tpg, gpt->lbt, i);
    734 }
    735 
    736 int
    737 gpt_usage(const char *prefix, const struct gpt_cmd *cmd)
    738 {
    739 	const char **a = cmd->help;
    740 	size_t hlen = cmd->hlen;
    741 	size_t i;
    742 
    743 	if (prefix == NULL) {
    744 		const char *pname = getprogname();
    745 		const char *d1, *d2, *d = " <device>";
    746 		int len = (int)strlen(pname);
    747 		if (strcmp(pname, "gpt") == 0) {
    748 			d1 = "";
    749 			d2 = d;
    750 		} else {
    751 			d2 = "";
    752 			d1 = d;
    753 		}
    754 		fprintf(stderr, "Usage: %s%s %s %s%s\n", pname,
    755 		    d1, cmd->name, a[0], d2);
    756 		for (i = 1; i < hlen; i++) {
    757 			fprintf(stderr,
    758 			    "       %*s%s %s %s%s\n", len, "",
    759 			    d1, cmd->name, a[i], d2);
    760 		}
    761 	} else {
    762 		for (i = 0; i < hlen; i++)
    763 		    fprintf(stderr, "%s%s %s\n", prefix, cmd->name, a[i]);
    764 	}
    765 	return -1;
    766 }
    767 
    768 off_t
    769 gpt_last(gpt_t gpt)
    770 {
    771 	return gpt->mediasz / gpt->secsz - 1LL;
    772 }
    773 
    774 int
    775 gpt_create(gpt_t gpt, off_t last, u_int parts, int primary_only)
    776 {
    777 	off_t blocks;
    778 	map_t map;
    779 	struct gpt_hdr *hdr;
    780 	struct gpt_ent *ent;
    781 	unsigned int i;
    782 	void *p;
    783 
    784 	if (map_find(gpt, MAP_TYPE_PRI_GPT_HDR) != NULL ||
    785 	    map_find(gpt, MAP_TYPE_SEC_GPT_HDR) != NULL) {
    786 		gpt_warnx(gpt, "Device already contains a GPT");
    787 		return -1;
    788 	}
    789 
    790 	/* Get the amount of free space after the MBR */
    791 	blocks = map_free(gpt, 1LL, 0LL);
    792 	if (blocks == 0LL) {
    793 		gpt_warnx(gpt, "No room for the GPT header");
    794 		return -1;
    795 	}
    796 
    797 	/* Don't create more than parts entries. */
    798 	if ((uint64_t)(blocks - 1) * gpt->secsz >
    799 	    parts * sizeof(struct gpt_ent)) {
    800 		blocks = (parts * sizeof(struct gpt_ent)) / gpt->secsz;
    801 		if ((parts * sizeof(struct gpt_ent)) % gpt->secsz)
    802 			blocks++;
    803 		blocks++;		/* Don't forget the header itself */
    804 	}
    805 
    806 	/* Never cross the median of the device. */
    807 	if ((blocks + 1LL) > ((last + 1LL) >> 1))
    808 		blocks = ((last + 1LL) >> 1) - 1LL;
    809 
    810 	/*
    811 	 * Get the amount of free space at the end of the device and
    812 	 * calculate the size for the GPT structures.
    813 	 */
    814 	map = map_last(gpt);
    815 	if (map->map_type != MAP_TYPE_UNUSED) {
    816 		gpt_warnx(gpt, "No room for the backup header");
    817 		return -1;
    818 	}
    819 
    820 	if (map->map_size < blocks)
    821 		blocks = map->map_size;
    822 	if (blocks == 1LL) {
    823 		gpt_warnx(gpt, "No room for the GPT table");
    824 		return -1;
    825 	}
    826 
    827 	blocks--;		/* Number of blocks in the GPT table. */
    828 
    829 	if ((p = calloc(1, gpt->secsz)) == NULL) {
    830 		gpt_warnx(gpt, "Can't allocate the primary GPT");
    831 		return -1;
    832 	}
    833 	if ((gpt->gpt = map_add(gpt, 1LL, 1LL,
    834 	    MAP_TYPE_PRI_GPT_HDR, p)) == NULL) {
    835 		free(p);
    836 		gpt_warnx(gpt, "Can't add the primary GPT");
    837 		return -1;
    838 	}
    839 
    840 	if ((p = calloc(blocks, gpt->secsz)) == NULL) {
    841 		gpt_warnx(gpt, "Can't allocate the primary GPT table");
    842 		return -1;
    843 	}
    844 	if ((gpt->tbl = map_add(gpt, 2LL, blocks,
    845 	    MAP_TYPE_PRI_GPT_TBL, p)) == NULL) {
    846 		free(p);
    847 		gpt_warnx(gpt, "Can't add the primary GPT table");
    848 		return -1;
    849 	}
    850 
    851 	hdr = gpt->gpt->map_data;
    852 	memcpy(hdr->hdr_sig, GPT_HDR_SIG, sizeof(hdr->hdr_sig));
    853 
    854 	/*
    855 	 * XXX struct gpt_hdr is not a multiple of 8 bytes in size and thus
    856 	 * contains padding we must not include in the size.
    857 	 */
    858 	hdr->hdr_revision = htole32(GPT_HDR_REVISION);
    859 	hdr->hdr_size = htole32(GPT_HDR_SIZE);
    860 	hdr->hdr_lba_self = htole64(gpt->gpt->map_start);
    861 	hdr->hdr_lba_alt = htole64(last);
    862 	hdr->hdr_lba_start = htole64(gpt->tbl->map_start + blocks);
    863 	hdr->hdr_lba_end = htole64(last - blocks - 1LL);
    864 	if (gpt_uuid_generate(gpt, hdr->hdr_guid) == -1)
    865 		return -1;
    866 	hdr->hdr_lba_table = htole64(gpt->tbl->map_start);
    867 	hdr->hdr_entries = htole32((blocks * gpt->secsz) /
    868 	    sizeof(struct gpt_ent));
    869 	if (le32toh(hdr->hdr_entries) > parts)
    870 		hdr->hdr_entries = htole32(parts);
    871 	hdr->hdr_entsz = htole32(sizeof(struct gpt_ent));
    872 
    873 	ent = gpt->tbl->map_data;
    874 	for (i = 0; i < le32toh(hdr->hdr_entries); i++) {
    875 		if (gpt_uuid_generate(gpt, ent[i].ent_guid) == -1)
    876 			return -1;
    877 	}
    878 
    879 	/*
    880 	 * Create backup GPT if the user didn't suppress it.
    881 	 */
    882 	if (primary_only)
    883 		return last;
    884 
    885 	if ((p = calloc(1, gpt->secsz)) == NULL) {
    886 		gpt_warnx(gpt, "Can't allocate the secondary GPT");
    887 		return -1;
    888 	}
    889 
    890 	if ((gpt->tpg = map_add(gpt, last, 1LL,
    891 	    MAP_TYPE_SEC_GPT_HDR, p)) == NULL) {
    892 		gpt_warnx(gpt, "Can't add the secondary GPT");
    893 		return -1;
    894 	}
    895 
    896 	if ((gpt->lbt = map_add(gpt, last - blocks, blocks,
    897 	    MAP_TYPE_SEC_GPT_TBL, gpt->tbl->map_data)) == NULL) {
    898 		gpt_warnx(gpt, "Can't add the secondary GPT table");
    899 		return -1;
    900 	}
    901 
    902 	memcpy(gpt->tpg->map_data, gpt->gpt->map_data, gpt->secsz);
    903 
    904 	hdr = gpt->tpg->map_data;
    905 	hdr->hdr_lba_self = htole64(gpt->tpg->map_start);
    906 	hdr->hdr_lba_alt = htole64(gpt->gpt->map_start);
    907 	hdr->hdr_lba_table = htole64(gpt->lbt->map_start);
    908 	return last;
    909 }
    910 
    911 static int
    912 gpt_size_get(gpt_t gpt, off_t *size)
    913 {
    914 	off_t sectors;
    915 	int64_t human_num;
    916 	char *p;
    917 
    918 	if (*size > 0)
    919 		return -1;
    920 	sectors = strtoll(optarg, &p, 10);
    921 	if (sectors < 1)
    922 		return -1;
    923 	if (*p == '\0' || ((*p == 's' || *p == 'S') && p[1] == '\0')) {
    924 		*size = sectors * gpt->secsz;
    925 		return 0;
    926 	}
    927 	if ((*p == 'b' || *p == 'B') && p[1] == '\0') {
    928 		*size = sectors;
    929 		return 0;
    930 	}
    931 	if (dehumanize_number(optarg, &human_num) < 0)
    932 		return -1;
    933 	*size = human_num;
    934 	return 0;
    935 }
    936 
    937 int
    938 gpt_human_get(off_t *human)
    939 {
    940 	int64_t human_num;
    941 
    942 	if (*human > 0)
    943 		return -1;
    944 	if (dehumanize_number(optarg, &human_num) < 0)
    945 		return -1;
    946 	*human = human_num;
    947 	if (*human < 1)
    948 		return -1;
    949 	return 0;
    950 }
    951 
    952 int
    953 gpt_add_find(gpt_t gpt, struct gpt_find *find, int ch)
    954 {
    955 	switch (ch) {
    956 	case 'a':
    957 		if (find->all > 0)
    958 			return -1;
    959 		find->all = 1;
    960 		break;
    961 	case 'b':
    962 		if (gpt_human_get(&find->block) == -1)
    963 			return -1;
    964 		break;
    965 	case 'i':
    966 		if (gpt_entry_get(&find->entry) == -1)
    967 			return -1;
    968 		break;
    969 	case 'L':
    970 		if (gpt_name_get(gpt, &find->label) == -1)
    971 			return -1;
    972 		break;
    973 	case 's':
    974 		if (gpt_size_get(gpt, &find->size) == -1)
    975 			return -1;
    976 		break;
    977 	case 't':
    978 		if (!gpt_uuid_is_nil(find->type))
    979 			return -1;
    980 		if (gpt_uuid_parse(optarg, find->type) != 0)
    981 			return -1;
    982 		break;
    983 	default:
    984 		return -1;
    985 	}
    986 	return 0;
    987 }
    988 
    989 int
    990 gpt_change_ent(gpt_t gpt, const struct gpt_find *find,
    991     void (*cfn)(struct gpt_ent *, void *), void *v)
    992 {
    993 	map_t m;
    994 	struct gpt_hdr *hdr;
    995 	struct gpt_ent *ent;
    996 	unsigned int i;
    997 	uint8_t utfbuf[__arraycount(ent->ent_name) * 3 + 1];
    998 
    999 	if (!find->all ^
   1000 	    (find->block > 0 || find->entry > 0 || find->label != NULL
   1001 	    || find->size > 0 || !gpt_uuid_is_nil(find->type)))
   1002 		return -1;
   1003 
   1004 	if ((hdr = gpt_hdr(gpt)) == NULL)
   1005 		return -1;
   1006 
   1007 	/* Relabel all matching entries in the map. */
   1008 	for (m = map_first(gpt); m != NULL; m = m->map_next) {
   1009 		if (m->map_type != MAP_TYPE_GPT_PART || m->map_index < 1)
   1010 			continue;
   1011 		if (find->entry > 0 && find->entry != m->map_index)
   1012 			continue;
   1013 		if (find->block > 0 && find->block != m->map_start)
   1014 			continue;
   1015 		if (find->size > 0 && find->size != m->map_size)
   1016 			continue;
   1017 
   1018 		i = m->map_index - 1;
   1019 
   1020 		ent = gpt_ent_primary(gpt, i);
   1021 		if (find->label != NULL) {
   1022 			utf16_to_utf8(ent->ent_name, utfbuf, sizeof(utfbuf));
   1023 			if (strcmp((char *)find->label, (char *)utfbuf) == 0)
   1024 				continue;
   1025 		}
   1026 
   1027 		if (!gpt_uuid_is_nil(find->type) &&
   1028 		    !gpt_uuid_equal(find->type, ent->ent_type))
   1029 			continue;
   1030 
   1031 		/* Change the primary entry. */
   1032 		(*cfn)(ent, v);
   1033 
   1034 		if (gpt_write_primary(gpt) == -1)
   1035 			return -1;
   1036 
   1037 		ent = gpt_ent_backup(gpt, i);
   1038 		/* Change the secondary entry. */
   1039 		(*cfn)(ent, v);
   1040 
   1041 		if (gpt_write_backup(gpt) == -1)
   1042 			return -1;
   1043 
   1044 		gpt_msg(gpt, "Partition %d %s", m->map_index, find->msg);
   1045 	}
   1046 	return 0;
   1047 }
   1048 
   1049 int
   1050 gpt_add_ais(gpt_t gpt, off_t *alignment, u_int *entry, off_t *size, int ch)
   1051 {
   1052 	switch (ch) {
   1053 	case 'a':
   1054 		if (gpt_human_get(alignment) == -1)
   1055 			return -1;
   1056 		return 0;
   1057 	case 'i':
   1058 		if (gpt_entry_get(entry) == -1)
   1059 			return -1;
   1060 		return 0;
   1061 	case 's':
   1062 		if (gpt_size_get(gpt, size) == -1)
   1063 			return -1;
   1064 		return 0;
   1065 	default:
   1066 		return -1;
   1067 	}
   1068 }
   1069 
   1070 off_t
   1071 gpt_check_ais(gpt_t gpt, off_t alignment, u_int entry, off_t size)
   1072 {
   1073 	if (entry == 0) {
   1074 		gpt_warnx(gpt, "Entry not specified");
   1075 		return -1;
   1076 	}
   1077 	if (alignment % gpt->secsz != 0) {
   1078 		gpt_warnx(gpt, "Alignment (%#jx) must be a multiple of "
   1079 		    "sector size (%#x)", (uintmax_t)alignment, gpt->secsz);
   1080 		return -1;
   1081 	}
   1082 
   1083 	if (size % gpt->secsz != 0) {
   1084 		gpt_warnx(gpt, "Size (%#jx) must be a multiple of "
   1085 		    "sector size (%#x)", (uintmax_t)size, gpt->secsz);
   1086 		return -1;
   1087 	}
   1088 	if (size > 0)
   1089 		return size / gpt->secsz;
   1090 	return 0;
   1091 }
   1092 int
   1093 gpt_attr_get(uint64_t *attributes)
   1094 {
   1095 	if (strcmp(optarg, "biosboot") == 0)
   1096 		*attributes |= GPT_ENT_ATTR_LEGACY_BIOS_BOOTABLE;
   1097 	else if (strcmp(optarg, "bootme") == 0)
   1098 		*attributes |= GPT_ENT_ATTR_BOOTME;
   1099 	else if (strcmp(optarg, "bootonce") == 0)
   1100 		*attributes |= GPT_ENT_ATTR_BOOTONCE;
   1101 	else if (strcmp(optarg, "bootfailed") == 0)
   1102 		*attributes |= GPT_ENT_ATTR_BOOTFAILED;
   1103 	else
   1104 		return -1;
   1105 	return 0;
   1106 }
   1107 int
   1108 gpt_attr_update(gpt_t gpt, u_int entry, uint64_t set, uint64_t clr)
   1109 {
   1110 	struct gpt_hdr *hdr;
   1111 	struct gpt_ent *ent;
   1112 	unsigned int i;
   1113 
   1114 	if (entry == 0 || (set == 0 && clr == 0))
   1115 		return -1;
   1116 
   1117 	if ((hdr = gpt_hdr(gpt)) == NULL)
   1118 		return -1;
   1119 
   1120 	if (entry > le32toh(hdr->hdr_entries)) {
   1121 		gpt_warnx(gpt, "Index %u out of range (%u max)",
   1122 		    entry, le32toh(hdr->hdr_entries));
   1123 		return -1;
   1124 	}
   1125 
   1126 	i = entry - 1;
   1127 	ent = gpt_ent_primary(gpt, i);
   1128 	if (gpt_uuid_is_nil(ent->ent_type)) {
   1129 		gpt_warnx(gpt, "Entry at index %u is unused", entry);
   1130 		return -1;
   1131 	}
   1132 
   1133 	ent->ent_attr &= ~clr;
   1134 	ent->ent_attr |= set;
   1135 
   1136 	if (gpt_write_primary(gpt) == -1)
   1137 		return -1;
   1138 
   1139 	ent = gpt_ent_backup(gpt, i);
   1140 	ent->ent_attr &= ~clr;
   1141 	ent->ent_attr |= set;
   1142 
   1143 	if (gpt_write_backup(gpt) == -1)
   1144 		return -1;
   1145 	gpt_msg(gpt, "Partition %d attributes updated", entry);
   1146 	return 0;
   1147 }
   1148 
   1149 int
   1150 gpt_entry_get(u_int *entry)
   1151 {
   1152 	char *p;
   1153 	if (*entry > 0)
   1154 		return -1;
   1155 	*entry = strtoul(optarg, &p, 10);
   1156 	if (*p != 0 || *entry < 1)
   1157 		return -1;
   1158 	return 0;
   1159 }
   1160 int
   1161 gpt_uuid_get(gpt_t gpt, gpt_uuid_t *uuid)
   1162 {
   1163 	if (!gpt_uuid_is_nil(*uuid))
   1164 		return -1;
   1165 	if (gpt_uuid_parse(optarg, *uuid) != 0) {
   1166 		gpt_warn(gpt, "Can't parse uuid");
   1167 		return -1;
   1168 	}
   1169 	return 0;
   1170 }
   1171 
   1172 int
   1173 gpt_name_get(gpt_t gpt, void *v)
   1174 {
   1175 	char **name = v;
   1176 	if (*name != NULL)
   1177 		return -1;
   1178 	*name = strdup(optarg);
   1179 	if (*name == NULL) {
   1180 		gpt_warn(gpt, "Can't copy string");
   1181 		return -1;
   1182 	}
   1183 	return 0;
   1184 }
   1185