import config command

This commit is contained in:
Jean-Baptiste Boric 2016-11-14 22:26:31 +01:00
parent ccee9c2e7b
commit fee8e88355
28 changed files with 18814 additions and 2 deletions

View File

@ -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

View File

@ -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

View File

@ -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 \

27
usr.bin/config/Makefile Normal file
View File

@ -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 <bsd.own.mk>
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 <bsd.prog.mk>

461
usr.bin/config/TODO Normal file
View File

@ -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 <ldscript> 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).

BIN
usr.bin/config/config Executable file

Binary file not shown.

358
usr.bin/config/config.1 Normal file
View File

@ -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 .

764
usr.bin/config/config.5 Normal file
View File

@ -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

View File

@ -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

666
usr.bin/config/defs.h Normal file
View File

@ -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 <sys/types.h>
#include <sys/param.h>
#include <sys/queue.h>
#if !defined(MAKE_BOOTSTRAP) && defined(BSD)
#include <sys/cdefs.h>
#include <paths.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
/* 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);

622
usr.bin/config/files.c Normal file
View File

@ -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 <sys/cdefs.h>
__RCSID("$NetBSD: files.c,v 1.35 2015/09/04 21:32:54 uebayasi Exp $");
#include <sys/param.h>
#include <assert.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <util.h>
#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

2431
usr.bin/config/gram.c Normal file

File diff suppressed because it is too large Load Diff

89
usr.bin/config/gram.h Normal file
View File

@ -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_ */

1450
usr.bin/config/gram.y Normal file

File diff suppressed because it is too large Load Diff

456
usr.bin/config/hash.c Normal file
View File

@ -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 <sys/cdefs.h>
__RCSID("$NetBSD: hash.c,v 1.11 2014/10/29 17:14:50 christos Exp $");
#include <sys/param.h>
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <util.h>
#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);

208
usr.bin/config/lint.c Normal file
View File

@ -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 <sys/cdefs.h>
__RCSID("$NetBSD: lint.c,v 1.15 2014/10/29 17:14:50 christos Exp $");
#include <assert.h>
#include <stdlib.h>
#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);
}

2037
usr.bin/config/main.c Normal file

File diff suppressed because it is too large Load Diff

241
usr.bin/config/mkdevsw.c Normal file
View File

@ -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 <sys/cdefs.h>
__RCSID("$NetBSD: mkdevsw.c,v 1.14 2015/09/03 13:53:36 uebayasi Exp $");
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <err.h>
#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 <sys/param.h>\n"
"#include <sys/conf.h>\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);
}

547
usr.bin/config/mkheaders.c Normal file
View File

@ -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 <sys/cdefs.h>
__RCSID("$NetBSD: mkheaders.c,v 1.29 2015/09/03 13:53:36 uebayasi Exp $");
#include <sys/param.h>
#include <ctype.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <util.h>
#include <err.h>
#include "defs.h"
#include <crc_extern.h>
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);
}

510
usr.bin/config/mkioconf.c Normal file
View File

@ -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 <sys/cdefs.h>
__RCSID("$NetBSD: mkioconf.c,v 1.32 2015/09/03 13:53:36 uebayasi Exp $");
#include <sys/param.h>
#include <err.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#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 <sys/param.h>\n"
"#include <sys/conf.h>\n"
"#include <sys/device.h>\n"
"#include <sys/mount.h>\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");
}

598
usr.bin/config/mkmakefile.c Normal file
View File

@ -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 <sys/cdefs.h>
__RCSID("$NetBSD: mkmakefile.c,v 1.68 2015/09/04 10:16:35 uebayasi Exp $");
#include <sys/param.h>
#include <ctype.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <err.h>
#include <util.h>
#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);
}

164
usr.bin/config/mkswap.c Normal file
View File

@ -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 <sys/cdefs.h>
__RCSID("$NetBSD: mkswap.c,v 1.10 2015/09/03 13:53:36 uebayasi Exp $");
#include <sys/param.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <err.h>
#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 <sys/param.h>\n"
"#include <sys/conf.h>\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);
}

352
usr.bin/config/pack.c Normal file
View File

@ -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 <sys/cdefs.h>
__RCSID("$NetBSD: pack.c,v 1.10 2015/09/12 19:11:13 joerg Exp $");
#include <sys/param.h>
#include <stdlib.h>
#include <string.h>
#include <util.h>
#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;
}
}

3094
usr.bin/config/scan.c Normal file

File diff suppressed because it is too large Load Diff

638
usr.bin/config/scan.l Normal file
View File

@ -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 <sys/cdefs.h>
__RCSID("$NetBSD: scan.l,v 1.25 2015/09/04 10:16:35 uebayasi Exp $");
#include <sys/param.h>
#include <errno.h>
#include <libgen.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <stddef.h>
#include <ctype.h>
#include <util.h>
#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++;
}
<IGNORED>\n {
yyline++;
}
<IGNORED>. /* 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]; }
<*><<EOF>> {
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;
}

2177
usr.bin/config/sem.c Normal file

File diff suppressed because it is too large Load Diff

91
usr.bin/config/sem.h Normal file
View File

@ -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;

575
usr.bin/config/util.c Normal file
View File

@ -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 <sys/cdefs.h>
__RCSID("$NetBSD: util.c,v 1.20 2015/09/01 13:42:48 uebayasi Exp $");
#include <sys/types.h>
#include <assert.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <util.h>
#include <err.h>
#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);
}