09fd84271d52bd4c57c166f9813fea1bce79d852
[unix-history] / usr / src / sbin / disklabel / disklabel.c
/*
* Copyright (c) 1987 Regents of the University of California.
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
*/
#ifndef lint
static char sccsid[] = "@(#)disklabel.c 5.9 (Berkeley) %G%";
/* from static char sccsid[] = "@(#)disklabel.c 1.2 (Symmetric) 11/28/85"; */
#endif
#include <stdio.h>
#include <ctype.h>
#include <sys/param.h>
#include <sys/signal.h>
#include <sys/errno.h>
#include <sys/file.h>
#include <sys/ioctl.h>
#include <sys/fs.h>
#include <strings.h>
#define DKTYPENAMES
#include <sys/disklabel.h>
/*
* Disklabel: read and write disklabels.
* The label is usually placed on one of the first sectors of the disk.
* Many machines (VAX 11/750) 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 vax
#define RAWPARTITION 'c'
#else
#define RAWPARTITION 'a'
#endif
#ifndef BBSIZE
#define BBSIZE 8192 /* size of boot area, with label */
#endif
#ifdef vax
#define BOOT /* also have bootstrap in "boot area" */
#define BOOTDIR "/usr/mdec" /* source of boot binaries */
#else
#ifdef lint
#define BOOT
#endif
#endif
#define DEFEDITOR "/usr/ucb/vi"
#define streq(a,b) (strcmp(a,b) == 0)
#ifdef BOOT
char *xxboot;
char *bootxx;
#endif
char *dkname;
char *specname;
char tmpfil[] = "/tmp/EdDk.aXXXXXX";
char *sprintf();
extern int errno;
char namebuf[BBSIZE], *np = namebuf;
struct disklabel lab;
struct disklabel *readlabel(), *makebootarea();
char bootarea[BBSIZE];
enum { READ, WRITE, EDIT, RESTORE } op = READ;
int rflag;
main(argc, argv)
int argc;
char *argv[];
{
extern int optind;
register struct disklabel *lp;
FILE *t;
int ch, f;
char *name = 0, *type;
while ((ch = getopt(argc, argv, "Rerw")) != EOF)
switch((char)ch) {
case 'R':
op = RESTORE;
break;
case 'e':
op = EDIT;
break;
case 'r':
++rflag;
break;
case 'w':
op = WRITE;
break;
case '?':
default:
usage();
}
argc -= optind;
argv += optind;
if (argc < 1)
usage();
dkname = argv[0];
if (dkname[0] != '/') {
sprintf(np, "/dev/r%s%c", 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] != '/') {
sprintf(specname, "/dev/r%s", 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, rflag);
if (edit(lp))
writelabel(f, bootarea, lp);
break;
case READ:
if (argc != 1)
usage();
lp = readlabel(f, 0);
display(stdout, lp);
(void) checklabel(lp);
break;
case RESTORE:
#ifdef BOOT
if (argc == 4) {
xxboot = argv[2];
bootxx = argv[3];
} else
#endif
if (argc != 2)
usage();
lab.d_secsize = DEV_BSIZE; /* XXX */
lab.d_bbsize = BBSIZE; /* XXX */
lp = makebootarea(bootarea, &lab);
if (!(t = fopen(argv[1],"r")))
Perror(argv[1]);
#ifdef BOOT
rflag = 1; /* force bootstrap to be written */
#endif
if (getasciilabel(t, lp))
writelabel(f, bootarea, lp);
break;
case WRITE:
type = argv[1];
#ifdef BOOT
if (argc > 5 || argc < 2)
usage();
if (argc > 3) {
bootxx = argv[--argc];
xxboot = argv[--argc];
}
#else
if (argc > 3 || argc < 2)
usage();
#endif
if (argc > 2)
name = argv[--argc];
makelabel(type, name, &lab);
lp = makebootarea(bootarea, &lab);
*lp = lab;
#ifdef BOOT
rflag = 1; /* force bootstrap to be written */
#endif
if (checklabel(lp) == 0)
writelabel(f, bootarea, lp);
break;
}
exit(0);
}
makelabel(type, name, lp)
char *type, *name;
register struct disklabel *lp;
{
register struct disklabel *dp;
dp = getdiskbyname(type);
if (dp == NULL) {
fprintf(stderr, "%s: unknown disk type\n", type);
exit(1);
}
*lp = *dp;
if (name)
(void)strncpy(lp->d_name, name, sizeof(lp->d_name));
}
writelabel(f, boot, lp)
int f;
char *boot;
register struct disklabel *lp;
{
register int i;
long lseek();
lp->d_magic = DISKMAGIC;
lp->d_magic2 = DISKMAGIC;
lp->d_checksum = 0;
lp->d_checksum = dkcksum(lp);
if (rflag) {
(void)lseek(f, (off_t)0, L_SET);
if (write(f, boot, lp->d_bbsize) < lp->d_bbsize)
Perror("write");
if (ioctl(f, DIOCSDINFO, lp) < 0)
Perror("ioctl DIOCSDINFO");
} else if (ioctl(f, DIOCWDINFO, lp) < 0)
Perror("ioctl DIOCWDINFO");
#if 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), L_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
}
/*
* Fetch disklabel for disk.
* If needboot is given, need bootstrap too.
* Use ioctl to get label unless -r flag is given.
*/
struct disklabel *
readlabel(f, needboot)
int f, needboot;
{
register struct disklabel *lp;
if (needboot || rflag) {
lp = (struct disklabel *)(bootarea + LABELOFFSET);
if (read(f, bootarea, BBSIZE) < BBSIZE)
Perror(specname);
} else
lp = &lab;
if (rflag == 0) {
if (ioctl(f, DIOCGDINFO, lp) < 0)
Perror("ioctl DIOCGDINFO");
} else {
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");
exit(1);
}
}
return (lp);
}
struct disklabel *
makebootarea(boot, dp)
char *boot;
register struct disklabel *dp;
{
struct disklabel *lp;
register char *p;
int b;
#ifdef BOOT
char *dkbasename;
if (xxboot == NULL) {
dkbasename = np;
if ((p = rindex(dkname, '/')) == NULL)
p = dkname;
else
p++;
while (*p && !isdigit(*p))
*np++ = *p++;
*np++ = '\0';
sprintf(np, "%s/%sboot", BOOTDIR, dkbasename);
if (access(np, F_OK) < 0 && dkbasename[0] == 'r')
dkbasename++;
xxboot = np;
sprintf(xxboot, "%s/%sboot", BOOTDIR, dkbasename);
np += strlen(xxboot) + 1;
bootxx = np;
sprintf(bootxx, "%s/boot%s", BOOTDIR, dkbasename);
np += strlen(bootxx) + 1;
}
b = open(xxboot, O_RDONLY);
if (b < 0)
Perror(xxboot);
if (read(b, boot, (int)dp->d_secsize) < 0)
Perror(xxboot);
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);
(void)close(b);
#endif
lp = (struct disklabel *)(boot + (LABELSECTOR * dp->d_secsize) +
LABELOFFSET);
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_name), lp->d_name);
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");
}
}
}
edit(lp)
struct disklabel *lp;
{
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 (0);
}
(void)fchmod(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");
break;
}
bzero((char *)&label, sizeof(label));
if (getasciilabel(fd, &label)) {
*lp = label;
(void) unlink(tmpfil);
return (1);
}
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 (0);
}
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_name, tp, sizeof (lp->d_name));
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;
}
v = atoi(cp);
if ((unsigned)v >= FSMAXTYPES)
fprintf(stderr, "line %d: %s %s\n", lineno,
"Warning, unknown filesystem type", cp);
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\n", 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\n");
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\n");
if (lp->d_npartitions > MAXPARTITIONS)
Warning("number of partitions (%d) > MAXPARTITIONS (%d)\n",
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\n",
part, pp->p_offset);
#ifdef notdef
if (pp->p_size % lp->d_secpercyl)
Warning("partition %c: size %% cylinder-size != 0\n",
part);
if (pp->p_offset % lp->d_secpercyl)
Warning("partition %c: offset %% cylinder-size != 0\n",
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\n",
pp->p_size, pp->p_offset);
}
return (errors);
}
/*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()
{
#ifdef BOOT
fprintf(stderr, "%-62s%s\n%-62s%s\n%-62s%s\n%-62s%s\n",
"usage: disklabel [-r] disk", "(to read label)",
"or disklabel -w [-r] disk type [ packid ] [ xxboot bootxx ]", "(to write label)",
"or disklabel -e [-r] disk", "(to edit label)",
"or disklabel -R [-r] disk protofile [ xxboot bootxx ]", "(to restore label)");
#else
fprintf(stderr, "%-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)");
#endif
exit(1);
}