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