home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / sbin / disklabel / disklabel.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-04-20  |  26.1 KB  |  1,135 lines

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