1: /* 2: * Copyright (c) 1983, 1987 Regents of the University of California. 3: * All rights reserved. 4: * 5: * Redistribution and use in source and binary forms, with or without 6: * modification, are permitted provided that the following conditions 7: * are met: 8: * 1. Redistributions of source code must retain the above copyright 9: * notice, this list of conditions and the following disclaimer. 10: * 2. Redistributions in binary form must reproduce the above copyright 11: * notice, this list of conditions and the following disclaimer in the 12: * documentation and/or other materials provided with the distribution. 13: * 3. All advertising materials mentioning features or use of this software 14: * must display the following acknowledgement: 15: * This product includes software developed by the University of 16: * California, Berkeley and its contributors. 17: * 4. Neither the name of the University nor the names of its contributors 18: * may be used to endorse or promote products derived from this software 19: * without specific prior written permission. 20: * 21: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31: * SUCH DAMAGE. 32: */ 33: 34: #if defined(LIBC_SCCS) && !defined(lint) 35: static char sccsid[] = "@(#)disklabel.c 5.17.1 (2.11BSD) 4/10/95"; 36: #endif /* LIBC_SCCS and not lint */ 37: 38: #include <sys/param.h> 39: #include <sys/errno.h> 40: #include <sys/fs.h> 41: #include <sys/file.h> 42: #include <sys/uio.h> 43: 44: #define DKTYPENAMES 45: #include <sys/disklabel.h> 46: #include <stdio.h> 47: #include <string.h> 48: 49: extern int errno; 50: 51: static char *dgetstr(); 52: static dgetent(); 53: static dnamatch(); 54: static long dgetnum(), _gtnumdflt(); 55: static dgetflag(); 56: static gettype(); 57: static error(); 58: 59: #define getnumdflt(field, dname, dflt) field=_gtnumdflt(dname,(long)dflt) 60: 61: struct disklabel * 62: getdiskbyname(name) 63: char *name; 64: { 65: static struct disklabel disk; 66: static char boot[MAXPATHLEN]; 67: char localbuf[256]; /* BUFSIZ reduced to save stack space */ 68: char buf[BUFSIZ]; 69: char *cp, *cq; /* can't be register */ 70: register struct disklabel *dp = &disk; 71: register struct partition *pp; 72: char p, max, psize[3], pbsize[3], 73: pfsize[3], poffset[3], ptype[3]; 74: u_long *dx; 75: 76: if (dgetent(buf, name) <= 0) 77: return ((struct disklabel *)0); 78: bzero((char *)&disk, sizeof(disk)); 79: /* 80: * typename 81: */ 82: cq = dp->d_typename; 83: cp = buf; 84: while (cq < dp->d_typename + sizeof(dp->d_typename) - 1 && 85: (*cq = *cp) && *cq != '|' && *cq != ':') 86: cq++, cp++; 87: *cq = '\0'; 88: /* 89: * boot name (optional) xxboot 90: */ 91: cp = boot; 92: dp->d_boot0 = dgetstr("b0", &cp); 93: cp = localbuf; 94: cq = dgetstr("ty", &cp); 95: if (cq && strcmp(cq, "removable") == 0) 96: dp->d_flags |= D_REMOVABLE; 97: else if (cq && strcmp(cq, "simulated") == 0) 98: dp->d_flags |= D_RAMDISK; 99: if (dgetflag("sf")) 100: dp->d_flags |= D_BADSECT; 101: 102: /* 103: * Have to do this because anything except 512 will cause chaos in 104: * disklabel(8). disklabel(8) tries to protect itself against this 105: * but the safest thing is to fix the sector size here. The only thing 106: * which ever used a value other than 512 was the RL02 and RL01 107: * disktab entries and they have been fixed. 108: */ 109: 110: #ifdef corrupt_filesystems 111: getnumdflt(dp->d_secsize, "se", 512); 112: #endif 113: dp->d_secsize = 512; 114: 115: dp->d_ntracks = dgetnum("nt"); 116: dp->d_nsectors = dgetnum("ns"); 117: dp->d_ncylinders = dgetnum("nc"); 118: cq = dgetstr("dt", &cp); 119: if (cq) 120: dp->d_type = gettype(cq, dktypenames); 121: else 122: getnumdflt(dp->d_type, "dt", 0); 123: getnumdflt(dp->d_secpercyl, "sc", dp->d_nsectors * dp->d_ntracks); 124: getnumdflt(dp->d_secperunit, "su", dp->d_secpercyl * dp->d_ncylinders); 125: getnumdflt(dp->d_sparespertrack, "rt", 0); 126: getnumdflt(dp->d_sparespercyl, "rc", 0); 127: getnumdflt(dp->d_acylinders, "ac", 0); 128: getnumdflt(dp->d_rpm, "rm", 3600); 129: getnumdflt(dp->d_interleave, "il", 1); 130: getnumdflt(dp->d_trackskew, "sk", 0); 131: getnumdflt(dp->d_cylskew, "cs", 0); 132: getnumdflt(dp->d_headswitch, "hs", 0); 133: getnumdflt(dp->d_trkseek, "ts", 0); 134: 135: /* 136: * See the comments in src/bin/disklabel.c for a more detailed explaination 137: * which the 'bbsize' is set to 512. The simple explanation is that the 138: * designers of disklabeling confused 'sectors' and 'filesystem blocks'. 139: * BBSIZE is set to 1024 even though the real boot area (what the boot roms 140: * will read) is 512. 141: */ 142: #ifdef boot_area_really_is_1k 143: getnumdflt(dp->d_bbsize, "bs", BBSIZE); 144: #endif 145: dp->d_bbsize = 512; 146: 147: getnumdflt(dp->d_sbsize, "sb", SBSIZE); 148: strcpy(psize, "px"); 149: strcpy(pbsize, "bx"); 150: strcpy(pfsize, "fx"); 151: strcpy(poffset, "ox"); 152: strcpy(ptype, "tx"); 153: max = 'a' - 1; 154: pp = &dp->d_partitions[0]; 155: for (p = 'a'; p < 'a' + MAXPARTITIONS; p++, pp++) { 156: psize[1] = pbsize[1] = pfsize[1] = poffset[1] = ptype[1] = p; 157: pp->p_size = dgetnum(psize); 158: if (pp->p_size == -1L) 159: pp->p_size = 0L; 160: else { 161: pp->p_offset = dgetnum(poffset); 162: getnumdflt(pp->p_fsize, pfsize, 0); 163: if (pp->p_fsize) 164: pp->p_frag = dgetnum(pbsize) / pp->p_fsize; 165: getnumdflt(pp->p_fstype, ptype, 0); 166: if (pp->p_fstype == 0 && (cq = dgetstr(ptype, &cp))) 167: pp->p_fstype = gettype(cq, fstypenames); 168: max = p; 169: } 170: } 171: dp->d_npartitions = max + 1 - 'a'; 172: (void)strcpy(psize, "dx"); 173: dx = dp->d_drivedata; 174: for (p = '0'; p < '0' + NDDATA; p++, dx++) { 175: psize[1] = p; 176: getnumdflt(*dx, psize, 0); 177: } 178: dp->d_magic = DISKMAGIC; 179: dp->d_magic2 = DISKMAGIC; 180: return (dp); 181: } 182: 183: #include <ctype.h> 184: 185: static char *tbuf; 186: static char *dskip(); 187: static char *ddecode(); 188: 189: /* 190: * Get an entry for disk name in buffer bp, 191: * from the diskcap file. Parse is very rudimentary; 192: * we just notice escaped newlines. 193: */ 194: static 195: dgetent(bp, name) 196: char *bp, *name; 197: { 198: register char *cp; 199: register int c; 200: register int i = 0, cnt = 0; 201: char ibuf[512]; /* BUFSIZE - reduced to conserve stack space */ 202: int tf; 203: 204: tbuf = bp; 205: tf = open(_PATH_DISKTAB, 0); 206: if (tf < 0) { 207: error(errno); 208: return (-1); 209: } 210: for (;;) { 211: cp = bp; 212: for (;;) { 213: if (i == cnt) { 214: cnt = read(tf, ibuf, sizeof (ibuf)); 215: if (cnt <= 0) { 216: error(errno); 217: close(tf); 218: return (0); 219: } 220: i = 0; 221: } 222: c = ibuf[i++]; 223: if (c == '\n') { 224: if (cp > bp && cp[-1] == '\\'){ 225: cp--; 226: continue; 227: } 228: break; 229: } 230: if (cp >= bp+BUFSIZ) { 231: error(EFTYPE); 232: break; 233: } else 234: *cp++ = c; 235: } 236: *cp = 0; 237: 238: /* 239: * The real work for the match. 240: */ 241: if (dnamatch(name)) { 242: close(tf); 243: return (1); 244: } 245: } 246: } 247: 248: /* 249: * Dnamatch deals with name matching. The first field of the disktab 250: * entry is a sequence of names separated by |'s, so we compare 251: * against each such name. The normal : terminator after the last 252: * name (before the first field) stops us. 253: */ 254: static 255: dnamatch(np) 256: char *np; 257: { 258: register char *Np, *Bp; 259: 260: Bp = tbuf; 261: if (*Bp == '#') 262: return (0); 263: for (;;) { 264: for (Np = np; *Np && *Bp == *Np; Bp++, Np++) 265: continue; 266: if (*Np == 0 && (*Bp == '|' || *Bp == ':' || *Bp == 0)) 267: return (1); 268: while (*Bp && *Bp != ':' && *Bp != '|') 269: Bp++; 270: if (*Bp == 0 || *Bp == ':') 271: return (0); 272: Bp++; 273: } 274: } 275: 276: /* 277: * Skip to the next field. Notice that this is very dumb, not 278: * knowing about \: escapes or any such. If necessary, :'s can be put 279: * into the diskcap file in octal. 280: */ 281: static char * 282: dskip(bp) 283: register char *bp; 284: { 285: 286: while (*bp && *bp != ':') 287: bp++; 288: while (*bp == ':') 289: bp++; 290: return (bp); 291: } 292: 293: /* 294: * Return the (numeric) option id. 295: * Numeric options look like 296: * li#80 297: * i.e. the option string is separated from the numeric value by 298: * a # character. If the option is not found we return -1. 299: * Note that we handle octal numbers beginning with 0. 300: */ 301: static long 302: dgetnum(id) 303: char *id; 304: { 305: register int base; 306: long i; 307: register char *bp = tbuf; 308: 309: for (;;) { 310: bp = dskip(bp); 311: if (*bp == 0) 312: return (-1); 313: if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1]) 314: continue; 315: if (*bp == '@') 316: return (-1); 317: if (*bp != '#') 318: continue; 319: bp++; 320: base = 10; 321: if (*bp == '0') 322: base = 8; 323: i = 0; 324: while (isdigit(*bp)) 325: i *= base, i += *bp++ - '0'; 326: return (i); 327: } 328: } 329: 330: /* 331: * Handle a flag option. 332: * Flag options are given "naked", i.e. followed by a : or the end 333: * of the buffer. Return 1 if we find the option, or 0 if it is 334: * not given. 335: */ 336: static 337: dgetflag(id) 338: char *id; 339: { 340: register char *bp = tbuf; 341: 342: for (;;) { 343: bp = dskip(bp); 344: if (!*bp) 345: return (0); 346: if (*bp++ == id[0] && *bp != 0 && *bp++ == id[1]) { 347: if (!*bp || *bp == ':') 348: return (1); 349: else if (*bp == '@') 350: return (0); 351: } 352: } 353: } 354: 355: /* 356: * Get a string valued option. 357: * These are given as 358: * cl=^Z 359: * Much decoding is done on the strings, and the strings are 360: * placed in area, which is a ref parameter which is updated. 361: * No checking on area overflow. 362: */ 363: static char * 364: dgetstr(id, area) 365: char *id, **area; 366: { 367: register char *bp = tbuf; 368: 369: for (;;) { 370: bp = dskip(bp); 371: if (!*bp) 372: return (0); 373: if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1]) 374: continue; 375: if (*bp == '@') 376: return (0); 377: if (*bp != '=') 378: continue; 379: bp++; 380: return (ddecode(bp, area)); 381: } 382: } 383: 384: /* 385: * Tdecode does the grung work to decode the 386: * string capability escapes. 387: */ 388: static char * 389: ddecode(str, area) 390: register char *str; 391: char **area; 392: { 393: register char *cp; 394: register int c; 395: register char *dp; 396: int i; 397: 398: cp = *area; 399: while ((c = *str++) && c != ':') { 400: switch (c) { 401: 402: case '^': 403: c = *str++ & 037; 404: break; 405: 406: case '\\': 407: dp = "E\033^^\\\\::n\nr\rt\tb\bf\f"; 408: c = *str++; 409: nextc: 410: if (*dp++ == c) { 411: c = *dp++; 412: break; 413: } 414: dp++; 415: if (*dp) 416: goto nextc; 417: if (isdigit(c)) { 418: c -= '0', i = 2; 419: do 420: c <<= 3, c |= *str++ - '0'; 421: while (--i && isdigit(*str)); 422: } 423: break; 424: } 425: *cp++ = c; 426: } 427: *cp++ = 0; 428: str = *area; 429: *area = cp; 430: return (str); 431: } 432: 433: static 434: gettype(t, names) 435: char *t; 436: char **names; 437: { 438: register char **nm; 439: 440: for (nm = names; *nm; nm++) 441: if (strcasecmp(t, *nm) == 0) 442: return (nm - names); 443: if (isdigit(*t)) 444: return (atoi(t)); 445: return (0); 446: } 447: 448: static 449: error(err) 450: int err; 451: { 452: struct iovec iov[4]; 453: 454: iov[0].iov_base = "disktab: "; 455: iov[0].iov_len = 9; 456: iov[1].iov_base = _PATH_DISKTAB; 457: iov[1].iov_len = sizeof (_PATH_DISKTAB) - 1; 458: iov[2].iov_base = strerror(err); 459: iov[2].iov_len = strlen(iov[2].iov_base); 460: iov[3].iov_base = "\n"; 461: iov[3].iov_len = 1; 462: (void)writev(fileno(stderr), &iov, 4); 463: } 464: 465: static long 466: _gtnumdflt(dname, dflt) 467: char *dname; 468: long dflt; 469: { 470: long f; 471: 472: f = dgetnum(dname); 473: if (f == -1L) 474: f = dflt; 475: return(f); 476: }