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