sunlabel.c revision 330897
1/*- 2 * Copyright (c) 2003 Jake Burkholder. 3 * Copyright (c) 2004,2005 Joerg Wunsch. 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 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 AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27/*- 28 * SPDX-License-Identifier: BSD-4-Clause 29 * 30 * Copyright (c) 1994, 1995 Gordon W. Ross 31 * Copyright (c) 1994 Theo de Raadt 32 * All rights reserved. 33 * Copyright (c) 1987, 1993 34 * The Regents of the University of California. All rights reserved. 35 * 36 * This code is derived from software contributed to Berkeley by 37 * Symmetric Computer Systems. 38 * 39 * Redistribution and use in source and binary forms, with or without 40 * modification, are permitted provided that the following conditions 41 * are met: 42 * 1. Redistributions of source code must retain the above copyright 43 * notice, this list of conditions and the following disclaimer. 44 * 2. Redistributions in binary form must reproduce the above copyright 45 * notice, this list of conditions and the following disclaimer in the 46 * documentation and/or other materials provided with the distribution. 47 * 3. All advertising materials mentioning features or use of this software 48 * must display the following acknowledgement: 49 * This product includes software developed by the University of 50 * California, Berkeley and its contributors. 51 * This product includes software developed by Theo de Raadt. 52 * 4. Neither the name of the University nor the names of its contributors 53 * may be used to endorse or promote products derived from this software 54 * without specific prior written permission. 55 * 56 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 57 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 58 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 59 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 60 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 61 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 62 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 63 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 64 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 65 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 66 * SUCH DAMAGE. 67 * 68 * from: $NetBSD: disksubr.c,v 1.13 2000/12/17 22:39:18 pk $ 69 */ 70 71#include <sys/cdefs.h> 72__FBSDID("$FreeBSD: stable/11/sbin/sunlabel/sunlabel.c 330897 2018-03-14 03:19:51Z eadler $"); 73 74#include <sys/types.h> 75#include <sys/param.h> 76#include <sys/disk.h> 77#include <sys/ioctl.h> 78#include <sys/sun_disklabel.h> 79#include <sys/wait.h> 80 81#include <ctype.h> 82#include <err.h> 83#include <fcntl.h> 84#include <inttypes.h> 85#include <libgeom.h> 86#include <paths.h> 87#include <stdio.h> 88#include <stdlib.h> 89#include <string.h> 90#include <unistd.h> 91 92#define _PATH_TMPFILE "/tmp/EdDk.XXXXXXXXXX" 93#define _PATH_BOOT "/boot/boot1" 94 95static int bflag; 96static int Bflag; 97static int cflag; 98static int eflag; 99static int hflag; 100static int nflag; 101static int Rflag; 102static int wflag; 103 104static off_t mediasize; 105static uint32_t sectorsize; 106 107struct tags { 108 const char *name; 109 unsigned int id; 110}; 111 112static int check_label(struct sun_disklabel *sl); 113static void read_label(struct sun_disklabel *sl, const char *disk); 114static void write_label(struct sun_disklabel *sl, const char *disk, 115 const char *bootpath); 116static void edit_label(struct sun_disklabel *sl, const char *disk, 117 const char *bootpath); 118static int parse_label(struct sun_disklabel *sl, const char *file); 119static void print_label(struct sun_disklabel *sl, const char *disk, FILE *out); 120 121static int parse_size(struct sun_disklabel *sl, int part, char *size); 122static int parse_offset(struct sun_disklabel *sl, int part, char *offset); 123 124static const char *flagname(unsigned int tag); 125static const char *tagname(unsigned int tag); 126static unsigned int parse_flag(struct sun_disklabel *sl, int part, 127 const char *flag); 128static unsigned int parse_tag(struct sun_disklabel *sl, int part, 129 const char *tag); 130static const char *make_h_number(uintmax_t u); 131 132static void usage(void); 133 134extern char *__progname; 135 136static struct tags knowntags[] = { 137 { "unassigned", VTOC_UNASSIGNED }, 138 { "boot", VTOC_BOOT }, 139 { "root", VTOC_ROOT }, 140 { "swap", VTOC_SWAP }, 141 { "usr", VTOC_USR }, 142 { "backup", VTOC_BACKUP }, 143 { "stand", VTOC_STAND }, 144 { "var", VTOC_VAR }, 145 { "home", VTOC_HOME }, 146 { "altsctr", VTOC_ALTSCTR }, 147 { "cache", VTOC_CACHE }, 148 { "VxVM_pub", VTOC_VXVM_PUB }, 149 { "VxVM_priv", VTOC_VXVM_PRIV }, 150}; 151 152static struct tags knownflags[] = { 153 { "wm", 0 }, 154 { "wu", VTOC_UNMNT }, 155 { "rm", VTOC_RONLY }, 156 { "ru", VTOC_UNMNT | VTOC_RONLY }, 157}; 158 159/* 160 * Disk label editor for sun disklabels. 161 */ 162int 163main(int ac, char **av) 164{ 165 struct sun_disklabel sl; 166 const char *bootpath; 167 const char *proto; 168 const char *disk; 169 int ch; 170 171 bootpath = _PATH_BOOT; 172 while ((ch = getopt(ac, av, "b:BcehnrRw")) != -1) 173 switch (ch) { 174 case 'b': 175 bflag = 1; 176 bootpath = optarg; 177 break; 178 case 'B': 179 Bflag = 1; 180 break; 181 case 'c': 182 cflag = 1; 183 break; 184 case 'e': 185 eflag = 1; 186 break; 187 case 'h': 188 hflag = 1; 189 break; 190 case 'n': 191 nflag = 1; 192 break; 193 case 'r': 194 fprintf(stderr, "Obsolete -r flag ignored\n"); 195 break; 196 case 'R': 197 Rflag = 1; 198 break; 199 case 'w': 200 wflag = 1; 201 break; 202 default: 203 usage(); 204 break; 205 } 206 if (bflag && !Bflag) 207 usage(); 208 if (nflag && !(Bflag || eflag || Rflag || wflag)) 209 usage(); 210 if (eflag && (Rflag || wflag)) 211 usage(); 212 if (eflag) 213 hflag = 0; 214 ac -= optind; 215 av += optind; 216 if (ac == 0) 217 usage(); 218 bzero(&sl, sizeof(sl)); 219 disk = av[0]; 220 if (wflag) { 221 if (ac != 2 || strcmp(av[1], "auto") != 0) 222 usage(); 223 read_label(&sl, disk); 224 bzero(sl.sl_part, sizeof(sl.sl_part)); 225 sl.sl_part[SUN_RAWPART].sdkp_cyloffset = 0; 226 sl.sl_part[SUN_RAWPART].sdkp_nsectors = sl.sl_ncylinders * 227 sl.sl_ntracks * sl.sl_nsectors; 228 write_label(&sl, disk, bootpath); 229 } else if (eflag) { 230 if (ac != 1) 231 usage(); 232 read_label(&sl, disk); 233 if (sl.sl_magic != SUN_DKMAGIC) 234 errx(1, "%s%s has no sun disklabel", _PATH_DEV, disk); 235 edit_label(&sl, disk, bootpath); 236 } else if (Rflag) { 237 if (ac != 2) 238 usage(); 239 proto = av[1]; 240 read_label(&sl, disk); 241 if (parse_label(&sl, proto) != 0) 242 errx(1, "%s: invalid label", proto); 243 write_label(&sl, disk, bootpath); 244 } else if (Bflag) { 245 read_label(&sl, disk); 246 if (sl.sl_magic != SUN_DKMAGIC) 247 errx(1, "%s%s has no sun disklabel", _PATH_DEV, disk); 248 write_label(&sl, disk, bootpath); 249 } else { 250 read_label(&sl, disk); 251 if (sl.sl_magic != SUN_DKMAGIC) 252 errx(1, "%s%s has no sun disklabel", _PATH_DEV, disk); 253 print_label(&sl, disk, stdout); 254 } 255 return (0); 256} 257 258static int 259check_label(struct sun_disklabel *sl) 260{ 261 uint64_t nsectors; 262 uint64_t ostart; 263 uint64_t start; 264 uint64_t oend; 265 uint64_t end; 266 int havevtoc; 267 int warnonly; 268 int i; 269 int j; 270 271 havevtoc = sl->sl_vtoc_sane == SUN_VTOC_SANE; 272 273 nsectors = sl->sl_ncylinders * sl->sl_ntracks * sl->sl_nsectors; 274 if (sl->sl_part[SUN_RAWPART].sdkp_cyloffset != 0 || 275 sl->sl_part[SUN_RAWPART].sdkp_nsectors != nsectors) { 276 warnx("partition c is incorrect, must start at 0 and cover " 277 "whole disk"); 278 return (1); 279 } 280 if (havevtoc && sl->sl_vtoc_map[2].svtoc_tag != VTOC_BACKUP) { 281 warnx("partition c must have tag \"backup\""); 282 return (1); 283 } 284 for (i = 0; i < SUN_NPART; i++) { 285 if (i == 2 || sl->sl_part[i].sdkp_nsectors == 0) 286 continue; 287 start = (uint64_t)sl->sl_part[i].sdkp_cyloffset * 288 sl->sl_ntracks * sl->sl_nsectors; 289 end = start + sl->sl_part[i].sdkp_nsectors; 290 if (end > nsectors) { 291 warnx("partition %c extends past end of disk", 292 'a' + i); 293 return (1); 294 } 295 if (havevtoc) { 296 if (sl->sl_vtoc_map[i].svtoc_tag == VTOC_BACKUP) { 297 warnx("only partition c is allowed to have " 298 "tag \"backup\""); 299 return (1); 300 } 301 } 302 for (j = 0; j < SUN_NPART; j++) { 303 /* 304 * Overlaps for unmountable partitions are 305 * non-fatal but will be warned anyway. 306 */ 307 warnonly = havevtoc && 308 ((sl->sl_vtoc_map[i].svtoc_flag & VTOC_UNMNT) != 0 || 309 (sl->sl_vtoc_map[j].svtoc_flag & VTOC_UNMNT) != 0); 310 311 if (j == 2 || j == i || 312 sl->sl_part[j].sdkp_nsectors == 0) 313 continue; 314 ostart = (uint64_t)sl->sl_part[j].sdkp_cyloffset * 315 sl->sl_ntracks * sl->sl_nsectors; 316 oend = ostart + sl->sl_part[j].sdkp_nsectors; 317 if ((start <= ostart && end >= oend) || 318 (start > ostart && start < oend) || 319 (end > ostart && end < oend)) { 320 warnx("partition %c overlaps partition %c", 321 'a' + i, 'a' + j); 322 if (!warnonly) 323 return (1); 324 } 325 } 326 } 327 return (0); 328} 329 330static void 331read_label(struct sun_disklabel *sl, const char *disk) 332{ 333 char path[MAXPATHLEN]; 334 uint32_t fwsectors; 335 uint32_t fwheads; 336 char buf[SUN_SIZE]; 337 int fd, error; 338 339 snprintf(path, sizeof(path), "%s%s", _PATH_DEV, disk); 340 if ((fd = open(path, O_RDONLY)) < 0) 341 err(1, "open %s", path); 342 if (read(fd, buf, sizeof(buf)) != sizeof(buf)) 343 err(1, "read"); 344 error = sunlabel_dec(buf, sl); 345 if (ioctl(fd, DIOCGMEDIASIZE, &mediasize) != 0) 346 if (error) 347 err(1, "%s: ioctl(DIOCGMEDIASIZE) failed", disk); 348 if (ioctl(fd, DIOCGSECTORSIZE, §orsize) != 0) { 349 if (error) 350 err(1, "%s: DIOCGSECTORSIZE failed", disk); 351 else 352 sectorsize = 512; 353 } 354 if (error) { 355 bzero(sl, sizeof(*sl)); 356 if (ioctl(fd, DIOCGFWSECTORS, &fwsectors) != 0) 357 fwsectors = 63; 358 if (ioctl(fd, DIOCGFWHEADS, &fwheads) != 0) { 359 if (mediasize <= 63 * 1024 * sectorsize) 360 fwheads = 1; 361 else if (mediasize <= 63 * 16 * 1024 * sectorsize) 362 fwheads = 16; 363 else 364 fwheads = 255; 365 } 366 sl->sl_rpm = 3600; 367 sl->sl_pcylinders = mediasize / (fwsectors * fwheads * 368 sectorsize); 369 sl->sl_sparespercyl = 0; 370 sl->sl_interleave = 1; 371 sl->sl_ncylinders = sl->sl_pcylinders - 2; 372 sl->sl_acylinders = 2; 373 sl->sl_nsectors = fwsectors; 374 sl->sl_ntracks = fwheads; 375 sl->sl_part[SUN_RAWPART].sdkp_cyloffset = 0; 376 sl->sl_part[SUN_RAWPART].sdkp_nsectors = sl->sl_ncylinders * 377 sl->sl_ntracks * sl->sl_nsectors; 378 if (mediasize > (off_t)4999L * 1024L * 1024L) { 379 sprintf(sl->sl_text, 380 "FreeBSD%jdG cyl %u alt %u hd %u sec %u", 381 (intmax_t)(mediasize + 512 * 1024 * 1024) / 382 (1024 * 1024 * 1024), 383 sl->sl_ncylinders, sl->sl_acylinders, 384 sl->sl_ntracks, sl->sl_nsectors); 385 } else { 386 sprintf(sl->sl_text, 387 "FreeBSD%jdM cyl %u alt %u hd %u sec %u", 388 (intmax_t)(mediasize + 512 * 1024) / (1024 * 1024), 389 sl->sl_ncylinders, sl->sl_acylinders, 390 sl->sl_ntracks, sl->sl_nsectors); 391 } 392 } 393 close(fd); 394} 395 396static void 397write_label(struct sun_disklabel *sl, const char *disk, const char *bootpath) 398{ 399 char path[MAXPATHLEN]; 400 char boot[SUN_BOOTSIZE]; 401 char buf[SUN_SIZE]; 402 const char *errstr; 403 off_t off; 404 int bfd; 405 int fd; 406 int i; 407 struct gctl_req *grq; 408 409 sl->sl_magic = SUN_DKMAGIC; 410 411 if (check_label(sl) != 0) 412 errx(1, "invalid label"); 413 414 bzero(buf, sizeof(buf)); 415 sunlabel_enc(buf, sl); 416 417 if (nflag) { 418 print_label(sl, disk, stdout); 419 return; 420 } 421 if (Bflag) { 422 if ((bfd = open(bootpath, O_RDONLY)) < 0) 423 err(1, "open %s", bootpath); 424 i = read(bfd, boot, sizeof(boot)); 425 if (i < 0) 426 err(1, "read"); 427 else if (i != sizeof (boot)) 428 errx(1, "read wrong size boot code (%d)", i); 429 close(bfd); 430 } 431 snprintf(path, sizeof(path), "%s%s", _PATH_DEV, disk); 432 fd = open(path, O_RDWR); 433 if (fd < 0) { 434 grq = gctl_get_handle(); 435 gctl_ro_param(grq, "verb", -1, "write label"); 436 gctl_ro_param(grq, "class", -1, "SUN"); 437 gctl_ro_param(grq, "geom", -1, disk); 438 gctl_ro_param(grq, "label", sizeof buf, buf); 439 errstr = gctl_issue(grq); 440 if (errstr != NULL) 441 errx(1, "%s", errstr); 442 gctl_free(grq); 443 if (Bflag) { 444 grq = gctl_get_handle(); 445 gctl_ro_param(grq, "verb", -1, "write bootcode"); 446 gctl_ro_param(grq, "class", -1, "SUN"); 447 gctl_ro_param(grq, "geom", -1, disk); 448 gctl_ro_param(grq, "bootcode", sizeof boot, boot); 449 errstr = gctl_issue(grq); 450 if (errstr != NULL) 451 errx(1, "%s", errstr); 452 gctl_free(grq); 453 } 454 } else { 455 if (lseek(fd, 0, SEEK_SET) < 0) 456 err(1, "lseek"); 457 if (write(fd, buf, sizeof(buf)) != sizeof(buf)) 458 err (1, "write"); 459 if (Bflag) { 460 for (i = 0; i < SUN_NPART; i++) { 461 if (sl->sl_part[i].sdkp_nsectors == 0) 462 continue; 463 off = sl->sl_part[i].sdkp_cyloffset * 464 sl->sl_ntracks * sl->sl_nsectors * 512; 465 /* 466 * Ignore first SUN_SIZE bytes of boot code to 467 * avoid overwriting the label. 468 */ 469 if (lseek(fd, off + SUN_SIZE, SEEK_SET) < 0) 470 err(1, "lseek"); 471 if (write(fd, boot + SUN_SIZE, 472 sizeof(boot) - SUN_SIZE) != 473 sizeof(boot) - SUN_SIZE) 474 err(1, "write"); 475 } 476 } 477 close(fd); 478 } 479 exit(0); 480} 481 482static void 483edit_label(struct sun_disklabel *sl, const char *disk, const char *bootpath) 484{ 485 char tmpfil[] = _PATH_TMPFILE; 486 const char *editor; 487 int status; 488 FILE *fp; 489 pid_t pid; 490 pid_t r; 491 int fd; 492 int c; 493 494 if ((fd = mkstemp(tmpfil)) < 0) 495 err(1, "mkstemp"); 496 if ((fp = fdopen(fd, "w")) == NULL) 497 err(1, "fdopen"); 498 print_label(sl, disk, fp); 499 fflush(fp); 500 for (;;) { 501 if ((pid = fork()) < 0) 502 err(1, "fork"); 503 if (pid == 0) { 504 if ((editor = getenv("EDITOR")) == NULL) 505 editor = _PATH_VI; 506 execlp(editor, editor, tmpfil, (char *)NULL); 507 err(1, "execlp %s", editor); 508 } 509 status = 0; 510 while ((r = wait(&status)) > 0 && r != pid) 511 ; 512 if (WIFEXITED(status)) { 513 if (parse_label(sl, tmpfil) == 0) { 514 fclose(fp); 515 unlink(tmpfil); 516 write_label(sl, disk, bootpath); 517 return; 518 } 519 printf("re-edit the label? [y]: "); 520 fflush(stdout); 521 c = getchar(); 522 if (c != EOF && c != '\n') 523 while (getchar() != '\n') 524 ; 525 if (c == 'n') { 526 fclose(fp); 527 unlink(tmpfil); 528 return; 529 } 530 } 531 } 532 fclose(fp); 533 unlink(tmpfil); 534 return; 535} 536 537static int 538parse_label(struct sun_disklabel *sl, const char *file) 539{ 540 char offset[32]; 541 char size[32]; 542 char flag[32]; 543 char tag[32]; 544 char buf[128]; 545 char text[128]; 546 char volname[SUN_VOLNAME_LEN + 1]; 547 struct sun_disklabel sl1; 548 char *bp; 549 const char *what; 550 uint8_t part; 551 FILE *fp; 552 int line; 553 int rv; 554 int wantvtoc; 555 unsigned alt, cyl, hd, nr, sec; 556 557 line = wantvtoc = 0; 558 if ((fp = fopen(file, "r")) == NULL) 559 err(1, "fopen"); 560 sl1 = *sl; 561 bzero(&sl1.sl_part, sizeof(sl1.sl_part)); 562 while (fgets(buf, sizeof(buf), fp) != NULL) { 563 /* 564 * In order to recognize a partition entry, we search 565 * for lines starting with a single letter followed by 566 * a colon as their first non-white characters. We 567 * silently ignore any other lines, so any comment etc. 568 * lines in the label template will be ignored. 569 * 570 * XXX We should probably also recognize the geometry 571 * fields on top, and allow changing the geometry 572 * emulated by this disk. 573 */ 574 for (bp = buf; isspace(*bp); bp++) 575 ; 576 if (strncmp(bp, "text:", strlen("text:")) == 0) { 577 bp += strlen("text:"); 578 rv = sscanf(bp, 579 " %s cyl %u alt %u hd %u sec %u", 580 text, &cyl, &alt, &hd, &sec); 581 if (rv != 5) { 582 warnx("%s, line %d: text label does not " 583 "contain required fields", 584 file, line + 1); 585 fclose(fp); 586 return (1); 587 } 588 if (alt != 2) { 589 warnx("%s, line %d: # alt must be equal 2", 590 file, line + 1); 591 fclose(fp); 592 return (1); 593 } 594 if (cyl == 0 || cyl > USHRT_MAX) { 595 what = "cyl"; 596 nr = cyl; 597 unreasonable: 598 warnx("%s, line %d: # %s %d unreasonable", 599 file, line + 1, what, nr); 600 fclose(fp); 601 return (1); 602 } 603 if (hd == 0 || hd > USHRT_MAX) { 604 what = "hd"; 605 nr = hd; 606 goto unreasonable; 607 } 608 if (sec == 0 || sec > USHRT_MAX) { 609 what = "sec"; 610 nr = sec; 611 goto unreasonable; 612 } 613 if (mediasize == 0) 614 warnx("unit size unknown, no sector count " 615 "check could be done"); 616 else if ((uintmax_t)(cyl + alt) * sec * hd > 617 (uintmax_t)mediasize / sectorsize) { 618 warnx("%s, line %d: sector count %ju exceeds " 619 "unit size %ju", 620 file, line + 1, 621 (uintmax_t)(cyl + alt) * sec * hd, 622 (uintmax_t)mediasize / sectorsize); 623 fclose(fp); 624 return (1); 625 } 626 sl1.sl_pcylinders = cyl + alt; 627 sl1.sl_ncylinders = cyl; 628 sl1.sl_acylinders = alt; 629 sl1.sl_nsectors = sec; 630 sl1.sl_ntracks = hd; 631 memset(sl1.sl_text, 0, sizeof(sl1.sl_text)); 632 snprintf(sl1.sl_text, sizeof(sl1.sl_text), 633 "%s cyl %u alt %u hd %u sec %u", 634 text, cyl, alt, hd, sec); 635 continue; 636 } 637 if (strncmp(bp, "volume name:", strlen("volume name:")) == 0) { 638 wantvtoc = 1; /* Volume name requires VTOC. */ 639 bp += strlen("volume name:"); 640#if SUN_VOLNAME_LEN != 8 641# error "scanf field width does not match SUN_VOLNAME_LEN" 642#endif 643 /* 644 * We set the field length to one more than 645 * SUN_VOLNAME_LEN to allow detecting an 646 * overflow. 647 */ 648 memset(volname, 0, sizeof volname); 649 rv = sscanf(bp, " %9[^\n]", volname); 650 if (rv != 1) { 651 /* Clear the volume name. */ 652 memset(sl1.sl_vtoc_volname, 0, 653 SUN_VOLNAME_LEN); 654 } else { 655 memcpy(sl1.sl_vtoc_volname, volname, 656 SUN_VOLNAME_LEN); 657 if (volname[SUN_VOLNAME_LEN] != '\0') 658 warnx( 659"%s, line %d: volume name longer than %d characters, truncating", 660 file, line + 1, SUN_VOLNAME_LEN); 661 } 662 continue; 663 } 664 if (strlen(bp) < 2 || bp[1] != ':') { 665 line++; 666 continue; 667 } 668 rv = sscanf(bp, "%c: %30s %30s %30s %30s", 669 &part, size, offset, tag, flag); 670 if (rv < 3) { 671 syntaxerr: 672 warnx("%s: syntax error on line %d", 673 file, line + 1); 674 fclose(fp); 675 return (1); 676 } 677 if (parse_size(&sl1, part - 'a', size) || 678 parse_offset(&sl1, part - 'a', offset)) 679 goto syntaxerr; 680 if (rv > 3) { 681 wantvtoc = 1; 682 if (rv == 5 && parse_flag(&sl1, part - 'a', flag)) 683 goto syntaxerr; 684 if (parse_tag(&sl1, part - 'a', tag)) 685 goto syntaxerr; 686 } 687 line++; 688 } 689 fclose(fp); 690 if (wantvtoc) { 691 sl1.sl_vtoc_sane = SUN_VTOC_SANE; 692 sl1.sl_vtoc_vers = SUN_VTOC_VERSION; 693 sl1.sl_vtoc_nparts = SUN_NPART; 694 } else { 695 sl1.sl_vtoc_sane = 0; 696 sl1.sl_vtoc_vers = 0; 697 sl1.sl_vtoc_nparts = 0; 698 bzero(&sl1.sl_vtoc_map, sizeof(sl1.sl_vtoc_map)); 699 } 700 *sl = sl1; 701 return (check_label(sl)); 702} 703 704static int 705parse_size(struct sun_disklabel *sl, int part, char *size) 706{ 707 uintmax_t nsectors; 708 uintmax_t total; 709 uintmax_t n; 710 char *p; 711 int i; 712 713 nsectors = 0; 714 n = strtoumax(size, &p, 10); 715 if (*p != '\0') { 716 if (strcmp(size, "*") == 0) { 717 total = sl->sl_ncylinders * sl->sl_ntracks * 718 sl->sl_nsectors; 719 for (i = 0; i < part; i++) { 720 if (i == 2) 721 continue; 722 nsectors += sl->sl_part[i].sdkp_nsectors; 723 } 724 n = total - nsectors; 725 } else if (p[1] == '\0' && (p[0] == 'C' || p[0] == 'c')) { 726 n = n * sl->sl_ntracks * sl->sl_nsectors; 727 } else if (p[1] == '\0' && (p[0] == 'K' || p[0] == 'k')) { 728 n = roundup((n * 1024) / 512, 729 sl->sl_ntracks * sl->sl_nsectors); 730 } else if (p[1] == '\0' && (p[0] == 'M' || p[0] == 'm')) { 731 n = roundup((n * 1024 * 1024) / 512, 732 sl->sl_ntracks * sl->sl_nsectors); 733 } else if (p[1] == '\0' && (p[0] == 'S' || p[0] == 's')) { 734 /* size in sectors, no action neded */ 735 } else if (p[1] == '\0' && (p[0] == 'G' || p[0] == 'g')) { 736 n = roundup((n * 1024 * 1024 * 1024) / 512, 737 sl->sl_ntracks * sl->sl_nsectors); 738 } else 739 return (-1); 740 } else if (cflag) { 741 n = n * sl->sl_ntracks * sl->sl_nsectors; 742 } 743 sl->sl_part[part].sdkp_nsectors = n; 744 return (0); 745} 746 747static int 748parse_offset(struct sun_disklabel *sl, int part, char *offset) 749{ 750 uintmax_t nsectors; 751 uintmax_t n; 752 char *p; 753 int i; 754 755 nsectors = 0; 756 n = strtoumax(offset, &p, 10); 757 if (*p != '\0') { 758 if (strcmp(offset, "*") == 0) { 759 for (i = 0; i < part; i++) { 760 if (i == 2) 761 continue; 762 nsectors += sl->sl_part[i].sdkp_nsectors; 763 } 764 n = nsectors / (sl->sl_nsectors * sl->sl_ntracks); 765 } else 766 return (-1); 767 } 768 sl->sl_part[part].sdkp_cyloffset = n; 769 return (0); 770} 771 772static void 773print_label(struct sun_disklabel *sl, const char *disk, FILE *out) 774{ 775 int i, j; 776 int havevtoc; 777 uintmax_t secpercyl; 778 /* Long enough to hex-encode each character. */ 779 char volname[4 * SUN_VOLNAME_LEN + 1]; 780 781 havevtoc = sl->sl_vtoc_sane == SUN_VTOC_SANE; 782 secpercyl = sl->sl_nsectors * sl->sl_ntracks; 783 784 fprintf(out, 785"# /dev/%s:\n" 786"text: %s\n" 787"bytes/sector: %d\n" 788"sectors/cylinder: %ju\n", 789 disk, 790 sl->sl_text, 791 sectorsize, 792 secpercyl); 793 if (eflag) 794 fprintf(out, 795 "# max sectors/unit (including alt cylinders): %ju\n", 796 (uintmax_t)mediasize / sectorsize); 797 fprintf(out, 798"sectors/unit: %ju\n", 799 secpercyl * sl->sl_ncylinders); 800 if (havevtoc && sl->sl_vtoc_volname[0] != '\0') { 801 for (i = j = 0; i < SUN_VOLNAME_LEN; i++) { 802 if (sl->sl_vtoc_volname[i] == '\0') 803 break; 804 if (isprint(sl->sl_vtoc_volname[i])) 805 volname[j++] = sl->sl_vtoc_volname[i]; 806 else 807 j += sprintf(volname + j, "\\x%02X", 808 sl->sl_vtoc_volname[i]); 809 } 810 volname[j] = '\0'; 811 fprintf(out, "volume name: %s\n", volname); 812 } 813 fprintf(out, 814"\n" 815"%d partitions:\n" 816"#\n", 817 SUN_NPART); 818 if (!hflag) { 819 fprintf(out, "# Size is in %s.", cflag? "cylinders": "sectors"); 820 if (eflag) 821 fprintf(out, 822" Use %%d%c, %%dK, %%dM or %%dG to specify in %s,\n" 823"# kilobytes, megabytes or gigabytes respectively, or '*' to specify rest of\n" 824"# disk.\n", 825 cflag? 's': 'c', 826 cflag? "sectors": "cylinders"); 827 else 828 putc('\n', out); 829 fprintf(out, "# Offset is in cylinders."); 830 if (eflag) 831 fprintf(out, 832" Use '*' to calculate offsets automatically.\n" 833"#\n"); 834 else 835 putc('\n', out); 836 } 837 if (havevtoc) 838 fprintf(out, 839"# size offset tag flag\n" 840"# ---------- ---------- ---------- ----\n" 841 ); 842 else 843 fprintf(out, 844"# size offset\n" 845"# ---------- ----------\n" 846 ); 847 848 for (i = 0; i < SUN_NPART; i++) { 849 if (sl->sl_part[i].sdkp_nsectors == 0) 850 continue; 851 if (hflag) { 852 fprintf(out, " %c: %10s", 853 'a' + i, 854 make_h_number((uintmax_t) 855 sl->sl_part[i].sdkp_nsectors * 512)); 856 fprintf(out, " %10s", 857 make_h_number((uintmax_t) 858 sl->sl_part[i].sdkp_cyloffset * 512 859 * secpercyl)); 860 } else { 861 fprintf(out, " %c: %10ju %10u", 862 'a' + i, 863 sl->sl_part[i].sdkp_nsectors / (cflag? secpercyl: 1), 864 sl->sl_part[i].sdkp_cyloffset); 865 } 866 if (havevtoc) 867 fprintf(out, " %11s %5s", 868 tagname(sl->sl_vtoc_map[i].svtoc_tag), 869 flagname(sl->sl_vtoc_map[i].svtoc_flag)); 870 putc('\n', out); 871 } 872} 873 874static void 875usage(void) 876{ 877 878 fprintf(stderr, "usage:" 879"\t%s [-r] [-c | -h] disk\n" 880"\t\t(to read label)\n" 881"\t%s -B [-b boot1] [-n] disk\n" 882"\t\t(to install boot program only)\n" 883"\t%s -R [-B [-b boot1]] [-r] [-n] [-c] disk protofile\n" 884"\t\t(to restore label)\n" 885"\t%s -e [-B [-b boot1]] [-r] [-n] [-c] disk\n" 886"\t\t(to edit label)\n" 887"\t%s -w [-B [-b boot1]] [-r] [-n] disk type\n" 888"\t\t(to write default label)\n", 889 __progname, 890 __progname, 891 __progname, 892 __progname, 893 __progname); 894 exit(1); 895} 896 897/* 898 * Return VTOC tag and flag names for tag or flag ID, resp. 899 */ 900static const char * 901tagname(unsigned int tag) 902{ 903 static char buf[32]; 904 size_t i; 905 struct tags *tp; 906 907 for (i = 0, tp = knowntags; i < nitems(knowntags); i++, tp++) 908 if (tp->id == tag) 909 return (tp->name); 910 911 sprintf(buf, "%u", tag); 912 913 return (buf); 914} 915 916static const char * 917flagname(unsigned int flag) 918{ 919 static char buf[32]; 920 size_t i; 921 struct tags *tp; 922 923 for (i = 0, tp = knownflags; i < nitems(knownflags); i++, tp++) 924 if (tp->id == flag) 925 return (tp->name); 926 927 sprintf(buf, "%u", flag); 928 929 return (buf); 930} 931 932static unsigned int 933parse_tag(struct sun_disklabel *sl, int part, const char *tag) 934{ 935 struct tags *tp; 936 char *endp; 937 size_t i; 938 unsigned long l; 939 940 for (i = 0, tp = knowntags; i < nitems(knowntags); i++, tp++) 941 if (strcmp(tp->name, tag) == 0) { 942 sl->sl_vtoc_map[part].svtoc_tag = (uint16_t)tp->id; 943 return (0); 944 } 945 946 l = strtoul(tag, &endp, 0); 947 if (*tag != '\0' && *endp == '\0') { 948 sl->sl_vtoc_map[part].svtoc_tag = (uint16_t)l; 949 return (0); 950 } 951 952 return (-1); 953} 954 955static unsigned int 956parse_flag(struct sun_disklabel *sl, int part, const char *flag) 957{ 958 struct tags *tp; 959 char *endp; 960 size_t i; 961 unsigned long l; 962 963 for (i = 0, tp = knownflags; i < nitems(knownflags); i++, tp++) 964 if (strcmp(tp->name, flag) == 0) { 965 sl->sl_vtoc_map[part].svtoc_flag = (uint16_t)tp->id; 966 return (0); 967 } 968 969 l = strtoul(flag, &endp, 0); 970 if (*flag != '\0' && *endp == '\0') { 971 sl->sl_vtoc_map[part].svtoc_flag = (uint16_t)l; 972 return (0); 973 } 974 975 return (-1); 976} 977 978/* 979 * Convert argument into `human readable' byte number form. 980 */ 981static const char * 982make_h_number(uintmax_t u) 983{ 984 static char buf[32]; 985 double d; 986 987 if (u == 0) { 988 strcpy(buf, "0B"); 989 } else if (u > 2000000000UL) { 990 d = (double)u / 1e9; 991 sprintf(buf, "%.1fG", d); 992 } else if (u > 2000000UL) { 993 d = (double)u / 1e6; 994 sprintf(buf, "%.1fM", d); 995 } else { 996 d = (double)u / 1e3; 997 sprintf(buf, "%.1fK", d); 998 } 999 1000 return (buf); 1001} 1002