summaryrefslogtreecommitdiffstats
path: root/sbin/disklabel/disklabel.c
diff options
context:
space:
mode:
Diffstat (limited to 'sbin/disklabel/disklabel.c')
-rw-r--r--sbin/disklabel/disklabel.c1314
1 files changed, 1314 insertions, 0 deletions
diff --git a/sbin/disklabel/disklabel.c b/sbin/disklabel/disklabel.c
new file mode 100644
index 0000000..4a29340
--- /dev/null
+++ b/sbin/disklabel/disklabel.c
@@ -0,0 +1,1314 @@
+/*
+ * Copyright (c) 1987, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Symmetric Computer Systems.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char copyright[] =
+"@(#) Copyright (c) 1987, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)disklabel.c 8.2 (Berkeley) 1/7/94";
+/* from static char sccsid[] = "@(#)disklabel.c 1.2 (Symmetric) 11/28/85"; */
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/signal.h>
+#include <sys/errno.h>
+#include <sys/file.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#define DKTYPENAMES
+#include <sys/disklabel.h>
+#include <ufs/ffs/fs.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdio.h>
+#include <ctype.h>
+#include "pathnames.h"
+
+/*
+ * Disklabel: read and write disklabels.
+ * The label is usually placed on one of the first sectors of the disk.
+ * Many machines also place a bootstrap in the same area,
+ * in which case the label is embedded in the bootstrap.
+ * The bootstrap source must leave space at the proper offset
+ * for the label on such machines.
+ */
+
+#ifdef tahoe
+#define RAWPARTITION 'a'
+#else
+#define RAWPARTITION 'c'
+#endif
+
+#ifndef BBSIZE
+#define BBSIZE 8192 /* size of boot area, with label */
+#endif
+
+#ifdef tahoe
+#define NUMBOOT 0
+#else
+#if defined(hp300) || defined(hp800)
+#define NUMBOOT 1
+#else
+#define NUMBOOT 2
+#endif
+#endif
+
+#define DEFEDITOR _PATH_VI
+#define streq(a,b) (strcmp(a,b) == 0)
+
+char *dkname;
+char *specname;
+char tmpfil[] = _PATH_TMP;
+
+extern int errno;
+char namebuf[BBSIZE], *np = namebuf;
+struct disklabel lab;
+struct disklabel *readlabel(), *makebootarea();
+char bootarea[BBSIZE];
+
+#if NUMBOOT > 0
+int installboot; /* non-zero if we should install a boot program */
+char *bootbuf; /* pointer to buffer with remainder of boot prog */
+int bootsize; /* size of remaining boot program */
+char *xxboot; /* primary boot */
+char *bootxx; /* secondary boot */
+char boot0[MAXPATHLEN];
+char boot1[MAXPATHLEN];
+#endif
+
+enum {
+ UNSPEC, EDIT, NOWRITE, READ, RESTORE, WRITE, WRITEABLE, WRITEBOOT
+} op = UNSPEC;
+
+int rflag;
+
+#ifdef DEBUG
+int debug;
+#define OPTIONS "BNRWb:ders:w"
+#else
+#define OPTIONS "BNRWb:ers:w"
+#endif
+
+
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ extern char *optarg;
+ extern int optind;
+ register struct disklabel *lp;
+ FILE *t;
+ int ch, f, flag, error = 0;
+ char *name = 0;
+
+ while ((ch = getopt(argc, argv, OPTIONS)) != EOF)
+ switch (ch) {
+#if NUMBOOT > 0
+ case 'B':
+ ++installboot;
+ break;
+ case 'b':
+ xxboot = optarg;
+ break;
+#if NUMBOOT > 1
+ case 's':
+ bootxx = optarg;
+ break;
+#endif
+#endif
+ case 'N':
+ if (op != UNSPEC)
+ usage();
+ op = NOWRITE;
+ break;
+ case 'R':
+ if (op != UNSPEC)
+ usage();
+ op = RESTORE;
+ break;
+ case 'W':
+ if (op != UNSPEC)
+ usage();
+ op = WRITEABLE;
+ break;
+ case 'e':
+ if (op != UNSPEC)
+ usage();
+ op = EDIT;
+ break;
+ case 'r':
+ ++rflag;
+ break;
+ case 'w':
+ if (op != UNSPEC)
+ usage();
+ op = WRITE;
+ break;
+#ifdef DEBUG
+ case 'd':
+ debug++;
+ break;
+#endif
+ case '?':
+ default:
+ usage();
+ }
+ argc -= optind;
+ argv += optind;
+#if NUMBOOT > 0
+ if (installboot) {
+ rflag++;
+ if (op == UNSPEC)
+ op = WRITEBOOT;
+ } else {
+ if (op == UNSPEC)
+ op = READ;
+ xxboot = bootxx = 0;
+ }
+#else
+ if (op == UNSPEC)
+ op = READ;
+#endif
+ if (argc < 1)
+ usage();
+
+ dkname = argv[0];
+ if (dkname[0] != '/') {
+ (void)sprintf(np, "%sr%s%c", _PATH_DEV, dkname, RAWPARTITION);
+ specname = np;
+ np += strlen(specname) + 1;
+ } else
+ specname = dkname;
+ f = open(specname, op == READ ? O_RDONLY : O_RDWR);
+ if (f < 0 && errno == ENOENT && dkname[0] != '/') {
+ (void)sprintf(specname, "%sr%s", _PATH_DEV, dkname);
+ np = namebuf + strlen(specname) + 1;
+ f = open(specname, op == READ ? O_RDONLY : O_RDWR);
+ }
+ if (f < 0)
+ Perror(specname);
+
+ switch(op) {
+
+ case EDIT:
+ if (argc != 1)
+ usage();
+ lp = readlabel(f);
+ error = edit(lp, f);
+ break;
+
+ case NOWRITE:
+ flag = 0;
+ if (ioctl(f, DIOCWLABEL, (char *)&flag) < 0)
+ Perror("ioctl DIOCWLABEL");
+ break;
+
+ case READ:
+ if (argc != 1)
+ usage();
+ lp = readlabel(f);
+ display(stdout, lp);
+ error = checklabel(lp);
+ break;
+
+ case RESTORE:
+#if NUMBOOT > 0
+ if (installboot && argc == 3) {
+ makelabel(argv[2], 0, &lab);
+ argc--;
+ }
+#endif
+ if (argc != 2)
+ usage();
+ lp = makebootarea(bootarea, &lab, f);
+ if (!(t = fopen(argv[1], "r")))
+ Perror(argv[1]);
+ if (getasciilabel(t, lp))
+ error = writelabel(f, bootarea, lp);
+ break;
+
+ case WRITE:
+ if (argc == 3) {
+ name = argv[2];
+ argc--;
+ }
+ if (argc != 2)
+ usage();
+ makelabel(argv[1], name, &lab);
+ lp = makebootarea(bootarea, &lab, f);
+ *lp = lab;
+ if (checklabel(lp) == 0)
+ error = writelabel(f, bootarea, lp);
+ break;
+
+ case WRITEABLE:
+ flag = 1;
+ if (ioctl(f, DIOCWLABEL, (char *)&flag) < 0)
+ Perror("ioctl DIOCWLABEL");
+ break;
+
+#if NUMBOOT > 0
+ case WRITEBOOT:
+ {
+ struct disklabel tlab;
+
+ lp = readlabel(f);
+ tlab = *lp;
+ if (argc == 2)
+ makelabel(argv[1], 0, &lab);
+ lp = makebootarea(bootarea, &lab, f);
+ *lp = tlab;
+ if (checklabel(lp) == 0)
+ error = writelabel(f, bootarea, lp);
+ break;
+ }
+#endif
+ }
+ exit(error);
+}
+
+/*
+ * Construct a prototype disklabel from /etc/disktab. As a side
+ * effect, set the names of the primary and secondary boot files
+ * if specified.
+ */
+makelabel(type, name, lp)
+ char *type, *name;
+ register struct disklabel *lp;
+{
+ register struct disklabel *dp;
+ char *strcpy();
+
+ dp = getdiskbyname(type);
+ if (dp == NULL) {
+ fprintf(stderr, "%s: unknown disk type\n", type);
+ exit(1);
+ }
+ *lp = *dp;
+#if NUMBOOT > 0
+ /*
+ * Set bootstrap name(s).
+ * 1. If set from command line, use those,
+ * 2. otherwise, check if disktab specifies them (b0 or b1),
+ * 3. otherwise, makebootarea() will choose ones based on the name
+ * of the disk special file. E.g. /dev/ra0 -> raboot, bootra
+ */
+ if (!xxboot && lp->d_boot0) {
+ if (*lp->d_boot0 != '/')
+ (void)sprintf(boot0, "%s/%s",
+ _PATH_BOOTDIR, lp->d_boot0);
+ else
+ (void)strcpy(boot0, lp->d_boot0);
+ xxboot = boot0;
+ }
+#if NUMBOOT > 1
+ if (!bootxx && lp->d_boot1) {
+ if (*lp->d_boot1 != '/')
+ (void)sprintf(boot1, "%s/%s",
+ _PATH_BOOTDIR, lp->d_boot1);
+ else
+ (void)strcpy(boot1, lp->d_boot1);
+ bootxx = boot1;
+ }
+#endif
+#endif
+ /* d_packname is union d_boot[01], so zero */
+ bzero(lp->d_packname, sizeof(lp->d_packname));
+ if (name)
+ (void)strncpy(lp->d_packname, name, sizeof(lp->d_packname));
+}
+
+writelabel(f, boot, lp)
+ int f;
+ char *boot;
+ register struct disklabel *lp;
+{
+ register int i;
+ int flag;
+
+ setbootflag(lp);
+ lp->d_magic = DISKMAGIC;
+ lp->d_magic2 = DISKMAGIC;
+ lp->d_checksum = 0;
+ lp->d_checksum = dkcksum(lp);
+ if (rflag) {
+ /*
+ * First set the kernel disk label,
+ * then write a label to the raw disk.
+ * If the SDINFO ioctl fails because it is unimplemented,
+ * keep going; otherwise, the kernel consistency checks
+ * may prevent us from changing the current (in-core)
+ * label.
+ */
+ if (ioctl(f, DIOCSDINFO, lp) < 0 &&
+ errno != ENODEV && errno != ENOTTY) {
+ l_perror("ioctl DIOCSDINFO");
+ return (1);
+ }
+ (void)lseek(f, (off_t)0, SEEK_SET);
+ /*
+ * write enable label sector before write (if necessary),
+ * disable after writing.
+ */
+ flag = 1;
+ if (ioctl(f, DIOCWLABEL, &flag) < 0)
+ perror("ioctl DIOCWLABEL");
+ if (write(f, boot, lp->d_bbsize) != lp->d_bbsize) {
+ perror("write");
+ return (1);
+ }
+#if NUMBOOT > 0
+ /*
+ * Output the remainder of the disklabel
+ */
+ if (bootbuf && write(f, bootbuf, bootsize) != bootsize) {
+ perror("write");
+ return(1);
+ }
+#endif
+ flag = 0;
+ (void) ioctl(f, DIOCWLABEL, &flag);
+ } else if (ioctl(f, DIOCWDINFO, lp) < 0) {
+ l_perror("ioctl DIOCWDINFO");
+ return (1);
+ }
+#ifdef vax
+ if (lp->d_type == DTYPE_SMD && lp->d_flags & D_BADSECT) {
+ daddr_t alt;
+
+ alt = lp->d_ncylinders * lp->d_secpercyl - lp->d_nsectors;
+ for (i = 1; i < 11 && i < lp->d_nsectors; i += 2) {
+ (void)lseek(f, (off_t)((alt + i) * lp->d_secsize),
+ SEEK_SET);
+ if (write(f, boot, lp->d_secsize) < lp->d_secsize) {
+ int oerrno = errno;
+ fprintf(stderr, "alternate label %d ", i/2);
+ errno = oerrno;
+ perror("write");
+ }
+ }
+ }
+#endif
+ return (0);
+}
+
+l_perror(s)
+ char *s;
+{
+ int saverrno = errno;
+
+ fprintf(stderr, "disklabel: %s: ", s);
+
+ switch (saverrno) {
+
+ case ESRCH:
+ fprintf(stderr, "No disk label on disk;\n");
+ fprintf(stderr,
+ "use \"disklabel -r\" to install initial label\n");
+ break;
+
+ case EINVAL:
+ fprintf(stderr, "Label magic number or checksum is wrong!\n");
+ fprintf(stderr, "(disklabel or kernel is out of date?)\n");
+ break;
+
+ case EBUSY:
+ fprintf(stderr, "Open partition would move or shrink\n");
+ break;
+
+ case EXDEV:
+ fprintf(stderr,
+ "Labeled partition or 'a' partition must start at beginning of disk\n");
+ break;
+
+ default:
+ errno = saverrno;
+ perror((char *)NULL);
+ break;
+ }
+}
+
+/*
+ * Fetch disklabel for disk.
+ * Use ioctl to get label unless -r flag is given.
+ */
+struct disklabel *
+readlabel(f)
+ int f;
+{
+ register struct disklabel *lp;
+
+ if (rflag) {
+ if (read(f, bootarea, BBSIZE) < BBSIZE)
+ Perror(specname);
+ for (lp = (struct disklabel *)bootarea;
+ lp <= (struct disklabel *)(bootarea + BBSIZE - sizeof(*lp));
+ lp = (struct disklabel *)((char *)lp + 16))
+ if (lp->d_magic == DISKMAGIC &&
+ lp->d_magic2 == DISKMAGIC)
+ break;
+ if (lp > (struct disklabel *)(bootarea+BBSIZE-sizeof(*lp)) ||
+ lp->d_magic != DISKMAGIC || lp->d_magic2 != DISKMAGIC ||
+ dkcksum(lp) != 0) {
+ fprintf(stderr,
+ "Bad pack magic number (label is damaged, or pack is unlabeled)\n");
+ /* lp = (struct disklabel *)(bootarea + LABELOFFSET); */
+ exit (1);
+ }
+ } else {
+ lp = &lab;
+ if (ioctl(f, DIOCGDINFO, lp) < 0)
+ Perror("ioctl DIOCGDINFO");
+ }
+ return (lp);
+}
+
+/*
+ * Construct a bootarea (d_bbsize bytes) in the specified buffer ``boot''
+ * Returns a pointer to the disklabel portion of the bootarea.
+ */
+struct disklabel *
+makebootarea(boot, dp, f)
+ char *boot;
+ register struct disklabel *dp;
+ int f;
+{
+ struct disklabel *lp;
+ register char *p;
+ int b;
+#if NUMBOOT > 0
+ char *dkbasename;
+ struct stat sb;
+#endif
+
+ /* XXX */
+ if (dp->d_secsize == 0) {
+ dp->d_secsize = DEV_BSIZE;
+ dp->d_bbsize = BBSIZE;
+ }
+ lp = (struct disklabel *)
+ (boot + (LABELSECTOR * dp->d_secsize) + LABELOFFSET);
+ bzero((char *)lp, sizeof *lp);
+#if NUMBOOT > 0
+ /*
+ * If we are not installing a boot program but we are installing a
+ * label on disk then we must read the current bootarea so we don't
+ * clobber the existing boot.
+ */
+ if (!installboot) {
+ if (rflag) {
+ if (read(f, boot, BBSIZE) < BBSIZE)
+ Perror(specname);
+ bzero((char *)lp, sizeof *lp);
+ }
+ return (lp);
+ }
+ /*
+ * We are installing a boot program. Determine the name(s) and
+ * read them into the appropriate places in the boot area.
+ */
+ if (!xxboot || !bootxx) {
+ dkbasename = np;
+ if ((p = rindex(dkname, '/')) == NULL)
+ p = dkname;
+ else
+ p++;
+ while (*p && !isdigit(*p))
+ *np++ = *p++;
+ *np++ = '\0';
+
+ if (!xxboot) {
+ (void)sprintf(np, "%s/%sboot",
+ _PATH_BOOTDIR, dkbasename);
+ if (access(np, F_OK) < 0 && dkbasename[0] == 'r')
+ dkbasename++;
+ xxboot = np;
+ (void)sprintf(xxboot, "%s/%sboot",
+ _PATH_BOOTDIR, dkbasename);
+ np += strlen(xxboot) + 1;
+ }
+#if NUMBOOT > 1
+ if (!bootxx) {
+ (void)sprintf(np, "%s/boot%s",
+ _PATH_BOOTDIR, dkbasename);
+ if (access(np, F_OK) < 0 && dkbasename[0] == 'r')
+ dkbasename++;
+ bootxx = np;
+ (void)sprintf(bootxx, "%s/boot%s",
+ _PATH_BOOTDIR, dkbasename);
+ np += strlen(bootxx) + 1;
+ }
+#endif
+ }
+#ifdef DEBUG
+ if (debug)
+ fprintf(stderr, "bootstraps: xxboot = %s, bootxx = %s\n",
+ xxboot, bootxx ? bootxx : "NONE");
+#endif
+
+ /*
+ * Strange rules:
+ * 1. One-piece bootstrap (hp300/hp800)
+ * up to d_bbsize bytes of ``xxboot'' go in bootarea, the rest
+ * is remembered and written later following the bootarea.
+ * 2. Two-piece bootstraps (vax/i386?/mips?)
+ * up to d_secsize bytes of ``xxboot'' go in first d_secsize
+ * bytes of bootarea, remaining d_bbsize-d_secsize filled
+ * from ``bootxx''.
+ */
+ b = open(xxboot, O_RDONLY);
+ if (b < 0)
+ Perror(xxboot);
+#if NUMBOOT > 1
+ if (read(b, boot, (int)dp->d_secsize) < 0)
+ Perror(xxboot);
+ (void)close(b);
+ b = open(bootxx, O_RDONLY);
+ if (b < 0)
+ Perror(bootxx);
+ if (read(b, &boot[dp->d_secsize], (int)(dp->d_bbsize-dp->d_secsize)) < 0)
+ Perror(bootxx);
+#else
+ if (read(b, boot, (int)dp->d_bbsize) < 0)
+ Perror(xxboot);
+ (void)fstat(b, &sb);
+ bootsize = (int)sb.st_size - dp->d_bbsize;
+ if (bootsize > 0) {
+ /* XXX assume d_secsize is a power of two */
+ bootsize = (bootsize + dp->d_secsize-1) & ~(dp->d_secsize-1);
+ bootbuf = (char *)malloc((size_t)bootsize);
+ if (bootbuf == 0)
+ Perror(xxboot);
+ if (read(b, bootbuf, bootsize) < 0) {
+ free(bootbuf);
+ Perror(xxboot);
+ }
+ }
+#endif
+ (void)close(b);
+#endif
+ /*
+ * Make sure no part of the bootstrap is written in the area
+ * reserved for the label.
+ */
+ for (p = (char *)lp; p < (char *)lp + sizeof(struct disklabel); p++)
+ if (*p) {
+ fprintf(stderr,
+ "Bootstrap doesn't leave room for disk label\n");
+ exit(2);
+ }
+ return (lp);
+}
+
+display(f, lp)
+ FILE *f;
+ register struct disklabel *lp;
+{
+ register int i, j;
+ register struct partition *pp;
+
+ fprintf(f, "# %s:\n", specname);
+ if ((unsigned) lp->d_type < DKMAXTYPES)
+ fprintf(f, "type: %s\n", dktypenames[lp->d_type]);
+ else
+ fprintf(f, "type: %d\n", lp->d_type);
+ fprintf(f, "disk: %.*s\n", sizeof(lp->d_typename), lp->d_typename);
+ fprintf(f, "label: %.*s\n", sizeof(lp->d_packname), lp->d_packname);
+ fprintf(f, "flags:");
+ if (lp->d_flags & D_REMOVABLE)
+ fprintf(f, " removeable");
+ if (lp->d_flags & D_ECC)
+ fprintf(f, " ecc");
+ if (lp->d_flags & D_BADSECT)
+ fprintf(f, " badsect");
+ fprintf(f, "\n");
+ fprintf(f, "bytes/sector: %d\n", lp->d_secsize);
+ fprintf(f, "sectors/track: %d\n", lp->d_nsectors);
+ fprintf(f, "tracks/cylinder: %d\n", lp->d_ntracks);
+ fprintf(f, "sectors/cylinder: %d\n", lp->d_secpercyl);
+ fprintf(f, "cylinders: %d\n", lp->d_ncylinders);
+ fprintf(f, "rpm: %d\n", lp->d_rpm);
+ fprintf(f, "interleave: %d\n", lp->d_interleave);
+ fprintf(f, "trackskew: %d\n", lp->d_trackskew);
+ fprintf(f, "cylinderskew: %d\n", lp->d_cylskew);
+ fprintf(f, "headswitch: %d\t\t# milliseconds\n", lp->d_headswitch);
+ fprintf(f, "track-to-track seek: %d\t# milliseconds\n", lp->d_trkseek);
+ fprintf(f, "drivedata: ");
+ for (i = NDDATA - 1; i >= 0; i--)
+ if (lp->d_drivedata[i])
+ break;
+ if (i < 0)
+ i = 0;
+ for (j = 0; j <= i; j++)
+ fprintf(f, "%d ", lp->d_drivedata[j]);
+ fprintf(f, "\n\n%d partitions:\n", lp->d_npartitions);
+ fprintf(f,
+ "# size offset fstype [fsize bsize cpg]\n");
+ pp = lp->d_partitions;
+ for (i = 0; i < lp->d_npartitions; i++, pp++) {
+ if (pp->p_size) {
+ fprintf(f, " %c: %8d %8d ", 'a' + i,
+ pp->p_size, pp->p_offset);
+ if ((unsigned) pp->p_fstype < FSMAXTYPES)
+ fprintf(f, "%8.8s", fstypenames[pp->p_fstype]);
+ else
+ fprintf(f, "%8d", pp->p_fstype);
+ switch (pp->p_fstype) {
+
+ case FS_UNUSED: /* XXX */
+ fprintf(f, " %5d %5d %5.5s ",
+ pp->p_fsize, pp->p_fsize * pp->p_frag, "");
+ break;
+
+ case FS_BSDFFS:
+ fprintf(f, " %5d %5d %5d ",
+ pp->p_fsize, pp->p_fsize * pp->p_frag,
+ pp->p_cpg);
+ break;
+
+ default:
+ fprintf(f, "%20.20s", "");
+ break;
+ }
+ fprintf(f, "\t# (Cyl. %4d",
+ pp->p_offset / lp->d_secpercyl);
+ if (pp->p_offset % lp->d_secpercyl)
+ putc('*', f);
+ else
+ putc(' ', f);
+ fprintf(f, "- %d",
+ (pp->p_offset +
+ pp->p_size + lp->d_secpercyl - 1) /
+ lp->d_secpercyl - 1);
+ if (pp->p_size % lp->d_secpercyl)
+ putc('*', f);
+ fprintf(f, ")\n");
+ }
+ }
+ fflush(f);
+}
+
+edit(lp, f)
+ struct disklabel *lp;
+ int f;
+{
+ register int c;
+ struct disklabel label;
+ FILE *fd;
+ char *mktemp();
+
+ (void) mktemp(tmpfil);
+ fd = fopen(tmpfil, "w");
+ if (fd == NULL) {
+ fprintf(stderr, "%s: Can't create\n", tmpfil);
+ return (1);
+ }
+ (void)fchmod(fileno(fd), 0600);
+ display(fd, lp);
+ fclose(fd);
+ for (;;) {
+ if (!editit())
+ break;
+ fd = fopen(tmpfil, "r");
+ if (fd == NULL) {
+ fprintf(stderr, "%s: Can't reopen for reading\n",
+ tmpfil);
+ break;
+ }
+ bzero((char *)&label, sizeof(label));
+ if (getasciilabel(fd, &label)) {
+ *lp = label;
+ if (writelabel(f, bootarea, lp) == 0) {
+ (void) unlink(tmpfil);
+ return (0);
+ }
+ }
+ printf("re-edit the label? [y]: "); fflush(stdout);
+ c = getchar();
+ if (c != EOF && c != (int)'\n')
+ while (getchar() != (int)'\n')
+ ;
+ if (c == (int)'n')
+ break;
+ }
+ (void) unlink(tmpfil);
+ return (1);
+}
+
+editit()
+{
+ register int pid, xpid;
+ int stat, omask;
+ extern char *getenv();
+
+ omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGHUP));
+ while ((pid = fork()) < 0) {
+ extern int errno;
+
+ if (errno == EPROCLIM) {
+ fprintf(stderr, "You have too many processes\n");
+ return(0);
+ }
+ if (errno != EAGAIN) {
+ perror("fork");
+ return(0);
+ }
+ sleep(1);
+ }
+ if (pid == 0) {
+ register char *ed;
+
+ sigsetmask(omask);
+ setgid(getgid());
+ setuid(getuid());
+ if ((ed = getenv("EDITOR")) == (char *)0)
+ ed = DEFEDITOR;
+ execlp(ed, ed, tmpfil, 0);
+ perror(ed);
+ exit(1);
+ }
+ while ((xpid = wait(&stat)) >= 0)
+ if (xpid == pid)
+ break;
+ sigsetmask(omask);
+ return(!stat);
+}
+
+char *
+skip(cp)
+ register char *cp;
+{
+
+ while (*cp != '\0' && isspace(*cp))
+ cp++;
+ if (*cp == '\0' || *cp == '#')
+ return ((char *)NULL);
+ return (cp);
+}
+
+char *
+word(cp)
+ register char *cp;
+{
+ register char c;
+
+ while (*cp != '\0' && !isspace(*cp) && *cp != '#')
+ cp++;
+ if ((c = *cp) != '\0') {
+ *cp++ = '\0';
+ if (c != '#')
+ return (skip(cp));
+ }
+ return ((char *)NULL);
+}
+
+/*
+ * Read an ascii label in from fd f,
+ * in the same format as that put out by display(),
+ * and fill in lp.
+ */
+getasciilabel(f, lp)
+ FILE *f;
+ register struct disklabel *lp;
+{
+ register char **cpp, *cp;
+ register struct partition *pp;
+ char *tp, *s, line[BUFSIZ];
+ int v, lineno = 0, errors = 0;
+
+ lp->d_bbsize = BBSIZE; /* XXX */
+ lp->d_sbsize = SBSIZE; /* XXX */
+ while (fgets(line, sizeof(line) - 1, f)) {
+ lineno++;
+ if (cp = index(line,'\n'))
+ *cp = '\0';
+ cp = skip(line);
+ if (cp == NULL)
+ continue;
+ tp = index(cp, ':');
+ if (tp == NULL) {
+ fprintf(stderr, "line %d: syntax error\n", lineno);
+ errors++;
+ continue;
+ }
+ *tp++ = '\0', tp = skip(tp);
+ if (streq(cp, "type")) {
+ if (tp == NULL)
+ tp = "unknown";
+ cpp = dktypenames;
+ for (; cpp < &dktypenames[DKMAXTYPES]; cpp++)
+ if ((s = *cpp) && streq(s, tp)) {
+ lp->d_type = cpp - dktypenames;
+ goto next;
+ }
+ v = atoi(tp);
+ if ((unsigned)v >= DKMAXTYPES)
+ fprintf(stderr, "line %d:%s %d\n", lineno,
+ "Warning, unknown disk type", v);
+ lp->d_type = v;
+ continue;
+ }
+ if (streq(cp, "flags")) {
+ for (v = 0; (cp = tp) && *cp != '\0';) {
+ tp = word(cp);
+ if (streq(cp, "removeable"))
+ v |= D_REMOVABLE;
+ else if (streq(cp, "ecc"))
+ v |= D_ECC;
+ else if (streq(cp, "badsect"))
+ v |= D_BADSECT;
+ else {
+ fprintf(stderr,
+ "line %d: %s: bad flag\n",
+ lineno, cp);
+ errors++;
+ }
+ }
+ lp->d_flags = v;
+ continue;
+ }
+ if (streq(cp, "drivedata")) {
+ register int i;
+
+ for (i = 0; (cp = tp) && *cp != '\0' && i < NDDATA;) {
+ lp->d_drivedata[i++] = atoi(cp);
+ tp = word(cp);
+ }
+ continue;
+ }
+ if (sscanf(cp, "%d partitions", &v) == 1) {
+ if (v == 0 || (unsigned)v > MAXPARTITIONS) {
+ fprintf(stderr,
+ "line %d: bad # of partitions\n", lineno);
+ lp->d_npartitions = MAXPARTITIONS;
+ errors++;
+ } else
+ lp->d_npartitions = v;
+ continue;
+ }
+ if (tp == NULL)
+ tp = "";
+ if (streq(cp, "disk")) {
+ strncpy(lp->d_typename, tp, sizeof (lp->d_typename));
+ continue;
+ }
+ if (streq(cp, "label")) {
+ strncpy(lp->d_packname, tp, sizeof (lp->d_packname));
+ continue;
+ }
+ if (streq(cp, "bytes/sector")) {
+ v = atoi(tp);
+ if (v <= 0 || (v % 512) != 0) {
+ fprintf(stderr,
+ "line %d: %s: bad sector size\n",
+ lineno, tp);
+ errors++;
+ } else
+ lp->d_secsize = v;
+ continue;
+ }
+ if (streq(cp, "sectors/track")) {
+ v = atoi(tp);
+ if (v <= 0) {
+ fprintf(stderr, "line %d: %s: bad %s\n",
+ lineno, tp, cp);
+ errors++;
+ } else
+ lp->d_nsectors = v;
+ continue;
+ }
+ if (streq(cp, "sectors/cylinder")) {
+ v = atoi(tp);
+ if (v <= 0) {
+ fprintf(stderr, "line %d: %s: bad %s\n",
+ lineno, tp, cp);
+ errors++;
+ } else
+ lp->d_secpercyl = v;
+ continue;
+ }
+ if (streq(cp, "tracks/cylinder")) {
+ v = atoi(tp);
+ if (v <= 0) {
+ fprintf(stderr, "line %d: %s: bad %s\n",
+ lineno, tp, cp);
+ errors++;
+ } else
+ lp->d_ntracks = v;
+ continue;
+ }
+ if (streq(cp, "cylinders")) {
+ v = atoi(tp);
+ if (v <= 0) {
+ fprintf(stderr, "line %d: %s: bad %s\n",
+ lineno, tp, cp);
+ errors++;
+ } else
+ lp->d_ncylinders = v;
+ continue;
+ }
+ if (streq(cp, "rpm")) {
+ v = atoi(tp);
+ if (v <= 0) {
+ fprintf(stderr, "line %d: %s: bad %s\n",
+ lineno, tp, cp);
+ errors++;
+ } else
+ lp->d_rpm = v;
+ continue;
+ }
+ if (streq(cp, "interleave")) {
+ v = atoi(tp);
+ if (v <= 0) {
+ fprintf(stderr, "line %d: %s: bad %s\n",
+ lineno, tp, cp);
+ errors++;
+ } else
+ lp->d_interleave = v;
+ continue;
+ }
+ if (streq(cp, "trackskew")) {
+ v = atoi(tp);
+ if (v < 0) {
+ fprintf(stderr, "line %d: %s: bad %s\n",
+ lineno, tp, cp);
+ errors++;
+ } else
+ lp->d_trackskew = v;
+ continue;
+ }
+ if (streq(cp, "cylinderskew")) {
+ v = atoi(tp);
+ if (v < 0) {
+ fprintf(stderr, "line %d: %s: bad %s\n",
+ lineno, tp, cp);
+ errors++;
+ } else
+ lp->d_cylskew = v;
+ continue;
+ }
+ if (streq(cp, "headswitch")) {
+ v = atoi(tp);
+ if (v < 0) {
+ fprintf(stderr, "line %d: %s: bad %s\n",
+ lineno, tp, cp);
+ errors++;
+ } else
+ lp->d_headswitch = v;
+ continue;
+ }
+ if (streq(cp, "track-to-track seek")) {
+ v = atoi(tp);
+ if (v < 0) {
+ fprintf(stderr, "line %d: %s: bad %s\n",
+ lineno, tp, cp);
+ errors++;
+ } else
+ lp->d_trkseek = v;
+ continue;
+ }
+ if ('a' <= *cp && *cp <= 'z' && cp[1] == '\0') {
+ unsigned part = *cp - 'a';
+
+ if (part > lp->d_npartitions) {
+ fprintf(stderr,
+ "line %d: bad partition name\n", lineno);
+ errors++;
+ continue;
+ }
+ pp = &lp->d_partitions[part];
+#define NXTNUM(n) { \
+ cp = tp, tp = word(cp); \
+ if (tp == NULL) \
+ tp = cp; \
+ (n) = atoi(cp); \
+ }
+
+ NXTNUM(v);
+ if (v < 0) {
+ fprintf(stderr,
+ "line %d: %s: bad partition size\n",
+ lineno, cp);
+ errors++;
+ } else
+ pp->p_size = v;
+ NXTNUM(v);
+ if (v < 0) {
+ fprintf(stderr,
+ "line %d: %s: bad partition offset\n",
+ lineno, cp);
+ errors++;
+ } else
+ pp->p_offset = v;
+ cp = tp, tp = word(cp);
+ cpp = fstypenames;
+ for (; cpp < &fstypenames[FSMAXTYPES]; cpp++)
+ if ((s = *cpp) && streq(s, cp)) {
+ pp->p_fstype = cpp - fstypenames;
+ goto gottype;
+ }
+ if (isdigit(*cp))
+ v = atoi(cp);
+ else
+ v = FSMAXTYPES;
+ if ((unsigned)v >= FSMAXTYPES) {
+ fprintf(stderr, "line %d: %s %s\n", lineno,
+ "Warning, unknown filesystem type", cp);
+ v = FS_UNUSED;
+ }
+ pp->p_fstype = v;
+ gottype:
+
+ switch (pp->p_fstype) {
+
+ case FS_UNUSED: /* XXX */
+ NXTNUM(pp->p_fsize);
+ if (pp->p_fsize == 0)
+ break;
+ NXTNUM(v);
+ pp->p_frag = v / pp->p_fsize;
+ break;
+
+ case FS_BSDFFS:
+ NXTNUM(pp->p_fsize);
+ if (pp->p_fsize == 0)
+ break;
+ NXTNUM(v);
+ pp->p_frag = v / pp->p_fsize;
+ NXTNUM(pp->p_cpg);
+ break;
+
+ default:
+ break;
+ }
+ continue;
+ }
+ fprintf(stderr, "line %d: %s: Unknown disklabel field\n",
+ lineno, cp);
+ errors++;
+ next:
+ ;
+ }
+ errors += checklabel(lp);
+ return (errors == 0);
+}
+
+/*
+ * Check disklabel for errors and fill in
+ * derived fields according to supplied values.
+ */
+checklabel(lp)
+ register struct disklabel *lp;
+{
+ register struct partition *pp;
+ int i, errors = 0;
+ char part;
+
+ if (lp->d_secsize == 0) {
+ fprintf(stderr, "sector size %d\n", lp->d_secsize);
+ return (1);
+ }
+ if (lp->d_nsectors == 0) {
+ fprintf(stderr, "sectors/track %d\n", lp->d_nsectors);
+ return (1);
+ }
+ if (lp->d_ntracks == 0) {
+ fprintf(stderr, "tracks/cylinder %d\n", lp->d_ntracks);
+ return (1);
+ }
+ if (lp->d_ncylinders == 0) {
+ fprintf(stderr, "cylinders/unit %d\n", lp->d_ncylinders);
+ errors++;
+ }
+ if (lp->d_rpm == 0)
+ Warning("revolutions/minute %d", lp->d_rpm);
+ if (lp->d_secpercyl == 0)
+ lp->d_secpercyl = lp->d_nsectors * lp->d_ntracks;
+ if (lp->d_secperunit == 0)
+ lp->d_secperunit = lp->d_secpercyl * lp->d_ncylinders;
+ if (lp->d_bbsize == 0) {
+ fprintf(stderr, "boot block size %d\n", lp->d_bbsize);
+ errors++;
+ } else if (lp->d_bbsize % lp->d_secsize)
+ Warning("boot block size %% sector-size != 0");
+ if (lp->d_sbsize == 0) {
+ fprintf(stderr, "super block size %d\n", lp->d_sbsize);
+ errors++;
+ } else if (lp->d_sbsize % lp->d_secsize)
+ Warning("super block size %% sector-size != 0");
+ if (lp->d_npartitions > MAXPARTITIONS)
+ Warning("number of partitions (%d) > MAXPARTITIONS (%d)",
+ lp->d_npartitions, MAXPARTITIONS);
+ for (i = 0; i < lp->d_npartitions; i++) {
+ part = 'a' + i;
+ pp = &lp->d_partitions[i];
+ if (pp->p_size == 0 && pp->p_offset != 0)
+ Warning("partition %c: size 0, but offset %d",
+ part, pp->p_offset);
+#ifdef notdef
+ if (pp->p_size % lp->d_secpercyl)
+ Warning("partition %c: size %% cylinder-size != 0",
+ part);
+ if (pp->p_offset % lp->d_secpercyl)
+ Warning("partition %c: offset %% cylinder-size != 0",
+ part);
+#endif
+ if (pp->p_offset > lp->d_secperunit) {
+ fprintf(stderr,
+ "partition %c: offset past end of unit\n", part);
+ errors++;
+ }
+ if (pp->p_offset + pp->p_size > lp->d_secperunit) {
+ fprintf(stderr,
+ "partition %c: partition extends past end of unit\n",
+ part);
+ errors++;
+ }
+ }
+ for (; i < MAXPARTITIONS; i++) {
+ part = 'a' + i;
+ pp = &lp->d_partitions[i];
+ if (pp->p_size || pp->p_offset)
+ Warning("unused partition %c: size %d offset %d",
+ 'a' + i, pp->p_size, pp->p_offset);
+ }
+ return (errors);
+}
+
+/*
+ * If we are installing a boot program that doesn't fit in d_bbsize
+ * we need to mark those partitions that the boot overflows into.
+ * This allows newfs to prevent creation of a filesystem where it might
+ * clobber bootstrap code.
+ */
+setbootflag(lp)
+ register struct disklabel *lp;
+{
+ register struct partition *pp;
+ int i, errors = 0;
+ char part;
+ u_long boffset;
+
+ if (bootbuf == 0)
+ return;
+ boffset = bootsize / lp->d_secsize;
+ for (i = 0; i < lp->d_npartitions; i++) {
+ part = 'a' + i;
+ pp = &lp->d_partitions[i];
+ if (pp->p_size == 0)
+ continue;
+ if (boffset <= pp->p_offset) {
+ if (pp->p_fstype == FS_BOOT)
+ pp->p_fstype = FS_UNUSED;
+ } else if (pp->p_fstype != FS_BOOT) {
+ if (pp->p_fstype != FS_UNUSED) {
+ fprintf(stderr,
+ "boot overlaps used partition %c\n",
+ part);
+ errors++;
+ } else {
+ pp->p_fstype = FS_BOOT;
+ Warning("boot overlaps partition %c, %s",
+ part, "marked as FS_BOOT");
+ }
+ }
+ }
+ if (errors) {
+ fprintf(stderr, "Cannot install boot program\n");
+ exit(4);
+ }
+}
+
+/*VARARGS1*/
+Warning(fmt, a1, a2, a3, a4, a5)
+ char *fmt;
+{
+
+ fprintf(stderr, "Warning, ");
+ fprintf(stderr, fmt, a1, a2, a3, a4, a5);
+ fprintf(stderr, "\n");
+}
+
+Perror(str)
+ char *str;
+{
+ fputs("disklabel: ", stderr); perror(str);
+ exit(4);
+}
+
+usage()
+{
+#if NUMBOOT > 0
+ fprintf(stderr,
+"%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",
+"usage: disklabel [-r] disk",
+ "(to read label)",
+"or disklabel -w [-r] disk type [ packid ]",
+ "(to write label with existing boot program)",
+"or disklabel -e [-r] disk",
+ "(to edit label)",
+"or disklabel -R [-r] disk protofile",
+ "(to restore label with existing boot program)",
+#if NUMBOOT > 1
+"or disklabel -B [ -b boot1 [ -s boot2 ] ] disk [ type ]",
+ "(to install boot program with existing label)",
+"or disklabel -w -B [ -b boot1 [ -s boot2 ] ] disk type [ packid ]",
+ "(to write label and boot program)",
+"or disklabel -R -B [ -b boot1 [ -s boot2 ] ] disk protofile [ type ]",
+ "(to restore label and boot program)",
+#else
+"or disklabel -B [ -b bootprog ] disk [ type ]",
+ "(to install boot program with existing on-disk label)",
+"or disklabel -w -B [ -b bootprog ] disk type [ packid ]",
+ "(to write label and install boot program)",
+"or disklabel -R -B [ -b bootprog ] disk protofile [ type ]",
+ "(to restore label and install boot program)",
+#endif
+"or disklabel [-NW] disk",
+ "(to write disable/enable label)");
+#else
+ fprintf(stderr, "%-43s%s\n%-43s%s\n%-43s%s\n%-43s%s\n%-43s%s\n",
+"usage: disklabel [-r] disk", "(to read label)",
+"or disklabel -w [-r] disk type [ packid ]", "(to write label)",
+"or disklabel -e [-r] disk", "(to edit label)",
+"or disklabel -R [-r] disk protofile", "(to restore label)",
+"or disklabel [-NW] disk", "(to write disable/enable label)");
+#endif
+ exit(1);
+}
OpenPOWER on IntegriCloud