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