diff options
Diffstat (limited to 'sbin/disklabel/disklabel.c')
-rw-r--r-- | sbin/disklabel/disklabel.c | 1455 |
1 files changed, 1455 insertions, 0 deletions
diff --git a/sbin/disklabel/disklabel.c b/sbin/disklabel/disklabel.c new file mode 100644 index 000000000000..5fcd1cdb7056 --- /dev/null +++ b/sbin/disklabel/disklabel.c @@ -0,0 +1,1455 @@ +/* + * 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> +#include <sys/wait.h> +#define DKTYPENAMES +#include <sys/disklabel.h> +#include <ufs/ffs/fs.h> +#include <unistd.h> +#include <string.h> +#include <stdio.h> +#include <stdlib.h> +#include <signal.h> +#include <stdarg.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 + +void makelabel __P((char *, char *, struct disklabel *)); +int writelabel __P((int, char *, struct disklabel *)); +void l_perror __P((char *)); +struct disklabel * readlabel __P((int)); +struct disklabel * makebootarea __P((char *, struct disklabel *, int)); +void display __P((FILE *, struct disklabel *)); +int edit __P((struct disklabel *, int)); +int editit __P((void)); +char * skip __P((char *)); +char * word __P((char *)); +int getasciilabel __P((FILE *, struct disklabel *)); +int checklabel __P((struct disklabel *)); +void setbootflag __P((struct disklabel *)); +void Warning (char *, ...); +void Perror __P((char *)); +void usage __P((void)); +extern u_short dkcksum __P((struct disklabel *)); +struct disklabel * getvirginlabel __P((void)); + +#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 + +int +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. + */ +void +makelabel(type, name, lp) + char *type, *name; + register struct disklabel *lp; +{ + register struct disklabel *dp; + + if (strcmp(type, "auto") == 0) + dp = getvirginlabel(); + else + 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)); +} + +int +writelabel(f, boot, lp) + int f; + char *boot; + register struct disklabel *lp; +{ +#ifdef vax + register int i; +#endif + 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); +} + +void +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; +#if NUMBOOT == 1 + struct stat sb; +#endif +#ifdef __i386__ + char *tmpbuf; + int i, found; +#endif /* i386 */ +#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 +#ifdef __i386__ + /* + * XXX Botch alert. + * The i386 has the so-called fdisk table embedded into the + * primary bootstrap. We take care to not clobber it, but + * only if it does already contain some data. (Otherwise, + * the xxboot provides a template.) + */ + if ((tmpbuf = (char *)malloc((int)dp->d_secsize)) == 0) + Perror(xxboot); + memcpy((void *)tmpbuf, (void *)boot, (int)dp->d_secsize); +#endif /* i386 */ + if (read(b, boot, (int)dp->d_secsize) < 0) + Perror(xxboot); + (void)close(b); +#ifdef __i386__ + for (i = DOSPARTOFF, found = 0; + !found && i < DOSPARTOFF + NDOSPART*sizeof(struct dos_partition); + i++) + found = tmpbuf[i] != 0; + if (found) + memcpy((void *)&boot[DOSPARTOFF], + (void *)&tmpbuf[DOSPARTOFF], + NDOSPART * sizeof(struct dos_partition)); + free(tmpbuf); +#endif /* i386 */ + 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); +} + +void +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", (int)sizeof(lp->d_typename), + lp->d_typename); + fprintf(f, "label: %.*s\n", (int)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: %ld\n", lp->d_secsize); + fprintf(f, "sectors/track: %ld\n", lp->d_nsectors); + fprintf(f, "tracks/cylinder: %ld\n", lp->d_ntracks); + fprintf(f, "sectors/cylinder: %ld\n", lp->d_secpercyl); + fprintf(f, "cylinders: %ld\n", lp->d_ncylinders); + fprintf(f, "sectors/unit: %ld\n", lp->d_secperunit); + 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: %ld\t\t# milliseconds\n", lp->d_headswitch); + fprintf(f, "track-to-track seek: %ld\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, "%ld ", lp->d_drivedata[j]); + fprintf(f, "\n\n%d partitions:\n", lp->d_npartitions); + fprintf(f, + "# size offset fstype [fsize bsize bps/cpg]\n"); + pp = lp->d_partitions; + for (i = 0; i < lp->d_npartitions; i++, pp++) { + if (pp->p_size) { + fprintf(f, " %c: %8ld %8ld ", '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, " %5ld %5ld %5.5s ", + pp->p_fsize, pp->p_fsize * pp->p_frag, ""); + break; + + case FS_BSDFFS: + fprintf(f, " %5ld %5ld %5d ", + pp->p_fsize, pp->p_fsize * pp->p_frag, + pp->p_cpg); + break; + + case FS_BSDLFS: + fprintf(f, " %5ld %5ld %5d", + pp->p_fsize, pp->p_fsize * pp->p_frag, + pp->p_cpg); + break; + + default: + fprintf(f, "%20.20s", ""); + break; + } + fprintf(f, "\t# (Cyl. %4ld", + pp->p_offset / lp->d_secpercyl); + if (pp->p_offset % lp->d_secpercyl) + putc('*', f); + else + putc(' ', f); + fprintf(f, "- %ld", + (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); +} + +int +edit(lp, f) + struct disklabel *lp; + int f; +{ + register int c; + struct disklabel label; + FILE *fd; + + (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); +} + +int +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. + */ +int +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')) != 0) + *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, "sectors/unit")) { + v = atoi(tp); + if (v <= 0) { + fprintf(stderr, "line %d: %s: bad %s\n", + lineno, tp, cp); + errors++; + } else + lp->d_secperunit = 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) { \ + if (tp == NULL) { \ + fprintf(stderr, "line %d: too few numeric fields\n", lineno); \ + errors++; \ + break; \ + } else { \ + 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; + + case FS_BSDLFS: + 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. + */ +int +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 %ld\n", lp->d_secsize); + return (1); + } + if (lp->d_nsectors == 0) { + fprintf(stderr, "sectors/track %ld\n", lp->d_nsectors); + return (1); + } + if (lp->d_ntracks == 0) { + fprintf(stderr, "tracks/cylinder %ld\n", lp->d_ntracks); + return (1); + } + if (lp->d_ncylinders == 0) { + fprintf(stderr, "cylinders/unit %ld\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 %ld\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 %ld\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); +} + +/* + * When operating on a "virgin" disk, try getting an initial label + * from the associated device driver. This might work for all device + * drivers that are able to fetch some initial device parameters + * without even having access to a (BSD) disklabel, like SCSI disks, + * most IDE drives, or vn devices. + * + * The device name must be given in its "canonical" form. + */ +struct disklabel * +getvirginlabel(void) +{ + static struct disklabel lab; + char namebuf[BBSIZE]; + int f; + + if (dkname[0] == '/') { + fprintf(stderr, + "\"auto\" requires the usage of a canonical disk name.\n"); + return (NULL); + } + (void)snprintf(namebuf, BBSIZE, "%sr%s", _PATH_DEV, dkname); + if ((f = open(namebuf, O_RDONLY, 0)) == -1) { + Perror("open()"); + return (NULL); + } + if (ioctl(f, DIOCGDINFO, &lab) < 0) { + Perror("ioctl DIOCGDINFO"); + close(f); + return (NULL); + } + close(f); + return (&lab); +} + + +/* + * 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. + */ +void +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*/ +void +Warning(char *fmt, ...) +{ + va_list ap; + + fprintf(stderr, "Warning, "); + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + fprintf(stderr, "\n"); + va_end(ap); +} + +void +Perror(str) + char *str; +{ + fputs("disklabel: ", stderr); perror(str); + exit(4); +} + +void +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); +} |