diff --git a/distrib/sets/lists/minix-base/mi b/distrib/sets/lists/minix-base/mi index bb4cbec8b..d45151deb 100644 --- a/distrib/sets/lists/minix-base/mi +++ b/distrib/sets/lists/minix-base/mi @@ -284,6 +284,7 @@ ./usr/bin/column minix-base ./usr/bin/comm minix-base ./usr/bin/compress minix-base +./usr/bin/config minix-base ./usr/bin/cpio minix-base ./usr/bin/cprofalyze minix-base obsolete ./usr/bin/crc minix-base diff --git a/distrib/sets/lists/minix-man/mi b/distrib/sets/lists/minix-man/mi index a188227b3..f87267a7f 100644 --- a/distrib/sets/lists/minix-man/mi +++ b/distrib/sets/lists/minix-man/mi @@ -66,6 +66,7 @@ ./usr/man/man1/comm.1 minix-man ./usr/man/man1/command.1 minix-man obsolete ./usr/man/man1/compress.1 minix-man +./usr/man/man1/config.1 minix-man ./usr/man/man1/continue.1 minix-man obsolete ./usr/man/man1/cp.1 minix-man ./usr/man/man1/cpio.1 minix-man @@ -3268,6 +3269,8 @@ ./usr/man/man5/blacklistd.conf.5 minix-man ./usr/man/man5/boot.cfg.5 minix-man ./usr/man/man5/cdb.5 minix-man +./usr/man/man5/config.5 minix-man +./usr/man/man5/config.samples.5 minix-man ./usr/man/man5/configfile.5 minix-man ./usr/man/man5/cpio.5 minix-man ./usr/man/man5/crontab.5 minix-man @@ -3424,7 +3427,7 @@ ./usr/man/man8/pr_routes.8 minix-man ./usr/man/man8/printroot.8 minix-man ./usr/man/man8/pwd_mkdb.8 minix-man -./usr/man/man8/pwdauth.8 minix-man obsolete +./usr/man/man8/pwdauth.8 minix-man obsolete ./usr/man/man8/rarpd.8 minix-man ./usr/man/man8/rawspeed.8 minix-man ./usr/man/man8/rdate.8 minix-man diff --git a/usr.bin/Makefile b/usr.bin/Makefile index 0c8cf553b..01e633bd2 100644 --- a/usr.bin/Makefile +++ b/usr.bin/Makefile @@ -7,7 +7,7 @@ SUBDIR= asa \ banner basename \ bzip2 bzip2recover cal calendar \ checknr chpass cksum cmp col colcrt colrm \ - column comm csplit ctags cut \ + column comm config csplit ctags cut \ deroff dirname du \ env expand \ false find finger flock fold fpr from \ diff --git a/usr.bin/config/Makefile b/usr.bin/config/Makefile new file mode 100644 index 000000000..429921eeb --- /dev/null +++ b/usr.bin/config/Makefile @@ -0,0 +1,27 @@ +# $NetBSD: Makefile,v 1.10 2014/10/29 19:10:49 christos Exp $ +# from: @(#)Makefile 8.2 (Berkeley) 4/19/94 + +.include +WARNS=6 + +PROG= config +SRCS= files.c gram.y hash.c lint.c main.c mkdevsw.c mkheaders.c mkioconf.c \ + mkmakefile.c mkswap.c pack.c scan.l sem.c util.c + +.PATH: ${NETBSDSRCDIR}/usr.bin/cksum +SRCS+= crc.c + +MAN= config.1 +MAN+= config.5 config.samples.5 +YHEADER=1 +CPPFLAGS+=-I${.CURDIR} -I. +CPPFLAGS+= -I${NETBSDSRCDIR}/usr.bin/cksum + +.ifndef HOSTPROG +LDADD+=-lutil +DPADD+=${LIBUTIL} +.endif + +CWARNFLAGS+=-Wno-format-y2k + +.include diff --git a/usr.bin/config/TODO b/usr.bin/config/TODO new file mode 100644 index 000000000..d92d3c5c8 --- /dev/null +++ b/usr.bin/config/TODO @@ -0,0 +1,461 @@ +o Call module as module. + + Until now, everything is called as attribute. Separate module from it: + + - Module is a collection of code (*.[cSo]), and provides a function. + Module can depend on other modules. + + - Attribute provides metadata for modules. One module can have + multiple attributes. Attribute doesn't generate a module (*.o, + *.ko). + +o Emit everything (ioconf.*, Makefile, ...) per-attribute. + + config(9) related metadata (cfdriver, cfattach, cfdata, ...) should be + collected using linker. Create ELF sections like + .{rodata,data}.config.{cfdriver,cfattach,cfdata}. Provide reference + symbols (e.g. cfdriverinit[]) using linker script. Sort entries by name + to lookup entries by binary search in kernel. + +o Generate modular(9) related information. Especially module dependency. + + At this moment modular(9) modules hardcode dependency in *.c using the + MODULE() macro: + + MODULE(MODULE_CLASS_DRIVER, hdaudio, "pci"); + + This information already exists in config(5) definitions (files.*). + Extend config(5) to be able to specify module's class. + + Ideally these module metadata are kept somewhere in ELF headers, so that + loaders (e.g. boot(8)) can easily read. One idea is to abuse DYNAMIC + sections to record dependency, as shared library does. (Feasibility + unknown.) + +o Rename "interface attribute" to "bus". + + Instead of + + define audiobus {} + attach audio at audiobus + + Do like this + + defbus audiobus {} + attach audio at audiobus + + Always provide xxxbusprint() (and xxxbussubmatch if multiple children). + Extend struct cfiattrdata like: + + struct cfiattrdata { + const char *ci_name; + cfprint_t ci_print; + cfsubmatch_t ci_submatch; + int ci_loclen; + const struct cflocdesc ci_locdesc[]; + }; + +o Simplify child configuration API + + With said struct cfiattrdata extension, config_found*() can omit + print/submatch args. If the found child is known (e.g., "pcibus" creating + "pci"): + + config_found(self, "pcibus"); + + If finding unknown children (e.g. "pci" finding pci devices): + + config_find(self, "pci", locs, aux); + +o Retire "attach foo at bar with foo_bar.c" + + Most of these should be rewritten by defining a common interface attribute + "foobus", instead of writing multiple attachments. com(4), ld(4), ehci(4) + are typical examples. For ehci(4), EHCI-capable controller drivers implement + "ehcibus" interface, like: + + defne ehcibus {} + device imxehci: ehcibus + + These drivers' attach functions call config_found() to attach ehci(4) via + the "ehcibus" interface attribute, instead of calling ehci_init() directly. + Same for com(4) (com_attach_subr()) and ld(4) (ldattach()). + +o Sort objects in more reasonable order. + + Put machdep.ko in the lowest address. uvm.ko and kern.ko follow. + + Kill alphabetical sort (${OBJS:O} in sys/conf/Makefile.inc.kern. + + Use ldscript. Do like this + + .text : + AT (ADDR(.text) & 0x0fffffff) + { + *(.text.machdep.locore.entry) + *(.text.machdep.locore) + *(.text.machdep) + *(.text) + *(.text.*) + : + + Kill linker definitions in sys/conf/Makefile.inc.kern. + +o Differentiate "options" and "flags"/"params". + + "options" enables features by adding *.c files (via attributes). + + "flags" and "params" are to change contents of *.c files. These don't add + *.c files to the result kernel, or don't build attributes (modules). + +o Make flags/params per attributes (modules). + + Basically flags and params are cpp(1) #define's generated in opt_*.h. Make + them local to one attributes (modules). Flags/params which affects files + across attributes (modules) are possible, but should be discouraged. + +o Generate things only by definitions. + + In the ideal dynamically modular world, "selection" will be done not at + compile time but at runtime. Users select their wanted modules, by + dynamically loading them. + + This means that the system provides all choices; that is, build all modules + in the source tree. Necessary information is defined in the "definition" + part. + +o Split cfdata. + + cfdata is a set of pattern matching rules to enable devices at runtime device + auto-configuration. It is pure data and can (should) be generated separately + from the code. + +o Allow easier adding and removing of options. + + It should be possible to add or remove options, flags, etc., + without regard to whether or not they are already defined. + For example, a configuration like this: + + include GENERIC + options FOO + no options BAR + + should work regardless of whether or not options FOO and/or + options BAR were defined in GENERIC. It should not give + errors like "options BAR was already defined" or "options FOO + was not defined". + +o Introduce "class". + + Every module should be classified as at least one class, as modular(9) + modules already do. For example, file systems are marked as "vfs", network + protocols are "netproto". + + Consider to merge "devclass" into "class". + + For syntax clarity, class names could be used as a keyword to select the + class's instance module: + + # Define net80211 module as netproto class + class netproto + define net80211: netproto + + # Select net80211 to be builtin + netproto net80211 + + Accordingly device/attach selection syntax should be revisited. + +o Support kernel constructor/destructor (.kctors/.kdtors) + + Initialization and finalization should be called via constructors and + destructors. Don't hardcode those sequences as sys/kern/init_main.c:main() + does. + + The order of .kctors/.kdtors is resolved by dependency. The difference from + userland is that in kernel depended ones are located in lower addresses; + "machdep" module is the lowest. Thus the lowest entry in .ctors must be + executed the first. + + The .kctors/.kdtors entries are executed by kernel's main() function, unlike + userland where start code executes .ctors/.dtors before main(). The hardcoded + sequence of various subsystem initializations in init_main.c:main() will be + replaced by an array of .kctors invocations, and #ifdef's there will be gone. + +o Hide link-set in the final kernel. + + Link-set is used to collect references (pointers) at link time. It relys on + the ld(1) behavior that it automatically generates `__start_X' and `__stop_X' + symbols for the section `X' to reduce coding. + + Don't allow kernel subsystems create random ELF sections. + + Pre-define all the available link-set names and pre-generate a linker script + to merge them into .rodata. + + (For modular(9) modules, `link_set_modules' is looked up by kernel loader. + Provide only it.) + + Provide a way for 3rd party modules to declare extra link-set. + +o Shared kernel objects. + + Since NetBSD has not established a clear kernel ABI, every single kernel + has to build all the objects by their own. As a result, similar kernels + (e.g. evbarm kernels) repeatedly compile similar objects, that is waste of + energy & space. + + Share them if possible. For evb* ports, ideally everything except machdep.ko + should be shared. + + While leaving optimizations as options (CPU specific optimizations, inlined + bus_space(9) operations, etc.) for users, the official binaries build + provided by TNF should be as portable as possible. + +o Always use explicit kernel linker script. + + ld(1) has an option -T to use a given linker script. If not + specified, a default, built-in linker script, mainly meant for userland + programs, is used. + + Currently m68k, sh3, and vax don't have kernel linker scripts. These work + because these have no constraints about page boundary; they map and access + kernel .text/.data in the same way. + +o Pass input files to ${LD} via linker script. + + Instead of passing input files on command-line, output "INPUT(xxx.o)" + commands, and include it from generated linker scripts. + +o Generate `*.d' files. + + Output source/object files in raw texts instead of `Makefile'. Generate + `*.d' (make(1) depend) files. make(1) knows which object files are to be + compiled. With "INPUT(xxx.o)" linker scripts, either generated `Makefile' + or `Makefile.kern.inc' don't need to keep source/object files in variables. + +o Control ELF sections using linker script. + + Now kernel is linked and built directly from object files (*.o). Each port + has an MD linker script, which does everything needed to be done at link + time. As a result, they do from MI alignment restriction (read_mostly, + cacheline_aligned) to load address specification for external boot loaders. + + Make this into multiple stages to make linkage more structural. Especially, + reserve the final link for purely MD purpose. Note that in modular build, + *.ko are shared between build of kernel and modular(9) modules (*.kmod). + + Monolithic build: + *.o ---> netbsd.ko Generic MI linkage + netbsd.ko ---> netbsd.ro Kernel MI linkage + netbsd.ro ---> netbsd Kernel MD linkage + + Modular build (kernel): + *.o ---> *.ko Generic + Per-module MI linkage + *.ko ---> netbsd.ro Kernel MI linkage + netbsd.ro ---> netbsd Kernel MD linkage + + Modular build (module): + *.o ---> *.ko Generic + Per-module MI linkage + *.ko ---> *.ro Modular MI linkage + *.ro ---> *.kmod Modular MD linkage + + Genric MI linkage is for processing MI linkage that can be applied generally. + Data section alignment (.data.read_mostly and .data.cacheline_aligned) is + processed here. + + Per-module MI linkage is for modules that want some ordering. For example, + machdep.ko wants to put entry code at the top of .text and .data. + + Kernel MI linkage is for collecting kernel global section data, that is what + link-set is used for now. Once they are collected and symbols to the ranges + are assigned, those sections are merged into the pre-existing sections + (.rodata) because link-set sections in "netbsd" will never be interpreted by + external loaders. + + Kernel MD linkage is used purely for MD purposes, that is, how kernels are + loaded by external loaders. It might be possible that one kernel relocatable + (netbsd.ro) is linked into multiple final kernel image (netbsd) for diferent + load addresses. + + Modular MI linkage is to prepare a module to be loadable as modular(9). This + may add some extra sections and/or symbols. + + Modular MD linkage is again for pure MD purposes like kernel MD linkage. + Adjustment and/or optimization may be done. + + Kernel and modular MI linkages may change behavior depending on existence + of debug information. In the future .symtab will be copied using linker + during this stage. + +o Fix db_symtab copying (COPY_SYMTAB) + + o Collect all objects and create a relocatable (netbsd.ro). At this point, + the number of symbols is known. + + o Relink and allocate .rodata.symtab with the calculated size of .symtab. + Linker recalculates symbol addresses. + + o Embed the .symtab into .rodata.symtab. + + o Link the final netbsd ELF. + + The make(1) rule (dependency graph) should be identical with/without + COPY_SYMTAB. Kill .ifdef COPY_SYMTAB from $S/conf/Makefile.kern.inc. + +o Preprocess and generate linker scripts dynamically. + + Include opt_xxx.h and replace some constant values (e.g. COHERENCY_UNIT, + PAGE_SIZE, KERNEL_BASE_PHYS, KERNEL_BASE_VIRT, ...) with cpp(1). + + Don't unnecessarily define symbols. Don't use sed(1). + +o Clean up linker scripts. + + o Don't specify OUTPUT_FORMAT()/OUTPUT_ARCH() + + These are basically set in compilers/linkers. If non-default ABI is used, + command-line arguments should be specified. + + o Remove .rel/.rela handlings. + + These are set in relocatable objects, and handled by dynamic linkers. + Totally irrelefant for kernels. + + o Clean up debug section handlings. + + o Document (section boundary) symbols set in linker scripts. + + There must be a reason why symbols are defined and exported. + + PROVIDE() is to define internal symbols. + + o Clean up load addresses. + + o Program headers. + + o According to matt@, .ARM.extab/.ARM.exidx sections are no longer needed. + +o Redesign swapnetbsd.c (root/swap device specification) + + Don't build a whole kernel only to specify root/swap devices. + + Make these parameter re-configurable afterwards. + +o Namespace. + + Investigate namespace of attributes/modules/options. Figure out the hidden + design about these, document it, then re-design it. + + At this moment, all of them share the single "selecttab", which means their + namespaces are common, but they also have respective tables (attrtab, + opttab, etc.). + + Selecting an option (addoption()), that is also a module name, works only if + the module doesn't depend on anything, because addoption() doesn't select + module and its dependencies (selectattr()). In other words, an option is + only safely converted to a module (define), only if it doesn't depend on + anything. (One example is DDB.) + +o Convert pseudo(dev) attach functions to take (void) (== kernel ctors). + + The pseudo attach function was originally designed to take `int n' as + the number of instances of the pseudo device. Now most of pseudo + devices have been converted to be `cloneable', meaning that their + instances are dynamically allocated at run-time, because guessing how + much instances are needed for users at compile time is almost impossible. + Restricting such a pure software resource at compile time is senseless, + considering that the rest of the world is dynamic. + + If pseudo attach functions once become (void), config(1) no longer + has to generate iteration to call those functions, by making them part + of kernel constructors, that are a list of (void) functions. + + Some pseudo devices may have dependency/ordering problems, because + pseudo attach functions have no choice when to be called. This could + be solved by converting to kctors, where functions are called in order + by dependency. + +o Enhance ioconf behavior for pseudo-devices + + See "bin/48571: config(1) ioconf is insufficient for pseudo-devices" for + more details. In a nutshell, it would be "useful" for config to emit + the necessary stuff in the generated ioconf.[ch] to enable use of + config_{init,fini}_component() for attaching and detaching pseudodev's. + + Currently, you need to manually construct your own data structures, and + manually "attach" them, one at a time. This leads to duplication of + code (where multiple drivers contain the same basic logic), and doesn't + necessarily handle all of the "frobbing" of the kernel lists. + +o Don't use -Ttext ${TEXTADDR}. + + Although ld(1)'s `-Ttext ${TEXTADDR}' is an easy way to specify the virtual + base address of .text at link time, it needs to change command-line; in + kernel build, Makefile needs to change to reflect kernel's configuration. + It is simpler to reflect kenel configuration using linker script via assym.h. + +o Convert ${DIAGNOSTIC} and ${DEBUG} as flags (defflag). + + Probably generate opt_diagnostic.h/opt_debug.h and include them in + sys/param.h. + +o Strictly define DIAGNOSTIC. + + It is possible to make DIAGNOSTIC kernel and modules binary-compatible with + non-DIAGNOSTIC ones. In that case, debug type informations should match + theoretically (not confirmed). + +o Use suffix rules. + + Build objects following suffix rules. Source files are defined as relative to + $S (e.g. sys/kern/init_main.c) and objects are generated in the corresponding + subdirectories under kernel build directories (e.g. + .../compile/GENERIC/sys/kern/init_main.o). Dig subdirectories from within + config(1). + + Debugging (-g) and profiling (-pg) objects could be generated with *.go/*.po + suffixes as userland libraries do. Maybe something similar for + DIAGNOSTIC/DEBUG. + + genassym(1) definitions will be split into per-source instead of the single + assym.h. Dependencies are corrected and some of misterious dependencies on + `Makefile' in sys/conf/Makefile.kern.inc can go away. + +o Define genassym(1) symbols per file. + + Have each file define symbols that have to be generated by genassym(1) so + that more accurate dependency is reflected. + + For example, if foo.S needs some symbols, it defines them in foo.assym, + declaring that foo.S depends on foo.assym.h, and includes foo.assym.h. + foo.assym.h is generated by following the suffix rule of .assym -> .assym.h. + When one header is updated, only related *.assym.h files are regenerated, + instead of rebuilding all MD/*.S files that depend on the global, single + assym.h. + +o Support library. + + Provide a consistent way to build library either as .o or .a. + + Build libraries in sub-make. Don't include library makefiles. Don't + pollute search path (.PATH). libkern does too much. + +o Accept `.a' suffix. + + Make "file" command accept `.a' suffix. Handle it the same way as `.o'. + +o Clean up ${MD_OBJS} and friends in Makefile.${MACHINE}. + + Don't use ${MD_OBJS}, ${MD_LIBS}, ${MD_SFILES}, and ${MD_CFILES}. + + List files in config(5)'s "file". Override build rules only when neccesary. + + Rely on the fact that config(1) parses files.${MACHINE} first, outputs + files in the order it parses files.* (actually include depth), and + `Makefile.kern.inc' preserve file order to pass to ${LD}. + +o Clean up CTF-related rules. + + Don't overwrite compile/link rules conditionally by existence of + ${CTFCONVERT}/${CTFMERGE}. Give a separate suffix (*.ctfo) and define its + rules (.c -> .ctfo). diff --git a/usr.bin/config/config b/usr.bin/config/config new file mode 100755 index 000000000..2e3baf7ce Binary files /dev/null and b/usr.bin/config/config differ diff --git a/usr.bin/config/config.1 b/usr.bin/config/config.1 new file mode 100644 index 000000000..0cef87847 --- /dev/null +++ b/usr.bin/config/config.1 @@ -0,0 +1,358 @@ +.\" $NetBSD: config.1,v 1.19 2015/09/01 16:01:23 uebayasi Exp $ +.\" +.\" Copyright (c) 1980, 1991, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" from: @(#)config.8 8.2 (Berkeley) 4/19/94 +.\" +.Dd September 1, 2015 +.Dt CONFIG 1 +.Os +.Sh NAME +.Nm config +.Nd build kernel compilation directories +.Sh SYNOPSIS +.Nm +.Op Fl dMPpSv +.Op Fl b Ar builddir +.Op Fl D Ar var=value +.Op Fl s Ar srcdir +.Op Fl U Ar value +.Op Ar config-file +.Nm +.Fl x +.Op Ar kernel-file +.Nm +.Fl L +.Op Fl v +.Op Fl s Ar srcdir +.Op Ar config-file +.Sh DESCRIPTION +In its first synopsis form, +.Nm +creates a kernel build directory from the machine description file +.Ar config-file , +which describes the system to configure. +Refer to section +.Sx KERNEL BUILD CONFIGURATION +for the details of that use +of +.Nm . +.Pp +In its second synopsis form, +.Nm +takes the binary kernel +.Ar kernel-file +as its single argument (aside from the mandatory +.Fl x +flag), then extracts the embedded configuration file (if any) and +writes it to standard output. +If +.Ar kernel-file +is not given, and the system is not running +.Nx +an error is printed. +On systems running +.Nx +the booted kernel is looked up using the +.Xr sysctl 3 +variable +.Dv machdep.booted_kernel +and if that is not found, +.Dv _PATH_UNIX +.Pq Pa /netbsd +is used. +Configuration data will be available if the given kernel was compiled +with either +.Va INCLUDE_CONFIG_FILE +or +.Va INCLUDE_JUST_CONFIG +options. +.Pp +In its third synopsis form, +.Nm +is a tool for the kernel developer and generates a +.Dq lint +configuration file to be used during regression testing. +Refer to section +.Sx LINT CONFIGURATION +for the details of that use of +.Nm . +.Pp +.Nm +accepts the following parameters: +.Bl -tag -width indent +.It Fl b Ar builddir +Use +.Ar builddir +as the kernel build directory, instead of computing and creating one +automatically. +.It Fl d +Issue diagnostic output for debugging problems with +.Nm +itself. +More +.Fl d +options (currently up to 5) produce more output. +.It Fl D Ar var=value +Define a makeoptions variable to the given value. +This is equivalent to appending a +.Li makeoptions var=value +line to the config file. +.It Fl L +Generate a lint configuration. +See section +.Sx LINT CONFIGURATION +for details. +.It Fl M +Do modular build (experimental). +Instead of linking all object files (*.o) at once, collect related object +files into an intermediate relocatable object (*.ko), then link those *.ko +files into the final kernel. +This changes the order of objects in the kernel binary. +.It Fl P +Pack locators to save space in the resulting kernel binary. +The amount of space saved that way is so small that this option should +be considered historical, and of no actual use. +.It Fl p +Generate a build directory suited for kernel profiling. +However, this options should be avoided in favor of the relevant options +inside the configuration file as described in section +.Sx KERNEL BUILD CONFIGURATION . +.It Fl s Ar srcdir +Point to the top of the kernel source tree. +It must be an absolute path when +.Nm +is used to prepare a kernel build directory, but can be relative +when it is used in combination with the +.Fl L +flag. +.It Fl S +Use suffix rules and build objects under subdirectories (experimental). +.It Fl U Ar var +Undefine the makeoption +.Ar var . +This is equivalent to appending the line +.Li no makeoptions var +to the config file. +.It Fl v +Increase verbosity by enabling some more warnings. +.It Fl x +Extract the configuration embedded in a kernel binary. +.El +.Ss KERNEL BUILD CONFIGURATION +There are several different ways to run the +.Nm +program. +The traditional way is to run +.Nm +from the +.Pa conf +subdirectory of the machine-specific directory of the system source +(usually +.Pa /sys/arch/MACHINE/conf , +where +.Pa MACHINE +is one of +.Pa vax , +.Pa hp300 , +and so forth), and to specify as the +.Ar config-file +the name of a machine description file located in that directory. +.Nm +will by default create files in the directory +.Pa ../compile/SYSTEMNAME , +where +.Pa SYSTEMNAME +is the last path component of +.Ar config-file . +.Nm +will assume that the top-level kernel source directory is located four +directories above the build directory. +.Pp +Another way is to create the build directory yourself, place the +machine description file in the build directory with the name +.Pa CONFIG , +and run +.Nm +from within the build directory without specifying a +.Ar config-file . +.Nm +will then by default create files in the current directory. +If you run +.Nm +this way, you must specify the location of the top-level kernel source +directory using the +.Fl s +option or by using the +.Dq Li source +directive at the beginning of the machine description file. +.Pp +Finally, you can specify the build directory for +.Nm +and run it from anywhere. +You can specify a build directory with the +.Fl b +option or by using the +.Dq Li build +directive at the beginning of the machine description file. +You must specify the location of the top-level kernel source directory if you +specify a build directory. +.Pp +If +.Ar config-file +is a binary kernel, +.Nm +will try to extract the configuration file embedded into it, which will +be present if that kernel was built either with +.Va INCLUDE_CONFIG_FILE +or +.Va INCLUDE_JUST_CONFIG +options. +This work mode requires you to manually specify a build directory with +the +.Fl b +option, which implies the need to provide a source tree too. +.Pp +If the +.Fl p +option is supplied, +.Pa .PROF +is appended to the default compilation directory name, and +.Nm +acts as if the lines +.Dq Li makeoptions PROF="-pg" +and +.Dq Li options GPROF +appeared in the machine description file. +This will build a system that includes profiling code; see +.Xr kgmon 8 +and +.Xr gprof 1 . +The +.Fl p +flag is expected to be used for +.Dq one-shot +profiles of existing systems; for regular profiling, it is probably +wiser to create a separate machine description file containing the +.Li makeoptions +line. +.Pp +The old undocumented +.Fl g +flag is no longer supported. +Instead, use +.Dq Li makeoptions DEBUG="-g" +and (typically) +.Dq Li options KGDB . +.Pp +The output of +.Nm +consists of a number of files, principally +.Pa ioconf.c , +a description of I/O devices that may be attached to the system; and a +.Pa Makefile , +used by +.Xr make 1 +in building the kernel. +.Pp +After running +.Nm , +it is wise to run +.Dq Li make depend +in the directory where the new makefile +was created. +.Nm +prints a reminder of this when it completes. +.Pp +If +.Nm +stops due to errors, the problems reported should be corrected and +.Nm +should be run again. +.Nm +attempts to avoid changing the compilation directory +if there are configuration errors, +but this code is not well-tested, +and some problems (such as running out of disk space) +are unrecoverable. +.Ss LINT CONFIGURATION +A so-called +.Dq lint +configuration should include everything from the kernel that can +possibly be selected. +The rationale is to provide a way to reach all the code a user might +select, in order to make sure all options and drivers compile without +error for a given source tree. +.Pp +When used with the +.Fl L +flag, +.Nm +takes the regular configuration file +.Ar config-file +and prints on the standard output a configuration file that includes +.Ar config-file , +selects all options and file-systems the user can possibly select, +and defines an instance of every possible attachment as described by +the kernel option definition files used by +.Ar config-file . +.Pp +The resulting configuration file is meant as a way to select all +possible features in order to test that each of them compiles. +It is not meant to result in a kernel binary that can run on any +hardware. +.Pp +Unlike the first synopsis form, the provided +.Ar srcdir +is relative to the current working directory. +In the first synopsis form, it is relative to the build directory. +.Sh SEE ALSO +The SYNOPSIS portion of each device in section 4. +.\".Rs +.\" .%T "Building 4.4 BSD Systems with Config" +.\" .%T "Device Support in 4.4BSD" +.\".Re +.Pp +.Xr options 4 , +.Xr config 5 , +.Xr config 9 +.Sh HISTORY +The +.Nm +command appeared in +.Bx 4.1 . +It was completely revised in +.Bx 4.4 . +The +.Fl x +option appeared in +.Nx 2.0 . +The +.Fl L +option appeared in +.Nx 5.0 . diff --git a/usr.bin/config/config.5 b/usr.bin/config/config.5 new file mode 100644 index 000000000..36c061c8e --- /dev/null +++ b/usr.bin/config/config.5 @@ -0,0 +1,764 @@ +.\" $NetBSD: config.5,v 1.34 2015/09/01 13:42:48 uebayasi Exp $ +.\" +.\" Copyright (c) 2006, 2007 The NetBSD Foundation. +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS +.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS +.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +.\" POSSIBILITY OF SUCH DAMAGE. +.\" +.Dd September 1, 2015 +.Dt CONFIG 5 +.Os +.Sh NAME +.Nm config +.Nd kernel configuration file syntax +.Sh DESCRIPTION +The kernel configuration file specifies the way the kernel should be compiled +by the rest of the toolchain. +It is processed by +.Xr config 1 +to produce a number of files that will allow the user to compile a possibly +customised kernel. +One compilation can issue several kernel binaries, with different root and +dump devices configurations, or with full debugging information. +.Pp +This manual page is intended to serve as a complete reference of all aspects +of the syntax used in the many files processed by +.Xr config 1 . +The novice user will prefer looking at the examples given in +.Xr config.samples 5 +in order to understand better how the default configuration can be changed, +and how all of its elements interact with each other. +.Pp +The kernel configuration file actually contains the description of all the +options, drivers and source files involved in the kernel compilation, and the +logic that binds them. +The +.Ic machine +statement, usually found in the +.Pa std.${MACHINE} +file, hides this from the user by automatically including all the descriptive +files spread all around the kernel source tree, the main one being +.Pa conf/files . +.Pp +Thus, the kernel configuration file contains two parts: +the description of the compilation options, and the selection of those options. +However, it begins with a small preamble that controls a couple of options of +.Xr config 1 , +and a few statements belong to any of the two sections. +.Pp +The user controls the options selection part, which is located in a file +commonly referenced as the +.Em main configuration file +or simply the +.Em kernel configuration file . +The developer is responsible for describing the options in the relevant files +from the kernel source tree. +.Pp +Statements are separated by new-line characters. +However, new-line characters can appear in the middle of a given statement, +with the value of a space character. +.Ss OBJECTS AND NAMES +.Xr config 1 +is a rather complicated piece of software that tries to comply with any +configuration the user might think of. +Quite a few different objects are manipulated through the kernel configuration +file, therefore some definitions are needed. +.Ss Options and attributes +The basic objects driving the kernel compilation are +.Em options , +and are called +.Ar attributes +in some contexts. +An +.Ar attribute +usually refers to a feature a given piece of hardware might have. +However, the scope of an attribute is rather wide and can just be a place +holder to group some source files together. +.Pp +There is a special class of attribute, named +.Em interface attribute , +which represents a hook that allows a device to attach to (i.e., be a child of) +another device. +An +.Em interface attribute +has a (possibly empty) list of +.Ar locators +to match the actual location of a device. +For example, on a PCI bus, devices are located by a +.Em device number +that is fixed by the wiring of the motherboard. +Additionally, each of those devices can appear through several interfaces named +.Em functions . +A single PCI device entity is a unique function number of a given device from +the considered PCI bus. +Therefore, the locators for a +.Xr pci 4 +device are +.Ar dev +(for device), and +.Ar function . +.Pp +A +.Ar locator +can either be a single integer value, or an array of integer values. +It can have a default value, in which case it can be wildcarded with a +.Dq \&? +in the options selection section of the configuration file. +A single +.Ar locator +definition can take one of the following forms: +.Bl -enum -offset indent -compact +.It +.Ar locator +.It +.Ar locator += +.Ar value +.It +.Ar locator Ns Oo Ar length Oc +.It +.Ar locator Ns Oo Ar length Oc = Brq Ar value , ... +.El +The variants that specify a default value can be enclosed into square brackets, +in which case the locator will not have to be specified later in the options +selection section of the configuration file. +.Pp +In the options selection section, the locators are specified when declaring an +instance as a space-separated list of +.Dq Ao Ar locator Ac Ao Ar value Ac +where value can be the +.Dq \&? +wildcard if the locator allows it. +.Ss Devices, instances and attachments +The main benefit of the kernel configuration file is to allow the user to avoid +compiling some drivers, and wire down the configuration of some others. +We have already seen that devices attach to each other through +.Em interface attributes , +but not everything can attach to anything. +Furthermore, the user has the ability to define precise instances for the +devices. +An +.Ar instance +is simply the reality of a device when it is probed and attached by the kernel. +.Pp +Each driver has a name for its devices. +It is called the base device name and is found as +.Ar base +in this documentation. +An +.Ar instance +is the concatenation of a device name and a number. +In the kernel configuration file, instances can sometimes be wildcarded +(i.e., the number is replaced by a +.Dq * +or a +.Dq \&? ) +in order to match all the possible instances of a device. +.Pp +The usual +.Dq * +becomes a +.Dq \&? +when the instance name is used as an +.Em attachment name . +In the options selection part of the kernel configuration files, an +.Em attachment +is an +.Em interface attribute +concatenated with a number or the wildcard +.Dq \&? . +.Ss Pseudo-devices +Some components of the kernel behave like a device although they don't have +any actual reality in the hardware. +For example, this is the case for special network devices, such as +.Xr tun 4 +and +.Xr tap 4 . +They are integrated in the kernel as pseudo-devices, and can have several +instances and even children, just like normal devices. +.Ss Dependencies +The options description part of the kernel configuration file contains all the +logic that ties the source files together, and it is done first through writing +down dependencies between +.Xr config 1 +objects. +.Pp +In this documentation, the syntax for +.Ar dependencies +is a comma-separated list of +.Ar options +and +.Ar attributes . +.Pp +For example, the use of an Ethernet network card requires the source files that +handle the specificities of that protocol. +Therefore, all Ethernet network card drivers depend on the +.Ar ether +attribute. +.Ss Conditions +Finally, source file selection is possible through the help of +conditionals, referred to as +.Ar condition +later in this documentation. +The syntax for those conditions uses well-known operators ( +.Dq \*[Am] , +.Dq | +and +.Dq \&! ) +to combine +.Ar options +and +.Ar attributes . +.Ss CONTEXT NEUTRAL STATEMENTS +.Bl -ohang +.It Ic version Ar yyyymmdd +Indicates the syntax version used by the rest of the file, or until the next +.Ic version +statement. +The argument is an ISO date. +A given +.Xr config 1 +binary might only be compatible with a limited range of version numbers. +.It Ic include Ar path +Includes a file. +The path is relative to the top of the kernel source tree, or the inner-most +defined +.Ic prefix . +.It Ic cinclude Ar path +Conditionally includes a file. +Contrary to +.Ic include , +it will not produce an error if the file does not exist. +The argument obeys the same rules as for +.Ic include . +.It Ic prefix Op Ar path +If +.Ar path +is given, it pushes a new prefix for +.Ic file , +.Ic include +and +.Ic cinclude . +.Ic prefix +statements act like a stack, and an empty +.Ar path +argument has the latest prefix popped out. +The +.Ar path +argument is either absolute or relative to the current defined prefix, which +defaults to the top of the kernel source tree. +.It Ic buildprefix Op Ar path +If +.Ar path +is given, it pushes a new build prefix for +.Ic file . +.Ic buildprefix +statements act like a stack, and an empty +.Ar path +argument has the latest prefix popped out. +The +.Ar path +argument is relative to the current defined buildprefix, which +defaults to the top of the kernel build directory. +When prefix is either absolute or relative out of the kernel source tree (../), +buildprefix must be defined. +.It Ic ifdef Ar attribute +.It Ic ifndef Ar attribute +.It Ic elifdef Ar attribute +.It Ic elifndef Ar attribute +.It Ic else +.It Ic endif +Conditionally interprets portions of the current file. +Those statements depend on whether or not the given +.Ar attribute +has been previously defined, through +.Ic define +or any other statement that implicitely defines attributes such as +.Ic device . +.El +.Ss PREAMBLE +In addition to +.Ic include , cinclude , +and +.Ic prefix , +the preamble may contain the following optional statements: +.Bl -ohang +.It Ic build Ar path +Defines the build directory for the compilation of the kernel. +It replaces the default of +.Pa ../compile/\*[Lt]config-file\*[Gt] +and is superseded by the +.Fl b +parameter of +.Xr config 1 . +.It Ic source Ar path +Defines the directory in which the source of the kernel lives. +It replaces the default of +.Pa ../../../.. +and is superseded by the +.Fl s +parameter of +.Xr config 1 . +.El +.Ss OPTIONS DESCRIPTION +The user will not usually have to use descriptive statements, as they are meant +for the developer to tie a given piece of code to the rest of the kernel. +However, third parties may provide sources to add to the kernel compilation, +and the logic that binds them to the +.Nx +kernel will have to be added to the user-edited configuration file. +.Bl -ohang +.It Ic devclass Ar class +Defines a special attribute, named +.Em device class . +A given device cannot belong to more than one device class. +.Xr config 1 +translates that property by the rule that a device cannot depend on more than +one device class, and will properly fill the configuration information file it +generates according to that value. +.It Ic defflag Oo Ar file Oc Ar option Oo Ar option Oo Ar ... Oc Oc \ + Op : Ar dependencies +Defines a boolean option, that can either be selected or be un-selected by the +user with the +.Ic options +statement. +The optional +.Ar file +argument names a header file that will contain the C pre-processor definition +for the option. +If no file name is given, it will default to +.Ar opt_\*[Lt]option\*[Gt].h . +.Xr config 1 +will always create the header file, but if the user choose not to select the +option, it will be empty. +Several options can be combined in one header file, for convenience. +The header file is created in the compilation directory, making them directly +accessible by source files. +.It Ic defparam Oo Ar file Oc Ar option Oo = Ar value Oc \ + Oo := Ar lint-value Oc Oo Ar option Oo Ar ... Oc Oc Op : Ar dependencies +Behaves like +.Ic defflag , +except the defined option must have a value. +Such options are not typed: +they can have either a numeric or a string value. +If a +.Ar value +is specified, it is treated as a default, and the option is +always defined in the corresponding header file. +If a +.Ar lint-value +is specified, +.Xr config 1 +will use it as a value when generating a lint configuration with +.Fl L , +and ignore it in all other cases. +.It Ic deffs Ar name Op Ar name Op Ar ... +Defines a file-system name. +It is no more than a regular option, as defined by +.Ic defflag , +but it allows the user to select the +file-systems to be compiled in the kernel with the +.Ic file-system +statement instead of the +.Ic options +statement. +.It Ic obsolete defflag Oo Ar file Oc Ar option Op Ar option Op Ar ... +.It Ic obsolete defparam Oo Ar file Oc Ar option Op Ar option Op Ar ... +Those two statements are identical and mark the listed option names as +obsolete. +If the user selects one of the listed options in the kernel configuration +file, +.Xr config 1 +will emit a warning and ignore the option. +The optional +.Ar file +argument should match the original definition of the option. +.It Ic define Ar attribute Oo Bro Ar locators Brc Oc Oo : Ar dependencies Oc +Defines an +.Ar attribute . +The +.Ar locators +list is optional, and can be empty. +If the pair of brackets are present, the locator list is defined and the +declared attribute becomes an +.Em interface attribute , +on which devices can attach. +.It Ic maxpartitions Ar number +Defines the maximum number of partitions the disklabels for the considered +architecture can hold. +This statement cannot be repeated and should only appear in the +.Pa std\&.$\&{ARCH\&} +file. +.It Ic maxusers Ar min default max +Indicates the range of values that will later be accepted by +.Xr config 1 +for the +.Ic maxusers +statement in the options selection part of the configuration file. +In case the user doesn't include a +.Ic maxusers +statement in the configuration file, the value +.Ar default +is used instead. +.It Ic device Ar base Oo Bro Ar locators Brc Oc Oo : dependencies Oc +Declares a device of name +.Ar base . +The optional list of +.Ar locators , +which can also be empty, indicates the device can have children attached +directly to it. +Internally, that means +.Ar base +becomes an +.Ar interface attribute . +For every device the user selects, +.Xr config 1 +will add the matching +.Fn CFDRIVER_DECL +statement to +.Pa ioconf.c . +However, it is the responsibility of the developer to add the relevant +.Fn CFATTACH_DECL +line to the source of the device's driver. +.It Ic attach Ar base Ic at Ar attr Oo , Ar attr Oo , Ar ... Oc Oc Oo Ic with \ + Ar name Oc Oo : dependencies Oc +All devices must have at least one declared attachment. +Otherwise, they will never be found in the +.Xr autoconf 9 +process. +The attributes on which an instance of device +.Ar base +can attach must be +.Ar interface attributes , +or +.Ic root +in case the device is at the top-level, which is usually the case of e.g., +.Xr mainbus 4 . +The instances of device +.Ar base +will later attach to one interface attribute from the specified list. +.Pp +Different +.Ic attach +definitions must use different names using the +.Ic with +option. +It is then possible to use the associated +.Ar name +as a conditional element in a +.Ic file +statement. +.It Ic defpseudo Ar base Oo : dependencies Oc +Declares a pseudo-device. +Those devices don't need an attachment to be declared, they will always be +attached if they were selected by the user. +.It Ic defpseudodev Ar base Oo Bro Ar locators Brc Oc Oo : dependencies Oc +Declares a pseudo-device. +Those devices don't need an attachment to be declared, they will always be +attached if they were selected by the user. +This declaration should be used if the pseudodevice uses +.Xr autoconf 9 +functions to manage its instances or attach children. +As for normal devices, an optional list of +.Ar locators +can be defined, which implies an interface attribute named +.Ar base , +allowing the pseudo-device to have children. +Interface attributes can also be defined in the +.Ar dependencies +list. +.It Ic file Ar path Oo Ar condition Oc Oo Ic needs-count Oc \ + Oo Ic needs-flag Oc Op Ic compile with Ar rule +Adds a source file to the list of files to be compiled into the kernel, if the +.Ar conditions +are met. +The +.Ic needs-count +option indicates that the source file requires the number of all the countable +objects it depends on (through the +.Ar conditions ) +to be defined. +It is usually used for +.Ar pseudo-devices +whose number can be specified by the user in the +.Ic pseudo-device +statement. +Countable objects are devices and pseudo-devices. +For the former, the count is the number of declared instances. +For the latter, it is the number specified by the user, defaulting to 1. +The +.Ic needs-flag +options requires that a flag indicating the selection of an attribute to +be created, but the precise number isn't needed. +This is useful for source files that only partly depend on the attribute, +and thus need to add pre-processor statements for it. +.Pp +.Ic needs-count +and +.Ic needs-flag +both produce a header file for each of the considered attributes. +The name of that file is +.Pa \*[Lt]attribute\*[Gt].h . +It contains one pre-processor definition of +.Dv NATTRIBUTE +set to 0 if the attribute was not selected by the user, or to the number of +instances of the device in the +.Ic needs-count +case, or to 1 in all the other cases. +.Pp +The +.Ar rule +argument specifies the +.Xr make 1 +rule that will be used to compile the source file. +If it is not given, the default rule for the type of the file will be used. +For a given file, there can be more than one +.Ic file +statement, but not from the same configuration source file, and all later +statements can only specify a +.Ar rule +argument, and no +.Ar conditions +or flags. +This is useful when a file needs special consideration from one particular +architecture. +.Pp +The path is relative to the top of the kernel source tree, or the inner-most +defined +.Ic prefix . +.It Ic object Ar path Op Ar condition +Adds an object file to the list of objects to be linked into the kernel, if the +.Ar conditions +are met. +This is most useful for third parties providing binary-only components. +.Pp +The path is relative to the top of the kernel source tree, or the inner-most +defined +.Ic prefix . +.It Ic device-major Ar base Oo Ic char Ar number Oc Oo Ic block Ar number Oc \ + Op Ar condition +Associates a major device number with the device +.Ar base . +A device can be a character device, a block device, or both, and can have +different numbers for each. +The +.Ar condition +indicates when the relevant line should be added to +.Pa ioconf.c , +and works just like the +.Ic file +statement. +.El +.Ss OPTIONS SELECTION +.Bl -ohang +.It Ic machine Ar machine Op Ar arch Op Ar subarch Op Ar ... +The +.Ic machine +statement should appear first in the kernel configuration file, with the +exception of context-neutral statements. +It makes +.Xr config 1 +include, in that order, the following files: +.Bl -enum -offset indent -compact +.It +.Pa conf/files +.It +.Pa arch/${ARCH}/conf/files.${ARCH} +if defined +.It +.Pa arch/${SUBARCH}/conf/files.${SUBARCH} +for each defined sub-architecture +.It +.Pa arch/${MACHINE}/conf/files.${MACHINE} +.El +It also defines an attribute for the +.Ar machine , +the +.Ar arch +and each of the +.Ar subarch . +.It Ic package Ar path +Simpler version of: +.Bd -literal -offset indent +prefix PATH +include FILE +prefix +.Ed +.It Ic ident Ar string +Defines the identification string of the kernel. +This statement is optional, and the name of the main configuration file will be +used as a default value. +.It Ic no ident +Deletes any pre-existing identification string of the kernel. +.It Ic maxusers Ar number +Despite its name, this statement does not limit the maximum number of users on +the system. +There is no such limit, actually. +However, some kernel structures need to be adjusted to accommodate with more +users, and the +.Ic maxusers +parameter is used for example to compute the maximum number of opened files, +and the maximum number of processes, which itself is used to adjust a few +other parameters. +.It Ic options Ar name Oo = Ar value Oc Op , Ar name Oo = Ar \ + value Oc , Ar ... +Selects the option +.Ar name , +affecting it a +.Ar value +if the options requires it (see the +.Ic defflag +and +.Ic defparam +statements). +.Pp +If the option has not been declared in the options description part of the +kernel configuration machinery, it will be added as a pre-processor definition +when source files are compiled. +If the option has previously been selected, the statement produces a +warning, and the new +.Ic options +statement replaces the original. +.It Ic no options Ar name Op , Ar name Op , Ar ... +Un-selects the option +.Ar name . +If option +.Ar name +has not previously been selected, the statement produces a warning. +.It Ic file-system Ar name Op , Ar name Op , Ar ... +Adds support for all the listed file-systems. +.It Ic no file-system Ar name Op , Ar name Op , Ar ... +Removes support for all the listed file-systems. +.It Ic config Ar name Ic root on Ar device Oo Ic type Ar fs Oc Op Ic dumps on \ + Ar device +Adds +.Ar name +to the list of kernel binaries to compile from the configuration file, using +the specified root and dump devices information. +.Pp +Any of the +.Ar device +and +.Ar fs +parameters can be wildcarded with +.Dq \&? +to let the kernel automatically discover those values. +.Pp +At least one +.Ic config +statement must appear in the configuration file. +.It Ic no config Ar name +Removes +.Ar name +from the list of kernel binaries to compile from the configuration file. +.It Ar instance Ic at Ar attachment Op Ar locator specification +Configures an instance of a device attaching at a specific location in the +device tree. +All parameters can be wildcarded, with a +.Dq * +for +.Ar instance , +and a +.Dq \&? +for +.Ar attachment +and the locators. +.It Ic no Ar instance Op Ic at Ar attachment +Removes the previously configured instances of a device that exactly match the +given specification. +If two instances differ only by their locators, both are removed. +If no +.Ar attachment +is specified, all matching instances are removed. +.Pp +If +.Ar instance +is a bare device name, all the previously defined instances of that device, +regardless of the numbers or wildcard, are removed. +.It Ic no device at Ar attachment +Removes all previously configured instances that attach to the specified +attachment. +If +.Ar attachment +ends with a +.Dq * , +all instances attaching to all the variants of +.Ar attachment +are removed. +.It Ic pseudo-device Ar device Op Ar number +Adds support for the specified pseudo-device. +The parameter +.Ar number +is passed to the initialisation function of the pseudo-device, usually to +indicate how many instances should be created. +It defaults to 1, and some pseudo-devices ignore that parameter. +.It Ic no pseudo-device Ar name +Removes support for the specified pseudo-device. +.It Ic makeoptions Ar name Ns = Ns Ar value Op , Ar name Ns += Ns Ar value \ + Op , Ar ... +Adds or appends to a definition in the generated +.Pa Makefile . +A definition cannot be overriden, it must be removed before it can be added +again. +Optionally, if an option +.Pa makeoptions_\*[Lt]name\*[Gt] +is defined with +.Ic defparam , +the +.Ar value +is defined as an option too. +.It Ic makeoptions Ar condition name Ns += Ns Ar value Op , Ar condition \ + name Ns += Ns Ar value +Appends to a definition in the generated +.Pa Makefile . +.It Ic no makeoptions Ar name Op , Ar name Op , Ar ... +Removes one or more definitions from the generated +.Pa Makefile . +.It Ic select Ar name +Adds the specified attribute and its dependencies. +.It Ic no select Ar name +Removes the specified attribute and all the attributes which depend on it. +.El +.Sh FILES +The files are relative to the kernel source top directory (e.g., +.Pa /usr/src/sys ) . +.Pp +.Bl -tag -width arch/${MACHINE}/conf/std.${MACHINE} +.It Pa arch/${MACHINE}/conf/std.${MACHINE} +Standard configuration for the given architecture. +This file should always be included. +.It Pa arch/${MACHINE}/conf/GENERIC +Standard options selection file for the given architecture. +Users should always start changing their main kernel configuration file by +editing a copy of this file. +.It Pa conf/files +Main options description file. +.El +.Sh EXAMPLES +.Xr config.samples 5 +uses several examples to cover all the practical aspects of writing or +modifying a kernel configuration file. +.Sh SEE ALSO +.Xr config 1 , +.Xr options 4 , +.Xr config.samples 5 , +.Xr config 9 diff --git a/usr.bin/config/config.samples.5 b/usr.bin/config/config.samples.5 new file mode 100644 index 000000000..b670c9af0 --- /dev/null +++ b/usr.bin/config/config.samples.5 @@ -0,0 +1,252 @@ +.\" $NetBSD: config.samples.5,v 1.6 2014/03/06 15:00:21 riastradh Exp $ +.\" +.\" Copyright (c) 2006 The NetBSD Foundation. +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS +.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS +.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +.\" POSSIBILITY OF SUCH DAMAGE. +.\" +.Dd June 4, 2006 +.Dt CONFIG.SAMPLES 5 +.Os +.Sh NAME +.Nm config.samples +.Nd kernel configuration file syntax examples +.Sh DESCRIPTION +.Ss Devices, drivers and instances +For a given device, at most one driver will attach. +In order for a driver to attach, the kernel configuration file must include a +compatible instance of the driver for the location of the device. +The following lines from the +.Pa GENERIC +kernel configuration file of +.Nx Ns / Ns i386 +are examples of instances of drivers: +.Bd -literal +pchb* at pci? dev ? function ? # PCI-Host bridges +pcib* at pci? dev ? function ? # PCI-ISA bridges +ppb* at pci? dev ? function ? # PCI-PCI bridges + +siop* at pci? dev ? function ? # Symbios 53c8xx SCSI +esiop* at pci? dev ? function ? # Symbios 53c875 SCSI and newer + +ix0 at isa? port 0x300 irq 10 # EtherExpress/16 +.Ed +.Pp +The first three instances allow three different drivers to attach to all the +matching devices found on any PCI bus. +This is the most generic case. +.Pp +The next two lines allow two distinct drivers to attach to any matching device +found on any PCI bus, but those two drivers are special because they both +support some of the same devices. +Each of the driver has a matching function that returns their score for the +device that is being considered. +.Xr autoconf 9 +decides at run-time which driver will attach. +Of course, it is deterministic so if the user wants to change the driver that +attaches to the device, the instance of the other driver will have to be +removed, e.g. by commenting it out. +.Pp +The last line configures an instance of an ISA device. +Unlike the PCI bus, the ISA bus cannot discover the devices that are present on +the bus. +The driver has to try accessing the device in order to discover it. +That implies locators must be specified to some extent: a driver would +usually need the base address of the device, some need the IRQ line that the +device is configured to use, though some others would just try a set of known +values, at the risk of badly interacting with other devices on the bus. +.Ss Hard-wiring kernel configuration +This technique consists in specifying exactly the location of the devices on a +given system. +In the general case it has very little use, because it does not change the size +of the kernel, and it will prevent it from finding devices in case the hardware +changes, even slightly. +.Pp +Let's consider the following excerpt of +.Xr dmesg 8 +output: +.Bd -literal +auich0 at pci0 dev 31 function 5: i82801DB/DBM (ICH4/ICH4M) AC-97 Audio +.Ed +.Pp +The +.Xr auich 4 +driver (which controls Intel's AC-97 audio chips) attached there because of the +following instance of +.Pa GENERIC : +.Bd -literal +auich* at pci? dev ? function ? +.Ed +.Pp +Hard-wiring that instance means re-writing it to the following: +.Bd -literal +auich0 at pci0 dev 31 function 5 +.Ed +.Pp +and that way, +.Ar auich0 +will attach to that specific location, or will not attach. +.Ss Removing options and drivers +When two kernel configurations differ by a very small number of changes, it is +easier to manage them by having one include the other, and add or remove the +differences. +Removing options and drivers is also useful in the situation of a user who +wants to follow the development of +.Nx : +drivers and options get added to the configuration files found in the source +tree, such as +.Pa GENERIC , +so one can include it and remove all options and drivers that are not relevant +to the considered system. +Additions to +.Pa GENERIC +will then automatically be followed and used in case they are relevant. +.Pp +While negating an options (with +.Ic no options ) +is unambiguous, it is not as clear for devices instances. +.Pp +The +.Ic no Ar instance definition +statements of +.Xr config 1 +syntax only apply on the current state of the configuration file, not on the +resulting kernel binary. +.Xr autoconf 9 +has no knowledge of instance negation, thus it is currently impossible to +express the following in a kernel configuration file: +.Bd -ragged -offset indent +.Do I want support for +.Xr ath 4 +attaching at +.Xr pci 4 , +but I do not want any instance of +.Xr ath 4 +attaching at +.Ar pci3 . +.Dc +.Ed +.Pp +For a real-world use of +.Ic no device at Ar instance +consider the following, taken from +.Nx Ns / Ns i386 : +.Bd -literal -offset indent +include "arch/i386/conf/GENERIC" + +acpi0 at mainbus? + +com* at acpi? +[... more instances of legacy devices attaching at acpi? ...] + +no device at isa0 +.Ed +.Pp +One could actually live without the +.Ar isa0 +instance, as all the legacy devices are attached at +.Ar acpi0 . +But unfortunately, dependencies on the +.Ar isa +attribute are not well registered all through the source tree, so an instance +of the +.Xr isa 4 +driver is required to compile a kernel. +So while: +.Bd -literal -offset indent +no isa* +.Ed +.Pp +is what is intended, the +.Xr isa 4 +instance itself must be kept, and that is precisely the difference made by: +.Bd -literal -offset indent +no device at isa0 +.Ed +.Ss Interface attributes +.Em Interface attributes +are a subtlety of +.Xr config 1 +and +.Xr autoconf 9 , +which often confuses users and utilities that parse +.Xr dmesg 8 +output to manipulate kernel configuration files. +What they are is best shown by the following example. +.Pp +The +.Xr dmesg 8 +output look like this: +.Bd -literal -offset indent +auvia0 at pci0 dev 17 function 5: VIA Technologies VT8235 AC'97 Audio (rev 0x50) +audio0 at auvia0: full duplex, mmap, independent +.Ed +.Pp +while the kernel configuration look like this: +.Bd -literal +auvia* at pci? dev ? function ? +audio* at audiobus? +.Ed +.Pp +It is not obvious from the kernel configuration file that an +.Xr audio 4 +device can attach at an +.Xr auvia 4 +device. +.Ar audiobus +is an +.Em interface attribute , +exposed by +.Ar auvia . +.Pp +Of course, it is possible to specify +.Bd -literal -offset indent +audio* at auvia? +.Ed +in the kernel configuration file, but then one instance per audio controller +would be needed. +.Em Interface attributes +reflect the fact there is a standard way to attach a device to its parent, no +matter what the latter is precisely. +It also means lower maintainance of the kernel configuration files because +drivers for audio controllers are added more easily. +.Pp +Most attachments are done through +.Em interface attributes , +although only a few of them are specified that way in the configuration files +found in the tree. +Another example of such an attribute is +.Ar ata : +.Bd -literal -offset indent +viaide0 at pci0 dev 17 function 1 +atabus0 at viaide0 channel 0 + +viaide* at pci? dev ? function ? +atabus* at ata? +.Ed +.\" Suggested section, maybe for later: +.\" .Ss Using a third-party driver +.Sh SEE ALSO +.Xr config 1 , +.Xr options 4 , +.Xr config 5 , +.Xr dmesg 8 diff --git a/usr.bin/config/defs.h b/usr.bin/config/defs.h new file mode 100644 index 000000000..5b4a4d236 --- /dev/null +++ b/usr.bin/config/defs.h @@ -0,0 +1,666 @@ +/* $NetBSD: defs.h,v 1.93 2015/09/04 10:16:35 uebayasi Exp $ */ + +/* + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Lawrence Berkeley Laboratories. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * from: @(#)config.h 8.1 (Berkeley) 6/6/93 + */ + +/* + * defs.h: Global definitions for "config" + */ + +#if HAVE_NBTOOL_CONFIG_H +#include "nbtool_config.h" +#endif + +#include +#include +#include + +#if !defined(MAKE_BOOTSTRAP) && defined(BSD) +#include +#include +#endif + +#include +#include +#include + +/* These are really for MAKE_BOOTSTRAP but harmless. */ +#ifndef __dead +#define __dead +#endif +#ifndef __printflike +#define __printflike(a, b) +#endif +#ifndef _PATH_DEVNULL +#define _PATH_DEVNULL "/dev/null" +#endif + +#ifdef MAKE_BOOTSTRAP +#undef dev_t +#undef devmajor_t +#undef devminor_t +#undef NODEV +#undef NODEVMAJOR +#undef major +#undef minor +#undef makedev +#define dev_t unsigned int /* XXX: assumes int is 32 bits */ +#define NODEV ((dev_t)-1) +#define devmajor_t int +#define devminor_t int +#define NODEVMAJOR (-1) +#define major(x) ((devmajor_t)((((x) & 0x000fff00) >> 8))) +#define minor(x) ((devminor_t)((((x) & 0xfff00000) >> 12) | \ + (((x) & 0x000000ff) >> 0))) +#define makedev(x,y) ((dev_t)((((x) << 8) & 0x000fff00) | \ + (((y) << 12) & 0xfff00000) | \ + (((y) << 0) & 0x000000ff))) +#define __attribute__(x) +#endif /* MAKE_BOOTSTRAP */ + +#undef setprogname +#undef getprogname +extern const char *progname; +#define setprogname(s) ((void)(progname = (s))) +#define getprogname() (progname) + +#define ARRCHR '#' + +/* + * The next two lines define the current version of the config(1) binary, + * and the minimum version of the configuration files it supports. + */ +#define CONFIG_VERSION 20150846 +#define CONFIG_MINVERSION 0 + +/* + * Name/value lists. Values can be strings or pointers and/or can carry + * integers. The names can be NULL, resulting in simple value lists. + */ +struct nvlist { + struct nvlist *nv_next; + const char *nv_name; + const char *nv_str; + void *nv_ptr; + long long nv_num; + int nv_ifunit; /* XXX XXX XXX */ + int nv_flags; +#define NV_DEPENDED 1 +}; + +/* + * Kernel configurations. + */ +struct config { + TAILQ_ENTRY(config) cf_next; + const char *cf_name; /* "netbsd" */ + int cf_lineno; /* source line */ + const char *cf_fstype; /* file system type */ + struct nvlist *cf_root; /* "root on ra0a" */ + struct nvlist *cf_dump; /* "dumps on ra0b" */ +}; + +/* + * Option definition list + */ +struct defoptlist { + struct defoptlist *dl_next; + const char *dl_name; + const char *dl_value; + const char *dl_lintvalue; + int dl_obsolete; + struct nvlist *dl_depends; +}; + +struct files; +TAILQ_HEAD(filelist, files); + +struct module { + const char *m_name; +#if 1 + struct attrlist *m_deps; +#else + struct attrlist *m_attrs; + struct modulelist *m_deps; +#endif + int m_expanding; + struct filelist m_files; + int m_weight; +}; + +/* + * Attributes. These come in three flavors: "plain", "device class," + * and "interface". Plain attributes (e.g., "ether") simply serve + * to pull in files. Device class attributes are like plain + * attributes, but additionally specify a device class (e.g., the + * "disk" device class attribute specifies that devices with the + * attribute belong to the "DV_DISK" class) and are mutually exclusive. + * Interface attributes (e.g., "scsi") carry three lists: locators, + * child devices, and references. The locators are those things + * that must be specified in order to configure a device instance + * using this attribute (e.g., "tg0 at scsi0"). The a_devs field + * lists child devices that can connect here (e.g., "tg"s), while + * the a_refs are parents that carry the attribute (e.g., actual + * SCSI host adapter drivers such as the SPARC "esp"). + */ +struct attr { + /* XXX */ + struct module a_m; +#define a_name a_m.m_name +#define a_deps a_m.m_deps +#define a_expanding a_m.m_expanding +#define a_files a_m.m_files +#define a_weight a_m.m_weight + + /* "interface attribute" */ + int a_iattr; /* true => allows children */ + struct loclist *a_locs; /* locators required */ + int a_loclen; /* length of above list */ + struct nvlist *a_devs; /* children */ + struct nvlist *a_refs; /* parents */ + + /* "device class" */ + const char *a_devclass; /* device class described */ +}; + +/* + * List of attributes. + */ +struct attrlist { + struct attrlist *al_next; + struct attr *al_this; +}; + +/* + * List of locators. (Either definitions or uses...) + * + * XXX it would be nice if someone could clarify wtf ll_string and ll_num + * are actually holding. (This stuff was previously stored in a very ad + * hoc fashion, and the code is far from clear.) + */ +struct loclist { + const char *ll_name; + const char *ll_string; + long long ll_num; + struct loclist *ll_next; +}; + +/* + * Parent specification. Multiple device instances may share a + * given parent spec. Parent specs are emitted only if there are + * device instances which actually reference it. + */ +struct pspec { + TAILQ_ENTRY(pspec) p_list; /* link on parent spec list */ + struct attr *p_iattr; /* interface attribute of parent */ + struct devbase *p_atdev; /* optional parent device base */ + int p_atunit; /* optional parent device unit */ + struct nvlist *p_devs; /* children using it */ + int p_inst; /* parent spec instance */ + int p_active; /* parent spec is actively used */ +}; + +/* + * The "base" part (struct devbase) of a device ("uba", "sd"; but not + * "uba2" or "sd0"). It may be found "at" one or more attributes, + * including "at root" (this is represented by a NULL attribute), as + * specified by the device attachments (struct deva). + * + * Each device may also export attributes. If any provide an output + * interface (e.g., "esp" provides "scsi"), other devices (e.g., + * "tg"s) can be found at instances of this one (e.g., "esp"s). + * Such a connection must provide locators as specified by that + * interface attribute (e.g., "target"). The base device can + * export both output (aka `interface') attributes, as well as + * import input (`plain') attributes. Device attachments may + * only import input attributes; it makes no sense to have a + * specific attachment export a new interface to other devices. + * + * Each base carries a list of instances (via d_ihead). Note that this + * list "skips over" aliases; those must be found through the instances + * themselves. Each base also carries a list of possible attachments, + * each of which specify a set of devices that the device can attach + * to, as well as the device instances that are actually using that + * attachment. + */ +struct devbase { + const char *d_name; /* e.g., "sd" */ + TAILQ_ENTRY(devbase) d_next; + int d_isdef; /* set once properly defined */ + int d_ispseudo; /* is a pseudo-device */ + devmajor_t d_major; /* used for "root on sd0", e.g. */ + struct attrlist *d_attrs; /* attributes, if any */ + int d_umax; /* highest unit number + 1 */ + struct devi *d_ihead; /* first instance, if any */ + struct devi **d_ipp; /* used for tacking on more instances */ + struct deva *d_ahead; /* first attachment, if any */ + struct deva **d_app; /* used for tacking on attachments */ + struct attr *d_classattr; /* device class attribute (if any) */ +}; + +struct deva { + const char *d_name; /* name of attachment, e.g. "com_isa" */ + TAILQ_ENTRY(deva) d_next; /* list of all instances */ + struct deva *d_bsame; /* list on same base */ + int d_isdef; /* set once properly defined */ + struct devbase *d_devbase; /* the base device */ + struct nvlist *d_atlist; /* e.g., "at tg" (attr list) */ + struct attrlist *d_attrs; /* attributes, if any */ + struct devi *d_ihead; /* first instance, if any */ + struct devi **d_ipp; /* used for tacking on more instances */ +}; + +/* + * An "instance" of a device. The same instance may be listed more + * than once, e.g., "xx0 at isa? port FOO" + "xx0 at isa? port BAR". + * + * After everything has been read in and verified, the devi's are + * "packed" to collect all the information needed to generate ioconf.c. + * In particular, we try to collapse multiple aliases into a single entry. + * We then assign each "primary" (non-collapsed) instance a cfdata index. + * Note that there may still be aliases among these. + */ +struct devi { + /* created while parsing config file */ + const char *i_name; /* e.g., "sd0" */ + int i_unit; /* unit from name, e.g., 0 */ + struct devbase *i_base;/* e.g., pointer to "sd" base */ + TAILQ_ENTRY(devi) i_next; /* list of all instances */ + struct devi *i_bsame; /* list on same base */ + struct devi *i_asame; /* list on same base attachment */ + struct devi *i_alias; /* other aliases of this instance */ + const char *i_at; /* where this is "at" (NULL if at root) */ + struct pspec *i_pspec; /* parent spec (NULL if at root) */ + struct deva *i_atdeva; + const char **i_locs; /* locators (as given by pspec's iattr) */ + int i_cfflags; /* flags from config line */ + int i_lineno; /* line # in config, for later errors */ + const char *i_srcfile; /* file it appears in */ + int i_level; /* position between negated instances */ + int i_active; +#define DEVI_ORPHAN 0 /* instance has no active parent */ +#define DEVI_ACTIVE 1 /* instance has an active parent */ +#define DEVI_IGNORED 2 /* instance's parent has been removed */ +#define DEVI_BROKEN 3 /* instance is broken (syntax error) */ + int i_pseudoroot; /* instance is pseudoroot */ + + /* created during packing or ioconf.c generation */ + short i_collapsed; /* set => this alias no longer needed */ + u_short i_cfindex; /* our index in cfdata */ + int i_locoff; /* offset in locators.vec */ + +}; +/* special units */ +#define STAR (-1) /* unit number for, e.g., "sd*" */ +#define WILD (-2) /* unit number for, e.g., "sd?" */ + +/* + * Files (*.c, *.S, or *.o). This structure defines the common fields + * between the two. + */ +struct files { + TAILQ_ENTRY(files) fi_next; + TAILQ_ENTRY(files) fi_snext; /* per-suffix list */ + const char *fi_srcfile; /* the name of the "files" file that got us */ + u_short fi_srcline; /* and the line number */ + u_char fi_flags; /* as below */ + const char *fi_tail; /* name, i.e., strrchr(fi_path, '/') + 1 */ + const char *fi_base; /* tail minus ".c" (or whatever) */ + const char *fi_dir; /* path to file */ + const char *fi_path; /* full file path */ + const char *fi_prefix; /* any file prefix */ + const char *fi_buildprefix; /* prefix in builddir */ + int fi_suffix; /* single char suffix */ + size_t fi_len; /* path string length */ + struct condexpr *fi_optx; /* options expression */ + struct nvlist *fi_optf; /* flattened version of above, if needed */ + const char *fi_mkrule; /* special make rule, if any */ + struct attr *fi_attr; /* owner attr */ + int fi_order; /* score of order in ${ALLFILES} */ + TAILQ_ENTRY(files) fi_anext; /* next file in attr */ +}; + +/* flags */ +#define FI_SEL 0x01 /* selected */ +#define FI_NEEDSCOUNT 0x02 /* needs-count */ +#define FI_NEEDSFLAG 0x04 /* needs-flag */ +#define FI_HIDDEN 0x08 /* obscured by other(s), base names overlap */ + +extern size_t nselfiles; +extern struct files **selfiles; + +/* + * Condition expressions. + */ + +enum condexpr_types { + CX_ATOM, + CX_NOT, + CX_AND, + CX_OR, +}; +struct condexpr { + enum condexpr_types cx_type; + union { + const char *atom; + struct condexpr *not; + struct { + struct condexpr *left; + struct condexpr *right; + } and, or; + } cx_u; +}; +#define cx_atom cx_u.atom +#define cx_not cx_u.not +#define cx_and cx_u.and +#define cx_or cx_u.or + +/* + * File/object prefixes. These are arranged in a stack, and affect + * the behavior of the source path. + */ + +struct prefix; +SLIST_HEAD(prefixlist, prefix); + +struct prefix { + SLIST_ENTRY(prefix) pf_next; /* next prefix in stack */ + const char *pf_prefix; /* the actual prefix */ +}; + +/* + * Device major informations. + */ +struct devm { + TAILQ_ENTRY(devm) dm_next; + const char *dm_srcfile; /* the name of the "majors" file */ + u_short dm_srcline; /* the line number */ + const char *dm_name; /* [bc]devsw name */ + devmajor_t dm_cmajor; /* character major */ + devmajor_t dm_bmajor; /* block major */ + struct condexpr *dm_opts; /* options */ + struct nvlist *dm_devnodes; /* information on /dev nodes */ +}; + +/* + * Hash tables look up name=value pairs. The pointer value of the name + * is assumed to be constant forever; this can be arranged by interning + * the name. (This is fairly convenient since our lexer does this for + * all identifier-like strings---it has to save them anyway, lest yacc's + * look-ahead wipe out the current one.) + */ +struct hashtab; + +int lkmmode; +const char *conffile; /* source file, e.g., "GENERIC.sparc" */ +const char *machine; /* machine type, e.g., "sparc" or "sun3" */ +const char *machinearch; /* machine arch, e.g., "sparc" or "m68k" */ +struct nvlist *machinesubarches; + /* machine subarches, e.g., "sun68k" or "hpc" */ +const char *ioconfname; /* ioconf name, mutually exclusive to machine */ +const char *srcdir; /* path to source directory (rel. to build) */ +const char *builddir; /* path to build directory */ +const char *defbuilddir; /* default build directory */ +const char *ident; /* kernel "ident"ification string */ +int errors; /* counts calls to error() */ +int minmaxusers; /* minimum "maxusers" parameter */ +int defmaxusers; /* default "maxusers" parameter */ +int maxmaxusers; /* default "maxusers" parameter */ +int maxusers; /* configuration's "maxusers" parameter */ +int maxpartitions; /* configuration's "maxpartitions" parameter */ +int version; /* version of the configuration file */ +struct nvlist *options; /* options */ +struct nvlist *fsoptions; /* filesystems */ +struct nvlist *mkoptions; /* makeoptions */ +struct nvlist *appmkoptions; /* appending mkoptions */ +struct nvlist *condmkoptions; /* conditional makeoption table */ +struct hashtab *devbasetab; /* devbase lookup */ +struct hashtab *devroottab; /* attach at root lookup */ +struct hashtab *devatab; /* devbase attachment lookup */ +struct hashtab *devitab; /* device instance lookup */ +struct hashtab *deaddevitab; /* removed instances lookup */ +struct hashtab *selecttab; /* selects things that are "optional foo" */ +struct hashtab *needcnttab; /* retains names marked "needs-count" */ +struct hashtab *opttab; /* table of configured options */ +struct hashtab *fsopttab; /* table of configured file systems */ +struct dlhash *defopttab; /* options that have been "defopt"'d */ +struct dlhash *defflagtab; /* options that have been "defflag"'d */ +struct dlhash *defparamtab; /* options that have been "defparam"'d */ +struct dlhash *defoptlint; /* lint values for options */ +struct nvhash *deffstab; /* defined file systems */ +struct dlhash *optfiletab; /* "defopt"'d option .h files */ +struct hashtab *attrtab; /* attributes (locators, etc.) */ +struct hashtab *attrdeptab; /* attribute dependencies */ +struct hashtab *bdevmtab; /* block devm lookup */ +struct hashtab *cdevmtab; /* character devm lookup */ + +TAILQ_HEAD(, devbase) allbases; /* list of all devbase structures */ +TAILQ_HEAD(, deva) alldevas; /* list of all devbase attachments */ +TAILQ_HEAD(conftq, config) allcf; /* list of configured kernels */ +TAILQ_HEAD(, devi) alldevi, /* list of all instances */ + allpseudo; /* list of all pseudo-devices */ +TAILQ_HEAD(, devm) alldevms; /* list of all device-majors */ +TAILQ_HEAD(, pspec) allpspecs; /* list of all parent specs */ +int ndevi; /* number of devi's (before packing) */ +int npspecs; /* number of parent specs */ +devmajor_t maxbdevm; /* max number of block major */ +devmajor_t maxcdevm; /* max number of character major */ +int do_devsw; /* 0 if pre-devsw config */ +int oktopackage; /* 0 before setmachine() */ +int devilevel; /* used for devi->i_level */ + +struct filelist allfiles; /* list of all kernel source files */ +struct filelist allcfiles; /* list of all .c files */ +struct filelist allsfiles; /* list of all .S files */ +struct filelist allofiles; /* list of all .o files */ + +struct prefixlist prefixes, /* prefix stack */ + allprefixes; /* all prefixes used (after popped) */ +struct prefixlist buildprefixes, /* build prefix stack */ + allbuildprefixes;/* all build prefixes used (after popped) */ +SLIST_HEAD(, prefix) curdirs; /* curdir stack */ + +extern struct attr allattr; +struct devi **packed; /* arrayified table for packed devi's */ +size_t npacked; /* size of packed table, <= ndevi */ + +struct { /* loc[] table for config */ + const char **vec; + int used; +} locators; + +struct numconst { + int64_t val; + int fmt; +}; + +/* files.c */ +void initfiles(void); +void checkfiles(void); +int fixfiles(void); /* finalize */ +int fixdevsw(void); +void addfile(const char *, struct condexpr *, u_char, const char *); +int expr_eval(struct condexpr *, int (*)(const char *, void *), void *); + +/* hash.c */ +struct hashtab *ht_new(void); +void ht_free(struct hashtab *); +int ht_insrep2(struct hashtab *, const char *, const char *, void *, int); +int ht_insrep(struct hashtab *, const char *, void *, int); +#define ht_insert2(ht, nam1, nam2, val) ht_insrep2(ht, nam1, nam2, val, 0) +#define ht_insert(ht, nam, val) ht_insrep(ht, nam, val, 0) +#define ht_replace(ht, nam, val) ht_insrep(ht, nam, val, 1) +int ht_remove2(struct hashtab *, const char *, const char *); +int ht_remove(struct hashtab *, const char *); +void *ht_lookup2(struct hashtab *, const char *, const char *); +void *ht_lookup(struct hashtab *, const char *); +void initintern(void); +const char *intern(const char *); +typedef int (*ht_callback2)(const char *, const char *, void *, void *); +typedef int (*ht_callback)(const char *, void *, void *); +int ht_enumerate2(struct hashtab *, ht_callback2, void *); +int ht_enumerate(struct hashtab *, ht_callback, void *); + +/* typed hash, named struct HT, whose type is string -> struct VT */ +#define DECLHASH(HT, VT) \ + struct HT; \ + struct HT *HT##_create(void); \ + int HT##_insert(struct HT *, const char *, struct VT *); \ + int HT##_replace(struct HT *, const char *, struct VT *); \ + int HT##_remove(struct HT *, const char *); \ + struct VT *HT##_lookup(struct HT *, const char *); \ + int HT##_enumerate(struct HT *, \ + int (*)(const char *, struct VT *, void *), \ + void *) +DECLHASH(nvhash, nvlist); +DECLHASH(dlhash, defoptlist); + +/* lint.c */ +void emit_instances(void); +void emit_options(void); +void emit_params(void); + +/* main.c */ +extern int Mflag; +extern int Sflag; +void addoption(const char *, const char *); +void addfsoption(const char *); +void addmkoption(const char *, const char *); +void appendmkoption(const char *, const char *); +void appendcondmkoption(struct condexpr *, const char *, const char *); +void deffilesystem(struct nvlist *, struct nvlist *); +void defoption(const char *, struct defoptlist *, struct nvlist *); +void defflag(const char *, struct defoptlist *, struct nvlist *, int); +void defparam(const char *, struct defoptlist *, struct nvlist *, int); +void deloption(const char *); +void delfsoption(const char *); +void delmkoption(const char *); +int devbase_has_instances(struct devbase *, int); +int is_declared_option(const char *); +int deva_has_instances(struct deva *, int); +void setupdirs(void); +void fixmaxusers(void); +void fixmkoption(void); +const char *strtolower(const char *); + +/* tests on option types */ +#define OPT_FSOPT(n) (nvhash_lookup(deffstab, (n)) != NULL) +#define OPT_DEFOPT(n) (dlhash_lookup(defopttab, (n)) != NULL) +#define OPT_DEFFLAG(n) (dlhash_lookup(defflagtab, (n)) != NULL) +#define OPT_DEFPARAM(n) (dlhash_lookup(defparamtab, (n)) != NULL) +#define OPT_OBSOLETE(n) (dlhash_lookup(obsopttab, (n)) != NULL) +#define DEFINED_OPTION(n) (is_declared_option((n))) + +/* main.c */ +void logconfig_include(FILE *, const char *); + +/* mkdevsw.c */ +int mkdevsw(void); + +/* mkheaders.c */ +int mkheaders(void); +int moveifchanged(const char *, const char *); +int emitlocs(void); +int emitioconfh(void); + +/* mkioconf.c */ +int mkioconf(void); + +/* mkmakefile.c */ +int mkmakefile(void); + +/* mkswap.c */ +int mkswap(void); + +/* pack.c */ +void pack(void); + +/* scan.l */ +u_short currentline(void); +int firstfile(const char *); +void package(const char *); +int include(const char *, int, int, int); +extern int includedepth; + +/* sem.c, other than for yacc actions */ +void initsem(void); +int onlist(struct nvlist *, void *); + +/* util.c */ +void prefix_push(const char *); +void prefix_pop(void); +void buildprefix_push(const char *); +void buildprefix_pop(void); +char *sourcepath(const char *); +extern int dflag; +#define CFGDBG(n, ...) \ + do { if ((dflag) >= (n)) cfgdbg(__VA_ARGS__); } while (0) +void cfgdbg(const char *, ...) /* debug info */ + __printflike(1, 2); +void cfgwarn(const char *, ...) /* immediate warns */ + __printflike(1, 2); +void cfgxwarn(const char *, int, const char *, ...) /* delayed warns */ + __printflike(3, 4); +void cfgerror(const char *, ...) /* immediate errs */ + __printflike(1, 2); +void cfgxerror(const char *, int, const char *, ...) /* delayed errs */ + __printflike(3, 4); +__dead void panic(const char *, ...) + __printflike(1, 2); +struct nvlist *newnv(const char *, const char *, void *, long long, struct nvlist *); +void nvfree(struct nvlist *); +void nvfreel(struct nvlist *); +struct nvlist *nvcat(struct nvlist *, struct nvlist *); +void autogen_comment(FILE *, const char *); +struct defoptlist *defoptlist_create(const char *, const char *, const char *); +void defoptlist_destroy(struct defoptlist *); +struct defoptlist *defoptlist_append(struct defoptlist *, struct defoptlist *); +struct attrlist *attrlist_create(void); +struct attrlist *attrlist_cons(struct attrlist *, struct attr *); +void attrlist_destroy(struct attrlist *); +void attrlist_destroyall(struct attrlist *); +struct loclist *loclist_create(const char *, const char *, long long); +void loclist_destroy(struct loclist *); +struct condexpr *condexpr_create(enum condexpr_types); +void condexpr_destroy(struct condexpr *); + +/* liby */ +void yyerror(const char *); +int yylex(void); diff --git a/usr.bin/config/files.c b/usr.bin/config/files.c new file mode 100644 index 000000000..3b43f69bf --- /dev/null +++ b/usr.bin/config/files.c @@ -0,0 +1,622 @@ +/* $NetBSD: files.c,v 1.35 2015/09/04 21:32:54 uebayasi Exp $ */ + +/* + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Lawrence Berkeley Laboratories. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * from: @(#)files.c 8.1 (Berkeley) 6/6/93 + */ + +#if HAVE_NBTOOL_CONFIG_H +#include "nbtool_config.h" +#endif + +#include +__RCSID("$NetBSD: files.c,v 1.35 2015/09/04 21:32:54 uebayasi Exp $"); + +#include +#include +#include +#include +#include +#include +#include +#include "defs.h" + +extern const char *yyfile; + +int nallfiles; +size_t nselfiles; +struct files **selfiles; + +/* + * We check that each full path name is unique. File base names + * should generally also be unique, e.g., having both a net/xx.c and + * a kern/xx.c (or, worse, a net/xx.c and a new/xx.c++) is probably + * wrong, but is permitted under some conditions. + */ +static struct hashtab *basetab; /* file base names */ +static struct hashtab *pathtab; /* full path names */ + +static struct files **unchecked; + +static void addfiletoattr(const char *, struct files *); +static int checkaux(const char *, void *); +static int fixcount(const char *, void *); +static int fixfsel(const char *, void *); +static int fixsel(const char *, void *); + +void +initfiles(void) +{ + + basetab = ht_new(); + pathtab = ht_new(); + TAILQ_INIT(&allfiles); + TAILQ_INIT(&allcfiles); + TAILQ_INIT(&allsfiles); + TAILQ_INIT(&allofiles); + unchecked = &TAILQ_FIRST(&allfiles); +} + +void +addfile(const char *path, struct condexpr *optx, u_char flags, const char *rule) +{ + struct files *fi; + const char *dotp, *tail; + size_t baselen; + size_t dirlen; + int needc, needf; + char base[200]; + char dir[MAXPATHLEN]; + + /* check various errors */ + needc = flags & FI_NEEDSCOUNT; + needf = flags & FI_NEEDSFLAG; + if (needc && needf) { + cfgerror("cannot mix needs-count and needs-flag"); + goto bad; + } + if (optx == NULL && (needc || needf)) { + cfgerror("nothing to %s for %s", needc ? "count" : "flag", + path); + goto bad; + } + if (*path == '/') { + cfgerror("path must be relative"); + goto bad; + } + + /* find last part of pathname, and same without trailing suffix */ + tail = strrchr(path, '/'); + if (tail == NULL) { + dirlen = 0; + tail = path; + } else { + dirlen = (size_t)(tail - path); + tail++; + } + memcpy(dir, path, dirlen); + dir[dirlen] = '\0'; + + dotp = strrchr(tail, '.'); + if (dotp == NULL || dotp[1] == 0 || + (baselen = (size_t)(dotp - tail)) >= sizeof(base)) { + cfgerror("invalid pathname `%s'", path); + goto bad; + } + + /* + * Commit this file to memory. We will decide later whether it + * will be used after all. + */ + fi = ecalloc(1, sizeof *fi); + if (ht_insert(pathtab, path, fi)) { + free(fi); + if ((fi = ht_lookup(pathtab, path)) == NULL) + panic("addfile: ht_lookup(%s)", path); + + /* + * If it's a duplicate entry, it is must specify a make + * rule, and only a make rule, and must come from + * a different source file than the original entry. + * If it does otherwise, it is disallowed. This allows + * machine-dependent files to override the compilation + * options for specific files. + */ + if (rule != NULL && optx == NULL && flags == 0 && + yyfile != fi->fi_srcfile) { + fi->fi_mkrule = rule; + return; + } + cfgerror("duplicate file %s", path); + cfgxerror(fi->fi_srcfile, fi->fi_srcline, + "here is the original definition"); + goto bad; + } + memcpy(base, tail, baselen); + base[baselen] = '\0'; + fi->fi_srcfile = yyfile; + fi->fi_srcline = currentline(); + fi->fi_flags = flags; + fi->fi_path = path; + fi->fi_tail = tail; + fi->fi_base = intern(base); + fi->fi_dir = intern(dir); + fi->fi_prefix = SLIST_EMPTY(&prefixes) ? NULL : + SLIST_FIRST(&prefixes)->pf_prefix; + fi->fi_buildprefix = SLIST_EMPTY(&buildprefixes) ? NULL : + SLIST_FIRST(&buildprefixes)->pf_prefix; + fi->fi_len = strlen(path); + fi->fi_suffix = path[fi->fi_len - 1]; + fi->fi_optx = optx; + fi->fi_optf = NULL; + fi->fi_mkrule = rule; + fi->fi_attr = NULL; + fi->fi_order = (int)nallfiles + (includedepth << 16); + switch (fi->fi_suffix) { + case 'c': + TAILQ_INSERT_TAIL(&allcfiles, fi, fi_snext); + TAILQ_INSERT_TAIL(&allfiles, fi, fi_next); + break; + case 'S': + fi->fi_suffix = 's'; + /* FALLTHRU */ + case 's': + TAILQ_INSERT_TAIL(&allsfiles, fi, fi_snext); + TAILQ_INSERT_TAIL(&allfiles, fi, fi_next); + break; + case 'o': + TAILQ_INSERT_TAIL(&allofiles, fi, fi_snext); + TAILQ_INSERT_TAIL(&allfiles, fi, fi_next); + break; + default: + cfgxerror(fi->fi_srcfile, fi->fi_srcline, + "unknown suffix"); + break; + } + CFGDBG(3, "file added `%s' at order score %d", fi->fi_path, fi->fi_order); + nallfiles++; + return; + bad: + if (optx != NULL) { + condexpr_destroy(optx); + } +} + +static void +addfiletoattr(const char *name, struct files *fi) +{ + struct attr *a; + + a = ht_lookup(attrtab, name); + if (a == NULL) { + CFGDBG(1, "attr `%s' not found", name); + } else { + fi->fi_attr = a; + TAILQ_INSERT_TAIL(&a->a_files, fi, fi_anext); + } +} + +/* + * We have finished reading some "files" file, either ../../conf/files + * or ./files.$machine. Make sure that everything that is flagged as + * needing a count is reasonable. (This prevents ../../conf/files from + * depending on some machine-specific device.) + */ +void +checkfiles(void) +{ + struct files *fi, *last; + + last = NULL; + for (fi = *unchecked; fi != NULL; + last = fi, fi = TAILQ_NEXT(fi, fi_next)) { + if ((fi->fi_flags & FI_NEEDSCOUNT) != 0) + (void)expr_eval(fi->fi_optx, checkaux, fi); + } + if (last != NULL) + unchecked = &TAILQ_NEXT(last, fi_next); +} + +/* + * Auxiliary function for checkfiles, called from expr_eval. + * We are not actually interested in the expression's value. + */ +static int +checkaux(const char *name, void *context) +{ + struct files *fi = context; + + if (ht_lookup(devbasetab, name) == NULL) { + cfgxerror(fi->fi_srcfile, fi->fi_srcline, + "`%s' is not a countable device", + name); + /* keep fixfiles() from complaining again */ + fi->fi_flags |= FI_HIDDEN; + } + return (0); +} + +static int +cmpfiles(const void *a, const void *b) +{ + const struct files * const *fia = a, * const *fib = b; + int sa = (*fia)->fi_order; + int sb = (*fib)->fi_order; + + if (sa < sb) + return -1; + else if (sa > sb) + return 1; + else + return 0; +} + +/* + * We have finished reading everything. Tack the files down: calculate + * selection and counts as needed. Check that the object files built + * from the selected sources do not collide. + */ +int +fixfiles(void) +{ + struct files *fi, *ofi; + struct nvlist *flathead, **flatp; + int err, sel; + struct config *cf; + char swapname[100]; + + /* Place these files at last. */ + int onallfiles = nallfiles; + nallfiles = 1 << 30; + addfile("devsw.c", NULL, 0, NULL); + addfile("ioconf.c", NULL, 0, NULL); + + TAILQ_FOREACH(cf, &allcf, cf_next) { + (void)snprintf(swapname, sizeof(swapname), "swap%s.c", + cf->cf_name); + addfile(intern(swapname), NULL, 0, NULL); + } + nallfiles = onallfiles; + + err = 0; + TAILQ_FOREACH(fi, &allfiles, fi_next) { + + /* Skip files that generated counted-device complaints. */ + if (fi->fi_flags & FI_HIDDEN) + continue; + + if (fi->fi_optx != NULL) { + if (fi->fi_optx->cx_type == CX_ATOM) { + addfiletoattr(fi->fi_optx->cx_u.atom, fi); + } + flathead = NULL; + flatp = &flathead; + sel = expr_eval(fi->fi_optx, + fi->fi_flags & FI_NEEDSCOUNT ? fixcount : + fi->fi_flags & FI_NEEDSFLAG ? fixfsel : + fixsel, + &flatp); + fi->fi_optf = flathead; + if (!sel) + continue; + } + + /* We like this file. Make sure it generates a unique .o. */ + if (ht_insert(basetab, fi->fi_base, fi)) { + if ((ofi = ht_lookup(basetab, fi->fi_base)) == NULL) + panic("fixfiles ht_lookup(%s)", fi->fi_base); + /* + * If the new file comes from a different source, + * allow the new one to override the old one. + */ + if (fi->fi_path != ofi->fi_path) { + if (ht_replace(basetab, fi->fi_base, fi) != 1) + panic("fixfiles ht_replace(%s)", + fi->fi_base); + ofi->fi_flags &= (u_char)~FI_SEL; + ofi->fi_flags |= FI_HIDDEN; + } else { + cfgxerror(fi->fi_srcfile, fi->fi_srcline, + "object file collision on %s.o, from %s", + fi->fi_base, fi->fi_path); + cfgxerror(ofi->fi_srcfile, ofi->fi_srcline, + "here is the previous file: %s", + ofi->fi_path); + err = 1; + } + } + fi->fi_flags |= FI_SEL; + nselfiles++; + CFGDBG(3, "file selected `%s'", fi->fi_path); + + /* Add other files to the default "netbsd" attribute. */ + if (fi->fi_attr == NULL) { + addfiletoattr(allattr.a_name, fi); + } + CFGDBG(3, "file `%s' belongs to attr `%s'", fi->fi_path, + fi->fi_attr->a_name); + } + + /* Order files. */ + selfiles = malloc(nselfiles * sizeof(fi)); + unsigned i = 0; + TAILQ_FOREACH(fi, &allfiles, fi_next) { + if ((fi->fi_flags & FI_SEL) == 0) + continue; + selfiles[i++] = fi; + } + assert(i <= nselfiles); + nselfiles = i; + qsort(selfiles, nselfiles, (unsigned)sizeof(fi), cmpfiles); + return (err); +} + + +/* + * We have finished reading everything. Tack the devsws down: calculate + * selection. + */ +int +fixdevsw(void) +{ + int error; + struct devm *dm, *res; + struct hashtab *fixdevmtab; + char mstr[16]; + + error = 0; + fixdevmtab = ht_new(); + + TAILQ_FOREACH(dm, &alldevms, dm_next) { + res = ht_lookup(fixdevmtab, intern(dm->dm_name)); + if (res != NULL) { + if (res->dm_cmajor != dm->dm_cmajor || + res->dm_bmajor != dm->dm_bmajor) { + cfgxerror(res->dm_srcfile, res->dm_srcline, + "device-major '%s' " + "block %d, char %d redefined" + " at %s:%d as block %d, char %d", + res->dm_name, + res->dm_bmajor, res->dm_cmajor, + dm->dm_srcfile, dm->dm_srcline, + dm->dm_bmajor, dm->dm_cmajor); + } else { + cfgxerror(res->dm_srcfile, res->dm_srcline, + "device-major '%s' " + "(block %d, char %d) duplicated" + " at %s:%d", + dm->dm_name, dm->dm_bmajor, + dm->dm_cmajor, + dm->dm_srcfile, dm->dm_srcline); + } + error = 1; + goto out; + } + if (ht_insert(fixdevmtab, intern(dm->dm_name), dm)) { + panic("fixdevsw: %s char %d block %d", + dm->dm_name, dm->dm_cmajor, dm->dm_bmajor); + } + + if (dm->dm_opts != NULL && + !expr_eval(dm->dm_opts, fixsel, NULL)) + continue; + + if (dm->dm_cmajor != NODEVMAJOR) { + if (ht_lookup(cdevmtab, intern(dm->dm_name)) != NULL) { + cfgxerror(dm->dm_srcfile, dm->dm_srcline, + "device-major of character device '%s' " + "is already defined", dm->dm_name); + error = 1; + goto out; + } + (void)snprintf(mstr, sizeof(mstr), "%d", dm->dm_cmajor); + if (ht_lookup(cdevmtab, intern(mstr)) != NULL) { + cfgxerror(dm->dm_srcfile, dm->dm_srcline, + "device-major of character major '%d' " + "is already defined", dm->dm_cmajor); + error = 1; + goto out; + } + if (ht_insert(cdevmtab, intern(dm->dm_name), dm) || + ht_insert(cdevmtab, intern(mstr), dm)) { + panic("fixdevsw: %s character major %d", + dm->dm_name, dm->dm_cmajor); + } + } + if (dm->dm_bmajor != NODEVMAJOR) { + if (ht_lookup(bdevmtab, intern(dm->dm_name)) != NULL) { + cfgxerror(dm->dm_srcfile, dm->dm_srcline, + "device-major of block device '%s' " + "is already defined", dm->dm_name); + error = 1; + goto out; + } + (void)snprintf(mstr, sizeof(mstr), "%d", dm->dm_bmajor); + if (ht_lookup(bdevmtab, intern(mstr)) != NULL) { + cfgxerror(dm->dm_srcfile, dm->dm_srcline, + "device-major of block major '%d' " + "is already defined", dm->dm_bmajor); + error = 1; + goto out; + } + if (ht_insert(bdevmtab, intern(dm->dm_name), dm) || + ht_insert(bdevmtab, intern(mstr), dm)) { + panic("fixdevsw: %s block major %d", + dm->dm_name, dm->dm_bmajor); + } + } + } + +out: + ht_free(fixdevmtab); + return (error); +} + +/* + * Called when evaluating a needs-count expression. Make sure the + * atom is a countable device. The expression succeeds iff there + * is at least one of them (note that while `xx*' will not always + * set xx's d_umax > 0, you cannot mix '*' and needs-count). The + * mkheaders() routine wants a flattened, in-order list of the + * atoms for `#define name value' lines, so we build that as we + * are called to eval each atom. + */ +static int +fixcount(const char *name, void *context) +{ + struct nvlist ***p = context; + struct devbase *dev; + struct nvlist *nv; + + dev = ht_lookup(devbasetab, name); + if (dev == NULL) /* cannot occur here; we checked earlier */ + panic("fixcount(%s)", name); + nv = newnv(name, NULL, NULL, dev->d_umax, NULL); + **p = nv; + *p = &nv->nv_next; + (void)ht_insert(needcnttab, name, nv); + return (dev->d_umax != 0); +} + +/* + * Called from fixfiles when eval'ing a selection expression for a + * file that will generate a .h with flags. We will need the flat list. + */ +static int +fixfsel(const char *name, void *context) +{ + struct nvlist ***p = context; + struct nvlist *nv; + int sel; + + sel = ht_lookup(selecttab, name) != NULL; + nv = newnv(name, NULL, NULL, sel, NULL); + **p = nv; + *p = &nv->nv_next; + return (sel); +} + +/* + * As for fixfsel above, but we do not need the flat list. + */ +static int +/*ARGSUSED*/ +fixsel(const char *name, void *context) +{ + + return (ht_lookup(selecttab, name) != NULL); +} + +/* + * Eval an expression tree. Calls the given function on each node, + * passing it the given context & the name; return value is &/|/! of + * results of evaluating atoms. + * + * No short circuiting ever occurs. fn must return 0 or 1 (otherwise + * our mixing of C's bitwise & boolean here may give surprises). + */ +int +expr_eval(struct condexpr *expr, int (*fn)(const char *, void *), void *ctx) +{ + int lhs, rhs; + + switch (expr->cx_type) { + + case CX_ATOM: + return ((*fn)(expr->cx_atom, ctx)); + + case CX_NOT: + return (!expr_eval(expr->cx_not, fn, ctx)); + + case CX_AND: + lhs = expr_eval(expr->cx_and.left, fn, ctx); + rhs = expr_eval(expr->cx_and.right, fn, ctx); + return (lhs & rhs); + + case CX_OR: + lhs = expr_eval(expr->cx_or.left, fn, ctx); + rhs = expr_eval(expr->cx_or.right, fn, ctx); + return (lhs | rhs); + } + panic("invalid condexpr type %d", (int)expr->cx_type); + /* NOTREACHED */ + return (0); +} + +#ifdef DEBUG +/* + * Print expression tree. + */ +void +prexpr(struct nvlist *expr) +{ + static void pr0(); + + printf("expr ="); + pr0(expr); + printf("\n"); + (void)fflush(stdout); +} + +static void +pr0(struct nvlist *e) +{ + + switch (e->nv_num) { + case FX_ATOM: + printf(" %s", e->nv_name); + return; + case FX_NOT: + printf(" (!"); + break; + case FX_AND: + printf(" (&"); + break; + case FX_OR: + printf(" (|"); + break; + default: + printf(" (?%lld?", e->nv_num); + break; + } + if (e->nv_ptr) + pr0(e->nv_ptr); + pr0(e->nv_next); + printf(")"); +} +#endif diff --git a/usr.bin/config/gram.c b/usr.bin/config/gram.c new file mode 100644 index 000000000..84dd4a614 --- /dev/null +++ b/usr.bin/config/gram.c @@ -0,0 +1,2431 @@ +/* original parser id follows */ +/* yysccsid[] = "@(#)yaccpar 1.9 (Berkeley) 02/21/93" */ +/* (use YYMAJOR/YYMINOR for ifdefs dependent on parser version) */ + +#define YYBYACC 1 +#define YYMAJOR 1 +#define YYMINOR 9 + +#define YYEMPTY (-1) +#define yyclearin (yychar = YYEMPTY) +#define yyerrok (yyerrflag = 0) +#define YYRECOVERING() (yyerrflag != 0) +#define YYENOMEM (-2) +#define YYEOF 0 +#undef YYBTYACC +#define YYBTYACC 0 +#define YYDEBUGSTR YYPREFIX "debug" +#define YYPREFIX "yy" + +#define YYPURE 0 + +#line 2 "gram.y" +/* $NetBSD: gram.y,v 1.52 2015/09/01 13:42:48 uebayasi Exp $ */ + +/* + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Lawrence Berkeley Laboratories. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * from: @(#)gram.y 8.1 (Berkeley) 6/6/93 + */ + +#include +__RCSID("$NetBSD: gram.y,v 1.52 2015/09/01 13:42:48 uebayasi Exp $"); + +#include +#include +#include +#include +#include +#include +#include +#include "defs.h" +#include "sem.h" + +#define FORMAT(n) (((n).fmt == 8 && (n).val != 0) ? "0%llo" : \ + ((n).fmt == 16) ? "0x%llx" : "%lld") + +#define stop(s) cfgerror(s), exit(1) + +static struct config conf; /* at most one active at a time */ + + +/* + * Allocation wrapper functions + */ +static void wrap_alloc(void *ptr, unsigned code); +static void wrap_continue(void); +static void wrap_cleanup(void); + +/* + * Allocation wrapper type codes + */ +#define WRAP_CODE_nvlist 1 +#define WRAP_CODE_defoptlist 2 +#define WRAP_CODE_loclist 3 +#define WRAP_CODE_attrlist 4 +#define WRAP_CODE_condexpr 5 + +/* + * The allocation wrappers themselves + */ +#define DECL_ALLOCWRAP(t) static struct t *wrap_mk_##t(struct t *arg) + +DECL_ALLOCWRAP(nvlist); +DECL_ALLOCWRAP(defoptlist); +DECL_ALLOCWRAP(loclist); +DECL_ALLOCWRAP(attrlist); +DECL_ALLOCWRAP(condexpr); + +/* allow shorter names */ +#define wrap_mk_loc(p) wrap_mk_loclist(p) +#define wrap_mk_cx(p) wrap_mk_condexpr(p) + +/* + * Macros for allocating new objects + */ + +/* old-style for struct nvlist */ +#define new0(n,s,p,i,x) wrap_mk_nvlist(newnv(n, s, p, i, x)) +#define new_n(n) new0(n, NULL, NULL, 0, NULL) +#define new_nx(n, x) new0(n, NULL, NULL, 0, x) +#define new_ns(n, s) new0(n, s, NULL, 0, NULL) +#define new_si(s, i) new0(NULL, s, NULL, i, NULL) +#define new_nsi(n,s,i) new0(n, s, NULL, i, NULL) +#define new_np(n, p) new0(n, NULL, p, 0, NULL) +#define new_s(s) new0(NULL, s, NULL, 0, NULL) +#define new_p(p) new0(NULL, NULL, p, 0, NULL) +#define new_px(p, x) new0(NULL, NULL, p, 0, x) +#define new_sx(s, x) new0(NULL, s, NULL, 0, x) +#define new_nsx(n,s,x) new0(n, s, NULL, 0, x) +#define new_i(i) new0(NULL, NULL, NULL, i, NULL) + +/* new style, type-polymorphic; ordinary and for types with multiple flavors */ +#define MK0(t) wrap_mk_##t(mk_##t()) +#define MK1(t, a0) wrap_mk_##t(mk_##t(a0)) +#define MK2(t, a0, a1) wrap_mk_##t(mk_##t(a0, a1)) +#define MK3(t, a0, a1, a2) wrap_mk_##t(mk_##t(a0, a1, a2)) + +#define MKF0(t, f) wrap_mk_##t(mk_##t##_##f()) +#define MKF1(t, f, a0) wrap_mk_##t(mk_##t##_##f(a0)) +#define MKF2(t, f, a0, a1) wrap_mk_##t(mk_##t##_##f(a0, a1)) + +/* + * Data constructors + */ + +static struct defoptlist *mk_defoptlist(const char *, const char *, + const char *); +static struct loclist *mk_loc(const char *, const char *, long long); +static struct loclist *mk_loc_val(const char *, struct loclist *); +static struct attrlist *mk_attrlist(struct attrlist *, struct attr *); +static struct condexpr *mk_cx_atom(const char *); +static struct condexpr *mk_cx_not(struct condexpr *); +static struct condexpr *mk_cx_and(struct condexpr *, struct condexpr *); +static struct condexpr *mk_cx_or(struct condexpr *, struct condexpr *); + +/* + * Other private functions + */ + +static void setmachine(const char *, const char *, struct nvlist *, int); +static void check_maxpart(void); + +static struct loclist *present_loclist(struct loclist *ll); +static void app(struct loclist *, struct loclist *); +static struct loclist *locarray(const char *, int, struct loclist *, int); +static struct loclist *namelocvals(const char *, struct loclist *); + +#line 153 "gram.y" +#ifdef YYSTYPE +#undef YYSTYPE_IS_DECLARED +#define YYSTYPE_IS_DECLARED 1 +#endif +#ifndef YYSTYPE_IS_DECLARED +#define YYSTYPE_IS_DECLARED 1 +typedef union { + struct attr *attr; + struct devbase *devb; + struct deva *deva; + struct nvlist *list; + struct defoptlist *defoptlist; + struct loclist *loclist; + struct attrlist *attrlist; + struct condexpr *condexpr; + const char *str; + struct numconst num; + int64_t val; + u_char flag; + devmajor_t devmajor; + int32_t i32; +} YYSTYPE; +#endif /* !YYSTYPE_IS_DECLARED */ +#line 197 "gram.c" + +/* compatibility with bison */ +#ifdef YYPARSE_PARAM +/* compatibility with FreeBSD */ +# ifdef YYPARSE_PARAM_TYPE +# define YYPARSE_DECL() yyparse(YYPARSE_PARAM_TYPE YYPARSE_PARAM) +# else +# define YYPARSE_DECL() yyparse(void *YYPARSE_PARAM) +# endif +#else +# define YYPARSE_DECL() yyparse(void) +#endif + +/* Parameters sent to lex. */ +#ifdef YYLEX_PARAM +# define YYLEX_DECL() yylex(void *YYLEX_PARAM) +# define YYLEX yylex(YYLEX_PARAM) +#else +# define YYLEX_DECL() yylex(void) +# define YYLEX yylex() +#endif + +/* Parameters sent to yyerror. */ +#ifndef YYERROR_DECL +#define YYERROR_DECL() yyerror(const char *s) +#endif +#ifndef YYERROR_CALL +#define YYERROR_CALL(msg) yyerror(msg) +#endif + +extern int YYPARSE_DECL(); + +#define AND 257 +#define AT 258 +#define ATTACH 259 +#define BLOCK 260 +#define BUILD 261 +#define CHAR 262 +#define COLONEQ 263 +#define COMPILE_WITH 264 +#define CONFIG 265 +#define DEFFS 266 +#define DEFINE 267 +#define DEFOPT 268 +#define DEFPARAM 269 +#define DEFFLAG 270 +#define DEFPSEUDO 271 +#define DEFPSEUDODEV 272 +#define DEVICE 273 +#define DEVCLASS 274 +#define DUMPS 275 +#define DEVICE_MAJOR 276 +#define ENDFILE 277 +#define XFILE 278 +#define FILE_SYSTEM 279 +#define FLAGS 280 +#define IDENT 281 +#define IOCONF 282 +#define LINKZERO 283 +#define XMACHINE 284 +#define MAJOR 285 +#define MAKEOPTIONS 286 +#define MAXUSERS 287 +#define MAXPARTITIONS 288 +#define MINOR 289 +#define NEEDS_COUNT 290 +#define NEEDS_FLAG 291 +#define NO 292 +#define XOBJECT 293 +#define OBSOLETE 294 +#define ON 295 +#define OPTIONS 296 +#define PACKAGE 297 +#define PLUSEQ 298 +#define PREFIX 299 +#define BUILDPREFIX 300 +#define PSEUDO_DEVICE 301 +#define PSEUDO_ROOT 302 +#define ROOT 303 +#define SELECT 304 +#define SINGLE 305 +#define SOURCE 306 +#define TYPE 307 +#define VECTOR 308 +#define VERSION 309 +#define WITH 310 +#define NUMBER 311 +#define PATHNAME 312 +#define QSTRING 313 +#define WORD 314 +#define EMPTYSTRING 315 +#define ENDDEFS 316 +#define YYERRCODE 256 +typedef int YYINT; +static const YYINT yylhs[] = { -1, + 0, 57, 57, 61, 61, 61, 58, 58, 58, 58, + 58, 46, 46, 59, 62, 62, 62, 62, 62, 63, + 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, + 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, + 63, 64, 65, 66, 67, 67, 68, 68, 68, 69, + 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, + 80, 81, 82, 83, 84, 85, 1, 1, 9, 9, + 10, 10, 13, 13, 11, 11, 12, 52, 52, 51, + 51, 53, 53, 53, 54, 54, 56, 56, 55, 39, + 39, 38, 18, 18, 18, 20, 20, 21, 21, 21, + 21, 21, 21, 49, 49, 22, 24, 25, 25, 26, + 26, 14, 44, 44, 43, 43, 42, 17, 17, 19, + 19, 41, 41, 40, 40, 40, 40, 86, 86, 88, + 15, 16, 16, 87, 87, 89, 35, 60, 90, 90, + 90, 90, 91, 91, 91, 91, 91, 91, 91, 91, + 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, + 91, 91, 91, 92, 93, 94, 95, 96, 97, 98, + 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, + 109, 110, 111, 113, 113, 121, 112, 112, 122, 115, + 115, 123, 123, 114, 114, 124, 117, 117, 125, 125, + 116, 116, 126, 118, 119, 119, 29, 29, 29, 33, + 8, 8, 120, 120, 128, 36, 36, 30, 30, 31, + 31, 31, 27, 27, 28, 28, 37, 37, 2, 4, + 4, 5, 5, 6, 7, 7, 7, 3, 50, 50, + 45, 45, 47, 47, 32, 32, 32, 32, 48, 48, + 23, 23, 34, 34, 127, 127, +}; +static const YYINT yylen[] = { 2, + 4, 0, 2, 1, 3, 3, 3, 4, 5, 3, + 1, 1, 2, 2, 0, 2, 3, 3, 2, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 5, 4, 6, 2, 1, 2, 2, 1, 2, + 3, 4, 4, 4, 4, 4, 4, 4, 6, 2, + 4, 2, 4, 4, 4, 2, 0, 1, 0, 2, + 1, 1, 0, 2, 0, 2, 1, 0, 2, 0, + 2, 0, 3, 1, 1, 3, 1, 3, 1, 1, + 2, 1, 0, 2, 3, 1, 3, 2, 1, 4, + 4, 5, 7, 1, 1, 2, 4, 0, 2, 1, + 3, 1, 0, 2, 1, 3, 1, 1, 3, 1, + 1, 1, 2, 1, 3, 3, 5, 1, 3, 4, + 1, 0, 2, 1, 3, 3, 1, 1, 0, 2, + 3, 3, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 2, 3, 3, 2, 3, 2, 3, + 2, 2, 2, 2, 4, 3, 3, 3, 2, 4, + 4, 2, 5, 1, 3, 1, 1, 3, 1, 1, + 3, 3, 3, 1, 3, 1, 1, 3, 1, 3, + 1, 3, 1, 1, 3, 4, 1, 1, 1, 4, + 2, 2, 0, 2, 3, 0, 1, 1, 2, 1, + 1, 2, 0, 2, 2, 2, 0, 2, 1, 1, + 3, 1, 3, 1, 1, 2, 3, 1, 1, 1, + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 3, 1, 2, 0, 1, +}; +static const YYINT yydefred[] = { 2, + 0, 0, 11, 0, 0, 0, 0, 4, 15, 3, + 244, 243, 0, 0, 0, 0, 139, 0, 6, 10, + 0, 7, 5, 1, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 14, 16, + 0, 20, 21, 22, 23, 24, 25, 26, 27, 28, + 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, + 39, 40, 41, 12, 8, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 140, 0, + 143, 0, 144, 145, 146, 147, 148, 149, 150, 151, + 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, + 162, 163, 18, 131, 0, 92, 90, 0, 0, 0, + 242, 0, 0, 0, 0, 0, 50, 0, 0, 0, + 238, 0, 0, 0, 235, 0, 0, 232, 234, 0, + 128, 137, 0, 60, 0, 0, 0, 45, 48, 47, + 66, 17, 13, 9, 142, 204, 0, 186, 0, 184, + 249, 250, 173, 239, 0, 0, 0, 190, 0, 0, + 0, 0, 174, 0, 0, 0, 0, 0, 0, 0, + 197, 0, 179, 164, 219, 0, 141, 0, 0, 91, + 51, 0, 0, 0, 122, 0, 0, 0, 0, 0, + 0, 0, 0, 69, 68, 0, 0, 134, 236, 0, + 240, 0, 0, 0, 0, 0, 75, 0, 0, 0, + 213, 0, 0, 0, 0, 176, 0, 189, 0, 187, + 196, 0, 194, 203, 0, 201, 177, 165, 0, 0, + 0, 217, 178, 220, 0, 223, 121, 120, 0, 118, + 117, 115, 0, 105, 104, 94, 0, 0, 0, 0, + 0, 52, 0, 0, 123, 53, 56, 54, 63, 64, + 58, 79, 0, 0, 0, 0, 65, 0, 237, 0, + 0, 233, 129, 61, 0, 0, 0, 256, 0, 0, + 185, 253, 245, 246, 247, 0, 193, 248, 192, 191, + 181, 0, 0, 0, 180, 200, 198, 222, 0, 0, + 0, 0, 0, 0, 95, 0, 0, 0, 98, 112, + 110, 0, 126, 0, 81, 0, 0, 71, 72, 70, + 42, 136, 135, 130, 77, 76, 0, 208, 207, 0, + 209, 0, 214, 254, 188, 195, 202, 0, 0, 224, + 183, 133, 119, 59, 116, 0, 0, 97, 106, 0, + 0, 0, 85, 0, 44, 0, 74, 0, 0, 206, + 0, 228, 225, 226, 0, 0, 100, 0, 111, 127, + 0, 0, 0, 212, 211, 215, 0, 0, 0, 102, + 0, 86, 89, 83, 210, 252, 0, 0, 0, 103, + 0, 88, 107, +}; +#if defined(YYDESTRUCT_CALL) || defined(YYSTYPE_TOSTRING) +static const YYINT yystos[] = { 0, + 318, 375, 256, 261, 282, 284, 306, 10, 376, 379, + 312, 313, 365, 314, 314, 365, 377, 380, 10, 10, + 314, 10, 10, 378, 408, 256, 259, 266, 267, 268, + 269, 270, 271, 272, 273, 274, 276, 277, 278, 285, + 286, 287, 288, 293, 294, 299, 300, 309, 316, 10, + 381, 382, 383, 384, 385, 386, 387, 388, 389, 390, + 391, 392, 393, 394, 395, 396, 397, 398, 399, 400, + 401, 402, 403, 314, 10, 364, 256, 265, 279, 281, + 286, 287, 292, 296, 301, 302, 304, 314, 10, 348, + 381, 409, 410, 411, 412, 413, 414, 415, 416, 417, + 418, 419, 420, 421, 422, 423, 424, 425, 426, 427, + 428, 429, 10, 314, 333, 314, 356, 357, 314, 363, + 365, 363, 363, 333, 333, 333, 314, 314, 365, 123, + 314, 33, 40, 320, 321, 322, 323, 324, 325, 404, + 406, 311, 353, 353, 365, 269, 270, 365, 314, 365, + 353, 10, 314, 10, 10, 314, 436, 314, 431, 439, + 313, 314, 366, 313, 314, 368, 433, 441, 353, 265, + 273, 279, 281, 286, 296, 301, 304, 348, 314, 435, + 443, 314, 348, 314, 42, 258, 10, 258, 58, 356, + 362, 123, 336, 314, 358, 359, 359, 359, 336, 336, + 336, 262, 370, 319, 320, 333, 405, 407, 321, 320, + 314, 368, 124, 38, 44, 353, 319, 363, 363, 303, + 437, 44, 298, 61, 44, 314, 258, 314, 430, 440, + 314, 432, 442, 314, 434, 444, 314, 314, 258, 61, + 44, 353, 354, 303, 314, 349, 303, 314, 335, 337, + 314, 360, 361, 313, 314, 125, 91, 338, 339, 367, + 58, 343, 263, 61, 358, 362, 362, 362, 343, 343, + 343, 353, 260, 369, 327, 61, 125, 44, 41, 298, + 323, 324, 406, 353, 329, 359, 359, 295, 445, 438, + 439, 311, 313, 314, 315, 45, 350, 352, 350, 441, + 349, 44, 44, 44, 349, 350, 443, 63, 345, 310, + 44, 334, 44, 367, 125, 44, 61, 91, 340, 314, + 332, 344, 350, 350, 353, 319, 264, 290, 291, 328, + 331, 353, 407, 350, 291, 330, 285, 314, 63, 347, + 351, 275, 446, 311, 440, 442, 444, 280, 314, 346, + 355, 314, 337, 343, 360, 91, 340, 338, 350, 353, + 44, 263, 305, 308, 371, 372, 366, 311, 307, 326, + 445, 353, 63, 341, 350, 353, 93, 93, 332, 350, + 61, 44, 289, 314, 63, 347, 44, 93, 61, 342, + 311, 374, 283, 373, 311, 341, 342, 123, 58, 93, + 341, 311, 125, +}; +#endif /* YYDESTRUCT_CALL || YYSTYPE_TOSTRING */ +static const YYINT yydgoto[] = { 1, + 204, 134, 135, 136, 137, 138, 139, 370, 275, 330, + 285, 336, 331, 321, 206, 312, 249, 193, 250, 258, + 259, 319, 374, 390, 262, 322, 309, 350, 340, 90, + 246, 375, 341, 298, 216, 243, 351, 117, 118, 195, + 196, 252, 253, 191, 120, 76, 121, 163, 260, 166, + 274, 203, 365, 366, 394, 392, 2, 9, 17, 24, + 10, 18, 51, 52, 53, 54, 55, 56, 57, 58, + 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, + 69, 70, 71, 72, 73, 140, 207, 141, 208, 25, + 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, + 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, + 112, 229, 159, 232, 167, 235, 180, 157, 221, 290, + 160, 230, 168, 233, 181, 236, 289, 343, +}; +static const YYINT yysindex[] = { 0, + 0, 117, 0, -188, -247, -238, -188, 0, 0, 0, + 0, 0, 85, 95, 12, 99, 0, -8, 0, 0, + 19, 0, 0, 0, 51, 101, -198, -193, -182, -188, + -188, -188, -198, -198, -198, -179, -172, 0, -188, 22, + -21, -164, -164, -188, -196, -188, -156, -164, 0, 0, + 141, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 26, 162, -141, -139, -184, + -30, -164, -194, -138, -137, -136, -135, 138, 0, -77, + 0, 172, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, -75, 0, 0, -40, 62, -128, + 0, -128, -128, 62, 62, 62, 0, -74, -21, -198, + 0, -127, -21, -175, 0, 65, 152, 0, 0, 148, + 0, 0, -164, 0, -21, -188, -188, 0, 0, 0, + 0, 0, 0, 0, 0, 0, -110, 0, 150, 0, + 0, 0, 0, 0, 0, -48, 154, 0, -164, -118, + -59, -113, 0, -112, -111, -109, -108, -54, 146, 164, + 0, -164, 0, 0, 0, -231, 0, -221, -105, 0, + 0, -76, 153, -36, 0, -27, -27, -27, 153, 153, + 153, -164, -50, 0, 0, 151, -12, 0, 0, 173, + 0, -85, -21, -21, -21, -164, 0, -128, -128, -80, + 0, -139, 89, 89, -175, 0, -231, 0, 174, 0, + 0, 175, 0, 0, 176, 0, 0, 0, -231, 89, + -138, 0, 0, 0, 158, 0, 0, 0, -28, 0, + 0, 0, 178, 0, 0, 0, -143, 91, 179, -7, + -97, 0, 89, 89, 0, 0, 0, 0, 0, 0, + 0, 0, -164, -21, -173, -164, 0, -198, 0, 89, + 152, 0, 0, 0, -67, -128, -128, 0, -18, -49, + 0, 0, 0, 0, 0, -86, 0, 0, 0, 0, + 0, -113, -112, -111, 0, 0, 0, 0, -236, -84, + -221, 153, -105, 9, 0, -71, 89, -164, 0, 0, + 0, 184, 0, -34, 0, -239, -184, 0, 0, 0, + 0, 0, 0, 0, 0, 0, -79, 0, 0, -72, + 0, -80, 0, 0, 0, 0, 0, -164, 83, 0, + 0, 0, 0, 0, 0, -164, 140, 0, 0, 143, + -97, 89, 0, 180, 0, 195, 0, -45, -25, 0, + -18, 0, 0, 0, 196, 156, 0, 185, 0, 0, + -66, -26, -64, 0, 0, 0, 89, 185, 130, 0, + 198, 0, 0, 0, 0, 0, 161, 89, -39, 0, + 165, 0, 0, +}; +static const YYINT yyrindex[] = { 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 273, 0, 0, 0, 0, -15, + -15, -15, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 324, 331, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, -6, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 101, 31, 0, + 0, 0, 0, 31, 31, 31, 0, -5, 7, 0, + 0, 0, 0, 0, 0, 78, 67, 0, 0, 338, + 0, 0, 0, 0, 4, -15, -15, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 344, 0, + 0, 0, 0, 0, 76, 0, 346, 0, 349, 0, + 0, 0, 0, 0, 0, 0, 0, 353, 50, 354, + 0, 356, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 357, -2, 0, 101, 101, 101, 357, 357, + 357, 0, -3, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, -10, + 0, 0, 0, 0, 0, 0, 0, 0, 360, 0, + 0, 361, 0, 0, 367, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 14, 0, 0, 0, 32, 0, + 0, 0, 372, 0, 0, 0, 0, 0, 262, 6, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 41, 378, 0, 0, 0, 0, 0, + 71, 0, 0, 0, 383, 385, 395, 0, 0, 396, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 397, 0, + 0, 357, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 398, 0, -1, 0, 399, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, + 0, -10, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 400, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 0, 0, 8, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, +}; +#if YYBTYACC +static const YYINT yycindex[] = { 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, +}; +#endif +static const YYINT yygindex[] = { 0, + -124, -90, 279, 0, 199, 200, 0, 0, 0, 0, + 0, 0, 0, 54, 128, 0, 0, 40, 102, 100, + 0, 103, -301, 30, -153, 0, 0, 0, 48, 20, + -159, -165, 0, 0, -42, 0, 0, 302, 0, -133, + -96, 108, 0, -29, 2, 0, 97, 98, 167, 288, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 401, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 212, 155, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 206, 127, 205, 129, 190, 131, 92, 0, +}; +#define YYTABLESIZE 435 +static const YYINT yytable[] = { 143, + 144, 50, 132, 218, 78, 151, 80, 124, 125, 133, + 251, 132, 224, 67, 257, 311, 67, 189, 133, 257, + 217, 22, 205, 221, 264, 197, 198, 78, 75, 80, + 189, 278, 122, 123, 78, 154, 80, 385, 205, 169, + 93, 132, 210, 348, 339, 269, 270, 271, 256, 99, + 67, 101, 255, 317, 205, 124, 125, 297, 299, 199, + 89, 87, 265, 265, 265, 363, 14, 301, 364, 317, + 170, 244, 146, 147, 306, 15, 230, 349, 171, 305, + 231, 247, 245, 318, 172, 396, 173, 229, 93, 132, + 327, 174, 248, 199, 19, 87, 401, 323, 324, 356, + 13, 175, 178, 16, 20, 183, 176, 230, 23, 177, + 113, 231, 277, 238, 334, 114, 328, 329, 229, 88, + 116, 286, 287, 11, 12, 251, 8, 296, 161, 162, + 99, 119, 101, 296, 127, 129, 240, 164, 211, 242, + 145, 128, 148, 150, 130, 373, 142, 218, 219, 326, + 152, 359, 265, 265, 115, 11, 12, 149, 354, 272, + 124, 125, 126, 199, 200, 201, 266, 267, 268, 254, + 255, 155, 156, 284, 158, 179, 182, 88, 184, 185, + 186, 187, 188, 205, 192, 194, 131, 202, 213, 214, + 230, 215, 220, 222, 231, 226, 380, 225, 227, 238, + 228, 231, 234, 239, 237, 238, 240, 241, 251, 273, + 261, 276, 280, 279, 288, 315, 320, 302, 303, 304, + 308, 313, 316, 335, 344, 342, 263, 361, 362, 352, + 325, 368, 377, 332, 369, 378, 254, 255, 382, 387, + 381, 254, 255, 383, 391, 389, 395, 26, 388, 223, + 27, 218, 398, 400, 78, 399, 393, 28, 29, 30, + 31, 32, 33, 34, 35, 36, 337, 37, 38, 39, + 67, 402, 138, 116, 255, 360, 40, 41, 42, 43, + 251, 310, 164, 165, 44, 45, 194, 205, 384, 403, + 46, 47, 131, 221, 67, 338, 67, 67, 241, 78, + 48, 80, 78, 255, 80, 372, 77, 49, 78, 27, + 80, 124, 125, 376, 251, 78, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 21, 37, 221, 39, 79, + 230, 80, 74, 46, 231, 40, 81, 82, 43, 153, + 49, 229, 83, 44, 45, 67, 84, 62, 67, 46, + 47, 85, 86, 167, 87, 169, 230, 230, 172, 48, + 231, 231, 182, 171, 88, 216, 108, 229, 229, 166, + 168, 230, 3, 240, 230, 231, 170, 4, 231, 230, + 230, 114, 229, 231, 231, 229, 96, 73, 238, 238, + 229, 229, 43, 292, 57, 293, 294, 295, 5, 292, + 6, 293, 294, 295, 55, 175, 227, 109, 82, 84, + 209, 281, 353, 282, 379, 358, 357, 397, 386, 190, + 355, 212, 7, 314, 367, 91, 283, 291, 345, 300, + 307, 346, 333, 371, 347, +}; +static const YYINT yycheck[] = { 42, + 43, 10, 33, 10, 10, 48, 10, 10, 10, 40, + 10, 33, 61, 10, 91, 44, 10, 58, 40, 91, + 145, 10, 10, 10, 61, 122, 123, 33, 10, 33, + 58, 44, 31, 32, 40, 10, 40, 63, 129, 82, + 10, 10, 133, 280, 63, 199, 200, 201, 125, 44, + 10, 44, 63, 61, 145, 58, 58, 223, 224, 10, + 10, 10, 196, 197, 198, 305, 314, 227, 308, 61, + 265, 303, 269, 270, 240, 314, 10, 314, 273, 239, + 10, 303, 314, 91, 279, 387, 281, 10, 58, 58, + 264, 286, 314, 44, 10, 44, 398, 263, 264, 91, + 4, 296, 83, 7, 10, 86, 301, 41, 10, 304, + 10, 41, 125, 38, 280, 314, 290, 291, 41, 314, + 314, 218, 219, 312, 313, 125, 10, 45, 313, 314, + 125, 314, 125, 45, 314, 39, 61, 313, 314, 182, + 44, 314, 46, 47, 123, 63, 311, 146, 147, 274, + 10, 317, 286, 287, 27, 312, 313, 314, 312, 202, + 33, 34, 35, 124, 125, 126, 196, 197, 198, 313, + 314, 10, 314, 216, 314, 314, 314, 314, 314, 42, + 258, 10, 258, 274, 123, 314, 314, 262, 124, 38, + 124, 44, 303, 44, 124, 314, 362, 44, 258, 124, + 314, 314, 314, 258, 314, 314, 61, 44, 314, 260, + 58, 61, 298, 41, 295, 125, 314, 44, 44, 44, + 63, 44, 44, 291, 311, 275, 263, 44, 263, 314, + 273, 311, 93, 276, 307, 93, 313, 314, 44, 44, + 61, 313, 314, 289, 311, 61, 311, 256, 93, 298, + 259, 258, 123, 93, 260, 58, 283, 266, 267, 268, + 269, 270, 271, 272, 273, 274, 285, 276, 277, 278, + 264, 311, 0, 314, 285, 318, 285, 286, 287, 288, + 280, 310, 313, 314, 293, 294, 314, 275, 314, 125, + 299, 300, 314, 280, 291, 314, 290, 291, 314, 305, + 309, 305, 308, 314, 308, 348, 256, 316, 314, 259, + 314, 314, 314, 356, 314, 265, 266, 267, 268, 269, + 270, 271, 272, 273, 274, 314, 276, 314, 278, 279, + 264, 281, 314, 10, 264, 285, 286, 287, 288, 314, + 10, 264, 292, 293, 294, 305, 296, 10, 308, 299, + 300, 301, 302, 10, 304, 10, 290, 291, 10, 309, + 290, 291, 10, 10, 314, 10, 10, 290, 291, 10, + 10, 305, 256, 298, 308, 305, 10, 261, 308, 313, + 314, 10, 305, 313, 314, 308, 125, 10, 313, 314, + 313, 314, 10, 311, 10, 313, 314, 315, 282, 311, + 284, 313, 314, 315, 10, 10, 10, 10, 10, 10, + 132, 213, 311, 214, 361, 316, 314, 388, 371, 118, + 313, 134, 306, 257, 327, 25, 215, 222, 302, 225, + 241, 303, 278, 342, 304, +}; +#if YYBTYACC +static const YYINT yyctable[] = { -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, +}; +#endif +#define YYFINAL 1 +#ifndef YYDEBUG +#define YYDEBUG 0 +#endif +#define YYMAXTOKEN 316 +#define YYUNDFTOKEN 447 +#define YYTRANSLATE(a) ((a) > YYMAXTOKEN ? YYUNDFTOKEN : (a)) +#if YYDEBUG +static const char *const yyname[] = { + +"$end",0,0,0,0,0,0,0,0,0,"'\\n'",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +"'!'",0,0,0,0,"'&'",0,"'('","')'","'*'",0,"','","'-'",0,0,0,0,0,0,0,0,0,0,0,0, +"':'",0,0,"'='",0,"'?'",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +"'['",0,"']'",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"'{'", +"'|'","'}'",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"error","AND","AT","ATTACH","BLOCK","BUILD", +"CHAR","COLONEQ","COMPILE_WITH","CONFIG","DEFFS","DEFINE","DEFOPT","DEFPARAM", +"DEFFLAG","DEFPSEUDO","DEFPSEUDODEV","DEVICE","DEVCLASS","DUMPS","DEVICE_MAJOR", +"ENDFILE","XFILE","FILE_SYSTEM","FLAGS","IDENT","IOCONF","LINKZERO","XMACHINE", +"MAJOR","MAKEOPTIONS","MAXUSERS","MAXPARTITIONS","MINOR","NEEDS_COUNT", +"NEEDS_FLAG","NO","XOBJECT","OBSOLETE","ON","OPTIONS","PACKAGE","PLUSEQ", +"PREFIX","BUILDPREFIX","PSEUDO_DEVICE","PSEUDO_ROOT","ROOT","SELECT","SINGLE", +"SOURCE","TYPE","VECTOR","VERSION","WITH","NUMBER","PATHNAME","QSTRING","WORD", +"EMPTYSTRING","ENDDEFS","$accept","configuration","fopts","condexpr","condatom", +"cond_or_expr","cond_and_expr","cond_prefix_expr","cond_base_expr","fs_spec", +"fflags","fflag","oflags","oflag","rule","depend","devbase","devattach_opt", +"atlist","interface_opt","atname","loclist","locdef","locdefault","values", +"locdefaults","depend_list","depends","locators","locator","dev_spec", +"device_instance","attachment","value","major_minor","signed_number","int32", +"npseudo","device_flags","deffs","deffses","defopt","defopts","optdepend", +"optdepends","optdepend_list","optfile_opt","subarches","filename", +"stringvalue","locname","mkvarname","device_major_block","device_major_char", +"devnodes","devnodetype","devnodeflags","devnode_dims","topthings", +"machine_spec","definition_part","selection_part","topthing","definitions", +"definition","define_file","define_object","define_device_major", +"define_prefix","define_buildprefix","define_devclass","define_filesystems", +"define_attribute","define_option","define_flag","define_obsolete_flag", +"define_param","define_obsolete_param","define_device", +"define_device_attachment","define_maxpartitions","define_maxusers", +"define_makeoptions","define_pseudo","define_pseudodev","define_major", +"define_version","condmkopt_list","majorlist","condmkoption","majordef", +"selections","selection","select_attr","select_no_attr","select_no_filesystems", +"select_filesystems","select_no_makeoptions","select_makeoptions", +"select_no_options","select_options","select_maxusers","select_ident", +"select_no_ident","select_config","select_no_config","select_no_pseudodev", +"select_pseudodev","select_pseudoroot","select_no_device_instance_attachment", +"select_no_device_attachment","select_no_device_instance", +"select_device_instance","no_fs_list","fs_list","no_mkopt_list","mkopt_list", +"no_opt_list","opt_list","conf","root_spec","sysparam_list","fsoption", +"no_fsoption","mkoption","no_mkoption","option","no_option","on_opt","sysparam", +"illegal-symbol", +}; +static const char *const yyrule[] = { +"$accept : configuration", +"configuration : topthings machine_spec definition_part selection_part", +"topthings :", +"topthings : topthings topthing", +"topthing : '\\n'", +"topthing : SOURCE filename '\\n'", +"topthing : BUILD filename '\\n'", +"machine_spec : XMACHINE WORD '\\n'", +"machine_spec : XMACHINE WORD WORD '\\n'", +"machine_spec : XMACHINE WORD WORD subarches '\\n'", +"machine_spec : IOCONF WORD '\\n'", +"machine_spec : error", +"subarches : WORD", +"subarches : subarches WORD", +"definition_part : definitions ENDDEFS", +"definitions :", +"definitions : definitions '\\n'", +"definitions : definitions definition '\\n'", +"definitions : definitions error '\\n'", +"definitions : definitions ENDFILE", +"definition : define_file", +"definition : define_object", +"definition : define_device_major", +"definition : define_prefix", +"definition : define_buildprefix", +"definition : define_devclass", +"definition : define_filesystems", +"definition : define_attribute", +"definition : define_option", +"definition : define_flag", +"definition : define_obsolete_flag", +"definition : define_param", +"definition : define_obsolete_param", +"definition : define_device", +"definition : define_device_attachment", +"definition : define_maxpartitions", +"definition : define_maxusers", +"definition : define_makeoptions", +"definition : define_pseudo", +"definition : define_pseudodev", +"definition : define_major", +"definition : define_version", +"define_file : XFILE filename fopts fflags rule", +"define_object : XOBJECT filename fopts oflags", +"define_device_major : DEVICE_MAJOR WORD device_major_char device_major_block fopts devnodes", +"define_prefix : PREFIX filename", +"define_prefix : PREFIX", +"define_buildprefix : BUILDPREFIX filename", +"define_buildprefix : BUILDPREFIX WORD", +"define_buildprefix : BUILDPREFIX", +"define_devclass : DEVCLASS WORD", +"define_filesystems : DEFFS deffses optdepend_list", +"define_attribute : DEFINE WORD interface_opt depend_list", +"define_option : DEFOPT optfile_opt defopts optdepend_list", +"define_flag : DEFFLAG optfile_opt defopts optdepend_list", +"define_obsolete_flag : OBSOLETE DEFFLAG optfile_opt defopts", +"define_param : DEFPARAM optfile_opt defopts optdepend_list", +"define_obsolete_param : OBSOLETE DEFPARAM optfile_opt defopts", +"define_device : DEVICE devbase interface_opt depend_list", +"define_device_attachment : ATTACH devbase AT atlist devattach_opt depend_list", +"define_maxpartitions : MAXPARTITIONS int32", +"define_maxusers : MAXUSERS int32 int32 int32", +"define_makeoptions : MAKEOPTIONS condmkopt_list", +"define_pseudo : DEFPSEUDO devbase interface_opt depend_list", +"define_pseudodev : DEFPSEUDODEV devbase interface_opt depend_list", +"define_major : MAJOR '{' majorlist '}'", +"define_version : VERSION int32", +"fopts :", +"fopts : condexpr", +"fflags :", +"fflags : fflags fflag", +"fflag : NEEDS_COUNT", +"fflag : NEEDS_FLAG", +"rule :", +"rule : COMPILE_WITH stringvalue", +"oflags :", +"oflags : oflags oflag", +"oflag : NEEDS_FLAG", +"device_major_char :", +"device_major_char : CHAR int32", +"device_major_block :", +"device_major_block : BLOCK int32", +"devnodes :", +"devnodes : devnodetype ',' devnodeflags", +"devnodes : devnodetype", +"devnodetype : SINGLE", +"devnodetype : VECTOR '=' devnode_dims", +"devnode_dims : NUMBER", +"devnode_dims : NUMBER ':' NUMBER", +"devnodeflags : LINKZERO", +"deffses : deffs", +"deffses : deffses deffs", +"deffs : WORD", +"interface_opt :", +"interface_opt : '{' '}'", +"interface_opt : '{' loclist '}'", +"loclist : locdef", +"loclist : locdef ',' loclist", +"locdef : locname locdefault", +"locdef : locname", +"locdef : '[' locname locdefault ']'", +"locdef : locname '[' int32 ']'", +"locdef : locname '[' int32 ']' locdefaults", +"locdef : '[' locname '[' int32 ']' locdefaults ']'", +"locname : WORD", +"locname : QSTRING", +"locdefault : '=' value", +"locdefaults : '=' '{' values '}'", +"depend_list :", +"depend_list : ':' depends", +"depends : depend", +"depends : depends ',' depend", +"depend : WORD", +"optdepend_list :", +"optdepend_list : ':' optdepends", +"optdepends : optdepend", +"optdepends : optdepends ',' optdepend", +"optdepend : WORD", +"atlist : atname", +"atlist : atlist ',' atname", +"atname : WORD", +"atname : ROOT", +"defopts : defopt", +"defopts : defopts defopt", +"defopt : WORD", +"defopt : WORD '=' value", +"defopt : WORD COLONEQ value", +"defopt : WORD '=' value COLONEQ value", +"condmkopt_list : condmkoption", +"condmkopt_list : condmkopt_list ',' condmkoption", +"condmkoption : condexpr mkvarname PLUSEQ value", +"devbase : WORD", +"devattach_opt :", +"devattach_opt : WITH WORD", +"majorlist : majordef", +"majorlist : majorlist ',' majordef", +"majordef : devbase '=' int32", +"int32 : NUMBER", +"selection_part : selections", +"selections :", +"selections : selections '\\n'", +"selections : selections selection '\\n'", +"selections : selections error '\\n'", +"selection : definition", +"selection : select_attr", +"selection : select_no_attr", +"selection : select_no_filesystems", +"selection : select_filesystems", +"selection : select_no_makeoptions", +"selection : select_makeoptions", +"selection : select_no_options", +"selection : select_options", +"selection : select_maxusers", +"selection : select_ident", +"selection : select_no_ident", +"selection : select_config", +"selection : select_no_config", +"selection : select_no_pseudodev", +"selection : select_pseudodev", +"selection : select_pseudoroot", +"selection : select_no_device_instance_attachment", +"selection : select_no_device_attachment", +"selection : select_no_device_instance", +"selection : select_device_instance", +"select_attr : SELECT WORD", +"select_no_attr : NO SELECT WORD", +"select_no_filesystems : NO FILE_SYSTEM no_fs_list", +"select_filesystems : FILE_SYSTEM fs_list", +"select_no_makeoptions : NO MAKEOPTIONS no_mkopt_list", +"select_makeoptions : MAKEOPTIONS mkopt_list", +"select_no_options : NO OPTIONS no_opt_list", +"select_options : OPTIONS opt_list", +"select_maxusers : MAXUSERS int32", +"select_ident : IDENT stringvalue", +"select_no_ident : NO IDENT", +"select_config : CONFIG conf root_spec sysparam_list", +"select_no_config : NO CONFIG WORD", +"select_no_pseudodev : NO PSEUDO_DEVICE WORD", +"select_pseudodev : PSEUDO_DEVICE WORD npseudo", +"select_pseudoroot : PSEUDO_ROOT device_instance", +"select_no_device_instance_attachment : NO device_instance AT attachment", +"select_no_device_attachment : NO DEVICE AT attachment", +"select_no_device_instance : NO device_instance", +"select_device_instance : device_instance AT attachment locators device_flags", +"fs_list : fsoption", +"fs_list : fs_list ',' fsoption", +"fsoption : WORD", +"no_fs_list : no_fsoption", +"no_fs_list : no_fs_list ',' no_fsoption", +"no_fsoption : WORD", +"mkopt_list : mkoption", +"mkopt_list : mkopt_list ',' mkoption", +"mkoption : mkvarname '=' value", +"mkoption : mkvarname PLUSEQ value", +"no_mkopt_list : no_mkoption", +"no_mkopt_list : no_mkopt_list ',' no_mkoption", +"no_mkoption : WORD", +"opt_list : option", +"opt_list : opt_list ',' option", +"option : WORD", +"option : WORD '=' value", +"no_opt_list : no_option", +"no_opt_list : no_opt_list ',' no_option", +"no_option : WORD", +"conf : WORD", +"root_spec : ROOT on_opt dev_spec", +"root_spec : ROOT on_opt dev_spec fs_spec", +"dev_spec : '?'", +"dev_spec : WORD", +"dev_spec : major_minor", +"major_minor : MAJOR NUMBER MINOR NUMBER", +"fs_spec : TYPE '?'", +"fs_spec : TYPE WORD", +"sysparam_list :", +"sysparam_list : sysparam_list sysparam", +"sysparam : DUMPS on_opt dev_spec", +"npseudo :", +"npseudo : int32", +"device_instance : WORD", +"device_instance : WORD '*'", +"attachment : ROOT", +"attachment : WORD", +"attachment : WORD '?'", +"locators :", +"locators : locators locator", +"locator : WORD '?'", +"locator : WORD values", +"device_flags :", +"device_flags : FLAGS int32", +"condexpr : cond_or_expr", +"cond_or_expr : cond_and_expr", +"cond_or_expr : cond_or_expr '|' cond_and_expr", +"cond_and_expr : cond_prefix_expr", +"cond_and_expr : cond_and_expr '&' cond_prefix_expr", +"cond_prefix_expr : cond_base_expr", +"cond_base_expr : condatom", +"cond_base_expr : '!' condatom", +"cond_base_expr : '(' condexpr ')'", +"condatom : WORD", +"mkvarname : QSTRING", +"mkvarname : WORD", +"optfile_opt :", +"optfile_opt : filename", +"filename : QSTRING", +"filename : PATHNAME", +"value : QSTRING", +"value : WORD", +"value : EMPTYSTRING", +"value : signed_number", +"stringvalue : QSTRING", +"stringvalue : WORD", +"values : value", +"values : value ',' values", +"signed_number : NUMBER", +"signed_number : '-' NUMBER", +"on_opt :", +"on_opt : ON", + +}; +#endif + +int yydebug; +int yynerrs; + +int yyerrflag; +int yychar; +YYSTYPE yyval; +YYSTYPE yylval; + +/* define the initial stack-sizes */ +#ifdef YYSTACKSIZE +#undef YYMAXDEPTH +#define YYMAXDEPTH YYSTACKSIZE +#else +#ifdef YYMAXDEPTH +#define YYSTACKSIZE YYMAXDEPTH +#else +#define YYSTACKSIZE 10000 +#define YYMAXDEPTH 10000 +#endif +#endif + +#define YYINITSTACKSIZE 200 + +typedef struct { + unsigned stacksize; + YYINT *s_base; + YYINT *s_mark; + YYINT *s_last; + YYSTYPE *l_base; + YYSTYPE *l_mark; +} YYSTACKDATA; +/* variables for the parser stack */ +static YYSTACKDATA yystack; +#line 1083 "gram.y" + +void +yyerror(const char *s) +{ + + cfgerror("%s", s); +} + +/************************************************************/ + +/* + * Wrap allocations that live on the parser stack so that we can free + * them again on error instead of leaking. + */ + +#define MAX_WRAP 1000 + +struct wrap_entry { + void *ptr; + unsigned typecode; +}; + +static struct wrap_entry wrapstack[MAX_WRAP]; +static unsigned wrap_depth; + +/* + * Remember pointer PTR with type-code CODE. + */ +static void +wrap_alloc(void *ptr, unsigned code) +{ + unsigned pos; + + if (wrap_depth >= MAX_WRAP) { + panic("allocation wrapper stack overflow"); + } + pos = wrap_depth++; + wrapstack[pos].ptr = ptr; + wrapstack[pos].typecode = code; +} + +/* + * We succeeded; commit to keeping everything that's been allocated so + * far and clear the stack. + */ +static void +wrap_continue(void) +{ + wrap_depth = 0; +} + +/* + * We failed; destroy all the objects allocated. + */ +static void +wrap_cleanup(void) +{ + unsigned i; + + /* + * Destroy each item. Note that because everything allocated + * is entered on the list separately, lists and trees need to + * have their links blanked before being destroyed. Also note + * that strings are interned elsewhere and not handled by this + * mechanism. + */ + + for (i=0; idl_next = NULL; + defoptlist_destroy(dl); + } + break; + case WRAP_CODE_loclist: + { + struct loclist *ll = wrapstack[i].ptr; + + ll->ll_next = NULL; + loclist_destroy(ll); + } + break; + case WRAP_CODE_attrlist: + { + struct attrlist *al = wrapstack[i].ptr; + + al->al_next = NULL; + al->al_this = NULL; + attrlist_destroy(al); + } + break; + case WRAP_CODE_condexpr: + { + struct condexpr *cx = wrapstack[i].ptr; + + cx->cx_type = CX_ATOM; + cx->cx_atom = NULL; + condexpr_destroy(cx); + } + break; + default: + panic("invalid code %u on allocation wrapper stack", + wrapstack[i].typecode); + } + } + + wrap_depth = 0; +} + +/* + * Instantiate the wrapper functions. + * + * Each one calls wrap_alloc to save the pointer and then returns the + * pointer again; these need to be generated with the preprocessor in + * order to be typesafe. + */ +#define DEF_ALLOCWRAP(t) \ + static struct t * \ + wrap_mk_##t(struct t *arg) \ + { \ + wrap_alloc(arg, WRAP_CODE_##t); \ + return arg; \ + } + +DEF_ALLOCWRAP(nvlist); +DEF_ALLOCWRAP(defoptlist); +DEF_ALLOCWRAP(loclist); +DEF_ALLOCWRAP(attrlist); +DEF_ALLOCWRAP(condexpr); + +/************************************************************/ + +/* + * Data constructors + * + * (These are *beneath* the allocation wrappers.) + */ + +static struct defoptlist * +mk_defoptlist(const char *name, const char *val, const char *lintval) +{ + return defoptlist_create(name, val, lintval); +} + +static struct loclist * +mk_loc(const char *name, const char *str, long long num) +{ + return loclist_create(name, str, num); +} + +static struct loclist * +mk_loc_val(const char *str, struct loclist *next) +{ + struct loclist *ll; + + ll = mk_loc(NULL, str, 0); + ll->ll_next = next; + return ll; +} + +static struct attrlist * +mk_attrlist(struct attrlist *next, struct attr *a) +{ + return attrlist_cons(next, a); +} + +static struct condexpr * +mk_cx_atom(const char *s) +{ + struct condexpr *cx; + + cx = condexpr_create(CX_ATOM); + cx->cx_atom = s; + return cx; +} + +static struct condexpr * +mk_cx_not(struct condexpr *sub) +{ + struct condexpr *cx; + + cx = condexpr_create(CX_NOT); + cx->cx_not = sub; + return cx; +} + +static struct condexpr * +mk_cx_and(struct condexpr *left, struct condexpr *right) +{ + struct condexpr *cx; + + cx = condexpr_create(CX_AND); + cx->cx_and.left = left; + cx->cx_and.right = right; + return cx; +} + +static struct condexpr * +mk_cx_or(struct condexpr *left, struct condexpr *right) +{ + struct condexpr *cx; + + cx = condexpr_create(CX_OR); + cx->cx_or.left = left; + cx->cx_or.right = right; + return cx; +} + +/************************************************************/ + +static void +setmachine(const char *mch, const char *mcharch, struct nvlist *mchsubarches, + int isioconf) +{ + char buf[MAXPATHLEN]; + struct nvlist *nv; + + if (isioconf) { + if (include(_PATH_DEVNULL, ENDDEFS, 0, 0) != 0) + exit(1); + ioconfname = mch; + return; + } + + machine = mch; + machinearch = mcharch; + machinesubarches = mchsubarches; + + /* + * Define attributes for all the given names + */ + if (defattr(machine, NULL, NULL, 0) != 0 || + (machinearch != NULL && + defattr(machinearch, NULL, NULL, 0) != 0)) + exit(1); + for (nv = machinesubarches; nv != NULL; nv = nv->nv_next) { + if (defattr(nv->nv_name, NULL, NULL, 0) != 0) + exit(1); + } + + /* + * Set up the file inclusion stack. This empty include tells + * the parser there are no more device definitions coming. + */ + if (include(_PATH_DEVNULL, ENDDEFS, 0, 0) != 0) + exit(1); + + /* Include arch/${MACHINE}/conf/files.${MACHINE} */ + (void)snprintf(buf, sizeof(buf), "arch/%s/conf/files.%s", + machine, machine); + if (include(buf, ENDFILE, 0, 0) != 0) + exit(1); + + /* Include any arch/${MACHINE_SUBARCH}/conf/files.${MACHINE_SUBARCH} */ + for (nv = machinesubarches; nv != NULL; nv = nv->nv_next) { + (void)snprintf(buf, sizeof(buf), "arch/%s/conf/files.%s", + nv->nv_name, nv->nv_name); + if (include(buf, ENDFILE, 0, 0) != 0) + exit(1); + } + + /* Include any arch/${MACHINE_ARCH}/conf/files.${MACHINE_ARCH} */ + if (machinearch != NULL) + (void)snprintf(buf, sizeof(buf), "arch/%s/conf/files.%s", + machinearch, machinearch); + else + strlcpy(buf, _PATH_DEVNULL, sizeof(buf)); + if (include(buf, ENDFILE, 0, 0) != 0) + exit(1); + + /* + * Include the global conf/files. As the last thing + * pushed on the stack, it will be processed first. + */ + if (include("conf/files", ENDFILE, 0, 0) != 0) + exit(1); + + oktopackage = 1; +} + +static void +check_maxpart(void) +{ + + if (maxpartitions <= 0 && ioconfname == NULL) { + stop("cannot proceed without maxpartitions specifier"); + } +} + +static void +check_version(void) +{ + /* + * In essence, version is 0 and is not supported anymore + */ + if (version < CONFIG_MINVERSION) + stop("your sources are out of date -- please update."); +} + +/* + * Prepend a blank entry to the locator definitions so the code in + * sem.c can distinguish "empty locator list" from "no locator list". + * XXX gross. + */ +static struct loclist * +present_loclist(struct loclist *ll) +{ + struct loclist *ret; + + ret = MK3(loc, "", NULL, 0); + ret->ll_next = ll; + return ret; +} + +static void +app(struct loclist *p, struct loclist *q) +{ + while (p->ll_next) + p = p->ll_next; + p->ll_next = q; +} + +static struct loclist * +locarray(const char *name, int count, struct loclist *adefs, int opt) +{ + struct loclist *defs = adefs; + struct loclist **p; + char buf[200]; + int i; + + if (count <= 0) { + fprintf(stderr, "config: array with <= 0 size: %s\n", name); + exit(1); + } + p = &defs; + for(i = 0; i < count; i++) { + if (*p == NULL) + *p = MK3(loc, NULL, "0", 0); + snprintf(buf, sizeof(buf), "%s%c%d", name, ARRCHR, i); + (*p)->ll_name = i == 0 ? name : intern(buf); + (*p)->ll_num = i > 0 || opt; + p = &(*p)->ll_next; + } + *p = 0; + return defs; +} + + +static struct loclist * +namelocvals(const char *name, struct loclist *vals) +{ + struct loclist *p; + char buf[200]; + int i; + + for (i = 0, p = vals; p; i++, p = p->ll_next) { + snprintf(buf, sizeof(buf), "%s%c%d", name, ARRCHR, i); + p->ll_name = i == 0 ? name : intern(buf); + } + return vals; +} + +#line 1456 "gram.c" + +#if YYDEBUG +#include /* needed for printf */ +#endif + +#include /* needed for malloc, etc */ +#include /* needed for memset */ + +/* allocate initial stack or double stack size, up to YYMAXDEPTH */ +static int yygrowstack(YYSTACKDATA *data) +{ + int i; + unsigned newsize; + YYINT *newss; + YYSTYPE *newvs; + + if ((newsize = data->stacksize) == 0) + newsize = YYINITSTACKSIZE; + else if (newsize >= YYMAXDEPTH) + return YYENOMEM; + else if ((newsize *= 2) > YYMAXDEPTH) + newsize = YYMAXDEPTH; + + i = (int) (data->s_mark - data->s_base); + newss = (YYINT *)realloc(data->s_base, newsize * sizeof(*newss)); + if (newss == 0) + return YYENOMEM; + + data->s_base = newss; + data->s_mark = newss + i; + + newvs = (YYSTYPE *)realloc(data->l_base, newsize * sizeof(*newvs)); + if (newvs == 0) + return YYENOMEM; + + data->l_base = newvs; + data->l_mark = newvs + i; + + data->stacksize = newsize; + data->s_last = data->s_base + newsize - 1; + return 0; +} + +#if YYPURE || defined(YY_NO_LEAKS) +static void yyfreestack(YYSTACKDATA *data) +{ + free(data->s_base); + free(data->l_base); + memset(data, 0, sizeof(*data)); +} +#else +#define yyfreestack(data) /* nothing */ +#endif + +#define YYABORT goto yyabort +#define YYREJECT goto yyabort +#define YYACCEPT goto yyaccept +#define YYERROR goto yyerrlab + +int +YYPARSE_DECL() +{ + int yym, yyn, yystate; +#if YYDEBUG + const char *yys; + + if ((yys = getenv("YYDEBUG")) != 0) + { + yyn = *yys; + if (yyn >= '0' && yyn <= '9') + yydebug = yyn - '0'; + } +#endif + + yynerrs = 0; + yyerrflag = 0; + yychar = YYEMPTY; + yystate = 0; + +#if YYPURE + memset(&yystack, 0, sizeof(yystack)); +#endif + + if (yystack.s_base == NULL && yygrowstack(&yystack) == YYENOMEM) goto yyoverflow; + yystack.s_mark = yystack.s_base; + yystack.l_mark = yystack.l_base; + yystate = 0; + *yystack.s_mark = 0; + +yyloop: + if ((yyn = yydefred[yystate]) != 0) goto yyreduce; + if (yychar < 0) + { + if ((yychar = YYLEX) < 0) yychar = YYEOF; +#if YYDEBUG + if (yydebug) + { + yys = yyname[YYTRANSLATE(yychar)]; + printf("%sdebug: state %d, reading %d (%s)\n", + YYPREFIX, yystate, yychar, yys); + } +#endif + } + if ((yyn = yysindex[yystate]) && (yyn += yychar) >= 0 && + yyn <= YYTABLESIZE && yycheck[yyn] == yychar) + { +#if YYDEBUG + if (yydebug) + printf("%sdebug: state %d, shifting to state %d\n", + YYPREFIX, yystate, yytable[yyn]); +#endif + if (yystack.s_mark >= yystack.s_last && yygrowstack(&yystack) == YYENOMEM) + { + goto yyoverflow; + } + yystate = yytable[yyn]; + *++yystack.s_mark = yytable[yyn]; + *++yystack.l_mark = yylval; + yychar = YYEMPTY; + if (yyerrflag > 0) --yyerrflag; + goto yyloop; + } + if ((yyn = yyrindex[yystate]) && (yyn += yychar) >= 0 && + yyn <= YYTABLESIZE && yycheck[yyn] == yychar) + { + yyn = yytable[yyn]; + goto yyreduce; + } + if (yyerrflag) goto yyinrecovery; + + YYERROR_CALL("syntax error"); + + goto yyerrlab; + +yyerrlab: + ++yynerrs; + +yyinrecovery: + if (yyerrflag < 3) + { + yyerrflag = 3; + for (;;) + { + if ((yyn = yysindex[*yystack.s_mark]) && (yyn += YYERRCODE) >= 0 && + yyn <= YYTABLESIZE && yycheck[yyn] == YYERRCODE) + { +#if YYDEBUG + if (yydebug) + printf("%sdebug: state %d, error recovery shifting\ + to state %d\n", YYPREFIX, *yystack.s_mark, yytable[yyn]); +#endif + if (yystack.s_mark >= yystack.s_last && yygrowstack(&yystack) == YYENOMEM) + { + goto yyoverflow; + } + yystate = yytable[yyn]; + *++yystack.s_mark = yytable[yyn]; + *++yystack.l_mark = yylval; + goto yyloop; + } + else + { +#if YYDEBUG + if (yydebug) + printf("%sdebug: error recovery discarding state %d\n", + YYPREFIX, *yystack.s_mark); +#endif + if (yystack.s_mark <= yystack.s_base) goto yyabort; + --yystack.s_mark; + --yystack.l_mark; + } + } + } + else + { + if (yychar == YYEOF) goto yyabort; +#if YYDEBUG + if (yydebug) + { + yys = yyname[YYTRANSLATE(yychar)]; + printf("%sdebug: state %d, error recovery discards token %d (%s)\n", + YYPREFIX, yystate, yychar, yys); + } +#endif + yychar = YYEMPTY; + goto yyloop; + } + +yyreduce: +#if YYDEBUG + if (yydebug) + printf("%sdebug: state %d, reducing by rule %d (%s)\n", + YYPREFIX, yystate, yyn, yyrule[yyn]); +#endif + yym = yylen[yyn]; + if (yym) + yyval = yystack.l_mark[1-yym]; + else + memset(&yyval, 0, sizeof yyval); + switch (yyn) + { +case 5: +#line 275 "gram.y" + { if (!srcdir) srcdir = yystack.l_mark[-1].str; } +break; +case 6: +#line 276 "gram.y" + { if (!builddir) builddir = yystack.l_mark[-1].str; } +break; +case 7: +#line 281 "gram.y" + { setmachine(yystack.l_mark[-1].str,NULL,NULL,0); } +break; +case 8: +#line 282 "gram.y" + { setmachine(yystack.l_mark[-2].str,yystack.l_mark[-1].str,NULL,0); } +break; +case 9: +#line 283 "gram.y" + { setmachine(yystack.l_mark[-3].str,yystack.l_mark[-2].str,yystack.l_mark[-1].list,0); } +break; +case 10: +#line 284 "gram.y" + { setmachine(yystack.l_mark[-1].str,NULL,NULL,1); } +break; +case 11: +#line 285 "gram.y" + { stop("cannot proceed without machine or ioconf specifier"); } +break; +case 12: +#line 290 "gram.y" + { yyval.list = new_n(yystack.l_mark[0].str); } +break; +case 13: +#line 291 "gram.y" + { yyval.list = new_nx(yystack.l_mark[0].str, yystack.l_mark[-1].list); } +break; +case 14: +#line 302 "gram.y" + { check_maxpart(); check_version(); } +break; +case 17: +#line 309 "gram.y" + { wrap_continue(); } +break; +case 18: +#line 310 "gram.y" + { wrap_cleanup(); } +break; +case 19: +#line 311 "gram.y" + { enddefs(); checkfiles(); } +break; +case 42: +#line 342 "gram.y" + { addfile(yystack.l_mark[-3].str, yystack.l_mark[-2].condexpr, yystack.l_mark[-1].flag, yystack.l_mark[0].str); } +break; +case 43: +#line 347 "gram.y" + { addfile(yystack.l_mark[-2].str, yystack.l_mark[-1].condexpr, yystack.l_mark[0].flag, NULL); } +break; +case 44: +#line 353 "gram.y" + { + adddevm(yystack.l_mark[-4].str, yystack.l_mark[-3].devmajor, yystack.l_mark[-2].devmajor, yystack.l_mark[-1].condexpr, yystack.l_mark[0].list); + do_devsw = 1; + } +break; +case 45: +#line 361 "gram.y" + { prefix_push(yystack.l_mark[0].str); } +break; +case 46: +#line 362 "gram.y" + { prefix_pop(); } +break; +case 47: +#line 366 "gram.y" + { buildprefix_push(yystack.l_mark[0].str); } +break; +case 48: +#line 367 "gram.y" + { buildprefix_push(yystack.l_mark[0].str); } +break; +case 49: +#line 368 "gram.y" + { buildprefix_pop(); } +break; +case 50: +#line 372 "gram.y" + { (void)defdevclass(yystack.l_mark[0].str, NULL, NULL, 1); } +break; +case 51: +#line 376 "gram.y" + { deffilesystem(yystack.l_mark[-1].list, yystack.l_mark[0].list); } +break; +case 52: +#line 381 "gram.y" + { (void)defattr0(yystack.l_mark[-2].str, yystack.l_mark[-1].loclist, yystack.l_mark[0].attrlist, 0); } +break; +case 53: +#line 386 "gram.y" + { defoption(yystack.l_mark[-2].str, yystack.l_mark[-1].defoptlist, yystack.l_mark[0].list); } +break; +case 54: +#line 391 "gram.y" + { defflag(yystack.l_mark[-2].str, yystack.l_mark[-1].defoptlist, yystack.l_mark[0].list, 0); } +break; +case 55: +#line 396 "gram.y" + { defflag(yystack.l_mark[-1].str, yystack.l_mark[0].defoptlist, NULL, 1); } +break; +case 56: +#line 401 "gram.y" + { defparam(yystack.l_mark[-2].str, yystack.l_mark[-1].defoptlist, yystack.l_mark[0].list, 0); } +break; +case 57: +#line 406 "gram.y" + { defparam(yystack.l_mark[-1].str, yystack.l_mark[0].defoptlist, NULL, 1); } +break; +case 58: +#line 411 "gram.y" + { defdev(yystack.l_mark[-2].devb, yystack.l_mark[-1].loclist, yystack.l_mark[0].attrlist, 0); } +break; +case 59: +#line 416 "gram.y" + { defdevattach(yystack.l_mark[-1].deva, yystack.l_mark[-4].devb, yystack.l_mark[-2].list, yystack.l_mark[0].attrlist); } +break; +case 60: +#line 420 "gram.y" + { maxpartitions = yystack.l_mark[0].i32; } +break; +case 61: +#line 425 "gram.y" + { setdefmaxusers(yystack.l_mark[-2].i32, yystack.l_mark[-1].i32, yystack.l_mark[0].i32); } +break; +case 63: +#line 435 "gram.y" + { defdev(yystack.l_mark[-2].devb, yystack.l_mark[-1].loclist, yystack.l_mark[0].attrlist, 1); } +break; +case 64: +#line 440 "gram.y" + { defdev(yystack.l_mark[-2].devb, yystack.l_mark[-1].loclist, yystack.l_mark[0].attrlist, 2); } +break; +case 66: +#line 448 "gram.y" + { setversion(yystack.l_mark[0].i32); } +break; +case 67: +#line 453 "gram.y" + { yyval.condexpr = NULL; } +break; +case 68: +#line 454 "gram.y" + { yyval.condexpr = yystack.l_mark[0].condexpr; } +break; +case 69: +#line 459 "gram.y" + { yyval.flag = 0; } +break; +case 70: +#line 460 "gram.y" + { yyval.flag = yystack.l_mark[-1].flag | yystack.l_mark[0].flag; } +break; +case 71: +#line 465 "gram.y" + { yyval.flag = FI_NEEDSCOUNT; } +break; +case 72: +#line 466 "gram.y" + { yyval.flag = FI_NEEDSFLAG; } +break; +case 73: +#line 471 "gram.y" + { yyval.str = NULL; } +break; +case 74: +#line 472 "gram.y" + { yyval.str = yystack.l_mark[0].str; } +break; +case 75: +#line 477 "gram.y" + { yyval.flag = 0; } +break; +case 76: +#line 478 "gram.y" + { yyval.flag = yystack.l_mark[-1].flag | yystack.l_mark[0].flag; } +break; +case 77: +#line 483 "gram.y" + { yyval.flag = FI_NEEDSFLAG; } +break; +case 78: +#line 488 "gram.y" + { yyval.devmajor = -1; } +break; +case 79: +#line 489 "gram.y" + { yyval.devmajor = yystack.l_mark[0].i32; } +break; +case 80: +#line 494 "gram.y" + { yyval.devmajor = -1; } +break; +case 81: +#line 495 "gram.y" + { yyval.devmajor = yystack.l_mark[0].i32; } +break; +case 82: +#line 500 "gram.y" + { yyval.list = new_s("DEVNODE_DONTBOTHER"); } +break; +case 83: +#line 501 "gram.y" + { yyval.list = nvcat(yystack.l_mark[-2].list, yystack.l_mark[0].list); } +break; +case 84: +#line 502 "gram.y" + { yyval.list = yystack.l_mark[0].list; } +break; +case 85: +#line 507 "gram.y" + { yyval.list = new_s("DEVNODE_SINGLE"); } +break; +case 86: +#line 508 "gram.y" + { yyval.list = nvcat(new_s("DEVNODE_VECTOR"), yystack.l_mark[0].list); } +break; +case 87: +#line 513 "gram.y" + { yyval.list = new_i(yystack.l_mark[0].num.val); } +break; +case 88: +#line 514 "gram.y" + { + struct nvlist *__nv1, *__nv2; + + __nv1 = new_i(yystack.l_mark[-2].num.val); + __nv2 = new_i(yystack.l_mark[0].num.val); + yyval.list = nvcat(__nv1, __nv2); + } +break; +case 89: +#line 525 "gram.y" + { yyval.list = new_s("DEVNODE_FLAG_LINKZERO");} +break; +case 90: +#line 530 "gram.y" + { yyval.list = new_n(yystack.l_mark[0].str); } +break; +case 91: +#line 531 "gram.y" + { yyval.list = new_nx(yystack.l_mark[0].str, yystack.l_mark[-1].list); } +break; +case 92: +#line 536 "gram.y" + { yyval.str = yystack.l_mark[0].str; } +break; +case 93: +#line 541 "gram.y" + { yyval.loclist = NULL; } +break; +case 94: +#line 542 "gram.y" + { yyval.loclist = present_loclist(NULL); } +break; +case 95: +#line 543 "gram.y" + { yyval.loclist = present_loclist(yystack.l_mark[-1].loclist); } +break; +case 96: +#line 553 "gram.y" + { yyval.loclist = yystack.l_mark[0].loclist; } +break; +case 97: +#line 554 "gram.y" + { yyval.loclist = yystack.l_mark[-2].loclist; app(yystack.l_mark[-2].loclist, yystack.l_mark[0].loclist); } +break; +case 98: +#line 563 "gram.y" + { yyval.loclist = MK3(loc, yystack.l_mark[-1].str, yystack.l_mark[0].str, 0); } +break; +case 99: +#line 564 "gram.y" + { yyval.loclist = MK3(loc, yystack.l_mark[0].str, NULL, 0); } +break; +case 100: +#line 565 "gram.y" + { yyval.loclist = MK3(loc, yystack.l_mark[-2].str, yystack.l_mark[-1].str, 1); } +break; +case 101: +#line 566 "gram.y" + { yyval.loclist = locarray(yystack.l_mark[-3].str, yystack.l_mark[-1].i32, NULL, 0); } +break; +case 102: +#line 568 "gram.y" + { yyval.loclist = locarray(yystack.l_mark[-4].str, yystack.l_mark[-2].i32, yystack.l_mark[0].loclist, 0); } +break; +case 103: +#line 570 "gram.y" + { yyval.loclist = locarray(yystack.l_mark[-5].str, yystack.l_mark[-3].i32, yystack.l_mark[-1].loclist, 1); } +break; +case 104: +#line 575 "gram.y" + { yyval.str = yystack.l_mark[0].str; } +break; +case 105: +#line 576 "gram.y" + { yyval.str = yystack.l_mark[0].str; } +break; +case 106: +#line 581 "gram.y" + { yyval.str = yystack.l_mark[0].str; } +break; +case 107: +#line 586 "gram.y" + { yyval.loclist = yystack.l_mark[-1].loclist; } +break; +case 108: +#line 591 "gram.y" + { yyval.attrlist = NULL; } +break; +case 109: +#line 592 "gram.y" + { yyval.attrlist = yystack.l_mark[0].attrlist; } +break; +case 110: +#line 597 "gram.y" + { yyval.attrlist = MK2(attrlist, NULL, yystack.l_mark[0].attr); } +break; +case 111: +#line 598 "gram.y" + { yyval.attrlist = MK2(attrlist, yystack.l_mark[-2].attrlist, yystack.l_mark[0].attr); } +break; +case 112: +#line 603 "gram.y" + { yyval.attr = refattr(yystack.l_mark[0].str); } +break; +case 113: +#line 608 "gram.y" + { yyval.list = NULL; } +break; +case 114: +#line 609 "gram.y" + { yyval.list = yystack.l_mark[0].list; } +break; +case 115: +#line 614 "gram.y" + { yyval.list = new_n(yystack.l_mark[0].str); } +break; +case 116: +#line 615 "gram.y" + { yyval.list = new_nx(yystack.l_mark[0].str, yystack.l_mark[-2].list); } +break; +case 117: +#line 620 "gram.y" + { yyval.str = yystack.l_mark[0].str; } +break; +case 118: +#line 626 "gram.y" + { yyval.list = new_n(yystack.l_mark[0].str); } +break; +case 119: +#line 627 "gram.y" + { yyval.list = new_nx(yystack.l_mark[0].str, yystack.l_mark[-2].list); } +break; +case 120: +#line 632 "gram.y" + { yyval.str = yystack.l_mark[0].str; } +break; +case 121: +#line 633 "gram.y" + { yyval.str = NULL; } +break; +case 122: +#line 638 "gram.y" + { yyval.defoptlist = yystack.l_mark[0].defoptlist; } +break; +case 123: +#line 639 "gram.y" + { yyval.defoptlist = defoptlist_append(yystack.l_mark[0].defoptlist, yystack.l_mark[-1].defoptlist); } +break; +case 124: +#line 644 "gram.y" + { yyval.defoptlist = MK3(defoptlist, yystack.l_mark[0].str, NULL, NULL); } +break; +case 125: +#line 645 "gram.y" + { yyval.defoptlist = MK3(defoptlist, yystack.l_mark[-2].str, yystack.l_mark[0].str, NULL); } +break; +case 126: +#line 646 "gram.y" + { yyval.defoptlist = MK3(defoptlist, yystack.l_mark[-2].str, NULL, yystack.l_mark[0].str); } +break; +case 127: +#line 647 "gram.y" + { yyval.defoptlist = MK3(defoptlist, yystack.l_mark[-4].str, yystack.l_mark[-2].str, yystack.l_mark[0].str); } +break; +case 130: +#line 658 "gram.y" + { appendcondmkoption(yystack.l_mark[-3].condexpr, yystack.l_mark[-2].str, yystack.l_mark[0].str); } +break; +case 131: +#line 663 "gram.y" + { yyval.devb = getdevbase(yystack.l_mark[0].str); } +break; +case 132: +#line 668 "gram.y" + { yyval.deva = NULL; } +break; +case 133: +#line 669 "gram.y" + { yyval.deva = getdevattach(yystack.l_mark[0].str); } +break; +case 136: +#line 681 "gram.y" + { setmajor(yystack.l_mark[-2].devb, yystack.l_mark[0].i32); } +break; +case 137: +#line 685 "gram.y" + { + if (yystack.l_mark[0].num.val > INT_MAX || yystack.l_mark[0].num.val < INT_MIN) + cfgerror("overflow %" PRId64, yystack.l_mark[0].num.val); + else + yyval.i32 = (int32_t)yystack.l_mark[0].num.val; + } +break; +case 141: +#line 708 "gram.y" + { wrap_continue(); } +break; +case 142: +#line 709 "gram.y" + { wrap_cleanup(); } +break; +case 164: +#line 738 "gram.y" + { addattr(yystack.l_mark[0].str); } +break; +case 165: +#line 742 "gram.y" + { delattr(yystack.l_mark[0].str); } +break; +case 172: +#line 770 "gram.y" + { setmaxusers(yystack.l_mark[0].i32); } +break; +case 173: +#line 774 "gram.y" + { setident(yystack.l_mark[0].str); } +break; +case 174: +#line 778 "gram.y" + { setident(NULL); } +break; +case 175: +#line 783 "gram.y" + { addconf(&conf); } +break; +case 176: +#line 787 "gram.y" + { delconf(yystack.l_mark[0].str); } +break; +case 177: +#line 791 "gram.y" + { delpseudo(yystack.l_mark[0].str); } +break; +case 178: +#line 795 "gram.y" + { addpseudo(yystack.l_mark[-1].str, yystack.l_mark[0].i32); } +break; +case 179: +#line 799 "gram.y" + { addpseudoroot(yystack.l_mark[0].str); } +break; +case 180: +#line 804 "gram.y" + { deldevi(yystack.l_mark[-2].str, yystack.l_mark[0].str); } +break; +case 181: +#line 808 "gram.y" + { deldeva(yystack.l_mark[0].str); } +break; +case 182: +#line 812 "gram.y" + { deldev(yystack.l_mark[0].str); } +break; +case 183: +#line 817 "gram.y" + { adddev(yystack.l_mark[-4].str, yystack.l_mark[-2].str, yystack.l_mark[-1].loclist, yystack.l_mark[0].i32); } +break; +case 186: +#line 828 "gram.y" + { addfsoption(yystack.l_mark[0].str); } +break; +case 189: +#line 839 "gram.y" + { delfsoption(yystack.l_mark[0].str); } +break; +case 192: +#line 851 "gram.y" + { addmkoption(yystack.l_mark[-2].str, yystack.l_mark[0].str); } +break; +case 193: +#line 852 "gram.y" + { appendmkoption(yystack.l_mark[-2].str, yystack.l_mark[0].str); } +break; +case 196: +#line 864 "gram.y" + { delmkoption(yystack.l_mark[0].str); } +break; +case 199: +#line 875 "gram.y" + { addoption(yystack.l_mark[0].str, NULL); } +break; +case 200: +#line 876 "gram.y" + { addoption(yystack.l_mark[-2].str, yystack.l_mark[0].str); } +break; +case 203: +#line 887 "gram.y" + { deloption(yystack.l_mark[0].str); } +break; +case 204: +#line 892 "gram.y" + { + conf.cf_name = yystack.l_mark[0].str; + conf.cf_lineno = currentline(); + conf.cf_fstype = NULL; + conf.cf_root = NULL; + conf.cf_dump = NULL; + } +break; +case 205: +#line 903 "gram.y" + { setconf(&conf.cf_root, "root", yystack.l_mark[0].list); } +break; +case 206: +#line 904 "gram.y" + { setconf(&conf.cf_root, "root", yystack.l_mark[-1].list); } +break; +case 207: +#line 909 "gram.y" + { yyval.list = new_si(intern("?"), + (long long)NODEV); } +break; +case 208: +#line 911 "gram.y" + { yyval.list = new_si(yystack.l_mark[0].str, + (long long)NODEV); } +break; +case 209: +#line 913 "gram.y" + { yyval.list = new_si(NULL, yystack.l_mark[0].val); } +break; +case 210: +#line 918 "gram.y" + { yyval.val = (int64_t)makedev(yystack.l_mark[-2].num.val, yystack.l_mark[0].num.val); } +break; +case 211: +#line 923 "gram.y" + { setfstype(&conf.cf_fstype, intern("?")); } +break; +case 212: +#line 924 "gram.y" + { setfstype(&conf.cf_fstype, yystack.l_mark[0].str); } +break; +case 215: +#line 935 "gram.y" + { setconf(&conf.cf_dump, "dumps", yystack.l_mark[0].list); } +break; +case 216: +#line 940 "gram.y" + { yyval.i32 = 1; } +break; +case 217: +#line 941 "gram.y" + { yyval.i32 = yystack.l_mark[0].i32; } +break; +case 218: +#line 946 "gram.y" + { yyval.str = yystack.l_mark[0].str; } +break; +case 219: +#line 947 "gram.y" + { yyval.str = starref(yystack.l_mark[-1].str); } +break; +case 220: +#line 952 "gram.y" + { yyval.str = NULL; } +break; +case 221: +#line 953 "gram.y" + { yyval.str = yystack.l_mark[0].str; } +break; +case 222: +#line 954 "gram.y" + { yyval.str = wildref(yystack.l_mark[-1].str); } +break; +case 223: +#line 959 "gram.y" + { yyval.loclist = NULL; } +break; +case 224: +#line 960 "gram.y" + { yyval.loclist = yystack.l_mark[0].loclist; app(yystack.l_mark[0].loclist, yystack.l_mark[-1].loclist); } +break; +case 225: +#line 965 "gram.y" + { yyval.loclist = MK3(loc, yystack.l_mark[-1].str, NULL, 0); } +break; +case 226: +#line 966 "gram.y" + { yyval.loclist = namelocvals(yystack.l_mark[-1].str, yystack.l_mark[0].loclist); } +break; +case 227: +#line 971 "gram.y" + { yyval.i32 = 0; } +break; +case 228: +#line 972 "gram.y" + { yyval.i32 = yystack.l_mark[0].i32; } +break; +case 231: +#line 995 "gram.y" + { yyval.condexpr = MKF2(cx, or, yystack.l_mark[-2].condexpr, yystack.l_mark[0].condexpr); } +break; +case 233: +#line 1000 "gram.y" + { yyval.condexpr = MKF2(cx, and, yystack.l_mark[-2].condexpr, yystack.l_mark[0].condexpr); } +break; +case 235: +#line 1010 "gram.y" + { yyval.condexpr = yystack.l_mark[0].condexpr; } +break; +case 236: +#line 1011 "gram.y" + { yyval.condexpr = MKF1(cx, not, yystack.l_mark[0].condexpr); } +break; +case 237: +#line 1012 "gram.y" + { yyval.condexpr = yystack.l_mark[-1].condexpr; } +break; +case 238: +#line 1017 "gram.y" + { yyval.condexpr = MKF1(cx, atom, yystack.l_mark[0].str); } +break; +case 239: +#line 1028 "gram.y" + { yyval.str = yystack.l_mark[0].str; } +break; +case 240: +#line 1029 "gram.y" + { yyval.str = yystack.l_mark[0].str; } +break; +case 241: +#line 1034 "gram.y" + { yyval.str = NULL; } +break; +case 242: +#line 1035 "gram.y" + { yyval.str = yystack.l_mark[0].str; } +break; +case 243: +#line 1040 "gram.y" + { yyval.str = yystack.l_mark[0].str; } +break; +case 244: +#line 1041 "gram.y" + { yyval.str = yystack.l_mark[0].str; } +break; +case 245: +#line 1046 "gram.y" + { yyval.str = yystack.l_mark[0].str; } +break; +case 246: +#line 1047 "gram.y" + { yyval.str = yystack.l_mark[0].str; } +break; +case 247: +#line 1048 "gram.y" + { yyval.str = yystack.l_mark[0].str; } +break; +case 248: +#line 1049 "gram.y" + { + char bf[40]; + + (void)snprintf(bf, sizeof(bf), FORMAT(yystack.l_mark[0].num), (long long)yystack.l_mark[0].num.val); + yyval.str = intern(bf); + } +break; +case 249: +#line 1059 "gram.y" + { yyval.str = yystack.l_mark[0].str; } +break; +case 250: +#line 1060 "gram.y" + { yyval.str = yystack.l_mark[0].str; } +break; +case 251: +#line 1066 "gram.y" + { yyval.loclist = MKF2(loc, val, yystack.l_mark[0].str, NULL); } +break; +case 252: +#line 1067 "gram.y" + { yyval.loclist = MKF2(loc, val, yystack.l_mark[-2].str, yystack.l_mark[0].loclist); } +break; +case 253: +#line 1072 "gram.y" + { yyval.num = yystack.l_mark[0].num; } +break; +case 254: +#line 1073 "gram.y" + { yyval.num.fmt = yystack.l_mark[0].num.fmt; yyval.num.val = -yystack.l_mark[0].num.val; } +break; +#line 2373 "gram.c" + } + yystack.s_mark -= yym; + yystate = *yystack.s_mark; + yystack.l_mark -= yym; + yym = yylhs[yyn]; + if (yystate == 0 && yym == 0) + { +#if YYDEBUG + if (yydebug) + printf("%sdebug: after reduction, shifting from state 0 to\ + state %d\n", YYPREFIX, YYFINAL); +#endif + yystate = YYFINAL; + *++yystack.s_mark = YYFINAL; + *++yystack.l_mark = yyval; + if (yychar < 0) + { + if ((yychar = YYLEX) < 0) yychar = YYEOF; +#if YYDEBUG + if (yydebug) + { + yys = yyname[YYTRANSLATE(yychar)]; + printf("%sdebug: state %d, reading %d (%s)\n", + YYPREFIX, YYFINAL, yychar, yys); + } +#endif + } + if (yychar == YYEOF) goto yyaccept; + goto yyloop; + } + if ((yyn = yygindex[yym]) && (yyn += yystate) >= 0 && + yyn <= YYTABLESIZE && yycheck[yyn] == yystate) + yystate = yytable[yyn]; + else + yystate = yydgoto[yym]; +#if YYDEBUG + if (yydebug) + printf("%sdebug: after reduction, shifting from state %d \ +to state %d\n", YYPREFIX, *yystack.s_mark, yystate); +#endif + if (yystack.s_mark >= yystack.s_last && yygrowstack(&yystack) == YYENOMEM) + { + goto yyoverflow; + } + *++yystack.s_mark = (YYINT) yystate; + *++yystack.l_mark = yyval; + goto yyloop; + +yyoverflow: + YYERROR_CALL("yacc stack overflow"); + +yyabort: + yyfreestack(&yystack); + return (1); + +yyaccept: + yyfreestack(&yystack); + return (0); +} diff --git a/usr.bin/config/gram.h b/usr.bin/config/gram.h new file mode 100644 index 000000000..16ef96578 --- /dev/null +++ b/usr.bin/config/gram.h @@ -0,0 +1,89 @@ +#ifndef _yy_defines_h_ +#define _yy_defines_h_ + +#define AND 257 +#define AT 258 +#define ATTACH 259 +#define BLOCK 260 +#define BUILD 261 +#define CHAR 262 +#define COLONEQ 263 +#define COMPILE_WITH 264 +#define CONFIG 265 +#define DEFFS 266 +#define DEFINE 267 +#define DEFOPT 268 +#define DEFPARAM 269 +#define DEFFLAG 270 +#define DEFPSEUDO 271 +#define DEFPSEUDODEV 272 +#define DEVICE 273 +#define DEVCLASS 274 +#define DUMPS 275 +#define DEVICE_MAJOR 276 +#define ENDFILE 277 +#define XFILE 278 +#define FILE_SYSTEM 279 +#define FLAGS 280 +#define IDENT 281 +#define IOCONF 282 +#define LINKZERO 283 +#define XMACHINE 284 +#define MAJOR 285 +#define MAKEOPTIONS 286 +#define MAXUSERS 287 +#define MAXPARTITIONS 288 +#define MINOR 289 +#define NEEDS_COUNT 290 +#define NEEDS_FLAG 291 +#define NO 292 +#define XOBJECT 293 +#define OBSOLETE 294 +#define ON 295 +#define OPTIONS 296 +#define PACKAGE 297 +#define PLUSEQ 298 +#define PREFIX 299 +#define BUILDPREFIX 300 +#define PSEUDO_DEVICE 301 +#define PSEUDO_ROOT 302 +#define ROOT 303 +#define SELECT 304 +#define SINGLE 305 +#define SOURCE 306 +#define TYPE 307 +#define VECTOR 308 +#define VERSION 309 +#define WITH 310 +#define NUMBER 311 +#define PATHNAME 312 +#define QSTRING 313 +#define WORD 314 +#define EMPTYSTRING 315 +#define ENDDEFS 316 +#ifdef YYSTYPE +#undef YYSTYPE_IS_DECLARED +#define YYSTYPE_IS_DECLARED 1 +#endif +#ifndef YYSTYPE_IS_DECLARED +#define YYSTYPE_IS_DECLARED 1 +typedef union { + struct attr *attr; + struct devbase *devb; + struct deva *deva; + struct nvlist *list; + struct defoptlist *defoptlist; + struct loclist *loclist; + struct attrlist *attrlist; + struct condexpr *condexpr; + const char *str; + struct numconst num; + int64_t val; + u_char flag; + devmajor_t devmajor; + int32_t i32; +} YYSTYPE; +#endif /* !YYSTYPE_IS_DECLARED */ +extern YYSTYPE yylval; + +#endif /* _yy_defines_h_ */ diff --git a/usr.bin/config/gram.y b/usr.bin/config/gram.y new file mode 100644 index 000000000..3c234d607 --- /dev/null +++ b/usr.bin/config/gram.y @@ -0,0 +1,1450 @@ +%{ +/* $NetBSD: gram.y,v 1.52 2015/09/01 13:42:48 uebayasi Exp $ */ + +/* + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Lawrence Berkeley Laboratories. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * from: @(#)gram.y 8.1 (Berkeley) 6/6/93 + */ + +#include +__RCSID("$NetBSD: gram.y,v 1.52 2015/09/01 13:42:48 uebayasi Exp $"); + +#include +#include +#include +#include +#include +#include +#include +#include "defs.h" +#include "sem.h" + +#define FORMAT(n) (((n).fmt == 8 && (n).val != 0) ? "0%llo" : \ + ((n).fmt == 16) ? "0x%llx" : "%lld") + +#define stop(s) cfgerror(s), exit(1) + +static struct config conf; /* at most one active at a time */ + + +/* + * Allocation wrapper functions + */ +static void wrap_alloc(void *ptr, unsigned code); +static void wrap_continue(void); +static void wrap_cleanup(void); + +/* + * Allocation wrapper type codes + */ +#define WRAP_CODE_nvlist 1 +#define WRAP_CODE_defoptlist 2 +#define WRAP_CODE_loclist 3 +#define WRAP_CODE_attrlist 4 +#define WRAP_CODE_condexpr 5 + +/* + * The allocation wrappers themselves + */ +#define DECL_ALLOCWRAP(t) static struct t *wrap_mk_##t(struct t *arg) + +DECL_ALLOCWRAP(nvlist); +DECL_ALLOCWRAP(defoptlist); +DECL_ALLOCWRAP(loclist); +DECL_ALLOCWRAP(attrlist); +DECL_ALLOCWRAP(condexpr); + +/* allow shorter names */ +#define wrap_mk_loc(p) wrap_mk_loclist(p) +#define wrap_mk_cx(p) wrap_mk_condexpr(p) + +/* + * Macros for allocating new objects + */ + +/* old-style for struct nvlist */ +#define new0(n,s,p,i,x) wrap_mk_nvlist(newnv(n, s, p, i, x)) +#define new_n(n) new0(n, NULL, NULL, 0, NULL) +#define new_nx(n, x) new0(n, NULL, NULL, 0, x) +#define new_ns(n, s) new0(n, s, NULL, 0, NULL) +#define new_si(s, i) new0(NULL, s, NULL, i, NULL) +#define new_nsi(n,s,i) new0(n, s, NULL, i, NULL) +#define new_np(n, p) new0(n, NULL, p, 0, NULL) +#define new_s(s) new0(NULL, s, NULL, 0, NULL) +#define new_p(p) new0(NULL, NULL, p, 0, NULL) +#define new_px(p, x) new0(NULL, NULL, p, 0, x) +#define new_sx(s, x) new0(NULL, s, NULL, 0, x) +#define new_nsx(n,s,x) new0(n, s, NULL, 0, x) +#define new_i(i) new0(NULL, NULL, NULL, i, NULL) + +/* new style, type-polymorphic; ordinary and for types with multiple flavors */ +#define MK0(t) wrap_mk_##t(mk_##t()) +#define MK1(t, a0) wrap_mk_##t(mk_##t(a0)) +#define MK2(t, a0, a1) wrap_mk_##t(mk_##t(a0, a1)) +#define MK3(t, a0, a1, a2) wrap_mk_##t(mk_##t(a0, a1, a2)) + +#define MKF0(t, f) wrap_mk_##t(mk_##t##_##f()) +#define MKF1(t, f, a0) wrap_mk_##t(mk_##t##_##f(a0)) +#define MKF2(t, f, a0, a1) wrap_mk_##t(mk_##t##_##f(a0, a1)) + +/* + * Data constructors + */ + +static struct defoptlist *mk_defoptlist(const char *, const char *, + const char *); +static struct loclist *mk_loc(const char *, const char *, long long); +static struct loclist *mk_loc_val(const char *, struct loclist *); +static struct attrlist *mk_attrlist(struct attrlist *, struct attr *); +static struct condexpr *mk_cx_atom(const char *); +static struct condexpr *mk_cx_not(struct condexpr *); +static struct condexpr *mk_cx_and(struct condexpr *, struct condexpr *); +static struct condexpr *mk_cx_or(struct condexpr *, struct condexpr *); + +/* + * Other private functions + */ + +static void setmachine(const char *, const char *, struct nvlist *, int); +static void check_maxpart(void); + +static struct loclist *present_loclist(struct loclist *ll); +static void app(struct loclist *, struct loclist *); +static struct loclist *locarray(const char *, int, struct loclist *, int); +static struct loclist *namelocvals(const char *, struct loclist *); + +%} + +%union { + struct attr *attr; + struct devbase *devb; + struct deva *deva; + struct nvlist *list; + struct defoptlist *defoptlist; + struct loclist *loclist; + struct attrlist *attrlist; + struct condexpr *condexpr; + const char *str; + struct numconst num; + int64_t val; + u_char flag; + devmajor_t devmajor; + int32_t i32; +} + +%token AND AT ATTACH +%token BLOCK BUILD +%token CHAR COLONEQ COMPILE_WITH CONFIG +%token DEFFS DEFINE DEFOPT DEFPARAM DEFFLAG DEFPSEUDO DEFPSEUDODEV +%token DEVICE DEVCLASS DUMPS DEVICE_MAJOR +%token ENDFILE +%token XFILE FILE_SYSTEM FLAGS +%token IDENT IOCONF +%token LINKZERO +%token XMACHINE MAJOR MAKEOPTIONS MAXUSERS MAXPARTITIONS MINOR +%token NEEDS_COUNT NEEDS_FLAG NO +%token XOBJECT OBSOLETE ON OPTIONS +%token PACKAGE PLUSEQ PREFIX BUILDPREFIX PSEUDO_DEVICE PSEUDO_ROOT +%token ROOT +%token SELECT SINGLE SOURCE +%token TYPE +%token VECTOR VERSION +%token WITH +%token NUMBER +%token PATHNAME QSTRING WORD EMPTYSTRING +%token ENDDEFS + +%type fopts condexpr condatom +%type cond_or_expr cond_and_expr cond_prefix_expr +%type cond_base_expr +%type fs_spec +%type fflags fflag oflags oflag +%type rule +%type depend +%type devbase +%type devattach_opt +%type atlist +%type interface_opt +%type atname +%type loclist locdef +%type locdefault +%type values locdefaults +%type depend_list depends +%type locators locator +%type dev_spec +%type device_instance +%type attachment +%type value +%type major_minor +%type signed_number +%type int32 npseudo device_flags +%type deffs +%type deffses +%type defopt +%type defopts +%type optdepend +%type optdepends +%type optdepend_list +%type optfile_opt +%type subarches +%type filename stringvalue locname mkvarname +%type device_major_block device_major_char +%type devnodes devnodetype devnodeflags devnode_dims + +%% + +/* + * A complete configuration consists of both the selection part (a + * kernel config such as GENERIC or SKYNET, plus also the various + * std.* files), which selects the material to be in the kernel, and + * also the definition part (files, files.*, etc.) that declares what + * material is available to be placed in kernels. + * + * The two parts have almost entirely separate syntaxes. This grammar + * covers both of them. When config is run on a kernel configuration + * file, the std.* file for the port is included explicitly. The + * files.* files are included implicitly when the std.* file declares + * the machine type. + * + * The machine spec, which brings in the definition part, must appear + * before all configuration material except for the "topthings"; these + * are the "source" and "build" declarations that tell config where + * things are. These are not used by default. + * + * A previous version of this comment contained the following text: + * + * Note that we do not have sufficient keywords to enforce any + * order between elements of "topthings" without introducing + * shift/reduce conflicts. Instead, check order requirements in + * the C code. + * + * As of March 2012 this comment makes no sense, as there are only two + * topthings and no reason for them to be forcibly ordered. + * Furthermore, the statement about conflicts is false. + */ + +/* Complete configuration. */ +configuration: + topthings machine_spec definition_part selection_part +; + +/* Sequence of zero or more topthings. */ +topthings: + /* empty */ + | topthings topthing +; + +/* Directory specification. */ +topthing: + '\n' + | SOURCE filename '\n' { if (!srcdir) srcdir = $2; } + | BUILD filename '\n' { if (!builddir) builddir = $2; } +; + +/* "machine foo" from std.whatever */ +machine_spec: + XMACHINE WORD '\n' { setmachine($2,NULL,NULL,0); } + | XMACHINE WORD WORD '\n' { setmachine($2,$3,NULL,0); } + | XMACHINE WORD WORD subarches '\n' { setmachine($2,$3,$4,0); } + | IOCONF WORD '\n' { setmachine($2,NULL,NULL,1); } + | error { stop("cannot proceed without machine or ioconf specifier"); } +; + +/* One or more sub-arches. */ +subarches: + WORD { $$ = new_n($1); } + | subarches WORD { $$ = new_nx($2, $1); } +; + +/************************************************************/ + +/* + * The machine definitions grammar. + */ + +/* Complete definition part: the contents of all files.* files. */ +definition_part: + definitions ENDDEFS { check_maxpart(); check_version(); } +; + +/* Zero or more definitions. Trap errors. */ +definitions: + /* empty */ + | definitions '\n' + | definitions definition '\n' { wrap_continue(); } + | definitions error '\n' { wrap_cleanup(); } + | definitions ENDFILE { enddefs(); checkfiles(); } +; + +/* A single definition. */ +definition: + define_file + | define_object + | define_device_major + | define_prefix + | define_buildprefix + | define_devclass + | define_filesystems + | define_attribute + | define_option + | define_flag + | define_obsolete_flag + | define_param + | define_obsolete_param + | define_device + | define_device_attachment + | define_maxpartitions + | define_maxusers + | define_makeoptions + | define_pseudo + | define_pseudodev + | define_major + | define_version +; + +/* source file: file foo/bar.c bar|baz needs-flag compile-with blah */ +define_file: + XFILE filename fopts fflags rule { addfile($2, $3, $4, $5); } +; + +/* object file: object zot.o foo|zot needs-flag */ +define_object: + XOBJECT filename fopts oflags { addfile($2, $3, $4, NULL); } +; + +/* device major declaration */ +define_device_major: + DEVICE_MAJOR WORD device_major_char device_major_block fopts devnodes + { + adddevm($2, $3, $4, $5, $6); + do_devsw = 1; + } +; + +/* prefix delimiter */ +define_prefix: + PREFIX filename { prefix_push($2); } + | PREFIX { prefix_pop(); } +; + +define_buildprefix: + BUILDPREFIX filename { buildprefix_push($2); } + | BUILDPREFIX WORD { buildprefix_push($2); } + | BUILDPREFIX { buildprefix_pop(); } +; + +define_devclass: + DEVCLASS WORD { (void)defdevclass($2, NULL, NULL, 1); } +; + +define_filesystems: + DEFFS deffses optdepend_list { deffilesystem($2, $3); } +; + +define_attribute: + DEFINE WORD interface_opt depend_list + { (void)defattr0($2, $3, $4, 0); } +; + +define_option: + DEFOPT optfile_opt defopts optdepend_list + { defoption($2, $3, $4); } +; + +define_flag: + DEFFLAG optfile_opt defopts optdepend_list + { defflag($2, $3, $4, 0); } +; + +define_obsolete_flag: + OBSOLETE DEFFLAG optfile_opt defopts + { defflag($3, $4, NULL, 1); } +; + +define_param: + DEFPARAM optfile_opt defopts optdepend_list + { defparam($2, $3, $4, 0); } +; + +define_obsolete_param: + OBSOLETE DEFPARAM optfile_opt defopts + { defparam($3, $4, NULL, 1); } +; + +define_device: + DEVICE devbase interface_opt depend_list + { defdev($2, $3, $4, 0); } +; + +define_device_attachment: + ATTACH devbase AT atlist devattach_opt depend_list + { defdevattach($5, $2, $4, $6); } +; + +define_maxpartitions: + MAXPARTITIONS int32 { maxpartitions = $2; } +; + +define_maxusers: + MAXUSERS int32 int32 int32 + { setdefmaxusers($2, $3, $4); } +; + +define_makeoptions: + MAKEOPTIONS condmkopt_list +; + +define_pseudo: + /* interface_opt in DEFPSEUDO is for backwards compatibility */ + DEFPSEUDO devbase interface_opt depend_list + { defdev($2, $3, $4, 1); } +; + +define_pseudodev: + DEFPSEUDODEV devbase interface_opt depend_list + { defdev($2, $3, $4, 2); } +; + +define_major: + MAJOR '{' majorlist '}' +; + +define_version: + VERSION int32 { setversion($2); } +; + +/* file options: optional expression of conditions */ +fopts: + /* empty */ { $$ = NULL; } + | condexpr { $$ = $1; } +; + +/* zero or more flags for a file */ +fflags: + /* empty */ { $$ = 0; } + | fflags fflag { $$ = $1 | $2; } +; + +/* one flag for a file */ +fflag: + NEEDS_COUNT { $$ = FI_NEEDSCOUNT; } + | NEEDS_FLAG { $$ = FI_NEEDSFLAG; } +; + +/* extra compile directive for a source file */ +rule: + /* empty */ { $$ = NULL; } + | COMPILE_WITH stringvalue { $$ = $2; } +; + +/* zero or more flags for an object file */ +oflags: + /* empty */ { $$ = 0; } + | oflags oflag { $$ = $1 | $2; } +; + +/* a single flag for an object file */ +oflag: + NEEDS_FLAG { $$ = FI_NEEDSFLAG; } +; + +/* char 55 */ +device_major_char: + /* empty */ { $$ = -1; } + | CHAR int32 { $$ = $2; } +; + +/* block 33 */ +device_major_block: + /* empty */ { $$ = -1; } + | BLOCK int32 { $$ = $2; } +; + +/* device node specification */ +devnodes: + /* empty */ { $$ = new_s("DEVNODE_DONTBOTHER"); } + | devnodetype ',' devnodeflags { $$ = nvcat($1, $3); } + | devnodetype { $$ = $1; } +; + +/* device nodes without flags */ +devnodetype: + SINGLE { $$ = new_s("DEVNODE_SINGLE"); } + | VECTOR '=' devnode_dims { $$ = nvcat(new_s("DEVNODE_VECTOR"), $3); } +; + +/* dimensions (?) */ +devnode_dims: + NUMBER { $$ = new_i($1.val); } + | NUMBER ':' NUMBER { + struct nvlist *__nv1, *__nv2; + + __nv1 = new_i($1.val); + __nv2 = new_i($3.val); + $$ = nvcat(__nv1, __nv2); + } +; + +/* flags for device nodes */ +devnodeflags: + LINKZERO { $$ = new_s("DEVNODE_FLAG_LINKZERO");} +; + +/* one or more file system names */ +deffses: + deffs { $$ = new_n($1); } + | deffses deffs { $$ = new_nx($2, $1); } +; + +/* a single file system name */ +deffs: + WORD { $$ = $1; } +; + +/* optional locator specification */ +interface_opt: + /* empty */ { $$ = NULL; } + | '{' '}' { $$ = present_loclist(NULL); } + | '{' loclist '}' { $$ = present_loclist($2); } +; + +/* + * loclist order matters, must use right recursion + * XXX wot? + */ + +/* list of locator definitions */ +loclist: + locdef { $$ = $1; } + | locdef ',' loclist { $$ = $1; app($1, $3); } +; + +/* + * "[ WORD locdefault ]" syntax may be unnecessary... + */ + +/* one locator definition */ +locdef: + locname locdefault { $$ = MK3(loc, $1, $2, 0); } + | locname { $$ = MK3(loc, $1, NULL, 0); } + | '[' locname locdefault ']' { $$ = MK3(loc, $2, $3, 1); } + | locname '[' int32 ']' { $$ = locarray($1, $3, NULL, 0); } + | locname '[' int32 ']' locdefaults + { $$ = locarray($1, $3, $5, 0); } + | '[' locname '[' int32 ']' locdefaults ']' + { $$ = locarray($2, $4, $6, 1); } +; + +/* locator name */ +locname: + WORD { $$ = $1; } + | QSTRING { $$ = $1; } +; + +/* locator default value */ +locdefault: + '=' value { $$ = $2; } +; + +/* multiple locator default values */ +locdefaults: + '=' '{' values '}' { $$ = $3; } +; + +/* list of depends, may be empty */ +depend_list: + /* empty */ { $$ = NULL; } + | ':' depends { $$ = $2; } +; + +/* one or more depend items */ +depends: + depend { $$ = MK2(attrlist, NULL, $1); } + | depends ',' depend { $$ = MK2(attrlist, $1, $3); } +; + +/* one depend item (which is an attribute) */ +depend: + WORD { $$ = refattr($1); } +; + +/* list of option depends, may be empty */ +optdepend_list: + /* empty */ { $$ = NULL; } + | ':' optdepends { $$ = $2; } +; + +/* a list of option dependencies */ +optdepends: + optdepend { $$ = new_n($1); } + | optdepends ',' optdepend { $$ = new_nx($3, $1); } +; + +/* one option depend, which is an option name */ +optdepend: + WORD { $$ = $1; } +; + + +/* list of places to attach: attach blah at ... */ +atlist: + atname { $$ = new_n($1); } + | atlist ',' atname { $$ = new_nx($3, $1); } +; + +/* a place to attach a device */ +atname: + WORD { $$ = $1; } + | ROOT { $$ = NULL; } +; + +/* one or more defined options */ +defopts: + defopt { $$ = $1; } + | defopts defopt { $$ = defoptlist_append($2, $1); } +; + +/* one defined option */ +defopt: + WORD { $$ = MK3(defoptlist, $1, NULL, NULL); } + | WORD '=' value { $$ = MK3(defoptlist, $1, $3, NULL); } + | WORD COLONEQ value { $$ = MK3(defoptlist, $1, NULL, $3); } + | WORD '=' value COLONEQ value { $$ = MK3(defoptlist, $1, $3, $5); } +; + +/* list of conditional makeoptions */ +condmkopt_list: + condmkoption + | condmkopt_list ',' condmkoption +; + +/* one conditional make option */ +condmkoption: + condexpr mkvarname PLUSEQ value { appendcondmkoption($1, $2, $4); } +; + +/* device name */ +devbase: + WORD { $$ = getdevbase($1); } +; + +/* optional attachment: with foo */ +devattach_opt: + /* empty */ { $$ = NULL; } + | WITH WORD { $$ = getdevattach($2); } +; + +/* list of major numbers */ +/* XXX why is this right-recursive? */ +majorlist: + majordef + | majorlist ',' majordef +; + +/* one major number */ +majordef: + devbase '=' int32 { setmajor($1, $3); } +; + +int32: + NUMBER { + if ($1.val > INT_MAX || $1.val < INT_MIN) + cfgerror("overflow %" PRId64, $1.val); + else + $$ = (int32_t)$1.val; + } +; + +/************************************************************/ + +/* + * The selection grammar. + */ + +/* Complete selection part: all std.* files plus selected config. */ +selection_part: + selections +; + +/* Zero or more config items. Trap errors. */ +selections: + /* empty */ + | selections '\n' + | selections selection '\n' { wrap_continue(); } + | selections error '\n' { wrap_cleanup(); } +; + +/* One config item. */ +selection: + definition + | select_attr + | select_no_attr + | select_no_filesystems + | select_filesystems + | select_no_makeoptions + | select_makeoptions + | select_no_options + | select_options + | select_maxusers + | select_ident + | select_no_ident + | select_config + | select_no_config + | select_no_pseudodev + | select_pseudodev + | select_pseudoroot + | select_no_device_instance_attachment + | select_no_device_attachment + | select_no_device_instance + | select_device_instance +; + +select_attr: + SELECT WORD { addattr($2); } +; + +select_no_attr: + NO SELECT WORD { delattr($3); } +; + +select_no_filesystems: + NO FILE_SYSTEM no_fs_list +; + +select_filesystems: + FILE_SYSTEM fs_list +; + +select_no_makeoptions: + NO MAKEOPTIONS no_mkopt_list +; + +select_makeoptions: + MAKEOPTIONS mkopt_list +; + +select_no_options: + NO OPTIONS no_opt_list +; + +select_options: + OPTIONS opt_list +; + +select_maxusers: + MAXUSERS int32 { setmaxusers($2); } +; + +select_ident: + IDENT stringvalue { setident($2); } +; + +select_no_ident: + NO IDENT { setident(NULL); } +; + +select_config: + CONFIG conf root_spec sysparam_list + { addconf(&conf); } +; + +select_no_config: + NO CONFIG WORD { delconf($3); } +; + +select_no_pseudodev: + NO PSEUDO_DEVICE WORD { delpseudo($3); } +; + +select_pseudodev: + PSEUDO_DEVICE WORD npseudo { addpseudo($2, $3); } +; + +select_pseudoroot: + PSEUDO_ROOT device_instance { addpseudoroot($2); } +; + +select_no_device_instance_attachment: + NO device_instance AT attachment + { deldevi($2, $4); } +; + +select_no_device_attachment: + NO DEVICE AT attachment { deldeva($4); } +; + +select_no_device_instance: + NO device_instance { deldev($2); } +; + +select_device_instance: + device_instance AT attachment locators device_flags + { adddev($1, $3, $4, $5); } +; + +/* list of filesystems */ +fs_list: + fsoption + | fs_list ',' fsoption +; + +/* one filesystem */ +fsoption: + WORD { addfsoption($1); } +; + +/* list of filesystems that had NO in front */ +no_fs_list: + no_fsoption + | no_fs_list ',' no_fsoption +; + +/* one filesystem that had NO in front */ +no_fsoption: + WORD { delfsoption($1); } +; + +/* list of make options */ +/* XXX why is this right-recursive? */ +mkopt_list: + mkoption + | mkopt_list ',' mkoption +; + +/* one make option */ +mkoption: + mkvarname '=' value { addmkoption($1, $3); } + | mkvarname PLUSEQ value { appendmkoption($1, $3); } +; + +/* list of make options that had NO in front */ +no_mkopt_list: + no_mkoption + | no_mkopt_list ',' no_mkoption +; + +/* one make option that had NO in front */ +/* XXX shouldn't this be mkvarname rather than WORD? */ +no_mkoption: + WORD { delmkoption($1); } +; + +/* list of options */ +opt_list: + option + | opt_list ',' option +; + +/* one option */ +option: + WORD { addoption($1, NULL); } + | WORD '=' value { addoption($1, $3); } +; + +/* list of options that had NO in front */ +no_opt_list: + no_option + | no_opt_list ',' no_option +; + +/* one option that had NO in front */ +no_option: + WORD { deloption($1); } +; + +/* the name in "config name root on ..." */ +conf: + WORD { + conf.cf_name = $1; + conf.cf_lineno = currentline(); + conf.cf_fstype = NULL; + conf.cf_root = NULL; + conf.cf_dump = NULL; + } +; + +/* root fs specification */ +root_spec: + ROOT on_opt dev_spec { setconf(&conf.cf_root, "root", $3); } + | ROOT on_opt dev_spec fs_spec { setconf(&conf.cf_root, "root", $3); } +; + +/* device for root fs or dump */ +dev_spec: + '?' { $$ = new_si(intern("?"), + (long long)NODEV); } + | WORD { $$ = new_si($1, + (long long)NODEV); } + | major_minor { $$ = new_si(NULL, $1); } +; + +/* major and minor device number */ +major_minor: + MAJOR NUMBER MINOR NUMBER { $$ = (int64_t)makedev($2.val, $4.val); } +; + +/* filesystem type for root fs specification */ +fs_spec: + TYPE '?' { setfstype(&conf.cf_fstype, intern("?")); } + | TYPE WORD { setfstype(&conf.cf_fstype, $2); } +; + +/* zero or more additional system parameters */ +sysparam_list: + /* empty */ + | sysparam_list sysparam +; + +/* one additional system parameter (there's only one: dumps) */ +sysparam: + DUMPS on_opt dev_spec { setconf(&conf.cf_dump, "dumps", $3); } +; + +/* number of pseudo devices to configure (which is optional) */ +npseudo: + /* empty */ { $$ = 1; } + | int32 { $$ = $1; } +; + +/* name of a device to configure */ +device_instance: + WORD { $$ = $1; } + | WORD '*' { $$ = starref($1); } +; + +/* name of a device to configure an attachment to */ +attachment: + ROOT { $$ = NULL; } + | WORD { $$ = $1; } + | WORD '?' { $$ = wildref($1); } +; + +/* zero or more locators */ +locators: + /* empty */ { $$ = NULL; } + | locators locator { $$ = $2; app($2, $1); } +; + +/* one locator */ +locator: + WORD '?' { $$ = MK3(loc, $1, NULL, 0); } + | WORD values { $$ = namelocvals($1, $2); } +; + +/* optional device flags */ +device_flags: + /* empty */ { $$ = 0; } + | FLAGS int32 { $$ = $2; } +; + +/************************************************************/ + +/* + * conditions + */ + + +/* + * order of options is important, must use right recursion + * + * dholland 20120310: wut? + */ + +/* expression of conditions */ +condexpr: + cond_or_expr +; + +cond_or_expr: + cond_and_expr + | cond_or_expr '|' cond_and_expr { $$ = MKF2(cx, or, $1, $3); } +; + +cond_and_expr: + cond_prefix_expr + | cond_and_expr '&' cond_prefix_expr { $$ = MKF2(cx, and, $1, $3); } +; + +cond_prefix_expr: + cond_base_expr +/* XXX notyet - need to strengthen downstream first */ +/* | '!' cond_prefix_expr { $$ = MKF1(cx, not, $2); } */ +; + +cond_base_expr: + condatom { $$ = $1; } + | '!' condatom { $$ = MKF1(cx, not, $2); } + | '(' condexpr ')' { $$ = $2; } +; + +/* basic element of config element expression: a config element */ +condatom: + WORD { $$ = MKF1(cx, atom, $1); } +; + +/************************************************************/ + +/* + * Various nonterminals shared between the grammars. + */ + +/* variable name for make option */ +mkvarname: + QSTRING { $$ = $1; } + | WORD { $$ = $1; } +; + +/* optional file for an option */ +optfile_opt: + /* empty */ { $$ = NULL; } + | filename { $$ = $1; } +; + +/* filename. */ +filename: + QSTRING { $$ = $1; } + | PATHNAME { $$ = $1; } +; + +/* constant value */ +value: + QSTRING { $$ = $1; } + | WORD { $$ = $1; } + | EMPTYSTRING { $$ = $1; } + | signed_number { + char bf[40]; + + (void)snprintf(bf, sizeof(bf), FORMAT($1), (long long)$1.val); + $$ = intern(bf); + } +; + +/* constant value that is a string */ +stringvalue: + QSTRING { $$ = $1; } + | WORD { $$ = $1; } +; + +/* comma-separated list of values */ +/* XXX why right-recursive? */ +values: + value { $$ = MKF2(loc, val, $1, NULL); } + | value ',' values { $$ = MKF2(loc, val, $1, $3); } +; + +/* possibly negative number */ +signed_number: + NUMBER { $$ = $1; } + | '-' NUMBER { $$.fmt = $2.fmt; $$.val = -$2.val; } +; + +/* optional ON keyword */ +on_opt: + /* empty */ + | ON +; + +%% + +void +yyerror(const char *s) +{ + + cfgerror("%s", s); +} + +/************************************************************/ + +/* + * Wrap allocations that live on the parser stack so that we can free + * them again on error instead of leaking. + */ + +#define MAX_WRAP 1000 + +struct wrap_entry { + void *ptr; + unsigned typecode; +}; + +static struct wrap_entry wrapstack[MAX_WRAP]; +static unsigned wrap_depth; + +/* + * Remember pointer PTR with type-code CODE. + */ +static void +wrap_alloc(void *ptr, unsigned code) +{ + unsigned pos; + + if (wrap_depth >= MAX_WRAP) { + panic("allocation wrapper stack overflow"); + } + pos = wrap_depth++; + wrapstack[pos].ptr = ptr; + wrapstack[pos].typecode = code; +} + +/* + * We succeeded; commit to keeping everything that's been allocated so + * far and clear the stack. + */ +static void +wrap_continue(void) +{ + wrap_depth = 0; +} + +/* + * We failed; destroy all the objects allocated. + */ +static void +wrap_cleanup(void) +{ + unsigned i; + + /* + * Destroy each item. Note that because everything allocated + * is entered on the list separately, lists and trees need to + * have their links blanked before being destroyed. Also note + * that strings are interned elsewhere and not handled by this + * mechanism. + */ + + for (i=0; idl_next = NULL; + defoptlist_destroy(dl); + } + break; + case WRAP_CODE_loclist: + { + struct loclist *ll = wrapstack[i].ptr; + + ll->ll_next = NULL; + loclist_destroy(ll); + } + break; + case WRAP_CODE_attrlist: + { + struct attrlist *al = wrapstack[i].ptr; + + al->al_next = NULL; + al->al_this = NULL; + attrlist_destroy(al); + } + break; + case WRAP_CODE_condexpr: + { + struct condexpr *cx = wrapstack[i].ptr; + + cx->cx_type = CX_ATOM; + cx->cx_atom = NULL; + condexpr_destroy(cx); + } + break; + default: + panic("invalid code %u on allocation wrapper stack", + wrapstack[i].typecode); + } + } + + wrap_depth = 0; +} + +/* + * Instantiate the wrapper functions. + * + * Each one calls wrap_alloc to save the pointer and then returns the + * pointer again; these need to be generated with the preprocessor in + * order to be typesafe. + */ +#define DEF_ALLOCWRAP(t) \ + static struct t * \ + wrap_mk_##t(struct t *arg) \ + { \ + wrap_alloc(arg, WRAP_CODE_##t); \ + return arg; \ + } + +DEF_ALLOCWRAP(nvlist); +DEF_ALLOCWRAP(defoptlist); +DEF_ALLOCWRAP(loclist); +DEF_ALLOCWRAP(attrlist); +DEF_ALLOCWRAP(condexpr); + +/************************************************************/ + +/* + * Data constructors + * + * (These are *beneath* the allocation wrappers.) + */ + +static struct defoptlist * +mk_defoptlist(const char *name, const char *val, const char *lintval) +{ + return defoptlist_create(name, val, lintval); +} + +static struct loclist * +mk_loc(const char *name, const char *str, long long num) +{ + return loclist_create(name, str, num); +} + +static struct loclist * +mk_loc_val(const char *str, struct loclist *next) +{ + struct loclist *ll; + + ll = mk_loc(NULL, str, 0); + ll->ll_next = next; + return ll; +} + +static struct attrlist * +mk_attrlist(struct attrlist *next, struct attr *a) +{ + return attrlist_cons(next, a); +} + +static struct condexpr * +mk_cx_atom(const char *s) +{ + struct condexpr *cx; + + cx = condexpr_create(CX_ATOM); + cx->cx_atom = s; + return cx; +} + +static struct condexpr * +mk_cx_not(struct condexpr *sub) +{ + struct condexpr *cx; + + cx = condexpr_create(CX_NOT); + cx->cx_not = sub; + return cx; +} + +static struct condexpr * +mk_cx_and(struct condexpr *left, struct condexpr *right) +{ + struct condexpr *cx; + + cx = condexpr_create(CX_AND); + cx->cx_and.left = left; + cx->cx_and.right = right; + return cx; +} + +static struct condexpr * +mk_cx_or(struct condexpr *left, struct condexpr *right) +{ + struct condexpr *cx; + + cx = condexpr_create(CX_OR); + cx->cx_or.left = left; + cx->cx_or.right = right; + return cx; +} + +/************************************************************/ + +static void +setmachine(const char *mch, const char *mcharch, struct nvlist *mchsubarches, + int isioconf) +{ + char buf[MAXPATHLEN]; + struct nvlist *nv; + + if (isioconf) { + if (include(_PATH_DEVNULL, ENDDEFS, 0, 0) != 0) + exit(1); + ioconfname = mch; + return; + } + + machine = mch; + machinearch = mcharch; + machinesubarches = mchsubarches; + + /* + * Define attributes for all the given names + */ + if (defattr(machine, NULL, NULL, 0) != 0 || + (machinearch != NULL && + defattr(machinearch, NULL, NULL, 0) != 0)) + exit(1); + for (nv = machinesubarches; nv != NULL; nv = nv->nv_next) { + if (defattr(nv->nv_name, NULL, NULL, 0) != 0) + exit(1); + } + + /* + * Set up the file inclusion stack. This empty include tells + * the parser there are no more device definitions coming. + */ + if (include(_PATH_DEVNULL, ENDDEFS, 0, 0) != 0) + exit(1); + + /* Include arch/${MACHINE}/conf/files.${MACHINE} */ + (void)snprintf(buf, sizeof(buf), "arch/%s/conf/files.%s", + machine, machine); + if (include(buf, ENDFILE, 0, 0) != 0) + exit(1); + + /* Include any arch/${MACHINE_SUBARCH}/conf/files.${MACHINE_SUBARCH} */ + for (nv = machinesubarches; nv != NULL; nv = nv->nv_next) { + (void)snprintf(buf, sizeof(buf), "arch/%s/conf/files.%s", + nv->nv_name, nv->nv_name); + if (include(buf, ENDFILE, 0, 0) != 0) + exit(1); + } + + /* Include any arch/${MACHINE_ARCH}/conf/files.${MACHINE_ARCH} */ + if (machinearch != NULL) + (void)snprintf(buf, sizeof(buf), "arch/%s/conf/files.%s", + machinearch, machinearch); + else + strlcpy(buf, _PATH_DEVNULL, sizeof(buf)); + if (include(buf, ENDFILE, 0, 0) != 0) + exit(1); + + /* + * Include the global conf/files. As the last thing + * pushed on the stack, it will be processed first. + */ + if (include("conf/files", ENDFILE, 0, 0) != 0) + exit(1); + + oktopackage = 1; +} + +static void +check_maxpart(void) +{ + + if (maxpartitions <= 0 && ioconfname == NULL) { + stop("cannot proceed without maxpartitions specifier"); + } +} + +static void +check_version(void) +{ + /* + * In essence, version is 0 and is not supported anymore + */ + if (version < CONFIG_MINVERSION) + stop("your sources are out of date -- please update."); +} + +/* + * Prepend a blank entry to the locator definitions so the code in + * sem.c can distinguish "empty locator list" from "no locator list". + * XXX gross. + */ +static struct loclist * +present_loclist(struct loclist *ll) +{ + struct loclist *ret; + + ret = MK3(loc, "", NULL, 0); + ret->ll_next = ll; + return ret; +} + +static void +app(struct loclist *p, struct loclist *q) +{ + while (p->ll_next) + p = p->ll_next; + p->ll_next = q; +} + +static struct loclist * +locarray(const char *name, int count, struct loclist *adefs, int opt) +{ + struct loclist *defs = adefs; + struct loclist **p; + char buf[200]; + int i; + + if (count <= 0) { + fprintf(stderr, "config: array with <= 0 size: %s\n", name); + exit(1); + } + p = &defs; + for(i = 0; i < count; i++) { + if (*p == NULL) + *p = MK3(loc, NULL, "0", 0); + snprintf(buf, sizeof(buf), "%s%c%d", name, ARRCHR, i); + (*p)->ll_name = i == 0 ? name : intern(buf); + (*p)->ll_num = i > 0 || opt; + p = &(*p)->ll_next; + } + *p = 0; + return defs; +} + + +static struct loclist * +namelocvals(const char *name, struct loclist *vals) +{ + struct loclist *p; + char buf[200]; + int i; + + for (i = 0, p = vals; p; i++, p = p->ll_next) { + snprintf(buf, sizeof(buf), "%s%c%d", name, ARRCHR, i); + p->ll_name = i == 0 ? name : intern(buf); + } + return vals; +} + diff --git a/usr.bin/config/hash.c b/usr.bin/config/hash.c new file mode 100644 index 000000000..77382a2fa --- /dev/null +++ b/usr.bin/config/hash.c @@ -0,0 +1,456 @@ +/* $NetBSD: hash.c,v 1.11 2014/10/29 17:14:50 christos Exp $ */ + +/* + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Lawrence Berkeley Laboratories. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * from: @(#)hash.c 8.1 (Berkeley) 6/6/93 + */ + +#if HAVE_NBTOOL_CONFIG_H +#include "nbtool_config.h" +#endif + +#include +__RCSID("$NetBSD: hash.c,v 1.11 2014/10/29 17:14:50 christos Exp $"); + +#include +#include +#include +#include +#include +#include "defs.h" + +/* + * Interned strings are kept in a hash table. By making each string + * unique, the program can compare strings by comparing pointers. + */ +struct hashent { + // XXXLUKEM: a SIMPLEQ might be more appropriate + TAILQ_ENTRY(hashent) h_next; + const char *h_names[2]; /* the string */ +#define h_name1 h_names[0] +#define h_name2 h_names[1] +#define h_name h_name1 + u_int h_hash; /* its hash value */ + void *h_value; /* other values (for name=value) */ +}; +struct hashtab { + size_t ht_size; /* size (power of 2) */ + size_t ht_mask; /* == ht_size - 1 */ + size_t ht_used; /* number of entries used */ + size_t ht_lim; /* when to expand */ + TAILQ_HEAD(hashenthead, hashent) *ht_tab; +}; + +static struct hashtab strings; + +/* + * HASHFRACTION controls ht_lim, which in turn controls the average chain + * length. We allow a few entries, on average, as comparing them is usually + * cheap (the h_hash values prevent a strcmp). + */ +#define HASHFRACTION(sz) ((sz) * 3 / 2) + +static void ht_expand(struct hashtab *); +static void ht_init(struct hashtab *, size_t); +static inline u_int hash(u_int, const char *); +static inline u_int hash2(u_int, const char *, const char *); +static inline struct hashent *newhashent(const char *, u_int); + +/* + * Initialize a new hash table. The size must be a power of 2. + */ +static void +ht_init(struct hashtab *ht, size_t sz) +{ + u_int n; + + ht->ht_tab = emalloc(sz * sizeof (ht->ht_tab[0])); + ht->ht_size = sz; + ht->ht_mask = sz - 1; + for (n = 0; n < sz; n++) + TAILQ_INIT(&ht->ht_tab[n]); + ht->ht_used = 0; + ht->ht_lim = HASHFRACTION(sz); +} + +/* + * Expand an existing hash table. + */ +static void +ht_expand(struct hashtab *ht) +{ + struct hashenthead *h, *oldh; + struct hashent *p; + size_t n, i; + + n = ht->ht_size * 2; + h = emalloc(n * sizeof *h); + for (i = 0; i < n; i++) + TAILQ_INIT(&h[i]); + oldh = ht->ht_tab; + n--; + for (i = 0; i < ht->ht_size; i++) { + while ((p = TAILQ_FIRST(&oldh[i])) != NULL) { + TAILQ_REMOVE(&oldh[i], p, h_next); + // XXXLUKEM: really should be TAILQ_INSERT_TAIL + TAILQ_INSERT_HEAD(&h[p->h_hash & n], p, h_next); + } + } + free(ht->ht_tab); + ht->ht_tab = h; + ht->ht_mask = n; + ht->ht_size = ++n; + ht->ht_lim = HASHFRACTION(n); +} + +/* + * Make a new hash entry, setting its h_next to NULL. + * If the free list is not empty, use the first entry from there, + * otherwise allocate a new entry. + */ +static inline struct hashent * +newhashent2(const char *name1, const char *name2, u_int h) +{ + struct hashent *hp; + + hp = ecalloc(1, sizeof(*hp)); + + hp->h_name1 = name1; + hp->h_name2 = name2; + hp->h_hash = h; + return (hp); +} + +static inline struct hashent * +newhashent(const char *name, u_int h) +{ + return newhashent2(name, NULL, h); +} + +static inline u_int +hv(u_int h, char c) +{ + return (h << 5) + h + (unsigned char)c; +} + +/* + * Hash a string. + */ +static inline u_int +hash(u_int h, const char *str) +{ + + while (str && *str) + h = hv(h, *str++); + return (h); +} + +#define HASH2DELIM ' ' + +static inline u_int +hash2(u_int h, const char *str1, const char *str2) +{ + + h = hash(h, str1); + h = hv(h, HASH2DELIM); + h = hash(h, str2); + return (h); +} + +void +initintern(void) +{ + + ht_init(&strings, 128); +} + +/* + * Generate a single unique copy of the given string. We expect this + * function to be used frequently, so it should be fast. + */ +const char * +intern(const char *s) +{ + struct hashtab *ht; + struct hashent *hp; + struct hashenthead *hpp; + u_int h; + char *p; + + ht = &strings; + h = hash2(0, s, NULL); + hpp = &ht->ht_tab[h & ht->ht_mask]; + TAILQ_FOREACH(hp, hpp, h_next) { + if (hp->h_hash == h && strcmp(hp->h_name, s) == 0) + return (hp->h_name); + } + p = estrdup(s); + hp = newhashent(p, h); + TAILQ_INSERT_TAIL(hpp, hp, h_next); + if (++ht->ht_used > ht->ht_lim) + ht_expand(ht); + return (p); +} + +struct hashtab * +ht_new(void) +{ + struct hashtab *ht; + + ht = ecalloc(1, sizeof *ht); + ht_init(ht, 8); + return (ht); +} + +void +ht_free(struct hashtab *ht) +{ + size_t i; + struct hashent *hp; + struct hashenthead *hpp; + + for (i = 0; i < ht->ht_size; i++) { + hpp = &ht->ht_tab[i]; + while ((hp = TAILQ_FIRST(hpp)) != NULL) { + TAILQ_REMOVE(hpp, hp, h_next); + free(hp); + ht->ht_used--; + } + } + + assert(ht->ht_used == 0); + free(ht->ht_tab); + free(ht); +} + +/* + * Insert and/or replace. + */ +int +ht_insrep2(struct hashtab *ht, const char *nam1, const char *nam2, void *val, int replace) +{ + struct hashent *hp; + struct hashenthead *hpp; + u_int h; + + h = hash2(0, nam1, nam2); + hpp = &ht->ht_tab[h & ht->ht_mask]; + TAILQ_FOREACH(hp, hpp, h_next) { + if (hp->h_name1 == nam1 && + hp->h_name2 == nam2) { + if (replace) + hp->h_value = val; + return (1); + } + } + hp = newhashent2(nam1, nam2, h); + TAILQ_INSERT_TAIL(hpp, hp, h_next); + hp->h_value = val; + if (++ht->ht_used > ht->ht_lim) + ht_expand(ht); + return (0); +} + +int +ht_insrep(struct hashtab *ht, const char *nam, void *val, int replace) +{ + return ht_insrep2(ht, nam, NULL, val, replace); +} + +/* + * Remove. + */ +int +ht_remove2(struct hashtab *ht, const char *name1, const char *name2) +{ + struct hashent *hp; + struct hashenthead *hpp; + u_int h; + + h = hash2(0, name1, name2); + hpp = &ht->ht_tab[h & ht->ht_mask]; + + TAILQ_FOREACH(hp, hpp, h_next) { + if (hp->h_name1 != name1 || hp->h_name2 != name2) + continue; + TAILQ_REMOVE(hpp, hp, h_next); + + free(hp); + ht->ht_used--; + return (0); + } + return (1); +} + +int +ht_remove(struct hashtab *ht, const char *name) +{ + return ht_remove2(ht, name, NULL); +} + +void * +ht_lookup2(struct hashtab *ht, const char *nam1, const char *nam2) +{ + struct hashent *hp; + struct hashenthead *hpp; + u_int h; + + h = hash2(0, nam1, nam2); + hpp = &ht->ht_tab[h & ht->ht_mask]; + TAILQ_FOREACH(hp, hpp, h_next) + if (hp->h_name == nam1) + return (hp->h_value); + return (NULL); +} + +void * +ht_lookup(struct hashtab *ht, const char *nam) +{ + return ht_lookup2(ht, nam, NULL); +} + +/* + * first parameter to callback is the entry name from the hash table + * second parameter is the value from the hash table + * third argument is passed through from the "arg" parameter to ht_enumerate() + */ + +int +ht_enumerate2(struct hashtab *ht, ht_callback2 cbfunc2, void *arg) +{ + struct hashent *hp; + struct hashenthead *hpp; + size_t i; + int rval = 0; + + for (i = 0; i < ht->ht_size; i++) { + hpp = &ht->ht_tab[i]; + TAILQ_FOREACH(hp, hpp, h_next) + rval += (*cbfunc2)(hp->h_name1, hp->h_name2, hp->h_value, arg); + } + return rval; +} + +int +ht_enumerate(struct hashtab *ht, ht_callback cbfunc, void *arg) +{ + struct hashent *hp; + struct hashenthead *hpp; + size_t i; + int rval = 0; + + for (i = 0; i < ht->ht_size; i++) { + hpp = &ht->ht_tab[i]; + TAILQ_FOREACH(hp, hpp, h_next) + rval += (*cbfunc)(hp->h_name, hp->h_value, arg); + } + return rval; +} + +/************************************************************/ + +/* + * Type-safe wrappers. + */ + +#define DEFHASH(HT, VT) \ + struct HT { \ + struct hashtab imp; \ + }; \ + \ + struct HT * \ + HT##_create(void) \ + { \ + struct HT *tbl; \ + \ + tbl = ecalloc(1, sizeof(*tbl)); \ + ht_init(&tbl->imp, 8); \ + return tbl; \ + } \ + \ + int \ + HT##_insert(struct HT *tbl, const char *name, struct VT *val) \ + { \ + return ht_insert(&tbl->imp, name, val); \ + } \ + \ + int \ + HT##_replace(struct HT *tbl, const char *name, struct VT *val) \ + { \ + return ht_replace(&tbl->imp, name, val); \ + } \ + \ + int \ + HT##_remove(struct HT *tbl, const char *name) \ + { \ + return ht_remove(&tbl->imp, name); \ + } \ + \ + struct VT * \ + HT##_lookup(struct HT *tbl, const char *name) \ + { \ + return ht_lookup(&tbl->imp, name); \ + } \ + \ + struct HT##_enumcontext { \ + int (*func)(const char *, struct VT *, void *); \ + void *userctx; \ + }; \ + \ + static int \ + HT##_enumerate_thunk(const char *name, void *value, void *voidctx) \ + { \ + struct HT##_enumcontext *ctx = voidctx; \ + \ + return ctx->func(name, value, ctx->userctx); \ + } \ + \ + int \ + HT##_enumerate(struct HT *tbl, \ + int (*func)(const char *, struct VT *, void *), \ + void *userctx) \ + { \ + struct HT##_enumcontext ctx; \ + \ + ctx.func = func; \ + ctx.userctx = userctx; \ + return ht_enumerate(&tbl->imp, HT##_enumerate_thunk, &ctx); \ + } + +DEFHASH(nvhash, nvlist); +DEFHASH(dlhash, defoptlist); diff --git a/usr.bin/config/lint.c b/usr.bin/config/lint.c new file mode 100644 index 000000000..0066acd8b --- /dev/null +++ b/usr.bin/config/lint.c @@ -0,0 +1,208 @@ +/* $NetBSD: lint.c,v 1.15 2014/10/29 17:14:50 christos Exp $ */ + +/* + * Copyright (c) 2007 The NetBSD Foundation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#if HAVE_NBTOOL_CONFIG_H +#include "nbtool_config.h" +#endif + +#include +__RCSID("$NetBSD: lint.c,v 1.15 2014/10/29 17:14:50 christos Exp $"); + +#include +#include + +#include "defs.h" + +void +emit_params(void) +{ + + printf("version\t%d\n", CONFIG_VERSION); + printf("ident\t\"LINT_%s\"\n", conffile); + printf("maxusers\t%d\n", defmaxusers); + printf("config netbsdlint root on ?\n"); + printf("\n"); +} + +enum opt_types { + OT_FLAG, + OT_PARAM, + OT_FS +}; + +static struct opt_type { + enum opt_types ot_type; + const char *ot_name; + struct hashtab **ot_ht; +} opt_types[] = { + { OT_FLAG, "options", &opttab }, + { OT_PARAM, "options", &opttab }, + { OT_FS, "file-system", &fsopttab }, +}; + +static int +do_emit_option(const char *name, struct defoptlist *dl, void *v) +{ + const struct opt_type *ot = v; + const char *value; + + if (dl->dl_obsolete) + return 0; + + if (ht_lookup(*(ot->ot_ht), name)) + return 0; + + printf("%s\t%s", ot->ot_name, dl->dl_name); + if (ot->ot_type == OT_PARAM) { + struct defoptlist *dl2 = dlhash_lookup(defoptlint, dl->dl_name); + if (dl2 != NULL) + value = dl2->dl_lintvalue; + else + value = dl->dl_value; + assert(dl2 == dl); + printf("=\"%s\"", value ? value : "1"); + } + printf("\n"); + + return 1; +} + +/* + * Same as do_emit_option but for filesystem definitions, which now + * have a different data type. XXX these should probably be unified + * again. + */ +static int +do_emit_fs(const char *name, struct nvlist *nv, void *v) +{ + const struct opt_type *ot = v; + + if (ht_lookup(*(ot->ot_ht), name)) + return 0; + + assert(ot->ot_type != OT_PARAM); + printf("%s\t%s\n", ot->ot_name, nv->nv_name); + + return 1; +} + + +void +emit_options(void) +{ + + (void)dlhash_enumerate(defflagtab, do_emit_option, &opt_types[0]); + printf("\n"); + (void)dlhash_enumerate(defparamtab, do_emit_option, &opt_types[1]); + printf("\n"); + (void)nvhash_enumerate(deffstab, do_emit_fs, &opt_types[2]); + printf("\n"); +} + +static void +do_emit_instances(struct devbase *d, struct attr *at) +{ + struct nvlist *nv1; + struct loclist *ll; + struct attrlist *al; + struct attr *a; + struct deva *da; + + /* + * d_isdef is used to check whether a deva has been seen or not, + * for there are devices that can be their own ancestor (e.g. + * uhub, pci). + */ + + if (at != NULL) { + for (da = d->d_ahead; da != NULL; da = da->d_bsame) + if (onlist(da->d_atlist, at)) + break; + if (da == NULL) + panic("do_emit_instances: no deva found for %s at %s", + d->d_name, at->a_name); + + if (da->d_isdef > 1) + return; + da->d_isdef = 2; + } + + if (at == NULL && !d->d_ispseudo && d->d_ihead == NULL) + printf("%s0\tat\troot\n", d->d_name); + else if (at != NULL && !d->d_ispseudo && da->d_ihead == NULL) { + printf("%s0\tat\t%s?", d->d_name, at->a_name); + + for (ll = at->a_locs; ll != NULL; ll = ll->ll_next) { + if (ll->ll_num == 0) + printf(" %s %c", ll->ll_name, + ll->ll_string ? '?' : '0'); + } + + printf("\n"); + } + + /* + * Children attachments are found the same way as in the orphan + * detection code in main.c. + */ + for (al = d->d_attrs; al != NULL; al = al->al_next) { + a = al->al_this; + for (nv1 = a->a_devs; nv1 != NULL; nv1 = nv1->nv_next) + do_emit_instances(nv1->nv_ptr, a); + } +} + +/* ARGSUSED */ +static int +emit_root_instance(const char *name, void *value, void *v) +{ + + do_emit_instances((struct devbase *)value, NULL); + + return 1; +} + +/* ARGSUSED */ +static int +emit_pseudo_instance(const char *name, void *value, void *v) +{ + struct devbase *d = value; + + if (d->d_ispseudo && d->d_ihead == NULL) + printf("pseudo-device\t%s\n", d->d_name); + return 0; +} + +void +emit_instances(void) +{ + + (void)ht_enumerate(devroottab, emit_root_instance, NULL); + printf("\n"); + (void)ht_enumerate(devbasetab, emit_pseudo_instance, NULL); +} diff --git a/usr.bin/config/main.c b/usr.bin/config/main.c new file mode 100644 index 000000000..20f29e0bd --- /dev/null +++ b/usr.bin/config/main.c @@ -0,0 +1,2037 @@ +/* $NetBSD: main.c,v 1.89 2015/09/04 06:01:40 uebayasi Exp $ */ + +/* + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Lawrence Berkeley Laboratories. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * from: @(#)main.c 8.1 (Berkeley) 6/6/93 + */ + +#if HAVE_NBTOOL_CONFIG_H +#include "nbtool_config.h" +#endif + +#include +__RCSID("$NetBSD: main.c,v 1.89 2015/09/04 06:01:40 uebayasi Exp $"); + +#ifndef MAKE_BOOTSTRAP +#include +#define COPYRIGHT(x) __COPYRIGHT(x) +#else +#define COPYRIGHT(x) static const char copyright[] = x +#endif + +#ifndef lint +COPYRIGHT("@(#) Copyright (c) 1992, 1993\ + The Regents of the University of California. All rights reserved."); +#endif /* not lint */ + +#include +#include +#include +#include +#if !HAVE_NBTOOL_CONFIG_H +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "defs.h" +#include "sem.h" + +#ifndef LINE_MAX +#define LINE_MAX 1024 +#endif + +int vflag; /* verbose output */ +int Pflag; /* pack locators */ +int Lflag; /* lint config generation */ +int Mflag; /* modular build */ +int Sflag; /* suffix rules & subdirectory */ +int handling_cmdlineopts; /* currently processing -D/-U options */ + +int yyparse(void); + +#ifndef MAKE_BOOTSTRAP +extern int yydebug; +#endif +int dflag; + +static struct dlhash *obsopttab; +static struct hashtab *mkopttab; +static struct nvlist **nextopt; +static struct nvlist **nextmkopt; +static struct nvlist **nextappmkopt; +static struct nvlist **nextcndmkopt; +static struct nvlist **nextfsopt; +static struct nvlist *cmdlinedefs, *cmdlineundefs; + +static void usage(void) __dead; +static void dependopts(void); +static void dependopts_one(const char *); +static void do_depends(struct nvlist *); +static void do_depend(struct nvlist *); +static void stop(void); +static int do_option(struct hashtab *, struct nvlist **, + struct nvlist ***, const char *, const char *, + const char *, struct hashtab *); +static int undo_option(struct hashtab *, struct nvlist **, + struct nvlist ***, const char *, const char *); +static int crosscheck(void); +static int badstar(void); + int main(int, char **); +static int mkallsubdirs(void); +static int mksymlinks(void); +static int mkident(void); +static int devbase_has_dead_instances(const char *, void *, void *); +static int devbase_has_any_instance(struct devbase *, int, int, int); +static int check_dead_devi(const char *, void *, void *); +static void add_makeopt(const char *); +static void remove_makeopt(const char *); +static void handle_cmdline_makeoptions(void); +static void kill_orphans(void); +static void do_kill_orphans(struct devbase *, struct attr *, + struct devbase *, int); +static int kill_orphans_cb(const char *, void *, void *); +static int cfcrosscheck(struct config *, const char *, struct nvlist *); +static void defopt(struct dlhash *ht, const char *fname, + struct defoptlist *opts, struct nvlist *deps, int obs); +static struct defoptlist *find_declared_option_option(const char *name); +static struct nvlist *find_declared_fs_option(const char *name); + +#define LOGCONFIG_LARGE "INCLUDE_CONFIG_FILE" +#define LOGCONFIG_SMALL "INCLUDE_JUST_CONFIG" + +static void logconfig_start(void); +static void logconfig_end(void); +static FILE *cfg; +static time_t cfgtime; + +static int is_elf(const char *); +static int extract_config(const char *, const char *, int); + +int badfilename(const char *fname); + +const char *progname; +extern const char *yyfile; + +int +main(int argc, char **argv) +{ + char *p, cname[PATH_MAX]; + const char *last_component; + int pflag, xflag, ch, removeit; + + setprogname(argv[0]); + + pflag = 0; + xflag = 0; + while ((ch = getopt(argc, argv, "D:LMPSU:dgpvb:s:x")) != -1) { + switch (ch) { + + case 'd': +#ifndef MAKE_BOOTSTRAP + yydebug = 1; +#endif + dflag++; + break; + + case 'M': + Mflag = 1; + break; + + case 'L': + Lflag = 1; + break; + + case 'P': + Pflag = 1; + break; + + case 'g': + /* + * In addition to DEBUG, you probably wanted to + * set "options KGDB" and maybe others. We could + * do that for you, but you really should just + * put them in the config file. + */ + warnx("-g is obsolete (use -D DEBUG=\"-g\")"); + usage(); + /*NOTREACHED*/ + + case 'p': + /* + * Essentially the same as makeoptions PROF="-pg", + * but also changes the path from ../../compile/FOO + * to ../../compile/FOO.PROF; i.e., compile a + * profiling kernel based on a typical "regular" + * kernel. + * + * Note that if you always want profiling, you + * can (and should) use a "makeoptions" line. + */ + pflag = 1; + break; + + case 'v': + vflag = 1; + break; + + case 'b': + builddir = optarg; + break; + + case 's': + srcdir = optarg; + break; + + case 'S': + Sflag = 1; + break; + + case 'x': + xflag = 1; + break; + + case 'D': + add_makeopt(optarg); + break; + + case 'U': + remove_makeopt(optarg); + break; + + case '?': + default: + usage(); + } + } + + if (xflag && optind != 2) { + errx(EXIT_FAILURE, "-x must be used alone"); + } + + argc -= optind; + argv += optind; + if (argc > 1) { + usage(); + } + + if (Lflag && (builddir != NULL || Pflag || pflag)) + errx(EXIT_FAILURE, "-L can only be used with -s and -v"); + + if (xflag) { + if (argc == 0) { +#if !HAVE_NBTOOL_CONFIG_H + char path_unix[MAXPATHLEN]; + size_t len = sizeof(path_unix) - 1; + path_unix[0] = '/'; + + conffile = sysctlbyname("machdep.booted_kernel", + &path_unix[1], &len, NULL, 0) == -1 ? _PATH_UNIX : + path_unix; +#else + errx(EXIT_FAILURE, "no kernel supplied"); +#endif + } else + conffile = argv[0]; + if (!is_elf(conffile)) + errx(EXIT_FAILURE, "%s: not a binary kernel", + conffile); + if (!extract_config(conffile, "stdout", STDOUT_FILENO)) + errx(EXIT_FAILURE, "%s does not contain embedded " + "configuration data", conffile); + exit(0); + } + + conffile = (argc == 1) ? argv[0] : "CONFIG"; + if (firstfile(conffile)) { + err(EXIT_FAILURE, "Cannot read `%s'", conffile); + exit(2); + } + + /* + * Init variables. + */ + minmaxusers = 1; + maxmaxusers = 10000; + initintern(); + ident = NULL; + devbasetab = ht_new(); + devroottab = ht_new(); + devatab = ht_new(); + devitab = ht_new(); + deaddevitab = ht_new(); + selecttab = ht_new(); + needcnttab = ht_new(); + opttab = ht_new(); + mkopttab = ht_new(); + fsopttab = ht_new(); + deffstab = nvhash_create(); + defopttab = dlhash_create(); + defparamtab = dlhash_create(); + defoptlint = dlhash_create(); + defflagtab = dlhash_create(); + optfiletab = dlhash_create(); + obsopttab = dlhash_create(); + bdevmtab = ht_new(); + maxbdevm = 0; + cdevmtab = ht_new(); + maxcdevm = 0; + nextopt = &options; + nextmkopt = &mkoptions; + nextappmkopt = &appmkoptions; + nextcndmkopt = &condmkoptions; + nextfsopt = &fsoptions; + initfiles(); + initsem(); + + /* + * Handle profiling (must do this before we try to create any + * files). + */ + last_component = strrchr(conffile, '/'); + last_component = (last_component) ? last_component + 1 : conffile; + if (pflag) { + p = emalloc(strlen(last_component) + 17); + (void)sprintf(p, "../compile/%s.PROF", last_component); + (void)addmkoption(intern("PROF"), "-pg"); + (void)addoption(intern("GPROF"), NULL); + } else { + p = emalloc(strlen(last_component) + 13); + (void)sprintf(p, "../compile/%s", last_component); + } + defbuilddir = (argc == 0) ? "." : p; + + if (Lflag) { + char resolvedname[MAXPATHLEN]; + + if (realpath(conffile, resolvedname) == NULL) + err(EXIT_FAILURE, "realpath(%s)", conffile); + + if (yyparse()) + stop(); + + printf("include \"%s\"\n", resolvedname); + + emit_params(); + emit_options(); + emit_instances(); + + exit(EXIT_SUCCESS); + } + + removeit = 0; + if (is_elf(conffile)) { + const char *tmpdir; + int cfd; + + if (builddir == NULL) + errx(EXIT_FAILURE, "Build directory must be specified " + "with binary kernels"); + + /* Open temporary configuration file */ + tmpdir = getenv("TMPDIR"); + if (tmpdir == NULL) + tmpdir = _PATH_TMP; + snprintf(cname, sizeof(cname), "%s/config.tmp.XXXXXX", tmpdir); + cfd = mkstemp(cname); + if (cfd == -1) + err(EXIT_FAILURE, "Cannot create `%s'", cname); + + printf("Using configuration data embedded in kernel...\n"); + if (!extract_config(conffile, cname, cfd)) { + unlink(cname); + errx(EXIT_FAILURE, "%s does not contain embedded " + "configuration data", conffile); + } + + removeit = 1; + close(cfd); + firstfile(cname); + } + + /* + * Log config file. We don't know until yyparse() if we're + * going to need config_file.h (i.e. if we're doing ioconf-only + * or not). Just start creating the file, and when we know + * later, we'll just keep or discard our work here. + */ + logconfig_start(); + + /* + * Parse config file (including machine definitions). + */ + if (yyparse()) + stop(); + + if (ioconfname && cfg) + fclose(cfg); + else + logconfig_end(); + + if (removeit) + unlink(cname); + + /* + * Handle command line overrides + */ + yyfile = "handle_cmdline_makeoptions"; + handle_cmdline_makeoptions(); + + /* + * Detect and properly ignore orphaned devices + */ + yyfile = "kill_orphans"; + kill_orphans(); + + /* + * Select devices and pseudo devices and their attributes + */ + yyfile = "fixdevis"; + if (fixdevis()) + stop(); + + /* + * Copy maxusers to param. + */ + yyfile = "fixmaxusers"; + fixmaxusers(); + + /* + * Copy makeoptions to params + */ + yyfile = "fixmkoption"; + fixmkoption(); + + /* + * If working on an ioconf-only config, process here and exit + */ + if (ioconfname) { + yyfile = "pack"; + pack(); + yyfile = "mkioconf"; + mkioconf(); + yyfile = "emitlocs"; + emitlocs(); + yyfile = "emitioconfh"; + emitioconfh(); + return 0; + } + + yyfile = "dependattrs"; + dependattrs(); + + /* + * Deal with option dependencies. + */ + yyfile = "dependopts"; + dependopts(); + + /* + * Fix (as in `set firmly in place') files. + */ + yyfile = "fixfiles"; + if (fixfiles()) + stop(); + + /* + * Fix device-majors. + */ + yyfile = "fixdevsw"; + if (fixdevsw()) + stop(); + + /* + * Perform cross-checking. + */ + if (maxusers == 0) { + if (defmaxusers) { + (void)printf("maxusers not specified; %d assumed\n", + defmaxusers); + maxusers = defmaxusers; + } else { + warnx("need \"maxusers\" line"); + errors++; + } + } + if (crosscheck() || errors) + stop(); + + /* + * Squeeze things down and finish cross-checks (STAR checks must + * run after packing). + */ + yyfile = "pack"; + pack(); + yyfile = "badstar"; + if (badstar()) + stop(); + + yyfile = NULL; + /* + * Ready to go. Build all the various files. + */ + if ((Sflag && mkallsubdirs()) || mksymlinks() || mkmakefile() || mkheaders() || mkswap() || + mkioconf() || (do_devsw ? mkdevsw() : 0) || mkident() || errors) + stop(); + (void)printf("Build directory is %s\n", builddir); + (void)printf("Don't forget to run \"make depend\"\n"); + + return 0; +} + +static void +usage(void) +{ + (void)fprintf(stderr, "Usage: %s [-Ppv] [-b builddir] [-D var=value] " + "[-s srcdir] [-U var] " + "[config-file]\n\t%s -x [kernel-file]\n" + "\t%s -L [-v] [-s srcdir] [config-file]\n", + getprogname(), getprogname(), getprogname()); + exit(1); +} + +/* + * Set any options that are implied by other options. + */ +static void +dependopts(void) +{ + struct nvlist *nv; + + for (nv = options; nv != NULL; nv = nv->nv_next) { + dependopts_one(nv->nv_name); + } + + for (nv = fsoptions; nv != NULL; nv = nv->nv_next) { + dependopts_one(nv->nv_name); + } +} + +static void +dependopts_one(const char *name) +{ + struct defoptlist *dl; + struct nvlist *fs; + + dl = find_declared_option_option(name); + if (dl != NULL) { + do_depends(dl->dl_depends); + } + fs = find_declared_fs_option(name); + if (fs != NULL) { + do_depends(fs->nv_ptr); + } + + CFGDBG(3, "depend `%s' searched", name); +} + +static void +do_depends(struct nvlist *nv) +{ + struct nvlist *opt; + + for (opt = nv; opt != NULL; opt = opt->nv_next) { + do_depend(opt); + } +} + +static void +do_depend(struct nvlist *nv) +{ + struct attr *a; + + if (nv != NULL && (nv->nv_flags & NV_DEPENDED) == 0) { + nv->nv_flags |= NV_DEPENDED; + /* + * If the dependency is an attribute, then just add + * it to the selecttab. + */ + CFGDBG(3, "depend attr `%s'", nv->nv_name); + if ((a = ht_lookup(attrtab, nv->nv_name)) != NULL) { + if (a->a_iattr) + panic("do_depend(%s): dep `%s' is an iattr", + nv->nv_name, a->a_name); + expandattr(a, selectattr); + } else { + if (ht_lookup(opttab, nv->nv_name) == NULL) + addoption(nv->nv_name, NULL); + dependopts_one(nv->nv_name); + } + } +} + +static int +recreate(const char *p, const char *q) +{ + int ret; + + if ((ret = unlink(q)) == -1 && errno != ENOENT) + warn("unlink(%s)", q); + if ((ret = symlink(p, q)) == -1) + warn("symlink(%s -> %s)", q, p); + return ret; +} + +static void +mksubdir(char *buf) +{ + char *p; + struct stat st; + + p = strrchr(buf, '/'); + if (p != NULL && *p == '/') { + *p = '\0'; + mksubdir(buf); + *p = '/'; + } + if (stat(buf, &st) == 0) { + if (!S_ISDIR(st.st_mode)) + errx(EXIT_FAILURE, "not directory %s", buf); + } else + if (mkdir(buf, 0777) == -1) + errx(EXIT_FAILURE, "cannot create %s", buf); +} + +static int +mksubdirs(struct filelist *fl) +{ + struct files *fi; + const char *prologue, *prefix, *sep; + char buf[MAXPATHLEN]; + + TAILQ_FOREACH(fi, fl, fi_next) { + if ((fi->fi_flags & FI_SEL) == 0) + continue; + prefix = sep = ""; + if (fi->fi_buildprefix != NULL) { + prefix = fi->fi_buildprefix; + sep = "/"; + } else { + if (fi->fi_prefix != NULL) { + prefix = fi->fi_prefix; + sep = "/"; + } + } + snprintf(buf, sizeof(buf), "%s%s%s", prefix, sep, fi->fi_dir); + if (buf[0] == '\0') + continue; + mksubdir(buf); + if (fi->fi_prefix != NULL && fi->fi_buildprefix != NULL) { + char org[MAXPATHLEN]; + + if (fi->fi_prefix[0] == '/') { + prologue = ""; + sep = ""; + } else { + prologue = srcdir; + sep = "/"; + } + snprintf(buf, sizeof(buf), "%s%s%s", + fi->fi_buildprefix, "/", fi->fi_path); + snprintf(org, sizeof(org), "%s%s%s%s%s", + prologue, sep, fi->fi_prefix, "/", fi->fi_path); + recreate(org, buf); + fi->fi_prefix = fi->fi_buildprefix; + fi->fi_buildprefix = NULL; + } + } + + return 0; +} + +static int +mkallsubdirs(void) +{ + + mksubdirs(&allfiles); + mksubdirs(&allofiles); + return 0; +} + +/* + * Make a symlink for "machine" so that "#include " works, + * and for the machine's CPU architecture, so that works as well. + */ +static int +mksymlinks(void) +{ + int ret; + char *p, buf[MAXPATHLEN]; + const char *q; + struct nvlist *nv; + + p = buf; + + snprintf(buf, sizeof(buf), "%s/arch/%s/include", srcdir, machine); + ret = recreate(p, "machine"); + ret = recreate(p, machine); + + if (machinearch != NULL) { + snprintf(buf, sizeof(buf), "%s/arch/%s/include", srcdir, machinearch); + q = machinearch; + } else { + snprintf(buf, sizeof(buf), "machine"); + q = machine; + } + + ret = recreate(p, q); + + for (nv = machinesubarches; nv != NULL; nv = nv->nv_next) { + q = nv->nv_name; + snprintf(buf, sizeof(buf), "%s/arch/%s/include", srcdir, q); + ret = recreate(p, q); + } + + return (ret); +} + +static __dead void +stop(void) +{ + (void)fprintf(stderr, "*** Stop.\n"); + exit(1); +} + +static void +check_dependencies(const char *thing, struct nvlist *deps) +{ + struct nvlist *dep; + struct attr *a; + + for (dep = deps; dep != NULL; dep = dep->nv_next) { + /* + * If the dependency is an attribute, it must not + * be an interface attribute. Otherwise, it must + * be a previously declared option. + */ + if ((a = ht_lookup(attrtab, dep->nv_name)) != NULL) { + if (a->a_iattr) + cfgerror("option `%s' dependency `%s' " + "is an interface attribute", + thing, a->a_name); + } else if (OPT_OBSOLETE(dep->nv_name)) { + cfgerror("option `%s' dependency `%s' " + "is obsolete", thing, dep->nv_name); + } else if (!is_declared_option(dep->nv_name)) { + cfgerror("option `%s' dependency `%s' " + "is an unknown option", + thing, dep->nv_name); + } + } +} + +static void +add_fs_dependencies(struct nvlist *nv, struct nvlist *deps) +{ + /* Use nv_ptr to link any other options that are implied. */ + nv->nv_ptr = deps; + check_dependencies(nv->nv_name, deps); +} + +static void +add_opt_dependencies(struct defoptlist *dl, struct nvlist *deps) +{ + dl->dl_depends = deps; + check_dependencies(dl->dl_name, deps); +} + +/* + * Define one or more file systems. + */ +void +deffilesystem(struct nvlist *fses, struct nvlist *deps) +{ + struct nvlist *nv; + + /* + * Mark these options as ones to skip when creating the Makefile. + */ + for (nv = fses; nv != NULL; nv = nv->nv_next) { + if (DEFINED_OPTION(nv->nv_name)) { + cfgerror("file system or option `%s' already defined", + nv->nv_name); + return; + } + + /* + * Also mark it as a valid file system, which may be + * used in "file-system" directives in the config + * file. + */ + if (nvhash_insert(deffstab, nv->nv_name, nv)) + panic("file system `%s' already in table?!", + nv->nv_name); + + add_fs_dependencies(nv, deps); + + /* + * Implicit attribute definition for filesystem. + */ + const char *n; + n = strtolower(nv->nv_name); + refattr(n); + } +} + +/* + * Sanity check a file name. + */ +int +badfilename(const char *fname) +{ + const char *n; + + /* + * We're putting multiple options into one file. Sanity + * check the file name. + */ + if (strchr(fname, '/') != NULL) { + cfgerror("option file name contains a `/'"); + return 1; + } + if ((n = strrchr(fname, '.')) == NULL || strcmp(n, ".h") != 0) { + cfgerror("option file name does not end in `.h'"); + return 1; + } + return 0; +} + + +/* + * Search for a defined option (defopt, filesystem, etc), and if found, + * return the option's struct nvlist. + * + * This used to be one function (find_declared_option) before options + * and filesystems became different types. + */ +static struct defoptlist * +find_declared_option_option(const char *name) +{ + struct defoptlist *option; + + if ((option = dlhash_lookup(defopttab, name)) != NULL || + (option = dlhash_lookup(defparamtab, name)) != NULL || + (option = dlhash_lookup(defflagtab, name)) != NULL) { + return (option); + } + + return (NULL); +} + +static struct nvlist * +find_declared_fs_option(const char *name) +{ + struct nvlist *fs; + + if ((fs = nvhash_lookup(deffstab, name)) != NULL) { + return fs; + } + + return (NULL); +} + +/* + * Like find_declared_option but doesn't return what it finds, so it + * can search both the various kinds of options and also filesystems. + */ +int +is_declared_option(const char *name) +{ + struct defoptlist *option = NULL; + struct nvlist *fs; + + if ((option = dlhash_lookup(defopttab, name)) != NULL || + (option = dlhash_lookup(defparamtab, name)) != NULL || + (option = dlhash_lookup(defflagtab, name)) != NULL) { + return 1; + } + if ((fs = nvhash_lookup(deffstab, name)) != NULL) { + return 1; + } + + return 0; +} + +/* + * Define one or more standard options. If an option file name is specified, + * place all options in one file with the specified name. Otherwise, create + * an option file for each option. + * record the option information in the specified table. + */ +void +defopt(struct dlhash *ht, const char *fname, struct defoptlist *opts, + struct nvlist *deps, int obs) +{ + struct defoptlist *dl, *nextdl, *olddl; + const char *name; + char buf[500]; + + if (fname != NULL && badfilename(fname)) { + return; + } + + /* + * Mark these options as ones to skip when creating the Makefile. + */ + for (dl = opts; dl != NULL; dl = nextdl) { + nextdl = dl->dl_next; + + if (dl->dl_lintvalue != NULL) { + /* + * If an entry already exists, then we are about to + * complain, so no worry. + */ + (void) dlhash_insert(defoptlint, dl->dl_name, + dl); + } + + /* An option name can be declared at most once. */ + if (DEFINED_OPTION(dl->dl_name)) { + cfgerror("file system or option `%s' already defined", + dl->dl_name); + return; + } + + if (dlhash_insert(ht, dl->dl_name, dl)) { + cfgerror("file system or option `%s' already defined", + dl->dl_name); + return; + } + + if (fname == NULL) { + /* + * Each option will be going into its own file. + * Convert the option name to lower case. This + * lower case name will be used as the option + * file name. + */ + (void) snprintf(buf, sizeof(buf), "opt_%s.h", + strtolower(dl->dl_name)); + name = intern(buf); + } else { + name = fname; + } + + add_opt_dependencies(dl, deps); + + /* + * Remove this option from the parameter list before adding + * it to the list associated with this option file. + */ + dl->dl_next = NULL; + + /* + * Flag as obsolete, if requested. + */ + if (obs) { + dl->dl_obsolete = 1; + (void)dlhash_insert(obsopttab, dl->dl_name, dl); + } + + /* + * Add this option file if we haven't seen it yet. + * Otherwise, append to the list of options already + * associated with this file. + */ + if ((olddl = dlhash_lookup(optfiletab, name)) == NULL) { + (void)dlhash_insert(optfiletab, name, dl); + } else { + while (olddl->dl_next != NULL) + olddl = olddl->dl_next; + olddl->dl_next = dl; + } + } +} + +/* + * Define one or more standard options. If an option file name is specified, + * place all options in one file with the specified name. Otherwise, create + * an option file for each option. + */ +void +defoption(const char *fname, struct defoptlist *opts, struct nvlist *deps) +{ + + cfgwarn("The use of `defopt' is deprecated"); + defopt(defopttab, fname, opts, deps, 0); +} + + +/* + * Define an option for which a value is required. + */ +void +defparam(const char *fname, struct defoptlist *opts, struct nvlist *deps, int obs) +{ + + defopt(defparamtab, fname, opts, deps, obs); +} + +/* + * Define an option which must not have a value, and which + * emits a "needs-flag" style output. + */ +void +defflag(const char *fname, struct defoptlist *opts, struct nvlist *deps, int obs) +{ + + defopt(defflagtab, fname, opts, deps, obs); +} + + +/* + * Add an option from "options FOO". Note that this selects things that + * are "optional foo". + */ +void +addoption(const char *name, const char *value) +{ + const char *n; + int is_fs, is_param, is_flag, is_undecl, is_obs; + + /* + * Figure out how this option was declared (if at all.) + * XXX should use "params" and "flags" in config. + * XXX crying out for a type field in a unified hashtab. + */ + is_fs = OPT_FSOPT(name); + is_param = OPT_DEFPARAM(name); + is_flag = OPT_DEFFLAG(name); + is_obs = OPT_OBSOLETE(name); + is_undecl = !DEFINED_OPTION(name); + + /* Warn and pretend the user had not selected the option */ + if (is_obs) { + cfgwarn("obsolete option `%s' will be ignored", name); + return; + } + + /* Make sure this is not a defined file system. */ + if (is_fs) { + cfgerror("`%s' is a defined file system", name); + return; + } + /* A defparam must have a value */ + if (is_param && value == NULL) { + cfgerror("option `%s' must have a value", name); + return; + } + /* A defflag must not have a value */ + if (is_flag && value != NULL) { + cfgerror("option `%s' must not have a value", name); + return; + } + + if (is_undecl && vflag) { + cfgwarn("undeclared option `%s' added to IDENT", name); + } + + if (do_option(opttab, &options, &nextopt, name, value, "options", + selecttab)) + return; + + /* make lowercase, then add to select table */ + n = strtolower(name); + (void)ht_insert(selecttab, n, (void *)__UNCONST(n)); + CFGDBG(3, "option selected `%s'", n); +} + +void +deloption(const char *name) +{ + + CFGDBG(4, "deselecting opt `%s'", name); + if (undo_option(opttab, &options, &nextopt, name, "options")) + return; + if (undo_option(selecttab, NULL, NULL, strtolower(name), "options")) + return; +} + +/* + * Add a file system option. This routine simply inserts the name into + * a list of valid file systems, which is used to validate the root + * file system type. The name is then treated like a standard option. + */ +void +addfsoption(const char *name) +{ + const char *n; + + /* Make sure this is a defined file system. */ + if (!OPT_FSOPT(name)) { + cfgerror("`%s' is not a defined file system", name); + return; + } + + /* + * Convert to lower case. This will be used in the select + * table, to verify root file systems. + */ + n = strtolower(name); + + if (do_option(fsopttab, &fsoptions, &nextfsopt, name, n, "file-system", + selecttab)) + return; + + /* Add to select table. */ + (void)ht_insert(selecttab, n, __UNCONST(n)); + CFGDBG(3, "fs selected `%s'", name); + + /* + * Select attribute if one exists. + */ + struct attr *a; + if ((a = ht_lookup(attrtab, n)) != NULL) + selectattr(a); +} + +void +delfsoption(const char *name) +{ + const char *n; + + CFGDBG(4, "deselecting fs `%s'", name); + n = strtolower(name); + if (undo_option(fsopttab, &fsoptions, &nextfsopt, name, "file-system")) + return; + if (undo_option(selecttab, NULL, NULL, n, "file-system")) + return; +} + +/* + * Add a "make" option. + */ +void +addmkoption(const char *name, const char *value) +{ + + (void)do_option(mkopttab, &mkoptions, &nextmkopt, name, value, + "makeoptions", NULL); +} + +void +delmkoption(const char *name) +{ + + CFGDBG(4, "deselecting mkopt `%s'", name); + (void)undo_option(mkopttab, &mkoptions, &nextmkopt, name, + "makeoptions"); +} + +/* + * Add an appending "make" option. + */ +void +appendmkoption(const char *name, const char *value) +{ + struct nvlist *nv; + + nv = newnv(name, value, NULL, 0, NULL); + *nextappmkopt = nv; + nextappmkopt = &nv->nv_next; +} + +/* + * Add a conditional appending "make" option. + */ +void +appendcondmkoption(struct condexpr *cond, const char *name, const char *value) +{ + struct nvlist *nv; + + nv = newnv(name, value, cond, 0, NULL); + *nextcndmkopt = nv; + nextcndmkopt = &nv->nv_next; +} + +/* + * Copy maxusers to param "MAXUSERS". + */ +void +fixmaxusers(void) +{ + char str[32]; + + snprintf(str, sizeof(str), "%d", maxusers); + addoption(intern("MAXUSERS"), intern(str)); +} + +/* + * Copy makeoptions to params with "makeoptions_" prefix. + */ +void +fixmkoption(void) +{ + struct nvlist *nv; + char buf[100]; + const char *name; + + for (nv = mkoptions; nv != NULL; nv = nv->nv_next) { + snprintf(buf, sizeof(buf), "makeoptions_%s", nv->nv_name); + name = intern(buf); + if (!DEFINED_OPTION(name) || !OPT_DEFPARAM(name)) + continue; + addoption(name, intern(nv->nv_str)); + } +} + +/* + * Add a name=value pair to an option list. The value may be NULL. + */ +static int +do_option(struct hashtab *ht, struct nvlist **npp, struct nvlist ***next, + const char *name, const char *value, const char *type, + struct hashtab *stab) +{ + struct nvlist *nv, *onv; + + /* assume it will work */ + nv = newnv(name, value, NULL, 0, NULL); + if (ht_insert(ht, name, nv) != 0) { + + /* oops, already got that option - remove it first */ + if ((onv = ht_lookup(ht, name)) == NULL) + panic("do_option 1"); + if (onv->nv_str != NULL && !OPT_FSOPT(name)) + cfgwarn("already have %s `%s=%s'", type, name, + onv->nv_str); + else + cfgwarn("already have %s `%s'", type, name); + + if (undo_option(ht, npp, next, name, type)) + panic("do_option 2"); + if (stab != NULL && + undo_option(stab, NULL, NULL, strtolower(name), type)) + panic("do_option 3"); + + /* now try adding it again */ + if (ht_insert(ht, name, nv) != 0) + panic("do_option 4"); + + CFGDBG(2, "opt `%s' replaced", name); + } + **next = nv; + *next = &nv->nv_next; + + return (0); +} + +/* + * Remove a name from a hash table, + * and optionally, a name=value pair from an option list. + */ +static int +undo_option(struct hashtab *ht, struct nvlist **npp, + struct nvlist ***next, const char *name, const char *type) +{ + struct nvlist *nv; + + if (ht_remove(ht, name)) { + /* + * -U command line option removals are always silent + */ + if (!handling_cmdlineopts) + cfgwarn("%s `%s' is not defined", type, name); + return (1); + } + if (npp == NULL) { + CFGDBG(2, "opt `%s' deselected", name); + return (0); + } + + for ( ; *npp != NULL; npp = &(*npp)->nv_next) { + if ((*npp)->nv_name != name) + continue; + if (next != NULL && *next == &(*npp)->nv_next) + *next = npp; + nv = (*npp)->nv_next; + CFGDBG(2, "opt `%s' deselected", (*npp)->nv_name); + nvfree(*npp); + *npp = nv; + return (0); + } + panic("%s `%s' is not defined in nvlist", type, name); + return (1); +} + +/* + * Return true if there is at least one instance of the given unit + * on the given device attachment (or any units, if unit == WILD). + */ +int +deva_has_instances(struct deva *deva, int unit) +{ + struct devi *i; + + /* + * EHAMMERTOOBIG: we shouldn't check i_pseudoroot here. + * What we want by this check is them to appear non-present + * except for purposes of other devices being able to attach + * to them. + */ + for (i = deva->d_ihead; i != NULL; i = i->i_asame) + if (i->i_active == DEVI_ACTIVE && i->i_pseudoroot == 0 && + (unit == WILD || unit == i->i_unit || i->i_unit == STAR)) + return (1); + return (0); +} + +/* + * Return true if there is at least one instance of the given unit + * on the given base (or any units, if unit == WILD). + */ +int +devbase_has_instances(struct devbase *dev, int unit) +{ + struct deva *da; + + /* + * Pseudo-devices are a little special. We consider them + * to have instances only if they are both: + * + * 1. Included in this kernel configuration. + * + * 2. Be declared "defpseudodev". + */ + if (dev->d_ispseudo) { + return ((ht_lookup(devitab, dev->d_name) != NULL) + && (dev->d_ispseudo > 1)); + } + + for (da = dev->d_ahead; da != NULL; da = da->d_bsame) + if (deva_has_instances(da, unit)) + return (1); + return (0); +} + +static int +cfcrosscheck(struct config *cf, const char *what, struct nvlist *nv) +{ + struct devbase *dev; + struct devi *pd; + int errs, devunit; + + if (maxpartitions <= 0) + panic("cfcrosscheck"); + + for (errs = 0; nv != NULL; nv = nv->nv_next) { + if (nv->nv_name == NULL) + continue; + dev = ht_lookup(devbasetab, nv->nv_name); + if (dev == NULL) + panic("cfcrosscheck(%s)", nv->nv_name); + if (has_attr(dev->d_attrs, s_ifnet)) + devunit = nv->nv_ifunit; /* XXX XXX XXX */ + else + devunit = (int)(minor(nv->nv_num) / maxpartitions); + if (devbase_has_instances(dev, devunit)) + continue; + if (devbase_has_instances(dev, STAR) && + devunit >= dev->d_umax) + continue; + TAILQ_FOREACH(pd, &allpseudo, i_next) { + if (pd->i_base == dev && devunit < dev->d_umax && + devunit >= 0) + goto loop; + } + (void)fprintf(stderr, + "%s:%d: %s says %s on %s, but there's no %s\n", + conffile, cf->cf_lineno, + cf->cf_name, what, nv->nv_str, nv->nv_str); + errs++; + loop: + ; + } + return (errs); +} + +/* + * Cross-check the configuration: make sure that each target device + * or attribute (`at foo[0*?]') names at least one real device. Also + * see that the root and dump devices for all configurations are there. + */ +int +crosscheck(void) +{ + struct config *cf; + int errs; + + errs = 0; + if (TAILQ_EMPTY(&allcf)) { + warnx("%s has no configurations!", conffile); + errs++; + } + TAILQ_FOREACH(cf, &allcf, cf_next) { + if (cf->cf_root != NULL) { /* i.e., not root on ? */ + errs += cfcrosscheck(cf, "root", cf->cf_root); + errs += cfcrosscheck(cf, "dumps", cf->cf_dump); + } + } + return (errs); +} + +/* + * Check to see if there is a *'d unit with a needs-count file. + */ +int +badstar(void) +{ + struct devbase *d; + struct deva *da; + struct devi *i; + int errs, n; + + errs = 0; + TAILQ_FOREACH(d, &allbases, d_next) { + for (da = d->d_ahead; da != NULL; da = da->d_bsame) + for (i = da->d_ihead; i != NULL; i = i->i_asame) { + if (i->i_unit == STAR) + goto aybabtu; + } + continue; + aybabtu: + if (ht_lookup(needcnttab, d->d_name)) { + warnx("%s's cannot be *'d until its driver is fixed", + d->d_name); + errs++; + continue; + } + for (n = 0; i != NULL; i = i->i_alias) + if (!i->i_collapsed) + n++; + if (n < 1) + panic("badstar() n<1"); + } + return (errs); +} + +/* + * Verify/create builddir if necessary, change to it, and verify srcdir. + * This will be called when we see the first include. + */ +void +setupdirs(void) +{ + struct stat st; + + /* srcdir must be specified if builddir is not specified or if + * no configuration filename was specified. */ + if ((builddir || strcmp(defbuilddir, ".") == 0) && !srcdir) { + cfgerror("source directory must be specified"); + exit(1); + } + + if (Lflag) { + if (srcdir == NULL) + srcdir = "../../.."; + return; + } + + if (srcdir == NULL) + srcdir = "../../../.."; + if (builddir == NULL) + builddir = defbuilddir; + + if (stat(builddir, &st) == -1) { + if (mkdir(builddir, 0777) == -1) + errx(EXIT_FAILURE, "cannot create %s", builddir); + } else if (!S_ISDIR(st.st_mode)) + errx(EXIT_FAILURE, "%s is not a directory", builddir); + if (chdir(builddir) == -1) + err(EXIT_FAILURE, "cannot change to %s", builddir); + if (stat(srcdir, &st) == -1) + err(EXIT_FAILURE, "cannot stat %s", srcdir); + if (!S_ISDIR(st.st_mode)) + errx(EXIT_FAILURE, "%s is not a directory", srcdir); +} + +/* + * Write identifier from "ident" directive into file, for + * newvers.sh to pick it up. + */ +int +mkident(void) +{ + FILE *fp; + int error = 0; + + (void)unlink("ident"); + + if (ident == NULL) + return (0); + + if ((fp = fopen("ident", "w")) == NULL) { + warn("cannot write ident"); + return (1); + } + if (vflag) + (void)printf("using ident '%s'\n", ident); + fprintf(fp, "%s\n", ident); + fflush(fp); + if (ferror(fp)) + error = 1; + (void)fclose(fp); + + return error; +} + +void +logconfig_start(void) +{ + extern FILE *yyin; + char line[1024]; + const char *tmpdir; + struct stat st; + int fd; + + if (yyin == NULL || fstat(fileno(yyin), &st) == -1) + return; + cfgtime = st.st_mtime; + + tmpdir = getenv("TMPDIR"); + if (tmpdir == NULL) + tmpdir = _PATH_TMP; + (void)snprintf(line, sizeof(line), "%s/config.tmp.XXXXXX", tmpdir); + if ((fd = mkstemp(line)) == -1 || + (cfg = fdopen(fd, "r+")) == NULL) { + if (fd != -1) { + (void)unlink(line); + (void)close(fd); + } + cfg = NULL; + return; + } + (void)unlink(line); + + (void)fprintf(cfg, "#include \n\n"); + (void)fprintf(cfg, "#include \"opt_config.h\"\n"); + (void)fprintf(cfg, "\n"); + (void)fprintf(cfg, "/*\n"); + (void)fprintf(cfg, " * Add either (or both) of\n"); + (void)fprintf(cfg, " *\n"); + (void)fprintf(cfg, " *\toptions %s\n", LOGCONFIG_LARGE); + (void)fprintf(cfg, " *\toptions %s\n", LOGCONFIG_SMALL); + (void)fprintf(cfg, " *\n"); + (void)fprintf(cfg, + " * to your kernel config file to embed it in the resulting\n"); + (void)fprintf(cfg, + " * kernel. The latter option does not include files that are\n"); + (void)fprintf(cfg, + " * included (recursively) by your config file. The embedded\n"); + (void)fprintf(cfg, + " * data be extracted by using the command:\n"); + (void)fprintf(cfg, " *\n"); + (void)fprintf(cfg, + " *\tstrings netbsd | sed -n 's/^_CFG_//p' | unvis\n"); + (void)fprintf(cfg, " */\n"); + (void)fprintf(cfg, "\n"); + (void)fprintf(cfg, "#ifdef CONFIG_FILE\n"); + (void)fprintf(cfg, "#if defined(%s) || defined(%s)\n\n", + LOGCONFIG_LARGE, LOGCONFIG_SMALL); + (void)fprintf(cfg, "static const char config[] __used =\n\n"); + + (void)fprintf(cfg, "#ifdef %s\n\n", LOGCONFIG_LARGE); + (void)fprintf(cfg, "\"_CFG_### START CONFIG FILE \\\"%s\\\"\\n\"\n\n", + conffile); + (void)fprintf(cfg, "#endif /* %s */\n\n", LOGCONFIG_LARGE); + + logconfig_include(yyin, NULL); + + (void)fprintf(cfg, "#ifdef %s\n\n", LOGCONFIG_LARGE); + (void)fprintf(cfg, "\"_CFG_### END CONFIG FILE \\\"%s\\\"\\n\"\n", + conffile); + + rewind(yyin); +} + +void +logconfig_include(FILE *cf, const char *filename) +{ + char line[1024], in[2048], *out; + struct stat st; + int missingeol; + + if (!cfg) + return; + + missingeol = 0; + if (fstat(fileno(cf), &st) == -1) + return; + if (cfgtime < st.st_mtime) + cfgtime = st.st_mtime; + + if (filename) + (void)fprintf(cfg, + "\"_CFG_### (included from \\\"%s\\\")\\n\"\n", + filename); + while (fgets(line, sizeof(line), cf) != NULL) { + missingeol = 1; + (void)fprintf(cfg, "\"_CFG_"); + if (filename) + (void)fprintf(cfg, "###> "); + strvis(in, line, VIS_TAB); + for (out = in; *out; out++) + switch (*out) { + case '\n': + (void)fprintf(cfg, "\\n\"\n"); + missingeol = 0; + break; + case '"': case '\\': + (void)fputc('\\', cfg); + /* FALLTHROUGH */ + default: + (void)fputc(*out, cfg); + break; + } + } + if (missingeol) { + (void)fprintf(cfg, "\\n\"\n"); + warnx("%s: newline missing at EOF", + filename != NULL ? filename : conffile); + } + if (filename) + (void)fprintf(cfg, "\"_CFG_### (end include \\\"%s\\\")\\n\"\n", + filename); + + rewind(cf); +} + +void +logconfig_end(void) +{ + char line[1024]; + FILE *fp; + struct stat st; + + if (!cfg) + return; + + (void)fprintf(cfg, "#endif /* %s */\n", LOGCONFIG_LARGE); + (void)fprintf(cfg, ";\n"); + (void)fprintf(cfg, "#endif /* %s || %s */\n", + LOGCONFIG_LARGE, LOGCONFIG_SMALL); + (void)fprintf(cfg, "#endif /* CONFIG_FILE */\n"); + fflush(cfg); + if (ferror(cfg)) + err(EXIT_FAILURE, "write to temporary file for config.h failed"); + rewind(cfg); + + if (stat("config_file.h", &st) != -1) { + if (cfgtime < st.st_mtime) { + fclose(cfg); + return; + } + } + + fp = fopen("config_file.h", "w"); + if (!fp) + err(EXIT_FAILURE, "cannot open \"config.h\""); + + while (fgets(line, sizeof(line), cfg) != NULL) + fputs(line, fp); + fflush(fp); + if (ferror(fp)) + err(EXIT_FAILURE, "write to \"config.h\" failed"); + fclose(fp); + fclose(cfg); +} + +const char * +strtolower(const char *name) +{ + const char *n; + char *p, low[500]; + char c; + + for (n = name, p = low; (c = *n) != '\0'; n++) + *p++ = (char)(isupper((u_char)c) ? tolower((u_char)c) : c); + *p = '\0'; + return (intern(low)); +} + +static int +is_elf(const char *file) +{ + int kernel; + char hdr[4]; + + kernel = open(file, O_RDONLY); + if (kernel == -1) + err(EXIT_FAILURE, "cannot open %s", file); + if (read(kernel, hdr, 4) != 4) + err(EXIT_FAILURE, "Cannot read from %s", file); + (void)close(kernel); + + return memcmp("\177ELF", hdr, 4) == 0 ? 1 : 0; +} + +static int +extract_config(const char *kname, const char *cname, int cfd) +{ + char *ptr; + void *base; + int found, kfd; + struct stat st; + off_t i; + + found = 0; + + /* mmap(2) binary kernel */ + kfd = open(conffile, O_RDONLY); + if (kfd == -1) + err(EXIT_FAILURE, "cannot open %s", kname); + if (fstat(kfd, &st) == -1) + err(EXIT_FAILURE, "cannot stat %s", kname); + base = mmap(0, (size_t)st.st_size, PROT_READ, MAP_FILE | MAP_SHARED, + kfd, 0); + if (base == MAP_FAILED) + err(EXIT_FAILURE, "cannot mmap %s", kname); + ptr = base; + + /* Scan mmap(2)'ed region, extracting kernel configuration */ + for (i = 0; i < st.st_size; i++) { + if ((*ptr == '_') && (st.st_size - i > 5) && memcmp(ptr, + "_CFG_", 5) == 0) { + /* Line found */ + char *oldptr, line[LINE_MAX + 1], uline[LINE_MAX + 1]; + int j; + + found = 1; + + oldptr = (ptr += 5); + while (*ptr != '\n' && *ptr != '\0') + ptr++; + if (ptr - oldptr > LINE_MAX) + errx(EXIT_FAILURE, "line too long"); + i += ptr - oldptr + 5; + (void)memcpy(line, oldptr, (size_t)(ptr - oldptr)); + line[ptr - oldptr] = '\0'; + j = strunvis(uline, line); + if (j == -1) + errx(EXIT_FAILURE, "unvis: invalid " + "encoded sequence"); + uline[j] = '\n'; + if (write(cfd, uline, (size_t)j + 1) == -1) + err(EXIT_FAILURE, "cannot write to %s", cname); + } else + ptr++; + } + + (void)close(kfd); + (void)munmap(base, (size_t)st.st_size); + + return found; +} + +struct dhdi_params { + struct devbase *d; + int unit; + int level; +}; + +static int +devbase_has_dead_instances(const char *key, void *value, void *aux) +{ + struct devi *i; + struct dhdi_params *dhdi = aux; + + for (i = value; i != NULL; i = i->i_alias) + if (i->i_base == dhdi->d && + (dhdi->unit == WILD || dhdi->unit == i->i_unit || + i->i_unit == STAR) && + i->i_level >= dhdi->level) + return 1; + return 0; +} + +/* + * This is almost the same as devbase_has_instances, except it + * may have special considerations regarding ignored instances. + */ + +static int +devbase_has_any_instance(struct devbase *dev, int unit, int state, int level) +{ + struct deva *da; + struct devi *i; + + if (dev->d_ispseudo) { + if (dev->d_ihead != NULL) + return 1; + else if (state != DEVI_IGNORED) + return 0; + if ((i = ht_lookup(deaddevitab, dev->d_name)) == NULL) + return 0; + return (i->i_level >= level); + } + + for (da = dev->d_ahead; da != NULL; da = da->d_bsame) + for (i = da->d_ihead; i != NULL; i = i->i_asame) + if ((i->i_active == DEVI_ACTIVE || + i->i_active == state) && + (unit == WILD || unit == i->i_unit || + i->i_unit == STAR)) + return 1; + + if (state == DEVI_IGNORED) { + struct dhdi_params dhdi = { dev, unit, level }; + /* also check dead devices */ + return ht_enumerate(deaddevitab, devbase_has_dead_instances, + &dhdi); + } + + return 0; +} + +/* + * check_dead_devi(), used with ht_enumerate, checks if any of the removed + * device instances would have been a valid instance considering the devbase, + * the parent device and the interface attribute. + * + * In other words, for a non-active device, it checks if children would be + * actual orphans or the result of a negative statement in the config file. + */ + +struct cdd_params { + struct devbase *d; + struct attr *at; + struct devbase *parent; +}; + +static int +check_dead_devi(const char *key, void *value, void *aux) +{ + struct cdd_params *cdd = aux; + struct devi *i = value; + struct pspec *p; + + if (i->i_base != cdd->d) + return 0; + + for (; i != NULL; i = i->i_alias) { + p = i->i_pspec; + if ((p == NULL && cdd->at == NULL) || + (p != NULL && p->p_iattr == cdd->at && + (p->p_atdev == NULL || p->p_atdev == cdd->parent))) { + if (p != NULL && + !devbase_has_any_instance(cdd->parent, p->p_atunit, + DEVI_IGNORED, i->i_level)) + return 0; + else + return 1; + } + } + return 0; +} + +static void +do_kill_orphans(struct devbase *d, struct attr *at, struct devbase *parent, + int state) +{ + struct nvlist *nv1; + struct attrlist *al; + struct attr *a; + struct devi *i, *j = NULL; + struct pspec *p; + int active = 0; + + /* + * A pseudo-device will always attach at root, and if it has an + * instance (it cannot have more than one), it is enough to consider + * it active, as there is no real attachment. + * + * A pseudo device can never be marked DEVI_IGNORED. + */ + if (d->d_ispseudo) { + if (d->d_ihead != NULL) + d->d_ihead->i_active = active = DEVI_ACTIVE; + else { + if (ht_lookup(deaddevitab, d->d_name) != NULL) + active = DEVI_IGNORED; + else + return; + } + } else { + int seen = 0; + + for (i = d->d_ihead; i != NULL; i = i->i_bsame) { + for (j = i; j != NULL; j = j->i_alias) { + p = j->i_pspec; + if ((p == NULL && at == NULL) || + (p != NULL && p->p_iattr == at && + (p->p_atdev == NULL || + p->p_atdev == parent))) { + if (p != NULL && + !devbase_has_any_instance(parent, + p->p_atunit, state, j->i_level)) + continue; + /* + * There are Fry-like devices which can + * be their own grand-parent (or even + * parent, like uhub). We don't want + * to loop, so if we've already reached + * an instance for one reason or + * another, stop there. + */ + if (j->i_active == DEVI_ACTIVE || + j->i_active == state) { + /* + * Device has already been + * seen. However it might + * have siblings who still + * have to be activated or + * orphaned. + */ + seen = 1; + continue; + } + j->i_active = active = state; + if (p != NULL) + p->p_active = state; + } + } + } + /* + * If we've been there but have made no change, stop. + */ + if (seen && !active) + return; + if (!active) { + struct cdd_params cdd = { d, at, parent }; + /* Look for a matching dead devi */ + if (ht_enumerate(deaddevitab, check_dead_devi, &cdd) && + d != parent) + /* + * That device had its instances removed. + * Continue the loop marking descendants + * with DEVI_IGNORED instead of DEVI_ACTIVE. + * + * There is one special case for devices that + * are their own parent: if that instance is + * removed (e.g., no uhub* at uhub?), we don't + * have to continue looping. + */ + active = DEVI_IGNORED; + else + return; + } + } + + for (al = d->d_attrs; al != NULL; al = al->al_next) { + a = al->al_this; + for (nv1 = a->a_devs; nv1 != NULL; nv1 = nv1->nv_next) + do_kill_orphans(nv1->nv_ptr, a, d, active); + } +} + +static int +/*ARGSUSED*/ +kill_orphans_cb(const char *key, void *value, void *aux) +{ + do_kill_orphans((struct devbase *)value, NULL, NULL, DEVI_ACTIVE); + return 0; +} + +static void +kill_orphans(void) +{ + ht_enumerate(devroottab, kill_orphans_cb, NULL); +} + +static void +add_makeopt(const char *opt) +{ + struct nvlist *p; + char *buf = estrdup(opt); + char *eq = strchr(buf, '='); + + if (!eq) + errx(EXIT_FAILURE, "-D %s is not in var=value format", opt); + + *eq = 0; + p = newnv(estrdup(buf), estrdup(eq+1), NULL, 0, NULL); + free(buf); + p->nv_next = cmdlinedefs; + cmdlinedefs = p; +} + +static void +remove_makeopt(const char *opt) +{ + struct nvlist *p; + + p = newnv(estrdup(opt), NULL, NULL, 0, NULL); + p->nv_next = cmdlineundefs; + cmdlineundefs = p; +} + +static void +handle_cmdline_makeoptions(void) +{ + struct nvlist *p, *n; + + handling_cmdlineopts = 1; + for (p = cmdlineundefs; p; p = n) { + n = p->nv_next; + delmkoption(intern(p->nv_name)); + free(__UNCONST(p->nv_name)); + nvfree(p); + } + for (p = cmdlinedefs; p; p = n) { + const char *name = intern(p->nv_name); + + n = p->nv_next; + delmkoption(name); + addmkoption(name, intern(p->nv_str)); + free(__UNCONST(p->nv_name)); + free(__UNCONST(p->nv_str)); + + nvfree(p); + } + handling_cmdlineopts = 0; +} diff --git a/usr.bin/config/mkdevsw.c b/usr.bin/config/mkdevsw.c new file mode 100644 index 000000000..66c8ac7d8 --- /dev/null +++ b/usr.bin/config/mkdevsw.c @@ -0,0 +1,241 @@ +/* $NetBSD: mkdevsw.c,v 1.14 2015/09/03 13:53:36 uebayasi Exp $ */ + +/* + * Copyright (c) 2002 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by MAEKAWA Masahide (gehenna@NetBSD.org). + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#if HAVE_NBTOOL_CONFIG_H +#include "nbtool_config.h" +#endif + +#include +__RCSID("$NetBSD: mkdevsw.c,v 1.14 2015/09/03 13:53:36 uebayasi Exp $"); + +#include +#include +#include +#include + +#include "defs.h" + +static void emitconv(FILE *); +static void emitdev(FILE *); +static void emitdevm(FILE *); +static void emitheader(FILE *); + +int +mkdevsw(void) +{ + FILE *fp; + + if ((fp = fopen("devsw.c.tmp", "w")) == NULL) { + warn("cannot create devsw.c"); + return (1); + } + + emitheader(fp); + emitdevm(fp); + emitconv(fp); + emitdev(fp); + + fflush(fp); + if (ferror(fp)) { + warn("error writing devsw.c"); + fclose(fp); + return 1; + } + + (void)fclose(fp); + + if (moveifchanged("devsw.c.tmp", "devsw.c") != 0) { + warn("error renaming devsw.c"); + return (1); + } + + return (0); +} + +static void +emitheader(FILE *fp) +{ + autogen_comment(fp, "devsw.c"); + + fputs("#include \n" + "#include \n", fp); +} + +static void +dentry(FILE *fp, struct hashtab *t, devmajor_t i, char p) +{ + const struct devm *dm; + char mstr[16]; + + (void)snprintf(mstr, sizeof(mstr), "%d", i); + if ((dm = ht_lookup(t, intern(mstr))) == NULL) + return; + + fprintf(fp, "extern const struct %cdevsw %s_%cdevsw;\n", + p, dm->dm_name, p); +} + +static void +pentry(FILE *fp, struct hashtab *t, devmajor_t i, char p) +{ + const struct devm *dm; + char mstr[16]; + + (void)snprintf(mstr, sizeof(mstr), "%d", i); + dm = ht_lookup(t, intern(mstr)); + + if (dm) + fprintf(fp, "\t&%s_%cdevsw", dm->dm_name, p); + else + fputs("\tNULL", fp); + + fprintf(fp, ",\t// %3d\n", i); +} + +/* + * Emit device switch table for character/block device. + */ +static void +emitdevm(FILE *fp) +{ + devmajor_t i; + + fputs("\n/* device switch table for block device */\n", fp); + + for (i = 0; i <= maxbdevm ; i++) + dentry(fp, cdevmtab, i, 'b'); + + fputs("\nconst struct bdevsw *bdevsw0[] = {\n", fp); + + for (i = 0; i <= maxbdevm; i++) + pentry(fp, bdevmtab, i, 'b'); + + fputs("};\n\nconst struct bdevsw **bdevsw = bdevsw0;\n", fp); + + fputs("const int sys_bdevsws = __arraycount(bdevsw0);\n" + "int max_bdevsws = __arraycount(bdevsw0);\n", fp); + + fputs("\n/* device switch table for character device */\n", fp); + + for (i = 0; i <= maxcdevm; i++) + dentry(fp, cdevmtab, i, 'c'); + + fputs("\nconst struct cdevsw *cdevsw0[] = {\n", fp); + + for (i = 0; i <= maxcdevm; i++) + pentry(fp, cdevmtab, i, 'c'); + + fputs("};\n\nconst struct cdevsw **cdevsw = cdevsw0;\n", fp); + + fputs("const int sys_cdevsws = __arraycount(cdevsw0);\n" + "int max_cdevsws = __arraycount(cdevsw0);\n", fp); +} + +/* + * Emit device major conversion table. + */ +static void +emitconv(FILE *fp) +{ + struct devm *dm; + + fputs("\n/* device conversion table */\n" + "struct devsw_conv devsw_conv0[] = {\n", fp); + TAILQ_FOREACH(dm, &alldevms, dm_next) { + if (version < 20100430) { + /* Emit compatible structure */ + fprintf(fp, "\t{ \"%s\", %d, %d },\n", dm->dm_name, + dm->dm_bmajor, dm->dm_cmajor); + continue; + } + struct nvlist *nv; + const char *d_class, *d_flags = "0"; + int d_vec[2] = { 0, 0 }; + int i = 0; + + /* + * "parse" info. currently the rules are simple: + * 1) first entry defines class + * 2) next ones without n_str are d_vectdim + * 3) next one with n_str is d_flags + * 4) EOL + */ + nv = dm->dm_devnodes; + d_class = nv->nv_str; + while ((nv = nv->nv_next) != NULL) { + if (i > 2) + panic("invalid devnode definition"); + if (nv->nv_str) { + d_flags = nv->nv_str; + break; + } + if (nv->nv_num > INT_MAX || nv->nv_num < INT_MIN) + panic("out of range devnode definition"); + d_vec[i++] = (int)nv->nv_num; + } + + fprintf(fp, "\t{ \"%s\", %d, %d, %s, %s, { %d, %d }},\n", + dm->dm_name, dm->dm_bmajor, dm->dm_cmajor, + d_class, d_flags, d_vec[0], d_vec[1]); + + } + fputs("};\n\n" + "struct devsw_conv *devsw_conv = devsw_conv0;\n" + "int max_devsw_convs = __arraycount(devsw_conv0);\n", + fp); +} + +/* + * Emit specific device major informations. + */ +static void +emitdev(FILE *fp) +{ + struct devm *dm; + char mstr[16]; + + fputs("\n", fp); + + (void)strlcpy(mstr, "swap", sizeof(mstr)); + if ((dm = ht_lookup(bdevmtab, intern(mstr))) != NULL) { + fprintf(fp, "const dev_t swapdev = makedev(%d, 0);\n", + dm->dm_bmajor); + } + + (void)strlcpy(mstr, "mem", sizeof(mstr)); + if ((dm = ht_lookup(cdevmtab, intern(mstr))) == NULL) + panic("memory device is not configured"); + fprintf(fp, "const dev_t zerodev = makedev(%d, DEV_ZERO);\n", + dm->dm_cmajor); + + fputs("\n/* mem_no is only used in iskmemdev() */\n", fp); + fprintf(fp, "const int mem_no = %d;\n", dm->dm_cmajor); +} diff --git a/usr.bin/config/mkheaders.c b/usr.bin/config/mkheaders.c new file mode 100644 index 000000000..bf250188f --- /dev/null +++ b/usr.bin/config/mkheaders.c @@ -0,0 +1,547 @@ +/* $NetBSD: mkheaders.c,v 1.29 2015/09/03 13:53:36 uebayasi Exp $ */ + +/* + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Lawrence Berkeley Laboratories. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * from: @(#)mkheaders.c 8.1 (Berkeley) 6/6/93 + */ + +#if HAVE_NBTOOL_CONFIG_H +#include "nbtool_config.h" +#endif + +#include +__RCSID("$NetBSD: mkheaders.c,v 1.29 2015/09/03 13:53:36 uebayasi Exp $"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "defs.h" + +#include + +static int emitcnt(struct nvlist *); +static int emitopts(void); +static int emittime(void); +static int herr(const char *, const char *, FILE *); +static int defopts_print(const char *, struct defoptlist *, void *); +static char *cntname(const char *); + +/* + * We define a global symbol with the name of each option and its value. + * This should stop code compiled with different options being linked together. + */ + +/* Unlikely constant for undefined options */ +#define UNDEFINED ('n' << 24 | 0 << 20 | 't' << 12 | 0xdefU) +/* Value for defined options with value UNDEFINED */ +#define DEFINED (0xdef1U << 16 | 'n' << 8 | 0xed) + +/* + * Make the various config-generated header files. + */ +int +mkheaders(void) +{ + struct files *fi; + + /* + * Make headers containing counts, as needed. + */ + TAILQ_FOREACH(fi, &allfiles, fi_next) { + if (fi->fi_flags & FI_HIDDEN) + continue; + if (fi->fi_flags & (FI_NEEDSCOUNT | FI_NEEDSFLAG) && + emitcnt(fi->fi_optf)) + return (1); + } + + if (emitopts() || emitlocs() || emitioconfh()) + return (1); + + /* + * If the minimum required version is ever bumped beyond 20090513, + * emittime() can be removed. + */ + if (version <= 20090513 && emittime()) + return (1); + + return (0); +} + +static void +fprint_global(FILE *fp, const char *name, long long value) +{ + /* + * We have to doubt the founding fathers here. + * The gas syntax for hppa is 'var .equ value', for all? other + * instruction sets it is ' .equ var,value'. both have been used in + * various assemblers, but supporting a common syntax would be good. + * Fortunately we can use .equiv since it has a consistent syntax, + * but requires us to detect multiple assignments - event with the + * same value. + */ + fprintf(fp, "#ifdef _LOCORE\n" + " .ifndef _KERNEL_OPT_%s\n" + " .global _KERNEL_OPT_%s\n" + " .equiv _KERNEL_OPT_%s,0x%llx\n" + " .endif\n" + "#else\n" + "__asm(\" .ifndef _KERNEL_OPT_%s\\n" + " .global _KERNEL_OPT_%s\\n" + " .equiv _KERNEL_OPT_%s,0x%llx\\n" + " .endif\");\n" + "#endif\n", + name, name, name, value, + name, name, name, value); +} + +/* Convert the option argument to a 32bit numder */ +static unsigned int +global_hash(const char *str) +{ + unsigned long h; + char *ep; + + /* + * If the value is a valid numeric, just use it + * We don't care about negative values here, we + * just use the value as a hash. + */ + h = strtoul(str, &ep, 0); + if (*ep != 0) + /* Otherwise shove through a 32bit CRC function */ + h = crc_buf(0, str, strlen(str)); + + /* Avoid colliding with the value used for undefined options. */ + /* At least until I stop any options being set to zero */ + return (unsigned int)(h != UNDEFINED ? h : DEFINED); +} + +static void +fprintcnt(FILE *fp, struct nvlist *nv) +{ + const char *name = cntname(nv->nv_name); + + fprintf(fp, "#define\t%s\t%lld\n", name, nv->nv_num); + fprint_global(fp, name, nv->nv_num); +} + +static int +emitcnt(struct nvlist *head) +{ + char nfname[BUFSIZ], tfname[BUFSIZ]; + struct nvlist *nv; + FILE *fp; + + (void)snprintf(nfname, sizeof(nfname), "%s.h", head->nv_name); + (void)snprintf(tfname, sizeof(tfname), "tmp_%s", nfname); + + if ((fp = fopen(tfname, "w")) == NULL) + return (herr("open", tfname, NULL)); + + for (nv = head; nv != NULL; nv = nv->nv_next) + fprintcnt(fp, nv); + + fflush(fp); + if (ferror(fp)) + return herr("writ", tfname, fp); + + if (fclose(fp) == EOF) + return (herr("clos", tfname, NULL)); + + return (moveifchanged(tfname, nfname)); +} + +/* + * Output a string, preceded by a tab and possibly unescaping any quotes. + * The argument will be output as is if it doesn't start with \". + * Otherwise the first backslash in a \? sequence will be dropped. + */ +static void +fprintstr(FILE *fp, const char *str) +{ + + if (strncmp(str, "\\\"", 2) != 0) { + (void)fprintf(fp, "\t%s", str); + return; + } + + (void)fputc('\t', fp); + + for (; *str; str++) { + switch (*str) { + case '\\': + if (!*++str) /* XXX */ + str--; + /*FALLTHROUGH*/ + default: + (void)fputc(*str, fp); + break; + } + } +} + +/* + * Callback function for walking the option file hash table. We write out + * the options defined for this file. + */ +static int +/*ARGSUSED*/ +defopts_print(const char *name, struct defoptlist *value, void *arg) +{ + char tfname[BUFSIZ]; + struct nvlist *option; + struct defoptlist *dl; + const char *opt_value; + int isfsoption; + FILE *fp; + + (void)snprintf(tfname, sizeof(tfname), "tmp_%s", name); + if ((fp = fopen(tfname, "w")) == NULL) + return (herr("open", tfname, NULL)); + + for (dl = value; dl != NULL; dl = dl->dl_next) { + isfsoption = OPT_FSOPT(dl->dl_name); + + if (dl->dl_obsolete) { + fprintf(fp, "/* %s `%s' is obsolete */\n", + isfsoption ? "file system" : "option", + dl->dl_name); + fprint_global(fp, dl->dl_name, 0xdeadbeef); + continue; + } + + if (((option = ht_lookup(opttab, dl->dl_name)) == NULL && + (option = ht_lookup(fsopttab, dl->dl_name)) == NULL) && + (dl->dl_value == NULL)) { + fprintf(fp, "/* %s `%s' not defined */\n", + isfsoption ? "file system" : "option", + dl->dl_name); + fprint_global(fp, dl->dl_name, UNDEFINED); + continue; + } + + opt_value = option != NULL ? option->nv_str : dl->dl_value; + if (isfsoption == 1) + /* For filesysteme we'd output the lower case name */ + opt_value = NULL; + + fprintf(fp, "#define\t%s", dl->dl_name); + if (opt_value != NULL) + fprintstr(fp, opt_value); + else if (!isfsoption) + fprintstr(fp, "1"); + fputc('\n', fp); + fprint_global(fp, dl->dl_name, + opt_value == NULL ? 1 : global_hash(opt_value)); + } + + fflush(fp); + if (ferror(fp)) + return herr("writ", tfname, fp); + + if (fclose(fp) == EOF) + return (herr("clos", tfname, NULL)); + + return (moveifchanged(tfname, name)); +} + +/* + * Emit the option header files. + */ +static int +emitopts(void) +{ + + return (dlhash_enumerate(optfiletab, defopts_print, NULL)); +} + +/* + * A callback function for walking the attribute hash table. + * Emit CPP definitions of manifest constants for the locators on the + * "name" attribute node (passed as the "value" parameter). + */ +static int +locators_print(const char *name, void *value, void *arg) +{ + struct attr *a; + struct loclist *ll; + int i; + char *locdup, *namedup; + char *cp; + FILE *fp = arg; + + a = value; + if (a->a_locs) { + if (strchr(name, ' ') != NULL || strchr(name, '\t') != NULL) + /* + * name contains a space; we can't generate + * usable defines, so ignore it. + */ + return 0; + locdup = estrdup(name); + for (cp = locdup; *cp; cp++) + if (islower((unsigned char)*cp)) + *cp = (char)toupper((unsigned char)*cp); + for (i = 0, ll = a->a_locs; ll; ll = ll->ll_next, i++) { + if (strchr(ll->ll_name, ' ') != NULL || + strchr(ll->ll_name, '\t') != NULL) + /* + * name contains a space; we can't generate + * usable defines, so ignore it. + */ + continue; + namedup = estrdup(ll->ll_name); + for (cp = namedup; *cp; cp++) + if (islower((unsigned char)*cp)) + *cp = (char)toupper((unsigned char)*cp); + else if (*cp == ARRCHR) + *cp = '_'; + fprintf(fp, "#define %sCF_%s %d\n", locdup, namedup, i); + if (ll->ll_string != NULL) + fprintf(fp, "#define %sCF_%s_DEFAULT %s\n", + locdup, namedup, ll->ll_string); + free(namedup); + } + /* assert(i == a->a_loclen) */ + fprintf(fp, "#define %sCF_NLOCS %d\n", locdup, a->a_loclen); + free(locdup); + } + return 0; +} + +/* + * Build the "locators.h" file with manifest constants for all potential + * locators in the configuration. Do this by enumerating the attribute + * hash table and emitting all the locators for each attribute. + */ +int +emitlocs(void) +{ + const char *tfname; + int rval; + FILE *tfp; + + tfname = "tmp_locators.h"; + if ((tfp = fopen(tfname, "w")) == NULL) + return (herr("open", tfname, NULL)); + + rval = ht_enumerate(attrtab, locators_print, tfp); + + fflush(tfp); + if (ferror(tfp)) + return (herr("writ", tfname, NULL)); + if (fclose(tfp) == EOF) + return (herr("clos", tfname, NULL)); + if (rval) + return (rval); + return (moveifchanged(tfname, "locators.h")); +} + +/* + * Build the "ioconf.h" file with extern declarations for all configured + * cfdrivers. + */ +int +emitioconfh(void) +{ + const char *tfname; + FILE *tfp; + struct devbase *d; + struct devi *i; + + tfname = "tmp_ioconf.h"; + if ((tfp = fopen(tfname, "w")) == NULL) + return (herr("open", tfname, NULL)); + + fputs("\n/* pseudo-devices */\n", tfp); + TAILQ_FOREACH(i, &allpseudo, i_next) { + fprintf(tfp, "void %sattach(int);\n", + i->i_base->d_name); + } + + fputs("\n/* driver structs */\n", tfp); + TAILQ_FOREACH(d, &allbases, d_next) { + if (!devbase_has_instances(d, WILD)) + continue; + fprintf(tfp, "extern struct cfdriver %s_cd;\n", d->d_name); + } + + fflush(tfp); + if (ferror(tfp)) + return herr("writ", tfname, tfp); + + if (fclose(tfp) == EOF) + return (herr("clos", tfname, NULL)); + + return (moveifchanged(tfname, "ioconf.h")); +} + +/* + * Make a file that config_time.h can use as a source, if required. + */ +static int +emittime(void) +{ + FILE *fp; + time_t t; + struct tm *tm; + char buf[128]; + + t = time(NULL); + tm = gmtime(&t); + + if ((fp = fopen("config_time.src", "w")) == NULL) + return (herr("open", "config_time.src", NULL)); + + if (strftime(buf, sizeof(buf), "%c %Z", tm) == 0) + return (herr("strftime", "config_time.src", fp)); + + fprintf(fp, "/* %s */\n" + "#define CONFIG_TIME\t%2lld\n" + "#define CONFIG_YEAR\t%2d\n" + "#define CONFIG_MONTH\t%2d\n" + "#define CONFIG_DATE\t%2d\n" + "#define CONFIG_HOUR\t%2d\n" + "#define CONFIG_MINS\t%2d\n" + "#define CONFIG_SECS\t%2d\n", + buf, (long long)t, + tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, + tm->tm_hour, tm->tm_min, tm->tm_sec); + + fflush(fp); + if (ferror(fp)) + return (herr("fprintf", "config_time.src", fp)); + + if (fclose(fp) != 0) + return (herr("clos", "config_time.src", NULL)); + + /* + * *Don't* moveifchanged this file. Makefile.kern.inc will + * handle that if it determines such a move is necessary. + */ + return (0); +} + +/* + * Compare two files. If nfname doesn't exist, or is different from + * tfname, move tfname to nfname. Otherwise, delete tfname. + */ +int +moveifchanged(const char *tfname, const char *nfname) +{ + char tbuf[BUFSIZ], nbuf[BUFSIZ]; + FILE *tfp, *nfp; + + if ((tfp = fopen(tfname, "r")) == NULL) + return (herr("open", tfname, NULL)); + + if ((nfp = fopen(nfname, "r")) == NULL) + goto moveit; + + while (fgets(tbuf, sizeof(tbuf), tfp) != NULL) { + if (fgets(nbuf, sizeof(nbuf), nfp) == NULL) { + /* + * Old file has fewer lines. + */ + goto moveit; + } + if (strcmp(tbuf, nbuf) != 0) + goto moveit; + } + + /* + * We've reached the end of the new file. Check to see if new file + * has fewer lines than old. + */ + if (fgets(nbuf, sizeof(nbuf), nfp) != NULL) { + /* + * New file has fewer lines. + */ + goto moveit; + } + + (void) fclose(nfp); + (void) fclose(tfp); + if (remove(tfname) == -1) + return(herr("remov", tfname, NULL)); + return (0); + + moveit: + /* + * They're different, or the file doesn't exist. + */ + if (nfp) + (void) fclose(nfp); + if (tfp) + (void) fclose(tfp); + if (rename(tfname, nfname) == -1) + return (herr("renam", tfname, NULL)); + return (0); +} + +static int +herr(const char *what, const char *fname, FILE *fp) +{ + + warn("error %sing %s", what, fname); + if (fp) + (void)fclose(fp); + return (1); +} + +static char * +cntname(const char *src) +{ + char *dst; + char c; + static char buf[100]; + + dst = buf; + *dst++ = 'N'; + while ((c = *src++) != 0) + *dst++ = (char)(islower((u_char)c) ? toupper((u_char)c) : c); + *dst = 0; + return (buf); +} diff --git a/usr.bin/config/mkioconf.c b/usr.bin/config/mkioconf.c new file mode 100644 index 000000000..88333a34f --- /dev/null +++ b/usr.bin/config/mkioconf.c @@ -0,0 +1,510 @@ +/* $NetBSD: mkioconf.c,v 1.32 2015/09/03 13:53:36 uebayasi Exp $ */ + +/* + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Lawrence Berkeley Laboratories. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * from: @(#)mkioconf.c 8.1 (Berkeley) 6/6/93 + */ + +#if HAVE_NBTOOL_CONFIG_H +#include "nbtool_config.h" +#endif + +#include +__RCSID("$NetBSD: mkioconf.c,v 1.32 2015/09/03 13:53:36 uebayasi Exp $"); + +#include +#include +#include +#include +#include +#include +#include "defs.h" + +/* + * Make ioconf.c. + */ +static int cf_locators_print(const char *, void *, void *); +static int cforder(const void *, const void *); +static void emitcfdata(FILE *); +static void emitcfdrivers(FILE *); +static void emitexterns(FILE *); +static void emitcfattachinit(FILE *); +static void emithdr(FILE *); +static void emitloc(FILE *); +static void emitpseudo(FILE *); +static void emitparents(FILE *); +static void emitroots(FILE *); +static void emitname2blk(FILE *); + +#define SEP(pos, max) (((u_int)(pos) % (max)) == 0 ? "\n\t" : " ") + +#define ARRNAME(n, l) (strchr((n), ARRCHR) && strncmp((n), (l), strlen((l))) == 0) + +/* + * NEWLINE can only be used in the emitXXX functions. + * In most cases it can be subsumed into an fprintf. + */ +#define NEWLINE putc('\n', fp) + +int +mkioconf(void) +{ + FILE *fp; + + qsort(packed, npacked, sizeof *packed, cforder); + if ((fp = fopen("ioconf.c.tmp", "w")) == NULL) { + warn("cannot write ioconf.c"); + return (1); + } + + fprintf(fp, "#include \"ioconf.h\"\n"); + + emithdr(fp); + emitcfdrivers(fp); + emitexterns(fp); + emitloc(fp); + emitparents(fp); + emitcfdata(fp); + emitcfattachinit(fp); + + if (ioconfname == NULL) { + emitroots(fp); + emitpseudo(fp); + if (!do_devsw) + emitname2blk(fp); + } + + fflush(fp); + if (ferror(fp)) { + warn("error writing ioconf.c"); + (void)fclose(fp); +#if 0 + (void)unlink("ioconf.c.tmp"); +#endif + return (1); + } + + (void)fclose(fp); + if (moveifchanged("ioconf.c.tmp", "ioconf.c") != 0) { + warn("error renaming ioconf.c"); + return (1); + } + return (0); +} + +static int +cforder(const void *a, const void *b) +{ + int n1, n2; + + n1 = (*(const struct devi * const *)a)->i_cfindex; + n2 = (*(const struct devi * const *)b)->i_cfindex; + return (n1 - n2); +} + +static void +emithdr(FILE *ofp) +{ + FILE *ifp; + size_t n; + char ifnbuf[200], buf[BUFSIZ]; + char *ifn; + + autogen_comment(ofp, "ioconf.c"); + + (void)snprintf(ifnbuf, sizeof(ifnbuf), "%s/arch/%s/conf/ioconf.incl.%s", + srcdir, + machine ? machine : "(null)", machine ? machine : "(null)"); + ifn = ifnbuf; + if ((ifp = fopen(ifn, "r")) != NULL) { + while ((n = fread(buf, 1, sizeof(buf), ifp)) > 0) + (void)fwrite(buf, 1, n, ofp); + if (ferror(ifp)) + err(EXIT_FAILURE, "error reading %s", ifn); + (void)fclose(ifp); + } else { + fputs("#include \n" + "#include \n" + "#include \n" + "#include \n", ofp); + } +} + +/* + * Emit an initialized array of character strings describing this + * attribute's locators. + */ +static int +cf_locators_print(const char *name, void *value, void *arg) +{ + struct attr *a; + struct loclist *ll; + FILE *fp = arg; + + a = value; + if (!a->a_iattr) + return (0); + if (ht_lookup(selecttab, name) == NULL) + return (0); + + if (a->a_locs) { + fprintf(fp, + "static const struct cfiattrdata %scf_iattrdata = {\n", + name); + fprintf(fp, "\t\"%s\", %d, {\n", name, a->a_loclen); + for (ll = a->a_locs; ll; ll = ll->ll_next) + fprintf(fp, "\t\t{ \"%s\", \"%s\", %s },\n", + ll->ll_name, + (ll->ll_string ? ll->ll_string : "NULL"), + (ll->ll_string ? ll->ll_string : "0")); + fprintf(fp, "\t}\n};\n"); + } else { + fprintf(fp, + "static const struct cfiattrdata %scf_iattrdata = {\n" + "\t\"%s\", 0, {\n\t\t{ NULL, NULL, 0 },\n\t}\n};\n", + name, name); + } + + return 0; +} + +static void +emitcfdrivers(FILE *fp) +{ + struct devbase *d; + struct attrlist *al; + struct attr *a; + int has_iattrs; + + NEWLINE; + ht_enumerate(attrtab, cf_locators_print, fp); + + NEWLINE; + TAILQ_FOREACH(d, &allbases, d_next) { + if (!devbase_has_instances(d, WILD)) + continue; + has_iattrs = 0; + for (al = d->d_attrs; al != NULL; al = al->al_next) { + a = al->al_this; + if (a->a_iattr == 0) + continue; + if (has_iattrs == 0) + fprintf(fp, + "static const struct cfiattrdata * const %s_attrs[] = { ", + d->d_name); + has_iattrs = 1; + fprintf(fp, "&%scf_iattrdata, ", a->a_name); + } + if (has_iattrs) + fprintf(fp, "NULL };\n"); + fprintf(fp, "CFDRIVER_DECL(%s, %s, ", d->d_name, /* ) */ + d->d_classattr != NULL ? d->d_classattr->a_devclass + : "DV_DULL"); + if (has_iattrs) + fprintf(fp, "%s_attrs", d->d_name); + else + fprintf(fp, "NULL"); + fprintf(fp, /* ( */ ");\n\n"); + } + + NEWLINE; + + fprintf(fp, + "%sstruct cfdriver * const cfdriver_%s_%s[] = {\n", + ioconfname ? "static " : "", + ioconfname ? "ioconf" : "list", + ioconfname ? ioconfname : "initial"); + + TAILQ_FOREACH(d, &allbases, d_next) { + if (!devbase_has_instances(d, WILD)) + continue; + fprintf(fp, "\t&%s_cd,\n", d->d_name); + } + fprintf(fp, "\tNULL\n};\n"); +} + +static void +emitexterns(FILE *fp) +{ + struct deva *da; + + NEWLINE; + TAILQ_FOREACH(da, &alldevas, d_next) { + if (!deva_has_instances(da, WILD)) + continue; + fprintf(fp, "extern struct cfattach %s_ca;\n", + da->d_name); + } +} + +static void +emitcfattachinit(FILE *fp) +{ + struct devbase *d; + struct deva *da; + + NEWLINE; + TAILQ_FOREACH(d, &allbases, d_next) { + if (!devbase_has_instances(d, WILD)) + continue; + if (d->d_ahead == NULL) + continue; + + fprintf(fp, + "static struct cfattach * const %s_cfattachinit[] = {\n\t", + d->d_name); + for (da = d->d_ahead; da != NULL; da = da->d_bsame) { + if (!deva_has_instances(da, WILD)) + continue; + fprintf(fp, "&%s_ca, ", da->d_name); + } + fprintf(fp, "NULL\n};\n"); + } + + NEWLINE; + fprintf(fp, "%sconst struct cfattachinit cfattach%s%s[] = {\n", + ioconfname ? "static " : "", + ioconfname ? "_ioconf_" : "init", + ioconfname ? ioconfname : ""); + + TAILQ_FOREACH(d, &allbases, d_next) { + if (!devbase_has_instances(d, WILD)) + continue; + if (d->d_ahead == NULL) + continue; + + fprintf(fp, "\t{ \"%s\", %s_cfattachinit },\n", + d->d_name, d->d_name); + } + + fprintf(fp, "\t{ NULL, NULL }\n};\n"); +} + +static void +emitloc(FILE *fp) +{ + int i; + + if (locators.used != 0) { + fprintf(fp, "\n/* locators */\n" + "static int loc[%d] = {", locators.used); + for (i = 0; i < locators.used; i++) + fprintf(fp, "%s%s,", SEP(i, 8), locators.vec[i]); + fprintf(fp, "\n};\n"); + } +} + +/* + * Emit static parent data. + */ +static void +emitparents(FILE *fp) +{ + struct pspec *p; + + NEWLINE; + TAILQ_FOREACH(p, &allpspecs, p_list) { + if (p->p_devs == NULL || p->p_active != DEVI_ACTIVE) + continue; + fprintf(fp, + "static const struct cfparent pspec%d = {\n", p->p_inst); + fprintf(fp, "\t\"%s\", ", p->p_iattr->a_name); + if (p->p_atdev != NULL) { + fprintf(fp, "\"%s\", ", p->p_atdev->d_name); + if (p->p_atunit == WILD) + fprintf(fp, "DVUNIT_ANY"); + else + fprintf(fp, "%d", p->p_atunit); + } else + fprintf(fp, "NULL, 0"); + fprintf(fp, "\n};\n"); + } +} + +/* + * Emit the cfdata array. + */ +static void +emitcfdata(FILE *fp) +{ + struct devi **p, *i; + struct pspec *ps; + int unit, v; + const char *state, *basename, *attachment; + struct loclist *ll; + struct attr *a; + const char *loc; + char locbuf[20]; + const char *lastname = ""; + + fprintf(fp, "\n" + "#define NORM FSTATE_NOTFOUND\n" + "#define STAR FSTATE_STAR\n" + "\n" + "%sstruct cfdata cfdata%s%s[] = {\n" + " /* driver attachment unit state " + " loc flags pspec */\n", + ioconfname ? "static " : "", + ioconfname ? "_ioconf_" : "", + ioconfname ? ioconfname : ""); + for (p = packed; (i = *p) != NULL; p++) { + /* the description */ + fprintf(fp, "/*%3d: %s at ", i->i_cfindex, i->i_name); + if ((ps = i->i_pspec) != NULL) { + if (ps->p_atdev != NULL && + ps->p_atunit != WILD) { + fprintf(fp, "%s%d", ps->p_atdev->d_name, + ps->p_atunit); + } else if (ps->p_atdev != NULL) { + fprintf(fp, "%s?", ps->p_atdev->d_name); + } else { + fprintf(fp, "%s?", ps->p_iattr->a_name); + } + + a = ps->p_iattr; + for (ll = a->a_locs, v = 0; ll != NULL; + ll = ll->ll_next, v++) { + if (ARRNAME(ll->ll_name, lastname)) { + fprintf(fp, " %s %s", + ll->ll_name, i->i_locs[v]); + } else { + fprintf(fp, " %s %s", + ll->ll_name, + i->i_locs[v]); + lastname = ll->ll_name; + } + } + } else { + a = NULL; + fputs("root", fp); + } + + fputs(" */\n", fp); + + /* then the actual defining line */ + basename = i->i_base->d_name; + attachment = i->i_atdeva->d_name; + if (i->i_unit == STAR) { + unit = i->i_base->d_umax; + state = "STAR"; + } else { + unit = i->i_unit; + state = "NORM"; + } + if (i->i_locoff >= 0) { + (void)snprintf(locbuf, sizeof(locbuf), "loc+%3d", + i->i_locoff); + loc = locbuf; + } else + loc = "NULL"; + fprintf(fp, " { \"%s\",%s\"%s\",%s%2d, %s, %7s, %#6x, ", + basename, strlen(basename) < 7 ? "\t\t" + : "\t", + attachment, strlen(attachment) < 5 ? "\t\t" + : "\t", + unit, state, loc, i->i_cfflags); + if (ps != NULL) + fprintf(fp, "&pspec%d },\n", ps->p_inst); + else + fputs("NULL },\n", fp); + } + fprintf(fp, " { %s,%s%s,%s%2d, %s, %7s, %#6x, %s }\n};\n", + "NULL", "\t\t", "NULL", "\t\t", 0, " 0", "NULL", 0, "NULL"); +} + +/* + * Emit the table of potential roots. + */ +static void +emitroots(FILE *fp) +{ + struct devi **p, *i; + + fputs("\nconst short cfroots[] = {\n", fp); + for (p = packed; (i = *p) != NULL; p++) { + if (i->i_at != NULL) + continue; + if (i->i_unit != 0 && + (i->i_unit != STAR || i->i_base->d_umax != 0)) + warnx("warning: `%s at root' is not unit 0", i->i_name); + fprintf(fp, "\t%2d /* %s */,\n", + i->i_cfindex, i->i_name); + } + fputs("\t-1\n};\n", fp); +} + +/* + * Emit pseudo-device initialization. + */ +static void +emitpseudo(FILE *fp) +{ + struct devi *i; + struct devbase *d; + + fputs("\n/* pseudo-devices */\n", fp); + fputs("\nconst struct pdevinit pdevinit[] = {\n", fp); + TAILQ_FOREACH(i, &allpseudo, i_next) { + d = i->i_base; + fprintf(fp, "\t{ %sattach, %d },\n", + d->d_name, d->d_umax); + } + fputs("\t{ 0, 0 }\n};\n", fp); +} + +/* + * Emit name to major block number table. + */ +void +emitname2blk(FILE *fp) +{ + struct devbase *dev; + + fputs("\n/* device name to major block number */\n", fp); + + fprintf(fp, "struct devnametobdevmaj dev_name2blk[] = {\n"); + + TAILQ_FOREACH(dev, &allbases, d_next) { + if (dev->d_major == NODEVMAJOR) + continue; + + fprintf(fp, "\t{ \"%s\", %d },\n", + dev->d_name, dev->d_major); + } + fprintf(fp, "\t{ NULL, 0 }\n};\n"); +} diff --git a/usr.bin/config/mkmakefile.c b/usr.bin/config/mkmakefile.c new file mode 100644 index 000000000..d848ef15a --- /dev/null +++ b/usr.bin/config/mkmakefile.c @@ -0,0 +1,598 @@ +/* $NetBSD: mkmakefile.c,v 1.68 2015/09/04 10:16:35 uebayasi Exp $ */ + +/* + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Lawrence Berkeley Laboratories. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * from: @(#)mkmakefile.c 8.1 (Berkeley) 6/6/93 + */ + +#if HAVE_NBTOOL_CONFIG_H +#include "nbtool_config.h" +#endif + +#include +__RCSID("$NetBSD: mkmakefile.c,v 1.68 2015/09/04 10:16:35 uebayasi Exp $"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include "defs.h" +#include "sem.h" + +/* + * Make the Makefile. + */ + +static void emitdefs(FILE *); +static void emitallfiles(FILE *); + +static void emitofiles(FILE *); +static void emitallkobjs(FILE *); +static int emitallkobjscb(const char *, void *, void *); +static void emitattrkobjs(FILE *); +static int emitattrkobjscb(const char *, void *, void *); +static void emitkobjs(FILE *); +static void emitcfiles(FILE *); +static void emitsfiles(FILE *); +static void emitrules(FILE *); +static void emitload(FILE *); +static void emitincludes(FILE *); +static void emitappmkoptions(FILE *); +static void emitsubs(FILE *, const char *, const char *, int); +static int selectopt(const char *, void *); + +int has_build_kernel; + +int +mkmakefile(void) +{ + FILE *ifp, *ofp; + int lineno; + void (*fn)(FILE *); + char line[BUFSIZ], ifname[200]; + + /* + * Check if conf/Makefile.kern.inc defines "build_kernel". + * + * (This is usually done by checking "version" in sys/conf/files; + * unfortunately the "build_kernel" change done around 2014 Aug didn't + * bump that version. Thus this hack.) + */ + (void)snprintf(ifname, sizeof(ifname), "%s/conf/Makefile.kern.inc", + srcdir); + if ((ifp = fopen(ifname, "r")) == NULL) { + warn("cannot read %s", ifname); + goto bad2; + } + while (fgets(line, sizeof(line), ifp) != NULL) { + if (strncmp(line, "build_kernel:", 13) == 0) { + has_build_kernel = 1; + break; + } + } + (void)fclose(ifp); + + /* + * Try a makefile for the port first. + */ + (void)snprintf(ifname, sizeof(ifname), "%s/arch/%s/conf/Makefile.%s", + srcdir, machine, machine); + if ((ifp = fopen(ifname, "r")) == NULL) { + /* + * Try a makefile for the architecture second. + */ + (void)snprintf(ifname, sizeof(ifname), + "%s/arch/%s/conf/Makefile.%s", + srcdir, machinearch, machinearch); + ifp = fopen(ifname, "r"); + } + if (ifp == NULL) { + warn("cannot read %s", ifname); + goto bad2; + } + + if ((ofp = fopen("Makefile.tmp", "w")) == NULL) { + warn("cannot write Makefile"); + goto bad1; + } + + emitdefs(ofp); + + lineno = 0; + while (fgets(line, sizeof(line), ifp) != NULL) { + lineno++; + if ((version < 20090214 && line[0] != '%') || line[0] == '#') { + fputs(line, ofp); + continue; + } + if (strcmp(line, "%OBJS\n") == 0) + fn = Mflag ? emitkobjs : emitofiles; + else if (strcmp(line, "%CFILES\n") == 0) + fn = emitcfiles; + else if (strcmp(line, "%SFILES\n") == 0) + fn = emitsfiles; + else if (strcmp(line, "%RULES\n") == 0) + fn = emitrules; + else if (strcmp(line, "%LOAD\n") == 0) + fn = emitload; + else if (strcmp(line, "%INCLUDES\n") == 0) + fn = emitincludes; + else if (strcmp(line, "%MAKEOPTIONSAPPEND\n") == 0) + fn = emitappmkoptions; + else if (strncmp(line, "%VERSION ", sizeof("%VERSION ")-1) == 0) { + int newvers; + if (sscanf(line, "%%VERSION %d\n", &newvers) != 1) { + cfgxerror(ifname, lineno, "syntax error for " + "%%VERSION"); + } else + setversion(newvers); + continue; + } else { + if (version < 20090214) + cfgxerror(ifname, lineno, + "unknown %% construct ignored: %s", line); + else + emitsubs(ofp, line, ifname, lineno); + continue; + } + (*fn)(ofp); + } + + fflush(ofp); + if (ferror(ofp)) + goto wrerror; + + if (ferror(ifp)) { + warn("error reading %s (at line %d)", ifname, lineno); + goto bad; + } + + if (fclose(ofp)) { + ofp = NULL; + goto wrerror; + } + (void)fclose(ifp); + + if (moveifchanged("Makefile.tmp", "Makefile") != 0) { + warn("error renaming Makefile"); + goto bad2; + } + return (0); + + wrerror: + warn("error writing Makefile"); + bad: + if (ofp != NULL) + (void)fclose(ofp); + bad1: + (void)fclose(ifp); + /* (void)unlink("Makefile.tmp"); */ + bad2: + return (1); +} + +static void +emitsubs(FILE *fp, const char *line, const char *file, int lineno) +{ + char *nextpct; + const char *optname; + struct nvlist *option; + + while (*line != '\0') { + if (*line != '%') { + fputc(*line++, fp); + continue; + } + + line++; + nextpct = strchr(line, '%'); + if (nextpct == NULL) { + cfgxerror(file, lineno, "unbalanced %% or " + "unknown construct"); + return; + } + *nextpct = '\0'; + + if (*line == '\0') + fputc('%', fp); + else { + optname = intern(line); + if (!DEFINED_OPTION(optname)) { + cfgxerror(file, lineno, "unknown option %s", + optname); + return; + } + + if ((option = ht_lookup(opttab, optname)) == NULL) + option = ht_lookup(fsopttab, optname); + if (option != NULL) + fputs(option->nv_str ? option->nv_str : "1", + fp); + /* + * Otherwise it's not a selected option and we don't + * output anything. + */ + } + + line = nextpct + 1; + } +} + +static void +emitdefs(FILE *fp) +{ + struct nvlist *nv; + + fprintf(fp, "KERNEL_BUILD=%s\n", conffile); + fputs("IDENT= \\\n", fp); + for (nv = options; nv != NULL; nv = nv->nv_next) { + + /* Skip any options output to a header file */ + if (DEFINED_OPTION(nv->nv_name)) + continue; + const char *s = nv->nv_str; + fprintf(fp, "\t-D%s%s%s%s \\\n", nv->nv_name, + s ? "=\"" : "", + s ? s : "", + s ? "\"" : ""); + } + putc('\n', fp); + fprintf(fp, "MACHINE=%s\n", machine); + + const char *subdir = ""; + if (*srcdir != '/' && *srcdir != '.') { + /* + * libkern and libcompat "Makefile.inc"s want relative S + * specification to begin with '.'. + */ + subdir = "./"; + } + fprintf(fp, "S=\t%s%s\n", subdir, srcdir); + if (Sflag) { + fprintf(fp, ".PATH: $S\n"); + fprintf(fp, "___USE_SUFFIX_RULES___=1\n"); + } + for (nv = mkoptions; nv != NULL; nv = nv->nv_next) + fprintf(fp, "%s=%s\n", nv->nv_name, nv->nv_str); +} + +static void +emitfile(FILE *fp, struct files *fi) +{ + const char *defprologue = "$S/"; + const char *prologue, *prefix, *sep; + + if (Sflag) + defprologue = ""; + prologue = prefix = sep = ""; + if (*fi->fi_path != '/') { + prologue = defprologue; + if (fi->fi_prefix != NULL) { + if (*fi->fi_prefix == '/') + prologue = ""; + prefix = fi->fi_prefix; + sep = "/"; + } + } + fprintf(fp, "%s%s%s%s", prologue, prefix, sep, fi->fi_path); +} + +static void +emitfilerel(FILE *fp, struct files *fi) +{ + const char *prefix, *sep; + + prefix = sep = ""; + if (*fi->fi_path != '/') { + if (fi->fi_prefix != NULL) { + prefix = fi->fi_prefix; + sep = "/"; + } + } + fprintf(fp, "%s%s%s", prefix, sep, fi->fi_path); +} + +static void +emitofiles(FILE *fp) +{ + + emitallfiles(fp); + fprintf(fp, "#%%OFILES\n"); +} + +static void +emitkobjs(FILE *fp) +{ + emitallkobjs(fp); + emitattrkobjs(fp); +} + +static int emitallkobjsweighcb(const char *name, void *v, void *arg); +static void weighattr(struct attr *a); +static int attrcmp(const void *l, const void *r); + +struct attr **attrbuf; +size_t attridx; + +static void +emitallkobjs(FILE *fp) +{ + size_t i; + + attrbuf = emalloc(nattrs * sizeof(*attrbuf)); + + ht_enumerate(attrtab, emitallkobjsweighcb, NULL); + ht_enumerate(attrtab, emitallkobjscb, NULL); + qsort(attrbuf, attridx, sizeof(struct attr *), attrcmp); + + fputs("OBJS= \\\n", fp); + for (i = 0; i < attridx; i++) + fprintf(fp, "\t%s.ko \\\n", attrbuf[i]->a_name); + putc('\n', fp); + + free(attrbuf); +} + +static int +emitallkobjscb(const char *name, void *v, void *arg) +{ + struct attr *a = v; + + if (ht_lookup(selecttab, name) == NULL) + return 0; + if (TAILQ_EMPTY(&a->a_files)) + return 0; + attrbuf[attridx++] = a; + /* XXX nattrs tracking is not exact yet */ + if (attridx == nattrs) { + nattrs *= 2; + attrbuf = erealloc(attrbuf, nattrs * sizeof(*attrbuf)); + } + return 0; +} + +static int +emitallkobjsweighcb(const char *name, void *v, void *arg) +{ + struct attr *a = v; + + weighattr(a); + return 0; +} + +static void +weighattr(struct attr *a) +{ + struct attrlist *al; + + for (al = a->a_deps; al != NULL; al = al->al_next) { + weighattr(al->al_this); + } + a->a_weight++; +} + +static int +attrcmp(const void *l, const void *r) +{ + const struct attr * const *a = l, * const *b = r; + const int wa = (*a)->a_weight, wb = (*b)->a_weight; + return (wa > wb) ? -1 : (wa < wb) ? 1 : 0; +} + +static void +emitattrkobjs(FILE *fp) +{ + extern struct hashtab *attrtab; + + ht_enumerate(attrtab, emitattrkobjscb, fp); +} + +static int +emitattrkobjscb(const char *name, void *v, void *arg) +{ + struct attr *a = v; + struct files *fi; + FILE *fp = arg; + + if (ht_lookup(selecttab, name) == NULL) + return 0; + if (TAILQ_EMPTY(&a->a_files)) + return 0; + fputc('\n', fp); + fprintf(fp, "# %s (%d)\n", name, a->a_weight); + fprintf(fp, "OBJS.%s= \\\n", name); + TAILQ_FOREACH(fi, &a->a_files, fi_anext) { + fprintf(fp, "\t%s.o \\\n", fi->fi_base); + } + fputc('\n', fp); + fprintf(fp, "%s.ko: ${OBJS.%s}\n", name, name); + fprintf(fp, "\t${LINK_O}\n"); + return 0; +} + +static void +emitcfiles(FILE *fp) +{ + + emitallfiles(fp); + fprintf(fp, "#%%CFILES\n"); +} + +static void +emitsfiles(FILE *fp) +{ + + emitallfiles(fp); + fprintf(fp, "#%%SFILES\n"); +} + +static void +emitallfiles(FILE *fp) +{ + struct files *fi; + static int called; + int i; + int found = 0; + + if (called++ != 0) + return; + for (i = 0; i < (int)nselfiles; i++) { + fi = selfiles[i]; + if (found++ == 0) + fprintf(fp, "ALLFILES= \\\n"); + putc('\t', fp); + emitfilerel(fp, fi); + fputs(" \\\n", fp); + } + fputc('\n', fp); +} + +/* + * Emit the make-rules. + */ +static void +emitrules(FILE *fp) +{ + struct files *fi; + int i; + int found = 0; + + for (i = 0; i < (int)nselfiles; i++) { + fi = selfiles[i]; + if (fi->fi_mkrule == NULL) + continue; + fprintf(fp, "%s.o: ", fi->fi_base); + emitfile(fp, fi); + putc('\n', fp); + fprintf(fp, "\t%s\n\n", fi->fi_mkrule); + found++; + } + if (found == 0) + fprintf(fp, "#%%RULES\n"); +} + +/* + * Emit the load commands. + * + * This function is not to be called `spurt'. + */ +static void +emitload(FILE *fp) +{ + struct config *cf; + int found = 0; + + /* + * Generate the backward-compatible "build_kernel" rule if + * sys/conf/Makefile.kern.inc doesn't define any (pre-2014 Aug). + */ + if (has_build_kernel == 0) { + fprintf(fp, "build_kernel: .USE\n" + "\t${SYSTEM_LD_HEAD}\n" + "\t${SYSTEM_LD}%s\n" + "\t${SYSTEM_LD_TAIL}\n" + "\n", + Sflag ? "" : " swap${.TARGET}.o"); + } + /* + * Generate per-kernel rules. + */ + TAILQ_FOREACH(cf, &allcf, cf_next) { + char swapobj[100]; + + if (Sflag) { + swapobj[0] = '\0'; + } else { + (void)snprintf(swapobj, sizeof(swapobj), " swap%s.o", + cf->cf_name); + } + fprintf(fp, "KERNELS+=%s\n", cf->cf_name); + found = 1; + } + if (found == 0) + fprintf(fp, "#%%LOAD\n"); +} + +/* + * Emit include headers (for any prefixes encountered) + */ +static void +emitincludes(FILE *fp) +{ + struct prefix *pf; + + SLIST_FOREACH(pf, &allprefixes, pf_next) { + const char *prologue = (*pf->pf_prefix == '/') ? "" : "$S/"; + + fprintf(fp, "EXTRA_INCLUDES+=\t-I%s%s\n", + prologue, pf->pf_prefix); + } +} + +/* + * Emit appending makeoptions. + */ +static void +emitappmkoptions(FILE *fp) +{ + struct nvlist *nv; + struct condexpr *cond; + + for (nv = appmkoptions; nv != NULL; nv = nv->nv_next) + fprintf(fp, "%s+=%s\n", nv->nv_name, nv->nv_str); + + for (nv = condmkoptions; nv != NULL; nv = nv->nv_next) { + cond = nv->nv_ptr; + if (expr_eval(cond, selectopt, NULL)) + fprintf(fp, "%s+=%s\n", nv->nv_name, nv->nv_str); + condexpr_destroy(cond); + nv->nv_ptr = NULL; + } +} + +static int +/*ARGSUSED*/ +selectopt(const char *name, void *context) +{ + + return (ht_lookup(selecttab, strtolower(name)) != NULL); +} diff --git a/usr.bin/config/mkswap.c b/usr.bin/config/mkswap.c new file mode 100644 index 000000000..37c8a8957 --- /dev/null +++ b/usr.bin/config/mkswap.c @@ -0,0 +1,164 @@ +/* $NetBSD: mkswap.c,v 1.10 2015/09/03 13:53:36 uebayasi Exp $ */ + +/* + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Lawrence Berkeley Laboratories. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * from: @(#)mkswap.c 8.1 (Berkeley) 6/6/93 + */ + +#if HAVE_NBTOOL_CONFIG_H +#include "nbtool_config.h" +#endif + +#include +__RCSID("$NetBSD: mkswap.c,v 1.10 2015/09/03 13:53:36 uebayasi Exp $"); + +#include +#include +#include +#include +#include +#include +#include "defs.h" +#include "sem.h" + +static char *mkdevstr(dev_t); +static int mkoneswap(struct config *); + +/* + * Make the various swap*.c files. Nothing to do for generic swap. + */ +int +mkswap(void) +{ + struct config *cf; + + TAILQ_FOREACH(cf, &allcf, cf_next) { + if (mkoneswap(cf)) + return (1); + } + return (0); +} + +static char * +mkdevstr(dev_t d) +{ + static char buf[32]; + + if (d == NODEV) + (void)snprintf(buf, sizeof(buf), "NODEV"); + else + (void)snprintf(buf, sizeof(buf), "makedev(%d, %d)", + major(d), minor(d)); + return buf; +} + +static int +mkoneswap(struct config *cf) +{ + struct nvlist *nv; + FILE *fp; + char fname[200], tname[200]; + char specinfo[200]; + + (void)snprintf(fname, sizeof(fname), "swap%s.c", cf->cf_name); + (void)snprintf(tname, sizeof(tname), "swap%s.c.tmp", cf->cf_name); + if ((fp = fopen(tname, "w")) == NULL) { + warn("cannot open %s", fname); + return (1); + } + + autogen_comment(fp, fname); + + fputs("#include \n" + "#include \n\n", fp); + /* + * Emit the root device. + */ + nv = cf->cf_root; + if (cf->cf_root->nv_str == s_qmark) + strlcpy(specinfo, "NULL", sizeof(specinfo)); + else + snprintf(specinfo, sizeof(specinfo), "\"%s\"", + cf->cf_root->nv_str); + fprintf(fp, "const char *rootspec = %s;\n", specinfo); + fprintf(fp, "dev_t\trootdev = %s;\t/* %s */\n\n", + mkdevstr((dev_t)nv->nv_num), + nv->nv_str == s_qmark ? "wildcarded" : nv->nv_str); + + /* + * Emit the dump device. + */ + nv = cf->cf_dump; + if (cf->cf_dump == NULL) + strlcpy(specinfo, "NULL", sizeof(specinfo)); + else + snprintf(specinfo, sizeof(specinfo), "\"%s\"", cf->cf_dump->nv_str); + fprintf(fp, "const char *dumpspec = %s;\n", specinfo); + fprintf(fp, "dev_t\tdumpdev = %s;\t/* %s */\n\n", + nv ? mkdevstr((dev_t)nv->nv_num) : "NODEV", + nv ? nv->nv_str : "unspecified"); + + /* + * Emit the root file system. + */ + fprintf(fp, "const char *rootfstype = \"%s\";\n", + cf->cf_fstype ? cf->cf_fstype : "?"); + + fflush(fp); + if (ferror(fp)) + goto wrerror; + + if (fclose(fp)) { + fp = NULL; + goto wrerror; + } + if (moveifchanged(tname, fname) != 0) { + warn("error renaming %s", fname); + return (1); + } + return (0); + + wrerror: + warn("error writing %s", fname); + if (fp != NULL) + (void)fclose(fp); +#if 0 + (void)unlink(fname); +#endif + return (1); +} diff --git a/usr.bin/config/pack.c b/usr.bin/config/pack.c new file mode 100644 index 000000000..f227aa3b3 --- /dev/null +++ b/usr.bin/config/pack.c @@ -0,0 +1,352 @@ +/* $NetBSD: pack.c,v 1.10 2015/09/12 19:11:13 joerg Exp $ */ + +/* + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Lawrence Berkeley Laboratories. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * from: @(#)pack.c 8.1 (Berkeley) 6/6/93 + */ + +#if HAVE_NBTOOL_CONFIG_H +#include "nbtool_config.h" +#endif + +#include +__RCSID("$NetBSD: pack.c,v 1.10 2015/09/12 19:11:13 joerg Exp $"); + +#include +#include +#include +#include +#include "defs.h" + +/* + * Packing. We have three separate kinds of packing here. + * + * First, we pack device instances which have identical parent specs. + * + * Second, we pack locators. Given something like + * + * hp0 at mba0 drive 0 + * hp* at mba* drive ? + * ht0 at mba0 drive 0 + * tu0 at ht0 slave 0 + * ht* at mba* drive ? + * tu* at ht* slave ? + * + * (where the default drive and slave numbers are -1), we have three + * locators whose value is 0 and three whose value is -1. Rather than + * emitting six integers, we emit just two. + * + * When packing locators, we would like to find sequences such as + * {1 2 3} {2 3 4} {3} {4 5} + * and turn this into the flat sequence {1 2 3 4 5}, with each subsequence + * given by the appropriate offset (here 0, 1, 2, and 3 respectively). + * Non-overlapping packing is much easier, and so we use that here + * and miss out on the chance to squeeze the locator sequence optimally. + * (So it goes.) + */ + +typedef int (*vec_cmp_func)(const void *, int, int); + +#define TAILHSIZE 128 +#define PVHASH(i) ((i) & (TAILHSIZE - 1)) +#define LOCHASH(l) (((long)(l) >> 2) & (TAILHSIZE - 1)) +struct tails { + struct tails *t_next; + int t_ends_at; +}; + +static struct tails *tails[TAILHSIZE]; +static int locspace; + +static void packdevi(void); +static void packlocs(void); + +static int sameas(struct devi *, struct devi *); +static int findvec(const void *, int, int, vec_cmp_func, int); +static int samelocs(const void *, int, int); +static int addlocs(const char **, int); +static int loclencmp(const void *, const void *); +static void resettails(void); + +void +pack(void) +{ + struct pspec *p; + struct devi *i; + + /* Pack instances and make parent vectors. */ + packdevi(); + + /* + * Now that we know what we have, find upper limits on space + * needed for the loc[] table. The loc table size is bounded by + * what we would get if no packing occurred. + */ + locspace = 0; + TAILQ_FOREACH(i, &alldevi, i_next) { + if (i->i_active != DEVI_ACTIVE || i->i_collapsed) + continue; + if ((p = i->i_pspec) == NULL) + continue; + locspace += p->p_iattr->a_loclen; + } + + /* Allocate and pack loc[]. */ + locators.vec = ecalloc((size_t)locspace, sizeof(*locators.vec)); + locators.used = 0; + packlocs(); +} + +/* + * Pack device instances together wherever possible. + */ +static void +packdevi(void) +{ + struct devi *firststar, *i, **ip, *l, *p; + struct devbase *d; + u_short j, m, n; + + /* + * Sort all the cloning units to after the non-cloning units, + * preserving order of cloning and non-cloning units with + * respect to other units of the same type. + * + * Algorithm: Walk down the list until the first cloning unit is + * seen for the second time (or until the end of the list, if there + * are no cloning units on the list), moving starred units to the + * end of the list. + */ + TAILQ_FOREACH(d, &allbases, d_next) { + ip = &d->d_ihead; + firststar = NULL; + + for (i = *ip; i != firststar; i = *ip) { + if (i->i_unit != STAR) { + /* try i->i_bsame next */ + ip = &i->i_bsame; + } else { + if (firststar == NULL) + firststar = i; + + *d->d_ipp = i; + d->d_ipp = &i->i_bsame; + + *ip = i->i_bsame; + i->i_bsame = NULL; + + /* leave ip alone; try (old) i->i_bsame next */ + } + } + } + + packed = ecalloc((size_t)ndevi + 1, sizeof *packed); + n = 0; + TAILQ_FOREACH(d, &allbases, d_next) { + /* + * For each instance of each device, add or collapse + * all its aliases. + * + * Pseudo-devices have a non-empty d_ihead for convenience. + * Ignore them. + */ + if (d->d_ispseudo) + continue; + for (i = d->d_ihead; i != NULL; i = i->i_bsame) { + m = n; + for (l = i; l != NULL; l = l->i_alias) { + if (l->i_active != DEVI_ACTIVE + || i->i_pseudoroot) + continue; + l->i_locoff = -1; + /* try to find an equivalent for l */ + for (j = m; j < n; j++) { + p = packed[j]; + if (sameas(l, p)) { + l->i_collapsed = 1; + l->i_cfindex = p->i_cfindex; + goto nextalias; + } + } + /* could not find a suitable alias */ + l->i_collapsed = 0; + l->i_cfindex = n; + packed[n++] = l; + nextalias:; + } + } + } + npacked = n; + packed[n] = NULL; +} + +/* + * Return true if two aliases are "the same". In this case, they need + * to have the same parent spec, have the same config flags, and have + * the same locators. + */ +static int +sameas(struct devi *i1, struct devi *i2) +{ + const char **p1, **p2; + + if (i1->i_pspec != i2->i_pspec) + return (0); + if (i1->i_cfflags != i2->i_cfflags) + return (0); + for (p1 = i1->i_locs, p2 = i2->i_locs; *p1 == *p2; p2++) + if (*p1++ == 0) + return (1); + return (0); +} + +static void +packlocs(void) +{ + struct pspec *ps; + struct devi **p, *i; + int l,o; + extern int Pflag; + + qsort(packed, npacked, sizeof *packed, loclencmp); + for (p = packed; (i = *p) != NULL; p++) { + if ((ps = i->i_pspec) != NULL && + (l = ps->p_iattr->a_loclen) > 0) { + if (Pflag) { + o = findvec(i->i_locs, + LOCHASH(i->i_locs[l - 1]), l, + samelocs, locators.used); + i->i_locoff = o < 0 ? + addlocs(i->i_locs, l) : o; + } else + i->i_locoff = addlocs(i->i_locs, l); + } else + i->i_locoff = -1; + } + resettails(); +} + +/* + * Return the index at which the given vector already exists, or -1 + * if it is not anywhere in the current set. If we return -1, we assume + * our caller will add it at the end of the current set, and we make + * sure that next time, we will find it there. + */ +static int +findvec(const void *ptr, int hash, int len, vec_cmp_func cmp, int nextplace) +{ + struct tails *t, **hp; + int off; + + hp = &tails[hash]; + for (t = *hp; t != NULL; t = t->t_next) { + off = t->t_ends_at - len; + if (off >= 0 && (*cmp)(ptr, off, len)) + return (off); + } + t = ecalloc(1, sizeof(*t)); + t->t_next = *hp; + *hp = t; + t->t_ends_at = nextplace + len; + return (-1); +} + +/* + * Comparison function for locators. + */ +static int +samelocs(const void *ptr, int off, int len) +{ + const char * const *p, * const *q; + + for (p = &locators.vec[off], q = (const char * const *)ptr; --len >= 0;) + if (*p++ != *q++) + return (0); /* different */ + return (1); /* same */ +} + +/* + * Add the given locators at the end of the global loc[] table. + */ +static int +addlocs(const char **locs, int len) +{ + const char **p; + int ret; + + ret = locators.used; + if ((locators.used = ret + len) > locspace) + panic("addlocs: overrun"); + for (p = &locators.vec[ret]; --len >= 0;) + *p++ = *locs++; + return (ret); +} + +/* + * Comparison function for qsort-by-locator-length, longest first. + * We rashly assume that subtraction of these lengths does not overflow. + */ +static int +loclencmp(const void *a, const void *b) +{ + const struct pspec *p1, *p2; + int l1, l2; + + p1 = (*(const struct devi * const *)a)->i_pspec; + l1 = p1 != NULL ? p1->p_iattr->a_loclen : 0; + + p2 = (*(const struct devi * const *)b)->i_pspec; + l2 = p2 != NULL ? p2->p_iattr->a_loclen : 0; + + return (l2 - l1); +} + +static void +resettails(void) +{ + struct tails **p, *t, *next; + int i; + + for (p = tails, i = TAILHSIZE; --i >= 0; p++) { + for (t = *p; t != NULL; t = next) { + next = t->t_next; + free(t); + } + *p = NULL; + } +} diff --git a/usr.bin/config/scan.c b/usr.bin/config/scan.c new file mode 100644 index 000000000..db205dee8 --- /dev/null +++ b/usr.bin/config/scan.c @@ -0,0 +1,3094 @@ +#line 2 "scan.c" + +#line 4 "scan.c" + +#define YY_INT_ALIGNED short int + +/* A lexical scanner generated by flex */ + +#define FLEX_SCANNER +#define YY_FLEX_MAJOR_VERSION 2 +#define YY_FLEX_MINOR_VERSION 5 +#define YY_FLEX_SUBMINOR_VERSION 35 +#if YY_FLEX_SUBMINOR_VERSION > 0 +#define FLEX_BETA +#endif + +/* First, we deal with platform-specific or compiler-specific issues. */ + +/* begin standard C headers. */ +#ifdef _LIBC +#include "namespace.h" +#endif +#include +#include +#include +#include + +/* end standard C headers. */ + +/* $NetBSD: flexint.h,v 1.2 2014/10/29 18:28:36 christos Exp $ */ + +/* flex integer type definitions */ + +#ifndef FLEXINT_H +#define FLEXINT_H + +/* C99 systems have . Non-C99 systems may or may not. */ + +#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L + +/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h, + * if you want the limit (max/min) macros for int types. + */ +#ifndef __STDC_LIMIT_MACROS +#define __STDC_LIMIT_MACROS 1 +#endif + +#include +typedef int8_t flex_int8_t; +typedef uint8_t flex_uint8_t; +typedef int16_t flex_int16_t; +typedef uint16_t flex_uint16_t; +typedef int32_t flex_int32_t; +typedef uint32_t flex_uint32_t; +#else +typedef signed char flex_int8_t; +typedef short int flex_int16_t; +typedef int flex_int32_t; +typedef unsigned char flex_uint8_t; +typedef unsigned short int flex_uint16_t; +typedef unsigned int flex_uint32_t; + +/* Limits of integral types. */ +#ifndef INT8_MIN +#define INT8_MIN (-128) +#endif +#ifndef INT16_MIN +#define INT16_MIN (-32767-1) +#endif +#ifndef INT32_MIN +#define INT32_MIN (-2147483647-1) +#endif +#ifndef INT8_MAX +#define INT8_MAX (127) +#endif +#ifndef INT16_MAX +#define INT16_MAX (32767) +#endif +#ifndef INT32_MAX +#define INT32_MAX (2147483647) +#endif +#ifndef UINT8_MAX +#define UINT8_MAX (255U) +#endif +#ifndef UINT16_MAX +#define UINT16_MAX (65535U) +#endif +#ifndef UINT32_MAX +#define UINT32_MAX (4294967295U) +#endif + +#endif /* ! C99 */ + +#endif /* ! FLEXINT_H */ + +#ifdef __cplusplus + +/* The "const" storage-class-modifier is valid. */ +#define YY_USE_CONST + +#else /* ! __cplusplus */ + +/* C99 requires __STDC__ to be defined as 1. */ +#if defined (__STDC__) + +#define YY_USE_CONST + +#endif /* defined (__STDC__) */ +#endif /* ! __cplusplus */ + +#ifdef YY_USE_CONST +#define yyconst const +#else +#define yyconst +#endif + +/* Returned upon end-of-file. */ +#define YY_NULL 0 + +/* Promotes a possibly negative, possibly signed char to an unsigned + * integer for use as an array index. If the signed char is negative, + * we want to instead treat it as an 8-bit unsigned char, hence the + * double cast. + */ +#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c) + +/* Enter a start condition. This macro really ought to take a parameter, + * but we do it the disgusting crufty way forced on us by the ()-less + * definition of BEGIN. + */ +#define BEGIN (yy_start) = 1 + 2 * + +/* Translate the current start state into a value that can be later handed + * to BEGIN to return to the state. The YYSTATE alias is for lex + * compatibility. + */ +#define YY_START (((yy_start) - 1) / 2) +#define YYSTATE YY_START + +/* Action number for EOF rule of a given start state. */ +#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) + +/* Special action meaning "start processing a new file". */ +#define YY_NEW_FILE yyrestart(yyin ) + +#define YY_END_OF_BUFFER_CHAR 0 + +/* Size of default input buffer. */ +#ifndef YY_BUF_SIZE +#define YY_BUF_SIZE 16384 +#endif + +/* The state buf must be large enough to hold one state per character in the main buffer. + */ +#define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type)) + +#ifndef YY_TYPEDEF_YY_BUFFER_STATE +#define YY_TYPEDEF_YY_BUFFER_STATE +typedef struct yy_buffer_state *YY_BUFFER_STATE; +#endif + +#ifndef YY_TYPEDEF_YY_SIZE_T +#define YY_TYPEDEF_YY_SIZE_T +typedef size_t yy_size_t; +#endif + +extern yy_size_t yyleng; + +extern FILE *yyin, *yyout; + +#define EOB_ACT_CONTINUE_SCAN 0 +#define EOB_ACT_END_OF_FILE 1 +#define EOB_ACT_LAST_MATCH 2 + + #define YY_LESS_LINENO(n) + #define YY_LINENO_REWIND_TO(ptr) + +/* Return all but the first "n" matched characters back to the input stream. */ +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + int yyless_macro_arg = (n); \ + YY_LESS_LINENO(yyless_macro_arg);\ + *yy_cp = (yy_hold_char); \ + YY_RESTORE_YY_MORE_OFFSET \ + (yy_c_buf_p) = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \ + YY_DO_BEFORE_ACTION; /* set up yytext again */ \ + } \ + while ( 0 ) + +#define unput(c) yyunput( c, (yytext_ptr) ) + +#ifndef YY_STRUCT_YY_BUFFER_STATE +#define YY_STRUCT_YY_BUFFER_STATE +struct yy_buffer_state + { + FILE *yy_input_file; + + char *yy_ch_buf; /* input buffer */ + char *yy_buf_pos; /* current position in input buffer */ + + /* Size of input buffer in bytes, not including room for EOB + * characters. + */ + yy_size_t yy_buf_size; + + /* Number of characters read into yy_ch_buf, not including EOB + * characters. + */ + yy_size_t yy_n_chars; + + /* Whether we "own" the buffer - i.e., we know we created it, + * and can realloc() it to grow it, and should free() it to + * delete it. + */ + int yy_is_our_buffer; + + /* Whether this is an "interactive" input source; if so, and + * if we're using stdio for input, then we want to use getc() + * instead of fread(), to make sure we stop fetching input after + * each newline. + */ + int yy_is_interactive; + + /* Whether we're considered to be at the beginning of a line. + * If so, '^' rules will be active on the next match, otherwise + * not. + */ + int yy_at_bol; + + int yy_bs_lineno; /**< The line count. */ + int yy_bs_column; /**< The column count. */ + + /* Whether to try to fill the input buffer when we reach the + * end of it. + */ + int yy_fill_buffer; + + int yy_buffer_status; + +#define YY_BUFFER_NEW 0 +#define YY_BUFFER_NORMAL 1 + /* When an EOF's been seen but there's still some text to process + * then we mark the buffer as YY_EOF_PENDING, to indicate that we + * shouldn't try reading from the input source any more. We might + * still have a bunch of tokens to match, though, because of + * possible backing-up. + * + * When we actually see the EOF, we change the status to "new" + * (via yyrestart()), so that the user can continue scanning by + * just pointing yyin at a new input file. + */ +#define YY_BUFFER_EOF_PENDING 2 + + }; +#endif /* !YY_STRUCT_YY_BUFFER_STATE */ + +/* Stack of input buffers. */ +static size_t yy_buffer_stack_top = 0; /**< index of top of stack. */ +static size_t yy_buffer_stack_max = 0; /**< capacity of stack. */ +static YY_BUFFER_STATE * yy_buffer_stack = 0; /**< Stack as an array. */ + +/* We provide macros for accessing buffer states in case in the + * future we want to put the buffer states in a more general + * "scanner state". + * + * Returns the top of the stack, or NULL. + */ +#define YY_CURRENT_BUFFER ( (yy_buffer_stack) \ + ? (yy_buffer_stack)[(yy_buffer_stack_top)] \ + : NULL) + +/* Same as previous macro, but useful when we know that the buffer stack is not + * NULL or when we need an lvalue. For internal use only. + */ +#define YY_CURRENT_BUFFER_LVALUE (yy_buffer_stack)[(yy_buffer_stack_top)] + +/* yy_hold_char holds the character lost when yytext is formed. */ +static char yy_hold_char; +static yy_size_t yy_n_chars; /* number of characters read into yy_ch_buf */ +yy_size_t yyleng; + +/* Points to current character in buffer. */ +static char *yy_c_buf_p = (char *) 0; +static int yy_init = 0; /* whether we need to initialize */ +static int yy_start = 0; /* start state number */ + +/* Flag which is used to allow yywrap()'s to do buffer switches + * instead of setting up a fresh yyin. A bit of a hack ... + */ +static int yy_did_buffer_switch_on_eof; + +void yyrestart (FILE *input_file ); +void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer ); +YY_BUFFER_STATE yy_create_buffer (FILE *file,int size ); +void yy_delete_buffer (YY_BUFFER_STATE b ); +void yy_flush_buffer (YY_BUFFER_STATE b ); +void yypush_buffer_state (YY_BUFFER_STATE new_buffer ); +void yypop_buffer_state (void ); + +static void yyensure_buffer_stack (void ); +static void yy_load_buffer_state (void ); +static void yy_init_buffer (YY_BUFFER_STATE b,FILE *file ); + +#define YY_FLUSH_BUFFER yy_flush_buffer(YY_CURRENT_BUFFER ) + +YY_BUFFER_STATE yy_scan_buffer (char *base,yy_size_t size ); +YY_BUFFER_STATE yy_scan_string (yyconst char *yy_str ); +YY_BUFFER_STATE yy_scan_bytes (yyconst char *bytes,yy_size_t len ); + +void *yyalloc (yy_size_t ); +void *yyrealloc (void *,yy_size_t ); +void yyfree (void * ); + +#define yy_new_buffer yy_create_buffer + +#define yy_set_interactive(is_interactive) \ + { \ + if ( ! YY_CURRENT_BUFFER ){ \ + yyensure_buffer_stack (); \ + YY_CURRENT_BUFFER_LVALUE = \ + yy_create_buffer(yyin,YY_BUF_SIZE ); \ + } \ + YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \ + } + +#define yy_set_bol(at_bol) \ + { \ + if ( ! YY_CURRENT_BUFFER ){\ + yyensure_buffer_stack (); \ + YY_CURRENT_BUFFER_LVALUE = \ + yy_create_buffer(yyin,YY_BUF_SIZE ); \ + } \ + YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \ + } + +#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol) + +/* Begin user sect3 */ + +#define yywrap() (/*CONSTCOND*/1) +#define YY_SKIP_YYWRAP + +typedef unsigned char YY_CHAR; + +FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0; + +typedef int yy_state_type; + +extern int yylineno; + +int yylineno = 1; + +extern char *yytext; +#define yytext_ptr yytext + +static yy_state_type yy_get_previous_state (void ); +static yy_state_type yy_try_NUL_trans (yy_state_type current_state ); +static int yy_get_next_buffer (void ); +#if defined(__GNUC__) && __GNUC__ >= 3 +__attribute__((__noreturn__)) +#endif +static void yy_fatal_error (yyconst char msg[] ); + +/* Done after the current pattern has been matched and before the + * corresponding action - sets up yytext. + */ +#define YY_DO_BEFORE_ACTION \ + (yytext_ptr) = yy_bp; \ + yyleng = (size_t) (yy_cp - yy_bp); \ + (yy_hold_char) = *yy_cp; \ + *yy_cp = '\0'; \ + (yy_c_buf_p) = yy_cp; + +#define YY_NUM_RULES 77 +#define YY_END_OF_BUFFER 78 +/* This struct is not used in this scanner, + but its presence is necessary. */ +struct yy_trans_info + { + flex_int32_t yy_verify; + flex_int32_t yy_nxt; + }; +static yyconst flex_int16_t yy_accept[437] = + { 0, + 0, 0, 0, 0, 78, 76, 75, 72, 76, 74, + 76, 64, 68, 70, 76, 65, 65, 65, 65, 65, + 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, + 65, 65, 65, 73, 60, 59, 60, 60, 75, 71, + 0, 66, 0, 74, 51, 64, 64, 68, 0, 0, + 70, 52, 65, 65, 65, 2, 65, 65, 65, 65, + 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, + 65, 65, 65, 65, 65, 34, 65, 37, 65, 65, + 65, 65, 65, 65, 65, 65, 65, 65, 65, 0, + 0, 0, 67, 69, 1, 65, 65, 65, 65, 65, + + 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, + 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, + 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, + 65, 65, 65, 65, 65, 65, 0, 0, 0, 0, + 0, 65, 65, 65, 6, 65, 65, 65, 65, 65, + 65, 65, 65, 65, 65, 65, 65, 65, 20, 65, + 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, + 65, 65, 65, 65, 65, 65, 65, 65, 65, 43, + 65, 65, 65, 47, 65, 65, 50, 0, 0, 0, + 0, 0, 65, 4, 5, 65, 65, 65, 65, 9, + + 65, 65, 65, 65, 65, 65, 19, 65, 65, 0, + 57, 0, 65, 65, 22, 23, 65, 65, 65, 65, + 65, 65, 27, 65, 65, 65, 31, 65, 65, 65, + 65, 65, 65, 65, 65, 65, 65, 65, 65, 0, + 0, 0, 0, 0, 3, 65, 65, 65, 8, 65, + 10, 12, 65, 65, 65, 17, 65, 65, 0, 0, + 58, 0, 65, 0, 65, 65, 24, 65, 65, 65, + 65, 65, 65, 35, 65, 65, 65, 39, 65, 44, + 45, 46, 48, 65, 0, 0, 0, 65, 65, 65, + 11, 65, 65, 65, 65, 65, 65, 0, 65, 0, + + 0, 65, 65, 26, 65, 65, 65, 65, 65, 65, + 38, 65, 65, 49, 0, 0, 65, 65, 65, 13, + 65, 16, 65, 0, 65, 65, 0, 53, 0, 0, + 0, 0, 25, 65, 65, 30, 65, 65, 36, 0, + 65, 65, 0, 65, 0, 65, 14, 65, 0, 0, + 65, 0, 0, 54, 0, 0, 0, 0, 0, 65, + 65, 65, 65, 0, 0, 0, 65, 65, 65, 0, + 0, 0, 65, 65, 65, 0, 55, 0, 0, 0, + 65, 0, 0, 0, 0, 0, 61, 0, 0, 65, + 65, 65, 33, 0, 0, 0, 0, 63, 0, 0, + + 65, 65, 40, 0, 0, 0, 0, 62, 0, 0, + 65, 65, 65, 0, 0, 56, 0, 0, 21, 0, + 28, 65, 32, 0, 65, 42, 0, 7, 15, 18, + 0, 65, 65, 29, 41, 0 + } ; + +static yyconst YY_CHAR yy_ec[256] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 2, 1, 4, 5, 1, 1, 1, 1, 1, + 1, 1, 6, 1, 7, 8, 8, 9, 10, 10, + 10, 10, 10, 10, 10, 11, 11, 12, 1, 1, + 13, 1, 1, 1, 14, 14, 14, 14, 14, 14, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 16, 15, 15, + 1, 17, 1, 1, 15, 1, 18, 19, 20, 21, + + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 15, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1 + } ; + +static yyconst YY_CHAR yy_meta[44] = + { 0, + 1, 2, 3, 4, 5, 1, 6, 7, 8, 8, + 8, 1, 1, 9, 9, 9, 1, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 1 + } ; + +static yyconst flex_uint16_t yy_base[470] = + { 0, + 0, 0, 41, 42, 924, 1387, 920, 885, 42, 0, + 871, 0, 39, 42, 869, 49, 53, 58, 65, 63, + 67, 73, 85, 75, 96, 102, 104, 111, 118, 125, + 113, 120, 123, 1387, 1387, 1387, 47, 855, 859, 1387, + 90, 1387, 849, 0, 1387, 0, 0, 130, 830, 150, + 166, 1387, 0, 136, 145, 148, 155, 171, 173, 175, + 178, 181, 185, 187, 191, 194, 203, 209, 217, 219, + 221, 225, 227, 229, 235, 237, 242, 244, 251, 254, + 256, 258, 263, 265, 268, 274, 276, 278, 281, 51, + 807, 84, 1387, 0, 283, 285, 293, 289, 297, 299, + + 307, 313, 315, 317, 319, 321, 327, 325, 338, 346, + 348, 350, 354, 356, 358, 360, 366, 369, 373, 375, + 379, 385, 391, 389, 396, 402, 408, 410, 412, 416, + 418, 420, 427, 425, 429, 432, 795, 791, 782, 769, + 766, 436, 438, 444, 451, 455, 460, 462, 464, 466, + 468, 471, 473, 475, 483, 496, 505, 507, 512, 514, + 516, 518, 521, 524, 526, 528, 530, 532, 537, 540, + 543, 546, 552, 555, 557, 560, 564, 569, 576, 566, + 581, 583, 586, 591, 595, 597, 600, 169, 608, 750, + 734, 729, 607, 609, 611, 613, 617, 621, 623, 626, + + 629, 631, 635, 640, 645, 648, 650, 652, 657, 670, + 1387, 742, 674, 691, 676, 678, 685, 681, 687, 683, + 689, 691, 693, 695, 702, 705, 707, 709, 711, 713, + 717, 722, 724, 726, 730, 732, 734, 736, 742, 701, + 686, 750, 703, 657, 752, 754, 760, 764, 768, 770, + 772, 775, 777, 782, 785, 789, 791, 793, 668, 800, + 1387, 665, 625, 659, 802, 799, 804, 809, 815, 817, + 819, 822, 319, 824, 826, 828, 832, 834, 837, 839, + 841, 843, 850, 852, 631, 627, 638, 857, 859, 861, + 863, 865, 867, 869, 605, 878, 882, 623, 587, 889, + + 607, 891, 889, 893, 899, 901, 895, 568, 567, 904, + 906, 908, 184, 910, 553, 523, 912, 921, 503, 924, + 926, 929, 498, 509, 936, 473, 937, 1387, 502, 943, + 947, 490, 946, 948, 952, 954, 459, 467, 956, 577, + 455, 428, 453, 958, 761, 427, 960, 423, 967, 439, + 407, 411, 971, 1387, 402, 980, 203, 984, 988, 970, + 986, 369, 354, 236, 995, 1000, 331, 327, 998, 367, + 1008, 1012, 314, 1010, 298, 1019, 1387, 313, 1023, 1028, + 280, 305, 385, 1032, 299, 1037, 1387, 276, 1041, 1040, + 1042, 232, 0, 390, 1049, 243, 1053, 1387, 227, 1057, + + 188, 167, 1056, 483, 1063, 193, 1067, 1387, 164, 1074, + 140, 1073, 114, 138, 1080, 1387, 133, 1084, 0, 110, + 1083, 1085, 0, 85, 49, 0, 59, 0, 1087, 0, + 55, 1089, 32, 1091, 0, 1387, 1124, 1133, 1142, 1146, + 1149, 1153, 1157, 1166, 1175, 1183, 1191, 1199, 1207, 1216, + 1224, 1232, 1240, 1248, 1256, 1264, 1273, 1282, 1290, 1299, + 1307, 1316, 1324, 1333, 1341, 1350, 1359, 1368, 1377 + } ; + +static yyconst flex_int16_t yy_def[470] = + { 0, + 436, 1, 437, 437, 436, 436, 436, 436, 438, 439, + 436, 440, 441, 441, 436, 442, 442, 442, 442, 442, + 442, 442, 442, 442, 442, 442, 442, 442, 442, 442, + 442, 442, 442, 436, 436, 436, 436, 436, 436, 436, + 438, 436, 438, 439, 436, 440, 440, 441, 441, 441, + 441, 436, 443, 442, 442, 442, 442, 442, 442, 442, + 442, 442, 442, 442, 442, 442, 442, 442, 442, 442, + 442, 442, 442, 442, 442, 442, 442, 442, 442, 442, + 442, 442, 442, 442, 442, 442, 442, 442, 442, 436, + 436, 436, 436, 50, 442, 442, 442, 442, 442, 442, + + 442, 442, 442, 442, 442, 442, 442, 442, 442, 442, + 442, 442, 442, 442, 442, 442, 442, 442, 442, 442, + 442, 442, 442, 442, 442, 442, 442, 442, 442, 442, + 442, 442, 442, 442, 442, 442, 436, 436, 436, 436, + 436, 442, 442, 442, 442, 442, 442, 442, 442, 442, + 442, 442, 442, 442, 442, 442, 442, 442, 442, 442, + 442, 442, 442, 442, 442, 442, 442, 442, 442, 442, + 442, 442, 442, 442, 442, 442, 442, 442, 442, 442, + 442, 442, 442, 442, 442, 442, 442, 436, 436, 436, + 436, 436, 442, 442, 442, 442, 442, 442, 442, 442, + + 442, 442, 442, 442, 442, 442, 442, 442, 442, 436, + 436, 444, 442, 443, 442, 442, 442, 442, 442, 442, + 442, 442, 442, 442, 442, 442, 442, 442, 442, 442, + 442, 442, 442, 442, 442, 442, 442, 442, 442, 436, + 436, 436, 436, 436, 442, 442, 442, 442, 442, 442, + 442, 442, 442, 442, 442, 442, 442, 442, 444, 436, + 436, 445, 443, 446, 442, 442, 442, 442, 442, 442, + 442, 442, 443, 442, 442, 442, 442, 442, 442, 442, + 442, 442, 442, 442, 436, 436, 436, 442, 442, 442, + 442, 442, 442, 442, 443, 442, 442, 445, 443, 447, + + 448, 442, 442, 442, 442, 442, 442, 443, 443, 442, + 442, 442, 443, 442, 436, 436, 442, 442, 443, 442, + 442, 442, 443, 449, 442, 443, 436, 436, 450, 447, + 451, 452, 442, 442, 442, 442, 443, 443, 442, 453, + 443, 443, 436, 442, 454, 443, 442, 443, 455, 456, + 443, 450, 436, 436, 457, 451, 458, 459, 452, 442, + 442, 443, 443, 460, 461, 453, 443, 443, 442, 462, + 463, 454, 443, 442, 443, 436, 436, 464, 455, 465, + 443, 457, 458, 436, 458, 436, 436, 466, 459, 442, + 442, 443, 443, 460, 436, 460, 436, 436, 467, 461, + + 443, 443, 442, 462, 436, 462, 436, 436, 468, 463, + 443, 442, 443, 464, 436, 436, 469, 465, 443, 466, + 442, 442, 443, 467, 443, 443, 468, 443, 442, 443, + 469, 442, 443, 442, 443, 0, 436, 436, 436, 436, + 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, + 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, + 436, 436, 436, 436, 436, 436, 436, 436, 436 + } ; + +static yyconst flex_uint16_t yy_nxt[1431] = + { 0, + 6, 7, 8, 9, 10, 11, 6, 12, 13, 14, + 14, 15, 6, 16, 16, 16, 6, 17, 18, 19, + 20, 21, 22, 16, 16, 23, 16, 16, 24, 25, + 26, 27, 28, 29, 30, 31, 16, 32, 33, 16, + 16, 16, 34, 36, 36, 42, 47, 48, 48, 47, + 51, 51, 51, 435, 50, 53, 47, 416, 43, 53, + 47, 408, 37, 37, 53, 47, 38, 38, 433, 53, + 47, 53, 47, 53, 47, 90, 137, 91, 50, 53, + 47, 53, 47, 55, 62, 138, 57, 398, 56, 59, + 60, 53, 47, 93, 58, 64, 61, 65, 66, 63, + + 72, 67, 53, 47, 140, 68, 43, 69, 53, 47, + 53, 47, 387, 73, 141, 70, 71, 53, 47, 53, + 47, 74, 77, 75, 53, 47, 53, 47, 80, 53, + 47, 53, 47, 76, 78, 416, 79, 47, 48, 48, + 377, 88, 53, 47, 81, 82, 84, 430, 89, 83, + 85, 53, 47, 87, 53, 47, 86, 47, 94, 94, + 94, 53, 47, 94, 428, 95, 408, 94, 94, 94, + 94, 94, 94, 47, 51, 51, 51, 53, 47, 53, + 47, 53, 47, 96, 53, 47, 97, 53, 47, 240, + 99, 53, 47, 53, 47, 436, 98, 53, 47, 241, + + 53, 47, 426, 103, 341, 100, 384, 101, 102, 53, + 47, 108, 106, 425, 105, 53, 47, 342, 104, 385, + 110, 107, 109, 53, 47, 53, 47, 53, 47, 398, + 111, 53, 47, 53, 47, 53, 47, 112, 114, 395, + 115, 53, 47, 53, 47, 436, 117, 113, 53, 47, + 53, 47, 396, 118, 119, 116, 122, 53, 47, 121, + 53, 47, 53, 47, 53, 47, 120, 423, 123, 53, + 47, 53, 47, 126, 53, 47, 124, 127, 387, 128, + 53, 47, 53, 47, 53, 47, 125, 53, 47, 53, + 47, 53, 47, 130, 129, 53, 47, 134, 131, 53, + + 47, 436, 142, 53, 47, 53, 47, 354, 133, 419, + 132, 135, 143, 53, 47, 377, 136, 144, 146, 53, + 47, 53, 47, 53, 47, 53, 47, 53, 47, 413, + 145, 53, 47, 53, 47, 148, 153, 149, 308, 147, + 150, 309, 154, 156, 53, 47, 151, 152, 157, 411, + 158, 155, 53, 47, 53, 47, 53, 47, 402, 159, + 53, 47, 53, 47, 53, 47, 53, 47, 401, 160, + 405, 162, 53, 47, 163, 53, 47, 393, 161, 53, + 47, 53, 47, 406, 164, 53, 47, 166, 384, 165, + 167, 53, 47, 395, 169, 53, 47, 53, 47, 392, + + 168, 385, 53, 47, 354, 173, 396, 170, 53, 47, + 172, 171, 174, 328, 53, 47, 53, 47, 53, 47, + 175, 176, 53, 47, 53, 47, 53, 47, 381, 177, + 178, 53, 47, 53, 47, 53, 47, 181, 53, 47, + 350, 182, 53, 47, 53, 47, 179, 180, 184, 375, + 53, 47, 373, 183, 350, 193, 187, 53, 47, 368, + 185, 53, 47, 186, 195, 194, 53, 47, 53, 47, + 53, 47, 53, 47, 53, 47, 367, 53, 47, 53, + 47, 53, 47, 196, 363, 197, 405, 198, 203, 53, + 47, 332, 199, 357, 206, 362, 201, 358, 200, 406, + + 202, 205, 53, 47, 328, 204, 210, 211, 351, 212, + 324, 53, 47, 53, 47, 348, 208, 207, 214, 47, + 53, 47, 53, 47, 53, 47, 209, 53, 47, 213, + 53, 47, 53, 47, 53, 47, 53, 47, 53, 47, + 217, 346, 218, 53, 47, 343, 53, 47, 215, 53, + 47, 216, 53, 47, 324, 222, 220, 225, 53, 47, + 219, 53, 47, 53, 47, 223, 53, 47, 224, 221, + 53, 47, 53, 47, 229, 53, 47, 226, 340, 227, + 364, 232, 53, 47, 365, 230, 228, 53, 47, 53, + 47, 231, 53, 47, 233, 338, 234, 53, 47, 337, + + 235, 53, 47, 53, 47, 237, 53, 47, 301, 210, + 211, 236, 212, 53, 47, 53, 47, 53, 47, 53, + 47, 326, 239, 53, 47, 261, 238, 53, 47, 53, + 47, 245, 53, 47, 323, 53, 47, 53, 47, 301, + 250, 53, 47, 246, 249, 248, 53, 47, 316, 247, + 251, 53, 47, 315, 53, 47, 53, 47, 53, 47, + 264, 254, 255, 53, 47, 299, 252, 261, 253, 256, + 211, 210, 211, 257, 212, 260, 261, 258, 262, 287, + 53, 47, 53, 47, 53, 47, 264, 53, 47, 53, + 47, 53, 47, 53, 47, 53, 47, 53, 47, 53, + + 47, 53, 47, 265, 264, 267, 286, 266, 53, 47, + 268, 53, 47, 53, 47, 273, 47, 53, 47, 53, + 47, 269, 285, 53, 47, 263, 272, 270, 53, 47, + 53, 47, 53, 47, 275, 271, 53, 47, 53, 47, + 53, 47, 53, 47, 211, 277, 274, 276, 53, 47, + 244, 260, 261, 281, 262, 282, 243, 279, 53, 47, + 53, 47, 345, 278, 370, 280, 53, 47, 371, 283, + 53, 47, 242, 284, 53, 47, 53, 47, 53, 47, + 289, 53, 47, 53, 47, 290, 192, 288, 53, 47, + 191, 53, 47, 291, 292, 295, 47, 53, 47, 53, + + 47, 260, 261, 301, 262, 53, 47, 190, 53, 47, + 53, 47, 189, 296, 297, 53, 47, 188, 293, 294, + 302, 53, 47, 53, 47, 53, 47, 139, 53, 47, + 53, 47, 53, 47, 53, 47, 304, 47, 53, 47, + 53, 47, 303, 313, 47, 53, 47, 53, 47, 53, + 47, 436, 305, 312, 306, 307, 53, 47, 53, 47, + 39, 310, 311, 53, 47, 53, 47, 319, 47, 53, + 47, 53, 47, 53, 47, 53, 47, 92, 317, 324, + 318, 52, 314, 45, 53, 47, 40, 321, 53, 47, + 327, 328, 332, 329, 320, 53, 47, 53, 47, 53, + + 47, 53, 47, 322, 325, 53, 47, 53, 47, 340, + 53, 47, 53, 47, 53, 47, 53, 47, 53, 47, + 333, 39, 345, 436, 334, 339, 335, 53, 47, 336, + 53, 47, 53, 47, 344, 53, 47, 350, 327, 328, + 436, 329, 53, 47, 327, 328, 436, 329, 353, 354, + 436, 355, 53, 47, 53, 47, 436, 347, 53, 47, + 53, 47, 53, 47, 53, 47, 53, 47, 376, 377, + 436, 378, 353, 354, 436, 355, 53, 47, 436, 360, + 374, 353, 354, 369, 355, 386, 387, 361, 388, 436, + 436, 436, 53, 47, 436, 358, 397, 398, 436, 399, + + 390, 436, 436, 436, 53, 47, 436, 365, 436, 407, + 408, 391, 409, 436, 436, 436, 53, 47, 436, 371, + 376, 377, 436, 378, 376, 377, 436, 378, 436, 415, + 416, 412, 417, 386, 387, 436, 388, 403, 386, 387, + 436, 388, 386, 387, 436, 388, 53, 47, 53, 47, + 397, 398, 436, 399, 397, 398, 436, 399, 397, 398, + 436, 399, 53, 47, 407, 408, 436, 409, 407, 408, + 436, 409, 436, 422, 421, 407, 408, 436, 409, 53, + 47, 415, 416, 436, 417, 415, 416, 436, 417, 53, + 47, 53, 47, 53, 47, 53, 47, 53, 47, 436, + + 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, + 429, 436, 436, 436, 436, 432, 436, 436, 436, 436, + 436, 436, 436, 434, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 41, 41, 41, 41, 41, 41, 41, + 41, 41, 44, 44, 436, 44, 44, 44, 44, 44, + 44, 46, 46, 46, 46, 49, 49, 49, 54, 54, + 54, 54, 53, 436, 53, 53, 259, 259, 259, 259, + 259, 259, 259, 259, 259, 298, 298, 298, 298, 298, + 298, 298, 298, 298, 300, 436, 436, 436, 436, 436, + 436, 300, 330, 330, 436, 330, 330, 436, 330, 330, + + 331, 436, 436, 436, 436, 436, 436, 331, 349, 436, + 436, 436, 436, 436, 436, 349, 352, 352, 352, 352, + 352, 352, 352, 352, 352, 356, 356, 436, 356, 356, + 436, 356, 356, 359, 436, 359, 436, 436, 359, 359, + 359, 366, 436, 366, 436, 436, 366, 366, 366, 372, + 436, 372, 436, 436, 372, 372, 372, 379, 379, 436, + 379, 379, 436, 379, 379, 380, 436, 436, 436, 436, + 436, 436, 380, 382, 382, 382, 382, 382, 382, 382, + 382, 382, 383, 383, 383, 383, 383, 383, 383, 383, + 383, 389, 389, 436, 389, 389, 389, 389, 389, 394, + + 394, 394, 394, 394, 394, 394, 394, 394, 400, 400, + 436, 400, 400, 400, 400, 400, 404, 404, 404, 404, + 404, 404, 404, 404, 404, 410, 410, 436, 410, 410, + 410, 410, 410, 414, 414, 414, 414, 414, 414, 414, + 414, 414, 418, 418, 436, 418, 418, 436, 418, 418, + 420, 420, 420, 420, 420, 420, 420, 420, 420, 424, + 424, 424, 424, 424, 424, 424, 424, 424, 427, 427, + 427, 427, 427, 427, 427, 427, 427, 431, 431, 431, + 431, 431, 431, 431, 431, 431, 5, 436, 436, 436, + 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, + + 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, + 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, + 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 + } ; + +static yyconst flex_int16_t yy_chk[1431] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 3, 4, 9, 13, 13, 13, 14, + 14, 14, 14, 433, 13, 16, 16, 431, 9, 17, + 17, 427, 3, 4, 18, 18, 3, 4, 425, 20, + 20, 19, 19, 21, 21, 37, 90, 37, 13, 22, + 22, 24, 24, 17, 20, 90, 18, 424, 17, 19, + 19, 23, 23, 41, 18, 21, 19, 21, 22, 20, + + 24, 22, 25, 25, 92, 23, 41, 23, 26, 26, + 27, 27, 420, 25, 92, 23, 23, 28, 28, 31, + 31, 25, 27, 26, 29, 29, 32, 32, 28, 33, + 33, 30, 30, 26, 27, 417, 27, 48, 48, 48, + 414, 32, 54, 54, 28, 28, 30, 413, 33, 29, + 30, 55, 55, 31, 56, 56, 30, 50, 50, 50, + 50, 57, 57, 50, 411, 55, 409, 50, 50, 50, + 50, 50, 50, 51, 51, 51, 51, 58, 58, 59, + 59, 60, 60, 56, 61, 61, 57, 62, 62, 188, + 59, 63, 63, 64, 64, 406, 58, 65, 65, 188, + + 66, 66, 402, 62, 313, 60, 357, 61, 61, 67, + 67, 65, 64, 401, 63, 68, 68, 313, 62, 357, + 67, 64, 66, 69, 69, 70, 70, 71, 71, 399, + 68, 72, 72, 73, 73, 74, 74, 69, 70, 364, + 71, 75, 75, 76, 76, 396, 73, 69, 77, 77, + 78, 78, 364, 73, 73, 72, 75, 79, 79, 74, + 80, 80, 81, 81, 82, 82, 73, 392, 77, 83, + 83, 84, 84, 80, 85, 85, 77, 81, 388, 82, + 86, 86, 87, 87, 88, 88, 79, 89, 89, 95, + 95, 96, 96, 84, 83, 98, 98, 88, 85, 97, + + 97, 385, 96, 99, 99, 100, 100, 382, 87, 381, + 86, 88, 97, 101, 101, 378, 89, 98, 100, 102, + 102, 103, 103, 104, 104, 105, 105, 106, 106, 375, + 99, 108, 108, 107, 107, 102, 104, 103, 273, 101, + 103, 273, 104, 106, 109, 109, 103, 103, 107, 373, + 108, 105, 110, 110, 111, 111, 112, 112, 368, 109, + 113, 113, 114, 114, 115, 115, 116, 116, 367, 110, + 370, 112, 117, 117, 113, 118, 118, 363, 111, 119, + 119, 120, 120, 370, 114, 121, 121, 116, 383, 115, + 117, 122, 122, 394, 119, 124, 124, 123, 123, 362, + + 118, 383, 125, 125, 355, 122, 394, 120, 126, 126, + 121, 120, 123, 352, 127, 127, 128, 128, 129, 129, + 124, 125, 130, 130, 131, 131, 132, 132, 351, 126, + 127, 134, 134, 133, 133, 135, 135, 130, 136, 136, + 350, 131, 142, 142, 143, 143, 128, 129, 133, 348, + 144, 144, 346, 132, 343, 142, 136, 145, 145, 342, + 134, 146, 146, 135, 144, 143, 147, 147, 148, 148, + 149, 149, 150, 150, 151, 151, 341, 152, 152, 153, + 153, 154, 154, 146, 338, 147, 404, 148, 152, 155, + 155, 332, 149, 332, 154, 337, 150, 332, 149, 404, + + 151, 153, 156, 156, 329, 152, 157, 157, 326, 157, + 324, 157, 157, 158, 158, 323, 156, 155, 159, 159, + 160, 160, 161, 161, 162, 162, 156, 163, 163, 158, + 164, 164, 165, 165, 166, 166, 167, 167, 168, 168, + 162, 319, 163, 169, 169, 316, 170, 170, 160, 171, + 171, 161, 172, 172, 315, 167, 165, 170, 173, 173, + 164, 174, 174, 175, 175, 168, 176, 176, 169, 166, + 177, 177, 180, 180, 174, 178, 178, 171, 340, 172, + 340, 177, 179, 179, 340, 175, 173, 181, 181, 182, + 182, 176, 183, 183, 178, 309, 179, 184, 184, 308, + + 181, 185, 185, 186, 186, 183, 187, 187, 301, 189, + 189, 182, 189, 193, 193, 194, 194, 195, 195, 196, + 196, 299, 186, 197, 197, 298, 185, 198, 198, 199, + 199, 193, 200, 200, 295, 201, 201, 202, 202, 287, + 199, 203, 203, 195, 198, 197, 204, 204, 286, 196, + 201, 205, 205, 285, 206, 206, 207, 207, 208, 208, + 264, 204, 205, 209, 209, 263, 202, 262, 203, 206, + 259, 210, 210, 208, 210, 213, 213, 209, 213, 244, + 213, 213, 215, 215, 216, 216, 217, 218, 218, 220, + 220, 217, 217, 219, 219, 221, 221, 222, 222, 223, + + 223, 224, 224, 218, 243, 220, 241, 219, 225, 225, + 221, 226, 226, 227, 227, 228, 228, 229, 229, 230, + 230, 222, 240, 231, 231, 214, 226, 224, 232, 232, + 233, 233, 234, 234, 230, 225, 235, 235, 236, 236, + 237, 237, 238, 238, 212, 232, 229, 231, 239, 239, + 192, 242, 242, 236, 242, 237, 191, 234, 245, 245, + 246, 246, 345, 233, 345, 235, 247, 247, 345, 238, + 248, 248, 190, 239, 249, 249, 250, 250, 251, 251, + 247, 252, 252, 253, 253, 248, 141, 246, 254, 254, + 140, 255, 255, 250, 253, 256, 256, 257, 257, 258, + + 258, 260, 260, 265, 260, 266, 266, 139, 265, 265, + 267, 267, 138, 257, 258, 268, 268, 137, 254, 255, + 266, 269, 269, 270, 270, 271, 271, 91, 272, 272, + 274, 274, 275, 275, 276, 276, 269, 49, 277, 277, + 278, 278, 268, 279, 279, 280, 280, 281, 281, 282, + 282, 43, 270, 277, 271, 272, 283, 283, 284, 284, + 39, 275, 276, 288, 288, 289, 289, 290, 290, 291, + 291, 292, 292, 293, 293, 294, 294, 38, 288, 296, + 289, 15, 284, 11, 296, 296, 8, 293, 297, 297, + 300, 300, 302, 300, 292, 303, 303, 302, 302, 304, + + 304, 307, 307, 294, 297, 305, 305, 306, 306, 312, + 310, 310, 311, 311, 312, 312, 314, 314, 317, 317, + 303, 7, 318, 5, 305, 310, 306, 318, 318, 307, + 320, 320, 321, 321, 317, 322, 322, 325, 327, 327, + 0, 327, 325, 325, 330, 330, 0, 330, 331, 331, + 0, 331, 333, 333, 334, 334, 0, 321, 335, 335, + 336, 336, 339, 339, 344, 344, 347, 347, 349, 349, + 0, 349, 353, 353, 0, 353, 360, 360, 0, 334, + 347, 356, 356, 344, 356, 358, 358, 335, 358, 359, + 0, 359, 361, 361, 0, 359, 365, 365, 0, 365, + + 360, 366, 0, 366, 369, 369, 0, 366, 0, 371, + 371, 361, 371, 372, 0, 372, 374, 374, 0, 372, + 376, 376, 0, 376, 379, 379, 0, 379, 0, 380, + 380, 374, 380, 384, 384, 0, 384, 369, 386, 386, + 0, 386, 389, 389, 0, 389, 390, 390, 391, 391, + 395, 395, 0, 395, 397, 397, 0, 397, 400, 400, + 0, 400, 403, 403, 405, 405, 0, 405, 407, 407, + 0, 407, 0, 391, 390, 410, 410, 0, 410, 412, + 412, 415, 415, 0, 415, 418, 418, 0, 418, 421, + 421, 422, 422, 429, 429, 432, 432, 434, 434, 0, + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 412, 0, 0, 0, 0, 422, 0, 0, 0, 0, + 0, 0, 0, 432, 437, 437, 437, 437, 437, 437, + 437, 437, 437, 438, 438, 438, 438, 438, 438, 438, + 438, 438, 439, 439, 0, 439, 439, 439, 439, 439, + 439, 440, 440, 440, 440, 441, 441, 441, 442, 442, + 442, 442, 443, 0, 443, 443, 444, 444, 444, 444, + 444, 444, 444, 444, 444, 445, 445, 445, 445, 445, + 445, 445, 445, 445, 446, 0, 0, 0, 0, 0, + 0, 446, 447, 447, 0, 447, 447, 0, 447, 447, + + 448, 0, 0, 0, 0, 0, 0, 448, 449, 0, + 0, 0, 0, 0, 0, 449, 450, 450, 450, 450, + 450, 450, 450, 450, 450, 451, 451, 0, 451, 451, + 0, 451, 451, 452, 0, 452, 0, 0, 452, 452, + 452, 453, 0, 453, 0, 0, 453, 453, 453, 454, + 0, 454, 0, 0, 454, 454, 454, 455, 455, 0, + 455, 455, 0, 455, 455, 456, 0, 0, 0, 0, + 0, 0, 456, 457, 457, 457, 457, 457, 457, 457, + 457, 457, 458, 458, 458, 458, 458, 458, 458, 458, + 458, 459, 459, 0, 459, 459, 459, 459, 459, 460, + + 460, 460, 460, 460, 460, 460, 460, 460, 461, 461, + 0, 461, 461, 461, 461, 461, 462, 462, 462, 462, + 462, 462, 462, 462, 462, 463, 463, 0, 463, 463, + 463, 463, 463, 464, 464, 464, 464, 464, 464, 464, + 464, 464, 465, 465, 0, 465, 465, 0, 465, 465, + 466, 466, 466, 466, 466, 466, 466, 466, 466, 467, + 467, 467, 467, 467, 467, 467, 467, 467, 468, 468, + 468, 468, 468, 468, 468, 468, 468, 469, 469, 469, + 469, 469, 469, 469, 469, 469, 436, 436, 436, 436, + 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, + + 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, + 436, 436, 436, 436, 436, 436, 436, 436, 436, 436, + 436, 436, 436, 436, 436, 436, 436, 436, 436, 436 + } ; + +static yy_state_type yy_last_accepting_state; +static char *yy_last_accepting_cpos; + +extern int yy_flex_debug; +int yy_flex_debug = 0; + +/* The intent behind this definition is that it'll catch + * any uses of REJECT which flex missed. + */ +#define REJECT reject_used_but_not_detected +#define yymore() yymore_used_but_not_detected +#define YY_MORE_ADJ 0 +#define YY_RESTORE_YY_MORE_OFFSET +char *yytext; +#line 1 "scan.l" +#line 2 "scan.l" +/* $NetBSD: scan.l,v 1.25 2015/09/04 10:16:35 uebayasi Exp $ */ + +/* + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Lawrence Berkeley Laboratories. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * from: @(#)scan.l 8.1 (Berkeley) 6/6/93 + */ + +#include +__RCSID("$NetBSD: scan.l,v 1.25 2015/09/04 10:16:35 uebayasi Exp $"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#undef ECHO +#include "defs.h" +#include "gram.h" + +int yyline; +const char *yyfile; +const char *lastfile; +char curinclpath[PATH_MAX]; +int ifdefstate = -1; +int st; +#define IDS_PARENT_DISABLED \ + ((ifdefstate > 6) && ((((ifdefstate/6)-1) & 1) == 1)) +#define IDS_MAX_DEPTH 362797056 /* 6^11 */ +/* States for ifdefstate: + + 0 -> matched ifdef + 1 -> unmatched ifdef + 2 -> matched elifdef + 3 -> unmatched elifdef + 4 -> matched else + 5 -> unmatched else + + Upon "ifdef", add one and multiply by 6. + Upon "endif", divide by 6, remove 1. + + ifdef -> MATCH => continue + MISMATCH => set to 1 + elifdef -> if (!1) -> MISMATCH + MATCH => set to 2 + MISMATCH => if (2 || 3) set to 3, else set to 1 + else -> if (1) -> MATCH + MATCH => set to 4 + MISMATCH => set to 5 + + in each case, if parent & 1 == 1, MISMATCH +*/ + +/* + * Data for returning to previous files from include files. + */ +struct incl { + struct incl *in_prev; /* previous includes in effect, if any */ + YY_BUFFER_STATE in_buf; /* previous lex state */ + const char *in_fname; /* previous file name */ + int in_lineno; /* previous line number */ + int in_ateof; /* token to insert at EOF */ + int in_interesting; /* previous value for "interesting" */ + int in_ifdefstate; /* conditional level */ +}; +static struct incl *incl; +static int endinclude(void); +static int getincludepath(void); +static int getcurifdef(void); + + +#define YY_NO_INPUT 1 + +#line 1039 "scan.c" + +#define INITIAL 0 +#define IGNORED 1 + +#ifndef YY_NO_UNISTD_H +/* Special case for "unistd.h", since it is non-ANSI. We include it way + * down here because we want the user's section 1 to have been scanned first. + * The user has a chance to override it with an option. + */ +#include +#endif + +#ifndef YY_EXTRA_TYPE +#define YY_EXTRA_TYPE void * +#endif + +static int yy_init_globals (void ); + +/* Accessor methods to globals. + These are made visible to non-reentrant scanners for convenience. */ + +int yylex_destroy (void ); + +int yyget_debug (void ); + +void yyset_debug (int debug_flag ); + +YY_EXTRA_TYPE yyget_extra (void ); + +void yyset_extra (YY_EXTRA_TYPE user_defined ); + +FILE *yyget_in (void ); + +void yyset_in (FILE * _in_str ); + +FILE *yyget_out (void ); + +void yyset_out (FILE * _out_str ); + +yy_size_t yyget_leng (void ); + +char *yyget_text (void ); + +int yyget_lineno (void ); + +void yyset_lineno (int _line_number ); + +/* Macros after this point can all be overridden by user definitions in + * section 1. + */ + +#ifndef YY_SKIP_YYWRAP +#ifdef __cplusplus +extern "C" int yywrap (void ); +#else +extern int yywrap (void ); +#endif +#endif + +#ifndef YY_NO_UNPUT + +#endif + +#ifndef yytext_ptr +static void yy_flex_strncpy (char *,yyconst char *,int ); +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen (yyconst char * ); +#endif + +#ifndef YY_NO_INPUT + +#ifdef __cplusplus +static int yyinput (void ); +#else +static int input (void ); +#endif + +#endif + +/* Amount of stuff to slurp up with each read. */ +#ifndef YY_READ_BUF_SIZE +#define YY_READ_BUF_SIZE 8192 +#endif + +/* Copy whatever the last rule matched to the standard output. */ +#ifndef ECHO +/* This used to be an fputs(), but since the string might contain NUL's, + * we now use fwrite(). + */ +#define ECHO do { if (fwrite( yytext, yyleng, 1, yyout )) {} } while (0) +#endif + +/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, + * is returned in "result". + */ +#ifndef YY_INPUT +#define YY_INPUT(buf,result,max_size) \ + if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \ + { \ + int c = '*'; \ + size_t n; \ + for ( n = 0; n < max_size && \ + (c = getc( yyin )) != EOF && c != '\n'; ++n ) \ + buf[n] = (char) c; \ + if ( c == '\n' ) \ + buf[n++] = (char) c; \ + if ( c == EOF && ferror( yyin ) ) \ + YY_FATAL_ERROR( "input in flex scanner failed" ); \ + result = n; \ + } \ + else \ + { \ + errno=0; \ + while ( (result = fread(buf, 1, max_size, yyin))==0 && ferror(yyin)) \ + { \ + if( errno != EINTR) \ + { \ + YY_FATAL_ERROR( "input in flex scanner failed" ); \ + break; \ + } \ + errno=0; \ + clearerr(yyin); \ + } \ + }\ +\ + +#endif + +/* No semi-colon after return; correct usage is to write "yyterminate();" - + * we don't want an extra ';' after the "return" because that will cause + * some compilers to complain about unreachable statements. + */ +#ifndef yyterminate +#define yyterminate() return YY_NULL +#endif + +/* Number of entries by which start-condition stack grows. */ +#ifndef YY_START_STACK_INCR +#define YY_START_STACK_INCR 25 +#endif + +/* Report a fatal error. */ +#ifndef YY_FATAL_ERROR +#define YY_FATAL_ERROR(msg) yy_fatal_error( msg ) +#endif + +/* end tables serialization structures and prototypes */ + +/* Default declaration of generated scanner - a define so the user can + * easily add parameters. + */ +#ifndef YY_DECL +#define YY_DECL_IS_OURS 1 + +extern int yylex (void); + +#define YY_DECL int yylex (void) +#endif /* !YY_DECL */ + +/* Code executed at the beginning of each rule, after yytext and yyleng + * have been set up. + */ +#ifndef YY_USER_ACTION +#define YY_USER_ACTION +#endif + +/* Code executed at the end of each rule. */ +#ifndef YY_BREAK +#define YY_BREAK /*LINTED*/break; +#endif + +#define YY_RULE_SETUP \ + YY_USER_ACTION + +/** The main scanner function which does all the work. + */ +YY_DECL +{ + register yy_state_type yy_current_state; + register char *yy_cp, *yy_bp; + register int yy_act; + + if ( !(yy_init) ) + { + (yy_init) = 1; + +#ifdef YY_USER_INIT + YY_USER_INIT; +#endif + + if ( ! (yy_start) ) + (yy_start) = 1; /* first start state */ + + if ( ! yyin ) + yyin = stdin; + + if ( ! yyout ) + yyout = stdout; + + if ( ! YY_CURRENT_BUFFER ) { + yyensure_buffer_stack (); + YY_CURRENT_BUFFER_LVALUE = + yy_create_buffer(yyin,YY_BUF_SIZE ); + } + + yy_load_buffer_state( ); + } + + { +#line 124 "scan.l" + + /* Local variables for yylex() */ + int tok; + +#line 1256 "scan.c" + + while (/*CONSTCOND*/ 1 ) /* loops until end-of-file is reached */ + { + yy_cp = (yy_c_buf_p); + + /* Support of yytext. */ + *yy_cp = (yy_hold_char); + + /* yy_bp points to the position in yy_ch_buf of the start of + * the current run. + */ + yy_bp = yy_cp; + + yy_current_state = (yy_start); +yy_match: + do + { + register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)] ; + if ( yy_accept[yy_current_state] ) + { + (yy_last_accepting_state) = yy_current_state; + (yy_last_accepting_cpos) = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 437 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + ++yy_cp; + } + while ( yy_base[yy_current_state] != 1387 ); + +yy_find_action: + yy_act = yy_accept[yy_current_state]; + if ( yy_act == 0 ) + { /* have to back up */ + yy_cp = (yy_last_accepting_cpos); + yy_current_state = (yy_last_accepting_state); + yy_act = yy_accept[yy_current_state]; + } + + YY_DO_BEFORE_ACTION; + +do_action: /* This label is used only to access EOF actions. */ + + switch ( yy_act ) + { /* beginning of action switch */ + case 0: /* must back up */ + /* undo the effects of YY_DO_BEFORE_ACTION */ + *yy_cp = (yy_hold_char); + yy_cp = (yy_last_accepting_cpos); + yy_current_state = (yy_last_accepting_state); + goto yy_find_action; + +case 1: +YY_RULE_SETUP +#line 128 "scan.l" +return AND; + YY_BREAK +case 2: +YY_RULE_SETUP +#line 129 "scan.l" +return AT; + YY_BREAK +case 3: +YY_RULE_SETUP +#line 130 "scan.l" +return ATTACH; + YY_BREAK +case 4: +YY_RULE_SETUP +#line 131 "scan.l" +return BLOCK; + YY_BREAK +case 5: +YY_RULE_SETUP +#line 132 "scan.l" +return BUILD; + YY_BREAK +case 6: +YY_RULE_SETUP +#line 133 "scan.l" +return CHAR; + YY_BREAK +case 7: +YY_RULE_SETUP +#line 134 "scan.l" +return COMPILE_WITH; + YY_BREAK +case 8: +YY_RULE_SETUP +#line 135 "scan.l" +return CONFIG; + YY_BREAK +case 9: +YY_RULE_SETUP +#line 136 "scan.l" +return DEFFS; + YY_BREAK +case 10: +YY_RULE_SETUP +#line 137 "scan.l" +return DEFINE; + YY_BREAK +case 11: +YY_RULE_SETUP +#line 138 "scan.l" +return DEFFLAG; + YY_BREAK +case 12: +YY_RULE_SETUP +#line 139 "scan.l" +return DEFOPT; + YY_BREAK +case 13: +YY_RULE_SETUP +#line 140 "scan.l" +return DEFPARAM; + YY_BREAK +case 14: +YY_RULE_SETUP +#line 141 "scan.l" +return DEFPSEUDO; + YY_BREAK +case 15: +YY_RULE_SETUP +#line 142 "scan.l" +return DEFPSEUDODEV; + YY_BREAK +case 16: +YY_RULE_SETUP +#line 143 "scan.l" +return DEVCLASS; + YY_BREAK +case 17: +YY_RULE_SETUP +#line 144 "scan.l" +return DEVICE; + YY_BREAK +case 18: +YY_RULE_SETUP +#line 145 "scan.l" +return DEVICE_MAJOR; + YY_BREAK +case 19: +YY_RULE_SETUP +#line 146 "scan.l" +return DUMPS; + YY_BREAK +case 20: +YY_RULE_SETUP +#line 147 "scan.l" +return XFILE; + YY_BREAK +case 21: +YY_RULE_SETUP +#line 148 "scan.l" +return FILE_SYSTEM; + YY_BREAK +case 22: +YY_RULE_SETUP +#line 149 "scan.l" +return FLAGS; + YY_BREAK +case 23: +YY_RULE_SETUP +#line 150 "scan.l" +return IDENT; + YY_BREAK +case 24: +YY_RULE_SETUP +#line 151 "scan.l" +return IOCONF; + YY_BREAK +case 25: +YY_RULE_SETUP +#line 152 "scan.l" +return LINKZERO; + YY_BREAK +case 26: +YY_RULE_SETUP +#line 153 "scan.l" +return XMACHINE; + YY_BREAK +case 27: +YY_RULE_SETUP +#line 154 "scan.l" +return MAJOR; + YY_BREAK +case 28: +YY_RULE_SETUP +#line 155 "scan.l" +return MAKEOPTIONS; + YY_BREAK +case 29: +YY_RULE_SETUP +#line 156 "scan.l" +return MAXPARTITIONS; + YY_BREAK +case 30: +YY_RULE_SETUP +#line 157 "scan.l" +return MAXUSERS; + YY_BREAK +case 31: +YY_RULE_SETUP +#line 158 "scan.l" +return MINOR; + YY_BREAK +case 32: +YY_RULE_SETUP +#line 159 "scan.l" +return NEEDS_COUNT; + YY_BREAK +case 33: +YY_RULE_SETUP +#line 160 "scan.l" +return NEEDS_FLAG; + YY_BREAK +case 34: +YY_RULE_SETUP +#line 161 "scan.l" +return NO; + YY_BREAK +case 35: +YY_RULE_SETUP +#line 162 "scan.l" +return XOBJECT; + YY_BREAK +case 36: +YY_RULE_SETUP +#line 163 "scan.l" +return OBSOLETE; + YY_BREAK +case 37: +YY_RULE_SETUP +#line 164 "scan.l" +return ON; + YY_BREAK +case 38: +YY_RULE_SETUP +#line 165 "scan.l" +return OPTIONS; + YY_BREAK +case 39: +YY_RULE_SETUP +#line 166 "scan.l" +return PREFIX; + YY_BREAK +case 40: +YY_RULE_SETUP +#line 167 "scan.l" +return BUILDPREFIX; + YY_BREAK +case 41: +YY_RULE_SETUP +#line 168 "scan.l" +return PSEUDO_DEVICE; + YY_BREAK +case 42: +YY_RULE_SETUP +#line 169 "scan.l" +return PSEUDO_ROOT; + YY_BREAK +case 43: +YY_RULE_SETUP +#line 170 "scan.l" +return ROOT; + YY_BREAK +case 44: +YY_RULE_SETUP +#line 171 "scan.l" +return SELECT; + YY_BREAK +case 45: +YY_RULE_SETUP +#line 172 "scan.l" +return SINGLE; + YY_BREAK +case 46: +YY_RULE_SETUP +#line 173 "scan.l" +return SOURCE; + YY_BREAK +case 47: +YY_RULE_SETUP +#line 174 "scan.l" +return TYPE; + YY_BREAK +case 48: +YY_RULE_SETUP +#line 175 "scan.l" +return VECTOR; + YY_BREAK +case 49: +YY_RULE_SETUP +#line 176 "scan.l" +return VERSION; + YY_BREAK +case 50: +YY_RULE_SETUP +#line 177 "scan.l" +return WITH; + YY_BREAK +case 51: +YY_RULE_SETUP +#line 179 "scan.l" +return PLUSEQ; + YY_BREAK +case 52: +YY_RULE_SETUP +#line 180 "scan.l" +return COLONEQ; + YY_BREAK +case 53: +/* rule 53 can match eol */ +YY_RULE_SETUP +#line 182 "scan.l" +{ + ifdefstate = (ifdefstate + 1) * 6; + if (ifdefstate >= IDS_MAX_DEPTH) { + yyerror("too many levels of conditional"); + } + if (!IDS_PARENT_DISABLED && getcurifdef()) { + BEGIN(INITIAL); + } else { + ifdefstate++; + BEGIN(IGNORED); + } + yyline++; + } + YY_BREAK +case 54: +/* rule 54 can match eol */ +YY_RULE_SETUP +#line 196 "scan.l" +{ + ifdefstate = (ifdefstate + 1) * 6; + if (ifdefstate >= IDS_MAX_DEPTH) { + yyerror("too many levels of conditional"); + } + if (!IDS_PARENT_DISABLED && !getcurifdef()) { + BEGIN(INITIAL); + } else { + ifdefstate++; + BEGIN(IGNORED); + } + yyline++; + } + YY_BREAK +case 55: +/* rule 55 can match eol */ +YY_RULE_SETUP +#line 211 "scan.l" +{ + st = ifdefstate % 6; + if (ifdefstate < 0 || st > 3) { + yyerror("mismatched elifdef"); + } + if (IDS_PARENT_DISABLED || + st != 1 || !getcurifdef()) { + if (st == 2 || st == 3) { + ifdefstate += 3 - st; + } else { + ifdefstate += 1 - st; + } + BEGIN(IGNORED); + } else { + ifdefstate++; + BEGIN(INITIAL); + } + yyline++; + } + YY_BREAK +case 56: +/* rule 56 can match eol */ +YY_RULE_SETUP +#line 231 "scan.l" +{ + st = ifdefstate % 6; + if (ifdefstate < 0 || st > 3) { + yyerror("mismatched elifndef"); + } + if (IDS_PARENT_DISABLED || + st != 1 || getcurifdef()) { + if (st == 2 || st == 3) { + ifdefstate += 3 - st; + } else { + ifdefstate += 1 - st; + } + BEGIN(IGNORED); + } else { + ifdefstate++; + BEGIN(INITIAL); + } + yyline++; + } + YY_BREAK +case 57: +/* rule 57 can match eol */ +YY_RULE_SETUP +#line 251 "scan.l" +{ + st = ifdefstate % 6; + if (ifdefstate < 0 || st > 3) { + yyerror("mismatched else"); + } + if (!IDS_PARENT_DISABLED && (st == 1)) { + ifdefstate += 3; + BEGIN(INITIAL); + } else { + ifdefstate += 5 - st; + BEGIN(IGNORED); + } + yyline++; + } + YY_BREAK +case 58: +/* rule 58 can match eol */ +YY_RULE_SETUP +#line 266 "scan.l" +{ + if (ifdefstate < 0) { + yyerror("mismatched endif"); + } + if (!IDS_PARENT_DISABLED) { + BEGIN(INITIAL); + } + ifdefstate = (ifdefstate/6) - 1; + yyline++; + } + YY_BREAK +case 59: +/* rule 59 can match eol */ +YY_RULE_SETUP +#line 277 "scan.l" +{ + yyline++; + } + YY_BREAK +case 60: +YY_RULE_SETUP +#line 281 "scan.l" +/* ignore */ + YY_BREAK +case 61: +/* rule 61 can match eol */ +YY_RULE_SETUP +#line 283 "scan.l" +{ + yyline++; + if (getincludepath()) { + include(curinclpath, 0, 0, 1); + } else { + yyerror("bad include path-name"); + } + } + YY_BREAK +case 62: +/* rule 62 can match eol */ +YY_RULE_SETUP +#line 292 "scan.l" +{ + yyline++; + if (getincludepath()) { + include(curinclpath, 0, 1, 1); + } else { + yyerror("bad cinclude path-name"); + } + } + YY_BREAK +case 63: +/* rule 63 can match eol */ +YY_RULE_SETUP +#line 301 "scan.l" +{ + yyline++; + if (!oktopackage) { + yyerror("package not allowed here"); + } else if (getincludepath()) { + package(curinclpath); + } else { + yyerror("bad package path-name"); + } + } + YY_BREAK +case 64: +YY_RULE_SETUP +#line 312 "scan.l" +{ + yylval.str = intern(yytext); + return PATHNAME; + } + YY_BREAK +case 65: +YY_RULE_SETUP +#line 317 "scan.l" +{ + yylval.str = intern(yytext); + return WORD; + } + YY_BREAK +case 66: +YY_RULE_SETUP +#line 322 "scan.l" +{ + yylval.str = intern(""); + return EMPTYSTRING; + } + YY_BREAK +case 67: +/* rule 67 can match eol */ +YY_RULE_SETUP +#line 327 "scan.l" +{ + size_t l = strlen(yytext); + if (l > 1 && yytext[l - 1] == '"') + yytext[l - 1] = '\0'; + + yylval.str = intern(yytext + 1); + return QSTRING; + } + YY_BREAK +case 68: +YY_RULE_SETUP +#line 335 "scan.l" +{ + yylval.num.fmt = 8; + yylval.num.val = strtoll(yytext, NULL, 8); + return NUMBER; + } + YY_BREAK +case 69: +YY_RULE_SETUP +#line 340 "scan.l" +{ + yylval.num.fmt = 16; + yylval.num.val = (long long)strtoull(yytext + 2, NULL, 16); + return NUMBER; + } + YY_BREAK +case 70: +YY_RULE_SETUP +#line 345 "scan.l" +{ + yylval.num.fmt = 10; + yylval.num.val = strtoll(yytext, NULL, 10); + return NUMBER; + } + YY_BREAK +case 71: +/* rule 71 can match eol */ +YY_RULE_SETUP +#line 350 "scan.l" +{ + /* + * Note: newline followed by whitespace is always a + * continuation of the previous line, so do NOT + * return a token in this case. + */ + yyline++; + } + YY_BREAK +case 72: +/* rule 72 can match eol */ +YY_RULE_SETUP +#line 358 "scan.l" +{ + yyline++; + return '\n'; + } + YY_BREAK +case 73: +YY_RULE_SETUP +#line 362 "scan.l" +{ + /* Detect NUL characters in the config file and + * error out. + */ + cfgerror("NUL character detected at line %i", yyline); + } + YY_BREAK +case 74: +YY_RULE_SETUP +#line 368 "scan.l" +{ /* ignored (comment) */; } + YY_BREAK +case 75: +YY_RULE_SETUP +#line 369 "scan.l" +{ /* ignored (white space) */; } + YY_BREAK +case 76: +YY_RULE_SETUP +#line 370 "scan.l" +{ return yytext[0]; } + YY_BREAK +case YY_STATE_EOF(INITIAL): +case YY_STATE_EOF(IGNORED): +#line 371 "scan.l" +{ + if (ifdefstate > (incl == NULL ? -1 : incl->in_ifdefstate)) { + yyerror("reached EOF while looking for endif"); + } + if (incl == NULL) + return YY_NULL; + tok = endinclude(); + if (tok) + return tok; + /* otherwise continue scanning */ + } + YY_BREAK +case 77: +YY_RULE_SETUP +#line 383 "scan.l" +ECHO; + YY_BREAK +#line 1876 "scan.c" + + case YY_END_OF_BUFFER: + { + /* Amount of text matched not including the EOB char. */ + int yy_amount_of_matched_text = (int) (yy_cp - (yytext_ptr)) - 1; + + /* Undo the effects of YY_DO_BEFORE_ACTION. */ + *yy_cp = (yy_hold_char); + YY_RESTORE_YY_MORE_OFFSET + + if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW ) + { + /* We're scanning a new file or input source. It's + * possible that this happened because the user + * just pointed yyin at a new source and called + * yylex(). If so, then we have to assure + * consistency between YY_CURRENT_BUFFER and our + * globals. Here is the right place to do so, because + * this is the first action (other than possibly a + * back-up) that will match for the new input source. + */ + (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; + YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin; + YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL; + } + + /* Note that here we test for yy_c_buf_p "<=" to the position + * of the first EOB in the buffer, since yy_c_buf_p will + * already have been incremented past the NUL character + * (since all states make transitions on EOB to the + * end-of-buffer state). Contrast this with the test + * in input(). + */ + if ( (yy_c_buf_p) <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] ) + { /* This was really a NUL. */ + yy_state_type yy_next_state; + + (yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state( ); + + /* Okay, we're now positioned to make the NUL + * transition. We couldn't have + * yy_get_previous_state() go ahead and do it + * for us because it doesn't know how to deal + * with the possibility of jamming (and we don't + * want to build jamming into it because then it + * will run more slowly). + */ + + yy_next_state = yy_try_NUL_trans( yy_current_state ); + + yy_bp = (yytext_ptr) + YY_MORE_ADJ; + + if ( yy_next_state ) + { + /* Consume the NUL. */ + yy_cp = ++(yy_c_buf_p); + yy_current_state = yy_next_state; + goto yy_match; + } + + else + { + yy_cp = (yy_c_buf_p); + goto yy_find_action; + } + } + + else switch ( yy_get_next_buffer( ) ) + { + case EOB_ACT_END_OF_FILE: + { + (yy_did_buffer_switch_on_eof) = 0; + + if ( yywrap( ) ) + { + /* Note: because we've taken care in + * yy_get_next_buffer() to have set up + * yytext, we can now set up + * yy_c_buf_p so that if some total + * hoser (like flex itself) wants to + * call the scanner after we return the + * YY_NULL, it'll still work - another + * YY_NULL will get returned. + */ + (yy_c_buf_p) = (yytext_ptr) + YY_MORE_ADJ; + + yy_act = YY_STATE_EOF(YY_START); + goto do_action; + } + + else + { + if ( ! (yy_did_buffer_switch_on_eof) ) + YY_NEW_FILE; + } + break; + } + + case EOB_ACT_CONTINUE_SCAN: + (yy_c_buf_p) = + (yytext_ptr) + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state( ); + + yy_cp = (yy_c_buf_p); + yy_bp = (yytext_ptr) + YY_MORE_ADJ; + goto yy_match; + + case EOB_ACT_LAST_MATCH: + (yy_c_buf_p) = + &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)]; + + yy_current_state = yy_get_previous_state( ); + + yy_cp = (yy_c_buf_p); + yy_bp = (yytext_ptr) + YY_MORE_ADJ; + goto yy_find_action; + } + break; + } + + default: + YY_FATAL_ERROR( + "fatal flex scanner internal error--no action found" ); + } /* end of action switch */ + } /* end of scanning one token */ + } /* end of user's declarations */ +} /* end of yylex */ + +/* yy_get_next_buffer - try to read in a new buffer + * + * Returns a code representing an action: + * EOB_ACT_LAST_MATCH - + * EOB_ACT_CONTINUE_SCAN - continue scanning from current position + * EOB_ACT_END_OF_FILE - end of file + */ +static int yy_get_next_buffer (void) +{ + register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; + register char *source = (yytext_ptr); + register yy_size_t number_to_move, i; + int ret_val; + + if ( (yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] ) + YY_FATAL_ERROR( + "fatal flex scanner internal error--end of buffer missed" ); + + if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 ) + { /* Don't try to fill the buffer, so this is an EOF. */ + if ( (yy_c_buf_p) - (yytext_ptr) - YY_MORE_ADJ == 1 ) + { + /* We matched a single character, the EOB, so + * treat this as a final EOF. + */ + return EOB_ACT_END_OF_FILE; + } + + else + { + /* We matched some text prior to the EOB, first + * process it. + */ + return EOB_ACT_LAST_MATCH; + } + } + + /* Try to read more data. */ + + /* First move last chars to start of buffer. */ + number_to_move = (yy_size_t)(((yy_c_buf_p) - (yytext_ptr)) - 1); + + for ( i = 0; i < number_to_move; ++i ) + *(dest++) = *(source++); + + if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING ) + /* don't do the read, it's not guaranteed to return an EOF, + * just force an EOF + */ + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars) = 0; + + else + { + yy_size_t num_to_read = + YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; + + while ( num_to_read <= 0 ) + { /* Not enough room in the buffer - grow it. */ + + /* just a shorter name for the current buffer */ + YY_BUFFER_STATE b = YY_CURRENT_BUFFER_LVALUE; + + int yy_c_buf_p_offset = + (int) ((yy_c_buf_p) - b->yy_ch_buf); + + if ( b->yy_is_our_buffer ) + { + yy_size_t new_size = b->yy_buf_size * 2; + + if ( new_size <= 0 ) + b->yy_buf_size += b->yy_buf_size / 8; + else + b->yy_buf_size *= 2; + + b->yy_ch_buf = (char *) + /* Include room in for 2 EOB chars. */ + yyrealloc((void *) b->yy_ch_buf,b->yy_buf_size + 2 ); + } + else + /* Can't grow it, we don't own it. */ + b->yy_ch_buf = 0; + + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( + "fatal error - scanner input buffer overflow" ); + + (yy_c_buf_p) = &b->yy_ch_buf[yy_c_buf_p_offset]; + + num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - + number_to_move - 1; + + } + + if ( num_to_read > YY_READ_BUF_SIZE ) + num_to_read = YY_READ_BUF_SIZE; + + /* Read in more data. */ + YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]), + (yy_n_chars), num_to_read ); + + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); + } + + if ( (yy_n_chars) == 0 ) + { + if ( number_to_move == YY_MORE_ADJ ) + { + ret_val = EOB_ACT_END_OF_FILE; + yyrestart(yyin ); + } + + else + { + ret_val = EOB_ACT_LAST_MATCH; + YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = + YY_BUFFER_EOF_PENDING; + } + } + + else + ret_val = EOB_ACT_CONTINUE_SCAN; + + if ((yy_size_t) ((yy_n_chars) + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) { + /* Extend the array by 50%, plus the number we really need. */ + yy_size_t new_size = (yy_n_chars) + number_to_move + ((yy_n_chars) >> 1); + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size ); + if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" ); + } + + (yy_n_chars) += number_to_move; + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] = YY_END_OF_BUFFER_CHAR; + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] = YY_END_OF_BUFFER_CHAR; + + (yytext_ptr) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0]; + + return ret_val; +} + +/* yy_get_previous_state - get the state just before the EOB char was reached */ + + static yy_state_type yy_get_previous_state (void) +{ + register yy_state_type yy_current_state; + register char *yy_cp; + + yy_current_state = (yy_start); + + for ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp ) + { + register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 43); + if ( yy_accept[yy_current_state] ) + { + (yy_last_accepting_state) = yy_current_state; + (yy_last_accepting_cpos) = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 437 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + } + + return yy_current_state; +} + +/* yy_try_NUL_trans - try to make a transition on the NUL character + * + * synopsis + * next_state = yy_try_NUL_trans( current_state ); + */ + static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state ) +{ + register int yy_is_jam; + register char *yy_cp = (yy_c_buf_p); + + register YY_CHAR yy_c = 43; + if ( yy_accept[yy_current_state] ) + { + (yy_last_accepting_state) = yy_current_state; + (yy_last_accepting_cpos) = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 437 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + yy_is_jam = (yy_current_state == 436); + + return yy_is_jam ? 0 : yy_current_state; +} + +#ifndef YY_NO_UNPUT + +#endif + +#ifndef YY_NO_INPUT +#ifdef __cplusplus + static int yyinput (void) +#else + static int input (void) +#endif + +{ + int c; + + *(yy_c_buf_p) = (yy_hold_char); + + if ( *(yy_c_buf_p) == YY_END_OF_BUFFER_CHAR ) + { + /* yy_c_buf_p now points to the character we want to return. + * If this occurs *before* the EOB characters, then it's a + * valid NUL; if not, then we've hit the end of the buffer. + */ + if ( (yy_c_buf_p) < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] ) + /* This was really a NUL. */ + *(yy_c_buf_p) = '\0'; + + else + { /* need more input */ + yy_size_t offset = (yy_size_t) + ((yy_c_buf_p) - (yytext_ptr)); + ++(yy_c_buf_p); + + switch ( yy_get_next_buffer( ) ) + { + case EOB_ACT_LAST_MATCH: + /* This happens because yy_g_n_b() + * sees that we've accumulated a + * token and flags that we need to + * try matching the token before + * proceeding. But for input(), + * there's no matching to consider. + * So convert the EOB_ACT_LAST_MATCH + * to EOB_ACT_END_OF_FILE. + */ + + /* Reset buffer status. */ + yyrestart(yyin ); + + /*FALLTHROUGH*/ + + case EOB_ACT_END_OF_FILE: + { + if ( yywrap( ) ) + return EOF; + + if ( ! (yy_did_buffer_switch_on_eof) ) + YY_NEW_FILE; +#ifdef __cplusplus + return yyinput(); +#else + return input(); +#endif + } + + case EOB_ACT_CONTINUE_SCAN: + (yy_c_buf_p) = (yytext_ptr) + offset; + break; + } + } + } + + c = *(unsigned char *) (yy_c_buf_p); /* cast for 8-bit char's */ + *(yy_c_buf_p) = '\0'; /* preserve yytext */ + (yy_hold_char) = *++(yy_c_buf_p); + + return c; +} +#endif /* ifndef YY_NO_INPUT */ + +/** Immediately switch to a different input stream. + * @param input_file A readable stream. + * + * @note This function does not reset the start condition to @c INITIAL . + */ + void yyrestart (FILE * input_file ) +{ + + if ( ! YY_CURRENT_BUFFER ){ + yyensure_buffer_stack (); + YY_CURRENT_BUFFER_LVALUE = + yy_create_buffer(yyin,YY_BUF_SIZE ); + } + + yy_init_buffer(YY_CURRENT_BUFFER,input_file ); + yy_load_buffer_state( ); +} + +/** Switch to a different input buffer. + * @param new_buffer The new input buffer. + * + */ + void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer ) +{ + + /* TODO. We should be able to replace this entire function body + * with + * yypop_buffer_state(); + * yypush_buffer_state(new_buffer); + */ + yyensure_buffer_stack (); + if ( YY_CURRENT_BUFFER == new_buffer ) + return; + + if ( YY_CURRENT_BUFFER ) + { + /* Flush out information for old buffer. */ + *(yy_c_buf_p) = (yy_hold_char); + YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p); + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); + } + + YY_CURRENT_BUFFER_LVALUE = new_buffer; + yy_load_buffer_state( ); + + /* We don't actually know whether we did this switch during + * EOF (yywrap()) processing, but the only time this flag + * is looked at is after yywrap() is called, so it's safe + * to go ahead and always set it. + */ + (yy_did_buffer_switch_on_eof) = 1; +} + +static void yy_load_buffer_state (void) +{ + (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; + (yytext_ptr) = (yy_c_buf_p) = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos; + yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file; + (yy_hold_char) = *(yy_c_buf_p); +} + +/** Allocate and initialize an input buffer state. + * @param file A readable stream. + * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE. + * + * @return the allocated buffer state. + */ + YY_BUFFER_STATE yy_create_buffer (FILE * file, int size ) +{ + YY_BUFFER_STATE b; + + b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); + + b->yy_buf_size = (yy_size_t)size; + + /* yy_ch_buf has to be 2 characters longer than the size given because + * we need to put in 2 end-of-buffer characters. + */ + b->yy_ch_buf = (char *) yyalloc(b->yy_buf_size + 2 ); + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); + + b->yy_is_our_buffer = 1; + + yy_init_buffer(b,file ); + + return b; +} + +/** Destroy the buffer. + * @param b a buffer created with yy_create_buffer() + * + */ + void yy_delete_buffer (YY_BUFFER_STATE b ) +{ + + if ( ! b ) + return; + + if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */ + YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0; + + if ( b->yy_is_our_buffer ) + yyfree((void *) b->yy_ch_buf ); + + yyfree((void *) b ); +} + +/* Initializes or reinitializes a buffer. + * This function is sometimes called more than once on the same buffer, + * such as during a yyrestart() or at EOF. + */ + static void yy_init_buffer (YY_BUFFER_STATE b, FILE * file ) + +{ + int oerrno = errno; + + yy_flush_buffer(b ); + + b->yy_input_file = file; + b->yy_fill_buffer = 1; + + /* If b is the current buffer, then yy_init_buffer was _probably_ + * called from yyrestart() or through yy_get_next_buffer. + * In that case, we don't want to reset the lineno or column. + */ + if (b != YY_CURRENT_BUFFER){ + b->yy_bs_lineno = 1; + b->yy_bs_column = 0; + } + + b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0; + + errno = oerrno; +} + +/** Discard all buffered characters. On the next scan, YY_INPUT will be called. + * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER. + * + */ + void yy_flush_buffer (YY_BUFFER_STATE b ) +{ + if ( ! b ) + return; + + b->yy_n_chars = 0; + + /* We always need two end-of-buffer characters. The first causes + * a transition to the end-of-buffer state. The second causes + * a jam in that state. + */ + b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR; + b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; + + b->yy_buf_pos = &b->yy_ch_buf[0]; + + b->yy_at_bol = 1; + b->yy_buffer_status = YY_BUFFER_NEW; + + if ( b == YY_CURRENT_BUFFER ) + yy_load_buffer_state( ); +} + +/** Pushes the new state onto the stack. The new state becomes + * the current state. This function will allocate the stack + * if necessary. + * @param new_buffer The new state. + * + */ +void yypush_buffer_state (YY_BUFFER_STATE new_buffer ) +{ + if (new_buffer == NULL) + return; + + yyensure_buffer_stack(); + + /* This block is copied from yy_switch_to_buffer. */ + if ( YY_CURRENT_BUFFER ) + { + /* Flush out information for old buffer. */ + *(yy_c_buf_p) = (yy_hold_char); + YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p); + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); + } + + /* Only push if top exists. Otherwise, replace top. */ + if (YY_CURRENT_BUFFER) + (yy_buffer_stack_top)++; + YY_CURRENT_BUFFER_LVALUE = new_buffer; + + /* copied from yy_switch_to_buffer. */ + yy_load_buffer_state( ); + (yy_did_buffer_switch_on_eof) = 1; +} + +/** Removes and deletes the top of the stack, if present. + * The next element becomes the new top. + * + */ +void yypop_buffer_state (void) +{ + if (!YY_CURRENT_BUFFER) + return; + + yy_delete_buffer(YY_CURRENT_BUFFER ); + YY_CURRENT_BUFFER_LVALUE = NULL; + if ((yy_buffer_stack_top) > 0) + --(yy_buffer_stack_top); + + if (YY_CURRENT_BUFFER) { + yy_load_buffer_state( ); + (yy_did_buffer_switch_on_eof) = 1; + } +} + +/* Allocates the stack if it does not exist. + * Guarantees space for at least one push. + */ +static void yyensure_buffer_stack (void) +{ + yy_size_t num_to_alloc; + + if (!(yy_buffer_stack)) { + + /* First allocation is just for 2 elements, since we don't know if this + * scanner will even need a stack. We use 2 instead of 1 to avoid an + * immediate realloc on the next call. + */ + num_to_alloc = 1; + (yy_buffer_stack) = (struct yy_buffer_state**)yyalloc + (num_to_alloc * sizeof(struct yy_buffer_state*) + ); + if ( ! (yy_buffer_stack) ) + YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); + + memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*)); + + (yy_buffer_stack_max) = num_to_alloc; + (yy_buffer_stack_top) = 0; + return; + } + + if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1){ + + /* Increase the buffer to prepare for a possible push. */ + yy_size_t grow_size = 8 /* arbitrary grow size */; + + num_to_alloc = (yy_buffer_stack_max) + grow_size; + (yy_buffer_stack) = (struct yy_buffer_state**)yyrealloc + ((yy_buffer_stack), + num_to_alloc * sizeof(struct yy_buffer_state*) + ); + if ( ! (yy_buffer_stack) ) + YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); + + /* zero only the new slots.*/ + memset((yy_buffer_stack) + (yy_buffer_stack_max), 0, grow_size * sizeof(struct yy_buffer_state*)); + (yy_buffer_stack_max) = num_to_alloc; + } +} + +/** Setup the input buffer state to scan directly from a user-specified character buffer. + * @param base the character buffer + * @param size the size in bytes of the character buffer + * + * @return the newly allocated buffer state object. + */ +YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size ) +{ + YY_BUFFER_STATE b; + + if ( size < 2 || + base[size-2] != YY_END_OF_BUFFER_CHAR || + base[size-1] != YY_END_OF_BUFFER_CHAR ) + /* They forgot to leave room for the EOB's. */ + return 0; + + b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" ); + + b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */ + b->yy_buf_pos = b->yy_ch_buf = base; + b->yy_is_our_buffer = 0; + b->yy_input_file = 0; + b->yy_n_chars = b->yy_buf_size; + b->yy_is_interactive = 0; + b->yy_at_bol = 1; + b->yy_fill_buffer = 0; + b->yy_buffer_status = YY_BUFFER_NEW; + + yy_switch_to_buffer(b ); + + return b; +} + +/** Setup the input buffer state to scan a string. The next call to yylex() will + * scan from a @e copy of @a str. + * @param yystr a NUL-terminated string to scan + * + * @return the newly allocated buffer state object. + * @note If you want to scan bytes that may contain NUL values, then use + * yy_scan_bytes() instead. + */ +YY_BUFFER_STATE yy_scan_string (yyconst char * yystr ) +{ + + return yy_scan_bytes(yystr,strlen(yystr) ); +} + +/** Setup the input buffer state to scan the given bytes. The next call to yylex() will + * scan from a @e copy of @a bytes. + * @param yybytes the byte buffer to scan + * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes. + * + * @return the newly allocated buffer state object. + */ +YY_BUFFER_STATE yy_scan_bytes (yyconst char * yybytes, yy_size_t _yybytes_len ) +{ + YY_BUFFER_STATE b; + char *buf; + yy_size_t n; + yy_size_t i; + + /* Get memory for full buffer, including space for trailing EOB's. */ + n = _yybytes_len + 2; + buf = (char *) yyalloc(n ); + if ( ! buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" ); + + for ( i = 0; i < _yybytes_len; ++i ) + buf[i] = yybytes[i]; + + buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR; + + b = yy_scan_buffer(buf,n ); + if ( ! b ) + YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" ); + + /* It's okay to grow etc. this buffer, and we should throw it + * away when we're done. + */ + b->yy_is_our_buffer = 1; + + return b; +} + +#ifndef YY_EXIT_FAILURE +#define YY_EXIT_FAILURE 2 +#endif + +static void yy_fatal_error (yyconst char* msg ) +{ + (void) fprintf( stderr, "%s\n", msg ); + exit( YY_EXIT_FAILURE ); +} + +/* Redefine yyless() so it works in section 3 code. */ + +#undef yyless +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + int yyless_macro_arg = (n); \ + YY_LESS_LINENO(yyless_macro_arg);\ + yytext[yyleng] = (yy_hold_char); \ + (yy_c_buf_p) = yytext + yyless_macro_arg; \ + (yy_hold_char) = *(yy_c_buf_p); \ + *(yy_c_buf_p) = '\0'; \ + yyleng = yyless_macro_arg; \ + } \ + while ( 0 ) + +/* Accessor methods (get/set functions) to struct members. */ + +/** Get the current line number. + * + */ +int yyget_lineno (void) +{ + + return yylineno; +} + +/** Get the input stream. + * + */ +FILE *yyget_in (void) +{ + return yyin; +} + +/** Get the output stream. + * + */ +FILE *yyget_out (void) +{ + return yyout; +} + +/** Get the length of the current token. + * + */ +yy_size_t yyget_leng (void) +{ + return yyleng; +} + +/** Get the current token. + * + */ + +char *yyget_text (void) +{ + return yytext; +} + +/** Set the current line number. + * @param _line_number + * + */ +void yyset_lineno (int _line_number ) +{ + + yylineno = _line_number; +} + +/** Set the input stream. This does not discard the current + * input buffer. + * @param _in_str A readable stream. + * + * @see yy_switch_to_buffer + */ +void yyset_in (FILE * _in_str ) +{ + yyin = _in_str ; +} + +void yyset_out (FILE * _out_str ) +{ + yyout = _out_str ; +} + +int yyget_debug (void) +{ + return yy_flex_debug; +} + +void yyset_debug (int _bdebug ) +{ + yy_flex_debug = _bdebug ; +} + +static int yy_init_globals (void) +{ + /* Initialization is the same as for the non-reentrant scanner. + * This function is called from yylex_destroy(), so don't allocate here. + */ + + (yy_buffer_stack) = 0; + (yy_buffer_stack_top) = 0; + (yy_buffer_stack_max) = 0; + (yy_c_buf_p) = (char *) 0; + (yy_init) = 0; + (yy_start) = 0; + +/* Defined in main.c */ +#ifdef YY_STDINIT + yyin = stdin; + yyout = stdout; +#else + yyin = (FILE *) 0; + yyout = (FILE *) 0; +#endif + + /* For future reference: Set errno on error, since we are called by + * yylex_init() + */ + return 0; +} + +/* yylex_destroy is for both reentrant and non-reentrant scanners. */ +int yylex_destroy (void) +{ + + /* Pop the buffer stack, destroying each element. */ + while(YY_CURRENT_BUFFER){ + yy_delete_buffer(YY_CURRENT_BUFFER ); + YY_CURRENT_BUFFER_LVALUE = NULL; + yypop_buffer_state(); + } + + /* Destroy the stack itself. */ + yyfree((yy_buffer_stack) ); + (yy_buffer_stack) = NULL; + + /* Reset the globals. This is important in a non-reentrant scanner so the next time + * yylex() is called, initialization will occur. */ + yy_init_globals( ); + + return 0; +} + +/* + * Internal utility routines. + */ + +#ifndef yytext_ptr +static void yy_flex_strncpy (char* s1, yyconst char * s2, int n ) +{ + register int i; + for ( i = 0; i < n; ++i ) + s1[i] = s2[i]; +} +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen (yyconst char * s ) +{ + register int n; + for ( n = 0; s[n]; ++n ) + ; + + return n; +} +#endif + +void *yyalloc (yy_size_t size ) +{ + return (void *) malloc( size ); +} + +void *yyrealloc (void * ptr, yy_size_t size ) +{ + /* The cast to (char *) in the following accommodates both + * implementations that use char* generic pointers, and those + * that use void* generic pointers. It works with the latter + * because both ANSI C and C++ allow castless assignment from + * any pointer type to void*, and deal with argument conversions + * as though doing an assignment. + */ + return (void *) realloc( (char *) ptr, size ); +} + +void yyfree (void * ptr ) +{ + free( (char *) ptr ); /* see yyrealloc() for (char *) cast */ +} + +#define YYTABLES_NAME "yytables" + +#line 383 "scan.l" + + + +int interesting = 1; + +static int +curdir_push(const char *fname) +{ + struct prefix *pf; + char *p, *d, *f; + + /* Set up the initial "current directory" for include directives. */ + d = dirname(f = estrdup(fname)); + if (*d == '/') + p = estrdup(d); + else { + char *cwd, buf[PATH_MAX]; + + if ((cwd = getcwd(buf, sizeof(buf))) == NULL) { + free(f); + return (-1); + } + easprintf(&p, "%s/%s", cwd, d); + } + free(f); + pf = ecalloc(1, sizeof(*pf)); + pf->pf_prefix = p; + SLIST_INSERT_HEAD(&curdirs, pf, pf_next); + + return (0); +} + +static void +curdir_pop(void) +{ + struct prefix *pf; + + pf = SLIST_FIRST(&curdirs); + SLIST_REMOVE_HEAD(&curdirs, pf_next); + if (SLIST_EMPTY(&curdirs)) + panic("curdirs is empty"); + /* LINTED cast away const (pf_prefix is malloc'd for curdirs) */ + free((void *)__UNCONST(pf->pf_prefix)); + free(pf); +} + +/* + * Open the "main" file (conffile). + */ +int +firstfile(const char *fname) +{ + +#if defined(__NetBSD__) + if ((yyin = fopen(fname, "rf")) == NULL) +#else + if ((yyin = fopen(fname, "r")) == NULL) +#endif + return (-1); + + if (curdir_push(fname) == -1) + return (-1); + + yyfile = conffile = fname; + yyline = 1; + return (0); +} + +/* + * Add a "package" to the configuration. This is essentially + * syntactic sugar around the sequence: + * + * prefix ../some/directory + * include "files.package" + * prefix + */ +void +package(const char *fname) +{ + char *fname1 = estrdup(fname); + char *fname2 = estrdup(fname); + char *dir = dirname(fname1); + char *file = basename(fname2); + + /* + * Push the prefix on to the prefix stack and process the include + * file. When we reach the end of the include file, inserting + * the PREFIX token into the input stream will pop the prefix off + * of the prefix stack. + */ + prefix_push(dir); + (void) include(file, PREFIX, 0, 1); + + free(fname1); + free(fname2); +} + +int includedepth; + +/* + * Open the named file for inclusion at the current point. Returns 0 on + * success (file opened and previous state pushed), nonzero on failure + * (fopen failed, complaint made). The `ateof' parameter controls the + * token to be inserted at the end of the include file (i.e. ENDFILE). + * If ateof == 0 then nothing is inserted. + */ +int +include(const char *fname, int ateof, int conditional, int direct) +{ + FILE *fp; + struct incl *in; + char *s; + static int havedirs; + extern int vflag; + + if (havedirs == 0) { + havedirs = 1; + setupdirs(); + } + + if (fname[0] == '/') + s = estrdup(fname); + else if (fname[0] == '.' && fname[1] == '/') { + struct prefix *pf = SLIST_FIRST(&curdirs); + easprintf(&s, "%s/%s", pf->pf_prefix, fname + 2); + } else + s = sourcepath(fname); + if ((fp = fopen(s, "r")) == NULL) { + if (conditional == 0) + cfgerror("cannot open %s for reading: %s", s, + strerror(errno)); + else if (vflag) + cfgwarn("cannot open conditional include file %s: %s", + s, strerror(errno)); + free(s); + return (-1); + } + if (curdir_push(s) == -1) { + cfgerror("cannot record current working directory for %s", s); + fclose(fp); + free(s); + return (-1); + } + in = ecalloc(1, sizeof *in); + in->in_prev = incl; + in->in_buf = YY_CURRENT_BUFFER; + in->in_fname = yyfile; + in->in_lineno = yyline; + in->in_ateof = ateof; + in->in_interesting = interesting; + in->in_ifdefstate = ifdefstate; + interesting = direct & interesting; + if (interesting) + logconfig_include(fp, fname); + incl = in; + CFGDBG(1, "include `%s' from `%s' line %d", fname, yyfile, yyline); + yy_switch_to_buffer(yy_create_buffer(fp,YY_BUF_SIZE)); + yyfile = intern(s); + yyline = 1; + free(s); + includedepth++; + return (0); +} + +/* + * Extract the pathname from a include/cinclude/package into curinclpath + */ +static int +getincludepath(void) +{ + const char *p = yytext; + ptrdiff_t len; + const char *e; + + while (*p && isascii((unsigned int)*p) && !isspace((unsigned int)*p)) + p++; + while (*p && isascii((unsigned int)*p) && isspace((unsigned int)*p)) + p++; + if (!*p) + return 0; + if (*p == '"') { + p++; + e = strchr(p, '"'); + if (!e) return 0; + } else { + e = p; + while (*e && isascii((unsigned int)*e) + && !isspace((unsigned int)*e)) + e++; + } + + len = e-p; + if (len > (ptrdiff_t)sizeof(curinclpath)-1) + len = sizeof(curinclpath)-1; + strncpy(curinclpath, p, sizeof(curinclpath)); + curinclpath[len] = '\0'; + + return 1; +} + +/* + * Terminate the most recent inclusion. + */ +static int +endinclude(void) +{ + struct incl *in; + int ateof; + + curdir_pop(); + if ((in = incl) == NULL) + panic("endinclude"); + incl = in->in_prev; + lastfile = yyfile; + yy_delete_buffer(YY_CURRENT_BUFFER); + (void)fclose(yyin); + yy_switch_to_buffer(in->in_buf); + yyfile = in->in_fname; + yyline = in->in_lineno; + ateof = in->in_ateof; + interesting = in->in_interesting; + free(in); + + includedepth--; + + return (ateof); +} + +/* + * Return the current line number. If yacc has looked ahead and caused + * us to consume a newline, we have to subtract one. yychar is yacc's + * token lookahead, so we can tell. + */ +u_short +currentline(void) +{ + extern int yychar; + + return (u_short)(yyline - (yychar == '\n')); +} + +static int +getcurifdef(void) +{ + char *p = yytext, *q; + + while (*p && isascii((unsigned int)*p) && !isspace((unsigned int)*p)) + p++; + while (*p && isascii((unsigned int)*p) && isspace((unsigned int)*p)) + p++; + q = p; + while (*q && isascii((unsigned int)*q) && !isspace((unsigned int)*q)) + q++; + *q = '\0'; + + return ht_lookup(attrtab, intern(p)) != NULL; +} + diff --git a/usr.bin/config/scan.l b/usr.bin/config/scan.l new file mode 100644 index 000000000..1c4209fe8 --- /dev/null +++ b/usr.bin/config/scan.l @@ -0,0 +1,638 @@ +%{ +/* $NetBSD: scan.l,v 1.25 2015/09/04 10:16:35 uebayasi Exp $ */ + +/* + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Lawrence Berkeley Laboratories. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * from: @(#)scan.l 8.1 (Berkeley) 6/6/93 + */ + +#include +__RCSID("$NetBSD: scan.l,v 1.25 2015/09/04 10:16:35 uebayasi Exp $"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#undef ECHO +#include "defs.h" +#include "gram.h" + +int yyline; +const char *yyfile; +const char *lastfile; +char curinclpath[PATH_MAX]; +int ifdefstate = -1; +int st; +#define IDS_PARENT_DISABLED \ + ((ifdefstate > 6) && ((((ifdefstate/6)-1) & 1) == 1)) +#define IDS_MAX_DEPTH 362797056 /* 6^11 */ +/* States for ifdefstate: + + 0 -> matched ifdef + 1 -> unmatched ifdef + 2 -> matched elifdef + 3 -> unmatched elifdef + 4 -> matched else + 5 -> unmatched else + + Upon "ifdef", add one and multiply by 6. + Upon "endif", divide by 6, remove 1. + + ifdef -> MATCH => continue + MISMATCH => set to 1 + elifdef -> if (!1) -> MISMATCH + MATCH => set to 2 + MISMATCH => if (2 || 3) set to 3, else set to 1 + else -> if (1) -> MATCH + MATCH => set to 4 + MISMATCH => set to 5 + + in each case, if parent & 1 == 1, MISMATCH +*/ + +/* + * Data for returning to previous files from include files. + */ +struct incl { + struct incl *in_prev; /* previous includes in effect, if any */ + YY_BUFFER_STATE in_buf; /* previous lex state */ + const char *in_fname; /* previous file name */ + int in_lineno; /* previous line number */ + int in_ateof; /* token to insert at EOF */ + int in_interesting; /* previous value for "interesting" */ + int in_ifdefstate; /* conditional level */ +}; +static struct incl *incl; +static int endinclude(void); +static int getincludepath(void); +static int getcurifdef(void); + + +%} + +%option noyywrap nounput noinput + +PATH [A-Za-z_0-9]*[./][-A-Za-z_0-9./]* +QCHARS \"(\\.|[^\\"])*\" +WORD [A-Za-z_][-A-Za-z_0-9]* +FILENAME ({PATH}|{QCHARS}) +RESTOFLINE [ \t]*(#[^\n]*)?\n + +%x IGNORED + +%% + /* Local variables for yylex() */ + int tok; + +and return AND; +at return AT; +attach return ATTACH; +block return BLOCK; +build return BUILD; +char return CHAR; +compile-with return COMPILE_WITH; +config return CONFIG; +deffs return DEFFS; +define return DEFINE; +defflag return DEFFLAG; +defopt return DEFOPT; +defparam return DEFPARAM; +defpseudo return DEFPSEUDO; +defpseudodev return DEFPSEUDODEV; +devclass return DEVCLASS; +device return DEVICE; +device-major return DEVICE_MAJOR; +dumps return DUMPS; +file return XFILE; +file-system return FILE_SYSTEM; +flags return FLAGS; +ident return IDENT; +ioconf return IOCONF; +linkzero return LINKZERO; +machine return XMACHINE; +major return MAJOR; +makeoptions return MAKEOPTIONS; +maxpartitions return MAXPARTITIONS; +maxusers return MAXUSERS; +minor return MINOR; +needs-count return NEEDS_COUNT; +needs-flag return NEEDS_FLAG; +no return NO; +object return XOBJECT; +obsolete return OBSOLETE; +on return ON; +options return OPTIONS; +prefix return PREFIX; +buildprefix return BUILDPREFIX; +pseudo-device return PSEUDO_DEVICE; +pseudo-root return PSEUDO_ROOT; +root return ROOT; +select return SELECT; +single return SINGLE; +source return SOURCE; +type return TYPE; +vector return VECTOR; +version return VERSION; +with return WITH; + +\+= return PLUSEQ; +:= return COLONEQ; + +<*>ifdef[ \t]+{WORD}{RESTOFLINE} { + ifdefstate = (ifdefstate + 1) * 6; + if (ifdefstate >= IDS_MAX_DEPTH) { + yyerror("too many levels of conditional"); + } + if (!IDS_PARENT_DISABLED && getcurifdef()) { + BEGIN(INITIAL); + } else { + ifdefstate++; + BEGIN(IGNORED); + } + yyline++; + } + +<*>ifndef[ \t]+{WORD}{RESTOFLINE} { + ifdefstate = (ifdefstate + 1) * 6; + if (ifdefstate >= IDS_MAX_DEPTH) { + yyerror("too many levels of conditional"); + } + if (!IDS_PARENT_DISABLED && !getcurifdef()) { + BEGIN(INITIAL); + } else { + ifdefstate++; + BEGIN(IGNORED); + } + yyline++; + } + + +<*>elifdef[ \t]+{WORD}{RESTOFLINE} { + st = ifdefstate % 6; + if (ifdefstate < 0 || st > 3) { + yyerror("mismatched elifdef"); + } + if (IDS_PARENT_DISABLED || + st != 1 || !getcurifdef()) { + if (st == 2 || st == 3) { + ifdefstate += 3 - st; + } else { + ifdefstate += 1 - st; + } + BEGIN(IGNORED); + } else { + ifdefstate++; + BEGIN(INITIAL); + } + yyline++; + } + +<*>elifndef[ \t]+{WORD}{RESTOFLINE} { + st = ifdefstate % 6; + if (ifdefstate < 0 || st > 3) { + yyerror("mismatched elifndef"); + } + if (IDS_PARENT_DISABLED || + st != 1 || getcurifdef()) { + if (st == 2 || st == 3) { + ifdefstate += 3 - st; + } else { + ifdefstate += 1 - st; + } + BEGIN(IGNORED); + } else { + ifdefstate++; + BEGIN(INITIAL); + } + yyline++; + } + +<*>else{RESTOFLINE} { + st = ifdefstate % 6; + if (ifdefstate < 0 || st > 3) { + yyerror("mismatched else"); + } + if (!IDS_PARENT_DISABLED && (st == 1)) { + ifdefstate += 3; + BEGIN(INITIAL); + } else { + ifdefstate += 5 - st; + BEGIN(IGNORED); + } + yyline++; + } + +<*>endif{RESTOFLINE} { + if (ifdefstate < 0) { + yyerror("mismatched endif"); + } + if (!IDS_PARENT_DISABLED) { + BEGIN(INITIAL); + } + ifdefstate = (ifdefstate/6) - 1; + yyline++; + } + +\n { + yyline++; + } + +. /* ignore */ + +include[ \t]+{FILENAME}{RESTOFLINE} { + yyline++; + if (getincludepath()) { + include(curinclpath, 0, 0, 1); + } else { + yyerror("bad include path-name"); + } + } + +cinclude[ \t]+{FILENAME}{RESTOFLINE} { + yyline++; + if (getincludepath()) { + include(curinclpath, 0, 1, 1); + } else { + yyerror("bad cinclude path-name"); + } + } + +package[ \t]+{FILENAME}{RESTOFLINE} { + yyline++; + if (!oktopackage) { + yyerror("package not allowed here"); + } else if (getincludepath()) { + package(curinclpath); + } else { + yyerror("bad package path-name"); + } + } + +{PATH} { + yylval.str = intern(yytext); + return PATHNAME; + } + +{WORD} { + yylval.str = intern(yytext); + return WORD; + } + +\"\" { + yylval.str = intern(""); + return EMPTYSTRING; + } + +{QCHARS} { + size_t l = strlen(yytext); + if (l > 1 && yytext[l - 1] == '"') + yytext[l - 1] = '\0'; + + yylval.str = intern(yytext + 1); + return QSTRING; + } +0[0-7]* { + yylval.num.fmt = 8; + yylval.num.val = strtoll(yytext, NULL, 8); + return NUMBER; + } +0[xX][0-9a-fA-F]+ { + yylval.num.fmt = 16; + yylval.num.val = (long long)strtoull(yytext + 2, NULL, 16); + return NUMBER; + } +[1-9][0-9]* { + yylval.num.fmt = 10; + yylval.num.val = strtoll(yytext, NULL, 10); + return NUMBER; + } +\n[ \t] { + /* + * Note: newline followed by whitespace is always a + * continuation of the previous line, so do NOT + * return a token in this case. + */ + yyline++; + } +\n { + yyline++; + return '\n'; + } +\00 { + /* Detect NUL characters in the config file and + * error out. + */ + cfgerror("NUL character detected at line %i", yyline); + } +#.* { /* ignored (comment) */; } +[ \t]+ { /* ignored (white space) */; } +. { return yytext[0]; } +<*><> { + if (ifdefstate > (incl == NULL ? -1 : incl->in_ifdefstate)) { + yyerror("reached EOF while looking for endif"); + } + if (incl == NULL) + return YY_NULL; + tok = endinclude(); + if (tok) + return tok; + /* otherwise continue scanning */ + } + +%% + +int interesting = 1; + +static int +curdir_push(const char *fname) +{ + struct prefix *pf; + char *p, *d, *f; + + /* Set up the initial "current directory" for include directives. */ + d = dirname(f = estrdup(fname)); + if (*d == '/') + p = estrdup(d); + else { + char *cwd, buf[PATH_MAX]; + + if ((cwd = getcwd(buf, sizeof(buf))) == NULL) { + free(f); + return (-1); + } + easprintf(&p, "%s/%s", cwd, d); + } + free(f); + pf = ecalloc(1, sizeof(*pf)); + pf->pf_prefix = p; + SLIST_INSERT_HEAD(&curdirs, pf, pf_next); + + return (0); +} + +static void +curdir_pop(void) +{ + struct prefix *pf; + + pf = SLIST_FIRST(&curdirs); + SLIST_REMOVE_HEAD(&curdirs, pf_next); + if (SLIST_EMPTY(&curdirs)) + panic("curdirs is empty"); + /* LINTED cast away const (pf_prefix is malloc'd for curdirs) */ + free((void *)__UNCONST(pf->pf_prefix)); + free(pf); +} + +/* + * Open the "main" file (conffile). + */ +int +firstfile(const char *fname) +{ + +#if defined(__NetBSD__) + if ((yyin = fopen(fname, "rf")) == NULL) +#else + if ((yyin = fopen(fname, "r")) == NULL) +#endif + return (-1); + + if (curdir_push(fname) == -1) + return (-1); + + yyfile = conffile = fname; + yyline = 1; + return (0); +} + +/* + * Add a "package" to the configuration. This is essentially + * syntactic sugar around the sequence: + * + * prefix ../some/directory + * include "files.package" + * prefix + */ +void +package(const char *fname) +{ + char *fname1 = estrdup(fname); + char *fname2 = estrdup(fname); + char *dir = dirname(fname1); + char *file = basename(fname2); + + /* + * Push the prefix on to the prefix stack and process the include + * file. When we reach the end of the include file, inserting + * the PREFIX token into the input stream will pop the prefix off + * of the prefix stack. + */ + prefix_push(dir); + (void) include(file, PREFIX, 0, 1); + + free(fname1); + free(fname2); +} + +int includedepth; + +/* + * Open the named file for inclusion at the current point. Returns 0 on + * success (file opened and previous state pushed), nonzero on failure + * (fopen failed, complaint made). The `ateof' parameter controls the + * token to be inserted at the end of the include file (i.e. ENDFILE). + * If ateof == 0 then nothing is inserted. + */ +int +include(const char *fname, int ateof, int conditional, int direct) +{ + FILE *fp; + struct incl *in; + char *s; + static int havedirs; + extern int vflag; + + if (havedirs == 0) { + havedirs = 1; + setupdirs(); + } + + if (fname[0] == '/') + s = estrdup(fname); + else if (fname[0] == '.' && fname[1] == '/') { + struct prefix *pf = SLIST_FIRST(&curdirs); + easprintf(&s, "%s/%s", pf->pf_prefix, fname + 2); + } else + s = sourcepath(fname); + if ((fp = fopen(s, "r")) == NULL) { + if (conditional == 0) + cfgerror("cannot open %s for reading: %s", s, + strerror(errno)); + else if (vflag) + cfgwarn("cannot open conditional include file %s: %s", + s, strerror(errno)); + free(s); + return (-1); + } + if (curdir_push(s) == -1) { + cfgerror("cannot record current working directory for %s", s); + fclose(fp); + free(s); + return (-1); + } + in = ecalloc(1, sizeof *in); + in->in_prev = incl; + in->in_buf = YY_CURRENT_BUFFER; + in->in_fname = yyfile; + in->in_lineno = yyline; + in->in_ateof = ateof; + in->in_interesting = interesting; + in->in_ifdefstate = ifdefstate; + interesting = direct & interesting; + if (interesting) + logconfig_include(fp, fname); + incl = in; + CFGDBG(1, "include `%s' from `%s' line %d", fname, yyfile, yyline); + yy_switch_to_buffer(yy_create_buffer(fp, YY_BUF_SIZE)); + yyfile = intern(s); + yyline = 1; + free(s); + includedepth++; + return (0); +} + +/* + * Extract the pathname from a include/cinclude/package into curinclpath + */ +static int +getincludepath(void) +{ + const char *p = yytext; + ptrdiff_t len; + const char *e; + + while (*p && isascii((unsigned int)*p) && !isspace((unsigned int)*p)) + p++; + while (*p && isascii((unsigned int)*p) && isspace((unsigned int)*p)) + p++; + if (!*p) + return 0; + if (*p == '"') { + p++; + e = strchr(p, '"'); + if (!e) return 0; + } else { + e = p; + while (*e && isascii((unsigned int)*e) + && !isspace((unsigned int)*e)) + e++; + } + + len = e-p; + if (len > (ptrdiff_t)sizeof(curinclpath)-1) + len = sizeof(curinclpath)-1; + strncpy(curinclpath, p, sizeof(curinclpath)); + curinclpath[len] = '\0'; + + return 1; +} + +/* + * Terminate the most recent inclusion. + */ +static int +endinclude(void) +{ + struct incl *in; + int ateof; + + curdir_pop(); + if ((in = incl) == NULL) + panic("endinclude"); + incl = in->in_prev; + lastfile = yyfile; + yy_delete_buffer(YY_CURRENT_BUFFER); + (void)fclose(yyin); + yy_switch_to_buffer(in->in_buf); + yyfile = in->in_fname; + yyline = in->in_lineno; + ateof = in->in_ateof; + interesting = in->in_interesting; + free(in); + + includedepth--; + + return (ateof); +} + +/* + * Return the current line number. If yacc has looked ahead and caused + * us to consume a newline, we have to subtract one. yychar is yacc's + * token lookahead, so we can tell. + */ +u_short +currentline(void) +{ + extern int yychar; + + return (u_short)(yyline - (yychar == '\n')); +} + +static int +getcurifdef(void) +{ + char *p = yytext, *q; + + while (*p && isascii((unsigned int)*p) && !isspace((unsigned int)*p)) + p++; + while (*p && isascii((unsigned int)*p) && isspace((unsigned int)*p)) + p++; + q = p; + while (*q && isascii((unsigned int)*q) && !isspace((unsigned int)*q)) + q++; + *q = '\0'; + + return ht_lookup(attrtab, intern(p)) != NULL; +} diff --git a/usr.bin/config/sem.c b/usr.bin/config/sem.c new file mode 100644 index 000000000..d3697748b --- /dev/null +++ b/usr.bin/config/sem.c @@ -0,0 +1,2177 @@ +/* $NetBSD: sem.c,v 1.73 2015/08/29 07:24:49 uebayasi Exp $ */ + +/* + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Lawrence Berkeley Laboratories. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * from: @(#)sem.c 8.1 (Berkeley) 6/6/93 + */ + +#if HAVE_NBTOOL_CONFIG_H +#include "nbtool_config.h" +#endif + +#include +__RCSID("$NetBSD: sem.c,v 1.73 2015/08/29 07:24:49 uebayasi Exp $"); + +#include +#include +#include +#include +#include +#include +#include "defs.h" +#include "sem.h" + +/* + * config semantics. + */ + +#define NAMESIZE 100 /* local name buffers */ + +const char *s_ifnet; /* magic attribute */ +const char *s_qmark; +const char *s_none; + +static struct hashtab *cfhashtab; /* for config lookup */ +struct hashtab *devitab; /* etc */ +struct attr allattr; +size_t nattrs; + +static struct attr errattr; +static struct devbase errdev; +static struct deva errdeva; + +static int has_errobj(struct attrlist *, struct attr *); +static struct nvlist *addtoattr(struct nvlist *, struct devbase *); +static int resolve(struct nvlist **, const char *, const char *, + struct nvlist *, int); +static struct pspec *getpspec(struct attr *, struct devbase *, int); +static struct devi *newdevi(const char *, int, struct devbase *d); +static struct devi *getdevi(const char *); +static void remove_devi(struct devi *); +static const char *concat(const char *, int); +static char *extend(char *, const char *); +static int split(const char *, size_t, char *, size_t, int *); +static void selectbase(struct devbase *, struct deva *); +static const char **fixloc(const char *, struct attr *, struct loclist *); +static const char *makedevstr(devmajor_t, devminor_t); +static const char *major2name(devmajor_t); +static devmajor_t dev2major(struct devbase *); + +extern const char *yyfile; +extern int vflag; + +void +initsem(void) +{ + + attrtab = ht_new(); + attrdeptab = ht_new(); + + allattr.a_name = "netbsd"; + TAILQ_INIT(&allattr.a_files); + (void)ht_insert(attrtab, allattr.a_name, &allattr); + selectattr(&allattr); + + errattr.a_name = ""; + + TAILQ_INIT(&allbases); + + TAILQ_INIT(&alldevas); + + TAILQ_INIT(&allpspecs); + + cfhashtab = ht_new(); + TAILQ_INIT(&allcf); + + TAILQ_INIT(&alldevi); + errdev.d_name = ""; + + TAILQ_INIT(&allpseudo); + + TAILQ_INIT(&alldevms); + + s_ifnet = intern("ifnet"); + s_qmark = intern("?"); + s_none = intern("none"); +} + +/* Name of include file just ended (set in scan.l) */ +extern const char *lastfile; + +static struct attr * +finddep(struct attr *a, const char *name) +{ + struct attrlist *al; + + for (al = a->a_deps; al != NULL; al = al->al_next) { + struct attr *this = al->al_this; + if (strcmp(this->a_name, name) == 0) + return this; + } + return NULL; +} + +static void +mergedeps(const char *dname, const char *name) +{ + struct attr *a, *newa; + + CFGDBG(4, "merging attr `%s' to devbase `%s'", name, dname); + a = refattr(dname); + if (finddep(a, name) == NULL) { + newa = refattr(name); + a->a_deps = attrlist_cons(a->a_deps, newa); + CFGDBG(3, "attr `%s' merged to attr `%s'", newa->a_name, + a->a_name); + } +} + +static void +fixdev(struct devbase *dev) +{ + struct attrlist *al; + struct attr *devattr, *a; + + devattr = refattr(dev->d_name); + if (devattr->a_devclass) + panic("%s: dev %s is devclass!", __func__, devattr->a_name); + + CFGDBG(4, "fixing devbase `%s'", dev->d_name); + for (al = dev->d_attrs; al != NULL; al = al->al_next) { + a = al->al_this; + CFGDBG(4, "fixing devbase `%s' attr `%s'", dev->d_name, a->a_name); + if (a->a_iattr) { + a->a_refs = addtoattr(a->a_refs, dev); + CFGDBG(3, "device `%s' has iattr `%s'", dev->d_name, + a->a_name); + } else if (a->a_devclass != NULL) { + if (dev->d_classattr != NULL && dev->d_classattr != a) { + cfgwarn("device `%s' has multiple classes " + "(`%s' and `%s')", + dev->d_name, dev->d_classattr->a_name, + a->a_name); + } + if (dev->d_classattr == NULL) { + dev->d_classattr = a; + CFGDBG(3, "device `%s' is devclass `%s'", dev->d_name, + a->a_name); + } + } else { + if (strcmp(dev->d_name, a->a_name) != 0) { + mergedeps(dev->d_name, a->a_name); + } + } + } +} + +void +enddefs(void) +{ + struct devbase *dev; + + yyfile = "enddefs"; + + TAILQ_FOREACH(dev, &allbases, d_next) { + if (!dev->d_isdef) { + (void)fprintf(stderr, + "%s: device `%s' used but not defined\n", + lastfile, dev->d_name); + errors++; + continue; + } + fixdev(dev); + } + if (errors) { + (void)fprintf(stderr, "*** Stop.\n"); + exit(1); + } +} + +void +setdefmaxusers(int min, int def, int max) +{ + + if (min < 1 || min > def || def > max) + cfgerror("maxusers must have 1 <= min (%d) <= default (%d) " + "<= max (%d)", min, def, max); + else { + minmaxusers = min; + defmaxusers = def; + maxmaxusers = max; + } +} + +void +setmaxusers(int n) +{ + + if (maxusers == n) { + cfgerror("duplicate maxusers parameter"); + return; + } + if (vflag && maxusers != 0) + cfgwarn("warning: maxusers already defined"); + maxusers = n; + if (n < minmaxusers) { + cfgerror("warning: minimum of %d maxusers assumed", + minmaxusers); + errors--; /* take it away */ + maxusers = minmaxusers; + } else if (n > maxmaxusers) { + cfgerror("warning: maxusers (%d) > %d", n, maxmaxusers); + errors--; + } +} + +void +setident(const char *i) +{ + + if (i) + ident = intern(i); + else + ident = NULL; +} + +/* + * Define an attribute, optionally with an interface (a locator list) + * and a set of attribute-dependencies. + * + * Attribute dependencies MAY NOT be interface attributes. + * + * Since an empty locator list is logically different from "no interface", + * all locator lists include a dummy head node, which we discard here. + */ +int +defattr0(const char *name, struct loclist *locs, struct attrlist *deps, + int devclass) +{ + + if (locs != NULL) + return defiattr(name, locs, deps, devclass); + else if (devclass) + return defdevclass(name, locs, deps, devclass); + else + return defattr(name, locs, deps, devclass); +} + +int +defattr(const char *name, struct loclist *locs, struct attrlist *deps, + int devclass) +{ + struct attr *a, *dep; + struct attrlist *al; + + /* + * If this attribute depends on any others, make sure none of + * the dependencies are interface attributes. + */ + for (al = deps; al != NULL; al = al->al_next) { + dep = al->al_this; + if (dep->a_iattr) { + cfgerror("`%s' dependency `%s' is an interface " + "attribute", name, dep->a_name); + return (1); + } + (void)ht_insert2(attrdeptab, name, dep->a_name, NULL); + CFGDBG(2, "attr `%s' depends on attr `%s'", name, dep->a_name); + } + + if (getrefattr(name, &a)) { + cfgerror("attribute `%s' already defined", name); + loclist_destroy(locs); + return (1); + } + if (a == NULL) + a = mkattr(name); + + a->a_deps = deps; + expandattr(a, NULL); + CFGDBG(3, "attr `%s' defined", a->a_name); + + return (0); +} + +struct attr * +mkattr(const char *name) +{ + struct attr *a; + + a = ecalloc(1, sizeof *a); + if (ht_insert(attrtab, name, a)) { + free(a); + return NULL; + } + a->a_name = name; + TAILQ_INIT(&a->a_files); + CFGDBG(3, "attr `%s' allocated", name); + + return a; +} + +/* "interface attribute" initialization */ +int +defiattr(const char *name, struct loclist *locs, struct attrlist *deps, + int devclass) +{ + struct attr *a; + int len; + struct loclist *ll; + + if (devclass) + panic("defattr(%s): locators and devclass", name); + + if (defattr(name, locs, deps, devclass) != 0) + return (1); + + a = getattr(name); + a->a_iattr = 1; + /* unwrap */ + a->a_locs = locs->ll_next; + locs->ll_next = NULL; + loclist_destroy(locs); + len = 0; + for (ll = a->a_locs; ll != NULL; ll = ll->ll_next) + len++; + a->a_loclen = len; + if (deps) + CFGDBG(2, "attr `%s' iface with deps", a->a_name); + return (0); +} + +/* "device class" initialization */ +int +defdevclass(const char *name, struct loclist *locs, struct attrlist *deps, + int devclass) +{ + struct attr *a; + char classenum[256], *cp; + int errored = 0; + + if (deps) + panic("defattr(%s): dependencies and devclass", name); + + if (defattr(name, locs, deps, devclass) != 0) + return (1); + + a = getattr(name); + (void)snprintf(classenum, sizeof(classenum), "DV_%s", name); + for (cp = classenum + 3; *cp; cp++) { + if (!errored && + (!isalnum((unsigned char)*cp) || + (isalpha((unsigned char)*cp) && !islower((unsigned char)*cp)))) { + cfgerror("device class names must be " + "lower-case alphanumeric characters"); + errored = 1; + } + *cp = (char)toupper((unsigned char)*cp); + } + a->a_devclass = intern(classenum); + + return (0); +} + +/* + * Return true if the given `error object' is embedded in the given + * pointer list. + */ +static int +has_errobj(struct attrlist *al, struct attr *obj) +{ + + for (; al != NULL; al = al->al_next) + if (al->al_this == obj) + return (1); + return (0); +} + +/* + * Return true if the given attribute is embedded in the given + * pointer list. + */ +int +has_attr(struct attrlist *al, const char *attr) +{ + struct attr *a; + + if ((a = getattr(attr)) == NULL) + return (0); + + for (; al != NULL; al = al->al_next) + if (al->al_this == a) + return (1); + return (0); +} + +/* + * Add a device base to a list in an attribute (actually, to any list). + * Note that this does not check for duplicates, and does reverse the + * list order, but no one cares anyway. + */ +static struct nvlist * +addtoattr(struct nvlist *l, struct devbase *dev) +{ + struct nvlist *n; + + n = newnv(NULL, NULL, dev, 0, l); + return (n); +} + +/* + * Define a device. This may (or may not) also define an interface + * attribute and/or refer to existing attributes. + */ +void +defdev(struct devbase *dev, struct loclist *loclist, struct attrlist *attrs, + int ispseudo) +{ + struct loclist *ll; + struct attrlist *al; + + if (dev == &errdev) + goto bad; + if (dev->d_isdef) { + cfgerror("redefinition of `%s'", dev->d_name); + goto bad; + } + + dev->d_isdef = 1; + if (has_errobj(attrs, &errattr)) + goto bad; + + /* + * Handle implicit attribute definition from locator list. Do + * this before scanning the `at' list so that we can have, e.g.: + * device foo at other, foo { slot = -1 } + * (where you can plug in a foo-bus extender to a foo-bus). + */ + if (loclist != NULL) { + ll = loclist; + loclist = NULL; /* defattr disposes of them for us */ + if (defiattr(dev->d_name, ll, NULL, 0)) + goto bad; + attrs = attrlist_cons(attrs, getattr(dev->d_name)); + /* This used to be stored but was never used */ + /* attrs->al_name = dev->d_name; */ + } + + /* + * Pseudo-devices can have children. Consider them as + * attaching at root. + */ + if (ispseudo) { + for (al = attrs; al != NULL; al = al->al_next) + if (al->al_this->a_iattr) + break; + if (al != NULL) { + if (ispseudo < 2) { + if (version >= 20080610) + cfgerror("interface attribute on " + "non-device pseudo `%s'", dev->d_name); + else { + ispseudo = 2; + } + } + ht_insert(devroottab, dev->d_name, dev); + } + } + + /* Committed! Set up fields. */ + dev->d_ispseudo = ispseudo; + dev->d_attrs = attrs; + dev->d_classattr = NULL; /* for now */ + CFGDBG(3, "dev `%s' defined", dev->d_name); + + /* + * Implicit attribute definition for device. + */ + refattr(dev->d_name); + + /* + * For each interface attribute this device refers to, add this + * device to its reference list. This makes, e.g., finding all + * "scsi"s easier. + * + * While looking through the attributes, set up the device + * class if any are devclass attributes (and error out if the + * device has two classes). + */ + for (al = attrs; al != NULL; al = al->al_next) { + /* + * Implicit attribute definition for device dependencies. + */ + refattr(al->al_this->a_name); + (void)ht_insert2(attrdeptab, dev->d_name, al->al_this->a_name, NULL); + CFGDBG(2, "device `%s' depends on attr `%s'", dev->d_name, + al->al_this->a_name); + } + return; + bad: + loclist_destroy(loclist); + attrlist_destroyall(attrs); +} + +/* + * Look up a devbase. Also makes sure it is a reasonable name, + * i.e., does not end in a digit or contain special characters. + */ +struct devbase * +getdevbase(const char *name) +{ + const u_char *p; + struct devbase *dev; + + p = (const u_char *)name; + if (!isalpha(*p)) + goto badname; + while (*++p) { + if (!isalnum(*p) && *p != '_') + goto badname; + } + if (isdigit(*--p)) { + badname: + cfgerror("bad device base name `%s'", name); + return (&errdev); + } + dev = ht_lookup(devbasetab, name); + if (dev == NULL) { + dev = ecalloc(1, sizeof *dev); + dev->d_name = name; + dev->d_isdef = 0; + dev->d_major = NODEVMAJOR; + dev->d_attrs = NULL; + dev->d_ihead = NULL; + dev->d_ipp = &dev->d_ihead; + dev->d_ahead = NULL; + dev->d_app = &dev->d_ahead; + dev->d_umax = 0; + TAILQ_INSERT_TAIL(&allbases, dev, d_next); + if (ht_insert(devbasetab, name, dev)) + panic("getdevbase(%s)", name); + CFGDBG(3, "devbase defined `%s'", dev->d_name); + } + return (dev); +} + +/* + * Define some of a device's allowable parent attachments. + * There may be a list of (plain) attributes. + */ +void +defdevattach(struct deva *deva, struct devbase *dev, struct nvlist *atlist, + struct attrlist *attrs) +{ + struct nvlist *nv; + struct attrlist *al; + struct attr *a; + struct deva *da; + + if (dev == &errdev) + goto bad; + if (deva == NULL) + deva = getdevattach(dev->d_name); + if (deva == &errdeva) + goto bad; + if (!dev->d_isdef) { + cfgerror("attaching undefined device `%s'", dev->d_name); + goto bad; + } + if (deva->d_isdef) { + cfgerror("redefinition of `%s'", deva->d_name); + goto bad; + } + if (dev->d_ispseudo) { + cfgerror("pseudo-devices can't attach"); + goto bad; + } + + deva->d_isdef = 1; + if (has_errobj(attrs, &errattr)) + goto bad; + for (al = attrs; al != NULL; al = al->al_next) { + a = al->al_this; + if (a == &errattr) + continue; /* already complained */ + if (a->a_iattr || a->a_devclass != NULL) + cfgerror("`%s' is not a plain attribute", a->a_name); + } + + /* Committed! Set up fields. */ + deva->d_attrs = attrs; + deva->d_atlist = atlist; + deva->d_devbase = dev; + CFGDBG(3, "deva `%s' defined", deva->d_name); + + /* + * Implicit attribute definition for device attachment. + */ + refattr(deva->d_name); + + /* + * Turn the `at' list into interface attributes (map each + * nv_name to an attribute, or to NULL for root), and add + * this device to those attributes, so that children can + * be listed at this particular device if they are supported + * by that attribute. + */ + for (nv = atlist; nv != NULL; nv = nv->nv_next) { + if (nv->nv_name == NULL) + nv->nv_ptr = a = NULL; /* at root */ + else + nv->nv_ptr = a = getattr(nv->nv_name); + if (a == &errattr) + continue; /* already complained */ + + /* + * Make sure that an attachment spec doesn't + * already say how to attach to this attribute. + */ + for (da = dev->d_ahead; da != NULL; da = da->d_bsame) + if (onlist(da->d_atlist, a)) + cfgerror("attach at `%s' already done by `%s'", + a ? a->a_name : "root", da->d_name); + + if (a == NULL) { + ht_insert(devroottab, dev->d_name, dev); + continue; /* at root; don't add */ + } + if (!a->a_iattr) + cfgerror("%s cannot be at plain attribute `%s'", + dev->d_name, a->a_name); + else + a->a_devs = addtoattr(a->a_devs, dev); + } + + /* attach to parent */ + *dev->d_app = deva; + dev->d_app = &deva->d_bsame; + return; + bad: + nvfreel(atlist); + attrlist_destroyall(attrs); +} + +/* + * Look up a device attachment. Also makes sure it is a reasonable + * name, i.e., does not contain digits or special characters. + */ +struct deva * +getdevattach(const char *name) +{ + const u_char *p; + struct deva *deva; + + p = (const u_char *)name; + if (!isalpha(*p)) + goto badname; + while (*++p) { + if (!isalnum(*p) && *p != '_') + goto badname; + } + if (isdigit(*--p)) { + badname: + cfgerror("bad device attachment name `%s'", name); + return (&errdeva); + } + deva = ht_lookup(devatab, name); + if (deva == NULL) { + deva = ecalloc(1, sizeof *deva); + deva->d_name = name; + deva->d_bsame = NULL; + deva->d_isdef = 0; + deva->d_devbase = NULL; + deva->d_atlist = NULL; + deva->d_attrs = NULL; + deva->d_ihead = NULL; + deva->d_ipp = &deva->d_ihead; + TAILQ_INSERT_TAIL(&alldevas, deva, d_next); + if (ht_insert(devatab, name, deva)) + panic("getdeva(%s)", name); + } + return (deva); +} + +/* + * Look up an attribute. + */ +struct attr * +getattr(const char *name) +{ + struct attr *a; + + if ((a = ht_lookup(attrtab, name)) == NULL) { + cfgerror("undefined attribute `%s'", name); + a = &errattr; + } + return (a); +} + +/* + * Implicit attribute definition. + */ +struct attr * +refattr(const char *name) +{ + struct attr *a; + + if ((a = ht_lookup(attrtab, name)) == NULL) + a = mkattr(name); + return a; +} + +int +getrefattr(const char *name, struct attr **ra) +{ + struct attr *a; + + a = ht_lookup(attrtab, name); + if (a == NULL) { + *ra = NULL; + return (0); + } + /* + * Check if the existing attr is only referenced, not really defined. + */ + if (a->a_deps == NULL && + a->a_iattr == 0 && + a->a_devclass == 0) { + *ra = a; + return (0); + } + return (1); +} + +/* + * Recursively expand an attribute and its dependencies, checking for + * cycles, and invoking a callback for each attribute found. + */ +void +expandattr(struct attr *a, void (*callback)(struct attr *)) +{ + struct attrlist *al; + struct attr *dep; + + if (a->a_expanding) { + cfgerror("circular dependency on attribute `%s'", a->a_name); + return; + } + + a->a_expanding = 1; + + /* First expand all of this attribute's dependencies. */ + for (al = a->a_deps; al != NULL; al = al->al_next) { + dep = al->al_this; + expandattr(dep, callback); + } + + /* ...and now invoke the callback for ourself. */ + if (callback != NULL) + (*callback)(a); + + a->a_expanding = 0; +} + +/* + * Set the major device number for a device, so that it can be used + * as a root/dumps "on" device in a configuration. + */ +void +setmajor(struct devbase *d, devmajor_t n) +{ + + if (d != &errdev && d->d_major != NODEVMAJOR) + cfgerror("device `%s' is already major %d", + d->d_name, d->d_major); + else + d->d_major = n; +} + +const char * +major2name(devmajor_t maj) +{ + struct devbase *dev; + struct devm *dm; + + if (!do_devsw) { + TAILQ_FOREACH(dev, &allbases, d_next) { + if (dev->d_major == maj) + return (dev->d_name); + } + } else { + TAILQ_FOREACH(dm, &alldevms, dm_next) { + if (dm->dm_bmajor == maj) + return (dm->dm_name); + } + } + return (NULL); +} + +devmajor_t +dev2major(struct devbase *dev) +{ + struct devm *dm; + + if (!do_devsw) + return (dev->d_major); + + TAILQ_FOREACH(dm, &alldevms, dm_next) { + if (strcmp(dm->dm_name, dev->d_name) == 0) + return (dm->dm_bmajor); + } + return (NODEVMAJOR); +} + +/* + * Make a string description of the device at maj/min. + */ +static const char * +makedevstr(devmajor_t maj, devminor_t min) +{ + const char *devicename; + char buf[32]; + + devicename = major2name(maj); + if (devicename == NULL) + (void)snprintf(buf, sizeof(buf), "<%d/%d>", maj, min); + else + (void)snprintf(buf, sizeof(buf), "%s%d%c", devicename, + min / maxpartitions, (min % maxpartitions) + 'a'); + + return (intern(buf)); +} + +/* + * Map things like "ra0b" => makedev(major("ra"), 0*maxpartitions + 'b'-'a'). + * Handle the case where the device number is given but there is no + * corresponding name, and map NULL to the default. + */ +static int +resolve(struct nvlist **nvp, const char *name, const char *what, + struct nvlist *dflt, int part) +{ + struct nvlist *nv; + struct devbase *dev; + const char *cp; + devmajor_t maj; + devminor_t min; + size_t i, l; + int unit; + char buf[NAMESIZE]; + + if ((part -= 'a') >= maxpartitions || part < 0) + panic("resolve"); + if ((nv = *nvp) == NULL) { + dev_t d = NODEV; + /* + * Apply default. Easiest to do this by number. + * Make sure to retain NODEVness, if this is dflt's disposition. + */ + if ((dev_t)dflt->nv_num != NODEV) { + maj = major(dflt->nv_num); + min = ((minor(dflt->nv_num) / maxpartitions) * + maxpartitions) + part; + d = makedev(maj, min); + cp = makedevstr(maj, min); + } else + cp = NULL; + *nvp = nv = newnv(NULL, cp, NULL, (long long)d, NULL); + } + if ((dev_t)nv->nv_num != NODEV) { + /* + * By the numbers. Find the appropriate major number + * to make a name. + */ + maj = major(nv->nv_num); + min = minor(nv->nv_num); + nv->nv_str = makedevstr(maj, min); + return (0); + } + + if (nv->nv_str == NULL || nv->nv_str == s_qmark) + /* + * Wildcarded or unspecified; leave it as NODEV. + */ + return (0); + + /* + * The normal case: things like "ra2b". Check for partition + * suffix, remove it if there, and split into name ("ra") and + * unit (2). + */ + l = i = strlen(nv->nv_str); + cp = &nv->nv_str[l]; + if (l > 1 && *--cp >= 'a' && *cp < 'a' + maxpartitions && + isdigit((unsigned char)cp[-1])) { + l--; + part = *cp - 'a'; + } + cp = nv->nv_str; + if (split(cp, l, buf, sizeof buf, &unit)) { + cfgerror("%s: invalid %s device name `%s'", name, what, cp); + return (1); + } + dev = ht_lookup(devbasetab, intern(buf)); + if (dev == NULL) { + cfgerror("%s: device `%s' does not exist", name, buf); + return (1); + } + + /* + * Check for the magic network interface attribute, and + * don't bother making a device number. + */ + if (has_attr(dev->d_attrs, s_ifnet)) { + nv->nv_num = (long long)NODEV; + nv->nv_ifunit = unit; /* XXX XXX XXX */ + } else { + maj = dev2major(dev); + if (maj == NODEVMAJOR) { + cfgerror("%s: can't make %s device from `%s'", + name, what, nv->nv_str); + return (1); + } + nv->nv_num = (long long)makedev(maj, unit * maxpartitions + part); + } + + nv->nv_name = dev->d_name; + return (0); +} + +/* + * Add a completed configuration to the list. + */ +void +addconf(struct config *cf0) +{ + struct config *cf; + const char *name; + + name = cf0->cf_name; + cf = ecalloc(1, sizeof *cf); + if (ht_insert(cfhashtab, name, cf)) { + cfgerror("configuration `%s' already defined", name); + free(cf); + goto bad; + } + *cf = *cf0; + + /* + * Resolve the root device. + */ + if (cf->cf_root == NULL) { + cfgerror("%s: no root device specified", name); + goto bad; + } + if (cf->cf_root && cf->cf_root->nv_str != s_qmark) { + struct nvlist *nv; + nv = cf->cf_root; + if (resolve(&cf->cf_root, name, "root", nv, 'a')) + goto bad; + } + + /* + * Resolve the dump device. + */ + if (cf->cf_dump == NULL || cf->cf_dump->nv_str == s_qmark) { + /* + * Wildcarded dump device is equivalent to unspecified. + */ + cf->cf_dump = NULL; + } else if (cf->cf_dump->nv_str == s_none) { + /* + * Operator has requested that no dump device should be + * configured; do nothing. + */ + } else { + if (resolve(&cf->cf_dump, name, "dumps", cf->cf_dump, 'b')) + goto bad; + } + + /* Wildcarded fstype is `unspecified'. */ + if (cf->cf_fstype == s_qmark) + cf->cf_fstype = NULL; + + TAILQ_INSERT_TAIL(&allcf, cf, cf_next); + return; + bad: + nvfreel(cf0->cf_root); + nvfreel(cf0->cf_dump); +} + +void +setconf(struct nvlist **npp, const char *what, struct nvlist *v) +{ + + if (*npp != NULL) { + cfgerror("duplicate %s specification", what); + nvfreel(v); + } else + *npp = v; +} + +void +delconf(const char *name) +{ + struct config *cf; + + CFGDBG(5, "deselecting config `%s'", name); + if (ht_lookup(cfhashtab, name) == NULL) { + cfgerror("configuration `%s' undefined", name); + return; + } + (void)ht_remove(cfhashtab, name); + + TAILQ_FOREACH(cf, &allcf, cf_next) + if (!strcmp(cf->cf_name, name)) + break; + if (cf == NULL) + panic("lost configuration `%s'", name); + + TAILQ_REMOVE(&allcf, cf, cf_next); +} + +void +setfstype(const char **fstp, const char *v) +{ + + if (*fstp != NULL) { + cfgerror("multiple fstype specifications"); + return; + } + + if (v != s_qmark && OPT_FSOPT(v)) { + cfgerror("\"%s\" is not a configured file system", v); + return; + } + + *fstp = v; +} + +static struct devi * +newdevi(const char *name, int unit, struct devbase *d) +{ + struct devi *i; + + i = ecalloc(1, sizeof *i); + i->i_name = name; + i->i_unit = unit; + i->i_base = d; + i->i_bsame = NULL; + i->i_asame = NULL; + i->i_alias = NULL; + i->i_at = NULL; + i->i_pspec = NULL; + i->i_atdeva = NULL; + i->i_locs = NULL; + i->i_cfflags = 0; + i->i_lineno = currentline(); + i->i_srcfile = yyfile; + i->i_active = DEVI_ORPHAN; /* Proper analysis comes later */ + i->i_level = devilevel; + i->i_pseudoroot = 0; + if (unit >= d->d_umax) + d->d_umax = unit + 1; + return (i); +} + +/* + * Add the named device as attaching to the named attribute (or perhaps + * another device instead) plus unit number. + */ +void +adddev(const char *name, const char *at, struct loclist *loclist, int flags) +{ + struct devi *i; /* the new instance */ + struct pspec *p; /* and its pspec */ + struct attr *attr; /* attribute that allows attach */ + struct devbase *ib; /* i->i_base */ + struct devbase *ab; /* not NULL => at another dev */ + struct attrlist *al; + struct deva *iba; /* devbase attachment used */ + const char *cp; + int atunit; + char atbuf[NAMESIZE]; + int hit; + + ab = NULL; + iba = NULL; + if (at == NULL) { + /* "at root" */ + p = NULL; + if ((i = getdevi(name)) == NULL) + goto bad; + /* + * Must warn about i_unit > 0 later, after taking care of + * the STAR cases (we could do non-star's here but why + * bother?). Make sure this device can be at root. + */ + ib = i->i_base; + hit = 0; + for (iba = ib->d_ahead; iba != NULL; iba = iba->d_bsame) + if (onlist(iba->d_atlist, NULL)) { + hit = 1; + break; + } + if (!hit) { + cfgerror("`%s' cannot attach to the root", ib->d_name); + i->i_active = DEVI_BROKEN; + goto bad; + } + attr = &errattr; /* a convenient "empty" attr */ + } else { + if (split(at, strlen(at), atbuf, sizeof atbuf, &atunit)) { + cfgerror("invalid attachment name `%s'", at); + /* (void)getdevi(name); -- ??? */ + goto bad; + } + if ((i = getdevi(name)) == NULL) + goto bad; + ib = i->i_base; + + /* + * Devices can attach to two types of things: Attributes, + * and other devices (which have the appropriate attributes + * to allow attachment). + * + * (1) If we're attached to an attribute, then we don't need + * look at the parent base device to see what attributes + * it has, and make sure that we can attach to them. + * + * (2) If we're attached to a real device (i.e. named in + * the config file), we want to remember that so that + * at cross-check time, if the device we're attached to + * is missing but other devices which also provide the + * attribute are present, we don't get a false "OK." + * + * (3) If the thing we're attached to is an attribute + * but is actually named in the config file, we still + * have to remember its devbase. + */ + cp = intern(atbuf); + + /* Figure out parent's devbase, to satisfy case (3). */ + ab = ht_lookup(devbasetab, cp); + + /* Find out if it's an attribute. */ + attr = ht_lookup(attrtab, cp); + + /* Make sure we're _really_ attached to the attr. Case (1). */ + if (attr != NULL && onlist(attr->a_devs, ib)) + goto findattachment; + + /* + * Else a real device, and not just an attribute. Case (2). + * + * Have to work a bit harder to see whether we have + * something like "tg0 at esp0" (where esp is merely + * not an attribute) or "tg0 at nonesuch0" (where + * nonesuch is not even a device). + */ + if (ab == NULL) { + cfgerror("%s at %s: `%s' unknown", + name, at, atbuf); + i->i_active = DEVI_BROKEN; + goto bad; + } + + /* + * See if the named parent carries an attribute + * that allows it to supervise device ib. + */ + for (al = ab->d_attrs; al != NULL; al = al->al_next) { + attr = al->al_this; + if (onlist(attr->a_devs, ib)) + goto findattachment; + } + cfgerror("`%s' cannot attach to `%s'", ib->d_name, atbuf); + i->i_active = DEVI_BROKEN; + goto bad; + + findattachment: + /* + * Find the parent spec. If a matching one has not yet been + * created, create one. + */ + p = getpspec(attr, ab, atunit); + p->p_devs = newnv(NULL, NULL, i, 0, p->p_devs); + + /* find out which attachment it uses */ + hit = 0; + for (iba = ib->d_ahead; iba != NULL; iba = iba->d_bsame) + if (onlist(iba->d_atlist, attr)) { + hit = 1; + break; + } + if (!hit) + panic("adddev: can't figure out attachment"); + } + if ((i->i_locs = fixloc(name, attr, loclist)) == NULL) { + i->i_active = DEVI_BROKEN; + goto bad; + } + i->i_at = at; + i->i_pspec = p; + i->i_atdeva = iba; + i->i_cfflags = flags; + CFGDBG(3, "devi `%s' added", i->i_name); + + *iba->d_ipp = i; + iba->d_ipp = &i->i_asame; + + /* all done, fall into ... */ + bad: + loclist_destroy(loclist); + return; +} + +void +deldevi(const char *name, const char *at) +{ + struct devi *firsti, *i; + struct devbase *d; + int unit; + char base[NAMESIZE]; + + CFGDBG(5, "deselecting devi `%s'", name); + if (split(name, strlen(name), base, sizeof base, &unit)) { + cfgerror("invalid device name `%s'", name); + return; + } + d = ht_lookup(devbasetab, intern(base)); + if (d == NULL) { + cfgerror("%s: unknown device `%s'", name, base); + return; + } + if (d->d_ispseudo) { + cfgerror("%s: %s is a pseudo-device", name, base); + return; + } + if ((firsti = ht_lookup(devitab, name)) == NULL) { + cfgerror("`%s' not defined", name); + return; + } + if (at == NULL && firsti->i_at == NULL) { + /* 'at root' */ + remove_devi(firsti); + return; + } else if (at != NULL) + for (i = firsti; i != NULL; i = i->i_alias) + if (i->i_active != DEVI_BROKEN && + strcmp(at, i->i_at) == 0) { + remove_devi(i); + return; + } + cfgerror("`%s' at `%s' not found", name, at ? at : "root"); +} + +static void +remove_devi(struct devi *i) +{ + struct devbase *d = i->i_base; + struct devi *f, *j, **ppi; + struct deva *iba; + + CFGDBG(5, "removing devi `%s'", i->i_name); + f = ht_lookup(devitab, i->i_name); + if (f == NULL) + panic("remove_devi(): instance %s disappeared from devitab", + i->i_name); + + if (i->i_active == DEVI_BROKEN) { + cfgerror("not removing broken instance `%s'", i->i_name); + return; + } + + /* + * We have the device instance, i. + * We have to: + * - delete the alias + * + * If the devi was an alias of an already listed devi, all is + * good we don't have to do more. + * If it was the first alias, we have to replace i's entry in + * d's list by its first alias. + * If it was the only entry, we must remove i's entry from d's + * list. + */ + if (i != f) { + for (j = f; j->i_alias != i; j = j->i_alias) + continue; + j->i_alias = i->i_alias; + } else { + if (i->i_alias == NULL) { + /* No alias, must unlink the entry from devitab */ + ht_remove(devitab, i->i_name); + j = i->i_bsame; + } else { + /* Or have the first alias replace i in d's list */ + i->i_alias->i_bsame = i->i_bsame; + j = i->i_alias; + if (i == f) + ht_replace(devitab, i->i_name, i->i_alias); + } + + /* + * - remove/replace the instance from the devbase's list + * + * A double-linked list would make this much easier. Oh, well, + * what is done is done. + */ + for (ppi = &d->d_ihead; + *ppi != NULL && *ppi != i && (*ppi)->i_bsame != i; + ppi = &(*ppi)->i_bsame) + continue; + if (*ppi == NULL) + panic("deldev: dev (%s) doesn't list the devi" + " (%s at %s)", d->d_name, i->i_name, i->i_at); + f = *ppi; + if (f == i) + /* That implies d->d_ihead == i */ + *ppi = j; + else + (*ppi)->i_bsame = j; + if (d->d_ipp == &i->i_bsame) { + if (i->i_alias == NULL) { + if (f == i) + d->d_ipp = &d->d_ihead; + else + d->d_ipp = &f->i_bsame; + } else + d->d_ipp = &i->i_alias->i_bsame; + } + } + /* + * - delete the attachment instance + */ + iba = i->i_atdeva; + for (ppi = &iba->d_ihead; + *ppi != NULL && *ppi != i && (*ppi)->i_asame != i; + ppi = &(*ppi)->i_asame) + continue; + if (*ppi == NULL) + panic("deldev: deva (%s) doesn't list the devi (%s)", + iba->d_name, i->i_name); + f = *ppi; + if (f == i) + /* That implies iba->d_ihead == i */ + *ppi = i->i_asame; + else + (*ppi)->i_asame = i->i_asame; + if (iba->d_ipp == &i->i_asame) { + if (f == i) + iba->d_ipp = &iba->d_ihead; + else + iba->d_ipp = &f->i_asame; + } + /* + * - delete the pspec + */ + if (i->i_pspec) { + struct pspec *p = i->i_pspec; + struct nvlist *nv, *onv; + + /* Double-linked nvlist anyone? */ + for (nv = p->p_devs; nv->nv_next != NULL; nv = nv->nv_next) { + if (nv->nv_next && nv->nv_next->nv_ptr == i) { + onv = nv->nv_next; + nv->nv_next = onv->nv_next; + nvfree(onv); + break; + } + if (nv->nv_ptr == i) { + /* nv is p->p_devs in that case */ + p->p_devs = nv->nv_next; + nvfree(nv); + break; + } + } + if (p->p_devs == NULL) + TAILQ_REMOVE(&allpspecs, p, p_list); + } + /* + * - delete the alldevi entry + */ + TAILQ_REMOVE(&alldevi, i, i_next); + ndevi--; + /* + * Put it in deaddevitab + * + * Each time a devi is removed, devilevel is increased so that later on + * it is possible to tell if an instance was added before or after the + * removal of its parent. + * + * For active instances, i_level contains the number of devi removed so + * far, and for dead devis, it contains its index. + */ + i->i_level = devilevel++; + i->i_alias = NULL; + f = ht_lookup(deaddevitab, i->i_name); + if (f == NULL) { + if (ht_insert(deaddevitab, i->i_name, i)) + panic("remove_devi(%s) - can't add to deaddevitab", + i->i_name); + } else { + for (j = f; j->i_alias != NULL; j = j->i_alias) + continue; + j->i_alias = i; + } + /* + * - reconstruct d->d_umax + */ + d->d_umax = 0; + for (i = d->d_ihead; i != NULL; i = i->i_bsame) + if (i->i_unit >= d->d_umax) + d->d_umax = i->i_unit + 1; +} + +void +deldeva(const char *at) +{ + int unit; + const char *cp; + struct devbase *d, *ad; + struct devi *i, *j; + struct attr *a; + struct pspec *p; + struct nvlist *nv, *stack = NULL; + + if (at == NULL) { + TAILQ_FOREACH(i, &alldevi, i_next) + if (i->i_at == NULL) + stack = newnv(NULL, NULL, i, 0, stack); + } else { + size_t l; + + CFGDBG(5, "deselecting deva `%s'", at); + if (at[0] == '\0') + goto out; + + l = strlen(at) - 1; + if (at[l] == '?' || isdigit((unsigned char)at[l])) { + char base[NAMESIZE]; + + if (split(at, l+1, base, sizeof base, &unit)) { +out: + cfgerror("invalid attachment name `%s'", at); + return; + } + cp = intern(base); + } else { + cp = intern(at); + unit = STAR; + } + + ad = ht_lookup(devbasetab, cp); + a = ht_lookup(attrtab, cp); + if (a == NULL) { + cfgerror("unknown attachment attribute or device `%s'", + cp); + return; + } + if (!a->a_iattr) { + cfgerror("plain attribute `%s' cannot have children", + a->a_name); + return; + } + + /* + * remove_devi() makes changes to the devbase's list and the + * alias list, * so the actual deletion of the instances must + * be delayed. + */ + for (nv = a->a_devs; nv != NULL; nv = nv->nv_next) { + d = nv->nv_ptr; + for (i = d->d_ihead; i != NULL; i = i->i_bsame) + for (j = i; j != NULL; j = j->i_alias) { + /* Ignore devices at root */ + if (j->i_at == NULL) + continue; + p = j->i_pspec; + /* + * There are three cases: + * + * 1. unit is not STAR. Consider 'at' + * to be explicit, even if it + * references an interface + * attribute. + * + * 2. unit is STAR and 'at' references + * a real device. Look for pspec + * that have a matching p_atdev + * field. + * + * 3. unit is STAR and 'at' references + * an interface attribute. Look + * for pspec that have a matching + * p_iattr field. + */ + if ((unit != STAR && /* Case */ + !strcmp(j->i_at, at)) || /* 1 */ + (unit == STAR && + ((ad != NULL && /* Case */ + p->p_atdev == ad) || /* 2 */ + (ad == NULL && /* Case */ + p->p_iattr == a)))) /* 3 */ + stack = newnv(NULL, NULL, j, 0, + stack); + } + } + } + + for (nv = stack; nv != NULL; nv = nv->nv_next) + remove_devi(nv->nv_ptr); + nvfreel(stack); +} + +void +deldev(const char *name) +{ + size_t l; + struct devi *firsti, *i; + struct nvlist *nv, *stack = NULL; + + CFGDBG(5, "deselecting dev `%s'", name); + if (name[0] == '\0') + goto out; + + l = strlen(name) - 1; + if (name[l] == '*' || isdigit((unsigned char)name[l])) { + /* `no mydev0' or `no mydev*' */ + firsti = ht_lookup(devitab, name); + if (firsti == NULL) { +out: + cfgerror("unknown instance %s", name); + return; + } + for (i = firsti; i != NULL; i = i->i_alias) + stack = newnv(NULL, NULL, i, 0, stack); + } else { + struct devbase *d = ht_lookup(devbasetab, name); + + if (d == NULL) { + cfgerror("unknown device %s", name); + return; + } + if (d->d_ispseudo) { + cfgerror("%s is a pseudo-device; " + "use \"no pseudo-device %s\" instead", name, + name); + return; + } + + for (firsti = d->d_ihead; firsti != NULL; + firsti = firsti->i_bsame) + for (i = firsti; i != NULL; i = i->i_alias) + stack = newnv(NULL, NULL, i, 0, stack); + } + + for (nv = stack; nv != NULL; nv = nv->nv_next) + remove_devi(nv->nv_ptr); + nvfreel(stack); +} + +/* + * Insert given device "name" into devroottab. In case "name" + * designates a pure interface attribute, create a fake device + * instance for the attribute and insert that into the roottab + * (this scheme avoids mucking around with the orphanage analysis). + */ +void +addpseudoroot(const char *name) +{ + char buf[NAMESIZE]; + int unit; + struct attr *attr; + struct devi *i; + struct deva *iba; + struct devbase *ib; + + if (split(name, strlen(name), buf, sizeof(buf), &unit)) { + cfgerror("invalid pseudo-root name `%s'", name); + return; + } + + /* + * Prefer device because devices with locators define an + * implicit interface attribute. However, if a device is + * not available, try to attach to the interface attribute. + * This makes sure adddev() doesn't get confused when we + * are really attaching to a device (alternatively we maybe + * could specify a non-NULL atlist to defdevattach() below). + */ + ib = ht_lookup(devbasetab, intern(buf)); + if (ib == NULL) { + struct devbase *fakedev; + char fakename[NAMESIZE]; + + attr = ht_lookup(attrtab, intern(buf)); + if (!(attr && attr->a_iattr)) { + cfgerror("pseudo-root `%s' not available", name); + return; + } + + /* + * here we cheat a bit: create a fake devbase with the + * interface attribute and instantiate it. quick, cheap, + * dirty & bad for you, much like the stuff in the fridge. + * and, it works, since the pseudoroot device is not included + * in ioconf, just used by config to make sure we start from + * the right place. + */ + snprintf(fakename, sizeof(fakename), "%s_devattrs", buf); + fakedev = getdevbase(intern(fakename)); + fakedev->d_isdef = 1; + fakedev->d_ispseudo = 0; + fakedev->d_attrs = attrlist_cons(NULL, attr); + defdevattach(NULL, fakedev, NULL, NULL); + + if (unit == STAR) + snprintf(buf, sizeof(buf), "%s*", fakename); + else + snprintf(buf, sizeof(buf), "%s%d", fakename, unit); + name = buf; + } + + /* ok, everything should be set up, so instantiate a fake device */ + i = getdevi(name); + if (i == NULL) + panic("device `%s' expected to be present", name); + ib = i->i_base; + iba = ib->d_ahead; + + i->i_atdeva = iba; + i->i_cfflags = 0; + i->i_locs = fixloc(name, &errattr, NULL); + i->i_pseudoroot = 1; + i->i_active = DEVI_ORPHAN; /* set active by kill_orphans() */ + + *iba->d_ipp = i; + iba->d_ipp = &i->i_asame; + + ht_insert(devroottab, ib->d_name, ib); +} + +void +addpseudo(const char *name, int number) +{ + struct devbase *d; + struct devi *i; + + d = ht_lookup(devbasetab, name); + if (d == NULL) { + cfgerror("undefined pseudo-device %s", name); + return; + } + if (!d->d_ispseudo) { + cfgerror("%s is a real device, not a pseudo-device", name); + return; + } + if (ht_lookup(devitab, name) != NULL) { + cfgerror("`%s' already defined", name); + return; + } + i = newdevi(name, number - 1, d); /* foo 16 => "foo0..foo15" */ + if (ht_insert(devitab, name, i)) + panic("addpseudo(%s)", name); + /* Useful to retrieve the instance from the devbase */ + d->d_ihead = i; + i->i_active = DEVI_ACTIVE; + TAILQ_INSERT_TAIL(&allpseudo, i, i_next); +} + +void +delpseudo(const char *name) +{ + struct devbase *d; + struct devi *i; + + CFGDBG(5, "deselecting pseudo `%s'", name); + d = ht_lookup(devbasetab, name); + if (d == NULL) { + cfgerror("undefined pseudo-device %s", name); + return; + } + if (!d->d_ispseudo) { + cfgerror("%s is a real device, not a pseudo-device", name); + return; + } + if ((i = ht_lookup(devitab, name)) == NULL) { + cfgerror("`%s' not defined", name); + return; + } + d->d_umax = 0; /* clear neads-count entries */ + d->d_ihead = NULL; /* make sure it won't be considered active */ + TAILQ_REMOVE(&allpseudo, i, i_next); + if (ht_remove(devitab, name)) + panic("delpseudo(%s) - can't remove from devitab", name); + if (ht_insert(deaddevitab, name, i)) + panic("delpseudo(%s) - can't add to deaddevitab", name); +} + +void +adddevm(const char *name, devmajor_t cmajor, devmajor_t bmajor, + struct condexpr *cond, struct nvlist *nv_nodes) +{ + struct devm *dm; + + if (cmajor != NODEVMAJOR && (cmajor < 0 || cmajor >= 4096)) { + cfgerror("character major %d is invalid", cmajor); + condexpr_destroy(cond); + nvfreel(nv_nodes); + return; + } + + if (bmajor != NODEVMAJOR && (bmajor < 0 || bmajor >= 4096)) { + cfgerror("block major %d is invalid", bmajor); + condexpr_destroy(cond); + nvfreel(nv_nodes); + return; + } + if (cmajor == NODEVMAJOR && bmajor == NODEVMAJOR) { + cfgerror("both character/block majors are not specified"); + condexpr_destroy(cond); + nvfreel(nv_nodes); + return; + } + + dm = ecalloc(1, sizeof(*dm)); + dm->dm_srcfile = yyfile; + dm->dm_srcline = currentline(); + dm->dm_name = name; + dm->dm_cmajor = cmajor; + dm->dm_bmajor = bmajor; + dm->dm_opts = cond; + dm->dm_devnodes = nv_nodes; + + TAILQ_INSERT_TAIL(&alldevms, dm, dm_next); + + maxcdevm = MAX(maxcdevm, dm->dm_cmajor); + maxbdevm = MAX(maxbdevm, dm->dm_bmajor); +} + +int +fixdevis(void) +{ + struct devi *i; + int error = 0; + + TAILQ_FOREACH(i, &alldevi, i_next) { + CFGDBG(3, "fixing devis `%s'", i->i_name); + if (i->i_active == DEVI_ACTIVE) + selectbase(i->i_base, i->i_atdeva); + else if (i->i_active == DEVI_ORPHAN) { + /* + * At this point, we can't have instances for which + * i_at or i_pspec are NULL. + */ + ++error; + cfgxerror(i->i_srcfile, i->i_lineno, + "`%s at %s' is orphaned (%s `%s' found)", + i->i_name, i->i_at, i->i_pspec->p_atunit == WILD ? + "nothing matching" : "no", i->i_at); + } else if (vflag && i->i_active == DEVI_IGNORED) + cfgxwarn(i->i_srcfile, i->i_lineno, "ignoring " + "explicitly orphaned instance `%s at %s'", + i->i_name, i->i_at); + } + + if (error) + return error; + + TAILQ_FOREACH(i, &allpseudo, i_next) + if (i->i_active == DEVI_ACTIVE) + selectbase(i->i_base, NULL); + return 0; +} + +/* + * Look up a parent spec, creating a new one if it does not exist. + */ +static struct pspec * +getpspec(struct attr *attr, struct devbase *ab, int atunit) +{ + struct pspec *p; + + TAILQ_FOREACH(p, &allpspecs, p_list) { + if (p->p_iattr == attr && + p->p_atdev == ab && + p->p_atunit == atunit) + return (p); + } + + p = ecalloc(1, sizeof(*p)); + + p->p_iattr = attr; + p->p_atdev = ab; + p->p_atunit = atunit; + p->p_inst = npspecs++; + p->p_active = 0; + + TAILQ_INSERT_TAIL(&allpspecs, p, p_list); + + return (p); +} + +/* + * Define a new instance of a specific device. + */ +static struct devi * +getdevi(const char *name) +{ + struct devi *i, *firsti; + struct devbase *d; + int unit; + char base[NAMESIZE]; + + if (split(name, strlen(name), base, sizeof base, &unit)) { + cfgerror("invalid device name `%s'", name); + return (NULL); + } + d = ht_lookup(devbasetab, intern(base)); + if (d == NULL) { + cfgerror("%s: unknown device `%s'", name, base); + return (NULL); + } + if (d->d_ispseudo) { + cfgerror("%s: %s is a pseudo-device", name, base); + return (NULL); + } + firsti = ht_lookup(devitab, name); + i = newdevi(name, unit, d); + if (firsti == NULL) { + if (ht_insert(devitab, name, i)) + panic("getdevi(%s)", name); + *d->d_ipp = i; + d->d_ipp = &i->i_bsame; + } else { + while (firsti->i_alias) + firsti = firsti->i_alias; + firsti->i_alias = i; + } + TAILQ_INSERT_TAIL(&alldevi, i, i_next); + ndevi++; + return (i); +} + +static const char * +concat(const char *name, int c) +{ + size_t len; + char buf[NAMESIZE]; + + len = strlen(name); + if (len + 2 > sizeof(buf)) { + cfgerror("device name `%s%c' too long", name, c); + len = sizeof(buf) - 2; + } + memmove(buf, name, len); + buf[len] = (char)c; + buf[len + 1] = '\0'; + return (intern(buf)); +} + +const char * +starref(const char *name) +{ + + return (concat(name, '*')); +} + +const char * +wildref(const char *name) +{ + + return (concat(name, '?')); +} + +/* + * Split a name like "foo0" into base name (foo) and unit number (0). + * Return 0 on success. To make this useful for names like "foo0a", + * the length of the "foo0" part is one of the arguments. + */ +static int +split(const char *name, size_t nlen, char *base, size_t bsize, int *aunit) +{ + const char *cp; + int c; + size_t l; + + l = nlen; + if (l < 2 || l >= bsize || isdigit((unsigned char)*name)) + return (1); + c = (u_char)name[--l]; + if (!isdigit(c)) { + if (c == '*') + *aunit = STAR; + else if (c == '?') + *aunit = WILD; + else + return (1); + } else { + cp = &name[l]; + while (isdigit((unsigned char)cp[-1])) + l--, cp--; + *aunit = atoi(cp); + } + memmove(base, name, l); + base[l] = 0; + return (0); +} + +void +addattr(const char *name) +{ + struct attr *a; + + a = refattr(name); + selectattr(a); +} + +void +delattr(const char *name) +{ + struct attr *a; + + a = refattr(name); + deselectattr(a); +} + +void +selectattr(struct attr *a) +{ + struct attrlist *al; + struct attr *dep; + + CFGDBG(5, "selecting attr `%s'", a->a_name); + for (al = a->a_deps; al != NULL; al = al->al_next) { + dep = al->al_this; + selectattr(dep); + } + if (ht_insert(selecttab, a->a_name, __UNCONST(a->a_name)) == 0) + nattrs++; + CFGDBG(3, "attr selected `%s'", a->a_name); +} + +static int +deselectattrcb2(const char *name1, const char *name2, void *v, void *arg) +{ + const char *name = arg; + + if (strcmp(name, name2) == 0) + delattr(name1); + return 0; +} + +void +deselectattr(struct attr *a) +{ + + CFGDBG(5, "deselecting attr `%s'", a->a_name); + ht_enumerate2(attrdeptab, deselectattrcb2, __UNCONST(a->a_name)); + if (ht_remove(selecttab, a->a_name) == 0) + nattrs--; + CFGDBG(3, "attr deselected `%s'", a->a_name); +} + +static int +dumpattrdepcb2(const char *name1, const char *name2, void *v, void *arg) +{ + + CFGDBG(3, "attr `%s' depends on attr `%s'", name1, name2); + return 0; +} + +void +dependattrs(void) +{ + + ht_enumerate2(attrdeptab, dumpattrdepcb2, NULL); +} + +/* + * We have an instance of the base foo, so select it and all its + * attributes for "optional foo". + */ +static void +selectbase(struct devbase *d, struct deva *da) +{ + struct attr *a; + struct attrlist *al; + + (void)ht_insert(selecttab, d->d_name, __UNCONST(d->d_name)); + CFGDBG(3, "devbase selected `%s'", d->d_name); + CFGDBG(5, "selecting dependencies of devbase `%s'", d->d_name); + for (al = d->d_attrs; al != NULL; al = al->al_next) { + a = al->al_this; + expandattr(a, selectattr); + } + + struct attr *devattr; + devattr = refattr(d->d_name); + expandattr(devattr, selectattr); + + if (da != NULL) { + (void)ht_insert(selecttab, da->d_name, __UNCONST(da->d_name)); + CFGDBG(3, "devattr selected `%s'", da->d_name); + for (al = da->d_attrs; al != NULL; al = al->al_next) { + a = al->al_this; + expandattr(a, selectattr); + } + } + + fixdev(d); +} + +/* + * Is the given pointer on the given list of pointers? + */ +int +onlist(struct nvlist *nv, void *ptr) +{ + for (; nv != NULL; nv = nv->nv_next) + if (nv->nv_ptr == ptr) + return (1); + return (0); +} + +static char * +extend(char *p, const char *name) +{ + size_t l; + + l = strlen(name); + memmove(p, name, l); + p += l; + *p++ = ','; + *p++ = ' '; + return (p); +} + +/* + * Check that we got all required locators, and default any that are + * given as "?" and have defaults. Return 0 on success. + */ +static const char ** +fixloc(const char *name, struct attr *attr, struct loclist *got) +{ + struct loclist *m, *n; + int ord; + const char **lp; + int nmissing, nextra, nnodefault; + char *mp, *ep, *ndp; + char missing[1000], extra[1000], nodefault[1000]; + static const char *nullvec[1]; + + /* + * Look for all required locators, and number the given ones + * according to the required order. While we are numbering, + * set default values for defaulted locators. + */ + if (attr->a_loclen == 0) /* e.g., "at root" */ + lp = nullvec; + else + lp = emalloc((size_t)(attr->a_loclen + 1) * sizeof(const char *)); + for (n = got; n != NULL; n = n->ll_next) + n->ll_num = -1; + nmissing = 0; + mp = missing; + /* yes, this is O(mn), but m and n should be small */ + for (ord = 0, m = attr->a_locs; m != NULL; m = m->ll_next, ord++) { + for (n = got; n != NULL; n = n->ll_next) { + if (n->ll_name == m->ll_name) { + n->ll_num = ord; + break; + } + } + if (n == NULL && m->ll_num == 0) { + nmissing++; + mp = extend(mp, m->ll_name); + } + lp[ord] = m->ll_string; + } + if (ord != attr->a_loclen) + panic("fixloc"); + lp[ord] = NULL; + nextra = 0; + ep = extra; + nnodefault = 0; + ndp = nodefault; + for (n = got; n != NULL; n = n->ll_next) { + if (n->ll_num >= 0) { + if (n->ll_string != NULL) + lp[n->ll_num] = n->ll_string; + else if (lp[n->ll_num] == NULL) { + nnodefault++; + ndp = extend(ndp, n->ll_name); + } + } else { + nextra++; + ep = extend(ep, n->ll_name); + } + } + if (nextra) { + ep[-2] = 0; /* kill ", " */ + cfgerror("%s: extraneous locator%s: %s", + name, nextra > 1 ? "s" : "", extra); + } + if (nmissing) { + mp[-2] = 0; + cfgerror("%s: must specify %s", name, missing); + } + if (nnodefault) { + ndp[-2] = 0; + cfgerror("%s: cannot wildcard %s", name, nodefault); + } + if (nmissing || nnodefault) { + free(lp); + lp = NULL; + } + return (lp); +} + +void +setversion(int newver) +{ + if (newver > CONFIG_VERSION) + cfgerror("your sources require a newer version of config(1) " + "-- please rebuild it."); + else if (newver < CONFIG_MINVERSION) + cfgerror("your sources are out of date -- please update."); + else + version = newver; +} diff --git a/usr.bin/config/sem.h b/usr.bin/config/sem.h new file mode 100644 index 000000000..43e3bc4e6 --- /dev/null +++ b/usr.bin/config/sem.h @@ -0,0 +1,91 @@ +/* $NetBSD: sem.h,v 1.19 2014/11/21 20:46:56 christos Exp $ */ + +/* + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Lawrence Berkeley Laboratories. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * from: @(#)sem.h 8.1 (Berkeley) 6/6/93 + */ + +void enddefs(void); + +void setversion(int); +void setdefmaxusers(int, int, int); +void setmaxusers(int); +void setident(const char *); +int defattr0(const char *, struct loclist *, struct attrlist *, int); +int defattr(const char *, struct loclist *, struct attrlist *, int); +int defiattr(const char *, struct loclist *, struct attrlist *, int); +int defdevclass(const char *, struct loclist *, struct attrlist *, int); +void defdev(struct devbase *, struct loclist *, struct attrlist *, int); +void defdevattach(struct deva *, struct devbase *, struct nvlist *, + struct attrlist *); +struct devbase *getdevbase(const char *); +struct deva *getdevattach(const char *); +struct attr *mkattr(const char *); +struct attr *getattr(const char *); +struct attr *refattr(const char *); +int getrefattr(const char *, struct attr **); +void expandattr(struct attr *, void (*)(struct attr *)); +void addattr(const char *); +void delattr(const char *); +void selectattr(struct attr *); +void deselectattr(struct attr *); +void dependattrs(void); +void setmajor(struct devbase *, int); +void addconf(struct config *); +void setconf(struct nvlist **, const char *, struct nvlist *); +void delconf(const char *); +void setfstype(const char **, const char *); +void adddev(const char *, const char *, struct loclist *, int); +void deldevi(const char *, const char *); +void deldeva(const char *); +void deldev(const char *); +void addpseudo(const char *, int); +void delpseudo(const char *); +void addpseudoroot(const char *); +void adddevm(const char *, devmajor_t, devmajor_t, + struct condexpr *, struct nvlist *); +int fixdevis(void); +const char *ref(const char *); +const char *starref(const char *); +const char *wildref(const char *); +int has_attr(struct attrlist *, const char *); + +extern const char *s_qmark; +extern const char *s_none; +extern const char *s_ifnet; +extern size_t nattrs; diff --git a/usr.bin/config/util.c b/usr.bin/config/util.c new file mode 100644 index 000000000..e1837ae45 --- /dev/null +++ b/usr.bin/config/util.c @@ -0,0 +1,575 @@ +/* $NetBSD: util.c,v 1.20 2015/09/01 13:42:48 uebayasi Exp $ */ + +/* + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Lawrence Berkeley Laboratories. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * from: @(#)util.c 8.1 (Berkeley) 6/6/93 + */ + +#if HAVE_NBTOOL_CONFIG_H +#include "nbtool_config.h" +#endif + +#include +__RCSID("$NetBSD: util.c,v 1.20 2015/09/01 13:42:48 uebayasi Exp $"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "defs.h" + +static void cfgvxerror(const char *, int, const char *, va_list) + __printflike(3, 0); +static void cfgvxdbg(const char *, int, const char *, va_list) + __printflike(3, 0); +static void cfgvxwarn(const char *, int, const char *, va_list) + __printflike(3, 0); +static void cfgvxmsg(const char *, int, const char *, const char *, va_list) + __printflike(4, 0); + +/************************************************************/ + +/* + * Prefix stack + */ + +static void +prefixlist_push(struct prefixlist *pl, const char *path) +{ + struct prefix *prevpf = SLIST_FIRST(pl); + struct prefix *pf; + char *cp; + + pf = ecalloc(1, sizeof(struct prefix)); + + if (prevpf != NULL) { + cp = emalloc(strlen(prevpf->pf_prefix) + 1 + + strlen(path) + 1); + (void) sprintf(cp, "%s/%s", prevpf->pf_prefix, path); + pf->pf_prefix = intern(cp); + free(cp); + } else + pf->pf_prefix = intern(path); + + SLIST_INSERT_HEAD(pl, pf, pf_next); +} + +static void +prefixlist_pop(struct prefixlist *allpl, struct prefixlist *pl) +{ + struct prefix *pf; + + if ((pf = SLIST_FIRST(pl)) == NULL) { + cfgerror("no prefixes on the stack to pop"); + return; + } + + SLIST_REMOVE_HEAD(pl, pf_next); + /* Remember this prefix for emitting -I... directives later. */ + SLIST_INSERT_HEAD(allpl, pf, pf_next); +} + +/* + * Push a prefix onto the prefix stack. + */ +void +prefix_push(const char *path) +{ + prefixlist_push(&prefixes, path); +} + +/* + * Pop a prefix off the prefix stack. + */ +void +prefix_pop(void) +{ + prefixlist_pop(&allprefixes, &prefixes); +} + +/* + * Push a buildprefix onto the buildprefix stack. + */ +void +buildprefix_push(const char *path) +{ + prefixlist_push(&buildprefixes, path); +} + +/* + * Pop a buildprefix off the buildprefix stack. + */ +void +buildprefix_pop(void) +{ + prefixlist_pop(&allbuildprefixes, &buildprefixes); +} + +/* + * Prepend the source path to a file name. + */ +char * +sourcepath(const char *file) +{ + size_t len; + char *cp; + struct prefix *pf; + + pf = SLIST_EMPTY(&prefixes) ? NULL : SLIST_FIRST(&prefixes); + if (pf != NULL && *pf->pf_prefix == '/') + len = strlen(pf->pf_prefix) + 1 + strlen(file) + 1; + else { + len = strlen(srcdir) + 1 + strlen(file) + 1; + if (pf != NULL) + len += strlen(pf->pf_prefix) + 1; + } + + cp = emalloc(len); + + if (pf != NULL) { + if (*pf->pf_prefix == '/') + (void) sprintf(cp, "%s/%s", pf->pf_prefix, file); + else + (void) sprintf(cp, "%s/%s/%s", srcdir, + pf->pf_prefix, file); + } else + (void) sprintf(cp, "%s/%s", srcdir, file); + return (cp); +} + +/************************************************************/ + +/* + * Data structures + */ + +/* + * nvlist + */ + +struct nvlist * +newnv(const char *name, const char *str, void *ptr, long long i, struct nvlist *next) +{ + struct nvlist *nv; + + nv = ecalloc(1, sizeof(*nv)); + nv->nv_next = next; + nv->nv_name = name; + nv->nv_str = str; + nv->nv_ptr = ptr; + nv->nv_num = i; + return nv; +} + +/* + * Free an nvlist structure (just one). + */ +void +nvfree(struct nvlist *nv) +{ + + free(nv); +} + +/* + * Free an nvlist (the whole list). + */ +void +nvfreel(struct nvlist *nv) +{ + struct nvlist *next; + + for (; nv != NULL; nv = next) { + next = nv->nv_next; + free(nv); + } +} + +struct nvlist * +nvcat(struct nvlist *nv1, struct nvlist *nv2) +{ + struct nvlist *nv; + + if (nv1 == NULL) + return nv2; + + for (nv = nv1; nv->nv_next != NULL; nv = nv->nv_next); + + nv->nv_next = nv2; + return nv1; +} + +/* + * Option definition lists + */ + +struct defoptlist * +defoptlist_create(const char *name, const char *val, const char *lintval) +{ + struct defoptlist *dl; + + dl = emalloc(sizeof(*dl)); + dl->dl_next = NULL; + dl->dl_name = name; + dl->dl_value = val; + dl->dl_lintvalue = lintval; + dl->dl_obsolete = 0; + dl->dl_depends = NULL; + return dl; +} + +void +defoptlist_destroy(struct defoptlist *dl) +{ + struct defoptlist *next; + + while (dl != NULL) { + next = dl->dl_next; + dl->dl_next = NULL; + + // XXX should we assert that dl->dl_deps is null to + // be sure the deps have already been destroyed? + free(dl); + + dl = next; + } +} + +struct defoptlist * +defoptlist_append(struct defoptlist *dla, struct defoptlist *dlb) +{ + struct defoptlist *dl; + + if (dla == NULL) + return dlb; + + for (dl = dla; dl->dl_next != NULL; dl = dl->dl_next) + ; + + dl->dl_next = dlb; + return dla; +} + +/* + * Locator lists + */ + +struct loclist * +loclist_create(const char *name, const char *string, long long num) +{ + struct loclist *ll; + + ll = emalloc(sizeof(*ll)); + ll->ll_name = name; + ll->ll_string = string; + ll->ll_num = num; + ll->ll_next = NULL; + return ll; +} + +void +loclist_destroy(struct loclist *ll) +{ + struct loclist *next; + + while (ll != NULL) { + next = ll->ll_next; + ll->ll_next = NULL; + free(ll); + ll = next; + } +} + +/* + * Attribute lists + */ + +struct attrlist * +attrlist_create(void) +{ + struct attrlist *al; + + al = emalloc(sizeof(*al)); + al->al_next = NULL; + al->al_this = NULL; + return al; +} + +struct attrlist * +attrlist_cons(struct attrlist *next, struct attr *a) +{ + struct attrlist *al; + + al = attrlist_create(); + al->al_next = next; + al->al_this = a; + return al; +} + +void +attrlist_destroy(struct attrlist *al) +{ + assert(al->al_next == NULL); + assert(al->al_this == NULL); + free(al); +} + +void +attrlist_destroyall(struct attrlist *al) +{ + struct attrlist *next; + + while (al != NULL) { + next = al->al_next; + al->al_next = NULL; + /* XXX should we make the caller guarantee this? */ + al->al_this = NULL; + attrlist_destroy(al); + al = next; + } +} + +/* + * Condition expressions + */ + +/* + * Create an expression node. + */ +struct condexpr * +condexpr_create(enum condexpr_types type) +{ + struct condexpr *cx; + + cx = emalloc(sizeof(*cx)); + cx->cx_type = type; + switch (type) { + + case CX_ATOM: + cx->cx_atom = NULL; + break; + + case CX_NOT: + cx->cx_not = NULL; + break; + + case CX_AND: + cx->cx_and.left = NULL; + cx->cx_and.right = NULL; + break; + + case CX_OR: + cx->cx_or.left = NULL; + cx->cx_or.right = NULL; + break; + + default: + panic("condexpr_create: invalid expr type %d", (int)type); + } + return cx; +} + +/* + * Free an expression tree. + */ +void +condexpr_destroy(struct condexpr *expr) +{ + switch (expr->cx_type) { + + case CX_ATOM: + /* nothing */ + break; + + case CX_NOT: + condexpr_destroy(expr->cx_not); + break; + + case CX_AND: + condexpr_destroy(expr->cx_and.left); + condexpr_destroy(expr->cx_and.right); + break; + + case CX_OR: + condexpr_destroy(expr->cx_or.left); + condexpr_destroy(expr->cx_or.right); + break; + + default: + panic("condexpr_destroy: invalid expr type %d", + (int)expr->cx_type); + } + free(expr); +} + +/************************************************************/ + +/* + * Diagnostic messages + */ + +void +cfgdbg(const char *fmt, ...) +{ + va_list ap; + extern const char *yyfile; + + va_start(ap, fmt); + cfgvxdbg(yyfile, currentline(), fmt, ap); + va_end(ap); +} + +void +cfgwarn(const char *fmt, ...) +{ + va_list ap; + extern const char *yyfile; + + va_start(ap, fmt); + cfgvxwarn(yyfile, currentline(), fmt, ap); + va_end(ap); +} + +void +cfgxwarn(const char *file, int line, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + cfgvxwarn(file, line, fmt, ap); + va_end(ap); +} + +static void +cfgvxdbg(const char *file, int line, const char *fmt, va_list ap) +{ + cfgvxmsg(file, line, "debug: ", fmt, ap); +} + +static void +cfgvxwarn(const char *file, int line, const char *fmt, va_list ap) +{ + cfgvxmsg(file, line, "warning: ", fmt, ap); +} + +/* + * External (config file) error. Complain, using current file + * and line number. + */ +void +cfgerror(const char *fmt, ...) +{ + va_list ap; + extern const char *yyfile; + + va_start(ap, fmt); + cfgvxerror(yyfile, currentline(), fmt, ap); + va_end(ap); +} + +/* + * Delayed config file error (i.e., something was wrong but we could not + * find out about it until later). + */ +void +cfgxerror(const char *file, int line, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + cfgvxerror(file, line, fmt, ap); + va_end(ap); +} + +/* + * Internal form of error() and xerror(). + */ +static void +cfgvxerror(const char *file, int line, const char *fmt, va_list ap) +{ + cfgvxmsg(file, line, "", fmt, ap); + errors++; +} + + +/* + * Internal error, abort. + */ +__dead void +panic(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + (void)fprintf(stderr, "%s: panic: ", getprogname()); + (void)vfprintf(stderr, fmt, ap); + (void)putc('\n', stderr); + va_end(ap); + exit(2); +} + +/* + * Internal form of error() and xerror(). + */ +static void +cfgvxmsg(const char *file, int line, const char *msgclass, const char *fmt, + va_list ap) +{ + + (void)fprintf(stderr, "%s:%d: %s", file, line, msgclass); + (void)vfprintf(stderr, fmt, ap); + (void)putc('\n', stderr); +} + +void +autogen_comment(FILE *fp, const char *targetfile) +{ + + (void)fprintf(fp, + "/*\n" + " * MACHINE GENERATED: DO NOT EDIT\n" + " *\n" + " * %s, from \"%s\"\n" + " */\n\n", + targetfile, conffile); +}