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