1 /*- 2 * Copyright (c) 1990 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * William Jolitz. 7 * 8 * %sccs.include.noredist.c% 9 * 10 * @(#)disktab.c 7.1 (Berkeley) 04/24/90 11 */ 12 13 #include <disktab.h> 14 15 #define BUFSIZ 1024 16 17 static char *dgetstr(); 18 19 struct disktab * 20 getdiskbyname(name) 21 char *name; 22 { 23 static struct disktab disk; 24 static char localbuf[100], *cp = localbuf; 25 register struct disktab *dp = &disk; 26 register struct partition *pp; 27 char p, psize[3], pbsize[3], pfsize[3], posize[3]; 28 char buf[BUFSIZ]; 29 30 if (dgetent(buf, name) <= 0) 31 return ((struct disktab *)0); 32 dp->d_name = cp; 33 strcpy(cp, name); 34 cp += strlen(name) + 1; 35 dp->d_type = dgetstr("ty", &cp); 36 dp->d_secsize = dgetnum("se"); 37 if (dp->d_secsize < 0) 38 dp->d_secsize = 512; 39 dp->d_ntracks = dgetnum("nt"); 40 dp->d_nsectors = dgetnum("ns"); 41 dp->d_ncylinders = dgetnum("nc"); 42 dp->d_secpercyl = dgetnum("sc"); 43 dp->d_rpm = dgetnum("rm"); 44 if (dp->d_rpm < 0) 45 dp->d_rpm = 3600; 46 if (strcmp(dp->d_type, "st506") == 0 || 47 strcmp(dp->d_type, "ST506") == 0) { 48 dp->d_precomp = dgetnum("wp"); 49 if (dp->d_precomp < 0) 50 dp->d_precomp = 1023; 51 } 52 if (strcmp(dp->d_type, "scsi") == 0 || 53 strcmp(dp->d_type, "SCSI") == 0) 54 dp->d_blind = dgetflag("bm"); 55 strcpy(psize, "px"); 56 strcpy(pbsize, "bx"); 57 strcpy(pfsize, "fx"); 58 strcpy(posize, "ox"); 59 for (p = 'a'; p < 'i'; p++) { 60 psize[1] = pbsize[1] = pfsize[1] = posize[1] = p; 61 pp = &dp->d_partitions[p - 'a']; 62 pp->p_size = dgetnum(psize); 63 if (pp->p_size == -1) 64 pp->p_size = 0; 65 pp->p_bsize = dgetnum(pbsize); 66 if (pp->p_bsize == -1) 67 pp->p_bsize = 0; 68 pp->p_fsize = dgetnum(pfsize); 69 if (pp->p_fsize == -1) 70 pp->p_fsize = 0; 71 pp->p_offset = dgetnum(posize); 72 if (pp->p_offset == -1) 73 pp->p_offset = 0; 74 } 75 return (dp); 76 } 77 78 #include <ctype.h> 79 80 static char *tbuf; 81 static char *dskip(); 82 static char *ddecode(); 83 84 /* 85 * Get an entry for disk name in buffer bp, 86 * from the diskcap file. Parse is very rudimentary; 87 * we just notice escaped newlines. 88 */ 89 extern char *standdisk; 90 static 91 dgetent(bp, name) 92 char *bp, *name; 93 { 94 register char *cp; 95 register int c; 96 register int i = 0, cnt = 0; 97 char ibuf[BUFSIZ]; 98 int tf; 99 100 tbuf = bp; 101 tf = open(standdisk, 0); 102 if (tf < 0) 103 return (-1); 104 for (;;) { 105 cp = bp; 106 for (;;) { 107 if (i == cnt) { 108 cnt = read(tf, ibuf, BUFSIZ); 109 if (cnt <= 0) { 110 close(tf); 111 return (0); 112 } 113 i = 0; 114 } 115 c = ibuf[i++]; 116 if (c == '\n') { 117 if (cp > bp && cp[-1] == '\\'){ 118 cp--; 119 continue; 120 } 121 break; 122 } 123 if (cp >= bp+BUFSIZ) { 124 write(2,"Disktab entry too long\n", 23); 125 break; 126 } else 127 *cp++ = c; 128 } 129 *cp = 0; 130 131 /* 132 * The real work for the match. 133 */ 134 if (dnamatch(name)) { 135 close(tf); 136 return (1); 137 } 138 } 139 } 140 141 /* 142 * Dnamatch deals with name matching. The first field of the disktab 143 * entry is a sequence of names separated by |'s, so we compare 144 * against each such name. The normal : terminator after the last 145 * name (before the first field) stops us. 146 */ 147 static 148 dnamatch(np) 149 char *np; 150 { 151 register char *Np, *Bp; 152 153 Bp = tbuf; 154 if (*Bp == '#') 155 return (0); 156 for (;;) { 157 for (Np = np; *Np && *Bp == *Np; Bp++, Np++) 158 continue; 159 if (*Np == 0 && (*Bp == '|' || *Bp == ':' || *Bp == 0)) 160 return (1); 161 while (*Bp && *Bp != ':' && *Bp != '|') 162 Bp++; 163 if (*Bp == 0 || *Bp == ':') 164 return (0); 165 Bp++; 166 } 167 } 168 169 /* 170 * Skip to the next field. Notice that this is very dumb, not 171 * knowing about \: escapes or any such. If necessary, :'s can be put 172 * into the diskcap file in octal. 173 */ 174 static char * 175 dskip(bp) 176 register char *bp; 177 { 178 179 while (*bp && *bp != ':') 180 bp++; 181 if (*bp == ':') 182 bp++; 183 return (bp); 184 } 185 186 /* 187 * Return the (numeric) option id. 188 * Numeric options look like 189 * li#80 190 * i.e. the option string is separated from the numeric value by 191 * a # character. If the option is not found we return -1. 192 * Note that we handle octal numbers beginning with 0. 193 */ 194 static 195 dgetnum(id) 196 char *id; 197 { 198 register int i, base; 199 register char *bp = tbuf; 200 201 for (;;) { 202 bp = dskip(bp); 203 if (*bp == 0) 204 return (-1); 205 if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1]) 206 continue; 207 if (*bp == '@') 208 return (-1); 209 if (*bp != '#') 210 continue; 211 bp++; 212 base = 10; 213 if (*bp == '0') 214 base = 8; 215 i = 0; 216 while (isdigit(*bp)) 217 i *= base, i += *bp++ - '0'; 218 return (i); 219 } 220 } 221 222 /* 223 * Handle a flag option. 224 * Flag options are given "naked", i.e. followed by a : or the end 225 * of the buffer. Return 1 if we find the option, or 0 if it is 226 * not given. 227 */ 228 static 229 dgetflag(id) 230 char *id; 231 { 232 register char *bp = tbuf; 233 234 for (;;) { 235 bp = dskip(bp); 236 if (!*bp) 237 return (0); 238 if (*bp++ == id[0] && *bp != 0 && *bp++ == id[1]) { 239 if (!*bp || *bp == ':') 240 return (1); 241 else if (*bp == '@') 242 return (0); 243 } 244 } 245 } 246 247 /* 248 * Get a string valued option. 249 * These are given as 250 * cl=^Z 251 * Much decoding is done on the strings, and the strings are 252 * placed in area, which is a ref parameter which is updated. 253 * No checking on area overflow. 254 */ 255 static char * 256 dgetstr(id, area) 257 char *id, **area; 258 { 259 register char *bp = tbuf; 260 261 for (;;) { 262 bp = dskip(bp); 263 if (!*bp) 264 return (0); 265 if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1]) 266 continue; 267 if (*bp == '@') 268 return (0); 269 if (*bp != '=') 270 continue; 271 bp++; 272 return (ddecode(bp, area)); 273 } 274 } 275 276 /* 277 * Tdecode does the grung work to decode the 278 * string capability escapes. 279 */ 280 static char * 281 ddecode(str, area) 282 register char *str; 283 char **area; 284 { 285 register char *cp; 286 register int c; 287 register char *dp; 288 int i; 289 290 cp = *area; 291 while ((c = *str++) && c != ':') { 292 switch (c) { 293 294 case '^': 295 c = *str++ & 037; 296 break; 297 298 case '\\': 299 dp = "E\033^^\\\\::n\nr\rt\tb\bf\f"; 300 c = *str++; 301 nextc: 302 if (*dp++ == c) { 303 c = *dp++; 304 break; 305 } 306 dp++; 307 if (*dp) 308 goto nextc; 309 if (isdigit(c)) { 310 c -= '0', i = 2; 311 do 312 c <<= 3, c |= *str++ - '0'; 313 while (--i && isdigit(*str)); 314 } 315 break; 316 } 317 *cp++ = c; 318 } 319 *cp++ = 0; 320 str = *area; 321 *area = cp; 322 return (str); 323 } 324