Home | History | Annotate | Line # | Download | only in gpt
gpt.c revision 1.48
      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.48 2015/12/01 02:03:55 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, nosync;
     72 
     73 static int modified;
     74 
     75 static uint32_t crc32_tab[] = {
     76 	0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
     77 	0xe963a535, 0x9e6495a3,	0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
     78 	0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
     79 	0xf3b97148, 0x84be41de,	0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
     80 	0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,	0x14015c4f, 0x63066cd9,
     81 	0xfa0f3d63, 0x8d080df5,	0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
     82 	0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,	0x35b5a8fa, 0x42b2986c,
     83 	0xdbbbc9d6, 0xacbcf940,	0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
     84 	0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
     85 	0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
     86 	0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,	0x76dc4190, 0x01db7106,
     87 	0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
     88 	0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
     89 	0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
     90 	0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
     91 	0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
     92 	0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
     93 	0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
     94 	0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
     95 	0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
     96 	0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
     97 	0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
     98 	0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
     99 	0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
    100 	0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
    101 	0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
    102 	0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
    103 	0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
    104 	0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
    105 	0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
    106 	0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
    107 	0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
    108 	0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
    109 	0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
    110 	0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
    111 	0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
    112 	0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
    113 	0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
    114 	0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
    115 	0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
    116 	0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
    117 	0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
    118 	0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
    119 };
    120 
    121 uint32_t
    122 crc32(const void *buf, size_t size)
    123 {
    124 	const uint8_t *p;
    125 	uint32_t crc;
    126 
    127 	p = buf;
    128 	crc = ~0U;
    129 
    130 	while (size--)
    131 		crc = crc32_tab[(crc ^ *p++) & 0xFF] ^ (crc >> 8);
    132 
    133 	return crc ^ ~0U;
    134 }
    135 
    136 uint8_t *
    137 utf16_to_utf8(uint16_t *s16)
    138 {
    139 	static uint8_t *s8 = NULL;
    140 	static size_t s8len = 0;
    141 	size_t s8idx, s16idx, s16len;
    142 	uint32_t utfchar;
    143 	unsigned int c;
    144 
    145 	s16len = 0;
    146 	while (s16[s16len++] != 0)
    147 		;
    148 	if (s8len < s16len * 3) {
    149 		if (s8 != NULL)
    150 			free(s8);
    151 		s8len = s16len * 3;
    152 		s8 = calloc(s16len, 3);
    153 	}
    154 	s8idx = s16idx = 0;
    155 	while (s16idx < s16len) {
    156 		utfchar = le16toh(s16[s16idx++]);
    157 		if ((utfchar & 0xf800) == 0xd800) {
    158 			c = le16toh(s16[s16idx]);
    159 			if ((utfchar & 0x400) != 0 || (c & 0xfc00) != 0xdc00)
    160 				utfchar = 0xfffd;
    161 			else
    162 				s16idx++;
    163 		}
    164 		if (utfchar < 0x80) {
    165 			s8[s8idx++] = utfchar;
    166 		} else if (utfchar < 0x800) {
    167 			s8[s8idx++] = 0xc0 | (utfchar >> 6);
    168 			s8[s8idx++] = 0x80 | (utfchar & 0x3f);
    169 		} else if (utfchar < 0x10000) {
    170 			s8[s8idx++] = 0xe0 | (utfchar >> 12);
    171 			s8[s8idx++] = 0x80 | ((utfchar >> 6) & 0x3f);
    172 			s8[s8idx++] = 0x80 | (utfchar & 0x3f);
    173 		} else if (utfchar < 0x200000) {
    174 			s8[s8idx++] = 0xf0 | (utfchar >> 18);
    175 			s8[s8idx++] = 0x80 | ((utfchar >> 12) & 0x3f);
    176 			s8[s8idx++] = 0x80 | ((utfchar >> 6) & 0x3f);
    177 			s8[s8idx++] = 0x80 | (utfchar & 0x3f);
    178 		}
    179 	}
    180 	return (s8);
    181 }
    182 
    183 void
    184 utf8_to_utf16(const uint8_t *s8, uint16_t *s16, size_t s16len)
    185 {
    186 	size_t s16idx, s8idx, s8len;
    187 	uint32_t utfchar = 0;
    188 	unsigned int c, utfbytes;
    189 
    190 	s8len = 0;
    191 	while (s8[s8len++] != 0)
    192 		;
    193 	s8idx = s16idx = 0;
    194 	utfbytes = 0;
    195 	do {
    196 		c = s8[s8idx++];
    197 		if ((c & 0xc0) != 0x80) {
    198 			/* Initial characters. */
    199 			if (utfbytes != 0) {
    200 				/* Incomplete encoding. */
    201 				s16[s16idx++] = htole16(0xfffd);
    202 				if (s16idx == s16len) {
    203 					s16[--s16idx] = 0;
    204 					return;
    205 				}
    206 			}
    207 			if ((c & 0xf8) == 0xf0) {
    208 				utfchar = c & 0x07;
    209 				utfbytes = 3;
    210 			} else if ((c & 0xf0) == 0xe0) {
    211 				utfchar = c & 0x0f;
    212 				utfbytes = 2;
    213 			} else if ((c & 0xe0) == 0xc0) {
    214 				utfchar = c & 0x1f;
    215 				utfbytes = 1;
    216 			} else {
    217 				utfchar = c & 0x7f;
    218 				utfbytes = 0;
    219 			}
    220 		} else {
    221 			/* Followup characters. */
    222 			if (utfbytes > 0) {
    223 				utfchar = (utfchar << 6) + (c & 0x3f);
    224 				utfbytes--;
    225 			} else if (utfbytes == 0)
    226 				utfbytes = -1;
    227 		}
    228 		if (utfbytes == 0) {
    229 			if (utfchar >= 0x10000 && s16idx + 2 >= s16len)
    230 				utfchar = 0xfffd;
    231 			if (utfchar >= 0x10000) {
    232 				s16[s16idx++] =
    233 				    htole16(0xd800 | ((utfchar>>10)-0x40));
    234 				s16[s16idx++] =
    235 				    htole16(0xdc00 | (utfchar & 0x3ff));
    236 			} else
    237 				s16[s16idx++] = htole16(utfchar);
    238 			if (s16idx == s16len) {
    239 				s16[--s16idx] = 0;
    240 				return;
    241 			}
    242 		}
    243 	} while (c != 0);
    244 }
    245 
    246 void*
    247 gpt_read(int fd, off_t lba, size_t count)
    248 {
    249 	off_t ofs;
    250 	void *buf;
    251 
    252 	count *= secsz;
    253 	buf = malloc(count);
    254 	if (buf == NULL)
    255 		return (NULL);
    256 
    257 	ofs = lba * secsz;
    258 	if (lseek(fd, ofs, SEEK_SET) == ofs &&
    259 	    read(fd, buf, count) == (ssize_t)count)
    260 		return (buf);
    261 
    262 	free(buf);
    263 	return (NULL);
    264 }
    265 
    266 int
    267 gpt_write(int fd, map_t *map)
    268 {
    269 	off_t ofs;
    270 	size_t count;
    271 
    272 	count = map->map_size * secsz;
    273 	ofs = map->map_start * secsz;
    274 	if (lseek(fd, ofs, SEEK_SET) != ofs ||
    275 	    write(fd, map->map_data, count) != (ssize_t)count)
    276 		return -1;
    277 	modified = 1;
    278 	return 0;
    279 }
    280 
    281 static int
    282 gpt_mbr(int fd, off_t lba)
    283 {
    284 	struct mbr *mbr;
    285 	map_t *m, *p;
    286 	off_t size, start;
    287 	unsigned int i, pmbr;
    288 
    289 	mbr = gpt_read(fd, lba, 1);
    290 	if (mbr == NULL) {
    291 		if (!quiet)
    292 			warn("%s: read failed", device_name);
    293 		return (-1);
    294 	}
    295 
    296 	if (mbr->mbr_sig != htole16(MBR_SIG)) {
    297 		if (verbose)
    298 			gpt_msg("MBR not found at sector %ju", (uintmax_t)lba);
    299 		free(mbr);
    300 		return (0);
    301 	}
    302 
    303 	/*
    304 	 * Differentiate between a regular MBR and a PMBR. This is more
    305 	 * convenient in general. A PMBR is one with a single partition
    306 	 * of type 0xee.
    307 	 */
    308 	pmbr = 0;
    309 	for (i = 0; i < 4; i++) {
    310 		if (mbr->mbr_part[i].part_typ == MBR_PTYPE_UNUSED)
    311 			continue;
    312 		if (mbr->mbr_part[i].part_typ == MBR_PTYPE_PMBR)
    313 			pmbr++;
    314 		else
    315 			break;
    316 	}
    317 	if (pmbr && i == 4 && lba == 0) {
    318 		if (pmbr != 1 && !quiet)
    319 			warnx("%s: Suspicious PMBR at sector %ju",
    320 			    device_name, (uintmax_t)lba);
    321 		else if (verbose > 1)
    322 			gpt_msg("PMBR at sector %ju", (uintmax_t)lba);
    323 		p = map_add(lba, 1LL, MAP_TYPE_PMBR, mbr);
    324 		return ((p == NULL) ? -1 : 0);
    325 	}
    326 	if (pmbr && !quiet)
    327 		warnx("%s: Suspicious MBR at sector %ju", device_name,
    328 		    (uintmax_t)lba);
    329 	else if (verbose > 1)
    330 		gpt_msg("MBR at sector %ju", (uintmax_t)lba);
    331 
    332 	p = map_add(lba, 1LL, MAP_TYPE_MBR, mbr);
    333 	if (p == NULL)
    334 		return (-1);
    335 	for (i = 0; i < 4; i++) {
    336 		if (mbr->mbr_part[i].part_typ == MBR_PTYPE_UNUSED ||
    337 		    mbr->mbr_part[i].part_typ == MBR_PTYPE_PMBR)
    338 			continue;
    339 		start = le16toh(mbr->mbr_part[i].part_start_hi);
    340 		start = (start << 16) + le16toh(mbr->mbr_part[i].part_start_lo);
    341 		size = le16toh(mbr->mbr_part[i].part_size_hi);
    342 		size = (size << 16) + le16toh(mbr->mbr_part[i].part_size_lo);
    343 		if (start == 0 && size == 0) {
    344 			warnx("%s: Malformed MBR at sector %llu", device_name,
    345 			    (long long)lba);
    346 			continue;
    347 		}
    348 		/* start is relative to the offset of the MBR itself. */
    349 		start += lba;
    350 		if (verbose > 2)
    351 			gpt_msg("MBR part: type=%d, start=%ju, size=%ju",
    352 			    mbr->mbr_part[i].part_typ,
    353 			    (uintmax_t)start, (uintmax_t)size);
    354 		if (mbr->mbr_part[i].part_typ != MBR_PTYPE_EXT_LBA) {
    355 			m = map_add(start, size, MAP_TYPE_MBR_PART, p);
    356 			if (m == NULL)
    357 				return (-1);
    358 			m->map_index = i + 1;
    359 		} else {
    360 			if (gpt_mbr(fd, start) == -1)
    361 				return (-1);
    362 		}
    363 	}
    364 	return (0);
    365 }
    366 
    367 int
    368 gpt_gpt(int fd, off_t lba, int found)
    369 {
    370 	off_t size;
    371 	struct gpt_ent *ent;
    372 	struct gpt_hdr *hdr;
    373 	char *p;
    374 	map_t *m;
    375 	size_t blocks, tblsz;
    376 	unsigned int i;
    377 	uint32_t crc;
    378 
    379 	hdr = gpt_read(fd, lba, 1);
    380 	if (hdr == NULL)
    381 		return (-1);
    382 
    383 	if (memcmp(hdr->hdr_sig, GPT_HDR_SIG, sizeof(hdr->hdr_sig)))
    384 		goto fail_hdr;
    385 
    386 	crc = le32toh(hdr->hdr_crc_self);
    387 	hdr->hdr_crc_self = 0;
    388 	if (crc32(hdr, le32toh(hdr->hdr_size)) != crc) {
    389 		if (verbose)
    390 			warnx("%s: Bad CRC in GPT header at sector %llu",
    391 			    device_name, (long long)lba);
    392 		goto fail_hdr;
    393 	}
    394 
    395 	tblsz = le32toh(hdr->hdr_entries) * le32toh(hdr->hdr_entsz);
    396 	blocks = tblsz / secsz + ((tblsz % secsz) ? 1 : 0);
    397 
    398 	/* Use generic pointer to deal with hdr->hdr_entsz != sizeof(*ent). */
    399 	p = gpt_read(fd, le64toh(hdr->hdr_lba_table), blocks);
    400 	if (p == NULL) {
    401 		if (found) {
    402 			if (verbose)
    403 				warn("%s: Cannot read LBA table at sector %llu",
    404 				    device_name, (unsigned long long)
    405 				    le64toh(hdr->hdr_lba_table));
    406 			return (-1);
    407 		}
    408 		goto fail_hdr;
    409 	}
    410 
    411 	if (crc32(p, tblsz) != le32toh(hdr->hdr_crc_table)) {
    412 		if (verbose)
    413 			warnx("%s: Bad CRC in GPT table at sector %llu",
    414 			    device_name,
    415 			    (long long)le64toh(hdr->hdr_lba_table));
    416 		goto fail_ent;
    417 	}
    418 
    419 	if (verbose > 1)
    420 		warnx("%s: %s GPT at sector %llu", device_name,
    421 		    (lba == 1) ? "Pri" : "Sec", (long long)lba);
    422 
    423 	m = map_add(lba, 1, (lba == 1)
    424 	    ? MAP_TYPE_PRI_GPT_HDR : MAP_TYPE_SEC_GPT_HDR, hdr);
    425 	if (m == NULL)
    426 		return (-1);
    427 
    428 	m = map_add(le64toh(hdr->hdr_lba_table), blocks, (lba == 1)
    429 	    ? MAP_TYPE_PRI_GPT_TBL : MAP_TYPE_SEC_GPT_TBL, p);
    430 	if (m == NULL)
    431 		return (-1);
    432 
    433 	if (lba != 1)
    434 		return (1);
    435 
    436 	for (i = 0; i < le32toh(hdr->hdr_entries); i++) {
    437 		ent = (void*)(p + i * le32toh(hdr->hdr_entsz));
    438 		if (gpt_uuid_is_nil(ent->ent_type))
    439 			continue;
    440 
    441 		size = le64toh(ent->ent_lba_end) - le64toh(ent->ent_lba_start) +
    442 		    1LL;
    443 		if (verbose > 2) {
    444 			char buf[128];
    445 			gpt_uuid_snprintf(buf, sizeof(buf), "%s",
    446 			    ent->ent_type);
    447 			warnx("%s: GPT partition: type=%s, start=%llu, "
    448 			    "size=%llu", device_name, buf,
    449 			    (long long)le64toh(ent->ent_lba_start),
    450 			    (long long)size);
    451 		}
    452 		m = map_add(le64toh(ent->ent_lba_start), size,
    453 		    MAP_TYPE_GPT_PART, ent);
    454 		if (m == NULL)
    455 			return (-1);
    456 		m->map_index = i + 1;
    457 	}
    458 	return (1);
    459 
    460  fail_ent:
    461 	free(p);
    462 
    463  fail_hdr:
    464 	free(hdr);
    465 	return (0);
    466 }
    467 
    468 int
    469 gpt_open(const char *dev, int flags)
    470 {
    471 	struct stat sb;
    472 	int fd, mode, found;
    473 	off_t devsz;
    474 
    475 	mode = readonly ? O_RDONLY : O_RDWR|O_EXCL;
    476 
    477 	device_arg = device_name = dev;
    478 	fd = opendisk(dev, mode, device_path, sizeof(device_path), 0);
    479 	if (fd == -1) {
    480 		if (!quiet)
    481 			warn("Cannot open `%s'", device_name);
    482 		return -1;
    483 	}
    484 	device_name = device_path;
    485 
    486 	if (fstat(fd, &sb) == -1) {
    487 		if (!quiet)
    488 			warn("Cannot stat `%s'", device_name);
    489 		goto close;
    490 	}
    491 
    492 	if ((sb.st_mode & S_IFMT) != S_IFREG) {
    493 		if (secsz == 0) {
    494 #ifdef DIOCGSECTORSIZE
    495 			if (ioctl(fd, DIOCGSECTORSIZE, &secsz) == -1) {
    496 				if (!quiet)
    497 					warn("Cannot get sector size for `%s'",
    498 					    device_name);
    499 				goto close;
    500 			}
    501 #endif
    502 			if (secsz == 0) {
    503 				if (!quiet)
    504 					warnx("Sector size for `%s' can't be 0",
    505 					    device_name);
    506 				goto close;
    507 			}
    508 		}
    509 		if (mediasz == 0) {
    510 #ifdef DIOCGMEDIASIZE
    511 			if (ioctl(fd, DIOCGMEDIASIZE, &mediasz) == -1) {
    512 				if (!quiet)
    513 					warn("Cannot get media size for `%s'",
    514 					device_name);
    515 				goto close;
    516 			}
    517 #endif
    518 			if (mediasz == 0) {
    519 				if (!quiet)
    520 					warnx("Media size for `%s' can't be 0",
    521 					    device_name);
    522 				goto close;
    523 			}
    524 		}
    525 	} else {
    526 		if (secsz == 0)
    527 			secsz = 512;	/* Fixed size for files. */
    528 		if (mediasz == 0) {
    529 			if (sb.st_size % secsz) {
    530 				errno = EINVAL;
    531 				goto close;
    532 			}
    533 			mediasz = sb.st_size;
    534 		}
    535 	}
    536 
    537 	/*
    538 	 * We require an absolute minimum of 6 sectors. One for the MBR,
    539 	 * 2 for the GPT header, 2 for the GPT table and one to hold some
    540 	 * user data. Let's catch this extreme border case here so that
    541 	 * we don't have to worry about it later.
    542 	 */
    543 	devsz = mediasz / secsz;
    544 	if (devsz < 6) {
    545 		if (!quiet)
    546 			warnx("Need 6 sectors on '%s' we have %ju",
    547 			    device_name, (uintmax_t)devsz);
    548 		goto close;
    549 	}
    550 
    551 	if (verbose) {
    552 		gpt_msg("mediasize=%ju; sectorsize=%u; blocks=%ju",
    553 		    (uintmax_t)mediasz, secsz, (uintmax_t)devsz);
    554 	}
    555 
    556 	map_init(devsz);
    557 
    558 	if (gpt_mbr(fd, 0LL) == -1)
    559 		goto close;
    560 	if ((found = gpt_gpt(fd, 1LL, 1)) == -1)
    561 		goto close;
    562 	if (gpt_gpt(fd, devsz - 1LL, found) == -1)
    563 		goto close;
    564 
    565 	return (fd);
    566 
    567  close:
    568 	close(fd);
    569 	return (-1);
    570 }
    571 
    572 void
    573 gpt_close(int fd)
    574 {
    575 
    576 	if (!modified)
    577 		goto out;
    578 
    579 	if (!nosync) {
    580 #ifdef DIOCMWEDGES
    581 		int bits;
    582 		if (ioctl(fd, DIOCMWEDGES, &bits) == -1)
    583 			warn("Can't update wedge information");
    584 		else
    585 			goto out;
    586 #endif
    587 	}
    588 	gpt_msg("You need to run \"dkctl %s makewedges\""
    589 	    " for the changes to take effect\n", device_name);
    590 
    591 out:
    592 	close(fd);
    593 }
    594 
    595 void
    596 gpt_msg(const char *fmt, ...)
    597 {
    598 	va_list ap;
    599 
    600 	if (quiet)
    601 		return;
    602 	printf("%s: ", device_name);
    603 	va_start(ap, fmt);
    604 	vprintf(fmt, ap);
    605 	va_end(ap);
    606 	printf("\n");
    607 }
    608