main.c revision 1.15 1 /* $NetBSD: main.c,v 1.15 2006/08/30 10:12:25 matt Exp $ */
2
3 /*
4 * Copyright (c) 1992, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * This software was developed by the Computer Systems Engineering group
8 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
9 * contributed to Berkeley.
10 *
11 * All advertising materials mentioning features or use of this software
12 * must display the following acknowledgement:
13 * This product includes software developed by the University of
14 * California, Lawrence Berkeley Laboratories.
15 *
16 * Redistribution and use in source and binary forms, with or without
17 * modification, are permitted provided that the following conditions
18 * are met:
19 * 1. Redistributions of source code must retain the above copyright
20 * notice, this list of conditions and the following disclaimer.
21 * 2. Redistributions in binary form must reproduce the above copyright
22 * notice, this list of conditions and the following disclaimer in the
23 * documentation and/or other materials provided with the distribution.
24 * 3. Neither the name of the University nor the names of its contributors
25 * may be used to endorse or promote products derived from this software
26 * without specific prior written permission.
27 *
28 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
29 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
32 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38 * SUCH DAMAGE.
39 *
40 * from: @(#)main.c 8.1 (Berkeley) 6/6/93
41 */
42
43 #if HAVE_NBTOOL_CONFIG_H
44 #include "nbtool_config.h"
45 #endif
46
47 #ifndef MAKE_BOOTSTRAP
48 #include <sys/cdefs.h>
49 #define COPYRIGHT(x) __COPYRIGHT(x)
50 #else
51 #define COPYRIGHT(x) static const char copyright[] = x
52 #endif
53
54 #ifndef lint
55 COPYRIGHT("@(#) Copyright (c) 1992, 1993\n\
56 The Regents of the University of California. All rights reserved.\n");
57 #endif /* not lint */
58
59 #include <sys/types.h>
60 #include <sys/stat.h>
61 #include <sys/param.h>
62 #include <sys/mman.h>
63 #include <paths.h>
64 #include <ctype.h>
65 #include <errno.h>
66 #include <fcntl.h>
67 #include <stdio.h>
68 #include <stdlib.h>
69 #include <string.h>
70 #include <unistd.h>
71 #include <vis.h>
72 #include <util.h>
73
74 #include "defs.h"
75 #include "sem.h"
76
77 #ifndef LINE_MAX
78 #define LINE_MAX 1024
79 #endif
80
81 int vflag; /* verbose output */
82 int Pflag; /* pack locators */
83
84 int yyparse(void);
85
86 #ifndef MAKE_BOOTSTRAP
87 extern int yydebug;
88 #endif
89
90 static struct hashtab *obsopttab;
91 static struct hashtab *mkopttab;
92 static struct nvlist **nextopt;
93 static struct nvlist **nextmkopt;
94 static struct nvlist **nextappmkopt;
95 static struct nvlist **nextfsopt;
96
97 static void usage(void);
98 static void dependopts(void);
99 static void do_depend(struct nvlist *);
100 static void stop(void);
101 static int do_option(struct hashtab *, struct nvlist ***,
102 const char *, const char *, const char *);
103 static int undo_option(struct hashtab *, struct nvlist **,
104 struct nvlist ***, const char *, const char *);
105 static int crosscheck(void);
106 static int badstar(void);
107 int main(int, char **);
108 static int mksymlinks(void);
109 static int mkident(void);
110 static int devbase_has_dead_instances(const char *, void *, void *);
111 static int devbase_has_any_instance(struct devbase *, int, int, int);
112 static int check_dead_devi(const char *, void *, void *);
113 static void kill_orphans(void);
114 static void do_kill_orphans(struct devbase *, struct attr *,
115 struct devbase *, int);
116 static int kill_orphans_cb(const char *, void *, void *);
117 static int cfcrosscheck(struct config *, const char *, struct nvlist *);
118 static const char *strtolower(const char *);
119 void defopt(struct hashtab *ht, const char *fname,
120 struct nvlist *opts, struct nvlist *deps, int obs);
121
122 #define LOGCONFIG_LARGE "INCLUDE_CONFIG_FILE"
123 #define LOGCONFIG_SMALL "INCLUDE_JUST_CONFIG"
124
125 static void logconfig_start(void);
126 static void logconfig_end(void);
127 static FILE *cfg;
128 static time_t cfgtime;
129
130 static int is_elf(const char *);
131 static int extract_config(const char *, const char *, int);
132
133 int badfilename(const char *fname);
134
135 const char *progname;
136
137 int
138 main(int argc, char **argv)
139 {
140 char *p, cname[20];
141 const char *last_component;
142 int pflag, xflag, ch, removeit;
143
144 setprogname(argv[0]);
145
146 pflag = 0;
147 xflag = 0;
148 while ((ch = getopt(argc, argv, "DPgpvb:s:x")) != -1) {
149 switch (ch) {
150
151 #ifndef MAKE_BOOTSTRAP
152 case 'D':
153 yydebug = 1;
154 break;
155 #endif
156
157 case 'P':
158 Pflag = 1;
159 break;
160
161 case 'g':
162 /*
163 * In addition to DEBUG, you probably wanted to
164 * set "options KGDB" and maybe others. We could
165 * do that for you, but you really should just
166 * put them in the config file.
167 */
168 (void)fprintf(stderr,
169 "config: -g is obsolete (use makeoptions DEBUG=\"-g\")\n");
170 usage();
171
172 case 'p':
173 /*
174 * Essentially the same as makeoptions PROF="-pg",
175 * but also changes the path from ../../compile/FOO
176 * to ../../compile/FOO.PROF; i.e., compile a
177 * profiling kernel based on a typical "regular"
178 * kernel.
179 *
180 * Note that if you always want profiling, you
181 * can (and should) use a "makeoptions" line.
182 */
183 pflag = 1;
184 break;
185
186 case 'v':
187 vflag = 1;
188 break;
189
190 case 'b':
191 builddir = optarg;
192 break;
193
194 case 's':
195 srcdir = optarg;
196 break;
197
198 case 'x':
199 xflag = 1;
200 break;
201
202 case '?':
203 default:
204 usage();
205 }
206 }
207
208 argc -= optind;
209 argv += optind;
210 if (argc > 1) {
211 usage();
212 }
213
214 if (xflag && (builddir != NULL || srcdir != NULL || Pflag || pflag ||
215 vflag)) {
216 (void)fprintf(stderr, "config: -x must be used alone\n");
217 exit(1);
218 }
219
220 if (xflag) {
221 #ifdef __NetBSD__
222 conffile = (argc == 1) ? argv[0] : _PATH_UNIX;
223 #else
224 if (argc == 0) {
225 (void)fprintf(stderr, "config: no kernel supplied\n");
226 exit(1);
227 }
228 #endif
229 if (!is_elf(conffile)) {
230 (void)fprintf(stderr,
231 "config: %s: not a binary kernel\n",
232 conffile);
233 exit(1);
234 }
235 if (!extract_config(conffile, "stdout", STDOUT_FILENO)) {
236 (void)fprintf(stderr,
237 "config: %s does not contain embedded "
238 "configuration data\n", conffile);
239 exit(2);
240 }
241 exit(0);
242 }
243
244 conffile = (argc == 1) ? argv[0] : "CONFIG";
245 if (firstfile(conffile)) {
246 (void)fprintf(stderr, "config: cannot read %s: %s\n",
247 conffile, strerror(errno));
248 exit(2);
249 }
250
251 /*
252 * Init variables.
253 */
254 minmaxusers = 1;
255 maxmaxusers = 10000;
256 initintern();
257 initfiles();
258 initsem();
259 ident = NULL;
260 devbasetab = ht_new();
261 devroottab = ht_new();
262 devatab = ht_new();
263 devitab = ht_new();
264 deaddevitab = ht_new();
265 selecttab = ht_new();
266 needcnttab = ht_new();
267 opttab = ht_new();
268 mkopttab = ht_new();
269 condmkopttab = ht_new();
270 fsopttab = ht_new();
271 deffstab = ht_new();
272 defopttab = ht_new();
273 defparamtab = ht_new();
274 defflagtab = ht_new();
275 optfiletab = ht_new();
276 obsopttab = ht_new();
277 bdevmtab = ht_new();
278 maxbdevm = 0;
279 cdevmtab = ht_new();
280 maxcdevm = 0;
281 nextopt = &options;
282 nextmkopt = &mkoptions;
283 nextappmkopt = &appmkoptions;
284 nextfsopt = &fsoptions;
285
286 /*
287 * Handle profiling (must do this before we try to create any
288 * files).
289 */
290 last_component = strrchr(conffile, '/');
291 last_component = (last_component) ? last_component + 1 : conffile;
292 if (pflag) {
293 p = emalloc(strlen(last_component) + 17);
294 (void)sprintf(p, "../compile/%s.PROF", last_component);
295 (void)addmkoption(intern("PROF"), "-pg");
296 (void)addoption(intern("GPROF"), NULL);
297 } else {
298 p = emalloc(strlen(last_component) + 13);
299 (void)sprintf(p, "../compile/%s", last_component);
300 }
301 defbuilddir = (argc == 0) ? "." : p;
302
303 removeit = 0;
304 if (is_elf(conffile)) {
305 const char *tmpdir;
306 int cfd;
307
308 if (builddir == NULL) {
309 (void)fprintf(stderr,
310 "config: build directory must be specified with "
311 "binary kernels\n");
312 exit(1);
313 }
314
315 /* Open temporary configuration file */
316 tmpdir = getenv("TMPDIR");
317 if (tmpdir == NULL)
318 tmpdir = "/tmp";
319 snprintf(cname, sizeof(cname), "%s/config.tmp.XXXXXX", tmpdir);
320 cfd = mkstemp(cname);
321 if (cfd == -1) {
322 fprintf(stderr, "config: cannot create %s: %s", cname,
323 strerror(errno));
324 exit(2);
325 }
326
327 printf("Using configuration data embedded in kernel...\n");
328 if (!extract_config(conffile, cname, cfd)) {
329 (void)fprintf(stderr,
330 "config: %s does not contain embedded "
331 "configuration data\n", conffile);
332 exit(2);
333 }
334
335 removeit = 1;
336 close(cfd);
337 firstfile(cname);
338 }
339
340 /*
341 * Parse config file (including machine definitions).
342 */
343 logconfig_start();
344 if (yyparse())
345 stop();
346 logconfig_end();
347
348 if (removeit)
349 unlink(cname);
350
351 /*
352 * Detect and properly ignore orphaned devices
353 */
354 kill_orphans();
355
356 /*
357 * Select devices and pseudo devices and their attributes
358 */
359 if (fixdevis())
360 stop();
361
362 /*
363 * Deal with option dependencies.
364 */
365 dependopts();
366
367 /*
368 * Fix (as in `set firmly in place') files.
369 */
370 if (fixfiles())
371 stop();
372
373 /*
374 * Fix objects and libraries.
375 */
376 if (fixobjects())
377 stop();
378
379 /*
380 * Fix device-majors.
381 */
382 if (fixdevsw())
383 stop();
384
385 /*
386 * Perform cross-checking.
387 */
388 if (maxusers == 0) {
389 if (defmaxusers) {
390 (void)printf("maxusers not specified; %d assumed\n",
391 defmaxusers);
392 maxusers = defmaxusers;
393 } else {
394 (void)fprintf(stderr,
395 "config: need \"maxusers\" line\n");
396 errors++;
397 }
398 }
399 if (fsoptions == NULL) {
400 (void)fprintf(stderr,
401 "config: need at least one \"file-system\" line\n");
402 errors++;
403 }
404 if (crosscheck() || errors)
405 stop();
406
407 /*
408 * Squeeze things down and finish cross-checks (STAR checks must
409 * run after packing).
410 */
411 pack();
412 if (badstar())
413 stop();
414
415 /*
416 * Ready to go. Build all the various files.
417 */
418 if (mksymlinks() || mkmakefile() || mkheaders() || mkswap() ||
419 mkioconf() || (do_devsw ? mkdevsw() : 0) || mkident())
420 stop();
421 (void)printf("Build directory is %s\n", builddir);
422 (void)printf("Don't forget to run \"make depend\"\n");
423 exit(0);
424 }
425
426 static void
427 usage(void)
428 {
429 (void)fputs("usage: config [-Ppv] [-s srcdir] [-b builddir] "
430 "[sysname]\n", stderr);
431 (void)fputs(" config -x [kernel-file]\n", stderr);
432 exit(1);
433 }
434
435 /*
436 * Set any options that are implied by other options.
437 */
438 static void
439 dependopts(void)
440 {
441 struct nvlist *nv, *opt;
442
443 for (nv = options; nv != NULL; nv = nv->nv_next) {
444 if ((opt = find_declared_option(nv->nv_name)) != NULL) {
445 for (opt = opt->nv_ptr; opt != NULL;
446 opt = opt->nv_next) {
447 do_depend(opt);
448 }
449 }
450 }
451
452 for (nv = fsoptions; nv != NULL; nv = nv->nv_next) {
453 if ((opt = find_declared_option(nv->nv_name)) != NULL) {
454 for (opt = opt->nv_ptr; opt != NULL;
455 opt = opt->nv_next) {
456 do_depend(opt);
457 }
458 }
459 }
460 }
461
462 static void
463 do_depend(struct nvlist *nv)
464 {
465 struct nvlist *nextnv;
466 struct attr *a;
467
468 if (nv != NULL && (nv->nv_flags & NV_DEPENDED) == 0) {
469 nv->nv_flags |= NV_DEPENDED;
470 /*
471 * If the dependency is an attribute, then just add
472 * it to the selecttab.
473 */
474 if ((a = ht_lookup(attrtab, nv->nv_name)) != NULL) {
475 if (a->a_iattr)
476 panic("do_depend(%s): dep `%s' is an iattr",
477 nv->nv_name, a->a_name);
478 expandattr(a, selectattr);
479 } else {
480 if (ht_lookup(opttab, nv->nv_name) == NULL)
481 addoption(nv->nv_name, NULL);
482 if ((nextnv =
483 find_declared_option(nv->nv_name)) != NULL)
484 do_depend(nextnv->nv_ptr);
485 }
486 }
487 }
488
489 /*
490 * Make a symlink for "machine" so that "#include <machine/foo.h>" works,
491 * and for the machine's CPU architecture, so that works as well.
492 */
493 static int
494 mksymlinks(void)
495 {
496 int ret;
497 char *p, buf[MAXPATHLEN];
498 const char *q;
499 struct nvlist *nv;
500
501 snprintf(buf, sizeof(buf), "arch/%s/include", machine);
502 p = sourcepath(buf);
503 ret = unlink("machine");
504 if (ret && errno != ENOENT)
505 (void)fprintf(stderr, "config: unlink(machine): %s\n",
506 strerror(errno));
507 ret = symlink(p, "machine");
508 if (ret)
509 (void)fprintf(stderr, "config: symlink(machine -> %s): %s\n",
510 p, strerror(errno));
511 free(p);
512
513 if (machinearch != NULL) {
514 snprintf(buf, sizeof(buf), "arch/%s/include", machinearch);
515 p = sourcepath(buf);
516 q = machinearch;
517 } else {
518 p = estrdup("machine");
519 q = machine;
520 }
521 ret = unlink(q);
522 if (ret && errno != ENOENT)
523 (void)fprintf(stderr, "config: unlink(%s): %s\n",
524 q, strerror(errno));
525 ret = symlink(p, q);
526 if (ret)
527 (void)fprintf(stderr, "config: symlink(%s -> %s): %s\n",
528 q, p, strerror(errno));
529 free(p);
530
531 for (nv = machinesubarches; nv != NULL; nv = nv->nv_next) {
532 q = nv->nv_name;
533 snprintf(buf, sizeof(buf), "arch/%s/include", q);
534 p = sourcepath(buf);
535 ret = unlink(q);
536 if (ret && errno != ENOENT)
537 (void)fprintf(stderr, "config: unlink(%s): %s\n",
538 q, strerror(errno));
539 ret = symlink(p, q);
540 if (ret)
541 (void)fprintf(stderr, "config: symlink(%s -> %s): %s\n",
542 q, p, strerror(errno));
543 free(p);
544 }
545
546 return (ret);
547 }
548
549 static __dead void
550 stop(void)
551 {
552 (void)fprintf(stderr, "*** Stop.\n");
553 exit(1);
554 }
555
556 static void
557 add_dependencies(struct nvlist *nv, struct nvlist *deps)
558 {
559 struct nvlist *dep;
560 struct attr *a;
561
562 /* Use nv_ptr to link any other options that are implied. */
563 nv->nv_ptr = deps;
564 for (dep = deps; dep != NULL; dep = dep->nv_next) {
565 /*
566 * If the dependency is an attribute, it must not
567 * be an interface attribute. Otherwise, it must
568 * be a previously declared option.
569 */
570 if ((a = ht_lookup(attrtab, dep->nv_name)) != NULL) {
571 if (a->a_iattr)
572 error("option `%s' dependency `%s' "
573 "is an interface attribute",
574 nv->nv_name, a->a_name);
575 } else if (OPT_OBSOLETE(dep->nv_name)) {
576 error("option `%s' dependency `%s' "
577 "is obsolete", nv->nv_name, dep->nv_name);
578 } else if (find_declared_option(dep->nv_name) == NULL) {
579 error("option `%s' dependency `%s' "
580 "is an unknown option",
581 nv->nv_name, dep->nv_name);
582 }
583 }
584 }
585
586 /*
587 * Define one or more file systems. If file system options file name is
588 * specified, a preprocessor #define for that file system will be placed
589 * in that file. In this case, only one file system may be specified.
590 * Otherwise, no preprocessor #defines will be generated.
591 */
592 void
593 deffilesystem(const char *fname, struct nvlist *fses, struct nvlist *deps)
594 {
595 struct nvlist *nv;
596
597 /*
598 * Mark these options as ones to skip when creating the Makefile.
599 */
600 for (nv = fses; nv != NULL; nv = nv->nv_next) {
601 if (ht_insert(defopttab, nv->nv_name, nv)) {
602 error("file system or option `%s' already defined",
603 nv->nv_name);
604 return;
605 }
606
607 /*
608 * Also mark it as a valid file system, which may be
609 * used in "file-system" directives in the config
610 * file.
611 */
612 if (ht_insert(deffstab, nv->nv_name, nv))
613 panic("file system `%s' already in table?!",
614 nv->nv_name);
615
616 if (fname != NULL) {
617 /*
618 * Only one file system allowed in this case.
619 */
620 if (nv->nv_next != NULL) {
621 error("only one file system per option "
622 "file may be specified");
623 return;
624 }
625
626 if (ht_insert(optfiletab, fname, nv)) {
627 error("option file `%s' already exists",
628 fname);
629 return;
630 }
631 }
632
633 add_dependencies(nv, deps);
634 }
635 }
636
637 /*
638 * Sanity check a file name.
639 */
640 int
641 badfilename(const char *fname)
642 {
643 const char *n;
644
645 /*
646 * We're putting multiple options into one file. Sanity
647 * check the file name.
648 */
649 if (strchr(fname, '/') != NULL) {
650 error("option file name contains a `/'");
651 return 1;
652 }
653 if ((n = strrchr(fname, '.')) == NULL || strcmp(n, ".h") != 0) {
654 error("option file name does not end in `.h'");
655 return 1;
656 }
657 return 0;
658 }
659
660
661 /*
662 * Search for a defined option (defopt, filesystem, etc), and if found,
663 * return the option's struct nvlist.
664 */
665 struct nvlist *
666 find_declared_option(const char *name)
667 {
668 struct nvlist *option = NULL;
669
670 if ((option = ht_lookup(defopttab, name)) != NULL ||
671 (option = ht_lookup(defparamtab, name)) != NULL ||
672 (option = ht_lookup(defflagtab, name)) != NULL ||
673 (option = ht_lookup(fsopttab, name)) != NULL) {
674 return (option);
675 }
676
677 return (NULL);
678 }
679
680
681 /*
682 * Define one or more standard options. If an option file name is specified,
683 * place all options in one file with the specified name. Otherwise, create
684 * an option file for each option.
685 * record the option information in the specified table.
686 */
687 void
688 defopt(struct hashtab *ht, const char *fname, struct nvlist *opts,
689 struct nvlist *deps, int obs)
690 {
691 struct nvlist *nv, *nextnv, *oldnv;
692 struct attr *a;
693 const char *name;
694 char buf[500];
695
696 if (fname != NULL && badfilename(fname)) {
697 return;
698 }
699
700 /*
701 * Mark these options as ones to skip when creating the Makefile.
702 */
703 for (nv = opts; nv != NULL; nv = nextnv) {
704 nextnv = nv->nv_next;
705
706 /* An option name can be declared at most once. */
707 if (DEFINED_OPTION(nv->nv_name)) {
708 error("file system or option `%s' already defined",
709 nv->nv_name);
710 return;
711 }
712
713 if (ht_insert(ht, nv->nv_name, nv)) {
714 error("file system or option `%s' already defined",
715 nv->nv_name);
716 return;
717 }
718
719 if (fname == NULL) {
720 /*
721 * Each option will be going into its own file.
722 * Convert the option name to lower case. This
723 * lower case name will be used as the option
724 * file name.
725 */
726 (void) snprintf(buf, sizeof(buf), "opt_%s.h",
727 strtolower(nv->nv_name));
728 name = intern(buf);
729 } else {
730 name = fname;
731 }
732
733 add_dependencies(nv, deps);
734
735 /*
736 * Remove this option from the parameter list before adding
737 * it to the list associated with this option file.
738 */
739 nv->nv_next = NULL;
740
741 /*
742 * Flag as obsolete, if requested.
743 */
744 if (obs) {
745 nv->nv_flags |= NV_OBSOLETE;
746 (void)ht_insert(obsopttab, nv->nv_name, nv);
747 }
748
749 /*
750 * Add this option file if we haven't seen it yet.
751 * Otherwise, append to the list of options already
752 * associated with this file.
753 */
754 if ((oldnv = ht_lookup(optfiletab, name)) == NULL) {
755 (void)ht_insert(optfiletab, name, nv);
756 } else {
757 while (oldnv->nv_next != NULL)
758 oldnv = oldnv->nv_next;
759 oldnv->nv_next = nv;
760 }
761 }
762 }
763
764 /*
765 * Define one or more standard options. If an option file name is specified,
766 * place all options in one file with the specified name. Otherwise, create
767 * an option file for each option.
768 */
769 void
770 defoption(const char *fname, struct nvlist *opts, struct nvlist *deps)
771 {
772
773 warn("The use of `defopt' is deprecated");
774 defopt(defopttab, fname, opts, deps, 0);
775 }
776
777
778 /*
779 * Define an option for which a value is required.
780 */
781 void
782 defparam(const char *fname, struct nvlist *opts, struct nvlist *deps, int obs)
783 {
784
785 defopt(defparamtab, fname, opts, deps, obs);
786 }
787
788 /*
789 * Define an option which must not have a value, and which
790 * emits a "needs-flag" style output.
791 */
792 void
793 defflag(const char *fname, struct nvlist *opts, struct nvlist *deps, int obs)
794 {
795
796 defopt(defflagtab, fname, opts, deps, obs);
797 }
798
799
800 /*
801 * Add an option from "options FOO". Note that this selects things that
802 * are "optional foo".
803 */
804 void
805 addoption(const char *name, const char *value)
806 {
807 const char *n;
808 int is_fs, is_param, is_flag, is_opt, is_undecl, is_obs;
809
810 /*
811 * Figure out how this option was declared (if at all.)
812 * XXX should use "params" and "flags" in config.
813 * XXX crying out for a type field in a unified hashtab.
814 */
815 is_fs = OPT_FSOPT(name);
816 is_param = OPT_DEFPARAM(name);
817 is_opt = OPT_DEFOPT(name);
818 is_flag = OPT_DEFFLAG(name);
819 is_obs = OPT_OBSOLETE(name);
820 is_undecl = !DEFINED_OPTION(name);
821
822 /* Warn and pretend the user had not selected the option */
823 if (is_obs) {
824 warn("obsolete option `%s' will be ignored", name);
825 return;
826 }
827
828 /* Make sure this is not a defined file system. */
829 if (is_fs) {
830 error("`%s' is a defined file system", name);
831 return;
832 }
833 /* A defparam must have a value */
834 if (is_param && value == NULL) {
835 error("option `%s' must have a value", name);
836 return;
837 }
838 /* A defflag must not have a value */
839 if (is_flag && value != NULL) {
840 error("option `%s' must not have a value", name);
841 return;
842 }
843
844 if (is_undecl && vflag) {
845 warn("undeclared option `%s' added to IDENT", name);
846 }
847
848 if (do_option(opttab, &nextopt, name, value, "options"))
849 return;
850
851 /* make lowercase, then add to select table */
852 n = strtolower(name);
853 (void)ht_insert(selecttab, n, (void *)n);
854 }
855
856 void
857 deloption(const char *name)
858 {
859
860 if (undo_option(opttab, &options, &nextopt, name, "options"))
861 return;
862 if (undo_option(selecttab, NULL, NULL, strtolower(name), "options"))
863 return;
864 }
865
866 /*
867 * Add a file system option. This routine simply inserts the name into
868 * a list of valid file systems, which is used to validate the root
869 * file system type. The name is then treated like a standard option.
870 */
871 void
872 addfsoption(const char *name)
873 {
874 const char *n;
875
876 /* Make sure this is a defined file system. */
877 if (!OPT_FSOPT(name)) {
878 error("`%s' is not a defined file system", name);
879 return;
880 }
881
882 /*
883 * Convert to lower case. This will be used in the select
884 * table, to verify root file systems, and when the initial
885 * VFS list is created.
886 */
887 n = strtolower(name);
888
889 if (do_option(fsopttab, &nextfsopt, name, n, "file-system"))
890 return;
891
892 /*
893 * Add a lower-case version to the table for root file system
894 * verification.
895 */
896 if (ht_insert(fsopttab, n, (void *)n))
897 panic("addfsoption: already in table");
898
899 /* Add to select table. */
900 (void)ht_insert(selecttab, n, (void *)n);
901 }
902
903 void
904 delfsoption(const char *name)
905 {
906 const char *n;
907
908 n = strtolower(name);
909 if (undo_option(fsopttab, &fsoptions, &nextfsopt, name, "file-system"))
910 return;
911 if (undo_option(fsopttab, NULL, NULL, n, "file-system"))
912 return;
913 if (undo_option(selecttab, NULL, NULL, n, "file-system"))
914 return;
915 }
916
917 /*
918 * Add a "make" option.
919 */
920 void
921 addmkoption(const char *name, const char *value)
922 {
923
924 (void)do_option(mkopttab, &nextmkopt, name, value, "makeoptions");
925 }
926
927 void
928 delmkoption(const char *name)
929 {
930
931 (void)undo_option(mkopttab, &mkoptions, &nextmkopt, name,
932 "makeoptions");
933 }
934
935 /*
936 * Add an appending "make" option.
937 */
938 void
939 appendmkoption(const char *name, const char *value)
940 {
941 struct nvlist *nv;
942
943 nv = newnv(name, value, NULL, 0, NULL);
944 *nextappmkopt = nv;
945 nextappmkopt = &nv->nv_next;
946 }
947
948 /*
949 * Add a conditional appending "make" option.
950 */
951 void
952 appendcondmkoption(const char *selname, const char *name, const char *value)
953 {
954 struct nvlist *nv, *lnv;
955 const char *n;
956
957 n = strtolower(selname);
958 nv = newnv(name, value, NULL, 0, NULL);
959 if (ht_insert(condmkopttab, n, nv) == 0)
960 return;
961
962 if ((lnv = ht_lookup(condmkopttab, n)) == NULL)
963 panic("appendcondmkoption");
964 for (; lnv->nv_next != NULL; lnv = lnv->nv_next)
965 /* search for the last list element */;
966 lnv->nv_next = nv;
967 }
968
969 /*
970 * Add a name=value pair to an option list. The value may be NULL.
971 */
972 static int
973 do_option(struct hashtab *ht, struct nvlist ***nppp, const char *name,
974 const char *value, const char *type)
975 {
976 struct nvlist *nv;
977
978 /*
979 * If a defopt'ed or defflag'ed option was enabled but without
980 * an explicit value (always the case for defflag), supply a
981 * default value of 1, as for non-defopt options (where cc
982 * treats -DBAR as -DBAR=1.)
983 */
984 if ((OPT_DEFOPT(name) || OPT_DEFFLAG(name)) && value == NULL)
985 value = "1";
986
987 /* assume it will work */
988 nv = newnv(name, value, NULL, 0, NULL);
989 if (ht_insert(ht, name, nv) == 0) {
990 **nppp = nv;
991 *nppp = &nv->nv_next;
992 return (0);
993 }
994
995 /* oops, already got that option */
996 nvfree(nv);
997 if ((nv = ht_lookup(ht, name)) == NULL)
998 panic("do_option");
999 if (nv->nv_str != NULL && !OPT_FSOPT(name))
1000 error("already have %s `%s=%s'", type, name, nv->nv_str);
1001 else
1002 error("already have %s `%s'", type, name);
1003 return (1);
1004 }
1005
1006 /*
1007 * Remove a name from a hash table,
1008 * and optionally, a name=value pair from an option list.
1009 */
1010 static int
1011 undo_option(struct hashtab *ht, struct nvlist **npp,
1012 struct nvlist ***next, const char *name, const char *type)
1013 {
1014 struct nvlist *nv;
1015
1016 if (ht_remove(ht, name)) {
1017 error("%s `%s' is not defined", type, name);
1018 return (1);
1019 }
1020 if (npp == NULL)
1021 return (0);
1022
1023 for ( ; *npp != NULL; npp = &(*npp)->nv_next) {
1024 if ((*npp)->nv_name != name)
1025 continue;
1026 if (next != NULL && *next == &(*npp)->nv_next)
1027 *next = npp;
1028 nv = (*npp)->nv_next;
1029 nvfree(*npp);
1030 *npp = nv;
1031 return (0);
1032 }
1033 panic("%s `%s' is not defined in nvlist", type, name);
1034 return (1);
1035 }
1036
1037 /*
1038 * Return true if there is at least one instance of the given unit
1039 * on the given device attachment (or any units, if unit == WILD).
1040 */
1041 int
1042 deva_has_instances(struct deva *deva, int unit)
1043 {
1044 struct devi *i;
1045
1046 for (i = deva->d_ihead; i != NULL; i = i->i_asame)
1047 if (i->i_active == DEVI_ACTIVE &&
1048 (unit == WILD || unit == i->i_unit || i->i_unit == STAR))
1049 return (1);
1050 return (0);
1051 }
1052
1053 /*
1054 * Return true if there is at least one instance of the given unit
1055 * on the given base (or any units, if unit == WILD).
1056 */
1057 int
1058 devbase_has_instances(struct devbase *dev, int unit)
1059 {
1060 struct deva *da;
1061
1062 /*
1063 * Pseudo-devices are a little special. We consider them
1064 * to have instances only if they are both:
1065 *
1066 * 1. Included in this kernel configuration.
1067 *
1068 * 2. Have one or more interface attributes.
1069 */
1070 if (dev->d_ispseudo) {
1071 struct nvlist *nv;
1072 struct attr *a;
1073
1074 if (ht_lookup(devitab, dev->d_name) == NULL)
1075 return (0);
1076
1077 for (nv = dev->d_attrs; nv != NULL; nv = nv->nv_next) {
1078 a = nv->nv_ptr;
1079 if (a->a_iattr)
1080 return (1);
1081 }
1082 return (0);
1083 }
1084
1085 for (da = dev->d_ahead; da != NULL; da = da->d_bsame)
1086 if (deva_has_instances(da, unit))
1087 return (1);
1088 return (0);
1089 }
1090
1091 static int
1092 cfcrosscheck(struct config *cf, const char *what, struct nvlist *nv)
1093 {
1094 struct devbase *dev;
1095 struct devi *pd;
1096 int errs, devunit;
1097
1098 if (maxpartitions <= 0)
1099 panic("cfcrosscheck");
1100
1101 for (errs = 0; nv != NULL; nv = nv->nv_next) {
1102 if (nv->nv_name == NULL)
1103 continue;
1104 dev = ht_lookup(devbasetab, nv->nv_name);
1105 if (dev == NULL)
1106 panic("cfcrosscheck(%s)", nv->nv_name);
1107 if (has_attr(dev->d_attrs, s_ifnet))
1108 devunit = nv->nv_ifunit; /* XXX XXX XXX */
1109 else
1110 devunit = minor(nv->nv_int) / maxpartitions;
1111 if (devbase_has_instances(dev, devunit))
1112 continue;
1113 if (devbase_has_instances(dev, STAR) &&
1114 devunit >= dev->d_umax)
1115 continue;
1116 TAILQ_FOREACH(pd, &allpseudo, i_next) {
1117 if (pd->i_base == dev && devunit < dev->d_umax &&
1118 devunit >= 0)
1119 goto loop;
1120 }
1121 (void)fprintf(stderr,
1122 "%s:%d: %s says %s on %s, but there's no %s\n",
1123 conffile, cf->cf_lineno,
1124 cf->cf_name, what, nv->nv_str, nv->nv_str);
1125 errs++;
1126 loop:
1127 ;
1128 }
1129 return (errs);
1130 }
1131
1132 /*
1133 * Cross-check the configuration: make sure that each target device
1134 * or attribute (`at foo[0*?]') names at least one real device. Also
1135 * see that the root and dump devices for all configurations are there.
1136 */
1137 int
1138 crosscheck(void)
1139 {
1140 struct config *cf;
1141 int errs;
1142
1143 errs = 0;
1144 if (TAILQ_EMPTY(&allcf)) {
1145 (void)fprintf(stderr, "%s has no configurations!\n",
1146 conffile);
1147 errs++;
1148 }
1149 TAILQ_FOREACH(cf, &allcf, cf_next) {
1150 if (cf->cf_root != NULL) { /* i.e., not root on ? */
1151 errs += cfcrosscheck(cf, "root", cf->cf_root);
1152 errs += cfcrosscheck(cf, "dumps", cf->cf_dump);
1153 }
1154 }
1155 return (errs);
1156 }
1157
1158 /*
1159 * Check to see if there is a *'d unit with a needs-count file.
1160 */
1161 int
1162 badstar(void)
1163 {
1164 struct devbase *d;
1165 struct deva *da;
1166 struct devi *i;
1167 int errs, n;
1168
1169 errs = 0;
1170 TAILQ_FOREACH(d, &allbases, d_next) {
1171 for (da = d->d_ahead; da != NULL; da = da->d_bsame)
1172 for (i = da->d_ihead; i != NULL; i = i->i_asame) {
1173 if (i->i_unit == STAR)
1174 goto aybabtu;
1175 }
1176 continue;
1177 aybabtu:
1178 if (ht_lookup(needcnttab, d->d_name)) {
1179 (void)fprintf(stderr,
1180 "config: %s's cannot be *'d until its driver is fixed\n",
1181 d->d_name);
1182 errs++;
1183 continue;
1184 }
1185 for (n = 0; i != NULL; i = i->i_alias)
1186 if (!i->i_collapsed)
1187 n++;
1188 if (n < 1)
1189 panic("badstar() n<1");
1190 }
1191 return (errs);
1192 }
1193
1194 /*
1195 * Verify/create builddir if necessary, change to it, and verify srcdir.
1196 * This will be called when we see the first include.
1197 */
1198 void
1199 setupdirs(void)
1200 {
1201 struct stat st;
1202
1203 /* srcdir must be specified if builddir is not specified or if
1204 * no configuration filename was specified. */
1205 if ((builddir || strcmp(defbuilddir, ".") == 0) && !srcdir) {
1206 error("source directory must be specified");
1207 exit(1);
1208 }
1209
1210 if (srcdir == NULL)
1211 srcdir = "../../../..";
1212 if (builddir == NULL)
1213 builddir = defbuilddir;
1214
1215 if (stat(builddir, &st) != 0) {
1216 if (mkdir(builddir, 0777)) {
1217 (void)fprintf(stderr, "config: cannot create %s: %s\n",
1218 builddir, strerror(errno));
1219 exit(2);
1220 }
1221 } else if (!S_ISDIR(st.st_mode)) {
1222 (void)fprintf(stderr, "config: %s is not a directory\n",
1223 builddir);
1224 exit(2);
1225 }
1226 if (chdir(builddir) != 0) {
1227 (void)fprintf(stderr, "config: cannot change to %s\n",
1228 builddir);
1229 exit(2);
1230 }
1231 if (stat(srcdir, &st) != 0 || !S_ISDIR(st.st_mode)) {
1232 (void)fprintf(stderr, "config: %s is not a directory\n",
1233 srcdir);
1234 exit(2);
1235 }
1236 }
1237
1238 /*
1239 * Write identifier from "ident" directive into file, for
1240 * newvers.sh to pick it up.
1241 */
1242 int
1243 mkident(void)
1244 {
1245 FILE *fp;
1246 int error = 0;
1247
1248 (void)unlink("ident");
1249
1250 if (ident == NULL)
1251 return (0);
1252
1253 if ((fp = fopen("ident", "w")) == NULL) {
1254 (void)fprintf(stderr, "config: cannot write ident: %s\n",
1255 strerror(errno));
1256 return (1);
1257 }
1258 if (vflag)
1259 (void)printf("using ident '%s'\n", ident);
1260 if (fprintf(fp, "%s\n", ident) < 0)
1261 error = 1;
1262 (void)fclose(fp);
1263
1264 return error;
1265 }
1266
1267 void
1268 logconfig_start(void)
1269 {
1270 extern FILE *yyin;
1271 char line[1024];
1272 const char *tmpdir;
1273 struct stat st;
1274 int fd;
1275
1276 if (yyin == NULL || fstat(fileno(yyin), &st) == -1)
1277 return;
1278 cfgtime = st.st_mtime;
1279
1280 tmpdir = getenv("TMPDIR");
1281 if (tmpdir == NULL)
1282 tmpdir = "/tmp";
1283 snprintf(line, sizeof(line), "%s/config.tmp.XXXXXX", tmpdir);
1284 if ((fd = mkstemp(line)) == -1 ||
1285 (cfg = fdopen(fd, "r+")) == NULL) {
1286 if (fd != -1) {
1287 unlink(line);
1288 close(fd);
1289 }
1290 cfg = NULL;
1291 return;
1292 }
1293 unlink(line);
1294
1295 (void)fprintf(cfg, "#include \"opt_config.h\"\n");
1296 (void)fprintf(cfg, "\n");
1297 (void)fprintf(cfg, "/*\n");
1298 (void)fprintf(cfg, " * Add either (or both) of\n");
1299 (void)fprintf(cfg, " *\n");
1300 (void)fprintf(cfg, " *\toptions %s\n", LOGCONFIG_LARGE);
1301 (void)fprintf(cfg, " *\toptions %s\n", LOGCONFIG_SMALL);
1302 (void)fprintf(cfg, " *\n");
1303 (void)fprintf(cfg,
1304 " * to your kernel config file to embed it in the resulting\n");
1305 (void)fprintf(cfg,
1306 " * kernel. The latter option does not include files that are\n");
1307 (void)fprintf(cfg,
1308 " * included (recursively) by your config file. The embedded\n");
1309 (void)fprintf(cfg,
1310 " * data be extracted by using the command:\n");
1311 (void)fprintf(cfg, " *\n");
1312 (void)fprintf(cfg,
1313 " *\tstrings netbsd | sed -n 's/^_CFG_//p' | unvis\n");
1314 (void)fprintf(cfg, " */\n");
1315 (void)fprintf(cfg, "\n");
1316 (void)fprintf(cfg, "#ifdef CONFIG_FILE\n");
1317 (void)fprintf(cfg, "#if defined(%s) || defined(%s)\n\n",
1318 LOGCONFIG_LARGE, LOGCONFIG_SMALL);
1319 (void)fprintf(cfg,
1320 "static const char config[]\n#ifdef __vax__\n"
1321 "\t__attribute__((__unused__))\n#else\n"
1322 "\t__attribute__((__used__))\n#endif\n\t=\n\n");
1323
1324 (void)fprintf(cfg, "#ifdef %s\n\n", LOGCONFIG_LARGE);
1325 (void)fprintf(cfg, "\"_CFG_### START CONFIG FILE \\\"%s\\\"\\n\"\n\n",
1326 conffile);
1327 (void)fprintf(cfg, "#endif /* %s */\n\n", LOGCONFIG_LARGE);
1328
1329 logconfig_include(yyin, NULL);
1330
1331 (void)fprintf(cfg, "#ifdef %s\n\n", LOGCONFIG_LARGE);
1332 (void)fprintf(cfg, "\"_CFG_### END CONFIG FILE \\\"%s\\\"\\n\"\n",
1333 conffile);
1334
1335 rewind(yyin);
1336 }
1337
1338 void
1339 logconfig_include(FILE *cf, const char *filename)
1340 {
1341 char line[1024], in[2048], *out;
1342 struct stat st;
1343 int missingeol;
1344
1345 if (!cfg)
1346 return;
1347
1348 missingeol = 0;
1349 if (fstat(fileno(cf), &st) == -1)
1350 return;
1351 if (cfgtime < st.st_mtime)
1352 cfgtime = st.st_mtime;
1353
1354 if (filename)
1355 (void)fprintf(cfg,
1356 "\"_CFG_### (included from \\\"%s\\\")\\n\"\n",
1357 filename);
1358 while (fgets(line, sizeof(line), cf) != NULL) {
1359 missingeol = 1;
1360 (void)fprintf(cfg, "\"_CFG_");
1361 if (filename)
1362 (void)fprintf(cfg, "###> ");
1363 strvis(in, line, VIS_TAB);
1364 for (out = in; *out; out++)
1365 switch (*out) {
1366 case '\n':
1367 (void)fprintf(cfg, "\\n\"\n");
1368 missingeol = 0;
1369 break;
1370 case '"': case '\\':
1371 (void)fputc('\\', cfg);
1372 /* FALLTHROUGH */
1373 default:
1374 (void)fputc(*out, cfg);
1375 break;
1376 }
1377 }
1378 if (missingeol) {
1379 (void)fprintf(cfg, "\\n\"\n");
1380 (void)fprintf(stderr,
1381 "config: %s: newline missing at EOF\n",
1382 filename != NULL ? filename : conffile);
1383 }
1384 if (filename)
1385 (void)fprintf(cfg, "\"_CFG_### (end include \\\"%s\\\")\\n\"\n",
1386 filename);
1387
1388 rewind(cf);
1389 }
1390
1391 void
1392 logconfig_end(void)
1393 {
1394 char line[1024];
1395 FILE *fp;
1396 struct stat st;
1397
1398 if (!cfg)
1399 return;
1400
1401 (void)fprintf(cfg, "#endif /* %s */\n", LOGCONFIG_LARGE);
1402 (void)fprintf(cfg, ";\n");
1403 (void)fprintf(cfg, "#endif /* %s || %s */\n",
1404 LOGCONFIG_LARGE, LOGCONFIG_SMALL);
1405 (void)fprintf(cfg, "#endif /* CONFIG_FILE */\n");
1406 rewind(cfg);
1407
1408 if (stat("config_file.h", &st) != -1) {
1409 if (cfgtime < st.st_mtime) {
1410 fclose(cfg);
1411 return;
1412 }
1413 }
1414
1415 fp = fopen("config_file.h", "w");
1416 if(!fp) {
1417 (void)fprintf(stderr,
1418 "config: cannot write to \"config_file.h\"\n");
1419 exit(1);
1420 }
1421
1422 while (fgets(line, sizeof(line), cfg) != NULL)
1423 fputs(line, fp);
1424 fclose(fp);
1425 fclose(cfg);
1426 }
1427
1428 static const char *
1429 strtolower(const char *name)
1430 {
1431 const char *n;
1432 char *p, low[500];
1433 unsigned char c;
1434
1435 for (n = name, p = low; (c = *n) != '\0'; n++)
1436 *p++ = isupper(c) ? tolower(c) : c;
1437 *p = 0;
1438 return (intern(low));
1439 }
1440
1441 static int
1442 is_elf(const char *file)
1443 {
1444 int kernel;
1445 char hdr[4];
1446
1447 kernel = open(file, O_RDONLY);
1448 if (kernel == -1) {
1449 fprintf(stderr, "config: cannot open %s: %s\n", file,
1450 strerror(errno));
1451 exit(2);
1452 }
1453 if (read(kernel, hdr, 4) == -1) {
1454 fprintf(stderr, "config: cannot read from %s: %s\n", file,
1455 strerror(errno));
1456 exit(2);
1457 }
1458 close(kernel);
1459
1460 return memcmp("\177ELF", hdr, 4) == 0 ? 1 : 0;
1461 }
1462
1463 static int
1464 extract_config(const char *kname, const char *cname, int cfd)
1465 {
1466 char *ptr;
1467 int found, kfd, i;
1468 struct stat st;
1469
1470 found = 0;
1471
1472 /* mmap(2) binary kernel */
1473 kfd = open(conffile, O_RDONLY);
1474 if (kfd == -1) {
1475 fprintf(stderr, "config: cannot open %s: %s\n", kname,
1476 strerror(errno));
1477 exit(2);
1478 }
1479 if ((fstat(kfd, &st) == -1)) {
1480 fprintf(stderr, "config: cannot stat %s: %s\n", kname,
1481 strerror(errno));
1482 exit(2);
1483 }
1484 ptr = (char *)mmap(0, st.st_size, PROT_READ, MAP_FILE | MAP_SHARED,
1485 kfd, 0);
1486 if (ptr == MAP_FAILED) {
1487 fprintf(stderr, "config: cannot mmap %s: %s\n", kname,
1488 strerror(errno));
1489 exit(2);
1490 }
1491
1492 /* Scan mmap(2)'ed region, extracting kernel configuration */
1493 for (i = 0; i < st.st_size; i++) {
1494 if ((*ptr == '_') && (st.st_size - i > 5) && memcmp(ptr,
1495 "_CFG_", 5) == 0) {
1496 /* Line found */
1497 char *oldptr, line[LINE_MAX + 1], uline[LINE_MAX + 1];
1498 int j;
1499
1500 found = 1;
1501
1502 oldptr = (ptr += 5);
1503 while (*ptr != '\n' && *ptr != '\0') ptr++;
1504 if (ptr - oldptr > LINE_MAX) {
1505 fprintf(stderr, "config: line too long\n");
1506 exit(2);
1507 }
1508 i += ptr - oldptr + 5;
1509 memcpy(line, oldptr, (ptr - oldptr));
1510 line[ptr - oldptr] = '\0';
1511 j = strunvis(uline, line);
1512 if (j == -1) {
1513 fprintf(stderr, "config: unvis: invalid "
1514 "encoded sequence\n");
1515 exit(2);
1516 }
1517 uline[j] = '\n';
1518 if (write(cfd, uline, j + 1) == -1) {
1519 fprintf(stderr, "config: cannot write to %s: "
1520 "%s\n", cname, strerror(errno));
1521 exit(2);
1522 }
1523 } else ptr++;
1524 }
1525
1526 close(kfd);
1527
1528 return found;
1529 }
1530
1531 struct dhdi_params {
1532 struct devbase *d;
1533 int unit;
1534 int level;
1535 };
1536
1537 static int
1538 devbase_has_dead_instances(const char *key, void *value, void *aux)
1539 {
1540 struct devi *i;
1541 struct dhdi_params *dhdi = aux;
1542
1543 for (i = value; i != NULL; i = i->i_alias)
1544 if (i->i_base == dhdi->d &&
1545 (dhdi->unit == WILD || dhdi->unit == i->i_unit ||
1546 i->i_unit == STAR) &&
1547 i->i_level >= dhdi->level)
1548 return 1;
1549 return 0;
1550 }
1551
1552 /*
1553 * This is almost the same as devbase_has_instances, except it
1554 * may have special considerations regarding ignored instances.
1555 */
1556
1557 static int
1558 devbase_has_any_instance(struct devbase *dev, int unit, int state, int level)
1559 {
1560 struct deva *da;
1561 struct devi *i;
1562
1563 if (dev->d_ispseudo) {
1564 if (dev->d_ihead != NULL)
1565 return 1;
1566 else if (state != DEVI_IGNORED)
1567 return 0;
1568 if ((i = ht_lookup(deaddevitab, dev->d_name)) == NULL)
1569 return 0;
1570 return (i->i_level >= level);
1571 }
1572
1573 for (da = dev->d_ahead; da != NULL; da = da->d_bsame)
1574 for (i = da->d_ihead; i != NULL; i = i->i_asame)
1575 if ((i->i_active == DEVI_ACTIVE ||
1576 i->i_active == state) &&
1577 (unit == WILD || unit == i->i_unit ||
1578 i->i_unit == STAR))
1579 return 1;
1580
1581 if (state == DEVI_IGNORED) {
1582 struct dhdi_params dhdi = { dev, unit, level };
1583 /* also check dead devices */
1584 return ht_enumerate(deaddevitab, devbase_has_dead_instances,
1585 &dhdi);
1586 }
1587
1588 return 0;
1589 }
1590
1591 /*
1592 * check_dead_devi(), used with ht_enumerate, checks if any of the removed
1593 * device instances would have been a valid instance considering the devbase,
1594 * the parent device and the interface attribute.
1595 *
1596 * In other words, for a non-active device, it checks if children would be
1597 * actual orphans or the result of a negative statement in the config file.
1598 */
1599
1600 struct cdd_params {
1601 struct devbase *d;
1602 struct attr *at;
1603 struct devbase *parent;
1604 };
1605
1606 static int
1607 check_dead_devi(const char *key, void *value, void *aux)
1608 {
1609 struct cdd_params *cdd = aux;
1610 struct devi *i = value;
1611 struct pspec *p;
1612
1613 if (i->i_base != cdd->d)
1614 return 0;
1615
1616 for (; i != NULL; i = i->i_alias) {
1617 p = i->i_pspec;
1618 if ((p == NULL && cdd->at == NULL) ||
1619 (p != NULL && p->p_iattr == cdd->at &&
1620 (p->p_atdev == NULL || p->p_atdev == cdd->parent))) {
1621 if (p != NULL &&
1622 !devbase_has_any_instance(cdd->parent, p->p_atunit,
1623 DEVI_IGNORED, i->i_level))
1624 return 0;
1625 else
1626 return 1;
1627 }
1628 }
1629 return 0;
1630 }
1631
1632 static void
1633 do_kill_orphans(struct devbase *d, struct attr *at, struct devbase *parent,
1634 int state)
1635 {
1636 struct nvlist *nv, *nv1;
1637 struct attr *a;
1638 struct devi *i, *j = NULL;
1639 struct pspec *p;
1640 int active = 0;
1641
1642 /*
1643 * A pseudo-device will always attach at root, and if it has an
1644 * instance (it cannot have more than one), it is enough to consider
1645 * it active, as there is no real attachment.
1646 *
1647 * A pseudo device can never be marked DEVI_IGNORED.
1648 */
1649 if (d->d_ispseudo) {
1650 if (d->d_ihead != NULL)
1651 d->d_ihead->i_active = active = DEVI_ACTIVE;
1652 else {
1653 if (ht_lookup(deaddevitab, d->d_name) != NULL)
1654 active = DEVI_IGNORED;
1655 else
1656 return;
1657 }
1658 } else {
1659 int seen = 0;
1660
1661 for (i = d->d_ihead; i != NULL; i = i->i_bsame) {
1662 for (j = i; j != NULL; j = j->i_alias) {
1663 p = j->i_pspec;
1664 if ((p == NULL && at == NULL) ||
1665 (p != NULL && p->p_iattr == at &&
1666 (p->p_atdev == NULL ||
1667 p->p_atdev == parent))) {
1668 if (p != NULL &&
1669 !devbase_has_any_instance(parent,
1670 p->p_atunit, state, j->i_level))
1671 continue;
1672 /*
1673 * There are Fry-like devices which can
1674 * be their own grand-parent (or even
1675 * parent, like uhub). We don't want
1676 * to loop, so if we've already reached
1677 * an instance for one reason or
1678 * another, stop there.
1679 */
1680 if (j->i_active == DEVI_ACTIVE ||
1681 j->i_active == state) {
1682 /*
1683 * Device has already been
1684 * seen. However it might
1685 * have siblings who still
1686 * have to be activated or
1687 * orphaned.
1688 */
1689 seen = 1;
1690 continue;
1691 }
1692 j->i_active = active = state;
1693 if (p != NULL)
1694 p->p_active = state;
1695 }
1696 }
1697 }
1698 /*
1699 * If we've been there but have made no change, stop.
1700 */
1701 if (seen && !active)
1702 return;
1703 if (!active) {
1704 struct cdd_params cdd = { d, at, parent };
1705 /* Look for a matching dead devi */
1706 if (ht_enumerate(deaddevitab, check_dead_devi, &cdd) &&
1707 d != parent)
1708 /*
1709 * That device had its instances removed.
1710 * Continue the loop marking descendants
1711 * with DEVI_IGNORED instead of DEVI_ACTIVE.
1712 *
1713 * There is one special case for devices that
1714 * are their own parent: if that instance is
1715 * removed (e.g., no uhub* at uhub?), we don't
1716 * have to continue looping.
1717 */
1718 active = DEVI_IGNORED;
1719 else
1720 return;
1721 }
1722 }
1723
1724 for (nv = d->d_attrs; nv != NULL; nv = nv->nv_next) {
1725 a = nv->nv_ptr;
1726 for (nv1 = a->a_devs; nv1 != NULL; nv1 = nv1->nv_next)
1727 do_kill_orphans(nv1->nv_ptr, a, d, active);
1728 }
1729 }
1730
1731 static int
1732 kill_orphans_cb(const char *key, void *value, void *aux)
1733 {
1734 do_kill_orphans((struct devbase *)value, NULL, NULL, DEVI_ACTIVE);
1735 return 0;
1736 }
1737
1738 static void
1739 kill_orphans()
1740 {
1741 ht_enumerate(devroottab, kill_orphans_cb, NULL);
1742 }
1743