1: /*
   2:  * Copyright (c) 1987, 1993
   3:  *	The Regents of the University of California.  All rights reserved.
   4:  *
   5:  * This code is derived from software contributed to Berkeley by
   6:  * Symmetric Computer Systems.
   7:  *
   8:  * Redistribution and use in source and binary forms, with or without
   9:  * modification, are permitted provided that the following conditions
  10:  * are met:
  11:  * 1. Redistributions of source code must retain the above copyright
  12:  *    notice, this list of conditions and the following disclaimer.
  13:  * 2. Redistributions in binary form must reproduce the above copyright
  14:  *    notice, this list of conditions and the following disclaimer in the
  15:  *    documentation and/or other materials provided with the distribution.
  16:  * 3. All advertising materials mentioning features or use of this software
  17:  *    must display the following acknowledgement:
  18:  *	This product includes software developed by the University of
  19:  *	California, Berkeley and its contributors.
  20:  * 4. Neither the name of the University nor the names of its contributors
  21:  *    may be used to endorse or promote products derived from this software
  22:  *    without specific prior written permission.
  23:  *
  24:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  25:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  26:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  27:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  28:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  29:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  30:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  31:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  32:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  33:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  34:  * SUCH DAMAGE.
  35:  */
  36: 
  37: #if !defined(lint) && defined(DOSCCS)
  38: static char copyright[] =
  39: "@(#) Copyright (c) 1987, 1993\n\
  40: 	The Regents of the University of California.  All rights reserved.\n";
  41: 
  42: static char sccsid[] = "@(#)disklabel.c	8.1.3 (2.11BSD) 1999/10/25";
  43: /* from static char sccsid[] = "@(#)disklabel.c	1.2 (Symmetric) 11/28/85"; */
  44: #endif
  45: 
  46: #include <sys/param.h>
  47: #include <sys/signal.h>
  48: #include <sys/errno.h>
  49: #include <sys/file.h>
  50: #include <sys/ioctl.h>
  51: #include <sys/stat.h>
  52: #define DKTYPENAMES
  53: #include <sys/disklabel.h>
  54: #include <sys/fs.h>
  55: #include <string.h>
  56: #include <stdlib.h>
  57: #include <stdio.h>
  58: #include <ctype.h>
  59: #include "pathnames.h"
  60: 
  61: /*
  62:  * Disklabel: read and write disklabels.
  63:  * The label is usually placed on one of the first sectors of the disk.
  64:  * Many machines also place a bootstrap in the same area,
  65:  * in which case the label is embedded in the bootstrap.
  66:  * The bootstrap source must leave space at the proper offset
  67:  * for the label on such machines.
  68:  */
  69: 
  70: /*
  71:  * 2.11BSD has to do some things differently than other systems.  BBSIZE
  72:  * may be 1024 bytes but the disk boot roms only read the 512 byte sector 0.
  73:  * The boot and label areas each occupy 1/2 of the 1kb 'filesystem block'
  74:  * which precedes the superblock.  The bootblock is sector 0 and the label block
  75:  * is sector 1.  Each is a disjoint and independent area.  Thus the logic in
  76:  * this program which treated the label area as a subset or offset of the
  77:  * boot area had to change.
  78:  *
  79:  * The 'a' partition is used to access the raw device - as did the 'tahoe'.
  80: */
  81: 
  82: #define RAWPARTITION    'a'
  83: 
  84: #define DEFEDITOR   _PATH_VI
  85: #define streq(a,b)  (strcmp(a,b) == 0)
  86: 
  87: char    *dkname;
  88: char    *specname;
  89: char    tmpfil[] = _PATH_TMP;
  90: 
  91: char    namebuf[256], *np = namebuf;
  92: struct  disklabel lab;
  93: struct  disklabel *readlabel(), *makebootarea();
  94: char    bootarea[BBSIZE];   /* 512 for bootblock, 512 for label */
  95: 
  96: int installboot;    /* non-zero if we should install a boot program */
  97: char    *xxboot;    /* primary boot */
  98: char    boot0[MAXPATHLEN];
  99: 
 100: enum    {
 101:     UNSPEC, EDIT, NOWRITE, READ, RESTORE, WRITE, WRITEABLE, WRITEBOOT
 102: } op = UNSPEC;
 103: 
 104: int rflag;
 105: 
 106: #ifdef DEBUG
 107: int debug;
 108: #define OPTIONS "BNRWb:derw"
 109: #else
 110: #define OPTIONS "BNRWb:erw"
 111: #endif
 112: 
 113: main(argc, argv)
 114:     int argc;
 115:     char *argv[];
 116: {
 117:     register struct disklabel *lp;
 118:     FILE *t;
 119:     int ch, f, flag, error = 0;
 120:     char *name = 0;
 121: 
 122:     while ((ch = getopt(argc, argv, OPTIONS)) != EOF)
 123:         switch (ch) {
 124:             case 'B':
 125:                 ++installboot;
 126:                 break;
 127:             case 'b':
 128:                 xxboot = optarg;
 129:                 break;
 130:             case 'N':
 131:                 if (op != UNSPEC)
 132:                     usage();
 133:                 op = NOWRITE;
 134:                 break;
 135:             case 'R':
 136:                 if (op != UNSPEC)
 137:                     usage();
 138:                 op = RESTORE;
 139:                 break;
 140:             case 'W':
 141:                 if (op != UNSPEC)
 142:                     usage();
 143:                 op = WRITEABLE;
 144:                 break;
 145:             case 'e':
 146:                 if (op != UNSPEC)
 147:                     usage();
 148:                 op = EDIT;
 149:                 break;
 150:             case 'r':
 151:                 ++rflag;
 152:                 break;
 153:             case 'w':
 154:                 if (op != UNSPEC)
 155:                     usage();
 156:                 op = WRITE;
 157:                 break;
 158: #ifdef DEBUG
 159:             case 'd':
 160:                 debug++;
 161:                 break;
 162: #endif
 163:             case '?':
 164:             default:
 165:                 usage();
 166:         }
 167:     argc -= optind;
 168:     argv += optind;
 169:     if (installboot) {
 170:         rflag++;
 171:         if (op == UNSPEC)
 172:             op = WRITEBOOT;
 173:     } else {
 174:         if (op == UNSPEC)
 175:             op = READ;
 176:         xxboot = 0;
 177:     }
 178: 
 179:     if (argc < 1)
 180:         usage();
 181: 
 182:     dkname = argv[0];
 183:     if (dkname[0] != '/') {
 184:         (void)sprintf(np, "%s/r%s%c", _PATH_DEV, dkname, RAWPARTITION);
 185:         specname = np;
 186:         np += strlen(specname) + 1;
 187:     } else
 188:         specname = dkname;
 189:     f = open(specname, op == READ ? O_RDONLY : O_RDWR);
 190:     if (f < 0 && errno == ENOENT && dkname[0] != '/') {
 191:         (void)sprintf(specname, "%s/r%s", _PATH_DEV, dkname);
 192:         np = namebuf + strlen(specname) + 1;
 193:         f = open(specname, op == READ ? O_RDONLY : O_RDWR);
 194:     }
 195:     if (f < 0)
 196:         Perror(specname);
 197: 
 198:     switch(op) {
 199: 
 200:     case EDIT:
 201:         if (argc != 1)
 202:             usage();
 203:         lp = readlabel(f);
 204:         error = edit(lp, f);
 205:         break;
 206: 
 207:     case NOWRITE:
 208:         flag = 0;
 209:         if (ioctl(f, DIOCWLABEL, (char *)&flag) < 0)
 210:             Perror("ioctl DIOCWLABEL");
 211:         break;
 212: 
 213:     case READ:
 214:         if (argc != 1)
 215:             usage();
 216:         lp = readlabel(f);
 217:         display(stdout, lp);
 218:         error = checklabel(lp);
 219:         break;
 220: 
 221:     case RESTORE:
 222:         if (installboot && argc == 3) {
 223:             makelabel(argv[2], 0, &lab);
 224:             argc--;
 225:         }
 226:         if (argc != 2)
 227:             usage();
 228:         lp = makebootarea(bootarea, &lab, f);
 229:         if (!(t = fopen(argv[1], "r")))
 230:             Perror(argv[1]);
 231:         if (getasciilabel(t, lp))
 232:             error = writelabel(f, bootarea, lp);
 233:         break;
 234: 
 235:     case WRITE:
 236:         if (argc == 3) {
 237:             name = argv[2];
 238:             argc--;
 239:         }
 240:         if (argc != 2)
 241:             usage();
 242:         makelabel(argv[1], name, &lab);
 243:         lp = makebootarea(bootarea, &lab, f);
 244:         *lp = lab;
 245:         if (checklabel(lp) == 0)
 246:             error = writelabel(f, bootarea, lp);
 247:         break;
 248: 
 249:     case WRITEABLE:
 250:         flag = 1;
 251:         if (ioctl(f, DIOCWLABEL, (char *)&flag) < 0)
 252:             Perror("ioctl DIOCWLABEL");
 253:         break;
 254: 
 255:     case WRITEBOOT:
 256:     {
 257:         struct disklabel tlab;
 258: 
 259:         lp = readlabel(f);
 260:         tlab = *lp;
 261:         if (argc == 2)
 262:             makelabel(argv[1], 0, &lab);
 263:         lp = makebootarea(bootarea, &lab, f);
 264:         *lp = tlab;
 265:         if (checklabel(lp) == 0)
 266:             error = writelabel(f, bootarea, lp);
 267:         break;
 268:     }
 269:     }
 270:     exit(error);
 271: }
 272: 
 273: /*
 274:  * Construct a prototype disklabel from /etc/disktab.  As a side
 275:  * effect, set the names of the primary and secondary boot files
 276:  * if specified.
 277:  */
 278: makelabel(type, name, lp)
 279:     char *type, *name;
 280:     register struct disklabel *lp;
 281: {
 282:     register struct disklabel *dp;
 283:     char *strcpy();
 284: 
 285:     dp = getdiskbyname(type);
 286:     if (dp == NULL) {
 287:         fprintf(stderr, "%s: unknown disk type\n", type);
 288:         exit(1);
 289:     }
 290:     *lp = *dp;
 291: 
 292:     /*
 293: 	 * Set bootstrap name.
 294: 	 * 1. If set from command line, use it,
 295: 	 * 2. otherwise, check if disktab specifies it (b0),
 296: 	 * 3. otherwise, makebootarea() will choose one based on the name
 297: 	 *    of the disk special file. E.g. /dev/ra0 -> rauboot
 298: 	 */
 299:     if (!xxboot && lp->d_boot0) {
 300:         if (*lp->d_boot0 != '/')
 301:             (void)sprintf(boot0, "%s/%s",
 302:                       _PATH_BOOTDIR, lp->d_boot0);
 303:         else
 304:             (void)strcpy(boot0, lp->d_boot0);
 305:         xxboot = boot0;
 306:     }
 307:     /* d_packname is union d_boot0, so zero */
 308:     bzero(lp->d_packname, sizeof(lp->d_packname));
 309:     if (name)
 310:         (void)strncpy(lp->d_packname, name, sizeof(lp->d_packname));
 311: }
 312: 
 313: writelabel(f, boot, lp)
 314:     int f;
 315:     char *boot;
 316:     register struct disklabel *lp;
 317: {
 318:     register int i;
 319:     int flag;
 320: 
 321:     lp->d_magic = DISKMAGIC;
 322:     lp->d_magic2 = DISKMAGIC;
 323:     lp->d_checksum = 0;
 324:     lp->d_checksum = dkcksum(lp);
 325:     if (rflag) {
 326:         /*
 327: 		 * First set the kernel disk label,
 328: 		 * then write a label to the raw disk.
 329: 		 * If the SDINFO ioctl fails because it is unimplemented,
 330: 		 * keep going; otherwise, the kernel consistency checks
 331: 		 * may prevent us from changing the current (in-core)
 332: 		 * label.  Normally EFAULT would not be here - but the ioctl
 333: 		 * maximum data length changed and old kernels would generate
 334: 		 * an error prematurely in the ioctl dispatch.
 335: 		 */
 336:         if (ioctl(f, DIOCSDINFO, lp) < 0 &&
 337:             errno != EFAULT && errno != ENODEV && errno != ENOTTY) {
 338:             l_perror("ioctl DIOCSDINFO");
 339:             return (1);
 340:         }
 341:         (void)lseek(f, (off_t)0, L_SET);
 342:         /*
 343: 		 * write enable label sector before write (if necessary),
 344: 		 * disable after writing.
 345: 		 */
 346:         flag = 1;
 347:         if (ioctl(f, DIOCWLABEL, &flag) < 0)
 348:             perror("ioctl DIOCWLABEL");
 349: /*
 350:  * Write the boot block sector (512 bytes) followed immediately by the
 351:  * label sector (512 bytes) = BBSIZE (1kb) total.
 352: */
 353:         if (write(f, boot, BBSIZE) != BBSIZE) {
 354:             perror("write");
 355:             return (1);
 356:         }
 357:         flag = 0;
 358:         (void) ioctl(f, DIOCWLABEL, &flag);
 359:     } else if (ioctl(f, DIOCWDINFO, lp) < 0) {
 360:         l_perror("ioctl DIOCWDINFO");
 361:         return (1);
 362:     }
 363:     return (0);
 364: }
 365: 
 366: l_perror(s)
 367:     char *s;
 368: {
 369:     int saverrno = errno;
 370: 
 371:     fprintf(stderr, "disklabel: %s: ", s);
 372: 
 373:     switch (saverrno) {
 374: 
 375:     case ESRCH:
 376:         fprintf(stderr, "No disk label on disk;\n");
 377:         fprintf(stderr,
 378:             "use \"disklabel -r\" to install initial label\n");
 379:         break;
 380: 
 381:     case EINVAL:
 382:         fprintf(stderr, "Label magic number or checksum is wrong!\n");
 383:         fprintf(stderr, "(disklabel or kernel is out of date?)\n");
 384:         break;
 385: 
 386:     case EBUSY:
 387:         fprintf(stderr, "Open partition would move or shrink\n");
 388:         break;
 389: 
 390:     case EXDEV:
 391:         fprintf(stderr,
 392:     "Labeled partition or 'a' partition must start at beginning of disk\n");
 393:         break;
 394: 
 395:     default:
 396:         errno = saverrno;
 397:         perror((char *)NULL);
 398:         break;
 399:     }
 400: }
 401: 
 402: /*
 403:  * Fetch disklabel for disk.
 404:  * Use ioctl to get label unless -r flag is given.
 405:  *
 406:  * We use the search logic for the label even though the label will be
 407:  * in the second half of the bootarea.  If there ever is a valid label
 408:  * residing in the boot sector things are going to get weird.
 409:  */
 410: struct disklabel *
 411: readlabel(f)
 412:     int f;
 413: {
 414:     register struct disklabel *lp;
 415: register struct disklabel *xx = (struct disklabel *)(bootarea + BBSIZE - sizeof (struct disklabel));
 416: 
 417:     if (rflag) {
 418:         if (lseek(f, (daddr_t)0, L_SET) < 0)
 419:             Perror(specname);
 420:         if (read(f, bootarea, BBSIZE) < BBSIZE)
 421:             Perror(specname);
 422:         for (lp = (struct disklabel *)bootarea;
 423:             lp <= xx;
 424:             lp = (struct disklabel *)((char *)lp + 16))
 425:             if (lp->d_magic == DISKMAGIC &&
 426:                 lp->d_magic2 == DISKMAGIC)
 427:                 break;
 428:         if (lp > xx ||
 429:             lp->d_magic != DISKMAGIC || lp->d_magic2 != DISKMAGIC ||
 430:             dkcksum(lp) != 0) {
 431:             fprintf(stderr,
 432:     "Bad pack magic number (label is damaged, or pack is unlabeled)\n");
 433:             exit (1);
 434:         }
 435:     } else {
 436:         lp = &lab;
 437:         if (ioctl(f, DIOCGDINFO, lp) < 0)
 438:             Perror("ioctl DIOCGDINFO");
 439:     }
 440:     return (lp);
 441: }
 442: 
 443: /*
 444:  * Construct a bootarea (d_bbsize bytes) in the specified buffer ``boot''
 445:  * Returns a pointer to the disklabel portion of the bootarea.
 446:  */
 447: struct disklabel *
 448: makebootarea(boot, dp, f)
 449:     char *boot;
 450:     register struct disklabel *dp;
 451:     int f;
 452: {
 453:     struct disklabel *lp;
 454:     register char *p;
 455:     int b;
 456:     char *dkbasename;
 457:     struct stat sb;
 458: 
 459:     /* XXX */
 460:     /*
 461: 	 * sectors are 512 bytes, filesystem blocks are DEV_BSIZE (1024) bytes.
 462: 	 * We override the sector size so that things like the RL02 work
 463: 	 * right.  The RL drives use a hardware sector size of 256 bytes
 464: 	 * which would wreck havoc in the calculation below.  Actually the
 465: 	 * disktab file should be "fixed" - all entries should omit 'se' and
 466: 	 * use the default of 512.
 467: 	*/
 468:     dp->d_secsize = 512;
 469:     dp->d_bbsize = 512;
 470:     lp = (struct disklabel *)
 471:         (boot + (LABELSECTOR * dp->d_secsize) + LABELOFFSET);
 472:     bzero((char *)lp, sizeof *lp);
 473: 
 474:     /*
 475: 	 * If we are not installing a boot program but we are installing a
 476: 	 * label on disk then we must read the current bootarea so we don't
 477: 	 * clobber the existing boot.
 478: 	 */
 479:     if (!installboot) {
 480:         if (rflag) {
 481:             if (lseek(f, (daddr_t)0, L_SET) < 0)
 482:                 Perror(specname);
 483:             if (read(f, boot, BBSIZE) < BBSIZE)
 484:                 Perror(specname);
 485:             bzero((char *)lp, sizeof *lp);
 486:         }
 487:         return (lp);
 488:     }
 489:     /*
 490: 	 * We are installing a boot program.  Determine the name(s) and
 491: 	 * read them into the appropriate places in the boot area.
 492: 	 */
 493:     if (!xxboot) {
 494:         dkbasename = np;
 495:         if ((p = rindex(dkname, '/')) == NULL)
 496:             p = dkname;
 497:         else
 498:             p++;
 499:         while (*p && !isdigit(*p))
 500:             *np++ = *p++;
 501:         *np++ = '\0';
 502: 
 503:         (void)sprintf(np, "%s/%suboot",
 504:                   _PATH_BOOTDIR, dkbasename);
 505:         if (access(np, F_OK) < 0 && dkbasename[0] == 'r')
 506:             dkbasename++;
 507:         xxboot = np;
 508:         (void)sprintf(xxboot, "%s/%suboot",
 509:                   _PATH_BOOTDIR, dkbasename);
 510:         np += strlen(xxboot) + 1;
 511:     }
 512: #ifdef DEBUG
 513:     if (debug)
 514:         fprintf(stderr, "bootstrap: xxboot = %s\n", xxboot);
 515: #endif
 516: 
 517:     /*
 518: 	 * Rule:
 519: 	 * 1. One-piece bootstrap up to 512 bytes is all that is supported.
 520: 	 */
 521:     b = open(xxboot, O_RDONLY);
 522:     if (b < 0)
 523:         Perror(xxboot);
 524:     if (read(b, boot, 512) < 0)
 525:         Perror(xxboot);
 526:     (void)fstat(b, &sb);
 527:     if (sb.st_size > 512)
 528:         Warning("boot > 512 bytes - filesystem likely not bootable");
 529:     (void)close(b);
 530:     return (lp);
 531: }
 532: 
 533: display(f, lp)
 534:     FILE *f;
 535:     register struct disklabel *lp;
 536: {
 537:     register int i, j;
 538:     register struct partition *pp;
 539: 
 540:     fprintf(f, "# %s:\n", specname);
 541:     if ((unsigned) lp->d_type < DKMAXTYPES)
 542:         fprintf(f, "type: %s\n", dktypenames[lp->d_type]);
 543:     else
 544:         fprintf(f, "type: %d\n", lp->d_type);
 545:     fprintf(f, "disk: %.*s\n", sizeof(lp->d_typename), lp->d_typename);
 546:     fprintf(f, "label: %.*s\n", sizeof(lp->d_packname), lp->d_packname);
 547:     fprintf(f, "flags:");
 548:     if (lp->d_flags & D_REMOVABLE)
 549:         fprintf(f, " removeable");
 550:     if (lp->d_flags & D_ECC)
 551:         fprintf(f, " ecc");
 552:     if (lp->d_flags & D_BADSECT)
 553:         fprintf(f, " badsect");
 554:     fprintf(f, "\n");
 555:     fprintf(f, "bytes/sector: %d\n", lp->d_secsize);
 556:     fprintf(f, "sectors/track: %d\n", lp->d_nsectors);
 557:     fprintf(f, "tracks/cylinder: %d\n", lp->d_ntracks);
 558:     fprintf(f, "sectors/cylinder: %d\n", lp->d_secpercyl);
 559:     fprintf(f, "cylinders: %d\n", lp->d_ncylinders);
 560:     fprintf(f, "rpm: %d\n", lp->d_rpm);
 561:     fprintf(f, "interleave: %d\n", lp->d_interleave);
 562:     fprintf(f, "trackskew: %d\n", lp->d_trackskew);
 563:     fprintf(f, "cylinderskew: %d\n", lp->d_cylskew);
 564:     fprintf(f, "headswitch: %d\t\t# milliseconds\n", lp->d_headswitch);
 565:     fprintf(f, "track-to-track seek: %d\t# milliseconds\n", lp->d_trkseek);
 566:     fprintf(f, "drivedata: ");
 567:     for (i = NDDATA - 1; i >= 0; i--)
 568:         if (lp->d_drivedata[i])
 569:             break;
 570:     if (i < 0)
 571:         i = 0;
 572:     for (j = 0; j <= i; j++)
 573:         fprintf(f, "%ld ", lp->d_drivedata[j]);
 574:     fprintf(f, "\n\n%d partitions:\n", lp->d_npartitions);
 575:     fprintf(f,
 576:         "#        size   offset    fstype   [fsize bsize]\n");
 577:     pp = lp->d_partitions;
 578:     for (i = 0; i < lp->d_npartitions; i++, pp++) {
 579:         if (pp->p_size) {
 580:             fprintf(f, "  %c: %8ld %8ld  ", 'a' + i,
 581:                pp->p_size, pp->p_offset);
 582:             if ((unsigned) pp->p_fstype < FSMAXTYPES)
 583:                 fprintf(f, "%8.8s", fstypenames[pp->p_fstype]);
 584:             else
 585:                 fprintf(f, "%8d", pp->p_fstype);
 586:             switch (pp->p_fstype) {
 587: 
 588:             case FS_V71K:
 589:             case FS_UNUSED:             /* XXX */
 590:                 fprintf(f, "    %5d %5d ",
 591:                     pp->p_fsize, pp->p_fsize * pp->p_frag);
 592:                 break;
 593: 
 594:             default:
 595:                 fprintf(f, "%20.20s", "");
 596:                 break;
 597:             }
 598:             fprintf(f, "\t# (Cyl. %4ld",
 599:                 pp->p_offset / lp->d_secpercyl);
 600:             if (pp->p_offset % lp->d_secpercyl)
 601:                 putc('*', f);
 602:             else
 603:                 putc(' ', f);
 604:             fprintf(f, "- %ld",
 605:                 (pp->p_offset +
 606:                 pp->p_size + lp->d_secpercyl - 1) /
 607:                 lp->d_secpercyl - 1);
 608:             if (pp->p_size % lp->d_secpercyl)
 609:                 putc('*', f);
 610:             fprintf(f, ")\n");
 611:         }
 612:     }
 613:     fflush(f);
 614: }
 615: 
 616: edit(lp, f)
 617:     struct disklabel *lp;
 618:     int f;
 619: {
 620:     register int c;
 621:     struct disklabel label;
 622:     FILE *fd;
 623:     char *mktemp();
 624: 
 625:     (void) mktemp(tmpfil);
 626:     fd = fopen(tmpfil, "w");
 627:     if (fd == NULL) {
 628:         fprintf(stderr, "%s: Can't create\n", tmpfil);
 629:         return (1);
 630:     }
 631:     (void)fchmod(fileno(fd), 0600);
 632:     display(fd, lp);
 633:     fclose(fd);
 634:     for (;;) {
 635:         if (!editit())
 636:             break;
 637:         fd = fopen(tmpfil, "r");
 638:         if (fd == NULL) {
 639:             fprintf(stderr, "%s: Can't reopen for reading\n",
 640:                 tmpfil);
 641:             break;
 642:         }
 643:         bzero((char *)&label, sizeof(label));
 644:         if (getasciilabel(fd, &label)) {
 645:             *lp = label;
 646:             if (writelabel(f, bootarea, lp) == 0) {
 647:                 (void) unlink(tmpfil);
 648:                 return (0);
 649:             }
 650:         }
 651:         printf("re-edit the label? [y]: "); fflush(stdout);
 652:         c = getchar();
 653:         if (c != EOF && c != (int)'\n')
 654:             while (getchar() != (int)'\n')
 655:                 ;
 656:         if  (c == (int)'n')
 657:             break;
 658:     }
 659:     (void) unlink(tmpfil);
 660:     return (1);
 661: }
 662: 
 663: editit()
 664: {
 665:     register int pid, xpid;
 666:     int stat;
 667:     sigset_t set, oset;
 668: 
 669:     sigemptyset(&set);
 670:     sigaddset(&set, SIGINT);
 671:     sigaddset(&set, SIGHUP);
 672:     sigaddset(&set, SIGQUIT);
 673:     (void)sigprocmask(SIG_BLOCK, &set, &oset);
 674:     while ((pid = fork()) < 0) {
 675: 
 676:         if (errno == EPROCLIM) {
 677:             fprintf(stderr, "You have too many processes\n");
 678:             return(0);
 679:         }
 680:         if (errno != EAGAIN) {
 681:             perror("fork");
 682:             return(0);
 683:         }
 684:         sleep(1);
 685:     }
 686:     if (pid == 0) {
 687:         register char *ed;
 688: 
 689:         (void)sigprocmask(SIG_SETMASK, &oset, NULL);
 690:         setgid(getgid());
 691:         setuid(getuid());
 692:         if ((ed = getenv("EDITOR")) == (char *)0)
 693:             ed = DEFEDITOR;
 694:         execlp(ed, ed, tmpfil, 0);
 695:         perror(ed);
 696:         exit(1);
 697:     }
 698:     while ((xpid = wait(&stat)) >= 0)
 699:         if (xpid == pid)
 700:             break;
 701:     (void)sigprocmask(SIG_SETMASK, &oset, NULL);
 702:     return(!stat);
 703: }
 704: 
 705: char *
 706: skip(cp)
 707:     register char *cp;
 708: {
 709: 
 710:     while (*cp != '\0' && isspace(*cp))
 711:         cp++;
 712:     if (*cp == '\0' || *cp == '#')
 713:         return ((char *)NULL);
 714:     return (cp);
 715: }
 716: 
 717: char *
 718: word(cp)
 719:     register char *cp;
 720: {
 721:     register char c;
 722: 
 723:     while (*cp != '\0' && !isspace(*cp) && *cp != '#')
 724:         cp++;
 725:     if ((c = *cp) != '\0') {
 726:         *cp++ = '\0';
 727:         if (c != '#')
 728:             return (skip(cp));
 729:     }
 730:     return ((char *)NULL);
 731: }
 732: 
 733: /*
 734:  * Read an ascii label in from fd f,
 735:  * in the same format as that put out by display(),
 736:  * and fill in lp.
 737:  */
 738: getasciilabel(f, lp)
 739:     FILE    *f;
 740:     register struct disklabel *lp;
 741: {
 742:     register char **cpp, *cp;
 743:     register struct partition *pp;
 744:     char *tp, *s, line[BUFSIZ];
 745:     int lineno = 0, errors = 0;
 746:     long v;
 747: 
 748:     lp->d_bbsize = 512;             /* XXX */
 749:     lp->d_sbsize = SBSIZE;
 750:     while (fgets(line, sizeof(line) - 1, f)) {
 751:         lineno++;
 752:         if (cp = index(line,'\n'))
 753:             *cp = '\0';
 754:         cp = skip(line);
 755:         if (cp == NULL)
 756:             continue;
 757:         tp = index(cp, ':');
 758:         if (tp == NULL) {
 759:             fprintf(stderr, "line %d: syntax error\n", lineno);
 760:             errors++;
 761:             continue;
 762:         }
 763:         *tp++ = '\0', tp = skip(tp);
 764:         if (streq(cp, "type")) {
 765:             if (tp == NULL)
 766:                 tp = "unknown";
 767:             cpp = dktypenames;
 768:             for (; cpp < &dktypenames[DKMAXTYPES]; cpp++)
 769:                 if ((s = *cpp) && streq(s, tp)) {
 770:                     lp->d_type = cpp - dktypenames;
 771:                     goto next;
 772:                 }
 773:             v = atoi(tp);
 774:             if ((unsigned)v >= DKMAXTYPES)
 775:                 fprintf(stderr, "line %d:%s %d\n", lineno,
 776:                     "Warning, unknown disk type", v);
 777:             lp->d_type = v;
 778:             continue;
 779:         }
 780:         if (streq(cp, "flags")) {
 781:             for (v = 0; (cp = tp) && *cp != '\0';) {
 782:                 tp = word(cp);
 783:                 if (streq(cp, "removeable"))
 784:                     v |= D_REMOVABLE;
 785:                 else if (streq(cp, "ecc"))
 786:                     v |= D_ECC;
 787:                 else if (streq(cp, "badsect"))
 788:                     v |= D_BADSECT;
 789:                 else {
 790:                     fprintf(stderr,
 791:                         "line %d: %s: bad flag\n",
 792:                         lineno, cp);
 793:                     errors++;
 794:                 }
 795:             }
 796:             lp->d_flags = v;
 797:             continue;
 798:         }
 799:         if (streq(cp, "drivedata")) {
 800:             register int i;
 801: 
 802:             for (i = 0; (cp = tp) && *cp != '\0' && i < NDDATA;) {
 803:                 lp->d_drivedata[i++] = atol(cp);
 804:                 tp = word(cp);
 805:             }
 806:             continue;
 807:         }
 808:         if (sscanf(cp, "%ld partitions", &v) == 1) {
 809:             if (v == 0 || (unsigned)v > MAXPARTITIONS) {
 810:                 fprintf(stderr,
 811:                     "line %d: bad # of partitions\n", lineno);
 812:                 lp->d_npartitions = MAXPARTITIONS;
 813:                 errors++;
 814:             } else
 815:                 lp->d_npartitions = v;
 816:             continue;
 817:         }
 818:         if (tp == NULL)
 819:             tp = "";
 820:         if (streq(cp, "disk")) {
 821:             strncpy(lp->d_typename, tp, sizeof (lp->d_typename));
 822:             continue;
 823:         }
 824:         if (streq(cp, "label")) {
 825:             strncpy(lp->d_packname, tp, sizeof (lp->d_packname));
 826:             continue;
 827:         }
 828: /*
 829:  * ARGH!  Have to fix the 'se#256' entries in disktab after all or this
 830:  * check will cause errors.
 831: */
 832:         if (streq(cp, "bytes/sector")) {
 833:             v = atoi(tp);
 834:             if (v <= 0 || (v % 512) != 0) {
 835:                 fprintf(stderr,
 836:                     "line %d: %s: bad sector size\n",
 837:                     lineno, tp);
 838:                 errors++;
 839:             } else
 840:                 lp->d_secsize = v;
 841:             continue;
 842:         }
 843:         if (streq(cp, "sectors/track")) {
 844:             v = atoi(tp);
 845:             if (v <= 0) {
 846:                 fprintf(stderr, "line %d: %s: bad %s\n",
 847:                     lineno, tp, cp);
 848:                 errors++;
 849:             } else
 850:                 lp->d_nsectors = v;
 851:             continue;
 852:         }
 853:         if (streq(cp, "sectors/cylinder")) {
 854:             v = atoi(tp);
 855:             if (v <= 0) {
 856:                 fprintf(stderr, "line %d: %s: bad %s\n",
 857:                     lineno, tp, cp);
 858:                 errors++;
 859:             } else
 860:                 lp->d_secpercyl = v;
 861:             continue;
 862:         }
 863:         if (streq(cp, "tracks/cylinder")) {
 864:             v = atoi(tp);
 865:             if (v <= 0) {
 866:                 fprintf(stderr, "line %d: %s: bad %s\n",
 867:                     lineno, tp, cp);
 868:                 errors++;
 869:             } else
 870:                 lp->d_ntracks = v;
 871:             continue;
 872:         }
 873:         if (streq(cp, "cylinders")) {
 874:             v = atoi(tp);
 875:             if (v <= 0) {
 876:                 fprintf(stderr, "line %d: %s: bad %s\n",
 877:                     lineno, tp, cp);
 878:                 errors++;
 879:             } else
 880:                 lp->d_ncylinders = v;
 881:             continue;
 882:         }
 883:         if (streq(cp, "rpm")) {
 884:             v = atoi(tp);
 885:             if (v <= 0) {
 886:                 fprintf(stderr, "line %d: %s: bad %s\n",
 887:                     lineno, tp, cp);
 888:                 errors++;
 889:             } else
 890:                 lp->d_rpm = v;
 891:             continue;
 892:         }
 893:         if (streq(cp, "interleave")) {
 894:             v = atoi(tp);
 895:             if (v <= 0) {
 896:                 fprintf(stderr, "line %d: %s: bad %s\n",
 897:                     lineno, tp, cp);
 898:                 errors++;
 899:             } else
 900:                 lp->d_interleave = v;
 901:             continue;
 902:         }
 903:         if (streq(cp, "trackskew")) {
 904:             v = atoi(tp);
 905:             if (v < 0) {
 906:                 fprintf(stderr, "line %d: %s: bad %s\n",
 907:                     lineno, tp, cp);
 908:                 errors++;
 909:             } else
 910:                 lp->d_trackskew = v;
 911:             continue;
 912:         }
 913:         if (streq(cp, "cylinderskew")) {
 914:             v = atoi(tp);
 915:             if (v < 0) {
 916:                 fprintf(stderr, "line %d: %s: bad %s\n",
 917:                     lineno, tp, cp);
 918:                 errors++;
 919:             } else
 920:                 lp->d_cylskew = v;
 921:             continue;
 922:         }
 923:         if (streq(cp, "headswitch")) {
 924:             v = atoi(tp);
 925:             if (v < 0) {
 926:                 fprintf(stderr, "line %d: %s: bad %s\n",
 927:                     lineno, tp, cp);
 928:                 errors++;
 929:             } else
 930:                 lp->d_headswitch = v;
 931:             continue;
 932:         }
 933:         if (streq(cp, "track-to-track seek")) {
 934:             v = atoi(tp);
 935:             if (v < 0) {
 936:                 fprintf(stderr, "line %d: %s: bad %s\n",
 937:                     lineno, tp, cp);
 938:                 errors++;
 939:             } else
 940:                 lp->d_trkseek = v;
 941:             continue;
 942:         }
 943:         if ('a' <= *cp && *cp <= 'z' && cp[1] == '\0') {
 944:             unsigned part = *cp - 'a';
 945: 
 946:             if (part > lp->d_npartitions) {
 947:                 fprintf(stderr,
 948:                     "line %d: bad partition name '%c' %d %d\n",
 949:                     lineno, *cp, part, lp->d_npartitions);
 950:                 errors++;
 951:                 continue;
 952:             }
 953:             pp = &lp->d_partitions[part];
 954: #define NXTNUM(n) { \
 955:     cp = tp, tp = word(cp); \
 956:     if (tp == NULL) \
 957:         tp = cp; \
 958:     (n) = atol(cp); \
 959:      }
 960: 
 961:             NXTNUM(v);
 962:             if (v < 0) {
 963:                 fprintf(stderr,
 964:                     "line %d: %s: bad partition size\n",
 965:                     lineno, cp);
 966:                 errors++;
 967:             } else
 968:                 pp->p_size = v;
 969:             NXTNUM(v);
 970:             if (v < 0) {
 971:                 fprintf(stderr,
 972:                     "line %d: %s: bad partition offset\n",
 973:                     lineno, cp);
 974:                 errors++;
 975:             } else
 976:                 pp->p_offset = v;
 977:             cp = tp, tp = word(cp);
 978:             cpp = fstypenames;
 979:             for (; cpp < &fstypenames[FSMAXTYPES]; cpp++)
 980:                 if ((s = *cpp) && streq(s, cp)) {
 981:                     pp->p_fstype = cpp - fstypenames;
 982:                     goto gottype;
 983:                 }
 984:             if (isdigit(*cp))
 985:                 v = atoi(cp);
 986:             else
 987:                 v = FSMAXTYPES;
 988:             if ((unsigned)v >= FSMAXTYPES) {
 989:                 fprintf(stderr, "line %d: %s %s\n", lineno,
 990:                     "Warning, unknown filesystem type", cp);
 991:                 v = FS_UNUSED;
 992:             }
 993:             pp->p_fstype = v;
 994:     gottype:
 995: 
 996:             switch (pp->p_fstype) {
 997: 
 998:             case FS_UNUSED:             /* XXX */
 999:             case FS_V71K:
1000:                 NXTNUM(pp->p_fsize);
1001:                 if (pp->p_fsize == 0)
1002:                     break;
1003:                 NXTNUM(v);
1004:                 pp->p_frag = v / pp->p_fsize;
1005:                 break;
1006: 
1007:             default:
1008:                 break;
1009:             }
1010:             continue;
1011:         }
1012:         fprintf(stderr, "line %d: %s: Unknown disklabel field\n",
1013:             lineno, cp);
1014:         errors++;
1015:     next:
1016:         ;
1017:     }
1018:     errors += checklabel(lp);
1019:     return (errors == 0);
1020: }
1021: 
1022: /*
1023:  * Check disklabel for errors and fill in
1024:  * derived fields according to supplied values.
1025:  */
1026: checklabel(lp)
1027:     register struct disklabel *lp;
1028: {
1029:     register struct partition *pp;
1030:     int i, errors = 0;
1031:     char part;
1032: 
1033:     if (lp->d_secsize == 0) {
1034:         fprintf(stderr, "sector size %d\n", lp->d_secsize);
1035:         return (1);
1036:     }
1037:     if (lp->d_nsectors == 0) {
1038:         fprintf(stderr, "sectors/track %d\n", lp->d_nsectors);
1039:         return (1);
1040:     }
1041:     if (lp->d_ntracks == 0) {
1042:         fprintf(stderr, "tracks/cylinder %d\n", lp->d_ntracks);
1043:         return (1);
1044:     }
1045:     if  (lp->d_ncylinders == 0) {
1046:         fprintf(stderr, "cylinders/unit %d\n", lp->d_ncylinders);
1047:         errors++;
1048:     }
1049:     if (lp->d_rpm == 0)
1050:         Warning("revolutions/minute %d", lp->d_rpm);
1051:     if (lp->d_secpercyl == 0)
1052:         lp->d_secpercyl = lp->d_nsectors * lp->d_ntracks;
1053:     if (lp->d_secperunit == 0)
1054:         lp->d_secperunit = (long) lp->d_secpercyl * lp->d_ncylinders;
1055:     if (lp->d_bbsize == 0) {
1056:         fprintf(stderr, "boot block size %d\n", lp->d_bbsize);
1057:         errors++;
1058:     } else if (lp->d_bbsize % lp->d_secsize)
1059:         Warning("boot block size %% sector-size != 0");
1060:     if (lp->d_sbsize == 0) {
1061:         fprintf(stderr, "super block size %d\n", lp->d_sbsize);
1062:         errors++;
1063:     } else if (lp->d_sbsize % lp->d_secsize)
1064:         Warning("super block size %% sector-size != 0");
1065:     if (lp->d_npartitions > MAXPARTITIONS)
1066:         Warning("number of partitions (%d) > MAXPARTITIONS (%d)",
1067:             lp->d_npartitions, MAXPARTITIONS);
1068:     for (i = 0; i < lp->d_npartitions; i++) {
1069:         part = 'a' + i;
1070:         pp = &lp->d_partitions[i];
1071:         if (pp->p_size == 0 && pp->p_offset != 0)
1072:             Warning("partition %c: size 0, but offset %ld",
1073:                 part, pp->p_offset);
1074: #ifdef notdef
1075:         if (pp->p_size % lp->d_secpercyl)
1076:             Warning("partition %c: size %% cylinder-size != 0",
1077:                 part);
1078:         if (pp->p_offset % lp->d_secpercyl)
1079:             Warning("partition %c: offset %% cylinder-size != 0",
1080:                 part);
1081: #endif
1082:         if (pp->p_offset > lp->d_secperunit) {
1083:             fprintf(stderr,
1084:                 "partition %c: offset past end of unit %ld %ld\n",
1085:                 part, pp->p_offset, lp->d_secperunit);
1086:             errors++;
1087:         }
1088:         if (pp->p_offset + pp->p_size > lp->d_secperunit) {
1089:             fprintf(stderr,
1090:                 "partition %c: extends past end of unit %ld %ld %ld\n",
1091:                 part, pp->p_offset, pp->p_size, lp->d_secperunit);
1092:             errors++;
1093:         }
1094:     }
1095:     for (; i < MAXPARTITIONS; i++) {
1096:         part = 'a' + i;
1097:         pp = &lp->d_partitions[i];
1098:         if (pp->p_size || pp->p_offset)
1099:             Warning("unused partition %c: size %ld offset %ld",
1100:                 'a' + i, pp->p_size, pp->p_offset);
1101:     }
1102:     return (errors);
1103: }
1104: 
1105: /*VARARGS1*/
1106: Warning(fmt, a1, a2, a3, a4, a5)
1107:     char *fmt;
1108: {
1109: 
1110:     fprintf(stderr, "Warning, ");
1111:     fprintf(stderr, fmt, a1, a2, a3, a4, a5);
1112:     fprintf(stderr, "\n");
1113: }
1114: 
1115: Perror(str)
1116:     char *str;
1117: {
1118:     fputs("disklabel: ", stderr); perror(str);
1119:     exit(4);
1120: }
1121: 
1122: usage()
1123: {
1124:     fprintf(stderr,
1125: "%s\n\t%s\n%s\n\t%s\n%s\n\t%s\n%s\n\t%s\n%s\n\t%s\n%s\n\t%s\n%s\n\t%s\n%s\n\t%s\n",
1126: "usage: disklabel [-r] disk",
1127:         "(to read label)",
1128: "or disklabel -w [-r] disk type [ packid ]",
1129:         "(to write label with existing boot program)",
1130: "or disklabel -e [-r] disk",
1131:         "(to edit label)",
1132: "or disklabel -R [-r] disk protofile",
1133:         "(to restore label with existing boot program)",
1134: "or disklabel -B [ -b bootprog ] disk [ type ]",
1135:         "(to install boot program with existing on-disk label)",
1136: "or disklabel -w -B [ -b bootprog ] disk type [ packid ]",
1137:         "(to write label and install boot program)",
1138: "or disklabel -R -B [ -b bootprog ] disk protofile [ type ]",
1139:         "(to restore label and install boot program)",
1140: "or disklabel [-NW] disk",
1141:         "(to write disable/enable label)");
1142:     exit(1);
1143: }

Defined functions

Perror defined in line 1115; used 11 times
Warning defined in line 1106; used 9 times
checklabel defined in line 1026; used 4 times
display defined in line 533; used 2 times
edit defined in line 616; used 1 times
editit defined in line 663; used 1 times
getasciilabel defined in line 738; used 2 times
l_perror defined in line 366; used 2 times
main defined in line 113; never used
makebootarea defined in line 447; used 4 times
makelabel defined in line 278; used 3 times
readlabel defined in line 410; used 4 times
skip defined in line 705; used 3 times
usage defined in line 1122; used 11 times
word defined in line 717; used 4 times
writelabel defined in line 313; used 4 times

Defined variables

boot0 defined in line 98; used 3 times
bootarea defined in line 94; used 10 times
copyright defined in line 38; never used
debug defined in line 107; used 2 times
dkname defined in line 87; used 8 times
installboot defined in line 96; used 4 times
lab defined in line 92; used 8 times
namebuf defined in line 91; used 2 times
np defined in line 91; used 11 times
rflag defined in line 104; used 5 times
sccsid defined in line 42; never used
specname defined in line 88; used 13 times
tmpfil defined in line 89; used 8 times
xxboot defined in line 97; used 12 times

Defined macros

DEFEDITOR defined in line 84; used 1 times
DKTYPENAMES defined in line 52; never used
NXTNUM defined in line 954; used 4 times
OPTIONS defined in line 110; used 1 times
RAWPARTITION defined in line 82; used 1 times
streq defined in line 85; used 21 times
Last modified: 1999-10-26
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 7500
Valid CSS Valid XHTML 1.0 Strict