+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * %sccs.include.noredist.c%
+ *
+ * @(#)disktab.c 7.1 (Berkeley) %G%
+ */
+
+#include <disktab.h>
+
+#define BUFSIZ 1024
+
+static char *dgetstr();
+
+struct disktab *
+getdiskbyname(name)
+ char *name;
+{
+ static struct disktab disk;
+ static char localbuf[100], *cp = localbuf;
+ register struct disktab *dp = &disk;
+ register struct partition *pp;
+ char p, psize[3], pbsize[3], pfsize[3], posize[3];
+ char buf[BUFSIZ];
+
+ if (dgetent(buf, name) <= 0)
+ return ((struct disktab *)0);
+ dp->d_name = cp;
+ strcpy(cp, name);
+ cp += strlen(name) + 1;
+ dp->d_type = dgetstr("ty", &cp);
+ dp->d_secsize = dgetnum("se");
+ if (dp->d_secsize < 0)
+ dp->d_secsize = 512;
+ dp->d_ntracks = dgetnum("nt");
+ dp->d_nsectors = dgetnum("ns");
+ dp->d_ncylinders = dgetnum("nc");
+ dp->d_secpercyl = dgetnum("sc");
+ dp->d_rpm = dgetnum("rm");
+ if (dp->d_rpm < 0)
+ dp->d_rpm = 3600;
+ if (strcmp(dp->d_type, "st506") == 0 ||
+ strcmp(dp->d_type, "ST506") == 0) {
+ dp->d_precomp = dgetnum("wp");
+ if (dp->d_precomp < 0)
+ dp->d_precomp = 1023;
+ }
+ if (strcmp(dp->d_type, "scsi") == 0 ||
+ strcmp(dp->d_type, "SCSI") == 0)
+ dp->d_blind = dgetflag("bm");
+ strcpy(psize, "px");
+ strcpy(pbsize, "bx");
+ strcpy(pfsize, "fx");
+ strcpy(posize, "ox");
+ for (p = 'a'; p < 'i'; p++) {
+ psize[1] = pbsize[1] = pfsize[1] = posize[1] = p;
+ pp = &dp->d_partitions[p - 'a'];
+ pp->p_size = dgetnum(psize);
+ if (pp->p_size == -1)
+ pp->p_size = 0;
+ pp->p_bsize = dgetnum(pbsize);
+ if (pp->p_bsize == -1)
+ pp->p_bsize = 0;
+ pp->p_fsize = dgetnum(pfsize);
+ if (pp->p_fsize == -1)
+ pp->p_fsize = 0;
+ pp->p_offset = dgetnum(posize);
+ if (pp->p_offset == -1)
+ pp->p_offset = 0;
+ }
+ return (dp);
+}
+
+#include <ctype.h>
+
+static char *tbuf;
+static char *dskip();
+static char *ddecode();
+
+/*
+ * Get an entry for disk name in buffer bp,
+ * from the diskcap file. Parse is very rudimentary;
+ * we just notice escaped newlines.
+ */
+extern char *standdisk;
+static
+dgetent(bp, name)
+ char *bp, *name;
+{
+ register char *cp;
+ register int c;
+ register int i = 0, cnt = 0;
+ char ibuf[BUFSIZ];
+ int tf;
+
+ tbuf = bp;
+ tf = open(standdisk, 0);
+ if (tf < 0)
+ return (-1);
+ for (;;) {
+ cp = bp;
+ for (;;) {
+ if (i == cnt) {
+ cnt = read(tf, ibuf, BUFSIZ);
+ if (cnt <= 0) {
+ close(tf);
+ return (0);
+ }
+ i = 0;
+ }
+ c = ibuf[i++];
+ if (c == '\n') {
+ if (cp > bp && cp[-1] == '\\'){
+ cp--;
+ continue;
+ }
+ break;
+ }
+ if (cp >= bp+BUFSIZ) {
+ write(2,"Disktab entry too long\n", 23);
+ break;
+ } else
+ *cp++ = c;
+ }
+ *cp = 0;
+
+ /*
+ * The real work for the match.
+ */
+ if (dnamatch(name)) {
+ close(tf);
+ return (1);
+ }
+ }
+}
+
+/*
+ * Dnamatch deals with name matching. The first field of the disktab
+ * entry is a sequence of names separated by |'s, so we compare
+ * against each such name. The normal : terminator after the last
+ * name (before the first field) stops us.
+ */
+static
+dnamatch(np)
+ char *np;
+{
+ register char *Np, *Bp;
+
+ Bp = tbuf;
+ if (*Bp == '#')
+ return (0);
+ for (;;) {
+ for (Np = np; *Np && *Bp == *Np; Bp++, Np++)
+ continue;
+ if (*Np == 0 && (*Bp == '|' || *Bp == ':' || *Bp == 0))
+ return (1);
+ while (*Bp && *Bp != ':' && *Bp != '|')
+ Bp++;
+ if (*Bp == 0 || *Bp == ':')
+ return (0);
+ Bp++;
+ }
+}
+
+/*
+ * Skip to the next field. Notice that this is very dumb, not
+ * knowing about \: escapes or any such. If necessary, :'s can be put
+ * into the diskcap file in octal.
+ */
+static char *
+dskip(bp)
+ register char *bp;
+{
+
+ while (*bp && *bp != ':')
+ bp++;
+ if (*bp == ':')
+ bp++;
+ return (bp);
+}
+
+/*
+ * Return the (numeric) option id.
+ * Numeric options look like
+ * li#80
+ * i.e. the option string is separated from the numeric value by
+ * a # character. If the option is not found we return -1.
+ * Note that we handle octal numbers beginning with 0.
+ */
+static
+dgetnum(id)
+ char *id;
+{
+ register int i, base;
+ register char *bp = tbuf;
+
+ for (;;) {
+ bp = dskip(bp);
+ if (*bp == 0)
+ return (-1);
+ if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1])
+ continue;
+ if (*bp == '@')
+ return (-1);
+ if (*bp != '#')
+ continue;
+ bp++;
+ base = 10;
+ if (*bp == '0')
+ base = 8;
+ i = 0;
+ while (isdigit(*bp))
+ i *= base, i += *bp++ - '0';
+ return (i);
+ }
+}
+
+/*
+ * Handle a flag option.
+ * Flag options are given "naked", i.e. followed by a : or the end
+ * of the buffer. Return 1 if we find the option, or 0 if it is
+ * not given.
+ */
+static
+dgetflag(id)
+ char *id;
+{
+ register char *bp = tbuf;
+
+ for (;;) {
+ bp = dskip(bp);
+ if (!*bp)
+ return (0);
+ if (*bp++ == id[0] && *bp != 0 && *bp++ == id[1]) {
+ if (!*bp || *bp == ':')
+ return (1);
+ else if (*bp == '@')
+ return (0);
+ }
+ }
+}
+
+/*
+ * Get a string valued option.
+ * These are given as
+ * cl=^Z
+ * Much decoding is done on the strings, and the strings are
+ * placed in area, which is a ref parameter which is updated.
+ * No checking on area overflow.
+ */
+static char *
+dgetstr(id, area)
+ char *id, **area;
+{
+ register char *bp = tbuf;
+
+ for (;;) {
+ bp = dskip(bp);
+ if (!*bp)
+ return (0);
+ if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1])
+ continue;
+ if (*bp == '@')
+ return (0);
+ if (*bp != '=')
+ continue;
+ bp++;
+ return (ddecode(bp, area));
+ }
+}
+
+/*
+ * Tdecode does the grung work to decode the
+ * string capability escapes.
+ */
+static char *
+ddecode(str, area)
+ register char *str;
+ char **area;
+{
+ register char *cp;
+ register int c;
+ register char *dp;
+ int i;
+
+ cp = *area;
+ while ((c = *str++) && c != ':') {
+ switch (c) {
+
+ case '^':
+ c = *str++ & 037;
+ break;
+
+ case '\\':
+ dp = "E\033^^\\\\::n\nr\rt\tb\bf\f";
+ c = *str++;
+nextc:
+ if (*dp++ == c) {
+ c = *dp++;
+ break;
+ }
+ dp++;
+ if (*dp)
+ goto nextc;
+ if (isdigit(c)) {
+ c -= '0', i = 2;
+ do
+ c <<= 3, c |= *str++ - '0';
+ while (--i && isdigit(*str));
+ }
+ break;
+ }
+ *cp++ = c;
+ }
+ *cp++ = 0;
+ str = *area;
+ *area = cp;
+ return (str);
+}