main.c revision 1.18 1 /* $NetBSD: main.c,v 1.18 2006/10/29 23:00:44 uwe 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 <err.h>
66 #include <errno.h>
67 #include <fcntl.h>
68 #include <stdio.h>
69 #include <stdlib.h>
70 #include <string.h>
71 #include <unistd.h>
72 #include <vis.h>
73 #include <util.h>
74
75 #include "defs.h"
76 #include "sem.h"
77
78 #ifndef LINE_MAX
79 #define LINE_MAX 1024
80 #endif
81
82 int vflag; /* verbose output */
83 int Pflag; /* pack locators */
84
85 int yyparse(void);
86
87 #ifndef MAKE_BOOTSTRAP
88 extern int yydebug;
89 #endif
90
91 static struct hashtab *obsopttab;
92 static struct hashtab *mkopttab;
93 static struct nvlist **nextopt;
94 static struct nvlist **nextmkopt;
95 static struct nvlist **nextappmkopt;
96 static struct nvlist **nextfsopt;
97
98 static void usage(void);
99 static void dependopts(void);
100 static void do_depend(struct nvlist *);
101 static void stop(void);
102 static int do_option(struct hashtab *, struct nvlist ***,
103 const char *, const char *, const char *);
104 static int undo_option(struct hashtab *, struct nvlist **,
105 struct nvlist ***, const char *, const char *);
106 static int crosscheck(void);
107 static int badstar(void);
108 int main(int, char **);
109 static int mksymlinks(void);
110 static int mkident(void);
111 static int devbase_has_dead_instances(const char *, void *, void *);
112 static int devbase_has_any_instance(struct devbase *, int, int, int);
113 static int check_dead_devi(const char *, void *, void *);
114 static void kill_orphans(void);
115 static void do_kill_orphans(struct devbase *, struct attr *,
116 struct devbase *, int);
117 static int kill_orphans_cb(const char *, void *, void *);
118 static int cfcrosscheck(struct config *, const char *, struct nvlist *);
119 static const char *strtolower(const char *);
120 void defopt(struct hashtab *ht, const char *fname,
121 struct nvlist *opts, struct nvlist *deps, int obs);
122
123 #define LOGCONFIG_LARGE "INCLUDE_CONFIG_FILE"
124 #define LOGCONFIG_SMALL "INCLUDE_JUST_CONFIG"
125
126 static void logconfig_start(void);
127 static void logconfig_end(void);
128 static FILE *cfg;
129 static time_t cfgtime;
130
131 static int is_elf(const char *);
132 static int extract_config(const char *, const char *, int);
133
134 int badfilename(const char *fname);
135
136 const char *progname;
137
138 int
139 main(int argc, char **argv)
140 {
141 char *p, cname[20];
142 const char *last_component;
143 int pflag, xflag, ch, removeit;
144
145 setprogname(argv[0]);
146
147 pflag = 0;
148 xflag = 0;
149 while ((ch = getopt(argc, argv, "DPgpvb:s:x")) != -1) {
150 switch (ch) {
151
152 #ifndef MAKE_BOOTSTRAP
153 case 'D':
154 yydebug = 1;
155 break;
156 #endif
157
158 case 'P':
159 Pflag = 1;
160 break;
161
162 case 'g':
163 /*
164 * In addition to DEBUG, you probably wanted to
165 * set "options KGDB" and maybe others. We could
166 * do that for you, but you really should just
167 * put them in the config file.
168 */
169 (void)fprintf(stderr,
170 "config: -g is obsolete (use makeoptions DEBUG=\"-g\")\n");
171 usage();
172
173 case 'p':
174 /*
175 * Essentially the same as makeoptions PROF="-pg",
176 * but also changes the path from ../../compile/FOO
177 * to ../../compile/FOO.PROF; i.e., compile a
178 * profiling kernel based on a typical "regular"
179 * kernel.
180 *
181 * Note that if you always want profiling, you
182 * can (and should) use a "makeoptions" line.
183 */
184 pflag = 1;
185 break;
186
187 case 'v':
188 vflag = 1;
189 break;
190
191 case 'b':
192 builddir = optarg;
193 break;
194
195 case 's':
196 srcdir = optarg;
197 break;
198
199 case 'x':
200 xflag = 1;
201 break;
202
203 case '?':
204 default:
205 usage();
206 }
207 }
208
209 argc -= optind;
210 argv += optind;
211 if (argc > 1) {
212 usage();
213 }
214
215 if (xflag && (builddir != NULL || srcdir != NULL || Pflag || pflag ||
216 vflag)) {
217 (void)fprintf(stderr, "config: -x must be used alone\n");
218 exit(1);
219 }
220
221 if (xflag) {
222 #ifdef __NetBSD__
223 conffile = (argc == 1) ? argv[0] : _PATH_UNIX;
224 #else
225 if (argc == 0) {
226 (void)fprintf(stderr, "config: no kernel supplied\n");
227 exit(1);
228 }
229 #endif
230 if (!is_elf(conffile)) {
231 (void)fprintf(stderr,
232 "config: %s: not a binary kernel\n",
233 conffile);
234 exit(1);
235 }
236 if (!extract_config(conffile, "stdout", STDOUT_FILENO)) {
237 (void)fprintf(stderr,
238 "config: %s does not contain embedded "
239 "configuration data\n", conffile);
240 exit(2);
241 }
242 exit(0);
243 }
244
245 conffile = (argc == 1) ? argv[0] : "CONFIG";
246 if (firstfile(conffile)) {
247 (void)fprintf(stderr, "config: cannot read %s: %s\n",
248 conffile, strerror(errno));
249 exit(2);
250 }
251
252 /*
253 * Init variables.
254 */
255 minmaxusers = 1;
256 maxmaxusers = 10000;
257 initintern();
258 initfiles();
259 initsem();
260 ident = NULL;
261 devbasetab = ht_new();
262 devroottab = ht_new();
263 devatab = ht_new();
264 devitab = ht_new();
265 deaddevitab = ht_new();
266 selecttab = ht_new();
267 needcnttab = ht_new();
268 opttab = ht_new();
269 mkopttab = ht_new();
270 condmkopttab = ht_new();
271 fsopttab = ht_new();
272 deffstab = ht_new();
273 defopttab = ht_new();
274 defparamtab = ht_new();
275 defflagtab = ht_new();
276 optfiletab = ht_new();
277 obsopttab = ht_new();
278 bdevmtab = ht_new();
279 maxbdevm = 0;
280 cdevmtab = ht_new();
281 maxcdevm = 0;
282 nextopt = &options;
283 nextmkopt = &mkoptions;
284 nextappmkopt = &appmkoptions;
285 nextfsopt = &fsoptions;
286
287 /*
288 * Handle profiling (must do this before we try to create any
289 * files).
290 */
291 last_component = strrchr(conffile, '/');
292 last_component = (last_component) ? last_component + 1 : conffile;
293 if (pflag) {
294 p = emalloc(strlen(last_component) + 17);
295 (void)sprintf(p, "../compile/%s.PROF", last_component);
296 (void)addmkoption(intern("PROF"), "-pg");
297 (void)addoption(intern("GPROF"), NULL);
298 } else {
299 p = emalloc(strlen(last_component) + 13);
300 (void)sprintf(p, "../compile/%s", last_component);
301 }
302 defbuilddir = (argc == 0) ? "." : p;
303
304 removeit = 0;
305 if (is_elf(conffile)) {
306 const char *tmpdir;
307 int cfd;
308
309 if (builddir == NULL) {
310 (void)fprintf(stderr,
311 "config: build directory must be specified with "
312 "binary kernels\n");
313 exit(1);
314 }
315
316 /* Open temporary configuration file */
317 tmpdir = getenv("TMPDIR");
318 if (tmpdir == NULL)
319 tmpdir = "/tmp";
320 snprintf(cname, sizeof(cname), "%s/config.tmp.XXXXXX", tmpdir);
321 cfd = mkstemp(cname);
322 if (cfd == -1) {
323 fprintf(stderr, "config: cannot create %s: %s", cname,
324 strerror(errno));
325 exit(2);
326 }
327
328 printf("Using configuration data embedded in kernel...\n");
329 if (!extract_config(conffile, cname, cfd)) {
330 (void)fprintf(stderr,
331 "config: %s does not contain embedded "
332 "configuration data\n", conffile);
333 exit(2);
334 }
335
336 removeit = 1;
337 close(cfd);
338 firstfile(cname);
339 }
340
341 /*
342 * Parse config file (including machine definitions).
343 */
344 logconfig_start();
345 if (yyparse())
346 stop();
347 logconfig_end();
348
349 if (removeit)
350 unlink(cname);
351
352 /*
353 * Detect and properly ignore orphaned devices
354 */
355 kill_orphans();
356
357 /*
358 * Select devices and pseudo devices and their attributes
359 */
360 if (fixdevis())
361 stop();
362
363 /*
364 * Deal with option dependencies.
365 */
366 dependopts();
367
368 /*
369 * Fix (as in `set firmly in place') files.
370 */
371 if (fixfiles())
372 stop();
373
374 /*
375 * Fix objects and libraries.
376 */
377 if (fixobjects())
378 stop();
379
380 /*
381 * Fix device-majors.
382 */
383 if (fixdevsw())
384 stop();
385
386 /*
387 * Perform cross-checking.
388 */
389 if (maxusers == 0) {
390 if (defmaxusers) {
391 (void)printf("maxusers not specified; %d assumed\n",
392 defmaxusers);
393 maxusers = defmaxusers;
394 } else {
395 (void)fprintf(stderr,
396 "config: need \"maxusers\" line\n");
397 errors++;
398 }
399 }
400 if (fsoptions == NULL) {
401 (void)fprintf(stderr,
402 "config: need at least one \"file-system\" line\n");
403 errors++;
404 }
405 if (crosscheck() || errors)
406 stop();
407
408 /*
409 * Squeeze things down and finish cross-checks (STAR checks must
410 * run after packing).
411 */
412 pack();
413 if (badstar())
414 stop();
415
416 /*
417 * Ready to go. Build all the various files.
418 */
419 if (mksymlinks() || mkmakefile() || mkheaders() || mkswap() ||
420 mkioconf() || (do_devsw ? mkdevsw() : 0) || mkident())
421 stop();
422 (void)printf("Build directory is %s\n", builddir);
423 (void)printf("Don't forget to run \"make depend\"\n");
424 exit(0);
425 }
426
427 static void
428 usage(void)
429 {
430 (void)fputs("usage: config [-Ppv] [-s srcdir] [-b builddir] "
431 "[sysname]\n", stderr);
432 (void)fputs(" config -x [kernel-file]\n", stderr);
433 exit(1);
434 }
435
436 /*
437 * Set any options that are implied by other options.
438 */
439 static void
440 dependopts(void)
441 {
442 struct nvlist *nv, *opt;
443
444 for (nv = options; nv != NULL; nv = nv->nv_next) {
445 if ((opt = find_declared_option(nv->nv_name)) != NULL) {
446 for (opt = opt->nv_ptr; opt != NULL;
447 opt = opt->nv_next) {
448 do_depend(opt);
449 }
450 }
451 }
452
453 for (nv = fsoptions; nv != NULL; nv = nv->nv_next) {
454 if ((opt = find_declared_option(nv->nv_name)) != NULL) {
455 for (opt = opt->nv_ptr; opt != NULL;
456 opt = opt->nv_next) {
457 do_depend(opt);
458 }
459 }
460 }
461 }
462
463 static void
464 do_depend(struct nvlist *nv)
465 {
466 struct nvlist *nextnv;
467 struct attr *a;
468
469 if (nv != NULL && (nv->nv_flags & NV_DEPENDED) == 0) {
470 nv->nv_flags |= NV_DEPENDED;
471 /*
472 * If the dependency is an attribute, then just add
473 * it to the selecttab.
474 */
475 if ((a = ht_lookup(attrtab, nv->nv_name)) != NULL) {
476 if (a->a_iattr)
477 panic("do_depend(%s): dep `%s' is an iattr",
478 nv->nv_name, a->a_name);
479 expandattr(a, selectattr);
480 } else {
481 if (ht_lookup(opttab, nv->nv_name) == NULL)
482 addoption(nv->nv_name, NULL);
483 if ((nextnv =
484 find_declared_option(nv->nv_name)) != NULL)
485 do_depend(nextnv->nv_ptr);
486 }
487 }
488 }
489
490 /*
491 * Make a symlink for "machine" so that "#include <machine/foo.h>" works,
492 * and for the machine's CPU architecture, so that works as well.
493 */
494 static int
495 mksymlinks(void)
496 {
497 int ret;
498 char *p, buf[MAXPATHLEN];
499 const char *q;
500 struct nvlist *nv;
501
502 snprintf(buf, sizeof(buf), "arch/%s/include", machine);
503 p = sourcepath(buf);
504 ret = unlink("machine");
505 if (ret && errno != ENOENT)
506 (void)fprintf(stderr, "config: unlink(machine): %s\n",
507 strerror(errno));
508 ret = symlink(p, "machine");
509 if (ret)
510 (void)fprintf(stderr, "config: symlink(machine -> %s): %s\n",
511 p, strerror(errno));
512 free(p);
513
514 if (machinearch != NULL) {
515 snprintf(buf, sizeof(buf), "arch/%s/include", machinearch);
516 p = sourcepath(buf);
517 q = machinearch;
518 } else {
519 p = estrdup("machine");
520 q = machine;
521 }
522 ret = unlink(q);
523 if (ret && errno != ENOENT)
524 (void)fprintf(stderr, "config: unlink(%s): %s\n",
525 q, strerror(errno));
526 ret = symlink(p, q);
527 if (ret)
528 (void)fprintf(stderr, "config: symlink(%s -> %s): %s\n",
529 q, p, strerror(errno));
530 free(p);
531
532 for (nv = machinesubarches; nv != NULL; nv = nv->nv_next) {
533 q = nv->nv_name;
534 snprintf(buf, sizeof(buf), "arch/%s/include", q);
535 p = sourcepath(buf);
536 ret = unlink(q);
537 if (ret && errno != ENOENT)
538 (void)fprintf(stderr, "config: unlink(%s): %s\n",
539 q, strerror(errno));
540 ret = symlink(p, q);
541 if (ret)
542 (void)fprintf(stderr, "config: symlink(%s -> %s): %s\n",
543 q, p, strerror(errno));
544 free(p);
545 }
546
547 return (ret);
548 }
549
550 static __dead void
551 stop(void)
552 {
553 (void)fprintf(stderr, "*** Stop.\n");
554 exit(1);
555 }
556
557 static void
558 add_dependencies(struct nvlist *nv, struct nvlist *deps)
559 {
560 struct nvlist *dep;
561 struct attr *a;
562
563 /* Use nv_ptr to link any other options that are implied. */
564 nv->nv_ptr = deps;
565 for (dep = deps; dep != NULL; dep = dep->nv_next) {
566 /*
567 * If the dependency is an attribute, it must not
568 * be an interface attribute. Otherwise, it must
569 * be a previously declared option.
570 */
571 if ((a = ht_lookup(attrtab, dep->nv_name)) != NULL) {
572 if (a->a_iattr)
573 error("option `%s' dependency `%s' "
574 "is an interface attribute",
575 nv->nv_name, a->a_name);
576 } else if (OPT_OBSOLETE(dep->nv_name)) {
577 error("option `%s' dependency `%s' "
578 "is obsolete", nv->nv_name, dep->nv_name);
579 } else if (find_declared_option(dep->nv_name) == NULL) {
580 error("option `%s' dependency `%s' "
581 "is an unknown option",
582 nv->nv_name, dep->nv_name);
583 }
584 }
585 }
586
587 /*
588 * Define one or more file systems. If file system options file name is
589 * specified, a preprocessor #define for that file system will be placed
590 * in that file. In this case, only one file system may be specified.
591 * Otherwise, no preprocessor #defines will be generated.
592 */
593 void
594 deffilesystem(const char *fname, struct nvlist *fses, struct nvlist *deps)
595 {
596 struct nvlist *nv;
597
598 /*
599 * Mark these options as ones to skip when creating the Makefile.
600 */
601 for (nv = fses; nv != NULL; nv = nv->nv_next) {
602 if (ht_insert(defopttab, nv->nv_name, nv)) {
603 error("file system or option `%s' already defined",
604 nv->nv_name);
605 return;
606 }
607
608 /*
609 * Also mark it as a valid file system, which may be
610 * used in "file-system" directives in the config
611 * file.
612 */
613 if (ht_insert(deffstab, nv->nv_name, nv))
614 panic("file system `%s' already in table?!",
615 nv->nv_name);
616
617 if (fname != NULL) {
618 /*
619 * Only one file system allowed in this case.
620 */
621 if (nv->nv_next != NULL) {
622 error("only one file system per option "
623 "file may be specified");
624 return;
625 }
626
627 if (ht_insert(optfiletab, fname, nv)) {
628 error("option file `%s' already exists",
629 fname);
630 return;
631 }
632 }
633
634 add_dependencies(nv, deps);
635 }
636 }
637
638 /*
639 * Sanity check a file name.
640 */
641 int
642 badfilename(const char *fname)
643 {
644 const char *n;
645
646 /*
647 * We're putting multiple options into one file. Sanity
648 * check the file name.
649 */
650 if (strchr(fname, '/') != NULL) {
651 error("option file name contains a `/'");
652 return 1;
653 }
654 if ((n = strrchr(fname, '.')) == NULL || strcmp(n, ".h") != 0) {
655 error("option file name does not end in `.h'");
656 return 1;
657 }
658 return 0;
659 }
660
661
662 /*
663 * Search for a defined option (defopt, filesystem, etc), and if found,
664 * return the option's struct nvlist.
665 */
666 struct nvlist *
667 find_declared_option(const char *name)
668 {
669 struct nvlist *option = NULL;
670
671 if ((option = ht_lookup(defopttab, name)) != NULL ||
672 (option = ht_lookup(defparamtab, name)) != NULL ||
673 (option = ht_lookup(defflagtab, name)) != NULL ||
674 (option = ht_lookup(fsopttab, name)) != NULL) {
675 return (option);
676 }
677
678 return (NULL);
679 }
680
681
682 /*
683 * Define one or more standard options. If an option file name is specified,
684 * place all options in one file with the specified name. Otherwise, create
685 * an option file for each option.
686 * record the option information in the specified table.
687 */
688 void
689 defopt(struct hashtab *ht, const char *fname, struct nvlist *opts,
690 struct nvlist *deps, int obs)
691 {
692 struct nvlist *nv, *nextnv, *oldnv;
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 fprintf(fp, "%s\n", ident);
1261 fflush(fp);
1262 if (ferror(fp))
1263 error = 1;
1264 (void)fclose(fp);
1265
1266 return error;
1267 }
1268
1269 void
1270 logconfig_start(void)
1271 {
1272 extern FILE *yyin;
1273 char line[1024];
1274 const char *tmpdir;
1275 struct stat st;
1276 int fd;
1277
1278 if (yyin == NULL || fstat(fileno(yyin), &st) == -1)
1279 return;
1280 cfgtime = st.st_mtime;
1281
1282 tmpdir = getenv("TMPDIR");
1283 if (tmpdir == NULL)
1284 tmpdir = "/tmp";
1285 snprintf(line, sizeof(line), "%s/config.tmp.XXXXXX", tmpdir);
1286 if ((fd = mkstemp(line)) == -1 ||
1287 (cfg = fdopen(fd, "r+")) == NULL) {
1288 if (fd != -1) {
1289 unlink(line);
1290 close(fd);
1291 }
1292 cfg = NULL;
1293 return;
1294 }
1295 unlink(line);
1296
1297 (void)fprintf(cfg, "#include <sys/cdefs.h>\n\n");
1298 (void)fprintf(cfg, "#include \"opt_config.h\"\n");
1299 (void)fprintf(cfg, "\n");
1300 (void)fprintf(cfg, "/*\n");
1301 (void)fprintf(cfg, " * Add either (or both) of\n");
1302 (void)fprintf(cfg, " *\n");
1303 (void)fprintf(cfg, " *\toptions %s\n", LOGCONFIG_LARGE);
1304 (void)fprintf(cfg, " *\toptions %s\n", LOGCONFIG_SMALL);
1305 (void)fprintf(cfg, " *\n");
1306 (void)fprintf(cfg,
1307 " * to your kernel config file to embed it in the resulting\n");
1308 (void)fprintf(cfg,
1309 " * kernel. The latter option does not include files that are\n");
1310 (void)fprintf(cfg,
1311 " * included (recursively) by your config file. The embedded\n");
1312 (void)fprintf(cfg,
1313 " * data be extracted by using the command:\n");
1314 (void)fprintf(cfg, " *\n");
1315 (void)fprintf(cfg,
1316 " *\tstrings netbsd | sed -n 's/^_CFG_//p' | unvis\n");
1317 (void)fprintf(cfg, " */\n");
1318 (void)fprintf(cfg, "\n");
1319 (void)fprintf(cfg, "#ifdef CONFIG_FILE\n");
1320 (void)fprintf(cfg, "#if defined(%s) || defined(%s)\n\n",
1321 LOGCONFIG_LARGE, LOGCONFIG_SMALL);
1322 (void)fprintf(cfg, "static const char config[] __used =\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 fflush(cfg);
1407 if (ferror(cfg))
1408 err(EXIT_FAILURE, "write to temporary file for config.h failed");
1409 rewind(cfg);
1410
1411 if (stat("config_file.h", &st) != -1) {
1412 if (cfgtime < st.st_mtime) {
1413 fclose(cfg);
1414 return;
1415 }
1416 }
1417
1418 fp = fopen("config_file.h", "w");
1419 if (!fp)
1420 err(EXIT_FAILURE, "cannot open \"config.h\"");
1421
1422 while (fgets(line, sizeof(line), cfg) != NULL)
1423 fputs(line, fp);
1424 fflush(fp);
1425 if (ferror(fp))
1426 err(EXIT_FAILURE, "write to \"config.h\" failed");
1427 fclose(fp);
1428 fclose(cfg);
1429 }
1430
1431 static const char *
1432 strtolower(const char *name)
1433 {
1434 const char *n;
1435 char *p, low[500];
1436 unsigned char c;
1437
1438 for (n = name, p = low; (c = *n) != '\0'; n++)
1439 *p++ = isupper(c) ? tolower(c) : c;
1440 *p = 0;
1441 return (intern(low));
1442 }
1443
1444 static int
1445 is_elf(const char *file)
1446 {
1447 int kernel;
1448 char hdr[4];
1449
1450 kernel = open(file, O_RDONLY);
1451 if (kernel == -1) {
1452 fprintf(stderr, "config: cannot open %s: %s\n", file,
1453 strerror(errno));
1454 exit(2);
1455 }
1456 if (read(kernel, hdr, 4) == -1) {
1457 fprintf(stderr, "config: cannot read from %s: %s\n", file,
1458 strerror(errno));
1459 exit(2);
1460 }
1461 close(kernel);
1462
1463 return memcmp("\177ELF", hdr, 4) == 0 ? 1 : 0;
1464 }
1465
1466 static int
1467 extract_config(const char *kname, const char *cname, int cfd)
1468 {
1469 char *ptr;
1470 int found, kfd, i;
1471 struct stat st;
1472
1473 found = 0;
1474
1475 /* mmap(2) binary kernel */
1476 kfd = open(conffile, O_RDONLY);
1477 if (kfd == -1) {
1478 fprintf(stderr, "config: cannot open %s: %s\n", kname,
1479 strerror(errno));
1480 exit(2);
1481 }
1482 if ((fstat(kfd, &st) == -1)) {
1483 fprintf(stderr, "config: cannot stat %s: %s\n", kname,
1484 strerror(errno));
1485 exit(2);
1486 }
1487 ptr = (char *)mmap(0, st.st_size, PROT_READ, MAP_FILE | MAP_SHARED,
1488 kfd, 0);
1489 if (ptr == MAP_FAILED) {
1490 fprintf(stderr, "config: cannot mmap %s: %s\n", kname,
1491 strerror(errno));
1492 exit(2);
1493 }
1494
1495 /* Scan mmap(2)'ed region, extracting kernel configuration */
1496 for (i = 0; i < st.st_size; i++) {
1497 if ((*ptr == '_') && (st.st_size - i > 5) && memcmp(ptr,
1498 "_CFG_", 5) == 0) {
1499 /* Line found */
1500 char *oldptr, line[LINE_MAX + 1], uline[LINE_MAX + 1];
1501 int j;
1502
1503 found = 1;
1504
1505 oldptr = (ptr += 5);
1506 while (*ptr != '\n' && *ptr != '\0') ptr++;
1507 if (ptr - oldptr > LINE_MAX) {
1508 fprintf(stderr, "config: line too long\n");
1509 exit(2);
1510 }
1511 i += ptr - oldptr + 5;
1512 memcpy(line, oldptr, (ptr - oldptr));
1513 line[ptr - oldptr] = '\0';
1514 j = strunvis(uline, line);
1515 if (j == -1) {
1516 fprintf(stderr, "config: unvis: invalid "
1517 "encoded sequence\n");
1518 exit(2);
1519 }
1520 uline[j] = '\n';
1521 if (write(cfd, uline, j + 1) == -1) {
1522 fprintf(stderr, "config: cannot write to %s: "
1523 "%s\n", cname, strerror(errno));
1524 exit(2);
1525 }
1526 } else ptr++;
1527 }
1528
1529 close(kfd);
1530
1531 return found;
1532 }
1533
1534 struct dhdi_params {
1535 struct devbase *d;
1536 int unit;
1537 int level;
1538 };
1539
1540 static int
1541 devbase_has_dead_instances(const char *key, void *value, void *aux)
1542 {
1543 struct devi *i;
1544 struct dhdi_params *dhdi = aux;
1545
1546 for (i = value; i != NULL; i = i->i_alias)
1547 if (i->i_base == dhdi->d &&
1548 (dhdi->unit == WILD || dhdi->unit == i->i_unit ||
1549 i->i_unit == STAR) &&
1550 i->i_level >= dhdi->level)
1551 return 1;
1552 return 0;
1553 }
1554
1555 /*
1556 * This is almost the same as devbase_has_instances, except it
1557 * may have special considerations regarding ignored instances.
1558 */
1559
1560 static int
1561 devbase_has_any_instance(struct devbase *dev, int unit, int state, int level)
1562 {
1563 struct deva *da;
1564 struct devi *i;
1565
1566 if (dev->d_ispseudo) {
1567 if (dev->d_ihead != NULL)
1568 return 1;
1569 else if (state != DEVI_IGNORED)
1570 return 0;
1571 if ((i = ht_lookup(deaddevitab, dev->d_name)) == NULL)
1572 return 0;
1573 return (i->i_level >= level);
1574 }
1575
1576 for (da = dev->d_ahead; da != NULL; da = da->d_bsame)
1577 for (i = da->d_ihead; i != NULL; i = i->i_asame)
1578 if ((i->i_active == DEVI_ACTIVE ||
1579 i->i_active == state) &&
1580 (unit == WILD || unit == i->i_unit ||
1581 i->i_unit == STAR))
1582 return 1;
1583
1584 if (state == DEVI_IGNORED) {
1585 struct dhdi_params dhdi = { dev, unit, level };
1586 /* also check dead devices */
1587 return ht_enumerate(deaddevitab, devbase_has_dead_instances,
1588 &dhdi);
1589 }
1590
1591 return 0;
1592 }
1593
1594 /*
1595 * check_dead_devi(), used with ht_enumerate, checks if any of the removed
1596 * device instances would have been a valid instance considering the devbase,
1597 * the parent device and the interface attribute.
1598 *
1599 * In other words, for a non-active device, it checks if children would be
1600 * actual orphans or the result of a negative statement in the config file.
1601 */
1602
1603 struct cdd_params {
1604 struct devbase *d;
1605 struct attr *at;
1606 struct devbase *parent;
1607 };
1608
1609 static int
1610 check_dead_devi(const char *key, void *value, void *aux)
1611 {
1612 struct cdd_params *cdd = aux;
1613 struct devi *i = value;
1614 struct pspec *p;
1615
1616 if (i->i_base != cdd->d)
1617 return 0;
1618
1619 for (; i != NULL; i = i->i_alias) {
1620 p = i->i_pspec;
1621 if ((p == NULL && cdd->at == NULL) ||
1622 (p != NULL && p->p_iattr == cdd->at &&
1623 (p->p_atdev == NULL || p->p_atdev == cdd->parent))) {
1624 if (p != NULL &&
1625 !devbase_has_any_instance(cdd->parent, p->p_atunit,
1626 DEVI_IGNORED, i->i_level))
1627 return 0;
1628 else
1629 return 1;
1630 }
1631 }
1632 return 0;
1633 }
1634
1635 static void
1636 do_kill_orphans(struct devbase *d, struct attr *at, struct devbase *parent,
1637 int state)
1638 {
1639 struct nvlist *nv, *nv1;
1640 struct attr *a;
1641 struct devi *i, *j = NULL;
1642 struct pspec *p;
1643 int active = 0;
1644
1645 /*
1646 * A pseudo-device will always attach at root, and if it has an
1647 * instance (it cannot have more than one), it is enough to consider
1648 * it active, as there is no real attachment.
1649 *
1650 * A pseudo device can never be marked DEVI_IGNORED.
1651 */
1652 if (d->d_ispseudo) {
1653 if (d->d_ihead != NULL)
1654 d->d_ihead->i_active = active = DEVI_ACTIVE;
1655 else {
1656 if (ht_lookup(deaddevitab, d->d_name) != NULL)
1657 active = DEVI_IGNORED;
1658 else
1659 return;
1660 }
1661 } else {
1662 int seen = 0;
1663
1664 for (i = d->d_ihead; i != NULL; i = i->i_bsame) {
1665 for (j = i; j != NULL; j = j->i_alias) {
1666 p = j->i_pspec;
1667 if ((p == NULL && at == NULL) ||
1668 (p != NULL && p->p_iattr == at &&
1669 (p->p_atdev == NULL ||
1670 p->p_atdev == parent))) {
1671 if (p != NULL &&
1672 !devbase_has_any_instance(parent,
1673 p->p_atunit, state, j->i_level))
1674 continue;
1675 /*
1676 * There are Fry-like devices which can
1677 * be their own grand-parent (or even
1678 * parent, like uhub). We don't want
1679 * to loop, so if we've already reached
1680 * an instance for one reason or
1681 * another, stop there.
1682 */
1683 if (j->i_active == DEVI_ACTIVE ||
1684 j->i_active == state) {
1685 /*
1686 * Device has already been
1687 * seen. However it might
1688 * have siblings who still
1689 * have to be activated or
1690 * orphaned.
1691 */
1692 seen = 1;
1693 continue;
1694 }
1695 j->i_active = active = state;
1696 if (p != NULL)
1697 p->p_active = state;
1698 }
1699 }
1700 }
1701 /*
1702 * If we've been there but have made no change, stop.
1703 */
1704 if (seen && !active)
1705 return;
1706 if (!active) {
1707 struct cdd_params cdd = { d, at, parent };
1708 /* Look for a matching dead devi */
1709 if (ht_enumerate(deaddevitab, check_dead_devi, &cdd) &&
1710 d != parent)
1711 /*
1712 * That device had its instances removed.
1713 * Continue the loop marking descendants
1714 * with DEVI_IGNORED instead of DEVI_ACTIVE.
1715 *
1716 * There is one special case for devices that
1717 * are their own parent: if that instance is
1718 * removed (e.g., no uhub* at uhub?), we don't
1719 * have to continue looping.
1720 */
1721 active = DEVI_IGNORED;
1722 else
1723 return;
1724 }
1725 }
1726
1727 for (nv = d->d_attrs; nv != NULL; nv = nv->nv_next) {
1728 a = nv->nv_ptr;
1729 for (nv1 = a->a_devs; nv1 != NULL; nv1 = nv1->nv_next)
1730 do_kill_orphans(nv1->nv_ptr, a, d, active);
1731 }
1732 }
1733
1734 static int
1735 kill_orphans_cb(const char *key, void *value, void *aux)
1736 {
1737 do_kill_orphans((struct devbase *)value, NULL, NULL, DEVI_ACTIVE);
1738 return 0;
1739 }
1740
1741 static void
1742 kill_orphans()
1743 {
1744 ht_enumerate(devroottab, kill_orphans_cb, NULL);
1745 }
1746