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