Home | History | Annotate | Line # | Download | only in gpt
gpt.c revision 1.42
      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.42 2015/11/29 00:14:46 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 
     62 char	device_path[MAXPATHLEN];
     63 const char *device_arg;
     64 const char *device_name;
     65 
     66 off_t	mediasz;
     67 
     68 u_int	parts;
     69 u_int	secsz;
     70 
     71 int	readonly, verbose, quiet;
     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 gpt_read(int fd, off_t lba, size_t count)
    246 {
    247 	off_t ofs;
    248 	void *buf;
    249 
    250 	count *= secsz;
    251 	buf = malloc(count);
    252 	if (buf == NULL)
    253 		return (NULL);
    254 
    255 	ofs = lba * secsz;
    256 	if (lseek(fd, ofs, SEEK_SET) == ofs &&
    257 	    read(fd, buf, count) == (ssize_t)count)
    258 		return (buf);
    259 
    260 	free(buf);
    261 	return (NULL);
    262 }
    263 
    264 int
    265 gpt_write(int fd, map_t *map)
    266 {
    267 	off_t ofs;
    268 	size_t count;
    269 
    270 	count = map->map_size * secsz;
    271 	ofs = map->map_start * secsz;
    272 	if (lseek(fd, ofs, SEEK_SET) == ofs &&
    273 	    write(fd, map->map_data, count) == (ssize_t)count)
    274 		return (0);
    275 	return (-1);
    276 }
    277 
    278 static int
    279 gpt_mbr(int fd, off_t lba)
    280 {
    281 	struct mbr *mbr;
    282 	map_t *m, *p;
    283 	off_t size, start;
    284 	unsigned int i, pmbr;
    285 
    286 	mbr = gpt_read(fd, lba, 1);
    287 	if (mbr == NULL) {
    288 		if (!quiet)
    289 			warn("%s: read failed", device_name);
    290 		return (-1);
    291 	}
    292 
    293 	if (mbr->mbr_sig != htole16(MBR_SIG)) {
    294 		if (verbose)
    295 			gpt_msg("MBR not found at sector %ju", (uintmax_t)lba);
    296 		free(mbr);
    297 		return (0);
    298 	}
    299 
    300 	/*
    301 	 * Differentiate between a regular MBR and a PMBR. This is more
    302 	 * convenient in general. A PMBR is one with a single partition
    303 	 * of type 0xee.
    304 	 */
    305 	pmbr = 0;
    306 	for (i = 0; i < 4; i++) {
    307 		if (mbr->mbr_part[i].part_typ == MBR_PTYPE_UNUSED)
    308 			continue;
    309 		if (mbr->mbr_part[i].part_typ == MBR_PTYPE_PMBR)
    310 			pmbr++;
    311 		else
    312 			break;
    313 	}
    314 	if (pmbr && i == 4 && lba == 0) {
    315 		if (pmbr != 1 && !quiet)
    316 			warnx("%s: Suspicious PMBR at sector %ju",
    317 			    device_name, (uintmax_t)lba);
    318 		else if (verbose > 1)
    319 			gpt_msg("PMBR at sector %ju", (uintmax_t)lba);
    320 		p = map_add(lba, 1LL, MAP_TYPE_PMBR, mbr);
    321 		return ((p == NULL) ? -1 : 0);
    322 	}
    323 	if (pmbr && !quiet)
    324 		warnx("%s: Suspicious MBR at sector %ju", device_name,
    325 		    (uintmax_t)lba);
    326 	else if (verbose > 1)
    327 		gpt_msg("MBR at sector %ju", (uintmax_t)lba);
    328 
    329 	p = map_add(lba, 1LL, MAP_TYPE_MBR, mbr);
    330 	if (p == NULL)
    331 		return (-1);
    332 	for (i = 0; i < 4; i++) {
    333 		if (mbr->mbr_part[i].part_typ == MBR_PTYPE_UNUSED ||
    334 		    mbr->mbr_part[i].part_typ == MBR_PTYPE_PMBR)
    335 			continue;
    336 		start = le16toh(mbr->mbr_part[i].part_start_hi);
    337 		start = (start << 16) + le16toh(mbr->mbr_part[i].part_start_lo);
    338 		size = le16toh(mbr->mbr_part[i].part_size_hi);
    339 		size = (size << 16) + le16toh(mbr->mbr_part[i].part_size_lo);
    340 		if (start == 0 && size == 0) {
    341 			warnx("%s: Malformed MBR at sector %llu", device_name,
    342 			    (long long)lba);
    343 			continue;
    344 		}
    345 		/* start is relative to the offset of the MBR itself. */
    346 		start += lba;
    347 		if (verbose > 2)
    348 			gpt_msg("MBR part: type=%d, start=%ju, size=%ju",
    349 			    mbr->mbr_part[i].part_typ,
    350 			    (uintmax_t)start, (uintmax_t)size);
    351 		if (mbr->mbr_part[i].part_typ != MBR_PTYPE_EXT_LBA) {
    352 			m = map_add(start, size, MAP_TYPE_MBR_PART, p);
    353 			if (m == NULL)
    354 				return (-1);
    355 			m->map_index = i + 1;
    356 		} else {
    357 			if (gpt_mbr(fd, start) == -1)
    358 				return (-1);
    359 		}
    360 	}
    361 	return (0);
    362 }
    363 
    364 int
    365 gpt_gpt(int fd, off_t lba, int found)
    366 {
    367 	off_t size;
    368 	struct gpt_ent *ent;
    369 	struct gpt_hdr *hdr;
    370 	char *p;
    371 	map_t *m;
    372 	size_t blocks, tblsz;
    373 	unsigned int i;
    374 	uint32_t crc;
    375 
    376 	hdr = gpt_read(fd, lba, 1);
    377 	if (hdr == NULL)
    378 		return (-1);
    379 
    380 	if (memcmp(hdr->hdr_sig, GPT_HDR_SIG, sizeof(hdr->hdr_sig)))
    381 		goto fail_hdr;
    382 
    383 	crc = le32toh(hdr->hdr_crc_self);
    384 	hdr->hdr_crc_self = 0;
    385 	if (crc32(hdr, le32toh(hdr->hdr_size)) != crc) {
    386 		if (verbose)
    387 			warnx("%s: Bad CRC in GPT header at sector %llu",
    388 			    device_name, (long long)lba);
    389 		goto fail_hdr;
    390 	}
    391 
    392 	tblsz = le32toh(hdr->hdr_entries) * le32toh(hdr->hdr_entsz);
    393 	blocks = tblsz / secsz + ((tblsz % secsz) ? 1 : 0);
    394 
    395 	/* Use generic pointer to deal with hdr->hdr_entsz != sizeof(*ent). */
    396 	p = gpt_read(fd, le64toh(hdr->hdr_lba_table), blocks);
    397 	if (p == NULL) {
    398 		if (found) {
    399 			if (verbose)
    400 				warn("%s: Cannot read LBA table at sector %llu",
    401 				    device_name, (unsigned long long)
    402 				    le64toh(hdr->hdr_lba_table));
    403 			return (-1);
    404 		}
    405 		goto fail_hdr;
    406 	}
    407 
    408 	if (crc32(p, tblsz) != le32toh(hdr->hdr_crc_table)) {
    409 		if (verbose)
    410 			warnx("%s: Bad CRC in GPT table at sector %llu",
    411 			    device_name,
    412 			    (long long)le64toh(hdr->hdr_lba_table));
    413 		goto fail_ent;
    414 	}
    415 
    416 	if (verbose > 1)
    417 		warnx("%s: %s GPT at sector %llu", device_name,
    418 		    (lba == 1) ? "Pri" : "Sec", (long long)lba);
    419 
    420 	m = map_add(lba, 1, (lba == 1)
    421 	    ? MAP_TYPE_PRI_GPT_HDR : MAP_TYPE_SEC_GPT_HDR, hdr);
    422 	if (m == NULL)
    423 		return (-1);
    424 
    425 	m = map_add(le64toh(hdr->hdr_lba_table), blocks, (lba == 1)
    426 	    ? MAP_TYPE_PRI_GPT_TBL : MAP_TYPE_SEC_GPT_TBL, p);
    427 	if (m == NULL)
    428 		return (-1);
    429 
    430 	if (lba != 1)
    431 		return (1);
    432 
    433 	for (i = 0; i < le32toh(hdr->hdr_entries); i++) {
    434 		ent = (void*)(p + i * le32toh(hdr->hdr_entsz));
    435 		if (gpt_uuid_is_nil(ent->ent_type))
    436 			continue;
    437 
    438 		size = le64toh(ent->ent_lba_end) - le64toh(ent->ent_lba_start) +
    439 		    1LL;
    440 		if (verbose > 2) {
    441 			char buf[128];
    442 			gpt_uuid_snprintf(buf, sizeof(buf), "%s",
    443 			    ent->ent_type);
    444 			warnx("%s: GPT partition: type=%s, start=%llu, "
    445 			    "size=%llu", device_name, buf,
    446 			    (long long)le64toh(ent->ent_lba_start),
    447 			    (long long)size);
    448 		}
    449 		m = map_add(le64toh(ent->ent_lba_start), size,
    450 		    MAP_TYPE_GPT_PART, ent);
    451 		if (m == NULL)
    452 			return (-1);
    453 		m->map_index = i + 1;
    454 	}
    455 	return (1);
    456 
    457  fail_ent:
    458 	free(p);
    459 
    460  fail_hdr:
    461 	free(hdr);
    462 	return (0);
    463 }
    464 
    465 int
    466 gpt_open(const char *dev, int flags)
    467 {
    468 	struct stat sb;
    469 	int fd, mode, found;
    470 
    471 	mode = readonly ? O_RDONLY : O_RDWR|O_EXCL;
    472 
    473 	device_arg = device_name = dev;
    474 	fd = opendisk(dev, mode, device_path, sizeof(device_path), 0);
    475 	if (fd == -1) {
    476 		if (!quiet)
    477 			warn("Cannot open `%s'", device_name);
    478 		return -1;
    479 	}
    480 	device_name = device_path;
    481 
    482 	if (fstat(fd, &sb) == -1) {
    483 		if (!quiet)
    484 			warn("Cannot stat `%s'", device_name);
    485 		goto close;
    486 	}
    487 
    488 	if ((sb.st_mode & S_IFMT) != S_IFREG) {
    489 		if (secsz == 0) {
    490 			if (ioctl(fd, DIOCGSECTORSIZE, &secsz) == -1) {
    491 				if (!quiet)
    492 					warn("Cannot get sector size for `%s'",
    493 					    device_name);
    494 				goto close;
    495 			}
    496 			if (secsz == 0) {
    497 				if (!quiet)
    498 					warnx("Sector size for `%s' can't be 0",
    499 					    device_name);
    500 				goto close;
    501 			}
    502 		}
    503 		if (mediasz == 0) {
    504 			if (ioctl(fd, DIOCGMEDIASIZE, &mediasz) == -1) {
    505 				if (!quiet)
    506 					warn("Cannot get media size for `%s'",
    507 					device_name);
    508 				goto close;
    509 			}
    510 			if (mediasz == 0) {
    511 				if (!quiet)
    512 					warnx("Media size for `%s' can't be 0",
    513 					    device_name);
    514 				goto close;
    515 			}
    516 		}
    517 	} else {
    518 		if (secsz == 0)
    519 			secsz = 512;	/* Fixed size for files. */
    520 		if (mediasz == 0) {
    521 			if (sb.st_size % secsz) {
    522 				errno = EINVAL;
    523 				goto close;
    524 			}
    525 			mediasz = sb.st_size;
    526 		}
    527 	}
    528 
    529 	/*
    530 	 * We require an absolute minimum of 6 sectors. One for the MBR,
    531 	 * 2 for the GPT header, 2 for the GPT table and one to hold some
    532 	 * user data. Let's catch this extreme border case here so that
    533 	 * we don't have to worry about it later.
    534 	 */
    535 	if (mediasz / secsz < 6) {
    536 		if (!quiet)
    537 			warnx("Need 6 sectors on '%s' we have %llu",
    538 			    device_name, (unsigned long long)(mediasz / secsz));
    539 		goto close;
    540 	}
    541 
    542 	if (verbose) {
    543 		gpt_msg("mediasize=%ju; sectorsize=%u; blocks=%ju",
    544 		    (uintmax_t)mediasz, secsz, (uintmax_t)(mediasz / secsz));
    545 	}
    546 
    547 	map_init(mediasz / secsz);
    548 
    549 	if (gpt_mbr(fd, 0LL) == -1)
    550 		goto close;
    551 	if ((found = gpt_gpt(fd, 1LL, 1)) == -1)
    552 		goto close;
    553 	if (gpt_gpt(fd, mediasz / secsz - 1LL, found) == -1)
    554 		goto close;
    555 
    556 	return (fd);
    557 
    558  close:
    559 	close(fd);
    560 	return (-1);
    561 }
    562 
    563 void
    564 gpt_close(int fd)
    565 {
    566 	/* XXX post processing? */
    567 	close(fd);
    568 }
    569 
    570 void
    571 gpt_msg(const char *fmt, ...)
    572 {
    573 	va_list ap;
    574 	printf("%s: ", device_name);
    575 	va_start(ap, fmt);
    576 	vprintf(fmt, ap);
    577 	va_end(ap);
    578 	printf("\n");
    579 }
    580 
    581 static struct {
    582 	int (*fptr)(int, char *[]);
    583 	const char *name;
    584 } cmdsw[] = {
    585 	{ cmd_add, "add" },
    586 #ifndef HAVE_NBTOOL_CONFIG_H
    587 	{ cmd_backup, "backup" },
    588 #endif
    589 	{ cmd_biosboot, "biosboot" },
    590 	{ cmd_create, "create" },
    591 	{ cmd_destroy, "destroy" },
    592 	{ cmd_header, "header" },
    593 	{ NULL, "help" },
    594 	{ cmd_label, "label" },
    595 	{ cmd_migrate, "migrate" },
    596 	{ cmd_recover, "recover" },
    597 	{ cmd_remove, "remove" },
    598 	{ NULL, "rename" },
    599 	{ cmd_resize, "resize" },
    600 	{ cmd_resizedisk, "resizedisk" },
    601 #ifndef HAVE_NBTOOL_CONFIG_H
    602 	{ cmd_restore, "restore" },
    603 #endif
    604 	{ cmd_set, "set" },
    605 	{ cmd_show, "show" },
    606 	{ cmd_type, "type" },
    607 	{ cmd_unset, "unset" },
    608 	{ NULL, "verify" },
    609 	{ NULL, NULL }
    610 };
    611 
    612 __dead static void
    613 usage(void)
    614 {
    615 	extern const char addmsg1[], addmsg2[], biosbootmsg[];
    616 	extern const char createmsg[], destroymsg[], headermsg[], labelmsg1[];
    617 	extern const char labelmsg2[], labelmsg3[], migratemsg[], recovermsg[];
    618 	extern const char removemsg1[], removemsg2[], resizemsg[];
    619 	extern const char resizediskmsg[], setmsg[], showmsg[], typemsg1[];
    620 	extern const char typemsg2[], typemsg3[], unsetmsg[];
    621 #ifndef HAVE_NBTOOL_CONFIG_H
    622 	extern const char backupmsg[], restoremsg[];
    623 #endif
    624 	const char *p = getprogname();
    625 	const char *f =
    626 	    "[-rv] [-m <mediasize>] [-p <partitionnum>] [-s <sectorsize>]";
    627 
    628 	fprintf(stderr,
    629 	    "Usage: %s %s <command> [<args>]\n", p, f);
    630 	fprintf(stderr,
    631 	    "Commands:\n"
    632 #ifndef HAVE_NBTOOL_CONFIG_H
    633 	    "       %s\n"
    634 	    "       %s\n"
    635 #endif
    636 	    "       %s\n"
    637 	    "       %s\n"
    638 	    "       %s\n"
    639 	    "       %s\n"
    640 	    "       %s\n"
    641 	    "       %s\n"
    642 	    "       %s\n"
    643 	    "       %s\n"
    644 	    "       %s\n"
    645 	    "       %s\n"
    646 	    "       %s\n"
    647 	    "       %s\n"
    648 	    "       %s\n"
    649 	    "       %s\n"
    650 	    "       %s\n"
    651 	    "       %s\n"
    652 	    "       %s\n"
    653 	    "       %s\n"
    654 	    "       %s\n"
    655 	    "       %s\n"
    656 	    "       %s\n",
    657 	    addmsg1, addmsg2,
    658 #ifndef HAVE_NBTOOL_CONFIG_H
    659 	    backupmsg,
    660 #endif
    661 	    biosbootmsg, createmsg, destroymsg,
    662 	    headermsg, labelmsg1, labelmsg2, labelmsg3,
    663 	    migratemsg, recovermsg,
    664 	    removemsg1, removemsg2,
    665 	    resizemsg, resizediskmsg,
    666 #ifndef HAVE_NBTOOL_CONFIG_H
    667 	    restoremsg,
    668 #endif
    669 	    setmsg, showmsg,
    670 	    typemsg1, typemsg2, typemsg3,
    671 	    unsetmsg);
    672 	exit(1);
    673 }
    674 
    675 static void
    676 prefix(const char *cmd)
    677 {
    678 	char *pfx;
    679 	const char *prg;
    680 
    681 	prg = getprogname();
    682 	pfx = malloc(strlen(prg) + strlen(cmd) + 2);
    683 	/* Don't bother failing. It's not important */
    684 	if (pfx == NULL)
    685 		return;
    686 
    687 	sprintf(pfx, "%s %s", prg, cmd);
    688 	setprogname(pfx);
    689 }
    690 
    691 int
    692 main(int argc, char *argv[])
    693 {
    694 	char *cmd, *p;
    695 	int ch, i;
    696 
    697 	/* Get the generic options */
    698 	while ((ch = getopt(argc, argv, "m:p:qrs:v")) != -1) {
    699 		switch(ch) {
    700 		case 'm':
    701 			if (mediasz > 0)
    702 				usage();
    703 			mediasz = strtoul(optarg, &p, 10);
    704 			if (*p != 0 || mediasz < 1)
    705 				usage();
    706 			break;
    707 		case 'p':
    708 			if (parts > 0)
    709 				usage();
    710 			parts = strtoul(optarg, &p, 10);
    711 			if (*p != 0 || parts < 1)
    712 				usage();
    713 			break;
    714 		case 'r':
    715 			readonly = 1;
    716 			break;
    717 		case 'q':
    718 			quiet = 1;
    719 			break;
    720 		case 's':
    721 			if (secsz > 0)
    722 				usage();
    723 			secsz = strtoul(optarg, &p, 10);
    724 			if (*p != 0 || secsz < 1)
    725 				usage();
    726 			break;
    727 		case 'v':
    728 			verbose++;
    729 			break;
    730 		default:
    731 			usage();
    732 		}
    733 	}
    734 	if (!parts)
    735 		parts = 128;
    736 
    737 	if (argc == optind)
    738 		usage();
    739 
    740 	cmd = argv[optind++];
    741 	for (i = 0; cmdsw[i].name != NULL && strcmp(cmd, cmdsw[i].name); i++);
    742 
    743 	if (cmdsw[i].fptr == NULL)
    744 		errx(1, "unknown command: %s", cmd);
    745 
    746 	prefix(cmd);
    747 	return ((*cmdsw[i].fptr)(argc, argv));
    748 }
    749