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