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