sunlabel.c revision 141956
1/*- 2 * Copyright (c) 2003 Jake Burkholder. 3 * Copyright (c) 2004 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 141956 2005-02-15 22:31:05Z obrien $"); 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 struct sun_disklabel sl1; 545 char *bp; 546 const char *what; 547 uint8_t part; 548 FILE *fp; 549 int line; 550 int rv; 551 int wantvtoc; 552 unsigned alt, cyl, hd, nr, sec; 553 554 line = wantvtoc = 0; 555 if ((fp = fopen(file, "r")) == NULL) 556 err(1, "fopen"); 557 sl1 = *sl; 558 bzero(&sl1.sl_part, sizeof(sl1.sl_part)); 559 while (fgets(buf, sizeof(buf), fp) != NULL) { 560 /* 561 * In order to recognize a partition entry, we search 562 * for lines starting with a single letter followed by 563 * a colon as their first non-white characters. We 564 * silently ignore any other lines, so any comment etc. 565 * lines in the label template will be ignored. 566 * 567 * XXX We should probably also recognize the geometry 568 * fields on top, and allow changing the geometry 569 * emulated by this disk. 570 */ 571 for (bp = buf; isspace(*bp); bp++) 572 ; 573 if (strncmp(bp, "text:", strlen("text:")) == 0) { 574 bp += strlen("text:"); 575 rv = sscanf(bp, 576 " %s cyl %u alt %u hd %u sec %u", 577 text, &cyl, &alt, &hd, &sec); 578 if (rv != 5) { 579 warnx("%s, line %d: text label does not " 580 "contain required fields", 581 file, line + 1); 582 fclose(fp); 583 return (1); 584 } 585 if (alt != 2) { 586 warnx("%s, line %d: # alt must be equal 2", 587 file, line + 1); 588 fclose(fp); 589 return (1); 590 } 591 if (cyl == 0 || cyl > USHRT_MAX) { 592 what = "cyl"; 593 nr = cyl; 594 unreasonable: 595 warnx("%s, line %d: # %s %d unreasonable", 596 file, line + 1, what, nr); 597 fclose(fp); 598 return (1); 599 } 600 if (hd == 0 || hd > USHRT_MAX) { 601 what = "hd"; 602 nr = hd; 603 goto unreasonable; 604 } 605 if (sec == 0 || sec > USHRT_MAX) { 606 what = "sec"; 607 nr = sec; 608 goto unreasonable; 609 } 610 if (mediasize == 0) 611 warnx("unit size unknown, no sector count " 612 "check could be done"); 613 else if ((uintmax_t)(cyl + alt) * sec * hd > 614 (uintmax_t)mediasize / sectorsize) { 615 warnx("%s, line %d: sector count %ju exceeds " 616 "unit size %ju", 617 file, line + 1, 618 (uintmax_t)(cyl + alt) * sec * hd, 619 (uintmax_t)mediasize / sectorsize); 620 fclose(fp); 621 return (1); 622 } 623 sl1.sl_pcylinders = cyl + alt; 624 sl1.sl_ncylinders = cyl; 625 sl1.sl_acylinders = alt; 626 sl1.sl_nsectors = sec; 627 sl1.sl_ntracks = hd; 628 memset(sl1.sl_text, 0, sizeof(sl1.sl_text)); 629 snprintf(sl1.sl_text, sizeof(sl1.sl_text), 630 "%s cyl %u alt %u hd %u sec %u", 631 text, cyl, alt, hd, sec); 632 continue; 633 } 634 if (strlen(bp) < 2 || bp[1] != ':') { 635 line++; 636 continue; 637 } 638 rv = sscanf(bp, "%c: %30s %30s %30s %30s", 639 &part, size, offset, tag, flag); 640 if (rv < 3) { 641 syntaxerr: 642 warnx("%s: syntax error on line %d", 643 file, line + 1); 644 fclose(fp); 645 return (1); 646 } 647 if (parse_size(&sl1, part - 'a', size) || 648 parse_offset(&sl1, part - 'a', offset)) 649 goto syntaxerr; 650 if (rv > 3) { 651 wantvtoc = 1; 652 if (rv == 5 && parse_flag(&sl1, part - 'a', flag)) 653 goto syntaxerr; 654 if (parse_tag(&sl1, part - 'a', tag)) 655 goto syntaxerr; 656 } 657 line++; 658 } 659 fclose(fp); 660 if (wantvtoc) { 661 sl1.sl_vtoc_sane = SUN_VTOC_SANE; 662 sl1.sl_vtoc_vers = SUN_VTOC_VERSION; 663 sl1.sl_vtoc_nparts = SUN_NPART; 664 } else { 665 sl1.sl_vtoc_sane = 0; 666 sl1.sl_vtoc_vers = 0; 667 sl1.sl_vtoc_nparts = 0; 668 bzero(&sl1.sl_vtoc_map, sizeof(sl1.sl_vtoc_map)); 669 } 670 *sl = sl1; 671 return (check_label(sl)); 672} 673 674static int 675parse_size(struct sun_disklabel *sl, int part, char *size) 676{ 677 uintmax_t nsectors; 678 uintmax_t total; 679 uintmax_t n; 680 char *p; 681 int i; 682 683 nsectors = 0; 684 n = strtoumax(size, &p, 10); 685 if (*p != '\0') { 686 if (strcmp(size, "*") == 0) { 687 total = sl->sl_ncylinders * sl->sl_ntracks * 688 sl->sl_nsectors; 689 for (i = 0; i < part; i++) { 690 if (i == 2) 691 continue; 692 nsectors += sl->sl_part[i].sdkp_nsectors; 693 } 694 n = total - nsectors; 695 } else if (p[1] == '\0' && (p[0] == 'C' || p[0] == 'c')) { 696 n = n * sl->sl_ntracks * sl->sl_nsectors; 697 } else if (p[1] == '\0' && (p[0] == 'K' || p[0] == 'k')) { 698 n = roundup((n * 1024) / 512, 699 sl->sl_ntracks * sl->sl_nsectors); 700 } else if (p[1] == '\0' && (p[0] == 'M' || p[0] == 'm')) { 701 n = roundup((n * 1024 * 1024) / 512, 702 sl->sl_ntracks * sl->sl_nsectors); 703 } else if (p[1] == '\0' && (p[0] == 'S' || p[0] == 's')) { 704 /* size in sectors, no action neded */ 705 } else if (p[1] == '\0' && (p[0] == 'G' || p[0] == 'g')) { 706 n = roundup((n * 1024 * 1024 * 1024) / 512, 707 sl->sl_ntracks * sl->sl_nsectors); 708 } else 709 return (-1); 710 } else if (cflag) { 711 n = n * sl->sl_ntracks * sl->sl_nsectors; 712 } 713 sl->sl_part[part].sdkp_nsectors = n; 714 return (0); 715} 716 717static int 718parse_offset(struct sun_disklabel *sl, int part, char *offset) 719{ 720 uintmax_t nsectors; 721 uintmax_t n; 722 char *p; 723 int i; 724 725 nsectors = 0; 726 n = strtoumax(offset, &p, 10); 727 if (*p != '\0') { 728 if (strcmp(offset, "*") == 0) { 729 for (i = 0; i < part; i++) { 730 if (i == 2) 731 continue; 732 nsectors += sl->sl_part[i].sdkp_nsectors; 733 } 734 n = nsectors / (sl->sl_nsectors * sl->sl_ntracks); 735 } else 736 return (-1); 737 } 738 sl->sl_part[part].sdkp_cyloffset = n; 739 return (0); 740} 741 742static void 743print_label(struct sun_disklabel *sl, const char *disk, FILE *out) 744{ 745 int i; 746 int havevtoc; 747 uintmax_t secpercyl; 748 749 havevtoc = sl->sl_vtoc_sane == SUN_VTOC_SANE; 750 secpercyl = sl->sl_nsectors * sl->sl_ntracks; 751 752 fprintf(out, 753"# /dev/%s:\n" 754"text: %s\n" 755"bytes/sector: %d\n" 756"sectors/cylinder: %ju\n", 757 disk, 758 sl->sl_text, 759 sectorsize, 760 secpercyl); 761 if (eflag) 762 fprintf(out, 763 "# max sectors/unit (including alt cylinders): %ju\n", 764 (uintmax_t)mediasize / sectorsize); 765 fprintf(out, 766"sectors/unit: %ju\n" 767"\n" 768"%d partitions:\n" 769"#\n", 770 secpercyl * sl->sl_ncylinders, 771 SUN_NPART); 772 if (!hflag) { 773 fprintf(out, "# Size is in %s.", cflag? "cylinders": "sectors"); 774 if (eflag) 775 fprintf(out, 776" Use %%d%c, %%dK, %%dM or %%dG to specify in %s,\n" 777"# kilobytes, megabytes or gigabytes respectively, or '*' to specify rest of\n" 778"# disk.\n", 779 cflag? 's': 'c', 780 cflag? "sectors": "cylinders"); 781 else 782 putc('\n', out); 783 fprintf(out, "# Offset is in cylinders."); 784 if (eflag) 785 fprintf(out, 786" Use '*' to calculate offsets automatically.\n" 787"#\n"); 788 else 789 putc('\n', out); 790 } 791 if (havevtoc) 792 fprintf(out, 793"# size offset tag flag\n" 794"# ---------- ---------- ---------- ----\n" 795 ); 796 else 797 fprintf(out, 798"# size offset\n" 799"# ---------- ----------\n" 800 ); 801 802 for (i = 0; i < SUN_NPART; i++) { 803 if (sl->sl_part[i].sdkp_nsectors == 0) 804 continue; 805 if (hflag) { 806 fprintf(out, " %c: %10s", 807 'a' + i, 808 make_h_number((uintmax_t) 809 sl->sl_part[i].sdkp_nsectors * 512)); 810 fprintf(out, " %10s", 811 make_h_number((uintmax_t) 812 sl->sl_part[i].sdkp_cyloffset * 512 813 * secpercyl)); 814 } else { 815 fprintf(out, " %c: %10ju %10u", 816 'a' + i, 817 sl->sl_part[i].sdkp_nsectors / (cflag? secpercyl: 1), 818 sl->sl_part[i].sdkp_cyloffset); 819 } 820 if (havevtoc) 821 fprintf(out, " %11s %5s", 822 tagname(sl->sl_vtoc_map[i].svtoc_tag), 823 flagname(sl->sl_vtoc_map[i].svtoc_flag)); 824 putc('\n', out); 825 } 826} 827 828static void 829usage(void) 830{ 831 832 fprintf(stderr, "usage:" 833"\t%s [-r] [-c | -h] disk\n" 834"\t\t(to read label)\n" 835"\t%s -B [-b boot1] [-n] disk\n" 836"\t\t(to install boot program only)\n" 837"\t%s -R [-B [-b boot1]] [-r] [-n] [-c] disk protofile\n" 838"\t\t(to restore label)\n" 839"\t%s -e [-B [-b boot1]] [-r] [-n] [-c] disk\n" 840"\t\t(to edit label)\n" 841"\t%s -w [-B [-b boot1]] [-r] [-n] disk type\n" 842"\t\t(to write default label)\n", 843 __progname, 844 __progname, 845 __progname, 846 __progname, 847 __progname); 848 exit(1); 849} 850 851/* 852 * Return VTOC tag and flag names for tag or flag ID, resp. 853 */ 854static const char * 855tagname(unsigned int tag) 856{ 857 static char buf[32]; 858 size_t i; 859 struct tags *tp; 860 861 for (i = 0, tp = knowntags; 862 i < sizeof(knowntags) / sizeof(struct tags); 863 i++, tp++) 864 if (tp->id == tag) 865 return (tp->name); 866 867 sprintf(buf, "%u", tag); 868 869 return (buf); 870} 871 872static const char * 873flagname(unsigned int flag) 874{ 875 static char buf[32]; 876 size_t i; 877 struct tags *tp; 878 879 for (i = 0, tp = knownflags; 880 i < sizeof(knownflags) / sizeof(struct tags); 881 i++, tp++) 882 if (tp->id == flag) 883 return (tp->name); 884 885 sprintf(buf, "%u", flag); 886 887 return (buf); 888} 889 890static unsigned int 891parse_tag(struct sun_disklabel *sl, int part, const char *tag) 892{ 893 struct tags *tp; 894 char *endp; 895 size_t i; 896 unsigned long l; 897 898 for (i = 0, tp = knowntags; 899 i < sizeof(knowntags) / sizeof(struct tags); 900 i++, tp++) 901 if (strcmp(tp->name, tag) == 0) { 902 sl->sl_vtoc_map[part].svtoc_tag = (uint16_t)tp->id; 903 return (0); 904 } 905 906 l = strtoul(tag, &endp, 0); 907 if (*tag != '\0' && *endp == '\0') { 908 sl->sl_vtoc_map[part].svtoc_tag = (uint16_t)l; 909 return (0); 910 } 911 912 return (-1); 913} 914 915static unsigned int 916parse_flag(struct sun_disklabel *sl, int part, const char *flag) 917{ 918 struct tags *tp; 919 char *endp; 920 size_t i; 921 unsigned long l; 922 923 for (i = 0, tp = knownflags; 924 i < sizeof(knownflags) / sizeof(struct tags); 925 i++, tp++) 926 if (strcmp(tp->name, flag) == 0) { 927 sl->sl_vtoc_map[part].svtoc_flag = (uint16_t)tp->id; 928 return (0); 929 } 930 931 l = strtoul(flag, &endp, 0); 932 if (*flag != '\0' && *endp == '\0') { 933 sl->sl_vtoc_map[part].svtoc_flag = (uint16_t)l; 934 return (0); 935 } 936 937 return (-1); 938} 939 940/* 941 * Convert argument into `human readable' byte number form. 942 */ 943static const char * 944make_h_number(uintmax_t u) 945{ 946 static char buf[32]; 947 double d; 948 949 if (u == 0) { 950 strcpy(buf, "0B"); 951 } else if (u > 2000000000UL) { 952 d = (double)u / 1e9; 953 sprintf(buf, "%.1fG", d); 954 } else if (u > 2000000UL) { 955 d = (double)u / 1e6; 956 sprintf(buf, "%.1fM", d); 957 } else { 958 d = (double)u / 1e3; 959 sprintf(buf, "%.1fK", d); 960 } 961 962 return (buf); 963} 964