121417Sdist /* 235104Sbostic * Copyright (c) 1983, 1987 Regents of the University of California. 335104Sbostic * All rights reserved. 435104Sbostic * 542622Sbostic * %sccs.include.redist.c% 621417Sdist */ 710748Ssam 826675Sdonn #if defined(LIBC_SCCS) && !defined(lint) 9*51531Sbostic static char sccsid[] = "@(#)disklabel.c 5.18 (Berkeley) 11/04/91"; 1035104Sbostic #endif /* LIBC_SCCS and not lint */ 1121417Sdist 1230420Skarels #include <sys/param.h> 1345646Sbostic #include <sys/errno.h> 1430420Skarels #include <sys/file.h> 1530420Skarels #define DKTYPENAMES 1630420Skarels #include <sys/disklabel.h> 17*51531Sbostic #include <ufs/ffs/fs.h> 1810748Ssam #include <stdio.h> 1942022Sbostic #include <string.h> 2046597Sdonn #include <stdlib.h> 2146597Sdonn #include <unistd.h> 2210748Ssam 2310748Ssam static char *dgetstr(); 2446597Sdonn static dgetent(); 2546597Sdonn static dnamatch(); 2646597Sdonn static dgetnum(); 2746597Sdonn static dgetflag(); 2846597Sdonn static gettype(); 2946597Sdonn static error(); 3010748Ssam 3130420Skarels struct disklabel * 3210748Ssam getdiskbyname(name) 3346597Sdonn const char *name; 3410748Ssam { 3533399Smarc static struct disklabel disk; 3633399Smarc static char boot[BUFSIZ]; 3733399Smarc char localbuf[BUFSIZ]; 3833399Smarc char buf[BUFSIZ]; 3933399Smarc char *cp, *cq; /* can't be register */ 4030420Skarels register struct disklabel *dp = &disk; 4110760Ssam register struct partition *pp; 4233399Smarc char p, max, psize[3], pbsize[3], 4333399Smarc pfsize[3], poffset[3], ptype[3]; 4433399Smarc u_long *dx; 4510748Ssam 4610748Ssam if (dgetent(buf, name) <= 0) 4730420Skarels return ((struct disklabel *)0); 4830420Skarels bzero((char *)&disk, sizeof(disk)); 4933399Smarc /* 5033399Smarc * typename 5133399Smarc */ 5230420Skarels cq = dp->d_typename; 5330420Skarels cp = buf; 5430420Skarels while (cq < dp->d_typename + sizeof(dp->d_typename) - 1 && 5530420Skarels (*cq = *cp) && *cq != '|' && *cq != ':') 5630420Skarels cq++, cp++; 5730420Skarels *cq = '\0'; 5833399Smarc /* 5933399Smarc * boot name (optional) xxboot, bootxx 6033399Smarc */ 6133399Smarc cp = boot; 6233399Smarc dp->d_boot0 = dgetstr("b0", &cp); 6333399Smarc dp->d_boot1 = dgetstr("b1", &cp); 6430420Skarels cp = localbuf; 6530420Skarels cq = dgetstr("ty", &cp); 6630420Skarels if (cq && strcmp(cq, "removable") == 0) 6730420Skarels dp->d_flags |= D_REMOVABLE; 6830420Skarels else if (cq && strcmp(cq, "simulated") == 0) 6930420Skarels dp->d_flags |= D_RAMDISK; 7030420Skarels if (dgetflag("sf")) 7130420Skarels dp->d_flags |= D_BADSECT; 7233399Smarc 7330420Skarels #define getnumdflt(field, dname, dflt) \ 7430420Skarels { int f = dgetnum(dname); \ 7530420Skarels (field) = f == -1 ? (dflt) : f; } 7630420Skarels 7730420Skarels getnumdflt(dp->d_secsize, "se", DEV_BSIZE); 7810748Ssam dp->d_ntracks = dgetnum("nt"); 7910748Ssam dp->d_nsectors = dgetnum("ns"); 8010748Ssam dp->d_ncylinders = dgetnum("nc"); 8130420Skarels cq = dgetstr("dt", &cp); 8230420Skarels if (cq) 8330420Skarels dp->d_type = gettype(cq, dktypenames); 8430420Skarels else 8530420Skarels getnumdflt(dp->d_type, "dt", 0); 8630420Skarels getnumdflt(dp->d_secpercyl, "sc", dp->d_nsectors * dp->d_ntracks); 8730420Skarels getnumdflt(dp->d_secperunit, "su", dp->d_secpercyl * dp->d_ncylinders); 8830420Skarels getnumdflt(dp->d_rpm, "rm", 3600); 8930420Skarels getnumdflt(dp->d_interleave, "il", 1); 9030420Skarels getnumdflt(dp->d_trackskew, "sk", 0); 9130420Skarels getnumdflt(dp->d_cylskew, "cs", 0); 9230420Skarels getnumdflt(dp->d_headswitch, "hs", 0); 9330420Skarels getnumdflt(dp->d_trkseek, "ts", 0); 9430420Skarels getnumdflt(dp->d_bbsize, "bs", BBSIZE); 9530420Skarels getnumdflt(dp->d_sbsize, "sb", SBSIZE); 9610760Ssam strcpy(psize, "px"); 9710760Ssam strcpy(pbsize, "bx"); 9810760Ssam strcpy(pfsize, "fx"); 9930420Skarels strcpy(poffset, "ox"); 10030420Skarels strcpy(ptype, "tx"); 10130420Skarels max = 'a' - 1; 10230420Skarels pp = &dp->d_partitions[0]; 10330420Skarels for (p = 'a'; p < 'a' + MAXPARTITIONS; p++, pp++) { 10430420Skarels psize[1] = pbsize[1] = pfsize[1] = poffset[1] = ptype[1] = p; 10510760Ssam pp->p_size = dgetnum(psize); 10630420Skarels if (pp->p_size == -1) 10730420Skarels pp->p_size = 0; 10830420Skarels else { 10930420Skarels pp->p_offset = dgetnum(poffset); 11030420Skarels getnumdflt(pp->p_fsize, pfsize, 0); 11130420Skarels if (pp->p_fsize) 11230420Skarels pp->p_frag = dgetnum(pbsize) / pp->p_fsize; 11330420Skarels getnumdflt(pp->p_fstype, ptype, 0); 11430420Skarels if (pp->p_fstype == 0 && (cq = dgetstr(ptype, &cp))) 11530420Skarels pp->p_fstype = gettype(cq, fstypenames); 11630420Skarels max = p; 11730420Skarels } 11810748Ssam } 11930420Skarels dp->d_npartitions = max + 1 - 'a'; 12030681Sbostic (void)strcpy(psize, "dx"); 12130420Skarels dx = dp->d_drivedata; 12230420Skarels for (p = '0'; p < '0' + NDDATA; p++, dx++) { 12330420Skarels psize[1] = p; 12430420Skarels getnumdflt(*dx, psize, 0); 12530420Skarels } 12630420Skarels dp->d_magic = DISKMAGIC; 12730420Skarels dp->d_magic2 = DISKMAGIC; 12810748Ssam return (dp); 12910748Ssam } 13010748Ssam 13110748Ssam #include <ctype.h> 13210748Ssam 13310748Ssam static char *tbuf; 13410748Ssam static char *dskip(); 13510748Ssam static char *ddecode(); 13610748Ssam 13710748Ssam /* 13810748Ssam * Get an entry for disk name in buffer bp, 13910748Ssam * from the diskcap file. Parse is very rudimentary; 14010748Ssam * we just notice escaped newlines. 14110748Ssam */ 14210748Ssam static 14310748Ssam dgetent(bp, name) 14410748Ssam char *bp, *name; 14510748Ssam { 14610748Ssam register char *cp; 14710748Ssam register int c; 14810748Ssam register int i = 0, cnt = 0; 14910748Ssam char ibuf[BUFSIZ]; 15010748Ssam int tf; 15110748Ssam 15210748Ssam tbuf = bp; 15345646Sbostic tf = open(_PATH_DISKTAB, 0); 15445646Sbostic if (tf < 0) { 15545646Sbostic error(errno); 15610748Ssam return (-1); 15745646Sbostic } 15810748Ssam for (;;) { 15910748Ssam cp = bp; 16010748Ssam for (;;) { 16110748Ssam if (i == cnt) { 16210748Ssam cnt = read(tf, ibuf, BUFSIZ); 16310748Ssam if (cnt <= 0) { 16445646Sbostic error(errno); 16510748Ssam close(tf); 16610748Ssam return (0); 16710748Ssam } 16810748Ssam i = 0; 16910748Ssam } 17010748Ssam c = ibuf[i++]; 17110748Ssam if (c == '\n') { 17210748Ssam if (cp > bp && cp[-1] == '\\'){ 17310748Ssam cp--; 17410748Ssam continue; 17510748Ssam } 17610748Ssam break; 17710748Ssam } 17810748Ssam if (cp >= bp+BUFSIZ) { 17945650Sbostic error(EFTYPE); 18010748Ssam break; 18110748Ssam } else 18210748Ssam *cp++ = c; 18310748Ssam } 18410748Ssam *cp = 0; 18510748Ssam 18610748Ssam /* 18710748Ssam * The real work for the match. 18810748Ssam */ 18910748Ssam if (dnamatch(name)) { 19010748Ssam close(tf); 19110748Ssam return (1); 19210748Ssam } 19310748Ssam } 19410748Ssam } 19510748Ssam 19610748Ssam /* 19710748Ssam * Dnamatch deals with name matching. The first field of the disktab 19810748Ssam * entry is a sequence of names separated by |'s, so we compare 19910748Ssam * against each such name. The normal : terminator after the last 20010748Ssam * name (before the first field) stops us. 20110748Ssam */ 20210748Ssam static 20310748Ssam dnamatch(np) 20410748Ssam char *np; 20510748Ssam { 20610748Ssam register char *Np, *Bp; 20710748Ssam 20810748Ssam Bp = tbuf; 20910748Ssam if (*Bp == '#') 21010748Ssam return (0); 21110748Ssam for (;;) { 21210748Ssam for (Np = np; *Np && *Bp == *Np; Bp++, Np++) 21310748Ssam continue; 21410748Ssam if (*Np == 0 && (*Bp == '|' || *Bp == ':' || *Bp == 0)) 21510748Ssam return (1); 21610748Ssam while (*Bp && *Bp != ':' && *Bp != '|') 21710748Ssam Bp++; 21810748Ssam if (*Bp == 0 || *Bp == ':') 21910748Ssam return (0); 22010748Ssam Bp++; 22110748Ssam } 22210748Ssam } 22310748Ssam 22410748Ssam /* 22510748Ssam * Skip to the next field. Notice that this is very dumb, not 22610748Ssam * knowing about \: escapes or any such. If necessary, :'s can be put 22710748Ssam * into the diskcap file in octal. 22810748Ssam */ 22910748Ssam static char * 23010748Ssam dskip(bp) 23110748Ssam register char *bp; 23210748Ssam { 23310748Ssam 23410748Ssam while (*bp && *bp != ':') 23510748Ssam bp++; 23610748Ssam if (*bp == ':') 23710748Ssam bp++; 23810748Ssam return (bp); 23910748Ssam } 24010748Ssam 24110748Ssam /* 24210748Ssam * Return the (numeric) option id. 24310748Ssam * Numeric options look like 24410748Ssam * li#80 24510748Ssam * i.e. the option string is separated from the numeric value by 24610748Ssam * a # character. If the option is not found we return -1. 24710748Ssam * Note that we handle octal numbers beginning with 0. 24810748Ssam */ 24910748Ssam static 25010748Ssam dgetnum(id) 25110748Ssam char *id; 25210748Ssam { 25310748Ssam register int i, base; 25410748Ssam register char *bp = tbuf; 25510748Ssam 25610748Ssam for (;;) { 25710748Ssam bp = dskip(bp); 25810748Ssam if (*bp == 0) 25910748Ssam return (-1); 26010748Ssam if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1]) 26110748Ssam continue; 26210748Ssam if (*bp == '@') 26310748Ssam return (-1); 26410748Ssam if (*bp != '#') 26510748Ssam continue; 26610748Ssam bp++; 26710748Ssam base = 10; 26810748Ssam if (*bp == '0') 26910748Ssam base = 8; 27010748Ssam i = 0; 27110748Ssam while (isdigit(*bp)) 27210748Ssam i *= base, i += *bp++ - '0'; 27310748Ssam return (i); 27410748Ssam } 27510748Ssam } 27610748Ssam 27710748Ssam /* 27810748Ssam * Handle a flag option. 27910748Ssam * Flag options are given "naked", i.e. followed by a : or the end 28010748Ssam * of the buffer. Return 1 if we find the option, or 0 if it is 28110748Ssam * not given. 28210748Ssam */ 28310748Ssam static 28410748Ssam dgetflag(id) 28510748Ssam char *id; 28610748Ssam { 28710748Ssam register char *bp = tbuf; 28810748Ssam 28910748Ssam for (;;) { 29010748Ssam bp = dskip(bp); 29110748Ssam if (!*bp) 29210748Ssam return (0); 29310748Ssam if (*bp++ == id[0] && *bp != 0 && *bp++ == id[1]) { 29410748Ssam if (!*bp || *bp == ':') 29510748Ssam return (1); 29610748Ssam else if (*bp == '@') 29710748Ssam return (0); 29810748Ssam } 29910748Ssam } 30010748Ssam } 30110748Ssam 30210748Ssam /* 30310748Ssam * Get a string valued option. 30410748Ssam * These are given as 30510748Ssam * cl=^Z 30610748Ssam * Much decoding is done on the strings, and the strings are 30710748Ssam * placed in area, which is a ref parameter which is updated. 30810748Ssam * No checking on area overflow. 30910748Ssam */ 31010748Ssam static char * 31110748Ssam dgetstr(id, area) 31210748Ssam char *id, **area; 31310748Ssam { 31410748Ssam register char *bp = tbuf; 31510748Ssam 31610748Ssam for (;;) { 31710748Ssam bp = dskip(bp); 31810748Ssam if (!*bp) 31910748Ssam return (0); 32010748Ssam if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1]) 32110748Ssam continue; 32210748Ssam if (*bp == '@') 32310748Ssam return (0); 32410748Ssam if (*bp != '=') 32510748Ssam continue; 32610748Ssam bp++; 32710748Ssam return (ddecode(bp, area)); 32810748Ssam } 32910748Ssam } 33010748Ssam 33110748Ssam /* 33210748Ssam * Tdecode does the grung work to decode the 33310748Ssam * string capability escapes. 33410748Ssam */ 33510748Ssam static char * 33610748Ssam ddecode(str, area) 33710748Ssam register char *str; 33810748Ssam char **area; 33910748Ssam { 34010748Ssam register char *cp; 34110748Ssam register int c; 34210748Ssam register char *dp; 34310748Ssam int i; 34410748Ssam 34510748Ssam cp = *area; 34610748Ssam while ((c = *str++) && c != ':') { 34710748Ssam switch (c) { 34810748Ssam 34910748Ssam case '^': 35010748Ssam c = *str++ & 037; 35110748Ssam break; 35210748Ssam 35310748Ssam case '\\': 35410748Ssam dp = "E\033^^\\\\::n\nr\rt\tb\bf\f"; 35510748Ssam c = *str++; 35610748Ssam nextc: 35710748Ssam if (*dp++ == c) { 35810748Ssam c = *dp++; 35910748Ssam break; 36010748Ssam } 36110748Ssam dp++; 36210748Ssam if (*dp) 36310748Ssam goto nextc; 36410748Ssam if (isdigit(c)) { 36510748Ssam c -= '0', i = 2; 36610748Ssam do 36710748Ssam c <<= 3, c |= *str++ - '0'; 36810748Ssam while (--i && isdigit(*str)); 36910748Ssam } 37010748Ssam break; 37110748Ssam } 37210748Ssam *cp++ = c; 37310748Ssam } 37410748Ssam *cp++ = 0; 37510748Ssam str = *area; 37610748Ssam *area = cp; 37710748Ssam return (str); 37810748Ssam } 37930420Skarels 38030420Skarels static 38130420Skarels gettype(t, names) 38230420Skarels char *t; 38330420Skarels char **names; 38430420Skarels { 38530420Skarels register char **nm; 38630420Skarels 38730420Skarels for (nm = names; *nm; nm++) 38833261Smckusick if (strcasecmp(t, *nm) == 0) 38930420Skarels return (nm - names); 39030420Skarels if (isdigit(*t)) 39130420Skarels return (atoi(t)); 39230420Skarels return (0); 39330420Skarels } 39430420Skarels 39545646Sbostic static 39645646Sbostic error(err) 39745646Sbostic int err; 39845646Sbostic { 39945646Sbostic char *p; 40045646Sbostic 40145646Sbostic (void)write(STDERR_FILENO, "disktab: ", 9); 40245646Sbostic (void)write(STDERR_FILENO, _PATH_DISKTAB, sizeof(_PATH_DISKTAB) - 1); 40345646Sbostic p = strerror(err); 40445646Sbostic (void)write(STDERR_FILENO, p, strlen(p)); 40545646Sbostic (void)write(STDERR_FILENO, "\n", 1); 40645646Sbostic } 407