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