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