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