1 1.87 joe /* $NetBSD: sem.c,v 1.87 2025/01/07 14:21:11 joe Exp $ */ 2 1.1 thorpej 3 1.1 thorpej /* 4 1.1 thorpej * Copyright (c) 1992, 1993 5 1.1 thorpej * The Regents of the University of California. All rights reserved. 6 1.1 thorpej * 7 1.1 thorpej * This software was developed by the Computer Systems Engineering group 8 1.1 thorpej * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and 9 1.1 thorpej * contributed to Berkeley. 10 1.1 thorpej * 11 1.1 thorpej * All advertising materials mentioning features or use of this software 12 1.1 thorpej * must display the following acknowledgement: 13 1.1 thorpej * This product includes software developed by the University of 14 1.1 thorpej * California, Lawrence Berkeley Laboratories. 15 1.1 thorpej * 16 1.1 thorpej * Redistribution and use in source and binary forms, with or without 17 1.1 thorpej * modification, are permitted provided that the following conditions 18 1.1 thorpej * are met: 19 1.1 thorpej * 1. Redistributions of source code must retain the above copyright 20 1.1 thorpej * notice, this list of conditions and the following disclaimer. 21 1.1 thorpej * 2. Redistributions in binary form must reproduce the above copyright 22 1.1 thorpej * notice, this list of conditions and the following disclaimer in the 23 1.1 thorpej * documentation and/or other materials provided with the distribution. 24 1.1 thorpej * 3. Neither the name of the University nor the names of its contributors 25 1.1 thorpej * may be used to endorse or promote products derived from this software 26 1.1 thorpej * without specific prior written permission. 27 1.1 thorpej * 28 1.1 thorpej * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 29 1.1 thorpej * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 30 1.1 thorpej * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 31 1.1 thorpej * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 32 1.1 thorpej * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 33 1.1 thorpej * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 34 1.1 thorpej * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 35 1.1 thorpej * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 36 1.1 thorpej * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 37 1.1 thorpej * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 38 1.1 thorpej * SUCH DAMAGE. 39 1.1 thorpej * 40 1.1 thorpej * from: @(#)sem.c 8.1 (Berkeley) 6/6/93 41 1.1 thorpej */ 42 1.1 thorpej 43 1.1 thorpej #if HAVE_NBTOOL_CONFIG_H 44 1.1 thorpej #include "nbtool_config.h" 45 1.1 thorpej #endif 46 1.1 thorpej 47 1.65 christos #include <sys/cdefs.h> 48 1.87 joe __RCSID("$NetBSD: sem.c,v 1.87 2025/01/07 14:21:11 joe Exp $"); 49 1.65 christos 50 1.1 thorpej #include <sys/param.h> 51 1.1 thorpej #include <ctype.h> 52 1.1 thorpej #include <stdio.h> 53 1.1 thorpej #include <stdlib.h> 54 1.1 thorpej #include <string.h> 55 1.24 christos #include <util.h> 56 1.1 thorpej #include "defs.h" 57 1.1 thorpej #include "sem.h" 58 1.1 thorpej 59 1.1 thorpej /* 60 1.1 thorpej * config semantics. 61 1.1 thorpej */ 62 1.1 thorpej 63 1.1 thorpej #define NAMESIZE 100 /* local name buffers */ 64 1.1 thorpej 65 1.1 thorpej const char *s_ifnet; /* magic attribute */ 66 1.1 thorpej const char *s_qmark; 67 1.1 thorpej const char *s_none; 68 1.1 thorpej 69 1.1 thorpej static struct hashtab *cfhashtab; /* for config lookup */ 70 1.1 thorpej struct hashtab *devitab; /* etc */ 71 1.46 uebayasi struct attr allattr; 72 1.71 christos size_t nattrs; 73 1.1 thorpej 74 1.1 thorpej static struct attr errattr; 75 1.1 thorpej static struct devbase errdev; 76 1.1 thorpej static struct deva errdeva; 77 1.1 thorpej 78 1.39 dholland static int has_errobj(struct attrlist *, struct attr *); 79 1.1 thorpej static struct nvlist *addtoattr(struct nvlist *, struct devbase *); 80 1.1 thorpej static int resolve(struct nvlist **, const char *, const char *, 81 1.1 thorpej struct nvlist *, int); 82 1.82 christos static struct pspec *getpspec(struct attr *, struct devbase *, int, int); 83 1.1 thorpej static struct devi *newdevi(const char *, int, struct devbase *d); 84 1.1 thorpej static struct devi *getdevi(const char *); 85 1.6 cube static void remove_devi(struct devi *); 86 1.1 thorpej static const char *concat(const char *, int); 87 1.1 thorpej static char *extend(char *, const char *); 88 1.1 thorpej static int split(const char *, size_t, char *, size_t, int *); 89 1.1 thorpej static void selectbase(struct devbase *, struct deva *); 90 1.41 dholland static const char **fixloc(const char *, struct attr *, struct loclist *); 91 1.32 drochner static const char *makedevstr(devmajor_t, devminor_t); 92 1.32 drochner static const char *major2name(devmajor_t); 93 1.32 drochner static devmajor_t dev2major(struct devbase *); 94 1.1 thorpej 95 1.1 thorpej extern const char *yyfile; 96 1.8 cube extern int vflag; 97 1.1 thorpej 98 1.76 christos #define V_ATTRIBUTE 0 99 1.76 christos #define V_DEVICE 1 100 1.76 christos struct vtype { 101 1.76 christos int type; 102 1.76 christos struct attr *attr; 103 1.76 christos void *value; 104 1.76 christos }; 105 1.76 christos 106 1.76 christos static struct nvlist * 107 1.76 christos makedevstack(struct devbase *d) 108 1.76 christos { 109 1.76 christos struct devi *firsti, *i; 110 1.76 christos struct nvlist *stack = NULL; 111 1.76 christos 112 1.76 christos for (firsti = d->d_ihead; firsti != NULL; firsti = firsti->i_bsame) 113 1.76 christos for (i = firsti; i != NULL; i = i->i_alias) 114 1.76 christos stack = newnv(NULL, NULL, i, 0, stack); 115 1.76 christos return stack; 116 1.76 christos } 117 1.76 christos 118 1.76 christos static void 119 1.76 christos devcleanup(struct nvlist *stack) 120 1.76 christos { 121 1.76 christos struct nvlist *nv; 122 1.76 christos for (nv = stack; nv != NULL; nv = nv->nv_next) 123 1.76 christos remove_devi(nv->nv_ptr); 124 1.76 christos nvfreel(stack); 125 1.76 christos } 126 1.76 christos 127 1.76 christos static void * 128 1.76 christos addvalue(int type, struct attr *a, void *value) 129 1.76 christos { 130 1.76 christos struct vtype *vt = emalloc(sizeof(*vt)); 131 1.76 christos vt->type = type; 132 1.76 christos vt->attr = a; 133 1.76 christos vt->value = value; 134 1.76 christos return vt; 135 1.76 christos } 136 1.76 christos 137 1.1 thorpej void 138 1.1 thorpej initsem(void) 139 1.1 thorpej { 140 1.1 thorpej 141 1.1 thorpej attrtab = ht_new(); 142 1.64 uebayasi attrdeptab = ht_new(); 143 1.46 uebayasi 144 1.46 uebayasi allattr.a_name = "netbsd"; 145 1.46 uebayasi TAILQ_INIT(&allattr.a_files); 146 1.46 uebayasi (void)ht_insert(attrtab, allattr.a_name, &allattr); 147 1.47 uebayasi selectattr(&allattr); 148 1.46 uebayasi 149 1.1 thorpej errattr.a_name = "<internal>"; 150 1.1 thorpej 151 1.1 thorpej TAILQ_INIT(&allbases); 152 1.1 thorpej 153 1.1 thorpej TAILQ_INIT(&alldevas); 154 1.1 thorpej 155 1.1 thorpej TAILQ_INIT(&allpspecs); 156 1.1 thorpej 157 1.1 thorpej cfhashtab = ht_new(); 158 1.1 thorpej TAILQ_INIT(&allcf); 159 1.1 thorpej 160 1.1 thorpej TAILQ_INIT(&alldevi); 161 1.1 thorpej errdev.d_name = "<internal>"; 162 1.1 thorpej 163 1.1 thorpej TAILQ_INIT(&allpseudo); 164 1.1 thorpej 165 1.1 thorpej TAILQ_INIT(&alldevms); 166 1.1 thorpej 167 1.1 thorpej s_ifnet = intern("ifnet"); 168 1.1 thorpej s_qmark = intern("?"); 169 1.1 thorpej s_none = intern("none"); 170 1.1 thorpej } 171 1.1 thorpej 172 1.1 thorpej /* Name of include file just ended (set in scan.l) */ 173 1.1 thorpej extern const char *lastfile; 174 1.1 thorpej 175 1.57 uebayasi static struct attr * 176 1.56 uebayasi finddep(struct attr *a, const char *name) 177 1.56 uebayasi { 178 1.56 uebayasi struct attrlist *al; 179 1.56 uebayasi 180 1.56 uebayasi for (al = a->a_deps; al != NULL; al = al->al_next) { 181 1.56 uebayasi struct attr *this = al->al_this; 182 1.56 uebayasi if (strcmp(this->a_name, name) == 0) 183 1.56 uebayasi return this; 184 1.56 uebayasi } 185 1.56 uebayasi return NULL; 186 1.56 uebayasi } 187 1.56 uebayasi 188 1.56 uebayasi static void 189 1.63 uebayasi mergedeps(const char *dname, const char *name) 190 1.56 uebayasi { 191 1.56 uebayasi struct attr *a, *newa; 192 1.56 uebayasi 193 1.63 uebayasi CFGDBG(4, "merging attr `%s' to devbase `%s'", name, dname); 194 1.63 uebayasi a = refattr(dname); 195 1.56 uebayasi if (finddep(a, name) == NULL) { 196 1.56 uebayasi newa = refattr(name); 197 1.56 uebayasi a->a_deps = attrlist_cons(a->a_deps, newa); 198 1.56 uebayasi CFGDBG(3, "attr `%s' merged to attr `%s'", newa->a_name, 199 1.56 uebayasi a->a_name); 200 1.56 uebayasi } 201 1.56 uebayasi } 202 1.56 uebayasi 203 1.56 uebayasi static void 204 1.56 uebayasi fixdev(struct devbase *dev) 205 1.56 uebayasi { 206 1.56 uebayasi struct attrlist *al; 207 1.56 uebayasi struct attr *devattr, *a; 208 1.56 uebayasi 209 1.56 uebayasi devattr = refattr(dev->d_name); 210 1.56 uebayasi if (devattr->a_devclass) 211 1.57 uebayasi panic("%s: dev %s is devclass!", __func__, devattr->a_name); 212 1.56 uebayasi 213 1.58 uebayasi CFGDBG(4, "fixing devbase `%s'", dev->d_name); 214 1.56 uebayasi for (al = dev->d_attrs; al != NULL; al = al->al_next) { 215 1.56 uebayasi a = al->al_this; 216 1.81 christos CFGDBG(4, "fixing devbase `%s' attr `%s'", dev->d_name, 217 1.81 christos a->a_name); 218 1.56 uebayasi if (a->a_iattr) { 219 1.56 uebayasi a->a_refs = addtoattr(a->a_refs, dev); 220 1.58 uebayasi CFGDBG(3, "device `%s' has iattr `%s'", dev->d_name, 221 1.58 uebayasi a->a_name); 222 1.56 uebayasi } else if (a->a_devclass != NULL) { 223 1.59 uebayasi if (dev->d_classattr != NULL && dev->d_classattr != a) { 224 1.56 uebayasi cfgwarn("device `%s' has multiple classes " 225 1.56 uebayasi "(`%s' and `%s')", 226 1.56 uebayasi dev->d_name, dev->d_classattr->a_name, 227 1.56 uebayasi a->a_name); 228 1.56 uebayasi } 229 1.59 uebayasi if (dev->d_classattr == NULL) { 230 1.59 uebayasi dev->d_classattr = a; 231 1.81 christos CFGDBG(3, "device `%s' is devclass `%s'", 232 1.81 christos dev->d_name, a->a_name); 233 1.59 uebayasi } 234 1.56 uebayasi } else { 235 1.56 uebayasi if (strcmp(dev->d_name, a->a_name) != 0) { 236 1.60 uebayasi mergedeps(dev->d_name, a->a_name); 237 1.56 uebayasi } 238 1.56 uebayasi } 239 1.56 uebayasi } 240 1.56 uebayasi } 241 1.56 uebayasi 242 1.1 thorpej void 243 1.1 thorpej enddefs(void) 244 1.1 thorpej { 245 1.1 thorpej struct devbase *dev; 246 1.1 thorpej 247 1.58 uebayasi yyfile = "enddefs"; 248 1.58 uebayasi 249 1.1 thorpej TAILQ_FOREACH(dev, &allbases, d_next) { 250 1.1 thorpej if (!dev->d_isdef) { 251 1.1 thorpej (void)fprintf(stderr, 252 1.1 thorpej "%s: device `%s' used but not defined\n", 253 1.1 thorpej lastfile, dev->d_name); 254 1.1 thorpej errors++; 255 1.1 thorpej continue; 256 1.1 thorpej } 257 1.60 uebayasi fixdev(dev); 258 1.1 thorpej } 259 1.1 thorpej if (errors) { 260 1.1 thorpej (void)fprintf(stderr, "*** Stop.\n"); 261 1.1 thorpej exit(1); 262 1.1 thorpej } 263 1.1 thorpej } 264 1.1 thorpej 265 1.1 thorpej void 266 1.1 thorpej setdefmaxusers(int min, int def, int max) 267 1.1 thorpej { 268 1.1 thorpej 269 1.1 thorpej if (min < 1 || min > def || def > max) 270 1.27 christos cfgerror("maxusers must have 1 <= min (%d) <= default (%d) " 271 1.27 christos "<= max (%d)", min, def, max); 272 1.1 thorpej else { 273 1.1 thorpej minmaxusers = min; 274 1.1 thorpej defmaxusers = def; 275 1.1 thorpej maxmaxusers = max; 276 1.1 thorpej } 277 1.1 thorpej } 278 1.1 thorpej 279 1.84 christos static const char *maxusers_srcfile; 280 1.84 christos static u_short maxusers_srcline; 281 1.84 christos 282 1.1 thorpej void 283 1.1 thorpej setmaxusers(int n) 284 1.1 thorpej { 285 1.1 thorpej 286 1.9 cube if (maxusers == n) { 287 1.84 christos cfgerror("duplicate maxusers parameter at %s:%hu", 288 1.84 christos maxusers_srcfile, maxusers_srcline); 289 1.1 thorpej return; 290 1.1 thorpej } 291 1.9 cube if (vflag && maxusers != 0) 292 1.84 christos cfgwarn("warning: maxusers already defined at %s:%hu", 293 1.84 christos maxusers_srcfile, maxusers_srcline); 294 1.1 thorpej maxusers = n; 295 1.84 christos maxusers_srcfile = yyfile; 296 1.84 christos maxusers_srcline = currentline(); 297 1.1 thorpej if (n < minmaxusers) { 298 1.27 christos cfgerror("warning: minimum of %d maxusers assumed", 299 1.27 christos minmaxusers); 300 1.1 thorpej errors--; /* take it away */ 301 1.1 thorpej maxusers = minmaxusers; 302 1.1 thorpej } else if (n > maxmaxusers) { 303 1.27 christos cfgerror("warning: maxusers (%d) > %d", n, maxmaxusers); 304 1.1 thorpej errors--; 305 1.1 thorpej } 306 1.1 thorpej } 307 1.1 thorpej 308 1.1 thorpej void 309 1.1 thorpej setident(const char *i) 310 1.1 thorpej { 311 1.1 thorpej 312 1.43 mrg if (i) 313 1.43 mrg ident = intern(i); 314 1.43 mrg else 315 1.43 mrg ident = NULL; 316 1.1 thorpej } 317 1.1 thorpej 318 1.1 thorpej /* 319 1.1 thorpej * Define an attribute, optionally with an interface (a locator list) 320 1.1 thorpej * and a set of attribute-dependencies. 321 1.1 thorpej * 322 1.1 thorpej * Attribute dependencies MAY NOT be interface attributes. 323 1.1 thorpej * 324 1.1 thorpej * Since an empty locator list is logically different from "no interface", 325 1.1 thorpej * all locator lists include a dummy head node, which we discard here. 326 1.1 thorpej */ 327 1.1 thorpej int 328 1.49 uebayasi defattr0(const char *name, struct loclist *locs, struct attrlist *deps, 329 1.49 uebayasi int devclass) 330 1.49 uebayasi { 331 1.49 uebayasi 332 1.49 uebayasi if (locs != NULL) 333 1.49 uebayasi return defiattr(name, locs, deps, devclass); 334 1.49 uebayasi else if (devclass) 335 1.49 uebayasi return defdevclass(name, locs, deps, devclass); 336 1.49 uebayasi else 337 1.49 uebayasi return defattr(name, locs, deps, devclass); 338 1.49 uebayasi } 339 1.49 uebayasi 340 1.49 uebayasi int 341 1.41 dholland defattr(const char *name, struct loclist *locs, struct attrlist *deps, 342 1.1 thorpej int devclass) 343 1.1 thorpej { 344 1.1 thorpej struct attr *a, *dep; 345 1.39 dholland struct attrlist *al; 346 1.1 thorpej 347 1.77 christos if (getrefattr(name, &a)) { 348 1.84 christos cfgerror("attribute `%s' already defined at %s:%hu", name, 349 1.84 christos a->a_where.w_srcfile, a->a_where.w_srcline); 350 1.77 christos loclist_destroy(locs); 351 1.77 christos return (1); 352 1.77 christos } 353 1.77 christos if (a == NULL) 354 1.77 christos a = mkattr(name); 355 1.77 christos 356 1.1 thorpej /* 357 1.1 thorpej * If this attribute depends on any others, make sure none of 358 1.1 thorpej * the dependencies are interface attributes. 359 1.1 thorpej */ 360 1.39 dholland for (al = deps; al != NULL; al = al->al_next) { 361 1.39 dholland dep = al->al_this; 362 1.1 thorpej if (dep->a_iattr) { 363 1.27 christos cfgerror("`%s' dependency `%s' is an interface " 364 1.27 christos "attribute", name, dep->a_name); 365 1.1 thorpej return (1); 366 1.1 thorpej } 367 1.76 christos (void)ht_insert2(attrdeptab, name, dep->a_name, 368 1.76 christos addvalue(V_ATTRIBUTE, a, dep)); 369 1.60 uebayasi CFGDBG(2, "attr `%s' depends on attr `%s'", name, dep->a_name); 370 1.1 thorpej } 371 1.1 thorpej 372 1.1 thorpej 373 1.48 uebayasi a->a_deps = deps; 374 1.49 uebayasi expandattr(a, NULL); 375 1.50 uebayasi CFGDBG(3, "attr `%s' defined", a->a_name); 376 1.49 uebayasi 377 1.49 uebayasi return (0); 378 1.49 uebayasi } 379 1.49 uebayasi 380 1.50 uebayasi struct attr * 381 1.50 uebayasi mkattr(const char *name) 382 1.50 uebayasi { 383 1.50 uebayasi struct attr *a; 384 1.50 uebayasi 385 1.50 uebayasi a = ecalloc(1, sizeof *a); 386 1.50 uebayasi if (ht_insert(attrtab, name, a)) { 387 1.50 uebayasi free(a); 388 1.50 uebayasi return NULL; 389 1.50 uebayasi } 390 1.50 uebayasi a->a_name = name; 391 1.84 christos a->a_where.w_srcfile = yyfile; 392 1.84 christos a->a_where.w_srcline = currentline(); 393 1.50 uebayasi TAILQ_INIT(&a->a_files); 394 1.50 uebayasi CFGDBG(3, "attr `%s' allocated", name); 395 1.50 uebayasi 396 1.50 uebayasi return a; 397 1.50 uebayasi } 398 1.50 uebayasi 399 1.49 uebayasi /* "interface attribute" initialization */ 400 1.49 uebayasi int 401 1.49 uebayasi defiattr(const char *name, struct loclist *locs, struct attrlist *deps, 402 1.49 uebayasi int devclass) 403 1.49 uebayasi { 404 1.49 uebayasi struct attr *a; 405 1.49 uebayasi int len; 406 1.49 uebayasi struct loclist *ll; 407 1.49 uebayasi 408 1.49 uebayasi if (devclass) 409 1.81 christos panic("%s: %s has both locators and devclass", __func__, name); 410 1.49 uebayasi 411 1.49 uebayasi if (defattr(name, locs, deps, devclass) != 0) 412 1.49 uebayasi return (1); 413 1.49 uebayasi 414 1.49 uebayasi a = getattr(name); 415 1.49 uebayasi a->a_iattr = 1; 416 1.49 uebayasi /* unwrap */ 417 1.49 uebayasi a->a_locs = locs->ll_next; 418 1.49 uebayasi locs->ll_next = NULL; 419 1.49 uebayasi loclist_destroy(locs); 420 1.49 uebayasi len = 0; 421 1.49 uebayasi for (ll = a->a_locs; ll != NULL; ll = ll->ll_next) 422 1.49 uebayasi len++; 423 1.49 uebayasi a->a_loclen = len; 424 1.49 uebayasi if (deps) 425 1.49 uebayasi CFGDBG(2, "attr `%s' iface with deps", a->a_name); 426 1.49 uebayasi return (0); 427 1.49 uebayasi } 428 1.49 uebayasi 429 1.49 uebayasi /* "device class" initialization */ 430 1.49 uebayasi int 431 1.49 uebayasi defdevclass(const char *name, struct loclist *locs, struct attrlist *deps, 432 1.49 uebayasi int devclass) 433 1.49 uebayasi { 434 1.49 uebayasi struct attr *a; 435 1.49 uebayasi char classenum[256], *cp; 436 1.49 uebayasi int errored = 0; 437 1.48 uebayasi 438 1.49 uebayasi if (deps) 439 1.81 christos panic("%s: %s has both dependencies and devclass", __func__, 440 1.81 christos name); 441 1.49 uebayasi 442 1.49 uebayasi if (defattr(name, locs, deps, devclass) != 0) 443 1.49 uebayasi return (1); 444 1.49 uebayasi 445 1.49 uebayasi a = getattr(name); 446 1.49 uebayasi (void)snprintf(classenum, sizeof(classenum), "DV_%s", name); 447 1.49 uebayasi for (cp = classenum + 3; *cp; cp++) { 448 1.81 christos if (!errored && (!isalnum((unsigned char)*cp) || 449 1.81 christos (isalpha((unsigned char)*cp) 450 1.81 christos && !islower((unsigned char)*cp)))) { 451 1.49 uebayasi cfgerror("device class names must be " 452 1.49 uebayasi "lower-case alphanumeric characters"); 453 1.49 uebayasi errored = 1; 454 1.1 thorpej } 455 1.68 joerg *cp = (char)toupper((unsigned char)*cp); 456 1.48 uebayasi } 457 1.49 uebayasi a->a_devclass = intern(classenum); 458 1.1 thorpej 459 1.1 thorpej return (0); 460 1.1 thorpej } 461 1.1 thorpej 462 1.1 thorpej /* 463 1.1 thorpej * Return true if the given `error object' is embedded in the given 464 1.1 thorpej * pointer list. 465 1.1 thorpej */ 466 1.1 thorpej static int 467 1.39 dholland has_errobj(struct attrlist *al, struct attr *obj) 468 1.1 thorpej { 469 1.1 thorpej 470 1.39 dholland for (; al != NULL; al = al->al_next) 471 1.39 dholland if (al->al_this == obj) 472 1.1 thorpej return (1); 473 1.1 thorpej return (0); 474 1.1 thorpej } 475 1.1 thorpej 476 1.1 thorpej /* 477 1.1 thorpej * Return true if the given attribute is embedded in the given 478 1.1 thorpej * pointer list. 479 1.1 thorpej */ 480 1.1 thorpej int 481 1.39 dholland has_attr(struct attrlist *al, const char *attr) 482 1.1 thorpej { 483 1.1 thorpej struct attr *a; 484 1.1 thorpej 485 1.1 thorpej if ((a = getattr(attr)) == NULL) 486 1.1 thorpej return (0); 487 1.1 thorpej 488 1.39 dholland for (; al != NULL; al = al->al_next) 489 1.39 dholland if (al->al_this == a) 490 1.1 thorpej return (1); 491 1.1 thorpej return (0); 492 1.1 thorpej } 493 1.1 thorpej 494 1.1 thorpej /* 495 1.1 thorpej * Add a device base to a list in an attribute (actually, to any list). 496 1.1 thorpej * Note that this does not check for duplicates, and does reverse the 497 1.1 thorpej * list order, but no one cares anyway. 498 1.1 thorpej */ 499 1.1 thorpej static struct nvlist * 500 1.1 thorpej addtoattr(struct nvlist *l, struct devbase *dev) 501 1.1 thorpej { 502 1.1 thorpej struct nvlist *n; 503 1.1 thorpej 504 1.1 thorpej n = newnv(NULL, NULL, dev, 0, l); 505 1.1 thorpej return (n); 506 1.1 thorpej } 507 1.1 thorpej 508 1.1 thorpej /* 509 1.1 thorpej * Define a device. This may (or may not) also define an interface 510 1.1 thorpej * attribute and/or refer to existing attributes. 511 1.1 thorpej */ 512 1.1 thorpej void 513 1.41 dholland defdev(struct devbase *dev, struct loclist *loclist, struct attrlist *attrs, 514 1.1 thorpej int ispseudo) 515 1.1 thorpej { 516 1.41 dholland struct loclist *ll; 517 1.39 dholland struct attrlist *al; 518 1.1 thorpej 519 1.1 thorpej if (dev == &errdev) 520 1.1 thorpej goto bad; 521 1.1 thorpej if (dev->d_isdef) { 522 1.83 christos cfgerror("redefinition of `%s' (previously defined at %s:%d)", 523 1.84 christos dev->d_name, dev->d_where.w_srcfile, dev->d_where.w_srcline); 524 1.1 thorpej goto bad; 525 1.1 thorpej } 526 1.1 thorpej 527 1.1 thorpej dev->d_isdef = 1; 528 1.1 thorpej if (has_errobj(attrs, &errattr)) 529 1.1 thorpej goto bad; 530 1.1 thorpej 531 1.1 thorpej /* 532 1.1 thorpej * Handle implicit attribute definition from locator list. Do 533 1.1 thorpej * this before scanning the `at' list so that we can have, e.g.: 534 1.1 thorpej * device foo at other, foo { slot = -1 } 535 1.1 thorpej * (where you can plug in a foo-bus extender to a foo-bus). 536 1.1 thorpej */ 537 1.1 thorpej if (loclist != NULL) { 538 1.41 dholland ll = loclist; 539 1.1 thorpej loclist = NULL; /* defattr disposes of them for us */ 540 1.49 uebayasi if (defiattr(dev->d_name, ll, NULL, 0)) 541 1.1 thorpej goto bad; 542 1.39 dholland attrs = attrlist_cons(attrs, getattr(dev->d_name)); 543 1.39 dholland /* This used to be stored but was never used */ 544 1.39 dholland /* attrs->al_name = dev->d_name; */ 545 1.17 cube } 546 1.17 cube 547 1.17 cube /* 548 1.17 cube * Pseudo-devices can have children. Consider them as 549 1.17 cube * attaching at root. 550 1.17 cube */ 551 1.17 cube if (ispseudo) { 552 1.39 dholland for (al = attrs; al != NULL; al = al->al_next) 553 1.39 dholland if (al->al_this->a_iattr) 554 1.17 cube break; 555 1.39 dholland if (al != NULL) { 556 1.29 drochner if (ispseudo < 2) { 557 1.29 drochner if (version >= 20080610) 558 1.29 drochner cfgerror("interface attribute on " 559 1.29 drochner "non-device pseudo `%s'", dev->d_name); 560 1.29 drochner else { 561 1.29 drochner ispseudo = 2; 562 1.29 drochner } 563 1.29 drochner } 564 1.6 cube ht_insert(devroottab, dev->d_name, dev); 565 1.29 drochner } 566 1.1 thorpej } 567 1.1 thorpej 568 1.1 thorpej /* Committed! Set up fields. */ 569 1.1 thorpej dev->d_ispseudo = ispseudo; 570 1.1 thorpej dev->d_attrs = attrs; 571 1.1 thorpej dev->d_classattr = NULL; /* for now */ 572 1.56 uebayasi CFGDBG(3, "dev `%s' defined", dev->d_name); 573 1.1 thorpej 574 1.1 thorpej /* 575 1.53 uebayasi * Implicit attribute definition for device. 576 1.53 uebayasi */ 577 1.62 martin refattr(dev->d_name); 578 1.53 uebayasi 579 1.53 uebayasi /* 580 1.1 thorpej * For each interface attribute this device refers to, add this 581 1.1 thorpej * device to its reference list. This makes, e.g., finding all 582 1.1 thorpej * "scsi"s easier. 583 1.1 thorpej * 584 1.1 thorpej * While looking through the attributes, set up the device 585 1.1 thorpej * class if any are devclass attributes (and error out if the 586 1.1 thorpej * device has two classes). 587 1.1 thorpej */ 588 1.39 dholland for (al = attrs; al != NULL; al = al->al_next) { 589 1.56 uebayasi /* 590 1.56 uebayasi * Implicit attribute definition for device dependencies. 591 1.56 uebayasi */ 592 1.60 uebayasi refattr(al->al_this->a_name); 593 1.76 christos (void)ht_insert2(attrdeptab, dev->d_name, al->al_this->a_name, 594 1.76 christos addvalue(V_DEVICE, al->al_this, dev)); 595 1.60 uebayasi CFGDBG(2, "device `%s' depends on attr `%s'", dev->d_name, 596 1.60 uebayasi al->al_this->a_name); 597 1.1 thorpej } 598 1.1 thorpej return; 599 1.1 thorpej bad: 600 1.41 dholland loclist_destroy(loclist); 601 1.39 dholland attrlist_destroyall(attrs); 602 1.1 thorpej } 603 1.1 thorpej 604 1.1 thorpej /* 605 1.1 thorpej * Look up a devbase. Also makes sure it is a reasonable name, 606 1.1 thorpej * i.e., does not end in a digit or contain special characters. 607 1.1 thorpej */ 608 1.1 thorpej struct devbase * 609 1.1 thorpej getdevbase(const char *name) 610 1.1 thorpej { 611 1.27 christos const u_char *p; 612 1.1 thorpej struct devbase *dev; 613 1.1 thorpej 614 1.27 christos p = (const u_char *)name; 615 1.1 thorpej if (!isalpha(*p)) 616 1.1 thorpej goto badname; 617 1.1 thorpej while (*++p) { 618 1.1 thorpej if (!isalnum(*p) && *p != '_') 619 1.1 thorpej goto badname; 620 1.1 thorpej } 621 1.1 thorpej if (isdigit(*--p)) { 622 1.1 thorpej badname: 623 1.27 christos cfgerror("bad device base name `%s'", name); 624 1.1 thorpej return (&errdev); 625 1.1 thorpej } 626 1.1 thorpej dev = ht_lookup(devbasetab, name); 627 1.1 thorpej if (dev == NULL) { 628 1.1 thorpej dev = ecalloc(1, sizeof *dev); 629 1.1 thorpej dev->d_name = name; 630 1.1 thorpej dev->d_isdef = 0; 631 1.32 drochner dev->d_major = NODEVMAJOR; 632 1.1 thorpej dev->d_attrs = NULL; 633 1.1 thorpej dev->d_ihead = NULL; 634 1.1 thorpej dev->d_ipp = &dev->d_ihead; 635 1.1 thorpej dev->d_ahead = NULL; 636 1.1 thorpej dev->d_app = &dev->d_ahead; 637 1.1 thorpej dev->d_umax = 0; 638 1.84 christos dev->d_where.w_srcfile = yyfile; 639 1.84 christos dev->d_where.w_srcline = currentline(); 640 1.1 thorpej TAILQ_INSERT_TAIL(&allbases, dev, d_next); 641 1.1 thorpej if (ht_insert(devbasetab, name, dev)) 642 1.81 christos panic("%s: Can't insert %s", __func__, name); 643 1.56 uebayasi CFGDBG(3, "devbase defined `%s'", dev->d_name); 644 1.1 thorpej } 645 1.1 thorpej return (dev); 646 1.1 thorpej } 647 1.1 thorpej 648 1.1 thorpej /* 649 1.1 thorpej * Define some of a device's allowable parent attachments. 650 1.1 thorpej * There may be a list of (plain) attributes. 651 1.1 thorpej */ 652 1.1 thorpej void 653 1.1 thorpej defdevattach(struct deva *deva, struct devbase *dev, struct nvlist *atlist, 654 1.39 dholland struct attrlist *attrs) 655 1.1 thorpej { 656 1.1 thorpej struct nvlist *nv; 657 1.39 dholland struct attrlist *al; 658 1.1 thorpej struct attr *a; 659 1.1 thorpej 660 1.1 thorpej if (dev == &errdev) 661 1.1 thorpej goto bad; 662 1.1 thorpej if (deva == NULL) 663 1.1 thorpej deva = getdevattach(dev->d_name); 664 1.1 thorpej if (deva == &errdeva) 665 1.1 thorpej goto bad; 666 1.1 thorpej if (!dev->d_isdef) { 667 1.27 christos cfgerror("attaching undefined device `%s'", dev->d_name); 668 1.1 thorpej goto bad; 669 1.1 thorpej } 670 1.1 thorpej if (deva->d_isdef) { 671 1.83 christos cfgerror("redefinition of `%s' (previously defined at %s:%d)", 672 1.84 christos deva->d_name, deva->d_where.w_srcfile, deva->d_where.w_srcline); 673 1.1 thorpej goto bad; 674 1.1 thorpej } 675 1.1 thorpej if (dev->d_ispseudo) { 676 1.27 christos cfgerror("pseudo-devices can't attach"); 677 1.1 thorpej goto bad; 678 1.1 thorpej } 679 1.1 thorpej 680 1.1 thorpej deva->d_isdef = 1; 681 1.1 thorpej if (has_errobj(attrs, &errattr)) 682 1.1 thorpej goto bad; 683 1.39 dholland for (al = attrs; al != NULL; al = al->al_next) { 684 1.39 dholland a = al->al_this; 685 1.1 thorpej if (a == &errattr) 686 1.1 thorpej continue; /* already complained */ 687 1.1 thorpej if (a->a_iattr || a->a_devclass != NULL) 688 1.27 christos cfgerror("`%s' is not a plain attribute", a->a_name); 689 1.1 thorpej } 690 1.1 thorpej 691 1.1 thorpej /* Committed! Set up fields. */ 692 1.1 thorpej deva->d_attrs = attrs; 693 1.1 thorpej deva->d_atlist = atlist; 694 1.1 thorpej deva->d_devbase = dev; 695 1.50 uebayasi CFGDBG(3, "deva `%s' defined", deva->d_name); 696 1.50 uebayasi 697 1.50 uebayasi /* 698 1.51 uebayasi * Implicit attribute definition for device attachment. 699 1.50 uebayasi */ 700 1.50 uebayasi refattr(deva->d_name); 701 1.1 thorpej 702 1.1 thorpej /* 703 1.1 thorpej * Turn the `at' list into interface attributes (map each 704 1.1 thorpej * nv_name to an attribute, or to NULL for root), and add 705 1.1 thorpej * this device to those attributes, so that children can 706 1.1 thorpej * be listed at this particular device if they are supported 707 1.1 thorpej * by that attribute. 708 1.1 thorpej */ 709 1.1 thorpej for (nv = atlist; nv != NULL; nv = nv->nv_next) { 710 1.1 thorpej if (nv->nv_name == NULL) 711 1.1 thorpej nv->nv_ptr = a = NULL; /* at root */ 712 1.1 thorpej else 713 1.1 thorpej nv->nv_ptr = a = getattr(nv->nv_name); 714 1.1 thorpej if (a == &errattr) 715 1.1 thorpej continue; /* already complained */ 716 1.1 thorpej 717 1.79 christos #if 0 718 1.1 thorpej /* 719 1.1 thorpej * Make sure that an attachment spec doesn't 720 1.1 thorpej * already say how to attach to this attribute. 721 1.1 thorpej */ 722 1.79 christos for (struct deva *da = dev->d_ahead; da; da = da->d_bsame) 723 1.1 thorpej if (onlist(da->d_atlist, a)) 724 1.27 christos cfgerror("attach at `%s' already done by `%s'", 725 1.1 thorpej a ? a->a_name : "root", da->d_name); 726 1.79 christos #endif 727 1.1 thorpej 728 1.6 cube if (a == NULL) { 729 1.6 cube ht_insert(devroottab, dev->d_name, dev); 730 1.1 thorpej continue; /* at root; don't add */ 731 1.6 cube } 732 1.1 thorpej if (!a->a_iattr) 733 1.27 christos cfgerror("%s cannot be at plain attribute `%s'", 734 1.1 thorpej dev->d_name, a->a_name); 735 1.1 thorpej else 736 1.1 thorpej a->a_devs = addtoattr(a->a_devs, dev); 737 1.1 thorpej } 738 1.1 thorpej 739 1.1 thorpej /* attach to parent */ 740 1.1 thorpej *dev->d_app = deva; 741 1.1 thorpej dev->d_app = &deva->d_bsame; 742 1.1 thorpej return; 743 1.1 thorpej bad: 744 1.1 thorpej nvfreel(atlist); 745 1.39 dholland attrlist_destroyall(attrs); 746 1.1 thorpej } 747 1.1 thorpej 748 1.1 thorpej /* 749 1.1 thorpej * Look up a device attachment. Also makes sure it is a reasonable 750 1.1 thorpej * name, i.e., does not contain digits or special characters. 751 1.1 thorpej */ 752 1.1 thorpej struct deva * 753 1.1 thorpej getdevattach(const char *name) 754 1.1 thorpej { 755 1.27 christos const u_char *p; 756 1.1 thorpej struct deva *deva; 757 1.1 thorpej 758 1.27 christos p = (const u_char *)name; 759 1.1 thorpej if (!isalpha(*p)) 760 1.1 thorpej goto badname; 761 1.1 thorpej while (*++p) { 762 1.1 thorpej if (!isalnum(*p) && *p != '_') 763 1.1 thorpej goto badname; 764 1.1 thorpej } 765 1.1 thorpej if (isdigit(*--p)) { 766 1.1 thorpej badname: 767 1.27 christos cfgerror("bad device attachment name `%s'", name); 768 1.1 thorpej return (&errdeva); 769 1.1 thorpej } 770 1.1 thorpej deva = ht_lookup(devatab, name); 771 1.1 thorpej if (deva == NULL) { 772 1.1 thorpej deva = ecalloc(1, sizeof *deva); 773 1.1 thorpej deva->d_name = name; 774 1.1 thorpej deva->d_bsame = NULL; 775 1.1 thorpej deva->d_isdef = 0; 776 1.1 thorpej deva->d_devbase = NULL; 777 1.1 thorpej deva->d_atlist = NULL; 778 1.1 thorpej deva->d_attrs = NULL; 779 1.1 thorpej deva->d_ihead = NULL; 780 1.1 thorpej deva->d_ipp = &deva->d_ihead; 781 1.84 christos deva->d_where.w_srcfile = yyfile; 782 1.84 christos deva->d_where.w_srcline = currentline(); 783 1.1 thorpej TAILQ_INSERT_TAIL(&alldevas, deva, d_next); 784 1.1 thorpej if (ht_insert(devatab, name, deva)) 785 1.81 christos panic("%s: Can't insert %s", __func__, name); 786 1.1 thorpej } 787 1.1 thorpej return (deva); 788 1.1 thorpej } 789 1.1 thorpej 790 1.1 thorpej /* 791 1.1 thorpej * Look up an attribute. 792 1.1 thorpej */ 793 1.1 thorpej struct attr * 794 1.1 thorpej getattr(const char *name) 795 1.1 thorpej { 796 1.1 thorpej struct attr *a; 797 1.1 thorpej 798 1.1 thorpej if ((a = ht_lookup(attrtab, name)) == NULL) { 799 1.27 christos cfgerror("undefined attribute `%s'", name); 800 1.1 thorpej a = &errattr; 801 1.1 thorpej } 802 1.1 thorpej return (a); 803 1.1 thorpej } 804 1.1 thorpej 805 1.1 thorpej /* 806 1.50 uebayasi * Implicit attribute definition. 807 1.50 uebayasi */ 808 1.55 uebayasi struct attr * 809 1.50 uebayasi refattr(const char *name) 810 1.50 uebayasi { 811 1.55 uebayasi struct attr *a; 812 1.50 uebayasi 813 1.55 uebayasi if ((a = ht_lookup(attrtab, name)) == NULL) 814 1.55 uebayasi a = mkattr(name); 815 1.55 uebayasi return a; 816 1.50 uebayasi } 817 1.50 uebayasi 818 1.52 uebayasi int 819 1.52 uebayasi getrefattr(const char *name, struct attr **ra) 820 1.52 uebayasi { 821 1.52 uebayasi struct attr *a; 822 1.52 uebayasi 823 1.52 uebayasi a = ht_lookup(attrtab, name); 824 1.52 uebayasi if (a == NULL) { 825 1.52 uebayasi *ra = NULL; 826 1.52 uebayasi return (0); 827 1.52 uebayasi } 828 1.52 uebayasi /* 829 1.52 uebayasi * Check if the existing attr is only referenced, not really defined. 830 1.52 uebayasi */ 831 1.85 mrg *ra = a; 832 1.52 uebayasi if (a->a_deps == NULL && 833 1.52 uebayasi a->a_iattr == 0 && 834 1.52 uebayasi a->a_devclass == 0) { 835 1.52 uebayasi return (0); 836 1.52 uebayasi } 837 1.52 uebayasi return (1); 838 1.52 uebayasi } 839 1.52 uebayasi 840 1.50 uebayasi /* 841 1.1 thorpej * Recursively expand an attribute and its dependencies, checking for 842 1.1 thorpej * cycles, and invoking a callback for each attribute found. 843 1.1 thorpej */ 844 1.1 thorpej void 845 1.1 thorpej expandattr(struct attr *a, void (*callback)(struct attr *)) 846 1.1 thorpej { 847 1.39 dholland struct attrlist *al; 848 1.1 thorpej struct attr *dep; 849 1.1 thorpej 850 1.1 thorpej if (a->a_expanding) { 851 1.27 christos cfgerror("circular dependency on attribute `%s'", a->a_name); 852 1.1 thorpej return; 853 1.1 thorpej } 854 1.1 thorpej 855 1.1 thorpej a->a_expanding = 1; 856 1.1 thorpej 857 1.1 thorpej /* First expand all of this attribute's dependencies. */ 858 1.39 dholland for (al = a->a_deps; al != NULL; al = al->al_next) { 859 1.39 dholland dep = al->al_this; 860 1.1 thorpej expandattr(dep, callback); 861 1.1 thorpej } 862 1.1 thorpej 863 1.1 thorpej /* ...and now invoke the callback for ourself. */ 864 1.1 thorpej if (callback != NULL) 865 1.1 thorpej (*callback)(a); 866 1.1 thorpej 867 1.1 thorpej a->a_expanding = 0; 868 1.1 thorpej } 869 1.1 thorpej 870 1.1 thorpej /* 871 1.1 thorpej * Set the major device number for a device, so that it can be used 872 1.1 thorpej * as a root/dumps "on" device in a configuration. 873 1.1 thorpej */ 874 1.1 thorpej void 875 1.32 drochner setmajor(struct devbase *d, devmajor_t n) 876 1.1 thorpej { 877 1.1 thorpej 878 1.32 drochner if (d != &errdev && d->d_major != NODEVMAJOR) 879 1.32 drochner cfgerror("device `%s' is already major %d", 880 1.32 drochner d->d_name, d->d_major); 881 1.1 thorpej else 882 1.1 thorpej d->d_major = n; 883 1.1 thorpej } 884 1.1 thorpej 885 1.1 thorpej const char * 886 1.32 drochner major2name(devmajor_t maj) 887 1.1 thorpej { 888 1.1 thorpej struct devbase *dev; 889 1.1 thorpej struct devm *dm; 890 1.1 thorpej 891 1.1 thorpej if (!do_devsw) { 892 1.1 thorpej TAILQ_FOREACH(dev, &allbases, d_next) { 893 1.1 thorpej if (dev->d_major == maj) 894 1.1 thorpej return (dev->d_name); 895 1.1 thorpej } 896 1.1 thorpej } else { 897 1.1 thorpej TAILQ_FOREACH(dm, &alldevms, dm_next) { 898 1.1 thorpej if (dm->dm_bmajor == maj) 899 1.1 thorpej return (dm->dm_name); 900 1.1 thorpej } 901 1.1 thorpej } 902 1.1 thorpej return (NULL); 903 1.1 thorpej } 904 1.1 thorpej 905 1.32 drochner devmajor_t 906 1.1 thorpej dev2major(struct devbase *dev) 907 1.1 thorpej { 908 1.1 thorpej struct devm *dm; 909 1.1 thorpej 910 1.1 thorpej if (!do_devsw) 911 1.1 thorpej return (dev->d_major); 912 1.1 thorpej 913 1.1 thorpej TAILQ_FOREACH(dm, &alldevms, dm_next) { 914 1.1 thorpej if (strcmp(dm->dm_name, dev->d_name) == 0) 915 1.1 thorpej return (dm->dm_bmajor); 916 1.1 thorpej } 917 1.32 drochner return (NODEVMAJOR); 918 1.1 thorpej } 919 1.1 thorpej 920 1.1 thorpej /* 921 1.1 thorpej * Make a string description of the device at maj/min. 922 1.1 thorpej */ 923 1.1 thorpej static const char * 924 1.32 drochner makedevstr(devmajor_t maj, devminor_t min) 925 1.1 thorpej { 926 1.27 christos const char *devicename; 927 1.1 thorpej char buf[32]; 928 1.1 thorpej 929 1.27 christos devicename = major2name(maj); 930 1.27 christos if (devicename == NULL) 931 1.32 drochner (void)snprintf(buf, sizeof(buf), "<%d/%d>", maj, min); 932 1.1 thorpej else 933 1.32 drochner (void)snprintf(buf, sizeof(buf), "%s%d%c", devicename, 934 1.32 drochner min / maxpartitions, (min % maxpartitions) + 'a'); 935 1.1 thorpej 936 1.1 thorpej return (intern(buf)); 937 1.1 thorpej } 938 1.1 thorpej 939 1.1 thorpej /* 940 1.1 thorpej * Map things like "ra0b" => makedev(major("ra"), 0*maxpartitions + 'b'-'a'). 941 1.1 thorpej * Handle the case where the device number is given but there is no 942 1.1 thorpej * corresponding name, and map NULL to the default. 943 1.1 thorpej */ 944 1.1 thorpej static int 945 1.1 thorpej resolve(struct nvlist **nvp, const char *name, const char *what, 946 1.1 thorpej struct nvlist *dflt, int part) 947 1.1 thorpej { 948 1.1 thorpej struct nvlist *nv; 949 1.1 thorpej struct devbase *dev; 950 1.1 thorpej const char *cp; 951 1.32 drochner devmajor_t maj; 952 1.32 drochner devminor_t min; 953 1.86 rillig size_t l; 954 1.1 thorpej int unit; 955 1.1 thorpej char buf[NAMESIZE]; 956 1.1 thorpej 957 1.33 lukem if ((part -= 'a') >= maxpartitions || part < 0) 958 1.81 christos panic("%s: Bad partition %c", __func__, part); 959 1.1 thorpej if ((nv = *nvp) == NULL) { 960 1.1 thorpej dev_t d = NODEV; 961 1.1 thorpej /* 962 1.1 thorpej * Apply default. Easiest to do this by number. 963 1.1 thorpej * Make sure to retain NODEVness, if this is dflt's disposition. 964 1.1 thorpej */ 965 1.33 lukem if ((dev_t)dflt->nv_num != NODEV) { 966 1.31 christos maj = major(dflt->nv_num); 967 1.31 christos min = ((minor(dflt->nv_num) / maxpartitions) * 968 1.1 thorpej maxpartitions) + part; 969 1.1 thorpej d = makedev(maj, min); 970 1.1 thorpej cp = makedevstr(maj, min); 971 1.1 thorpej } else 972 1.1 thorpej cp = NULL; 973 1.65 christos *nvp = nv = newnv(NULL, cp, NULL, (long long)d, NULL); 974 1.1 thorpej } 975 1.33 lukem if ((dev_t)nv->nv_num != NODEV) { 976 1.1 thorpej /* 977 1.1 thorpej * By the numbers. Find the appropriate major number 978 1.1 thorpej * to make a name. 979 1.1 thorpej */ 980 1.31 christos maj = major(nv->nv_num); 981 1.31 christos min = minor(nv->nv_num); 982 1.1 thorpej nv->nv_str = makedevstr(maj, min); 983 1.1 thorpej return (0); 984 1.1 thorpej } 985 1.1 thorpej 986 1.1 thorpej if (nv->nv_str == NULL || nv->nv_str == s_qmark) 987 1.1 thorpej /* 988 1.1 thorpej * Wildcarded or unspecified; leave it as NODEV. 989 1.1 thorpej */ 990 1.1 thorpej return (0); 991 1.1 thorpej 992 1.74 mlelstv if (nv->nv_ptr != NULL && strcmp(nv->nv_ptr, "spec") == 0) 993 1.74 mlelstv /* 994 1.74 mlelstv * spec string, interpreted by kernel 995 1.74 mlelstv */ 996 1.74 mlelstv return (0); 997 1.74 mlelstv 998 1.1 thorpej /* 999 1.1 thorpej * The normal case: things like "ra2b". Check for partition 1000 1.1 thorpej * suffix, remove it if there, and split into name ("ra") and 1001 1.1 thorpej * unit (2). 1002 1.1 thorpej */ 1003 1.86 rillig l = strlen(nv->nv_str); 1004 1.1 thorpej cp = &nv->nv_str[l]; 1005 1.1 thorpej if (l > 1 && *--cp >= 'a' && *cp < 'a' + maxpartitions && 1006 1.1 thorpej isdigit((unsigned char)cp[-1])) { 1007 1.1 thorpej l--; 1008 1.1 thorpej part = *cp - 'a'; 1009 1.1 thorpej } 1010 1.1 thorpej cp = nv->nv_str; 1011 1.1 thorpej if (split(cp, l, buf, sizeof buf, &unit)) { 1012 1.27 christos cfgerror("%s: invalid %s device name `%s'", name, what, cp); 1013 1.1 thorpej return (1); 1014 1.1 thorpej } 1015 1.1 thorpej dev = ht_lookup(devbasetab, intern(buf)); 1016 1.1 thorpej if (dev == NULL) { 1017 1.27 christos cfgerror("%s: device `%s' does not exist", name, buf); 1018 1.1 thorpej return (1); 1019 1.1 thorpej } 1020 1.1 thorpej 1021 1.1 thorpej /* 1022 1.1 thorpej * Check for the magic network interface attribute, and 1023 1.1 thorpej * don't bother making a device number. 1024 1.1 thorpej */ 1025 1.1 thorpej if (has_attr(dev->d_attrs, s_ifnet)) { 1026 1.65 christos nv->nv_num = (long long)NODEV; 1027 1.1 thorpej nv->nv_ifunit = unit; /* XXX XXX XXX */ 1028 1.1 thorpej } else { 1029 1.1 thorpej maj = dev2major(dev); 1030 1.33 lukem if (maj == NODEVMAJOR) { 1031 1.27 christos cfgerror("%s: can't make %s device from `%s'", 1032 1.1 thorpej name, what, nv->nv_str); 1033 1.1 thorpej return (1); 1034 1.1 thorpej } 1035 1.69 joerg nv->nv_num = (long long)makedev(maj, unit * maxpartitions + part); 1036 1.1 thorpej } 1037 1.1 thorpej 1038 1.1 thorpej nv->nv_name = dev->d_name; 1039 1.1 thorpej return (0); 1040 1.1 thorpej } 1041 1.1 thorpej 1042 1.1 thorpej /* 1043 1.1 thorpej * Add a completed configuration to the list. 1044 1.1 thorpej */ 1045 1.1 thorpej void 1046 1.1 thorpej addconf(struct config *cf0) 1047 1.1 thorpej { 1048 1.1 thorpej struct config *cf; 1049 1.1 thorpej const char *name; 1050 1.1 thorpej 1051 1.1 thorpej name = cf0->cf_name; 1052 1.84 christos if ((cf = ht_lookup(cfhashtab, name)) != NULL) { 1053 1.84 christos cfgerror("configuration `%s' already defined %s:%hu", name, 1054 1.84 christos cf->cf_where.w_srcfile, cf->cf_where.w_srcline); 1055 1.84 christos goto bad; 1056 1.84 christos } 1057 1.1 thorpej cf = ecalloc(1, sizeof *cf); 1058 1.1 thorpej if (ht_insert(cfhashtab, name, cf)) { 1059 1.1 thorpej free(cf); 1060 1.1 thorpej } 1061 1.1 thorpej *cf = *cf0; 1062 1.84 christos cf->cf_where.w_srcfile = yyfile; 1063 1.84 christos cf->cf_where.w_srcline = currentline(); 1064 1.1 thorpej 1065 1.1 thorpej /* 1066 1.1 thorpej * Resolve the root device. 1067 1.1 thorpej */ 1068 1.15 erh if (cf->cf_root == NULL) { 1069 1.27 christos cfgerror("%s: no root device specified", name); 1070 1.15 erh goto bad; 1071 1.15 erh } 1072 1.15 erh if (cf->cf_root && cf->cf_root->nv_str != s_qmark) { 1073 1.15 erh struct nvlist *nv; 1074 1.1 thorpej nv = cf->cf_root; 1075 1.1 thorpej if (resolve(&cf->cf_root, name, "root", nv, 'a')) 1076 1.1 thorpej goto bad; 1077 1.1 thorpej } 1078 1.1 thorpej 1079 1.1 thorpej /* 1080 1.1 thorpej * Resolve the dump device. 1081 1.1 thorpej */ 1082 1.1 thorpej if (cf->cf_dump == NULL || cf->cf_dump->nv_str == s_qmark) { 1083 1.1 thorpej /* 1084 1.1 thorpej * Wildcarded dump device is equivalent to unspecified. 1085 1.1 thorpej */ 1086 1.1 thorpej cf->cf_dump = NULL; 1087 1.1 thorpej } else if (cf->cf_dump->nv_str == s_none) { 1088 1.1 thorpej /* 1089 1.1 thorpej * Operator has requested that no dump device should be 1090 1.1 thorpej * configured; do nothing. 1091 1.1 thorpej */ 1092 1.1 thorpej } else { 1093 1.1 thorpej if (resolve(&cf->cf_dump, name, "dumps", cf->cf_dump, 'b')) 1094 1.1 thorpej goto bad; 1095 1.1 thorpej } 1096 1.1 thorpej 1097 1.1 thorpej /* Wildcarded fstype is `unspecified'. */ 1098 1.1 thorpej if (cf->cf_fstype == s_qmark) 1099 1.1 thorpej cf->cf_fstype = NULL; 1100 1.1 thorpej 1101 1.1 thorpej TAILQ_INSERT_TAIL(&allcf, cf, cf_next); 1102 1.1 thorpej return; 1103 1.1 thorpej bad: 1104 1.1 thorpej nvfreel(cf0->cf_root); 1105 1.1 thorpej nvfreel(cf0->cf_dump); 1106 1.1 thorpej } 1107 1.1 thorpej 1108 1.1 thorpej void 1109 1.1 thorpej setconf(struct nvlist **npp, const char *what, struct nvlist *v) 1110 1.1 thorpej { 1111 1.1 thorpej 1112 1.1 thorpej if (*npp != NULL) { 1113 1.27 christos cfgerror("duplicate %s specification", what); 1114 1.1 thorpej nvfreel(v); 1115 1.1 thorpej } else 1116 1.1 thorpej *npp = v; 1117 1.1 thorpej } 1118 1.1 thorpej 1119 1.1 thorpej void 1120 1.75 christos delconf(const char *name, int nowarn) 1121 1.18 cube { 1122 1.18 cube struct config *cf; 1123 1.18 cube 1124 1.61 uebayasi CFGDBG(5, "deselecting config `%s'", name); 1125 1.18 cube if (ht_lookup(cfhashtab, name) == NULL) { 1126 1.75 christos if (!nowarn) 1127 1.75 christos cfgerror("configuration `%s' undefined", name); 1128 1.18 cube return; 1129 1.18 cube } 1130 1.18 cube (void)ht_remove(cfhashtab, name); 1131 1.18 cube 1132 1.18 cube TAILQ_FOREACH(cf, &allcf, cf_next) 1133 1.18 cube if (!strcmp(cf->cf_name, name)) 1134 1.18 cube break; 1135 1.18 cube if (cf == NULL) 1136 1.81 christos panic("%s: lost configuration for %s", __func__, name); 1137 1.18 cube 1138 1.18 cube TAILQ_REMOVE(&allcf, cf, cf_next); 1139 1.18 cube } 1140 1.18 cube 1141 1.18 cube void 1142 1.1 thorpej setfstype(const char **fstp, const char *v) 1143 1.1 thorpej { 1144 1.1 thorpej 1145 1.1 thorpej if (*fstp != NULL) { 1146 1.27 christos cfgerror("multiple fstype specifications"); 1147 1.1 thorpej return; 1148 1.1 thorpej } 1149 1.1 thorpej 1150 1.1 thorpej if (v != s_qmark && OPT_FSOPT(v)) { 1151 1.27 christos cfgerror("\"%s\" is not a configured file system", v); 1152 1.1 thorpej return; 1153 1.1 thorpej } 1154 1.1 thorpej 1155 1.1 thorpej *fstp = v; 1156 1.1 thorpej } 1157 1.1 thorpej 1158 1.1 thorpej static struct devi * 1159 1.1 thorpej newdevi(const char *name, int unit, struct devbase *d) 1160 1.1 thorpej { 1161 1.1 thorpej struct devi *i; 1162 1.1 thorpej 1163 1.1 thorpej i = ecalloc(1, sizeof *i); 1164 1.1 thorpej i->i_name = name; 1165 1.1 thorpej i->i_unit = unit; 1166 1.1 thorpej i->i_base = d; 1167 1.1 thorpej i->i_bsame = NULL; 1168 1.1 thorpej i->i_asame = NULL; 1169 1.1 thorpej i->i_alias = NULL; 1170 1.1 thorpej i->i_at = NULL; 1171 1.1 thorpej i->i_pspec = NULL; 1172 1.1 thorpej i->i_atdeva = NULL; 1173 1.1 thorpej i->i_locs = NULL; 1174 1.1 thorpej i->i_cfflags = 0; 1175 1.84 christos i->i_where.w_srcline = currentline(); 1176 1.84 christos i->i_where.w_srcfile = yyfile; 1177 1.8 cube i->i_active = DEVI_ORPHAN; /* Proper analysis comes later */ 1178 1.13 cube i->i_level = devilevel; 1179 1.34 pooka i->i_pseudoroot = 0; 1180 1.84 christos i->i_where.w_srcfile = yyfile; 1181 1.84 christos i->i_where.w_srcline = currentline(); 1182 1.1 thorpej if (unit >= d->d_umax) 1183 1.1 thorpej d->d_umax = unit + 1; 1184 1.1 thorpej return (i); 1185 1.1 thorpej } 1186 1.1 thorpej 1187 1.79 christos static struct attr * 1188 1.79 christos finddevattr(const char *name, const char *at, struct devbase *ib, 1189 1.79 christos struct devbase **ab, int *atunit) 1190 1.79 christos { 1191 1.79 christos const char *cp; 1192 1.79 christos char atbuf[NAMESIZE]; 1193 1.79 christos struct attrlist *al; 1194 1.79 christos struct attr *attr; 1195 1.79 christos 1196 1.79 christos if (at == NULL) { 1197 1.79 christos *ab = NULL; 1198 1.79 christos *atunit = -1; 1199 1.79 christos return &errattr; /* a convenient "empty" attr */ 1200 1.79 christos } 1201 1.79 christos if (split(at, strlen(at), atbuf, sizeof atbuf, atunit)) { 1202 1.79 christos cfgerror("invalid attachment name `%s'", at); 1203 1.79 christos /* (void)getdevi(name); -- ??? */ 1204 1.79 christos return NULL; 1205 1.79 christos } 1206 1.79 christos 1207 1.79 christos /* 1208 1.79 christos * Devices can attach to two types of things: Attributes, 1209 1.79 christos * and other devices (which have the appropriate attributes 1210 1.79 christos * to allow attachment). 1211 1.79 christos * 1212 1.79 christos * (1) If we're attached to an attribute, then we don't need 1213 1.79 christos * look at the parent base device to see what attributes 1214 1.87 joe * it has, and make sure that we can attach to them. 1215 1.79 christos * 1216 1.79 christos * (2) If we're attached to a real device (i.e. named in 1217 1.79 christos * the config file), we want to remember that so that 1218 1.79 christos * at cross-check time, if the device we're attached to 1219 1.79 christos * is missing but other devices which also provide the 1220 1.79 christos * attribute are present, we don't get a false "OK." 1221 1.79 christos * 1222 1.79 christos * (3) If the thing we're attached to is an attribute 1223 1.79 christos * but is actually named in the config file, we still 1224 1.79 christos * have to remember its devbase. 1225 1.79 christos */ 1226 1.79 christos cp = intern(atbuf); 1227 1.79 christos 1228 1.79 christos /* Figure out parent's devbase, to satisfy case (3). */ 1229 1.79 christos *ab = ht_lookup(devbasetab, cp); 1230 1.79 christos 1231 1.79 christos /* Find out if it's an attribute. */ 1232 1.79 christos attr = ht_lookup(attrtab, cp); 1233 1.79 christos 1234 1.79 christos /* Make sure we're _really_ attached to the attr. Case (1). */ 1235 1.79 christos if (attr != NULL && onlist(attr->a_devs, ib)) 1236 1.79 christos return attr; 1237 1.79 christos 1238 1.79 christos /* 1239 1.79 christos * Else a real device, and not just an attribute. Case (2). 1240 1.79 christos * 1241 1.79 christos * Have to work a bit harder to see whether we have 1242 1.79 christos * something like "tg0 at esp0" (where esp is merely 1243 1.79 christos * not an attribute) or "tg0 at nonesuch0" (where 1244 1.79 christos * nonesuch is not even a device). 1245 1.79 christos */ 1246 1.79 christos if (*ab == NULL) { 1247 1.79 christos cfgerror("%s at %s: `%s' unknown", name, at, atbuf); 1248 1.79 christos return NULL; 1249 1.79 christos } 1250 1.79 christos 1251 1.79 christos /* 1252 1.79 christos * See if the named parent carries an attribute 1253 1.79 christos * that allows it to supervise device ib. 1254 1.79 christos */ 1255 1.79 christos for (al = (*ab)->d_attrs; al != NULL; al = al->al_next) { 1256 1.79 christos attr = al->al_this; 1257 1.79 christos if (onlist(attr->a_devs, ib)) 1258 1.79 christos return attr; 1259 1.79 christos } 1260 1.79 christos cfgerror("`%s' cannot attach to `%s'", ib->d_name, atbuf); 1261 1.79 christos return NULL; 1262 1.79 christos } 1263 1.79 christos 1264 1.1 thorpej /* 1265 1.1 thorpej * Add the named device as attaching to the named attribute (or perhaps 1266 1.1 thorpej * another device instead) plus unit number. 1267 1.1 thorpej */ 1268 1.1 thorpej void 1269 1.41 dholland adddev(const char *name, const char *at, struct loclist *loclist, int flags) 1270 1.1 thorpej { 1271 1.1 thorpej struct devi *i; /* the new instance */ 1272 1.1 thorpej struct pspec *p; /* and its pspec */ 1273 1.1 thorpej struct attr *attr; /* attribute that allows attach */ 1274 1.1 thorpej struct devbase *ib; /* i->i_base */ 1275 1.1 thorpej struct devbase *ab; /* not NULL => at another dev */ 1276 1.1 thorpej struct deva *iba; /* devbase attachment used */ 1277 1.79 christos struct deva *lastiba; 1278 1.81 christos int atunit, first; 1279 1.1 thorpej 1280 1.79 christos lastiba = NULL; 1281 1.79 christos if ((i = getdevi(name)) == NULL) 1282 1.79 christos goto bad; 1283 1.79 christos ib = i->i_base; 1284 1.79 christos attr = finddevattr(name, at, ib, &ab, &atunit); 1285 1.79 christos if (attr == NULL) { 1286 1.79 christos i->i_active = DEVI_BROKEN; 1287 1.79 christos goto bad; 1288 1.79 christos } 1289 1.79 christos 1290 1.79 christos for (lastiba = ib->d_ahead; lastiba; lastiba = iba->d_bsame) { 1291 1.79 christos for (iba = lastiba; iba != NULL; iba = iba->d_bsame) 1292 1.79 christos if (onlist(iba->d_atlist, 1293 1.79 christos attr == &errattr ? NULL : attr)) 1294 1.1 thorpej break; 1295 1.79 christos 1296 1.81 christos first = lastiba == ib->d_ahead; 1297 1.79 christos if (iba == NULL) { 1298 1.81 christos if (!first) 1299 1.79 christos goto bad; 1300 1.79 christos if (attr != &errattr) { 1301 1.81 christos panic("%s: can't figure out attachment", 1302 1.81 christos __func__); 1303 1.79 christos } else { 1304 1.79 christos cfgerror("`%s' cannot attach to the root", 1305 1.79 christos ib->d_name); 1306 1.79 christos i->i_active = DEVI_BROKEN; 1307 1.1 thorpej } 1308 1.1 thorpej } 1309 1.79 christos // get a new one if it is not the first time 1310 1.81 christos if (!first && (i = getdevi(name)) == NULL) 1311 1.1 thorpej goto bad; 1312 1.79 christos 1313 1.79 christos if (attr != &errattr) { 1314 1.79 christos /* 1315 1.79 christos * Find the parent spec. If a matching one has not 1316 1.79 christos * yet been created, create one. 1317 1.79 christos * 1318 1.79 christos * XXX: This creates multiple pspecs that look the 1319 1.79 christos * same in the config file and could be merged. 1320 1.79 christos */ 1321 1.82 christos p = getpspec(attr, ab, atunit, first); 1322 1.79 christos p->p_devs = newnv(NULL, NULL, i, 0, p->p_devs); 1323 1.81 christos } else 1324 1.81 christos p = NULL; 1325 1.1 thorpej 1326 1.79 christos if ((i->i_locs = fixloc(name, attr, loclist)) == NULL) { 1327 1.11 cube i->i_active = DEVI_BROKEN; 1328 1.1 thorpej goto bad; 1329 1.1 thorpej } 1330 1.79 christos i->i_at = at; 1331 1.79 christos i->i_pspec = p; 1332 1.79 christos i->i_atdeva = iba; 1333 1.79 christos i->i_cfflags = flags; 1334 1.79 christos CFGDBG(3, "devi `%s' at '%s' added", i->i_name, iba->d_name); 1335 1.1 thorpej 1336 1.79 christos *iba->d_ipp = i; 1337 1.79 christos iba->d_ipp = &i->i_asame; 1338 1.11 cube } 1339 1.1 thorpej 1340 1.1 thorpej /* all done, fall into ... */ 1341 1.1 thorpej bad: 1342 1.41 dholland loclist_destroy(loclist); 1343 1.1 thorpej return; 1344 1.1 thorpej } 1345 1.1 thorpej 1346 1.1 thorpej void 1347 1.75 christos deldevi(const char *name, const char *at, int nowarn) 1348 1.1 thorpej { 1349 1.7 cube struct devi *firsti, *i; 1350 1.1 thorpej struct devbase *d; 1351 1.1 thorpej int unit; 1352 1.1 thorpej char base[NAMESIZE]; 1353 1.1 thorpej 1354 1.61 uebayasi CFGDBG(5, "deselecting devi `%s'", name); 1355 1.1 thorpej if (split(name, strlen(name), base, sizeof base, &unit)) { 1356 1.75 christos if (!nowarn) { 1357 1.75 christos cfgerror("invalid device name `%s'", name); 1358 1.75 christos return; 1359 1.75 christos } 1360 1.1 thorpej } 1361 1.1 thorpej d = ht_lookup(devbasetab, intern(base)); 1362 1.1 thorpej if (d == NULL) { 1363 1.75 christos if (!nowarn) 1364 1.75 christos cfgerror("%s: unknown device `%s'", name, base); 1365 1.1 thorpej return; 1366 1.1 thorpej } 1367 1.1 thorpej if (d->d_ispseudo) { 1368 1.27 christos cfgerror("%s: %s is a pseudo-device", name, base); 1369 1.1 thorpej return; 1370 1.1 thorpej } 1371 1.1 thorpej if ((firsti = ht_lookup(devitab, name)) == NULL) { 1372 1.27 christos cfgerror("`%s' not defined", name); 1373 1.1 thorpej return; 1374 1.1 thorpej } 1375 1.7 cube if (at == NULL && firsti->i_at == NULL) { 1376 1.2 cube /* 'at root' */ 1377 1.7 cube remove_devi(firsti); 1378 1.7 cube return; 1379 1.7 cube } else if (at != NULL) 1380 1.7 cube for (i = firsti; i != NULL; i = i->i_alias) 1381 1.28 cube if (i->i_active != DEVI_BROKEN && 1382 1.28 cube strcmp(at, i->i_at) == 0) { 1383 1.7 cube remove_devi(i); 1384 1.7 cube return; 1385 1.2 cube } 1386 1.27 christos cfgerror("`%s' at `%s' not found", name, at ? at : "root"); 1387 1.7 cube } 1388 1.7 cube 1389 1.7 cube static void 1390 1.78 christos remove_pspec(struct devi *i) 1391 1.78 christos { 1392 1.78 christos struct pspec *p = i->i_pspec; 1393 1.78 christos struct nvlist *nv, *onv; 1394 1.78 christos 1395 1.78 christos if (p == NULL) 1396 1.78 christos return; 1397 1.78 christos 1398 1.78 christos /* Double-linked nvlist anyone? */ 1399 1.78 christos for (nv = p->p_devs; nv->nv_next != NULL; nv = nv->nv_next) { 1400 1.78 christos if (nv->nv_next && nv->nv_next->nv_ptr == i) { 1401 1.78 christos onv = nv->nv_next; 1402 1.78 christos nv->nv_next = onv->nv_next; 1403 1.78 christos nvfree(onv); 1404 1.78 christos break; 1405 1.78 christos } 1406 1.78 christos if (nv->nv_ptr == i) { 1407 1.78 christos /* nv is p->p_devs in that case */ 1408 1.78 christos p->p_devs = nv->nv_next; 1409 1.78 christos nvfree(nv); 1410 1.78 christos break; 1411 1.78 christos } 1412 1.78 christos } 1413 1.78 christos if (p->p_devs == NULL) 1414 1.78 christos TAILQ_REMOVE(&allpspecs, p, p_list); 1415 1.78 christos } 1416 1.78 christos 1417 1.78 christos static void 1418 1.7 cube remove_devi(struct devi *i) 1419 1.7 cube { 1420 1.7 cube struct devbase *d = i->i_base; 1421 1.7 cube struct devi *f, *j, **ppi; 1422 1.7 cube struct deva *iba; 1423 1.7 cube 1424 1.66 uebayasi CFGDBG(5, "removing devi `%s'", i->i_name); 1425 1.7 cube f = ht_lookup(devitab, i->i_name); 1426 1.21 cube if (f == NULL) 1427 1.81 christos panic("%s: instance %s disappeared from devitab", __func__, 1428 1.21 cube i->i_name); 1429 1.2 cube 1430 1.28 cube if (i->i_active == DEVI_BROKEN) { 1431 1.28 cube cfgerror("not removing broken instance `%s'", i->i_name); 1432 1.28 cube return; 1433 1.28 cube } 1434 1.28 cube 1435 1.2 cube /* 1436 1.2 cube * We have the device instance, i. 1437 1.2 cube * We have to: 1438 1.2 cube * - delete the alias 1439 1.2 cube * 1440 1.2 cube * If the devi was an alias of an already listed devi, all is 1441 1.2 cube * good we don't have to do more. 1442 1.2 cube * If it was the first alias, we have to replace i's entry in 1443 1.2 cube * d's list by its first alias. 1444 1.2 cube * If it was the only entry, we must remove i's entry from d's 1445 1.2 cube * list. 1446 1.2 cube */ 1447 1.7 cube if (i != f) { 1448 1.67 uebayasi for (j = f; j->i_alias != i; j = j->i_alias) 1449 1.67 uebayasi continue; 1450 1.7 cube j->i_alias = i->i_alias; 1451 1.5 cube } else { 1452 1.5 cube if (i->i_alias == NULL) { 1453 1.2 cube /* No alias, must unlink the entry from devitab */ 1454 1.7 cube ht_remove(devitab, i->i_name); 1455 1.7 cube j = i->i_bsame; 1456 1.5 cube } else { 1457 1.2 cube /* Or have the first alias replace i in d's list */ 1458 1.2 cube i->i_alias->i_bsame = i->i_bsame; 1459 1.7 cube j = i->i_alias; 1460 1.7 cube if (i == f) 1461 1.7 cube ht_replace(devitab, i->i_name, i->i_alias); 1462 1.5 cube } 1463 1.5 cube 1464 1.2 cube /* 1465 1.2 cube * - remove/replace the instance from the devbase's list 1466 1.2 cube * 1467 1.2 cube * A double-linked list would make this much easier. Oh, well, 1468 1.2 cube * what is done is done. 1469 1.2 cube */ 1470 1.2 cube for (ppi = &d->d_ihead; 1471 1.2 cube *ppi != NULL && *ppi != i && (*ppi)->i_bsame != i; 1472 1.67 uebayasi ppi = &(*ppi)->i_bsame) 1473 1.67 uebayasi continue; 1474 1.2 cube if (*ppi == NULL) 1475 1.81 christos panic("%s: dev (%s) doesn't list the devi (%s at %s)", 1476 1.81 christos __func__, d->d_name, i->i_name, i->i_at); 1477 1.7 cube f = *ppi; 1478 1.7 cube if (f == i) 1479 1.4 cube /* That implies d->d_ihead == i */ 1480 1.7 cube *ppi = j; 1481 1.2 cube else 1482 1.7 cube (*ppi)->i_bsame = j; 1483 1.2 cube if (d->d_ipp == &i->i_bsame) { 1484 1.5 cube if (i->i_alias == NULL) { 1485 1.7 cube if (f == i) 1486 1.5 cube d->d_ipp = &d->d_ihead; 1487 1.5 cube else 1488 1.7 cube d->d_ipp = &f->i_bsame; 1489 1.5 cube } else 1490 1.5 cube d->d_ipp = &i->i_alias->i_bsame; 1491 1.2 cube } 1492 1.2 cube } 1493 1.2 cube /* 1494 1.2 cube * - delete the attachment instance 1495 1.2 cube */ 1496 1.2 cube iba = i->i_atdeva; 1497 1.2 cube for (ppi = &iba->d_ihead; 1498 1.2 cube *ppi != NULL && *ppi != i && (*ppi)->i_asame != i; 1499 1.67 uebayasi ppi = &(*ppi)->i_asame) 1500 1.67 uebayasi continue; 1501 1.2 cube if (*ppi == NULL) 1502 1.81 christos panic("%s: deva (%s) doesn't list the devi (%s)", __func__, 1503 1.2 cube iba->d_name, i->i_name); 1504 1.7 cube f = *ppi; 1505 1.7 cube if (f == i) 1506 1.4 cube /* That implies iba->d_ihead == i */ 1507 1.2 cube *ppi = i->i_asame; 1508 1.2 cube else 1509 1.2 cube (*ppi)->i_asame = i->i_asame; 1510 1.2 cube if (iba->d_ipp == &i->i_asame) { 1511 1.7 cube if (f == i) 1512 1.2 cube iba->d_ipp = &iba->d_ihead; 1513 1.2 cube else 1514 1.7 cube iba->d_ipp = &f->i_asame; 1515 1.2 cube } 1516 1.2 cube /* 1517 1.2 cube * - delete the pspec 1518 1.2 cube */ 1519 1.78 christos remove_pspec(i); 1520 1.78 christos 1521 1.2 cube /* 1522 1.2 cube * - delete the alldevi entry 1523 1.2 cube */ 1524 1.2 cube TAILQ_REMOVE(&alldevi, i, i_next); 1525 1.2 cube ndevi--; 1526 1.8 cube /* 1527 1.8 cube * Put it in deaddevitab 1528 1.13 cube * 1529 1.13 cube * Each time a devi is removed, devilevel is increased so that later on 1530 1.13 cube * it is possible to tell if an instance was added before or after the 1531 1.13 cube * removal of its parent. 1532 1.13 cube * 1533 1.13 cube * For active instances, i_level contains the number of devi removed so 1534 1.13 cube * far, and for dead devis, it contains its index. 1535 1.8 cube */ 1536 1.13 cube i->i_level = devilevel++; 1537 1.8 cube i->i_alias = NULL; 1538 1.8 cube f = ht_lookup(deaddevitab, i->i_name); 1539 1.8 cube if (f == NULL) { 1540 1.8 cube if (ht_insert(deaddevitab, i->i_name, i)) 1541 1.81 christos panic("%s: can't add %s to deaddevitab", __func__, 1542 1.8 cube i->i_name); 1543 1.8 cube } else { 1544 1.67 uebayasi for (j = f; j->i_alias != NULL; j = j->i_alias) 1545 1.67 uebayasi continue; 1546 1.8 cube j->i_alias = i; 1547 1.8 cube } 1548 1.2 cube /* 1549 1.19 wiz * - reconstruct d->d_umax 1550 1.2 cube */ 1551 1.2 cube d->d_umax = 0; 1552 1.2 cube for (i = d->d_ihead; i != NULL; i = i->i_bsame) 1553 1.2 cube if (i->i_unit >= d->d_umax) 1554 1.2 cube d->d_umax = i->i_unit + 1; 1555 1.1 thorpej } 1556 1.1 thorpej 1557 1.1 thorpej void 1558 1.75 christos deldeva(const char *at, int nowarn) 1559 1.7 cube { 1560 1.7 cube int unit; 1561 1.7 cube const char *cp; 1562 1.7 cube struct devbase *d, *ad; 1563 1.7 cube struct devi *i, *j; 1564 1.7 cube struct attr *a; 1565 1.7 cube struct pspec *p; 1566 1.7 cube struct nvlist *nv, *stack = NULL; 1567 1.7 cube 1568 1.7 cube if (at == NULL) { 1569 1.7 cube TAILQ_FOREACH(i, &alldevi, i_next) 1570 1.7 cube if (i->i_at == NULL) 1571 1.7 cube stack = newnv(NULL, NULL, i, 0, stack); 1572 1.7 cube } else { 1573 1.65 christos size_t l; 1574 1.7 cube 1575 1.61 uebayasi CFGDBG(5, "deselecting deva `%s'", at); 1576 1.65 christos if (at[0] == '\0') 1577 1.65 christos goto out; 1578 1.87 joe 1579 1.7 cube l = strlen(at) - 1; 1580 1.7 cube if (at[l] == '?' || isdigit((unsigned char)at[l])) { 1581 1.7 cube char base[NAMESIZE]; 1582 1.7 cube 1583 1.7 cube if (split(at, l+1, base, sizeof base, &unit)) { 1584 1.65 christos out: 1585 1.27 christos cfgerror("invalid attachment name `%s'", at); 1586 1.7 cube return; 1587 1.7 cube } 1588 1.7 cube cp = intern(base); 1589 1.7 cube } else { 1590 1.7 cube cp = intern(at); 1591 1.7 cube unit = STAR; 1592 1.7 cube } 1593 1.7 cube 1594 1.7 cube ad = ht_lookup(devbasetab, cp); 1595 1.7 cube a = ht_lookup(attrtab, cp); 1596 1.7 cube if (a == NULL) { 1597 1.27 christos cfgerror("unknown attachment attribute or device `%s'", 1598 1.7 cube cp); 1599 1.7 cube return; 1600 1.7 cube } 1601 1.7 cube if (!a->a_iattr) { 1602 1.27 christos cfgerror("plain attribute `%s' cannot have children", 1603 1.7 cube a->a_name); 1604 1.7 cube return; 1605 1.7 cube } 1606 1.7 cube 1607 1.7 cube /* 1608 1.7 cube * remove_devi() makes changes to the devbase's list and the 1609 1.7 cube * alias list, * so the actual deletion of the instances must 1610 1.7 cube * be delayed. 1611 1.7 cube */ 1612 1.7 cube for (nv = a->a_devs; nv != NULL; nv = nv->nv_next) { 1613 1.7 cube d = nv->nv_ptr; 1614 1.7 cube for (i = d->d_ihead; i != NULL; i = i->i_bsame) 1615 1.7 cube for (j = i; j != NULL; j = j->i_alias) { 1616 1.7 cube /* Ignore devices at root */ 1617 1.7 cube if (j->i_at == NULL) 1618 1.7 cube continue; 1619 1.7 cube p = j->i_pspec; 1620 1.7 cube /* 1621 1.7 cube * There are three cases: 1622 1.7 cube * 1623 1.7 cube * 1. unit is not STAR. Consider 'at' 1624 1.7 cube * to be explicit, even if it 1625 1.7 cube * references an interface 1626 1.7 cube * attribute. 1627 1.7 cube * 1628 1.7 cube * 2. unit is STAR and 'at' references 1629 1.7 cube * a real device. Look for pspec 1630 1.7 cube * that have a matching p_atdev 1631 1.7 cube * field. 1632 1.7 cube * 1633 1.7 cube * 3. unit is STAR and 'at' references 1634 1.7 cube * an interface attribute. Look 1635 1.7 cube * for pspec that have a matching 1636 1.7 cube * p_iattr field. 1637 1.7 cube */ 1638 1.7 cube if ((unit != STAR && /* Case */ 1639 1.7 cube !strcmp(j->i_at, at)) || /* 1 */ 1640 1.7 cube (unit == STAR && 1641 1.7 cube ((ad != NULL && /* Case */ 1642 1.7 cube p->p_atdev == ad) || /* 2 */ 1643 1.7 cube (ad == NULL && /* Case */ 1644 1.7 cube p->p_iattr == a)))) /* 3 */ 1645 1.7 cube stack = newnv(NULL, NULL, j, 0, 1646 1.7 cube stack); 1647 1.7 cube } 1648 1.7 cube } 1649 1.7 cube } 1650 1.7 cube 1651 1.76 christos devcleanup(stack); 1652 1.7 cube } 1653 1.7 cube 1654 1.7 cube void 1655 1.75 christos deldev(const char *name, int nowarn) 1656 1.7 cube { 1657 1.65 christos size_t l; 1658 1.7 cube struct devi *firsti, *i; 1659 1.76 christos struct nvlist *stack = NULL; 1660 1.7 cube 1661 1.61 uebayasi CFGDBG(5, "deselecting dev `%s'", name); 1662 1.65 christos if (name[0] == '\0') 1663 1.65 christos goto out; 1664 1.65 christos 1665 1.7 cube l = strlen(name) - 1; 1666 1.7 cube if (name[l] == '*' || isdigit((unsigned char)name[l])) { 1667 1.7 cube /* `no mydev0' or `no mydev*' */ 1668 1.7 cube firsti = ht_lookup(devitab, name); 1669 1.7 cube if (firsti == NULL) { 1670 1.65 christos out: 1671 1.75 christos if (!nowarn) 1672 1.75 christos cfgerror("unknown instance %s", name); 1673 1.7 cube return; 1674 1.7 cube } 1675 1.7 cube for (i = firsti; i != NULL; i = i->i_alias) 1676 1.7 cube stack = newnv(NULL, NULL, i, 0, stack); 1677 1.7 cube } else { 1678 1.7 cube struct devbase *d = ht_lookup(devbasetab, name); 1679 1.7 cube 1680 1.7 cube if (d == NULL) { 1681 1.27 christos cfgerror("unknown device %s", name); 1682 1.7 cube return; 1683 1.7 cube } 1684 1.23 cube if (d->d_ispseudo) { 1685 1.27 christos cfgerror("%s is a pseudo-device; " 1686 1.23 cube "use \"no pseudo-device %s\" instead", name, 1687 1.23 cube name); 1688 1.23 cube return; 1689 1.23 cube } 1690 1.76 christos stack = makedevstack(d); 1691 1.7 cube } 1692 1.7 cube 1693 1.76 christos devcleanup(stack); 1694 1.7 cube } 1695 1.7 cube 1696 1.38 pooka /* 1697 1.38 pooka * Insert given device "name" into devroottab. In case "name" 1698 1.38 pooka * designates a pure interface attribute, create a fake device 1699 1.38 pooka * instance for the attribute and insert that into the roottab 1700 1.38 pooka * (this scheme avoids mucking around with the orphanage analysis). 1701 1.38 pooka */ 1702 1.7 cube void 1703 1.34 pooka addpseudoroot(const char *name) 1704 1.34 pooka { 1705 1.36 pooka char buf[NAMESIZE]; 1706 1.36 pooka int unit; 1707 1.36 pooka struct attr *attr; 1708 1.34 pooka struct devi *i; 1709 1.34 pooka struct deva *iba; 1710 1.34 pooka struct devbase *ib; 1711 1.34 pooka 1712 1.36 pooka if (split(name, strlen(name), buf, sizeof(buf), &unit)) { 1713 1.36 pooka cfgerror("invalid pseudo-root name `%s'", name); 1714 1.36 pooka return; 1715 1.36 pooka } 1716 1.36 pooka 1717 1.36 pooka /* 1718 1.38 pooka * Prefer device because devices with locators define an 1719 1.38 pooka * implicit interface attribute. However, if a device is 1720 1.38 pooka * not available, try to attach to the interface attribute. 1721 1.38 pooka * This makes sure adddev() doesn't get confused when we 1722 1.38 pooka * are really attaching to a device (alternatively we maybe 1723 1.38 pooka * could specify a non-NULL atlist to defdevattach() below). 1724 1.36 pooka */ 1725 1.38 pooka ib = ht_lookup(devbasetab, intern(buf)); 1726 1.38 pooka if (ib == NULL) { 1727 1.36 pooka struct devbase *fakedev; 1728 1.36 pooka char fakename[NAMESIZE]; 1729 1.36 pooka 1730 1.38 pooka attr = ht_lookup(attrtab, intern(buf)); 1731 1.38 pooka if (!(attr && attr->a_iattr)) { 1732 1.38 pooka cfgerror("pseudo-root `%s' not available", name); 1733 1.38 pooka return; 1734 1.38 pooka } 1735 1.38 pooka 1736 1.36 pooka /* 1737 1.36 pooka * here we cheat a bit: create a fake devbase with the 1738 1.36 pooka * interface attribute and instantiate it. quick, cheap, 1739 1.36 pooka * dirty & bad for you, much like the stuff in the fridge. 1740 1.36 pooka * and, it works, since the pseudoroot device is not included 1741 1.36 pooka * in ioconf, just used by config to make sure we start from 1742 1.36 pooka * the right place. 1743 1.87 joe */ 1744 1.38 pooka snprintf(fakename, sizeof(fakename), "%s_devattrs", buf); 1745 1.36 pooka fakedev = getdevbase(intern(fakename)); 1746 1.36 pooka fakedev->d_isdef = 1; 1747 1.36 pooka fakedev->d_ispseudo = 0; 1748 1.39 dholland fakedev->d_attrs = attrlist_cons(NULL, attr); 1749 1.36 pooka defdevattach(NULL, fakedev, NULL, NULL); 1750 1.36 pooka 1751 1.36 pooka if (unit == STAR) 1752 1.36 pooka snprintf(buf, sizeof(buf), "%s*", fakename); 1753 1.36 pooka else 1754 1.36 pooka snprintf(buf, sizeof(buf), "%s%d", fakename, unit); 1755 1.36 pooka name = buf; 1756 1.36 pooka } 1757 1.36 pooka 1758 1.36 pooka /* ok, everything should be set up, so instantiate a fake device */ 1759 1.34 pooka i = getdevi(name); 1760 1.34 pooka if (i == NULL) 1761 1.81 christos panic("%s: device `%s' expected to be present", __func__, 1762 1.81 christos name); 1763 1.34 pooka ib = i->i_base; 1764 1.36 pooka iba = ib->d_ahead; 1765 1.34 pooka 1766 1.34 pooka i->i_atdeva = iba; 1767 1.34 pooka i->i_cfflags = 0; 1768 1.34 pooka i->i_locs = fixloc(name, &errattr, NULL); 1769 1.34 pooka i->i_pseudoroot = 1; 1770 1.34 pooka i->i_active = DEVI_ORPHAN; /* set active by kill_orphans() */ 1771 1.34 pooka 1772 1.34 pooka *iba->d_ipp = i; 1773 1.34 pooka iba->d_ipp = &i->i_asame; 1774 1.34 pooka 1775 1.34 pooka ht_insert(devroottab, ib->d_name, ib); 1776 1.34 pooka } 1777 1.34 pooka 1778 1.76 christos static void 1779 1.76 christos deldevbase(struct devbase *d) 1780 1.76 christos { 1781 1.76 christos struct devi *i; 1782 1.76 christos const char *name = d->d_name; 1783 1.76 christos 1784 1.76 christos if (!d->d_ispseudo) { 1785 1.76 christos devcleanup(makedevstack(d)); 1786 1.76 christos return; 1787 1.76 christos } 1788 1.76 christos 1789 1.76 christos if ((i = ht_lookup(devitab, name)) == NULL) 1790 1.76 christos return; 1791 1.76 christos 1792 1.76 christos d->d_umax = 0; /* clear neads-count entries */ 1793 1.76 christos d->d_ihead = NULL; /* make sure it won't be considered active */ 1794 1.76 christos TAILQ_REMOVE(&allpseudo, i, i_next); 1795 1.76 christos if (ht_remove(devitab, name)) 1796 1.81 christos panic("%s: Can't remove %s from devitab", __func__, name); 1797 1.76 christos if (ht_insert(deaddevitab, name, i)) 1798 1.81 christos panic("%s: Can't add %s to deaddevitab", __func__, name); 1799 1.76 christos } 1800 1.76 christos 1801 1.34 pooka void 1802 1.1 thorpej addpseudo(const char *name, int number) 1803 1.1 thorpej { 1804 1.1 thorpej struct devbase *d; 1805 1.1 thorpej struct devi *i; 1806 1.1 thorpej 1807 1.1 thorpej d = ht_lookup(devbasetab, name); 1808 1.1 thorpej if (d == NULL) { 1809 1.27 christos cfgerror("undefined pseudo-device %s", name); 1810 1.1 thorpej return; 1811 1.1 thorpej } 1812 1.1 thorpej if (!d->d_ispseudo) { 1813 1.27 christos cfgerror("%s is a real device, not a pseudo-device", name); 1814 1.1 thorpej return; 1815 1.1 thorpej } 1816 1.84 christos if ((i = ht_lookup(devitab, name)) != NULL) { 1817 1.84 christos cfgerror("`%s' already defined at %s:%hu", name, 1818 1.84 christos i->i_where.w_srcfile, i->i_where.w_srcline); 1819 1.1 thorpej return; 1820 1.1 thorpej } 1821 1.1 thorpej i = newdevi(name, number - 1, d); /* foo 16 => "foo0..foo15" */ 1822 1.1 thorpej if (ht_insert(devitab, name, i)) 1823 1.81 christos panic("%s: %s", __func__, name); 1824 1.7 cube /* Useful to retrieve the instance from the devbase */ 1825 1.7 cube d->d_ihead = i; 1826 1.8 cube i->i_active = DEVI_ACTIVE; 1827 1.1 thorpej TAILQ_INSERT_TAIL(&allpseudo, i, i_next); 1828 1.1 thorpej } 1829 1.1 thorpej 1830 1.1 thorpej void 1831 1.75 christos delpseudo(const char *name, int nowarn) 1832 1.1 thorpej { 1833 1.1 thorpej struct devbase *d; 1834 1.1 thorpej 1835 1.61 uebayasi CFGDBG(5, "deselecting pseudo `%s'", name); 1836 1.1 thorpej d = ht_lookup(devbasetab, name); 1837 1.1 thorpej if (d == NULL) { 1838 1.75 christos if (!nowarn) 1839 1.75 christos cfgerror("undefined pseudo-device %s", name); 1840 1.1 thorpej return; 1841 1.1 thorpej } 1842 1.1 thorpej if (!d->d_ispseudo) { 1843 1.27 christos cfgerror("%s is a real device, not a pseudo-device", name); 1844 1.1 thorpej return; 1845 1.1 thorpej } 1846 1.76 christos deldevbase(d); 1847 1.1 thorpej } 1848 1.1 thorpej 1849 1.1 thorpej void 1850 1.32 drochner adddevm(const char *name, devmajor_t cmajor, devmajor_t bmajor, 1851 1.40 dholland struct condexpr *cond, struct nvlist *nv_nodes) 1852 1.1 thorpej { 1853 1.1 thorpej struct devm *dm; 1854 1.1 thorpej 1855 1.32 drochner if (cmajor != NODEVMAJOR && (cmajor < 0 || cmajor >= 4096)) { 1856 1.27 christos cfgerror("character major %d is invalid", cmajor); 1857 1.40 dholland condexpr_destroy(cond); 1858 1.35 pooka nvfreel(nv_nodes); 1859 1.1 thorpej return; 1860 1.1 thorpej } 1861 1.1 thorpej 1862 1.32 drochner if (bmajor != NODEVMAJOR && (bmajor < 0 || bmajor >= 4096)) { 1863 1.27 christos cfgerror("block major %d is invalid", bmajor); 1864 1.40 dholland condexpr_destroy(cond); 1865 1.35 pooka nvfreel(nv_nodes); 1866 1.1 thorpej return; 1867 1.1 thorpej } 1868 1.32 drochner if (cmajor == NODEVMAJOR && bmajor == NODEVMAJOR) { 1869 1.27 christos cfgerror("both character/block majors are not specified"); 1870 1.40 dholland condexpr_destroy(cond); 1871 1.35 pooka nvfreel(nv_nodes); 1872 1.1 thorpej return; 1873 1.1 thorpej } 1874 1.1 thorpej 1875 1.1 thorpej dm = ecalloc(1, sizeof(*dm)); 1876 1.84 christos dm->dm_where.w_srcfile = yyfile; 1877 1.84 christos dm->dm_where.w_srcline = currentline(); 1878 1.1 thorpej dm->dm_name = name; 1879 1.1 thorpej dm->dm_cmajor = cmajor; 1880 1.1 thorpej dm->dm_bmajor = bmajor; 1881 1.40 dholland dm->dm_opts = cond; 1882 1.35 pooka dm->dm_devnodes = nv_nodes; 1883 1.1 thorpej 1884 1.1 thorpej TAILQ_INSERT_TAIL(&alldevms, dm, dm_next); 1885 1.1 thorpej 1886 1.1 thorpej maxcdevm = MAX(maxcdevm, dm->dm_cmajor); 1887 1.1 thorpej maxbdevm = MAX(maxbdevm, dm->dm_bmajor); 1888 1.1 thorpej } 1889 1.1 thorpej 1890 1.8 cube int 1891 1.1 thorpej fixdevis(void) 1892 1.1 thorpej { 1893 1.81 christos const char *msg; 1894 1.1 thorpej struct devi *i; 1895 1.78 christos struct pspec *p; 1896 1.8 cube int error = 0; 1897 1.1 thorpej 1898 1.60 uebayasi TAILQ_FOREACH(i, &alldevi, i_next) { 1899 1.60 uebayasi CFGDBG(3, "fixing devis `%s'", i->i_name); 1900 1.8 cube if (i->i_active == DEVI_ACTIVE) 1901 1.6 cube selectbase(i->i_base, i->i_atdeva); 1902 1.8 cube else if (i->i_active == DEVI_ORPHAN) { 1903 1.6 cube /* 1904 1.6 cube * At this point, we can't have instances for which 1905 1.6 cube * i_at or i_pspec are NULL. 1906 1.6 cube */ 1907 1.8 cube ++error; 1908 1.78 christos p = i->i_pspec; 1909 1.81 christos msg = p == NULL ? "no parent" : 1910 1.81 christos (p->p_atunit == WILD ? "nothing matching" : "no"); 1911 1.84 christos cfgxerror(i->i_where.w_srcfile, i->i_where.w_srcline, 1912 1.10 cube "`%s at %s' is orphaned (%s `%s' found)", 1913 1.81 christos i->i_name, i->i_at, msg, i->i_at); 1914 1.8 cube } else if (vflag && i->i_active == DEVI_IGNORED) 1915 1.84 christos cfgxwarn(i->i_where.w_srcfile, i->i_where.w_srcline, "ignoring " 1916 1.27 christos "explicitly orphaned instance `%s at %s'", 1917 1.27 christos i->i_name, i->i_at); 1918 1.60 uebayasi } 1919 1.8 cube 1920 1.8 cube if (error) 1921 1.8 cube return error; 1922 1.1 thorpej 1923 1.1 thorpej TAILQ_FOREACH(i, &allpseudo, i_next) 1924 1.8 cube if (i->i_active == DEVI_ACTIVE) 1925 1.6 cube selectbase(i->i_base, NULL); 1926 1.8 cube return 0; 1927 1.1 thorpej } 1928 1.1 thorpej 1929 1.1 thorpej /* 1930 1.1 thorpej * Look up a parent spec, creating a new one if it does not exist. 1931 1.1 thorpej */ 1932 1.1 thorpej static struct pspec * 1933 1.82 christos getpspec(struct attr *attr, struct devbase *ab, int atunit, int first) 1934 1.1 thorpej { 1935 1.1 thorpej struct pspec *p; 1936 1.79 christos int inst = npspecs; 1937 1.82 christos int ref = 1; 1938 1.1 thorpej 1939 1.1 thorpej TAILQ_FOREACH(p, &allpspecs, p_list) { 1940 1.79 christos if (p->p_iattr == attr && p->p_atdev == ab && 1941 1.79 christos p->p_atunit == atunit) { 1942 1.82 christos p->p_ref++; 1943 1.82 christos if (first) 1944 1.82 christos return p; 1945 1.82 christos else { 1946 1.82 christos inst = p->p_inst; 1947 1.82 christos ref = p->p_ref; 1948 1.82 christos } 1949 1.87 joe 1950 1.79 christos } 1951 1.1 thorpej } 1952 1.1 thorpej 1953 1.1 thorpej p = ecalloc(1, sizeof(*p)); 1954 1.1 thorpej 1955 1.1 thorpej p->p_iattr = attr; 1956 1.1 thorpej p->p_atdev = ab; 1957 1.1 thorpej p->p_atunit = atunit; 1958 1.79 christos p->p_inst = inst; 1959 1.79 christos if (inst == npspecs) 1960 1.79 christos npspecs++; 1961 1.6 cube p->p_active = 0; 1962 1.82 christos p->p_ref = ref; 1963 1.1 thorpej 1964 1.1 thorpej TAILQ_INSERT_TAIL(&allpspecs, p, p_list); 1965 1.1 thorpej 1966 1.1 thorpej return (p); 1967 1.1 thorpej } 1968 1.1 thorpej 1969 1.1 thorpej /* 1970 1.1 thorpej * Define a new instance of a specific device. 1971 1.1 thorpej */ 1972 1.1 thorpej static struct devi * 1973 1.1 thorpej getdevi(const char *name) 1974 1.1 thorpej { 1975 1.1 thorpej struct devi *i, *firsti; 1976 1.1 thorpej struct devbase *d; 1977 1.1 thorpej int unit; 1978 1.1 thorpej char base[NAMESIZE]; 1979 1.1 thorpej 1980 1.1 thorpej if (split(name, strlen(name), base, sizeof base, &unit)) { 1981 1.27 christos cfgerror("invalid device name `%s'", name); 1982 1.1 thorpej return (NULL); 1983 1.1 thorpej } 1984 1.1 thorpej d = ht_lookup(devbasetab, intern(base)); 1985 1.1 thorpej if (d == NULL) { 1986 1.27 christos cfgerror("%s: unknown device `%s'", name, base); 1987 1.1 thorpej return (NULL); 1988 1.1 thorpej } 1989 1.1 thorpej if (d->d_ispseudo) { 1990 1.27 christos cfgerror("%s: %s is a pseudo-device", name, base); 1991 1.1 thorpej return (NULL); 1992 1.1 thorpej } 1993 1.1 thorpej firsti = ht_lookup(devitab, name); 1994 1.1 thorpej i = newdevi(name, unit, d); 1995 1.1 thorpej if (firsti == NULL) { 1996 1.1 thorpej if (ht_insert(devitab, name, i)) 1997 1.81 christos panic("%s: %s", __func__, name); 1998 1.1 thorpej *d->d_ipp = i; 1999 1.1 thorpej d->d_ipp = &i->i_bsame; 2000 1.1 thorpej } else { 2001 1.1 thorpej while (firsti->i_alias) 2002 1.1 thorpej firsti = firsti->i_alias; 2003 1.1 thorpej firsti->i_alias = i; 2004 1.1 thorpej } 2005 1.1 thorpej TAILQ_INSERT_TAIL(&alldevi, i, i_next); 2006 1.1 thorpej ndevi++; 2007 1.1 thorpej return (i); 2008 1.1 thorpej } 2009 1.1 thorpej 2010 1.1 thorpej static const char * 2011 1.1 thorpej concat(const char *name, int c) 2012 1.1 thorpej { 2013 1.27 christos size_t len; 2014 1.1 thorpej char buf[NAMESIZE]; 2015 1.1 thorpej 2016 1.1 thorpej len = strlen(name); 2017 1.1 thorpej if (len + 2 > sizeof(buf)) { 2018 1.27 christos cfgerror("device name `%s%c' too long", name, c); 2019 1.1 thorpej len = sizeof(buf) - 2; 2020 1.1 thorpej } 2021 1.1 thorpej memmove(buf, name, len); 2022 1.65 christos buf[len] = (char)c; 2023 1.65 christos buf[len + 1] = '\0'; 2024 1.1 thorpej return (intern(buf)); 2025 1.1 thorpej } 2026 1.1 thorpej 2027 1.1 thorpej const char * 2028 1.1 thorpej starref(const char *name) 2029 1.1 thorpej { 2030 1.1 thorpej 2031 1.1 thorpej return (concat(name, '*')); 2032 1.1 thorpej } 2033 1.1 thorpej 2034 1.1 thorpej const char * 2035 1.1 thorpej wildref(const char *name) 2036 1.1 thorpej { 2037 1.1 thorpej 2038 1.1 thorpej return (concat(name, '?')); 2039 1.1 thorpej } 2040 1.1 thorpej 2041 1.1 thorpej /* 2042 1.1 thorpej * Split a name like "foo0" into base name (foo) and unit number (0). 2043 1.1 thorpej * Return 0 on success. To make this useful for names like "foo0a", 2044 1.1 thorpej * the length of the "foo0" part is one of the arguments. 2045 1.1 thorpej */ 2046 1.1 thorpej static int 2047 1.1 thorpej split(const char *name, size_t nlen, char *base, size_t bsize, int *aunit) 2048 1.1 thorpej { 2049 1.1 thorpej const char *cp; 2050 1.27 christos int c; 2051 1.27 christos size_t l; 2052 1.1 thorpej 2053 1.1 thorpej l = nlen; 2054 1.1 thorpej if (l < 2 || l >= bsize || isdigit((unsigned char)*name)) 2055 1.1 thorpej return (1); 2056 1.1 thorpej c = (u_char)name[--l]; 2057 1.1 thorpej if (!isdigit(c)) { 2058 1.1 thorpej if (c == '*') 2059 1.1 thorpej *aunit = STAR; 2060 1.1 thorpej else if (c == '?') 2061 1.1 thorpej *aunit = WILD; 2062 1.1 thorpej else 2063 1.1 thorpej return (1); 2064 1.1 thorpej } else { 2065 1.1 thorpej cp = &name[l]; 2066 1.1 thorpej while (isdigit((unsigned char)cp[-1])) 2067 1.1 thorpej l--, cp--; 2068 1.1 thorpej *aunit = atoi(cp); 2069 1.1 thorpej } 2070 1.1 thorpej memmove(base, name, l); 2071 1.1 thorpej base[l] = 0; 2072 1.1 thorpej return (0); 2073 1.1 thorpej } 2074 1.1 thorpej 2075 1.1 thorpej void 2076 1.66 uebayasi addattr(const char *name) 2077 1.66 uebayasi { 2078 1.66 uebayasi struct attr *a; 2079 1.66 uebayasi 2080 1.66 uebayasi a = refattr(name); 2081 1.66 uebayasi selectattr(a); 2082 1.66 uebayasi } 2083 1.66 uebayasi 2084 1.66 uebayasi void 2085 1.75 christos delattr(const char *name, int nowarn) 2086 1.66 uebayasi { 2087 1.66 uebayasi struct attr *a; 2088 1.66 uebayasi 2089 1.66 uebayasi a = refattr(name); 2090 1.66 uebayasi deselectattr(a); 2091 1.66 uebayasi } 2092 1.66 uebayasi 2093 1.66 uebayasi void 2094 1.1 thorpej selectattr(struct attr *a) 2095 1.1 thorpej { 2096 1.54 uebayasi struct attrlist *al; 2097 1.54 uebayasi struct attr *dep; 2098 1.1 thorpej 2099 1.66 uebayasi CFGDBG(5, "selecting attr `%s'", a->a_name); 2100 1.54 uebayasi for (al = a->a_deps; al != NULL; al = al->al_next) { 2101 1.54 uebayasi dep = al->al_this; 2102 1.54 uebayasi selectattr(dep); 2103 1.54 uebayasi } 2104 1.70 uebayasi if (ht_insert(selecttab, a->a_name, __UNCONST(a->a_name)) == 0) 2105 1.70 uebayasi nattrs++; 2106 1.44 uebayasi CFGDBG(3, "attr selected `%s'", a->a_name); 2107 1.1 thorpej } 2108 1.1 thorpej 2109 1.64 uebayasi static int 2110 1.66 uebayasi deselectattrcb2(const char *name1, const char *name2, void *v, void *arg) 2111 1.66 uebayasi { 2112 1.76 christos struct attr *a = arg; 2113 1.76 christos const char *name = a->a_name; 2114 1.76 christos struct vtype *vt = v; 2115 1.66 uebayasi 2116 1.76 christos if (strcmp(name, name2) == 0) { 2117 1.75 christos delattr(name1, 0); 2118 1.76 christos return 0; 2119 1.76 christos } 2120 1.76 christos 2121 1.76 christos if (!vt->attr->a_deselected) 2122 1.76 christos return 0; 2123 1.76 christos 2124 1.76 christos switch (vt->type) { 2125 1.76 christos case V_ATTRIBUTE: 2126 1.76 christos #ifdef notyet 2127 1.76 christos // XXX: Loops 2128 1.76 christos deselectattr(vt->value); 2129 1.76 christos #endif 2130 1.76 christos break; 2131 1.76 christos case V_DEVICE: 2132 1.76 christos CFGDBG(5, "removing device `%s' with attr `%s' because attr `%s'" 2133 1.76 christos " is deselected", name1, name2, name); 2134 1.76 christos deldevbase(vt->value); 2135 1.76 christos break; 2136 1.76 christos default: 2137 1.76 christos abort(); 2138 1.76 christos } 2139 1.66 uebayasi return 0; 2140 1.66 uebayasi } 2141 1.66 uebayasi 2142 1.66 uebayasi void 2143 1.66 uebayasi deselectattr(struct attr *a) 2144 1.66 uebayasi { 2145 1.66 uebayasi CFGDBG(5, "deselecting attr `%s'", a->a_name); 2146 1.76 christos a->a_deselected = 1; 2147 1.76 christos ht_enumerate2(attrdeptab, deselectattrcb2, a); 2148 1.70 uebayasi if (ht_remove(selecttab, a->a_name) == 0) 2149 1.70 uebayasi nattrs--; 2150 1.66 uebayasi CFGDBG(3, "attr deselected `%s'", a->a_name); 2151 1.66 uebayasi } 2152 1.66 uebayasi 2153 1.66 uebayasi static int 2154 1.64 uebayasi dumpattrdepcb2(const char *name1, const char *name2, void *v, void *arg) 2155 1.64 uebayasi { 2156 1.64 uebayasi 2157 1.64 uebayasi CFGDBG(3, "attr `%s' depends on attr `%s'", name1, name2); 2158 1.64 uebayasi return 0; 2159 1.64 uebayasi } 2160 1.64 uebayasi 2161 1.64 uebayasi void 2162 1.64 uebayasi dependattrs(void) 2163 1.64 uebayasi { 2164 1.64 uebayasi 2165 1.64 uebayasi ht_enumerate2(attrdeptab, dumpattrdepcb2, NULL); 2166 1.64 uebayasi } 2167 1.64 uebayasi 2168 1.1 thorpej /* 2169 1.1 thorpej * We have an instance of the base foo, so select it and all its 2170 1.1 thorpej * attributes for "optional foo". 2171 1.1 thorpej */ 2172 1.1 thorpej static void 2173 1.1 thorpej selectbase(struct devbase *d, struct deva *da) 2174 1.1 thorpej { 2175 1.1 thorpej struct attr *a; 2176 1.39 dholland struct attrlist *al; 2177 1.1 thorpej 2178 1.27 christos (void)ht_insert(selecttab, d->d_name, __UNCONST(d->d_name)); 2179 1.44 uebayasi CFGDBG(3, "devbase selected `%s'", d->d_name); 2180 1.64 uebayasi CFGDBG(5, "selecting dependencies of devbase `%s'", d->d_name); 2181 1.39 dholland for (al = d->d_attrs; al != NULL; al = al->al_next) { 2182 1.39 dholland a = al->al_this; 2183 1.1 thorpej expandattr(a, selectattr); 2184 1.1 thorpej } 2185 1.56 uebayasi 2186 1.56 uebayasi struct attr *devattr; 2187 1.56 uebayasi devattr = refattr(d->d_name); 2188 1.56 uebayasi expandattr(devattr, selectattr); 2189 1.87 joe 2190 1.1 thorpej if (da != NULL) { 2191 1.27 christos (void)ht_insert(selecttab, da->d_name, __UNCONST(da->d_name)); 2192 1.44 uebayasi CFGDBG(3, "devattr selected `%s'", da->d_name); 2193 1.39 dholland for (al = da->d_attrs; al != NULL; al = al->al_next) { 2194 1.39 dholland a = al->al_this; 2195 1.1 thorpej expandattr(a, selectattr); 2196 1.1 thorpej } 2197 1.1 thorpej } 2198 1.58 uebayasi 2199 1.58 uebayasi fixdev(d); 2200 1.1 thorpej } 2201 1.1 thorpej 2202 1.1 thorpej /* 2203 1.1 thorpej * Is the given pointer on the given list of pointers? 2204 1.1 thorpej */ 2205 1.26 cube int 2206 1.1 thorpej onlist(struct nvlist *nv, void *ptr) 2207 1.1 thorpej { 2208 1.1 thorpej for (; nv != NULL; nv = nv->nv_next) 2209 1.1 thorpej if (nv->nv_ptr == ptr) 2210 1.1 thorpej return (1); 2211 1.1 thorpej return (0); 2212 1.1 thorpej } 2213 1.1 thorpej 2214 1.1 thorpej static char * 2215 1.1 thorpej extend(char *p, const char *name) 2216 1.1 thorpej { 2217 1.27 christos size_t l; 2218 1.1 thorpej 2219 1.1 thorpej l = strlen(name); 2220 1.1 thorpej memmove(p, name, l); 2221 1.1 thorpej p += l; 2222 1.1 thorpej *p++ = ','; 2223 1.1 thorpej *p++ = ' '; 2224 1.1 thorpej return (p); 2225 1.1 thorpej } 2226 1.1 thorpej 2227 1.1 thorpej /* 2228 1.1 thorpej * Check that we got all required locators, and default any that are 2229 1.1 thorpej * given as "?" and have defaults. Return 0 on success. 2230 1.1 thorpej */ 2231 1.1 thorpej static const char ** 2232 1.41 dholland fixloc(const char *name, struct attr *attr, struct loclist *got) 2233 1.1 thorpej { 2234 1.41 dholland struct loclist *m, *n; 2235 1.1 thorpej int ord; 2236 1.1 thorpej const char **lp; 2237 1.1 thorpej int nmissing, nextra, nnodefault; 2238 1.1 thorpej char *mp, *ep, *ndp; 2239 1.1 thorpej char missing[1000], extra[1000], nodefault[1000]; 2240 1.1 thorpej static const char *nullvec[1]; 2241 1.1 thorpej 2242 1.1 thorpej /* 2243 1.1 thorpej * Look for all required locators, and number the given ones 2244 1.1 thorpej * according to the required order. While we are numbering, 2245 1.1 thorpej * set default values for defaulted locators. 2246 1.1 thorpej */ 2247 1.1 thorpej if (attr->a_loclen == 0) /* e.g., "at root" */ 2248 1.1 thorpej lp = nullvec; 2249 1.1 thorpej else 2250 1.65 christos lp = emalloc((size_t)(attr->a_loclen + 1) * sizeof(const char *)); 2251 1.41 dholland for (n = got; n != NULL; n = n->ll_next) 2252 1.41 dholland n->ll_num = -1; 2253 1.1 thorpej nmissing = 0; 2254 1.1 thorpej mp = missing; 2255 1.1 thorpej /* yes, this is O(mn), but m and n should be small */ 2256 1.41 dholland for (ord = 0, m = attr->a_locs; m != NULL; m = m->ll_next, ord++) { 2257 1.41 dholland for (n = got; n != NULL; n = n->ll_next) { 2258 1.41 dholland if (n->ll_name == m->ll_name) { 2259 1.41 dholland n->ll_num = ord; 2260 1.1 thorpej break; 2261 1.1 thorpej } 2262 1.1 thorpej } 2263 1.41 dholland if (n == NULL && m->ll_num == 0) { 2264 1.1 thorpej nmissing++; 2265 1.41 dholland mp = extend(mp, m->ll_name); 2266 1.1 thorpej } 2267 1.41 dholland lp[ord] = m->ll_string; 2268 1.1 thorpej } 2269 1.1 thorpej if (ord != attr->a_loclen) 2270 1.81 christos panic("%s: bad length", __func__); 2271 1.1 thorpej lp[ord] = NULL; 2272 1.1 thorpej nextra = 0; 2273 1.1 thorpej ep = extra; 2274 1.1 thorpej nnodefault = 0; 2275 1.1 thorpej ndp = nodefault; 2276 1.41 dholland for (n = got; n != NULL; n = n->ll_next) { 2277 1.41 dholland if (n->ll_num >= 0) { 2278 1.41 dholland if (n->ll_string != NULL) 2279 1.41 dholland lp[n->ll_num] = n->ll_string; 2280 1.41 dholland else if (lp[n->ll_num] == NULL) { 2281 1.1 thorpej nnodefault++; 2282 1.41 dholland ndp = extend(ndp, n->ll_name); 2283 1.1 thorpej } 2284 1.1 thorpej } else { 2285 1.1 thorpej nextra++; 2286 1.41 dholland ep = extend(ep, n->ll_name); 2287 1.1 thorpej } 2288 1.1 thorpej } 2289 1.1 thorpej if (nextra) { 2290 1.1 thorpej ep[-2] = 0; /* kill ", " */ 2291 1.27 christos cfgerror("%s: extraneous locator%s: %s", 2292 1.1 thorpej name, nextra > 1 ? "s" : "", extra); 2293 1.1 thorpej } 2294 1.1 thorpej if (nmissing) { 2295 1.1 thorpej mp[-2] = 0; 2296 1.27 christos cfgerror("%s: must specify %s", name, missing); 2297 1.1 thorpej } 2298 1.1 thorpej if (nnodefault) { 2299 1.1 thorpej ndp[-2] = 0; 2300 1.27 christos cfgerror("%s: cannot wildcard %s", name, nodefault); 2301 1.1 thorpej } 2302 1.1 thorpej if (nmissing || nnodefault) { 2303 1.1 thorpej free(lp); 2304 1.1 thorpej lp = NULL; 2305 1.1 thorpej } 2306 1.1 thorpej return (lp); 2307 1.1 thorpej } 2308 1.14 cube 2309 1.14 cube void 2310 1.14 cube setversion(int newver) 2311 1.14 cube { 2312 1.14 cube if (newver > CONFIG_VERSION) 2313 1.27 christos cfgerror("your sources require a newer version of config(1) " 2314 1.14 cube "-- please rebuild it."); 2315 1.14 cube else if (newver < CONFIG_MINVERSION) 2316 1.27 christos cfgerror("your sources are out of date -- please update."); 2317 1.14 cube else 2318 1.14 cube version = newver; 2319 1.14 cube } 2320