1 /* 2 * Copyright (c) 1983,1987 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 #if defined(LIBC_SCCS) && !defined(lint) 8 static char sccsid[] = "@(#)disklabel.c 5.9 (Berkeley) 01/27/88"; 9 #endif LIBC_SCCS and not lint 10 11 #include <sys/param.h> 12 #include <sys/fs.h> 13 #include <sys/file.h> 14 #define DKTYPENAMES 15 #include <sys/disklabel.h> 16 #include <stdio.h> 17 #include <strings.h> 18 19 static char *dgetstr(); 20 21 struct disklabel * 22 getdiskbyname(name) 23 char *name; 24 { 25 static struct disklabel disk; 26 static char boot[BUFSIZ]; 27 char localbuf[BUFSIZ]; 28 char buf[BUFSIZ]; 29 char *cp, *cq; /* can't be register */ 30 register struct disklabel *dp = &disk; 31 register struct partition *pp; 32 char p, max, psize[3], pbsize[3], 33 pfsize[3], poffset[3], ptype[3]; 34 u_long *dx; 35 36 if (dgetent(buf, name) <= 0) 37 return ((struct disklabel *)0); 38 bzero((char *)&disk, sizeof(disk)); 39 /* 40 * typename 41 */ 42 cq = dp->d_typename; 43 cp = buf; 44 while (cq < dp->d_typename + sizeof(dp->d_typename) - 1 && 45 (*cq = *cp) && *cq != '|' && *cq != ':') 46 cq++, cp++; 47 *cq = '\0'; 48 /* 49 * boot name (optional) xxboot, bootxx 50 */ 51 cp = boot; 52 dp->d_boot0 = dgetstr("b0", &cp); 53 dp->d_boot1 = dgetstr("b1", &cp); 54 cp = localbuf; 55 cq = dgetstr("ty", &cp); 56 if (cq && strcmp(cq, "removable") == 0) 57 dp->d_flags |= D_REMOVABLE; 58 else if (cq && strcmp(cq, "simulated") == 0) 59 dp->d_flags |= D_RAMDISK; 60 if (dgetflag("sf")) 61 dp->d_flags |= D_BADSECT; 62 63 #define getnumdflt(field, dname, dflt) \ 64 { int f = dgetnum(dname); \ 65 (field) = f == -1 ? (dflt) : f; } 66 67 getnumdflt(dp->d_secsize, "se", DEV_BSIZE); 68 dp->d_ntracks = dgetnum("nt"); 69 dp->d_nsectors = dgetnum("ns"); 70 dp->d_ncylinders = dgetnum("nc"); 71 cq = dgetstr("dt", &cp); 72 if (cq) 73 dp->d_type = gettype(cq, dktypenames); 74 else 75 getnumdflt(dp->d_type, "dt", 0); 76 getnumdflt(dp->d_secpercyl, "sc", dp->d_nsectors * dp->d_ntracks); 77 getnumdflt(dp->d_secperunit, "su", dp->d_secpercyl * dp->d_ncylinders); 78 getnumdflt(dp->d_rpm, "rm", 3600); 79 getnumdflt(dp->d_interleave, "il", 1); 80 getnumdflt(dp->d_trackskew, "sk", 0); 81 getnumdflt(dp->d_cylskew, "cs", 0); 82 getnumdflt(dp->d_headswitch, "hs", 0); 83 getnumdflt(dp->d_trkseek, "ts", 0); 84 getnumdflt(dp->d_bbsize, "bs", BBSIZE); 85 getnumdflt(dp->d_sbsize, "sb", SBSIZE); 86 strcpy(psize, "px"); 87 strcpy(pbsize, "bx"); 88 strcpy(pfsize, "fx"); 89 strcpy(poffset, "ox"); 90 strcpy(ptype, "tx"); 91 max = 'a' - 1; 92 pp = &dp->d_partitions[0]; 93 for (p = 'a'; p < 'a' + MAXPARTITIONS; p++, pp++) { 94 psize[1] = pbsize[1] = pfsize[1] = poffset[1] = ptype[1] = p; 95 pp->p_size = dgetnum(psize); 96 if (pp->p_size == -1) 97 pp->p_size = 0; 98 else { 99 pp->p_offset = dgetnum(poffset); 100 getnumdflt(pp->p_fsize, pfsize, 0); 101 if (pp->p_fsize) 102 pp->p_frag = dgetnum(pbsize) / pp->p_fsize; 103 getnumdflt(pp->p_fstype, ptype, 0); 104 if (pp->p_fstype == 0 && (cq = dgetstr(ptype, &cp))) 105 pp->p_fstype = gettype(cq, fstypenames); 106 max = p; 107 } 108 } 109 dp->d_npartitions = max + 1 - 'a'; 110 (void)strcpy(psize, "dx"); 111 dx = dp->d_drivedata; 112 for (p = '0'; p < '0' + NDDATA; p++, dx++) { 113 psize[1] = p; 114 getnumdflt(*dx, psize, 0); 115 } 116 dp->d_magic = DISKMAGIC; 117 dp->d_magic2 = DISKMAGIC; 118 return (dp); 119 } 120 121 #include <ctype.h> 122 123 static char *tbuf; 124 static char *dskip(); 125 static char *ddecode(); 126 127 /* 128 * Get an entry for disk name in buffer bp, 129 * from the diskcap file. Parse is very rudimentary; 130 * we just notice escaped newlines. 131 */ 132 static 133 dgetent(bp, name) 134 char *bp, *name; 135 { 136 register char *cp; 137 register int c; 138 register int i = 0, cnt = 0; 139 char ibuf[BUFSIZ]; 140 int tf; 141 142 tbuf = bp; 143 tf = open(DISKTAB, 0); 144 if (tf < 0) 145 return (-1); 146 for (;;) { 147 cp = bp; 148 for (;;) { 149 if (i == cnt) { 150 cnt = read(tf, ibuf, BUFSIZ); 151 if (cnt <= 0) { 152 close(tf); 153 return (0); 154 } 155 i = 0; 156 } 157 c = ibuf[i++]; 158 if (c == '\n') { 159 if (cp > bp && cp[-1] == '\\'){ 160 cp--; 161 continue; 162 } 163 break; 164 } 165 if (cp >= bp+BUFSIZ) { 166 write(2,"Disktab entry too long\n", 23); 167 break; 168 } else 169 *cp++ = c; 170 } 171 *cp = 0; 172 173 /* 174 * The real work for the match. 175 */ 176 if (dnamatch(name)) { 177 close(tf); 178 return (1); 179 } 180 } 181 } 182 183 /* 184 * Dnamatch deals with name matching. The first field of the disktab 185 * entry is a sequence of names separated by |'s, so we compare 186 * against each such name. The normal : terminator after the last 187 * name (before the first field) stops us. 188 */ 189 static 190 dnamatch(np) 191 char *np; 192 { 193 register char *Np, *Bp; 194 195 Bp = tbuf; 196 if (*Bp == '#') 197 return (0); 198 for (;;) { 199 for (Np = np; *Np && *Bp == *Np; Bp++, Np++) 200 continue; 201 if (*Np == 0 && (*Bp == '|' || *Bp == ':' || *Bp == 0)) 202 return (1); 203 while (*Bp && *Bp != ':' && *Bp != '|') 204 Bp++; 205 if (*Bp == 0 || *Bp == ':') 206 return (0); 207 Bp++; 208 } 209 } 210 211 /* 212 * Skip to the next field. Notice that this is very dumb, not 213 * knowing about \: escapes or any such. If necessary, :'s can be put 214 * into the diskcap file in octal. 215 */ 216 static char * 217 dskip(bp) 218 register char *bp; 219 { 220 221 while (*bp && *bp != ':') 222 bp++; 223 if (*bp == ':') 224 bp++; 225 return (bp); 226 } 227 228 /* 229 * Return the (numeric) option id. 230 * Numeric options look like 231 * li#80 232 * i.e. the option string is separated from the numeric value by 233 * a # character. If the option is not found we return -1. 234 * Note that we handle octal numbers beginning with 0. 235 */ 236 static 237 dgetnum(id) 238 char *id; 239 { 240 register int i, base; 241 register char *bp = tbuf; 242 243 for (;;) { 244 bp = dskip(bp); 245 if (*bp == 0) 246 return (-1); 247 if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1]) 248 continue; 249 if (*bp == '@') 250 return (-1); 251 if (*bp != '#') 252 continue; 253 bp++; 254 base = 10; 255 if (*bp == '0') 256 base = 8; 257 i = 0; 258 while (isdigit(*bp)) 259 i *= base, i += *bp++ - '0'; 260 return (i); 261 } 262 } 263 264 /* 265 * Handle a flag option. 266 * Flag options are given "naked", i.e. followed by a : or the end 267 * of the buffer. Return 1 if we find the option, or 0 if it is 268 * not given. 269 */ 270 static 271 dgetflag(id) 272 char *id; 273 { 274 register char *bp = tbuf; 275 276 for (;;) { 277 bp = dskip(bp); 278 if (!*bp) 279 return (0); 280 if (*bp++ == id[0] && *bp != 0 && *bp++ == id[1]) { 281 if (!*bp || *bp == ':') 282 return (1); 283 else if (*bp == '@') 284 return (0); 285 } 286 } 287 } 288 289 /* 290 * Get a string valued option. 291 * These are given as 292 * cl=^Z 293 * Much decoding is done on the strings, and the strings are 294 * placed in area, which is a ref parameter which is updated. 295 * No checking on area overflow. 296 */ 297 static char * 298 dgetstr(id, area) 299 char *id, **area; 300 { 301 register char *bp = tbuf; 302 303 for (;;) { 304 bp = dskip(bp); 305 if (!*bp) 306 return (0); 307 if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1]) 308 continue; 309 if (*bp == '@') 310 return (0); 311 if (*bp != '=') 312 continue; 313 bp++; 314 return (ddecode(bp, area)); 315 } 316 } 317 318 /* 319 * Tdecode does the grung work to decode the 320 * string capability escapes. 321 */ 322 static char * 323 ddecode(str, area) 324 register char *str; 325 char **area; 326 { 327 register char *cp; 328 register int c; 329 register char *dp; 330 int i; 331 332 cp = *area; 333 while ((c = *str++) && c != ':') { 334 switch (c) { 335 336 case '^': 337 c = *str++ & 037; 338 break; 339 340 case '\\': 341 dp = "E\033^^\\\\::n\nr\rt\tb\bf\f"; 342 c = *str++; 343 nextc: 344 if (*dp++ == c) { 345 c = *dp++; 346 break; 347 } 348 dp++; 349 if (*dp) 350 goto nextc; 351 if (isdigit(c)) { 352 c -= '0', i = 2; 353 do 354 c <<= 3, c |= *str++ - '0'; 355 while (--i && isdigit(*str)); 356 } 357 break; 358 } 359 *cp++ = c; 360 } 361 *cp++ = 0; 362 str = *area; 363 *area = cp; 364 return (str); 365 } 366 367 static 368 gettype(t, names) 369 char *t; 370 char **names; 371 { 372 register char **nm; 373 374 for (nm = names; *nm; nm++) 375 if (strcasecmp(t, *nm) == 0) 376 return (nm - names); 377 if (isdigit(*t)) 378 return (atoi(t)); 379 return (0); 380 } 381 382 dkcksum(lp) 383 register struct disklabel *lp; 384 { 385 register u_short *start, *end; 386 register u_short sum = 0; 387 388 start = (u_short *)lp; 389 end = (u_short *)&lp->d_partitions[lp->d_npartitions]; 390 while (start < end) 391 sum ^= *start++; 392 return (sum); 393 } 394