2.11BSD/sys/pdpstand/disklabel.c
/*
* Public domain, June 1995
*
* @(#)disklabel.c 1.4 (2.11BSD GTE) 1996/5/2
*/
#define DKTYPENAMES
#include "../h/param.h"
#include "saio.h"
int Nolabelerr = 1; /* Inhibit spurious label error msgs */
char module[] = "disklabel"; /* This program's name */
char line[80], device[80];
extern long atol();
extern struct iob iob[];
extern struct devsw devsw[];
main()
{
register int f;
register struct disklabel *lp;
struct iob *io;
printf("%s\n", module);
while (1)
{
printf("Disk? ");
gets(line);
if (!line[0])
continue;
strcpy(device, line);
f = open(device, F_WRITE);
if (f < 0)
{
printf("Error opening '%s' for writing\n", device);
continue;
}
io = &iob[f - 3];
if (io->i_flgs & F_TAPE)
{
printf("Can not label tapes.\n");
continue;
}
break;
}
/*
* The open() will have retrieved the label sector. This explicit read
* is for debugging and testing because the driver's open routine may be
* under development and the automatic retrieval of the label is commented
* out.
*/
if (devlabel(io, READLABEL) < 0)
{
printf("Can not read label sector from '%s'\n", device);
return; /* back to Boot */
}
lp = &io->i_label;
if (lp->d_magic != DISKMAGIC || lp->d_magic2 != DISKMAGIC ||
dkcksum(lp))
{
printf("'%s' is unlabeled or the label is corrupt.\n", device);
printf("Proceed? [y/n] ");
if (gyon() == 'n')
return; /* back to Boot */
/*
* We next call the driver's entry which attempts to identify the drive
* and set up a default (1 partition) label with the best guess as to
* geometry, etc. If this call fails then the driver does not support
* labels ('nullsys' is being used in the device table).
*/
if (devlabel(io, DEFAULTLABEL) < 0)
{
printf("The '%s' driver does not support labels.\n",
devsw[io->i_ino.i_dev].dv_name);
return; /* back to Boot */
}
}
doit(io);
return;
}
doit(io)
register struct iob *io;
{
int c, dirty = 0;
struct disklabel *lp = &io->i_label;
while (1)
{
printf("d(isplay) D(efault) m(odify) w(rite) q(uit)? ");
c = egetchar("dDmwq");
switch (c)
{
case 'm':
modifylabel(lp);
overlapchk(lp);
(void)checklabel(lp);
/*
* We make the assumption that the label was modified - the dirty
* flag is set so we can ask if the changes should be discarded on a 'q'.
*/
dirty = 1;
break;
case 'w':
overlapchk(lp);
(void)checklabel(lp);
devlabel(io, WRITELABEL);
/*
* Changed label was committed to disk so we can clear the dirty flag now
* and not ask the user if the changes should be kept when a 'q'uit is done.
*/
dirty = 0;
break;
case 'd':
displaylabel(lp);
break;
case 'D':
devlabel(io, DEFAULTLABEL);
dirty = 1;
break;
case 'q':
if (!dirty)
return;
printf("Label changed. Discard changes [y/n]? ");
if (gyon() == 'n')
break;
return;
default:
break;
}
}
/* NOTREACHED */
}
modifylabel(lp)
register struct disklabel *lp;
{
register int c;
while (1)
{
printf("modify\n");
printf("d(isplay) g(eometry) m(isc) p(artitions) q(uit)? ");
c = egetchar("dgmpq");
switch (c)
{
case 'd':
displaylabel(lp);
break;
case 'g':
dogeometry(lp);
break;
case 'm':
domisc(lp);
break;
case 'p':
dopartitions(lp);
break;
case 'q':
return;
default:
break;
}
}
/* NOTREACHED */
}
dogeometry(lp)
struct disklabel *lp;
{
register int c;
while (1)
{
printf("modify geometry\n");
printf("d(isplay) s(ector/trk) t(rk/cyl) c(yl) S(ector/cyl) q(uit)? ");
c = egetchar("dstcSq");
switch (c)
{
case 'd':
displaylabel(lp);
break;
case 's':
fillin_int(&lp->d_nsectors,
"sectors/track [%d]: ", 512);
break;
case 't':
fillin_int(&lp->d_ntracks,
"tracks/cylinder [%d]: ", 127);
break;
case 'c':
fillin_int(&lp->d_ncylinders,
"cylinders [%d]: ", 4096);
break;
case 'S':
lp->d_secpercyl= lp->d_nsectors * lp->d_ntracks;
fillin_int(&lp->d_secpercyl,
"sectors/cylinder [%d]: ", 65535);
break;
case 'q':
if (lp->d_secpercyl == 0)
lp->d_secpercyl = lp->d_nsectors *
lp->d_ntracks;
lp->d_secperunit = (long)lp->d_ncylinders *
lp->d_secpercyl;
return;
default:
break;
}
}
/* NOTREACHED */
}
domisc(lp)
register struct disklabel *lp;
{
register int c;
char junk[32];
while (1)
{
printf("modify misc\n");
printf("d(isplay) t(ype) n(ame) l(abel) f(lags) r(pm) D(rivedata) q(uit)? ");
c = egetchar("dtnlfrDq");
switch (c)
{
case 'd':
displaylabel(lp);
break;
case 't':
if (lp->d_type >= DKMAXTYPES)
lp->d_type = 0;
printf("type [%s]: ", dktypenames[lp->d_type]);
gets(line);
if (line[0])
lp->d_type = findtype(dktypenames,
line,
lp->d_type);
break;
case 'n':
strncpy(junk, lp->d_typename,
sizeof (lp->d_typename));
junk[sizeof (lp->d_typename)] = '\0';
printf("disk [%s]: ", junk);
gets(line);
if (line[0])
strncpy(lp->d_typename, line,
sizeof (lp->d_typename));
break;
case 'l':
strncpy(junk, lp->d_packname,
sizeof (lp->d_packname));
junk[sizeof (lp->d_packname)] = '\0';
printf("label [%s]: ", junk);
gets(line);
if (line[0])
strncpy(lp->d_packname, line,
sizeof (lp->d_packname));
break;
case 'f':
doflags(lp);
break;
case 'r':
fillin_int(&lp->d_rpm, "rpm [%d]: ", 32767);
break;
case 'D':
dodrivedata(lp);
break;
case 'q':
return;
default:
break;
}
}
/* NOTREACHED */
}
dodrivedata(lp)
struct disklabel *lp;
{
register u_long *ulp;
register int i;
for (i = 0, ulp = lp->d_drivedata; i < NDDATA; i++, ulp++)
{
printf("modify misc drivedata\n");
printf("drivedata #%d [%D]: ", i, *ulp);
gets(line);
if (line[0])
*ulp = atol(line);
}
return;
}
doflags(lp)
register struct disklabel *lp;
{
register int c;
while (1)
{
printf("modify misc flags\n");
printf("d(isplay) c(lear) e(cc) b(adsect) r(emovable) q(uit)? ");
c = egetchar("dcerbq");
switch (c)
{
case 'c':
lp->d_flags = 0;
break;
case 'd':
displaylabel(lp);
break;
case 'r':
lp->d_flags |= D_REMOVABLE;
break;
case 'e':
lp->d_flags |= D_ECC;
break;
case 'b':
lp->d_flags |= D_BADSECT;
break;
case 'q':
return;
default:
break;
}
}
/* NOTREACHED */
}
dopartitions(lp)
struct disklabel *lp;
{
register int c;
int i;
while (1)
{
printf("modify partitions\n");
printf("d(isplay) n(umber) s(elect) q(uit)? ");
c = egetchar("dsnq");
switch (c)
{
case 'd':
displaylabel(lp);
break;
case 'n':
printf("Number of partitions (%d max) [%d]? ",
MAXPARTITIONS, lp->d_npartitions);
gets(line);
if (line[0] == '\0')
i = lp->d_npartitions;
else
i = atoi(line);
if (i > 0 && i <= MAXPARTITIONS)
lp->d_npartitions = i;
break;
case 's':
printf("a b c d e f g h q(uit)? ");
i = getpartnum();
if (i < 0)
break;
if (i >= lp->d_npartitions)
lp->d_npartitions = i + 1;
dopartmods(lp, i);
break;
case 'q':
return;
default:
break;
}
}
/* NOTREACHED */
}
dopartmods(lp, part)
struct disklabel *lp;
int part;
{
char pname = 'a' + part;
int i, c;
register struct partition *pp = &lp->d_partitions[part];
u_int cyl;
daddr_t off, sec, size;
printf("sizes and offsets may be given as sectors, cylinders\n");
printf("or cylinders plus sectors: 6200, 32c, 19c10s respectively\n");
while (1)
{
printf("modify partition '%c'\n", pname);
printf("d(isplay) z(ero) t(ype) o(ffset) s(ize) f(rag) F(size) q(uit)? ");
c = egetchar("dztosfFq");
switch (c)
{
case 'z':
pp->p_size = 0;
pp->p_offset = 0;
pp->p_fstype = FS_UNUSED;
break;
case 'd':
displaylabel(lp);
break;
case 't':
if (pp->p_fstype >= FSMAXTYPES)
pp->p_fstype = FS_UNUSED;
printf("'%c' fstype [%s]: ", pname,
fstypenames[pp->p_fstype]);
gets(line);
if (line[0])
pp->p_fstype = findtype(fstypenames,
line,
pp->p_fstype);
break;
case 'o':
printf("'%c' offset [%D]: ",pname,pp->p_offset);
gets(line);
if (line[0] == '\0')
break;
i = parse_sec_cyl(lp, line, &sec, &cyl);
if (i < 0)
break;
if (cyl)
off = (long)lp->d_secpercyl * cyl;
else
off = 0;
off += sec;
pp->p_offset = off;
break;
case 's':
printf("'%c' size [%D]: ", pname, pp->p_size);
gets(line);
if (line[0] == '\0')
break;
i = parse_sec_cyl(lp, line, &sec, &cyl);
if (i < 0)
break;
if (cyl)
size = (long)lp->d_secpercyl * cyl;
else
size = 0;
size += sec;
pp->p_size = size;
break;
case 'f':
printf("'%c' frags/fs-block [1]: ", pname);
gets(line);
if (line[0] == '\0')
break;
i = atoi(line);
if (i <= 0 || i > 255)
{
printf("frags/block <= 0 || > 255\n");
pp->p_frag = 1;
}
else
pp->p_frag = i;
break;
case 'F': /* Not really used at the present */
printf("'%c' frag size [1024]: ", pname);
gets(line);
if (line[0] == '\0')
break;
i = atoi(line);
if (i <= 0 || (i % NBPG))
{
printf("fragsize <= 0 || ! % NBPG\n");
pp->p_fsize = 0;
}
else
pp->p_fsize = i;
break;
case 'q':
if (pp->p_fsize == 0)
pp->p_fsize = 1024;
if (pp->p_frag == 0)
pp->p_frag = 1;
return;
default:
break;
}
}
/* NOTREACHED */
}
getpartnum()
{
register int c;
c = egetchar("abcdefghq");
if (c == 'q')
return(-1);
return(c - 'a');
}
findtype(list, name, deflt)
char **list;
char *name;
int deflt;
{
register char **cpp;
int i;
for (i = 0, cpp = list; *cpp; cpp++, i++)
{
if (strcmp(*cpp, name) == 0)
return(i);
}
printf("%s not found in list. The possible choices are:\n\n", name);
for (cpp = list; *cpp; cpp++)
printf(" %s\n", *cpp);
putchar('\n');
return(deflt);
}
/*
* Sizes and offsets can be specified in four ways:
*
* Number of sectors: 32678
* Number of cylinders: 110c
* Number of cylinders and sectors: 29c14s
* Number of sectors and cylinders: 22s134c
*
* The trailing 's' or 'c' can be left off in the last two cases.
*
* The geometry section of the label must have been filled in previously.
* A warning is issued if the cylinder or cylinder+sector forms are used
* and the necessary geometry information is not present.
*/
parse_sec_cyl(lp, line, sec, cyl)
struct disklabel *lp;
char line[];
daddr_t *sec;
u_int *cyl;
{
register char *cp;
int error = 0;
long tmp, tmpcyl = 0, tmpsec = 0;
for (tmp = 0, cp = line; *cp; cp++)
{
if (*cp >= '0' && *cp <= '9')
{
tmp *= 10;
tmp += (*cp - '0');
}
else if (*cp == 'c')
{
if (tmpcyl)
{
printf("duplicate 'c'ylinder specified\n");
error = 1;
break;
}
tmpcyl = tmp;
tmp = 0;
}
else if (*cp == 's')
{
if (tmpsec)
{
printf("duplicate 's'ector specified\n");
error = 1;
break;
}
tmpsec = tmp;
tmp = 0;
}
else
{
printf("illegal character '%c'\n", *cp);
error = 1;
break;
}
}
if (error)
return(-1);
/*
* At this point if either a 's' or 'c' was encountered in the string then
* one or both of 'tmpsec' and 'tmpcyl' will be non-zero. If the trailing
* character was omitted we need to figure out which variable gets the
* contents left in 'tmp' when the terminating null character was seen. This
* is because "15c8" and "18s3" are both valid and indicate "15 cylinders +
* 8 sectors" and "18 sectors + 3 cylinders" respectively.
*
* If neither 'tmpsec' or 'tmpcyl' are nonzero then we have a simple sector
* number in 'tmp'.
*/
if (tmpsec || tmpcyl)
{
if (tmpsec)
tmpcyl = tmp;
else
tmpsec = tmp;
}
else
{
tmpsec = tmp;
tmpcyl = 0;
}
/*
* It is an error condition to specify a number of cylinders and not
* have previously defined the geometry - it is impossible to calculate
* the number of sectors in the partition without geometry.
*/
if (tmpcyl && lp->d_secpercyl == 0)
{
printf("# cylinders specified but no geometry info present!\n");
return(-1);
}
/*
* Sanity check to make sure erroneous number of cylinders is not believed
* due to truncation (number of cylinders is really a 'u_int')
*/
if (tmpcyl > 65535L)
{
printf("Number of cylinders specified (%D) is ridiculous!\n",
tmpcyl);
return(-1);
}
*cyl = (u_int)tmpcyl;
*sec = tmpsec;
return(0);
}
fillin_int(where, fmt, limit)
u_int *where;
char *fmt;
u_int limit;
{
u_int i;
printf(fmt, *where);
gets(line);
if (line[0])
{
i = (u_int)atoi(line);
if (i > limit)
{
printf("%d is out of bounds (> %d)\n", i, limit);
return;
}
*where = i;
}
}
fillin_long(where, fmt, limit)
u_long *where;
char *fmt;
u_long limit;
{
u_long l;
printf(fmt, *where);
gets(line);
if (line[0])
{
l = (u_int)atol(line);
if (l > limit)
{
printf("%D is out of bounds (> %D)\n", l, limit);
return;
}
*where = l;
}
}
gyon()
{
register int c;
c = egetchar("yYnN");
if (c >= 'A' && c <= 'Z')
c += ('a' - 'A');
return(c);
}
egetchar(str)
char *str;
{
register int c;
while (1)
{
c = getchar();
if (index(str, c))
break;
putchar('\007');
}
putchar(c);
putchar('\n');
return(c);
}
/*
* Check disklabel for errors and fill in
* derived fields according to supplied values.
*
* Adapted from the disklabel utility.
*/
checklabel(lp)
register struct disklabel *lp;
{
register struct partition *pp;
int i, errors = 0;
char part;
if (lp->d_nsectors == 0)
{
printf("sectors/track %d\n", lp->d_nsectors);
return(1);
}
if (lp->d_ntracks == 0)
{
printf("tracks/cylinder %d\n", lp->d_ntracks);
return(1);
}
if (lp->d_ncylinders == 0)
{
printf("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 = (long) lp->d_secpercyl * lp->d_ncylinders;
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)
{
printf("partition %c: offset past end of unit %D %D\n",
part, pp->p_offset, lp->d_secperunit);
errors++;
}
if (pp->p_offset + pp->p_size > lp->d_secperunit)
{
printf("partition %c: extends past end of unit %D %D %D\n",
part, pp->p_offset, pp->p_size, lp->d_secperunit);
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);
}
/*VARARGS1*/
Warning(fmt, a1, a2, a3, a4, a5)
char *fmt;
{
printf("Warning, ");
printf(fmt, a1, a2, a3, a4, a5);
printf("\n");
}