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