Home | History | Annotate | Line # | Download | only in gpt
gpt.c revision 1.17
      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 #include <sys/cdefs.h>
     30 #ifdef __FBSDID
     31 __FBSDID("$FreeBSD: src/sbin/gpt/gpt.c,v 1.16 2006/07/07 02:44:23 marcel Exp $");
     32 #endif
     33 #ifdef __RCSID
     34 __RCSID("$NetBSD: gpt.c,v 1.17 2012/07/30 00:53:59 matt Exp $");
     35 #endif
     36 
     37 #include <sys/param.h>
     38 #include <sys/types.h>
     39 #include <sys/disk.h>
     40 #include <sys/stat.h>
     41 #include <sys/ioctl.h>
     42 
     43 #include <err.h>
     44 #include <errno.h>
     45 #include <fcntl.h>
     46 #include <paths.h>
     47 #include <stddef.h>
     48 #include <stdio.h>
     49 #include <stdlib.h>
     50 #include <string.h>
     51 #include <unistd.h>
     52 #ifdef __NetBSD__
     53 #include <util.h>
     54 #include <ctype.h>
     55 #include <prop/proplib.h>
     56 #include <sys/drvctlio.h>
     57 #endif
     58 
     59 #include "map.h"
     60 #include "gpt.h"
     61 
     62 char	device_path[MAXPATHLEN];
     63 const char *device_arg;
     64 char	*device_name;
     65 
     66 off_t	mediasz;
     67 
     68 u_int	parts;
     69 u_int	secsz;
     70 
     71 int	readonly, verbose;
     72 
     73 static uint32_t crc32_tab[] = {
     74 	0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
     75 	0xe963a535, 0x9e6495a3,	0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
     76 	0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
     77 	0xf3b97148, 0x84be41de,	0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
     78 	0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,	0x14015c4f, 0x63066cd9,
     79 	0xfa0f3d63, 0x8d080df5,	0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
     80 	0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,	0x35b5a8fa, 0x42b2986c,
     81 	0xdbbbc9d6, 0xacbcf940,	0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
     82 	0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
     83 	0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
     84 	0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,	0x76dc4190, 0x01db7106,
     85 	0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
     86 	0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
     87 	0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
     88 	0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
     89 	0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
     90 	0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
     91 	0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
     92 	0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
     93 	0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
     94 	0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
     95 	0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
     96 	0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
     97 	0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
     98 	0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
     99 	0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
    100 	0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
    101 	0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
    102 	0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
    103 	0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
    104 	0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
    105 	0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
    106 	0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
    107 	0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
    108 	0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
    109 	0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
    110 	0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
    111 	0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
    112 	0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
    113 	0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
    114 	0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
    115 	0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
    116 	0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
    117 };
    118 
    119 uint32_t
    120 crc32(const void *buf, size_t size)
    121 {
    122 	const uint8_t *p;
    123 	uint32_t crc;
    124 
    125 	p = buf;
    126 	crc = ~0U;
    127 
    128 	while (size--)
    129 		crc = crc32_tab[(crc ^ *p++) & 0xFF] ^ (crc >> 8);
    130 
    131 	return crc ^ ~0U;
    132 }
    133 
    134 uint8_t *
    135 utf16_to_utf8(uint16_t *s16)
    136 {
    137 	static uint8_t *s8 = NULL;
    138 	static size_t s8len = 0;
    139 	size_t s8idx, s16idx, s16len;
    140 	uint32_t utfchar;
    141 	unsigned int c;
    142 
    143 	s16len = 0;
    144 	while (s16[s16len++] != 0)
    145 		;
    146 	if (s8len < s16len * 3) {
    147 		if (s8 != NULL)
    148 			free(s8);
    149 		s8len = s16len * 3;
    150 		s8 = calloc(s16len, 3);
    151 	}
    152 	s8idx = s16idx = 0;
    153 	while (s16idx < s16len) {
    154 		utfchar = le16toh(s16[s16idx++]);
    155 		if ((utfchar & 0xf800) == 0xd800) {
    156 			c = le16toh(s16[s16idx]);
    157 			if ((utfchar & 0x400) != 0 || (c & 0xfc00) != 0xdc00)
    158 				utfchar = 0xfffd;
    159 			else
    160 				s16idx++;
    161 		}
    162 		if (utfchar < 0x80) {
    163 			s8[s8idx++] = utfchar;
    164 		} else if (utfchar < 0x800) {
    165 			s8[s8idx++] = 0xc0 | (utfchar >> 6);
    166 			s8[s8idx++] = 0x80 | (utfchar & 0x3f);
    167 		} else if (utfchar < 0x10000) {
    168 			s8[s8idx++] = 0xe0 | (utfchar >> 12);
    169 			s8[s8idx++] = 0x80 | ((utfchar >> 6) & 0x3f);
    170 			s8[s8idx++] = 0x80 | (utfchar & 0x3f);
    171 		} else if (utfchar < 0x200000) {
    172 			s8[s8idx++] = 0xf0 | (utfchar >> 18);
    173 			s8[s8idx++] = 0x80 | ((utfchar >> 12) & 0x3f);
    174 			s8[s8idx++] = 0x80 | ((utfchar >> 6) & 0x3f);
    175 			s8[s8idx++] = 0x80 | (utfchar & 0x3f);
    176 		}
    177 	}
    178 	return (s8);
    179 }
    180 
    181 void
    182 utf8_to_utf16(const uint8_t *s8, uint16_t *s16, size_t s16len)
    183 {
    184 	size_t s16idx, s8idx, s8len;
    185 	uint32_t utfchar = 0;
    186 	unsigned int c, utfbytes;
    187 
    188 	s8len = 0;
    189 	while (s8[s8len++] != 0)
    190 		;
    191 	s8idx = s16idx = 0;
    192 	utfbytes = 0;
    193 	do {
    194 		c = s8[s8idx++];
    195 		if ((c & 0xc0) != 0x80) {
    196 			/* Initial characters. */
    197 			if (utfbytes != 0) {
    198 				/* Incomplete encoding. */
    199 				s16[s16idx++] = htole16(0xfffd);
    200 				if (s16idx == s16len) {
    201 					s16[--s16idx] = 0;
    202 					return;
    203 				}
    204 			}
    205 			if ((c & 0xf8) == 0xf0) {
    206 				utfchar = c & 0x07;
    207 				utfbytes = 3;
    208 			} else if ((c & 0xf0) == 0xe0) {
    209 				utfchar = c & 0x0f;
    210 				utfbytes = 2;
    211 			} else if ((c & 0xe0) == 0xc0) {
    212 				utfchar = c & 0x1f;
    213 				utfbytes = 1;
    214 			} else {
    215 				utfchar = c & 0x7f;
    216 				utfbytes = 0;
    217 			}
    218 		} else {
    219 			/* Followup characters. */
    220 			if (utfbytes > 0) {
    221 				utfchar = (utfchar << 6) + (c & 0x3f);
    222 				utfbytes--;
    223 			} else if (utfbytes == 0)
    224 				utfbytes = -1;
    225 		}
    226 		if (utfbytes == 0) {
    227 			if (utfchar >= 0x10000 && s16idx + 2 >= s16len)
    228 				utfchar = 0xfffd;
    229 			if (utfchar >= 0x10000) {
    230 				s16[s16idx++] =
    231 				    htole16(0xd800 | ((utfchar>>10)-0x40));
    232 				s16[s16idx++] =
    233 				    htole16(0xdc00 | (utfchar & 0x3ff));
    234 			} else
    235 				s16[s16idx++] = htole16(utfchar);
    236 			if (s16idx == s16len) {
    237 				s16[--s16idx] = 0;
    238 				return;
    239 			}
    240 		}
    241 	} while (c != 0);
    242 }
    243 
    244 void
    245 le_uuid_dec(void const *buf, uuid_t *uuid)
    246 {
    247 	u_char const *p;
    248 	int i;
    249 
    250 	p = buf;
    251 	uuid->time_low = le32dec(p);
    252 	uuid->time_mid = le16dec(p + 4);
    253 	uuid->time_hi_and_version = le16dec(p + 6);
    254 	uuid->clock_seq_hi_and_reserved = p[8];
    255 	uuid->clock_seq_low = p[9];
    256 	for (i = 0; i < _UUID_NODE_LEN; i++)
    257 		uuid->node[i] = p[10 + i];
    258 }
    259 
    260 void
    261 le_uuid_enc(void *buf, uuid_t const *uuid)
    262 {
    263 	u_char *p;
    264 	int i;
    265 
    266 	p = buf;
    267 	le32enc(p, uuid->time_low);
    268 	le16enc(p + 4, uuid->time_mid);
    269 	le16enc(p + 6, uuid->time_hi_and_version);
    270 	p[8] = uuid->clock_seq_hi_and_reserved;
    271 	p[9] = uuid->clock_seq_low;
    272 	for (i = 0; i < _UUID_NODE_LEN; i++)
    273 		p[10 + i] = uuid->node[i];
    274 }
    275 
    276 int
    277 parse_uuid(const char *s, uuid_t *uuid)
    278 {
    279 	uint32_t status;
    280 
    281 	uuid_from_string(s, uuid, &status);
    282 	if (status == uuid_s_ok)
    283 		return (0);
    284 
    285 	switch (*s) {
    286 	case 'b':
    287 		if (strcmp(s, "bios") == 0) {
    288 			uuid_t bios = GPT_ENT_TYPE_BIOS;
    289 			*uuid = bios;
    290 			return (0);
    291 		}
    292 		break;
    293 	case 'c':
    294 		if (strcmp(s, "ccd") == 0) {
    295 			uuid_t ccd = GPT_ENT_TYPE_NETBSD_CCD;
    296 			*uuid = ccd;
    297 			return (0);
    298 		} else if (strcmp(s, "cgd") == 0) {
    299 			uuid_t cgd = GPT_ENT_TYPE_NETBSD_CGD;
    300 			*uuid = cgd;
    301 			return (0);
    302 		}
    303 		break;
    304 	case 'e':
    305 		if (strcmp(s, "efi") == 0) {
    306 			uuid_t efi = GPT_ENT_TYPE_EFI;
    307 			*uuid = efi;
    308 			return (0);
    309 		}
    310 		break;
    311 	case 'f':
    312 		if (strcmp(s, "ffs") == 0) {
    313 			uuid_t nb_ffs = GPT_ENT_TYPE_NETBSD_FFS;
    314 			*uuid = nb_ffs;
    315 			return (0);
    316 		}
    317 		break;
    318 	case 'h':
    319 		if (strcmp(s, "hfs") == 0) {
    320 			uuid_t hfs = GPT_ENT_TYPE_APPLE_HFS;
    321 			*uuid = hfs;
    322 			return (0);
    323 		}
    324 		break;
    325 	case 'l':
    326 		if (strcmp(s, "lfs") == 0) {
    327 			uuid_t lfs = GPT_ENT_TYPE_NETBSD_LFS;
    328 			*uuid = lfs;
    329 			return (0);
    330 		} else if (strcmp(s, "linux") == 0) {
    331 			uuid_t lnx = GPT_ENT_TYPE_MS_BASIC_DATA;
    332 			*uuid = lnx;
    333 			return (0);
    334 		}
    335 		break;
    336 	case 'r':
    337 		if (strcmp(s, "raid") == 0) {
    338 			uuid_t raid = GPT_ENT_TYPE_NETBSD_RAIDFRAME;
    339 			*uuid = raid;
    340 			return (0);
    341 		}
    342 		break;
    343 	case 's':
    344 		if (strcmp(s, "swap") == 0) {
    345 			uuid_t sw = GPT_ENT_TYPE_NETBSD_SWAP;
    346 			*uuid = sw;
    347 			return (0);
    348 		}
    349 		break;
    350 	case 'u':
    351 		if (strcmp(s, "ufs") == 0) {
    352 			uuid_t ufs = GPT_ENT_TYPE_NETBSD_FFS;
    353 			*uuid = ufs;
    354 			return (0);
    355 		}
    356 		break;
    357 	case 'w':
    358 		if (strcmp(s, "windows") == 0) {
    359 			uuid_t win = GPT_ENT_TYPE_MS_BASIC_DATA;
    360 			*uuid = win;
    361 			return (0);
    362 		}
    363 		break;
    364 	}
    365 	return (EINVAL);
    366 }
    367 
    368 void*
    369 gpt_read(int fd, off_t lba, size_t count)
    370 {
    371 	off_t ofs;
    372 	void *buf;
    373 
    374 	count *= secsz;
    375 	buf = malloc(count);
    376 	if (buf == NULL)
    377 		return (NULL);
    378 
    379 	ofs = lba * secsz;
    380 	if (lseek(fd, ofs, SEEK_SET) == ofs &&
    381 	    read(fd, buf, count) == (ssize_t)count)
    382 		return (buf);
    383 
    384 	free(buf);
    385 	return (NULL);
    386 }
    387 
    388 int
    389 gpt_write(int fd, map_t *map)
    390 {
    391 	off_t ofs;
    392 	size_t count;
    393 
    394 	count = map->map_size * secsz;
    395 	ofs = map->map_start * secsz;
    396 	if (lseek(fd, ofs, SEEK_SET) == ofs &&
    397 	    write(fd, map->map_data, count) == (ssize_t)count)
    398 		return (0);
    399 	return (-1);
    400 }
    401 
    402 static int
    403 gpt_mbr(int fd, off_t lba)
    404 {
    405 	struct mbr *mbr;
    406 	map_t *m, *p;
    407 	off_t size, start;
    408 	unsigned int i, pmbr;
    409 
    410 	mbr = gpt_read(fd, lba, 1);
    411 	if (mbr == NULL)
    412 		return (-1);
    413 
    414 	if (mbr->mbr_sig != htole16(MBR_SIG)) {
    415 		if (verbose)
    416 			warnx("%s: MBR not found at sector %llu", device_name,
    417 			    (long long)lba);
    418 		free(mbr);
    419 		return (0);
    420 	}
    421 
    422 	/*
    423 	 * Differentiate between a regular MBR and a PMBR. This is more
    424 	 * convenient in general. A PMBR is one with a single partition
    425 	 * of type 0xee.
    426 	 */
    427 	pmbr = 0;
    428 	for (i = 0; i < 4; i++) {
    429 		if (mbr->mbr_part[i].part_typ == 0)
    430 			continue;
    431 		if (mbr->mbr_part[i].part_typ == 0xee)
    432 			pmbr++;
    433 		else
    434 			break;
    435 	}
    436 	if (pmbr && i == 4 && lba == 0) {
    437 		if (pmbr != 1)
    438 			warnx("%s: Suspicious PMBR at sector %llu",
    439 			    device_name, (long long)lba);
    440 		else if (verbose > 1)
    441 			warnx("%s: PMBR at sector %llu", device_name,
    442 			    (long long)lba);
    443 		p = map_add(lba, 1LL, MAP_TYPE_PMBR, mbr);
    444 		return ((p == NULL) ? -1 : 0);
    445 	}
    446 	if (pmbr)
    447 		warnx("%s: Suspicious MBR at sector %llu", device_name,
    448 		    (long long)lba);
    449 	else if (verbose > 1)
    450 		warnx("%s: MBR at sector %llu", device_name, (long long)lba);
    451 
    452 	p = map_add(lba, 1LL, MAP_TYPE_MBR, mbr);
    453 	if (p == NULL)
    454 		return (-1);
    455 	for (i = 0; i < 4; i++) {
    456 		if (mbr->mbr_part[i].part_typ == 0 ||
    457 		    mbr->mbr_part[i].part_typ == 0xee)
    458 			continue;
    459 		start = le16toh(mbr->mbr_part[i].part_start_hi);
    460 		start = (start << 16) + le16toh(mbr->mbr_part[i].part_start_lo);
    461 		size = le16toh(mbr->mbr_part[i].part_size_hi);
    462 		size = (size << 16) + le16toh(mbr->mbr_part[i].part_size_lo);
    463 		if (start == 0 && size == 0) {
    464 			warnx("%s: Malformed MBR at sector %llu", device_name,
    465 			    (long long)lba);
    466 			continue;
    467 		}
    468 		/* start is relative to the offset of the MBR itself. */
    469 		start += lba;
    470 		if (verbose > 2)
    471 			warnx("%s: MBR part: type=%d, start=%llu, size=%llu",
    472 			    device_name, mbr->mbr_part[i].part_typ,
    473 			    (long long)start, (long long)size);
    474 		if (mbr->mbr_part[i].part_typ != 15) {
    475 			m = map_add(start, size, MAP_TYPE_MBR_PART, p);
    476 			if (m == NULL)
    477 				return (-1);
    478 			m->map_index = i + 1;
    479 		} else {
    480 			if (gpt_mbr(fd, start) == -1)
    481 				return (-1);
    482 		}
    483 	}
    484 	return (0);
    485 }
    486 
    487 #ifdef __NetBSD__
    488 static int
    489 drvctl(const char *name, u_int *sector_size, off_t *media_size)
    490 {
    491 	prop_dictionary_t command_dict, args_dict, results_dict, data_dict,
    492 	    disk_info, geometry;
    493 	prop_string_t string;
    494 	prop_number_t number;
    495 	int dfd, res;
    496 	char *dname, *p;
    497 
    498 	if ((dfd = open("/dev/drvctl", O_RDONLY)) == -1) {
    499 		warn("%s: /dev/drvctl", __func__);
    500 		return -1;
    501 	}
    502 
    503 	command_dict = prop_dictionary_create();
    504 	args_dict = prop_dictionary_create();
    505 
    506 	string = prop_string_create_cstring_nocopy("get-properties");
    507 	prop_dictionary_set(command_dict, "drvctl-command", string);
    508 	prop_object_release(string);
    509 
    510 	if ((dname = strdup(name[0] == 'r' ? name + 1 : name)) == NULL) {
    511 		(void)close(dfd);
    512 		return -1;
    513 	}
    514 	for (p = dname; *p; p++)
    515 		continue;
    516 	for (--p; p >= dname && !isdigit((unsigned char)*p); *p-- = '\0')
    517 		continue;
    518 
    519 	string = prop_string_create_cstring(dname);
    520 	free(dname);
    521 	prop_dictionary_set(args_dict, "device-name", string);
    522 	prop_object_release(string);
    523 
    524 	prop_dictionary_set(command_dict, "drvctl-arguments", args_dict);
    525 	prop_object_release(args_dict);
    526 
    527 	res = prop_dictionary_sendrecv_ioctl(command_dict, dfd, DRVCTLCOMMAND,
    528 	    &results_dict);
    529 	(void)close(dfd);
    530 	prop_object_release(command_dict);
    531 	if (res) {
    532 		warn("%s: prop_dictionary_sendrecv_ioctl", __func__);
    533 		errno = res;
    534 		return -1;
    535 	}
    536 
    537 	number = prop_dictionary_get(results_dict, "drvctl-error");
    538 	if ((errno = prop_number_integer_value(number)) != 0)
    539 		return -1;
    540 
    541 	data_dict = prop_dictionary_get(results_dict, "drvctl-result-data");
    542 	if (data_dict == NULL)
    543 		goto out;
    544 
    545 	disk_info = prop_dictionary_get(data_dict, "disk-info");
    546 	if (disk_info == NULL)
    547 		goto out;
    548 
    549 	geometry = prop_dictionary_get(disk_info, "geometry");
    550 	if (geometry == NULL)
    551 		goto out;
    552 
    553 	number = prop_dictionary_get(geometry, "sector-size");
    554 	if (number == NULL)
    555 		goto out;
    556 
    557 	*sector_size = prop_number_integer_value(number);
    558 
    559 	number = prop_dictionary_get(geometry, "sectors-per-unit");
    560 	if (number == NULL)
    561 		goto out;
    562 
    563 	*media_size = prop_number_integer_value(number) * *sector_size;
    564 
    565 	return 0;
    566 out:
    567 	errno = EINVAL;
    568 	return -1;
    569 }
    570 #endif
    571 
    572 static int
    573 gpt_gpt(int fd, off_t lba, int found)
    574 {
    575 	uuid_t type;
    576 	off_t size;
    577 	struct gpt_ent *ent;
    578 	struct gpt_hdr *hdr;
    579 	char *p, *s;
    580 	map_t *m;
    581 	size_t blocks, tblsz;
    582 	unsigned int i;
    583 	uint32_t crc;
    584 
    585 	hdr = gpt_read(fd, lba, 1);
    586 	if (hdr == NULL)
    587 		return (-1);
    588 
    589 	if (memcmp(hdr->hdr_sig, GPT_HDR_SIG, sizeof(hdr->hdr_sig)))
    590 		goto fail_hdr;
    591 
    592 	crc = le32toh(hdr->hdr_crc_self);
    593 	hdr->hdr_crc_self = 0;
    594 	if (crc32(hdr, le32toh(hdr->hdr_size)) != crc) {
    595 		if (verbose)
    596 			warnx("%s: Bad CRC in GPT header at sector %llu",
    597 			    device_name, (long long)lba);
    598 		goto fail_hdr;
    599 	}
    600 
    601 	tblsz = le32toh(hdr->hdr_entries) * le32toh(hdr->hdr_entsz);
    602 	blocks = tblsz / secsz + ((tblsz % secsz) ? 1 : 0);
    603 
    604 	/* Use generic pointer to deal with hdr->hdr_entsz != sizeof(*ent). */
    605 	p = gpt_read(fd, le64toh(hdr->hdr_lba_table), blocks);
    606 	if (p == NULL) {
    607 		if (found) {
    608 			if (verbose)
    609 				warn("%s: Cannot read LBA table at sector %llu",
    610 				    device_name, (unsigned long long)
    611 				    le64toh(hdr->hdr_lba_table));
    612 			return (-1);
    613 		}
    614 		goto fail_hdr;
    615 	}
    616 
    617 	if (crc32(p, tblsz) != le32toh(hdr->hdr_crc_table)) {
    618 		if (verbose)
    619 			warnx("%s: Bad CRC in GPT table at sector %llu",
    620 			    device_name,
    621 			    (long long)le64toh(hdr->hdr_lba_table));
    622 		goto fail_ent;
    623 	}
    624 
    625 	if (verbose > 1)
    626 		warnx("%s: %s GPT at sector %llu", device_name,
    627 		    (lba == 1) ? "Pri" : "Sec", (long long)lba);
    628 
    629 	m = map_add(lba, 1, (lba == 1)
    630 	    ? MAP_TYPE_PRI_GPT_HDR : MAP_TYPE_SEC_GPT_HDR, hdr);
    631 	if (m == NULL)
    632 		return (-1);
    633 
    634 	m = map_add(le64toh(hdr->hdr_lba_table), blocks, (lba == 1)
    635 	    ? MAP_TYPE_PRI_GPT_TBL : MAP_TYPE_SEC_GPT_TBL, p);
    636 	if (m == NULL)
    637 		return (-1);
    638 
    639 	if (lba != 1)
    640 		return (1);
    641 
    642 	for (i = 0; i < le32toh(hdr->hdr_entries); i++) {
    643 		ent = (void*)(p + i * le32toh(hdr->hdr_entsz));
    644 		if (uuid_is_nil((uuid_t *)&ent->ent_type, NULL))
    645 			continue;
    646 
    647 		size = le64toh(ent->ent_lba_end) - le64toh(ent->ent_lba_start) +
    648 		    1LL;
    649 		if (verbose > 2) {
    650 			le_uuid_dec(&ent->ent_type, &type);
    651 			uuid_to_string(&type, &s, NULL);
    652 			warnx(
    653 	"%s: GPT partition: type=%s, start=%llu, size=%llu", device_name, s,
    654 			    (long long)le64toh(ent->ent_lba_start),
    655 			    (long long)size);
    656 			free(s);
    657 		}
    658 		m = map_add(le64toh(ent->ent_lba_start), size,
    659 		    MAP_TYPE_GPT_PART, ent);
    660 		if (m == NULL)
    661 			return (-1);
    662 		m->map_index = i + 1;
    663 	}
    664 	return (1);
    665 
    666  fail_ent:
    667 	free(p);
    668 
    669  fail_hdr:
    670 	free(hdr);
    671 	return (0);
    672 }
    673 
    674 int
    675 gpt_open(const char *dev)
    676 {
    677 	struct stat sb;
    678 	int fd, mode, found;
    679 
    680 	mode = readonly ? O_RDONLY : O_RDWR|O_EXCL;
    681 
    682 	device_arg = dev;
    683 #ifdef __FreeBSD__
    684 	strlcpy(device_path, dev, sizeof(device_path));
    685 	if ((fd = open(device_path, mode)) != -1)
    686 		goto found;
    687 
    688 	snprintf(device_path, sizeof(device_path), "%s%s", _PATH_DEV, dev);
    689 	device_name = device_path + strlen(_PATH_DEV);
    690 	if ((fd = open(device_path, mode)) != -1)
    691 		goto found;
    692 	return (-1);
    693  found:
    694 #endif
    695 #ifdef __NetBSD__
    696 	device_name = device_path + strlen(_PATH_DEV);
    697 	fd = opendisk(dev, mode, device_path, sizeof(device_path), 0);
    698 	if (fd == -1)
    699 		return -1;
    700 #endif
    701 
    702 	if (fstat(fd, &sb) == -1)
    703 		goto close;
    704 
    705 	if ((sb.st_mode & S_IFMT) != S_IFREG) {
    706 #ifdef DIOCGSECTORSIZE
    707 		if (ioctl(fd, DIOCGSECTORSIZE, &secsz) == -1 ||
    708 		    ioctl(fd, DIOCGMEDIASIZE, &mediasz) == -1)
    709 			goto close;
    710 #endif
    711 #ifdef __NetBSD__
    712 		if (drvctl(device_name, &secsz, &mediasz) == -1)
    713 			goto close;
    714 #endif
    715 	} else {
    716 		secsz = 512;	/* Fixed size for files. */
    717 		if (sb.st_size % secsz) {
    718 			errno = EINVAL;
    719 			goto close;
    720 		}
    721 		mediasz = sb.st_size;
    722 	}
    723 
    724 	/*
    725 	 * We require an absolute minimum of 6 sectors. One for the MBR,
    726 	 * 2 for the GPT header, 2 for the GPT table and one to hold some
    727 	 * user data. Let's catch this extreme border case here so that
    728 	 * we don't have to worry about it later.
    729 	 */
    730 	if (mediasz / secsz < 6) {
    731 		errno = ENODEV;
    732 		goto close;
    733 	}
    734 
    735 	if (verbose)
    736 		warnx("%s: mediasize=%llu; sectorsize=%u; blocks=%llu",
    737 		    device_name, (long long)mediasz, secsz,
    738 		    (long long)(mediasz / secsz));
    739 
    740 	map_init(mediasz / secsz);
    741 
    742 	if (gpt_mbr(fd, 0LL) == -1)
    743 		goto close;
    744 	if ((found = gpt_gpt(fd, 1LL, 1)) == -1)
    745 		goto close;
    746 	if (gpt_gpt(fd, mediasz / secsz - 1LL, found) == -1)
    747 		goto close;
    748 
    749 	return (fd);
    750 
    751  close:
    752 	close(fd);
    753 	return (-1);
    754 }
    755 
    756 void
    757 gpt_close(int fd)
    758 {
    759 	/* XXX post processing? */
    760 	close(fd);
    761 }
    762 
    763 static struct {
    764 	int (*fptr)(int, char *[]);
    765 	const char *name;
    766 } cmdsw[] = {
    767 	{ cmd_add, "add" },
    768 	{ cmd_biosboot, "biosboot" },
    769 	{ cmd_create, "create" },
    770 	{ cmd_destroy, "destroy" },
    771 	{ NULL, "help" },
    772 	{ cmd_label, "label" },
    773 	{ cmd_migrate, "migrate" },
    774 	{ cmd_recover, "recover" },
    775 	{ cmd_remove, "remove" },
    776 	{ NULL, "rename" },
    777 	{ cmd_show, "show" },
    778 	{ NULL, "verify" },
    779 	{ NULL, NULL }
    780 };
    781 
    782 __dead static void
    783 usage(void)
    784 {
    785 	extern const char addmsg[], biosbootmsg[], createmsg[], destroymsg[];
    786 	extern const char labelmsg1[], labelmsg2[], labelmsg3[];
    787 	extern const char migratemsg[], recovermsg[], removemsg1[];
    788 	extern const char removemsg2[], showmsg[];
    789 
    790 	fprintf(stderr,
    791 	    "usage: %s %s\n"
    792 	    "       %s %s\n"
    793 	    "       %s %s\n"
    794 	    "       %s %s\n"
    795 	    "       %s %s\n"
    796 	    "       %s %s\n"
    797 	    "       %*s %s\n"
    798 	    "       %s %s\n"
    799 	    "       %s %s\n"
    800 	    "       %s %s\n"
    801 	    "       %s %s\n"
    802 	    "       %s %s\n",
    803 	    getprogname(), addmsg,
    804 	    getprogname(), biosbootmsg,
    805 	    getprogname(), createmsg,
    806 	    getprogname(), destroymsg,
    807 	    getprogname(), labelmsg1,
    808 	    getprogname(), labelmsg2,
    809 	    (int)strlen(getprogname()), "", labelmsg3,
    810 	    getprogname(), migratemsg,
    811 	    getprogname(), recovermsg,
    812 	    getprogname(), removemsg1,
    813 	    getprogname(), removemsg2,
    814 	    getprogname(), showmsg);
    815 	exit(1);
    816 }
    817 
    818 static void
    819 prefix(const char *cmd)
    820 {
    821 	char *pfx;
    822 	const char *prg;
    823 
    824 	prg = getprogname();
    825 	pfx = malloc(strlen(prg) + strlen(cmd) + 2);
    826 	/* Don't bother failing. It's not important */
    827 	if (pfx == NULL)
    828 		return;
    829 
    830 	sprintf(pfx, "%s %s", prg, cmd);
    831 	setprogname(pfx);
    832 }
    833 
    834 int
    835 main(int argc, char *argv[])
    836 {
    837 	char *cmd, *p;
    838 	int ch, i;
    839 
    840 	/* Get the generic options */
    841 	while ((ch = getopt(argc, argv, "p:rv")) != -1) {
    842 		switch(ch) {
    843 		case 'p':
    844 			if (parts > 0)
    845 				usage();
    846 			parts = strtoul(optarg, &p, 10);
    847 			if (*p != 0 || parts < 1)
    848 				usage();
    849 			break;
    850 		case 'r':
    851 			readonly = 1;
    852 			break;
    853 		case 'v':
    854 			verbose++;
    855 			break;
    856 		default:
    857 			usage();
    858 		}
    859 	}
    860 	if (!parts)
    861 		parts = 128;
    862 
    863 	if (argc == optind)
    864 		usage();
    865 
    866 	cmd = argv[optind++];
    867 	for (i = 0; cmdsw[i].name != NULL && strcmp(cmd, cmdsw[i].name); i++);
    868 
    869 	if (cmdsw[i].fptr == NULL)
    870 		errx(1, "unknown command: %s", cmd);
    871 
    872 	prefix(cmd);
    873 	return ((*cmdsw[i].fptr)(argc, argv));
    874 }
    875