Index: head/sys/kern/kern_mib.c =================================================================== --- head/sys/kern/kern_mib.c (revision 169506) +++ head/sys/kern/kern_mib.c (revision 169507) @@ -1,377 +1,410 @@ /*- * Copyright (c) 1982, 1986, 1989, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Mike Karels at Berkeley Software Design, Inc. * * Quite extensively rewritten by Poul-Henning Kamp of the FreeBSD * project, to make these variables more userfriendly. * * 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. * 4. 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. * * @(#)kern_sysctl.c 8.4 (Berkeley) 4/14/94 */ #include __FBSDID("$FreeBSD$"); #include "opt_posix.h" #include #include +#include #include #include #include #include #include #include #include #include SYSCTL_NODE(, 0, sysctl, CTLFLAG_RW, 0, "Sysctl internal magic"); SYSCTL_NODE(, CTL_KERN, kern, CTLFLAG_RW, 0, "High kernel, proc, limits &c"); SYSCTL_NODE(, CTL_VM, vm, CTLFLAG_RW, 0, "Virtual memory"); SYSCTL_NODE(, CTL_VFS, vfs, CTLFLAG_RW, 0, "File system"); SYSCTL_NODE(, CTL_NET, net, CTLFLAG_RW, 0, "Network, (see socket.h)"); SYSCTL_NODE(, CTL_DEBUG, debug, CTLFLAG_RW, 0, "Debugging"); SYSCTL_NODE(_debug, OID_AUTO, sizeof, CTLFLAG_RW, 0, "Sizeof various things"); SYSCTL_NODE(, CTL_HW, hw, CTLFLAG_RW, 0, "hardware"); SYSCTL_NODE(, CTL_MACHDEP, machdep, CTLFLAG_RW, 0, "machine dependent"); SYSCTL_NODE(, CTL_USER, user, CTLFLAG_RW, 0, "user-level"); SYSCTL_NODE(, CTL_P1003_1B, p1003_1b, CTLFLAG_RW, 0, "p1003_1b, (see p1003_1b.h)"); SYSCTL_NODE(, OID_AUTO, compat, CTLFLAG_RW, 0, "Compatibility code"); SYSCTL_NODE(, OID_AUTO, security, CTLFLAG_RW, 0, "Security"); #ifdef REGRESSION SYSCTL_NODE(, OID_AUTO, regression, CTLFLAG_RW, 0, "Regression test MIB"); #endif SYSCTL_STRING(_kern, OID_AUTO, ident, CTLFLAG_RD, kern_ident, 0, "Kernel identifier"); SYSCTL_STRING(_kern, KERN_OSRELEASE, osrelease, CTLFLAG_RD, osrelease, 0, "Operating system release"); SYSCTL_INT(_kern, KERN_OSREV, osrevision, CTLFLAG_RD, 0, BSD, "Operating system revision"); SYSCTL_STRING(_kern, KERN_VERSION, version, CTLFLAG_RD, version, 0, "Kernel version"); SYSCTL_STRING(_kern, KERN_OSTYPE, ostype, CTLFLAG_RD, ostype, 0, "Operating system type"); /* * NOTICE: The *userland* release date is available in * /usr/include/osreldate.h */ extern int osreldate; SYSCTL_INT(_kern, KERN_OSRELDATE, osreldate, CTLFLAG_RD, &osreldate, 0, "Kernel release date"); SYSCTL_INT(_kern, KERN_MAXPROC, maxproc, CTLFLAG_RDTUN, &maxproc, 0, "Maximum number of processes"); SYSCTL_INT(_kern, KERN_MAXPROCPERUID, maxprocperuid, CTLFLAG_RW, &maxprocperuid, 0, "Maximum processes allowed per userid"); SYSCTL_INT(_kern, OID_AUTO, maxusers, CTLFLAG_RDTUN, &maxusers, 0, "Hint for kernel tuning"); SYSCTL_INT(_kern, KERN_ARGMAX, argmax, CTLFLAG_RD, 0, ARG_MAX, "Maximum bytes of argument to execve(2)"); SYSCTL_INT(_kern, KERN_POSIX1, posix1version, CTLFLAG_RD, 0, _POSIX_VERSION, "Version of POSIX attempting to comply to"); SYSCTL_INT(_kern, KERN_NGROUPS, ngroups, CTLFLAG_RD, 0, NGROUPS_MAX, "Maximum number of groups a user can belong to"); SYSCTL_INT(_kern, KERN_JOB_CONTROL, job_control, CTLFLAG_RD, 0, 1, "Whether job control is available"); #ifdef _POSIX_SAVED_IDS SYSCTL_INT(_kern, KERN_SAVED_IDS, saved_ids, CTLFLAG_RD, 0, 1, "Whether saved set-group/user ID is available"); #else SYSCTL_INT(_kern, KERN_SAVED_IDS, saved_ids, CTLFLAG_RD, 0, 0, "Whether saved set-group/user ID is available"); #endif char kernelname[MAXPATHLEN] = "/kernel"; /* XXX bloat */ SYSCTL_STRING(_kern, KERN_BOOTFILE, bootfile, CTLFLAG_RW, kernelname, sizeof kernelname, "Name of kernel file booted"); SYSCTL_INT(_hw, HW_NCPU, ncpu, CTLFLAG_RD, &mp_ncpus, 0, "Number of active CPUs"); SYSCTL_INT(_hw, HW_BYTEORDER, byteorder, CTLFLAG_RD, 0, BYTE_ORDER, "System byte order"); SYSCTL_INT(_hw, HW_PAGESIZE, pagesize, CTLFLAG_RD, 0, PAGE_SIZE, "System memory page size"); static int sysctl_hw_physmem(SYSCTL_HANDLER_ARGS) { u_long val; val = ctob(physmem); return (sysctl_handle_long(oidp, &val, 0, req)); } SYSCTL_PROC(_hw, HW_PHYSMEM, physmem, CTLTYPE_ULONG | CTLFLAG_RD, 0, 0, sysctl_hw_physmem, "LU", ""); static int sysctl_hw_realmem(SYSCTL_HANDLER_ARGS) { u_long val; val = ctob(realmem); return (sysctl_handle_long(oidp, &val, 0, req)); } SYSCTL_PROC(_hw, HW_REALMEM, realmem, CTLTYPE_ULONG | CTLFLAG_RD, 0, 0, sysctl_hw_realmem, "LU", ""); static int sysctl_hw_usermem(SYSCTL_HANDLER_ARGS) { u_long val; val = ctob(physmem - cnt.v_wire_count); return (sysctl_handle_long(oidp, &val, 0, req)); } SYSCTL_PROC(_hw, HW_USERMEM, usermem, CTLTYPE_ULONG | CTLFLAG_RD, 0, 0, sysctl_hw_usermem, "LU", ""); SYSCTL_ULONG(_hw, OID_AUTO, availpages, CTLFLAG_RD, &physmem, 0, ""); static char machine_arch[] = MACHINE_ARCH; SYSCTL_STRING(_hw, HW_MACHINE_ARCH, machine_arch, CTLFLAG_RD, machine_arch, 0, "System architecture"); char hostname[MAXHOSTNAMELEN]; static int sysctl_hostname(SYSCTL_HANDLER_ARGS) { struct prison *pr; char tmphostname[MAXHOSTNAMELEN]; int error; pr = req->td->td_ucred->cr_prison; if (pr != NULL) { if (!jail_set_hostname_allowed && req->newptr) return (EPERM); /* * Process is in jail, so make a local copy of jail * hostname to get/set so we don't have to hold the jail * mutex during the sysctl copyin/copyout activities. */ mtx_lock(&pr->pr_mtx); bcopy(pr->pr_host, tmphostname, MAXHOSTNAMELEN); mtx_unlock(&pr->pr_mtx); error = sysctl_handle_string(oidp, tmphostname, sizeof pr->pr_host, req); if (req->newptr != NULL && error == 0) { /* * Copy the locally set hostname to the jail, if * appropriate. */ mtx_lock(&pr->pr_mtx); bcopy(tmphostname, pr->pr_host, MAXHOSTNAMELEN); mtx_unlock(&pr->pr_mtx); } } else error = sysctl_handle_string(oidp, hostname, sizeof hostname, req); return (error); } SYSCTL_PROC(_kern, KERN_HOSTNAME, hostname, CTLTYPE_STRING|CTLFLAG_RW|CTLFLAG_PRISON, 0, 0, sysctl_hostname, "A", "Hostname"); static int regression_securelevel_nonmonotonic = 0; #ifdef REGRESSION SYSCTL_INT(_regression, OID_AUTO, securelevel_nonmonotonic, CTLFLAG_RW, ®ression_securelevel_nonmonotonic, 0, "securelevel may be lowered"); #endif int securelevel = -1; static struct mtx securelevel_mtx; MTX_SYSINIT(securelevel_lock, &securelevel_mtx, "securelevel mutex lock", MTX_DEF); static int sysctl_kern_securelvl(SYSCTL_HANDLER_ARGS) { struct prison *pr; int error, level; pr = req->td->td_ucred->cr_prison; /* * If the process is in jail, return the maximum of the global and * local levels; otherwise, return the global level. Perform a * lockless read since the securelevel is an integer. */ if (pr != NULL) level = imax(securelevel, pr->pr_securelevel); else level = securelevel; error = sysctl_handle_int(oidp, &level, 0, req); if (error || !req->newptr) return (error); /* * Permit update only if the new securelevel exceeds the * global level, and local level if any. */ if (pr != NULL) { mtx_lock(&pr->pr_mtx); if (!regression_securelevel_nonmonotonic && (level < imax(securelevel, pr->pr_securelevel))) { mtx_unlock(&pr->pr_mtx); return (EPERM); } pr->pr_securelevel = level; mtx_unlock(&pr->pr_mtx); } else { mtx_lock(&securelevel_mtx); if (!regression_securelevel_nonmonotonic && (level < securelevel)) { mtx_unlock(&securelevel_mtx); return (EPERM); } securelevel = level; mtx_unlock(&securelevel_mtx); } return (error); } SYSCTL_PROC(_kern, KERN_SECURELVL, securelevel, CTLTYPE_INT|CTLFLAG_RW|CTLFLAG_PRISON, 0, 0, sysctl_kern_securelvl, "I", "Current secure level"); + +/* Actual kernel configuration options. */ +extern char kernconfstring[]; + +static int +sysctl_kern_config(SYSCTL_HANDLER_ARGS) +{ + struct sbuf *sb; + int error; + char *p; + + sb = sbuf_new(NULL, NULL, 2048, SBUF_AUTOEXTEND); + if (sb == NULL) + return (ENOMEM); + sbuf_clear(sb); + p = kernconfstring; + if (p == NULL || *p == '\0') { + sbuf_printf(sb, "No kernel configuration\n"); + } else { + sbuf_printf(sb, "%s", p); + } + sbuf_trim(sb); + sbuf_putc(sb, '\n'); + sbuf_finish(sb); + error = sysctl_handle_string(oidp, sbuf_data(sb), sbuf_len(sb), req); + if (error) + return (error); + sbuf_delete(sb); + return (error); +} +SYSCTL_PROC(_kern, OID_AUTO, conftxt, CTLTYPE_STRING|CTLFLAG_RW, + 0, 0, sysctl_kern_config, "", "Kernel configuration file"); char domainname[MAXHOSTNAMELEN]; SYSCTL_STRING(_kern, KERN_NISDOMAINNAME, domainname, CTLFLAG_RW, &domainname, sizeof(domainname), "Name of the current YP/NIS domain"); u_long hostid; SYSCTL_ULONG(_kern, KERN_HOSTID, hostid, CTLFLAG_RW, &hostid, 0, "Host ID"); char hostuuid[64] = "00000000-0000-0000-0000-000000000000"; SYSCTL_STRING(_kern, KERN_HOSTUUID, hostuuid, CTLFLAG_RW, hostuuid, sizeof(hostuuid), "Host UUID"); /* * This is really cheating. These actually live in the libc, something * which I'm not quite sure is a good idea anyway, but in order for * getnext and friends to actually work, we define dummies here. */ SYSCTL_STRING(_user, USER_CS_PATH, cs_path, CTLFLAG_RD, "", 0, "PATH that finds all the standard utilities"); SYSCTL_INT(_user, USER_BC_BASE_MAX, bc_base_max, CTLFLAG_RD, 0, 0, "Max ibase/obase values in bc(1)"); SYSCTL_INT(_user, USER_BC_DIM_MAX, bc_dim_max, CTLFLAG_RD, 0, 0, "Max array size in bc(1)"); SYSCTL_INT(_user, USER_BC_SCALE_MAX, bc_scale_max, CTLFLAG_RD, 0, 0, "Max scale value in bc(1)"); SYSCTL_INT(_user, USER_BC_STRING_MAX, bc_string_max, CTLFLAG_RD, 0, 0, "Max string length in bc(1)"); SYSCTL_INT(_user, USER_COLL_WEIGHTS_MAX, coll_weights_max, CTLFLAG_RD, 0, 0, "Maximum number of weights assigned to an LC_COLLATE locale entry"); SYSCTL_INT(_user, USER_EXPR_NEST_MAX, expr_nest_max, CTLFLAG_RD, 0, 0, ""); SYSCTL_INT(_user, USER_LINE_MAX, line_max, CTLFLAG_RD, 0, 0, "Max length (bytes) of a text-processing utility's input line"); SYSCTL_INT(_user, USER_RE_DUP_MAX, re_dup_max, CTLFLAG_RD, 0, 0, "Maximum number of repeats of a regexp permitted"); SYSCTL_INT(_user, USER_POSIX2_VERSION, posix2_version, CTLFLAG_RD, 0, 0, "The version of POSIX 1003.2 with which the system attempts to comply"); SYSCTL_INT(_user, USER_POSIX2_C_BIND, posix2_c_bind, CTLFLAG_RD, 0, 0, "Whether C development supports the C bindings option"); SYSCTL_INT(_user, USER_POSIX2_C_DEV, posix2_c_dev, CTLFLAG_RD, 0, 0, "Whether system supports the C development utilities option"); SYSCTL_INT(_user, USER_POSIX2_CHAR_TERM, posix2_char_term, CTLFLAG_RD, 0, 0, ""); SYSCTL_INT(_user, USER_POSIX2_FORT_DEV, posix2_fort_dev, CTLFLAG_RD, 0, 0, "Whether system supports FORTRAN development utilities"); SYSCTL_INT(_user, USER_POSIX2_FORT_RUN, posix2_fort_run, CTLFLAG_RD, 0, 0, "Whether system supports FORTRAN runtime utilities"); SYSCTL_INT(_user, USER_POSIX2_LOCALEDEF, posix2_localedef, CTLFLAG_RD, 0, 0, "Whether system supports creation of locales"); SYSCTL_INT(_user, USER_POSIX2_SW_DEV, posix2_sw_dev, CTLFLAG_RD, 0, 0, "Whether system supports software development utilities"); SYSCTL_INT(_user, USER_POSIX2_UPE, posix2_upe, CTLFLAG_RD, 0, 0, "Whether system supports the user portability utilities"); SYSCTL_INT(_user, USER_STREAM_MAX, stream_max, CTLFLAG_RD, 0, 0, "Min Maximum number of streams a process may have open at one time"); SYSCTL_INT(_user, USER_TZNAME_MAX, tzname_max, CTLFLAG_RD, 0, 0, "Min Maximum number of types supported for timezone names"); #include SYSCTL_INT(_debug_sizeof, OID_AUTO, vnode, CTLFLAG_RD, 0, sizeof(struct vnode), "sizeof(struct vnode)"); SYSCTL_INT(_debug_sizeof, OID_AUTO, proc, CTLFLAG_RD, 0, sizeof(struct proc), "sizeof(struct proc)"); #include #include SYSCTL_INT(_debug_sizeof, OID_AUTO, bio, CTLFLAG_RD, 0, sizeof(struct bio), "sizeof(struct bio)"); SYSCTL_INT(_debug_sizeof, OID_AUTO, buf, CTLFLAG_RD, 0, sizeof(struct buf), "sizeof(struct buf)"); #include SYSCTL_INT(_debug_sizeof, OID_AUTO, kinfo_proc, CTLFLAG_RD, 0, sizeof(struct kinfo_proc), "sizeof(struct kinfo_proc)"); /* XXX compatibility, remove for 6.0 */ #include #include SYSCTL_INT(_kern, OID_AUTO, fallback_elf_brand, CTLFLAG_RW, &__elfN(fallback_brand), sizeof(__elfN(fallback_brand)), "compatibility for kern.fallback_elf_brand"); Index: head/usr.sbin/config/Makefile =================================================================== --- head/usr.sbin/config/Makefile (revision 169506) +++ head/usr.sbin/config/Makefile (revision 169507) @@ -1,17 +1,22 @@ # @(#)Makefile 8.1 (Berkeley) 6/6/93 # $FreeBSD$ PROG= config MAN= config.5 config.8 SRCS= config.y main.c lang.l mkmakefile.c mkheaders.c \ - mkoptions.c y.tab.h + mkoptions.c y.tab.h kernconf.c +kernconf.c: kernconf.tmpl + file2c 'char kernconfstr[] = {' ',0};' < kernconf.tmpl > kernconf.c + WARNS?= 6 CFLAGS+= -I. -I${.CURDIR} DPADD= ${LIBL} -LDADD= -ll +LDADD= -ll -lsbuf + +CLEANFILES+= kernconf.c mkmakefile.o: configvers.h .include Index: head/usr.sbin/config/config.8 =================================================================== --- head/usr.sbin/config/config.8 (revision 169506) +++ head/usr.sbin/config/config.8 (revision 169507) @@ -1,258 +1,274 @@ .\" 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. .\" 4. 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. .\" .\" @(#)config.8 8.2 (Berkeley) 4/19/94 .\" $FreeBSD$ .\" -.Dd December 16, 2004 +.Dd May 8, 2007 .Dt CONFIG 8 .Os .Sh NAME .Nm config .Nd build system configuration files .Sh SYNOPSIS .Nm -.Op Fl Vgp +.Op Fl CVgp .Op Fl d Ar destdir .Ar SYSTEM_NAME +.Nm +.Op Fl x Ar kernel .Sh DESCRIPTION .\" This is the old version of the .\" .Nm .\" utility. .\" It understands the old autoconfiguration scheme .\" used on the HP300, i386, DECstation, and derivative platforms. .\" The new version of .\" .Nm .\" is used with the .\" SPARC platform. .\" Only the version of .\" .Nm .\" applicable to the architecture that you are running .\" will be installed on your machine. .\" .Pp The .Nm utility builds a set of system configuration files from the file .Ar SYSTEM_NAME which describes the system to configure. A second file tells .Nm what files are needed to generate a system and can be augmented by configuration specific set of files that give alternate files for a specific machine (see the .Sx FILES section below). .Pp Available options and operands: .Bl -tag -width ".Ar SYSTEM_NAME" .It Fl V Print the .Nm version number. +.It Fl C +If the INCLUDE_CONFIG_FILE is present in a configuration file, +kernel image will contain full configuration files included +literally (preserving comments). +This flag is kept for backward compatibility. .It Fl d Ar destdir Use .Ar destdir as the output directory, instead of the default one. Note that .Nm does not append .Ar SYSTEM_NAME to the directory given. .It Fl g Configure a system for debugging. +.It Fl x Ar kernel +Print kernel configuration file embedded into a kernel +file. +This option makes sense only if +.Cd "options INCLUDE_CONFIG_FILE" +entry was present in your configuration file. .It Fl p Configure a system for profiling; for example, .Xr kgmon 8 and .Xr gprof 1 . If two or more .Fl p options are supplied, .Nm configures a system for high resolution profiling. .It Ar SYSTEM_NAME Specify the name of the system configuration file containing device specifications, configuration options and other system parameters for one system configuration. .El .Pp The .Nm utility should be run from the .Pa conf subdirectory of the system source (usually .Pa /sys/ Ns Va ARCH Ns Pa /conf ) , where .Va ARCH represents one of the architectures supported by .Fx . The .Nm utility creates the directory .Pa ../compile/ Ns Ar SYSTEM_NAME or the one given with the .Fl d option as necessary and places all output files there. The output of .Nm consists of a number of files; for the .Tn i386 , they are: .Pa Makefile , used by .Xr make 1 in building the system; header files, definitions of the number of various devices that will be compiled into the system. .Pp After running .Nm , it is necessary to run .Dq Li make depend in the directory where the new makefile was created. The .Nm utility prints a reminder of this when it completes. .Pp If any other error messages are produced by .Nm , the problems in the configuration file should be corrected and .Nm should be run again. Attempts to compile a system that had configuration errors are likely to fail. -.Pp -If the -.Cd "options INCLUDE_CONFIG_FILE" -is used in the configuration file the -entire input file is embedded in the new kernel. -This means that -.Xr strings 1 -can be used to extract it from a kernel: -to extract the configuration information, use the command -.Pp -.Dl "strings -n 3 kernel | sed -n 's/^___//p'" .Sh DEBUG KERNELS Traditional .Bx kernels are compiled without symbols due to the heavy load on the system when compiling a .Dq debug kernel. A debug kernel contains complete symbols for all the source files, and enables an experienced kernel programmer to analyse the cause of a problem. The debuggers available prior to .Bx 4.4 Lite were able to find some information from a normal kernel; .Xr gdb 1 provides very little support for normal kernels, and a debug kernel is needed for any meaningful analysis. .Pp For reasons of history, time and space, building a debug kernel is not the default with .Fx : a debug kernel takes up to 30% longer to build and requires about 30 MB of disk storage in the build directory, compared to about 6 MB for a non-debug kernel. A debug kernel is about 11 MB in size, compared to about 2 MB for a non-debug kernel. This space is used both in the root file system and at run time in memory. Use the .Fl g option to build a debug kernel. With this option, .Nm causes two kernel files to be built in the kernel build directory: .Bl -bullet .It .Pa kernel.debug is the complete debug kernel. .It .Pa kernel is a copy of the kernel with the debug symbols stripped off. This is equivalent to the normal non-debug kernel. .El .Pp There is currently little sense in installing and booting from a debug kernel, since the only tools available which use the symbols do not run on-line. There are therefore two options for installing a debug kernel: .Bl -bullet .It .Dq Li "make install" installs .Pa kernel in the root file system. .It .Dq Li "make install.debug" installs .Pa kernel.debug in the root file system. .El .Sh FILES .Bl -tag -width ".Pa /sys/ Ns Va ARCH Ns Pa /compile/ Ns Ar SYSTEM_NAME" -compact .It Pa /sys/conf/files list of common files system is built from .It Pa /sys/conf/Makefile. Ns Va ARCH generic makefile for the .Va ARCH .It Pa /sys/conf/files. Ns Va ARCH list of .Va ARCH specific files .It Pa /sys/ Ns Va ARCH Ns Pa /compile/ Ns Ar SYSTEM_NAME default kernel build directory for system .Ar SYSTEM_NAME on .Va ARCH . .El .Sh SEE ALSO .Xr config 5 .Pp The .Sx SYNOPSIS portion of each device in section 4. .Rs .%T "Building 4.3 BSD UNIX System with Config" .Re .Sh HISTORY The .Nm utility appeared in .Bx 4.1 . +.Pp +Before support for +.Fl x +was introduced, +.Cd "options INCLUDE_CONFIG_FILE" +included entire configuration file that used to be embedded in +the new kernel. +This meant that +.Xr strings 1 +could be used to extract it from a kernel: +to extract the configuration information, you had to use +the command: +.Pp +.Dl "strings -n 3 kernel | sed -n 's/^___//p'" .Sh BUGS The line numbers reported in error messages are usually off by one. Index: head/usr.sbin/config/config.h =================================================================== --- head/usr.sbin/config/config.h (revision 169506) +++ head/usr.sbin/config/config.h (revision 169507) @@ -1,177 +1,200 @@ /* * Copyright (c) 1980, 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. * 4. 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. * * @(#)config.h 8.1 (Berkeley) 6/6/93 * $FreeBSD$ */ /* * Config. */ #include #include #include #include +struct cfgfile { + STAILQ_ENTRY(cfgfile) cfg_next; + char *cfg_path; +}; +STAILQ_HEAD(, cfgfile) cfgfiles; + struct file_list { STAILQ_ENTRY(file_list) f_next; char *f_fn; /* the name */ int f_type; /* type */ u_char f_flags; /* see below */ char *f_compilewith; /* special make rule if present */ char *f_depends; /* additional dependancies */ char *f_clean; /* File list to add to clean rule */ char *f_warn; /* warning message */ }; struct files_name { char *f_name; STAILQ_ENTRY(files_name) f_next; }; /* * Types. */ #define NORMAL 1 #define PROFILING 3 #define NODEPEND 4 #define LOCAL 5 #define DEVDONE 0x80000000 #define TYPEMASK 0x7fffffff /* * Attributes (flags). */ #define NO_IMPLCT_RULE 1 #define NO_OBJ 2 #define BEFORE_DEPEND 4 #define NOWERROR 16 struct device { int d_done; /* processed */ char *d_name; /* name of device (e.g. rk11) */ #define UNKNOWN -2 /* -2 means not set yet */ STAILQ_ENTRY(device) d_next; /* Next one in list */ }; struct config { char *s_sysname; }; /* * Config has a global notion of which machine type is * being used. It uses the name of the machine in choosing * files and directories. Thus if the name of the machine is ``i386'', * it will build from ``Makefile.i386'' and use ``../i386/inline'' * in the makerules, etc. machinearch is the global notion of the * MACHINE_ARCH for this MACHINE. */ char *machinename; char *machinearch; /* * For each machine, a set of CPU's may be specified as supported. * These and the options (below) are put in the C flags in the makefile. */ struct cputype { char *cpu_name; SLIST_ENTRY(cputype) cpu_next; }; SLIST_HEAD(, cputype) cputype; /* * A set of options may also be specified which are like CPU types, * but which may also specify values for the options. * A separate set of options may be defined for make-style options. */ struct opt { char *op_name; char *op_value; int op_ownfile; /* true = own file, false = makefile */ SLIST_ENTRY(opt) op_next; }; -SLIST_HEAD(opt_head, opt) opt, mkopt; +SLIST_HEAD(opt_head, opt) opt, mkopt, rmopts; struct opt_list { char *o_name; char *o_file; SLIST_ENTRY(opt_list) o_next; }; SLIST_HEAD(, opt_list) otab; struct hint { char *hint_name; STAILQ_ENTRY(hint) hint_next; }; STAILQ_HEAD(hint_head, hint) hints; +/* + * Tag present in the kernelconf.tmlp template file. It's mandatory for those + * two strings to be the same. Otherwise you'll get into trouble. + */ +#define KERNCONFTAG "%%KERNCONFFILE%%" + +/* + * Faked option to note, that the configuration file has been taken from the + * kernel file and inclusion of DEFAULTS etc.. isn't nessesery, because we + * already have a list of all required devices. + */ +#define OPT_AUTOGEN "CONFIG_AUTOGENERATED" + extern char *ident; extern char *env; +extern char kernconfstr[]; extern int do_trace; extern int envmode; extern int hintmode; +extern int incignore; char *get_word(FILE *); char *get_quoted_word(FILE *); char *path(const char *); char *raisestr(char *); void remember(const char *); void moveifchanged(const char *, const char *); int yyparse(void); int yylex(void); void options(void); void makefile(void); void makeenv(void); void makehints(void); void headers(void); +void cfgfile_add(const char *); +void cfgfile_removeall(void); -extern STAILQ_HEAD(device_head, device) dtab; +extern STAILQ_HEAD(device_head, device) dtab, rmdtab; extern char errbuf[80]; extern int yyline; extern const char *yyfile; extern STAILQ_HEAD(file_list_head, file_list) ftab; extern STAILQ_HEAD(files_name_head, files_name) fntab; extern int profiling; extern int debugging; extern int found_defaults; extern int maxusers; extern char *PREFIX; /* Config file name - for error messages */ extern char srcdir[]; /* root of the kernel source tree */ #define eq(a,b) (!strcmp(a,b)) #define ns(s) strdup(s) Index: head/usr.sbin/config/config.y =================================================================== --- head/usr.sbin/config/config.y (revision 169506) +++ head/usr.sbin/config/config.y (revision 169507) @@ -1,444 +1,499 @@ %union { char *str; int val; struct file_list *file; } %token ARCH %token COMMA %token CONFIG %token CPU %token NOCPU %token DEVICE %token NODEVICE %token ENV %token EQUALS %token HINTS %token IDENT %token MAXUSERS %token PROFILE %token OPTIONS %token NOOPTION %token MAKEOPTIONS %token NOMAKEOPTION %token SEMICOLON %token INCLUDE %token FILES %token ID %token NUMBER %type Save_id %type Opt_value %type Dev %{ /* * Copyright (c) 1988, 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. 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, Berkeley and its contributors. * 4. 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. * * @(#)config.y 8.1 (Berkeley) 6/6/93 * $FreeBSD$ */ +#include #include #include #include #include #include "config.h" -struct device_head dtab; +struct device_head dtab, rmdtab; char *ident; char *env; int envmode; int hintmode; int yyline; const char *yyfile; struct file_list_head ftab; struct files_name_head fntab; char errbuf[80]; int maxusers; #define ns(s) strdup(s) int include(const char *, int); void yyerror(const char *s); int yywrap(void); static char * devopt(char *dev) { char *ret = malloc(strlen(dev) + 5); sprintf(ret, "DEV_%s", dev); raisestr(ret); return ret; } +static void rmoptall(struct opt_head *list, struct opt_head *torem); +static void rmdevall(struct device_head *dh, struct device_head *torem); + %} %% Configuration: Many_specs ; Many_specs: Many_specs Spec | /* lambda */ ; Spec: Device_spec SEMICOLON | Config_spec SEMICOLON | INCLUDE ID SEMICOLON - = { include($2, 0); }; + = { + if (incignore == 0) + include($2, 0); + }; | FILES ID SEMICOLON = { newfile($2); }; | SEMICOLON | error SEMICOLON ; Config_spec: ARCH Save_id = { if (machinename != NULL && !eq($2, machinename)) errx(1, "%s:%d: only one machine directive is allowed", yyfile, yyline); machinename = $2; machinearch = $2; } | ARCH Save_id Save_id = { if (machinename != NULL && !(eq($2, machinename) && eq($3, machinearch))) errx(1, "%s:%d: only one machine directive is allowed", yyfile, yyline); machinename = $2; machinearch = $3; } | CPU Save_id = { struct cputype *cp = (struct cputype *)calloc(1, sizeof (struct cputype)); cp->cpu_name = $2; SLIST_INSERT_HEAD(&cputype, cp, cpu_next); } | NOCPU Save_id = { struct cputype *cp, *cp2; SLIST_FOREACH_SAFE(cp, &cputype, cpu_next, cp2) { if (eq(cp->cpu_name, $2)) { SLIST_REMOVE(&cputype, cp, cputype, cpu_next); free(cp); } } } | OPTIONS Opt_list | NOOPTION Save_id - = { rmopt(&opt, $2); } | + = { rmopt_schedule(&rmopts, $2); } | MAKEOPTIONS Mkopt_list | NOMAKEOPTION Save_id - = { rmopt(&mkopt, $2); } | + = { rmopt_schedule(&mkopt, $2); } | IDENT ID = { ident = $2; } | System_spec | MAXUSERS NUMBER = { maxusers = $2; } | PROFILE NUMBER = { profiling = $2; } | ENV ID = { env = $2; envmode = 1; } | HINTS ID = { struct hint *hint; hint = (struct hint *)calloc(1, sizeof (struct hint)); hint->hint_name = $2; STAILQ_INSERT_TAIL(&hints, hint, hint_next); hintmode = 1; } System_spec: CONFIG System_id System_parameter_list = { errx(1, "%s:%d: root/dump/swap specifications obsolete", yyfile, yyline);} | CONFIG System_id ; System_id: Save_id = { newopt(&mkopt, ns("KERNEL"), $1); }; System_parameter_list: System_parameter_list ID | ID ; Opt_list: Opt_list COMMA Option | Option ; Option: Save_id = { newopt(&opt, $1, NULL); if (strchr($1, '=') != NULL) errx(1, "%s:%d: The `=' in options should not be " "quoted", yyfile, yyline); } | Save_id EQUALS Opt_value = { newopt(&opt, $1, $3); } ; Opt_value: ID = { $$ = $1; } | NUMBER = { char buf[80]; (void) snprintf(buf, sizeof(buf), "%d", $1); $$ = ns(buf); } ; Save_id: ID = { $$ = $1; } ; Mkopt_list: Mkopt_list COMMA Mkoption | Mkoption ; Mkoption: Save_id = { newopt(&mkopt, $1, ns("")); } | Save_id EQUALS Opt_value = { newopt(&mkopt, $1, $3); } ; Dev: ID = { $$ = $1; } ; Device_spec: DEVICE Dev_list | NODEVICE NoDev_list ; Dev_list: Dev_list COMMA Device | Device ; NoDev_list: NoDev_list COMMA NoDevice | NoDevice ; Device: Dev = { newopt(&opt, devopt($1), ns("1")); /* and the device part */ newdev($1); } NoDevice: Dev = { char *s = devopt($1); - rmopt(&opt, s); + rmopt_schedule(&rmopts, s); free(s); /* and the device part */ - rmdev($1); + rmdev_schedule(&rmdtab, $1); } ; %% void yyerror(const char *s) { errx(1, "%s:%d: %s", yyfile, yyline + 1, s); } int yywrap(void) { - if (found_defaults) { - if (freopen(PREFIX, "r", stdin) == NULL) - err(2, "%s", PREFIX); - yyfile = PREFIX; + if (found_defaults == 0 && incignore == 0) { + if (freopen("DEFAULTS", "r", stdin) == NULL) + return 1; + yyfile = "DEFAULTS"; yyline = 0; - found_defaults = 0; + found_defaults = 1; return 0; } + rmoptall(&opt, &rmopts); + rmdevall(&dtab, &rmdtab); return 1; } /* * Add a new file to the list of files. */ static void newfile(char *name) { struct files_name *nl; nl = (struct files_name *) calloc(1, sizeof *nl); nl->f_name = name; STAILQ_INSERT_TAIL(&fntab, nl, f_next); } /* * Find a device in the list of devices. */ static struct device * -finddev(char *name) +finddev(struct device_head *dlist, char *name) { struct device *dp; - STAILQ_FOREACH(dp, &dtab, d_next) + STAILQ_FOREACH(dp, dlist, d_next) if (eq(dp->d_name, name)) return (dp); return (NULL); } /* * Add a device to the list of devices. */ static void newdev(char *name) { struct device *np; - if (finddev(name)) { + if (finddev(&dtab, name)) { printf("WARNING: duplicate device `%s' encountered.\n", name); return; } np = (struct device *) calloc(1, sizeof *np); np->d_name = name; STAILQ_INSERT_TAIL(&dtab, np, d_next); } /* - * Remove a device from the list of devices. + * Schedule a device to removal. */ static void -rmdev(char *name) +rmdev_schedule(struct device_head *dh, char *name) { struct device *dp; - dp = finddev(name); - if (dp != NULL) { - STAILQ_REMOVE(&dtab, dp, device, d_next); - free(dp->d_name); + dp = calloc(1, sizeof(struct device)); + dp->d_name = strdup(name); + assert(dp->d_name != NULL); + STAILQ_INSERT_HEAD(dh, dp, d_next); +} + +/* + * Take care a devices previously scheduled for removal. + */ +static void +rmdevall(struct device_head *dh, struct device_head *torem) +{ + struct device *dp, *rdp; + + while (!STAILQ_EMPTY(torem)) { + dp = STAILQ_FIRST(torem); + STAILQ_REMOVE_HEAD(torem, d_next); + rdp = finddev(dh, dp->d_name); + if (rdp != NULL) { + STAILQ_REMOVE(dh, rdp, device, d_next); + free(rdp->d_name); + free(rdp); + } free(dp); } } /* * Find an option in the list of options. */ static struct opt * findopt(struct opt_head *list, char *name) { struct opt *op; SLIST_FOREACH(op, list, op_next) if (eq(op->op_name, name)) return (op); return (NULL); } /* * Add an option to the list of options. */ static void newopt(struct opt_head *list, char *name, char *value) { struct opt *op; + /* + * Ignore inclusions listed explicitly for configuration files. + */ + if (eq(name, OPT_AUTOGEN)) { + incignore = 1; + return; + } + if (findopt(list, name)) { printf("WARNING: duplicate option `%s' encountered.\n", name); return; } op = (struct opt *)calloc(1, sizeof (struct opt)); op->op_name = name; op->op_ownfile = 0; op->op_value = value; SLIST_INSERT_HEAD(list, op, op_next); } /* * Remove an option from the list of options. */ static void -rmopt(struct opt_head *list, char *name) +rmopt_schedule(struct opt_head *list, char *name) { struct opt *op; - op = findopt(list, name); - if (op != NULL) { - SLIST_REMOVE(list, op, opt, op_next); - free(op->op_name); - if (op->op_value != NULL) - free(op->op_value); + op = calloc(1, sizeof(*op)); + op->op_name = ns(name); + SLIST_INSERT_HEAD(list, op, op_next); +} + +/* + * Remove all options that were scheduled for removal. + */ +static void +rmoptall(struct opt_head *list, struct opt_head *torem) +{ + struct opt *op, *rop; + + op = rop = NULL; + while (!SLIST_EMPTY(torem)) { + op = SLIST_FIRST(torem); + SLIST_REMOVE_HEAD(torem, op_next); + rop = findopt(list, op->op_name); + if (rop != NULL) { + SLIST_REMOVE(list, rop, opt, op_next); + free(rop->op_name); + if (rop->op_value != NULL) + free(rop->op_value); + free(rop); + } free(op); } } Index: head/usr.sbin/config/kernconf.tmpl =================================================================== --- head/usr.sbin/config/kernconf.tmpl (nonexistent) +++ head/usr.sbin/config/kernconf.tmpl (revision 169507) @@ -0,0 +1,17 @@ +/* + * This file acts as a template for config.c that will be generated in the + * kernel build directory after config(8) has been successfully run. + * + * $FreeBSD$ + */ +#include "opt_config.h" +#ifdef INCLUDE_CONFIG_FILE + +const char kernconfstring[] __attribute__ ((section("kern_conf"))) = +"%%KERNCONFFILE%%"; + +#else + +const char kernconfstring[] = "\0"; + +#endif /* INCLUDE_CONFIG_FILE */ Property changes on: head/usr.sbin/config/kernconf.tmpl ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: head/usr.sbin/config/lang.l =================================================================== --- head/usr.sbin/config/lang.l (revision 169506) +++ head/usr.sbin/config/lang.l (revision 169507) @@ -1,273 +1,299 @@ %{ /*- * Copyright (c) 1980, 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. * 4. 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. * * @(#)lang.l 8.1 (Berkeley) 6/6/93 * $FreeBSD$ */ #include #include #include #include "y.tab.h" #include "config.h" #define YY_NO_UNPUT /* * 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 */ }; static struct incl *inclp; static const char *lastfile; /* * Key word table */ struct kt { const char *kt_name; int kt_val; } key_words[] = { { "config", CONFIG }, { "cpu", CPU }, { "nocpu", NOCPU }, { "device", DEVICE }, { "devices", DEVICE }, { "nodevice", NODEVICE }, { "nodevices", NODEVICE }, { "env", ENV }, { "hints", HINTS }, { "ident", IDENT }, { "machine", ARCH }, /* MACHINE is defined in /sys/param.h */ { "makeoption", MAKEOPTIONS }, { "makeoptions", MAKEOPTIONS }, { "nomakeoption", NOMAKEOPTION }, { "nomakeoptions", NOMAKEOPTION }, { "maxusers", MAXUSERS }, { "profile", PROFILE }, { "option", OPTIONS }, { "options", OPTIONS }, { "nooption", NOOPTION }, { "nooptions", NOOPTION }, { "include", INCLUDE }, { "files", FILES }, { 0, 0 }, }; static int endinclude(void); int include(const char *, int); int kw_lookup(char *); unsigned int octal(const char *); unsigned int hex(const char *); int yyerror(const char *); %} ID [A-Za-z_][-A-Za-z_0-9]* %START TOEOL %% {ID} { int i; BEGIN 0; if ((i = kw_lookup(yytext)) == -1) { yylval.str = strdup(yytext); return ID; } return i; } \\\"[^"]+\\\" { BEGIN 0; yytext[yyleng-2] = '"'; yytext[yyleng-1] = '\0'; yylval.str = strdup(yytext + 1); return ID; } \"[^"]+\" { BEGIN 0; yytext[yyleng-1] = '\0'; yylval.str = strdup(yytext + 1); return ID; } [^# \t\n]* { BEGIN 0; yylval.str = strdup(yytext); return ID; } 0[0-7]* { yylval.val = octal(yytext); return NUMBER; } 0x[0-9a-fA-F]+ { yylval.val = hex(yytext); return NUMBER; } -?[1-9][0-9]* { yylval.val = atoi(yytext); return NUMBER; } "?" { yylval.val = -1; return NUMBER; } \n/[ \t] { yyline++; } \n { yyline++; return SEMICOLON; } #.* { /* Ignored (comment) */; } [ \t\f]* { /* Ignored (white space) */; } ";" { return SEMICOLON; } "," { return COMMA; } "=" { BEGIN TOEOL; return EQUALS; } <> { int tok; if (inclp == NULL) return YY_NULL; tok = endinclude(); if (tok != 0) return tok; /* otherwise continue scanning */ } . { return yytext[0]; } %% /* * kw_lookup * Look up a string in the keyword table. Returns a -1 if the * string is not a keyword otherwise it returns the keyword number */ int kw_lookup(char *word) { struct kt *kp; for (kp = key_words; kp->kt_name != 0; kp++) if (eq(word, kp->kt_name)) return kp->kt_val; return -1; } /* * Number conversion routines */ unsigned int octal(const char *str) { unsigned int num; (void) sscanf(str, "%o", &num); return num; } unsigned int hex(const char *str) { unsigned int num; (void) sscanf(str+2, "%x", &num); return num; } +void +cfgfile_add(const char *fname) +{ + struct cfgfile *cf; + cf = calloc(1, sizeof(*cf)); + assert(cf != NULL); + asprintf(&cf->cfg_path, "%s", fname); + STAILQ_INSERT_TAIL(&cfgfiles, cf, cfg_next); +} + +void +cfgfile_removeall(void) +{ + struct cfgfile *cf; + + while (!STAILQ_EMPTY(&cfgfiles)) { + cf = STAILQ_FIRST(&cfgfiles); + STAILQ_REMOVE_HEAD(&cfgfiles, cfg_next); + if (cf->cfg_path != NULL) + free(cf->cfg_path); + free(cf); + } +} + /* * 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. If ateof == 0, * then nothing is inserted. */ int include(const char *fname, int ateof) { FILE *fp; struct incl *in; char *fnamebuf; + fnamebuf = NULL; fp = fopen(fname, "r"); if (fp == NULL && fname[0] != '.' && fname[0] != '/') { asprintf(&fnamebuf, "../../conf/%s", fname); if (fnamebuf != NULL) { fp = fopen(fnamebuf, "r"); free(fnamebuf); } } if (fp == NULL) { yyerror("cannot open included file"); return (-1); } + cfgfile_add(fnamebuf == NULL ? fname : fnamebuf); in = malloc(sizeof(*in)); assert(in != NULL); in->in_prev = inclp; in->in_buf = YY_CURRENT_BUFFER; in->in_fname = yyfile; in->in_lineno = yyline; in->in_ateof = ateof; inclp = in; yy_switch_to_buffer(yy_create_buffer(fp, YY_BUF_SIZE)); yyfile = fname; yyline = 0; return (0); } /* * Terminate the most recent inclusion. */ static int endinclude() { struct incl *in; int ateof; in = inclp; assert(in != NULL); inclp = 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; free(in); return (ateof); } Index: head/usr.sbin/config/main.c =================================================================== --- head/usr.sbin/config/main.c (revision 169506) +++ head/usr.sbin/config/main.c (revision 169507) @@ -1,526 +1,683 @@ /* * Copyright (c) 1980, 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. * 4. 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. */ #ifndef lint static const char copyright[] = "@(#) Copyright (c) 1980, 1993\n\ The Regents of the University of California. All rights reserved.\n"; #endif /* not lint */ #ifndef lint #if 0 static char sccsid[] = "@(#)main.c 8.1 (Berkeley) 6/6/93"; #endif static const char rcsid[] = "$FreeBSD$"; #endif /* not lint */ #include #include +#include #include #include #include + +#include #include #include #include #include #include #include #include "y.tab.h" #include "config.h" #include "configvers.h" #ifndef TRUE #define TRUE (1) #endif #ifndef FALSE #define FALSE (0) #endif #define CDIR "../compile/" char * PREFIX; char destdir[MAXPATHLEN]; char srcdir[MAXPATHLEN]; int debugging; int profiling; int found_defaults; +int incignore; +/* + * Preserve old behaviour in INCLUDE_CONFIG_FILE handling (files are included + * literally). + */ +int filebased = 0; + static void configfile(void); static void get_srcdir(void); static void usage(void); static void cleanheaders(char *); +static void kernconfdump(const char *); struct hdr_list { char *h_name; struct hdr_list *h_next; } *htab; /* * Config builds a set of files for building a UNIX * system given a description of the desired system. */ int main(int argc, char **argv) { struct stat buf; int ch, len; char *p; char xxx[MAXPATHLEN]; - FILE *fp; + char *kernfile; - while ((ch = getopt(argc, argv, "d:gpV")) != -1) + kernfile = NULL; + while ((ch = getopt(argc, argv, "Cd:gpVx:")) != -1) switch (ch) { - case 'V': - printf("%d\n", CONFIGVERS); - exit(0); + case 'C': + filebased = 1; + break; case 'd': if (*destdir == '\0') strlcpy(destdir, optarg, sizeof(destdir)); else errx(2, "directory already set"); break; case 'g': debugging++; break; case 'p': profiling++; break; + case 'V': + printf("%d\n", CONFIGVERS); + exit(0); + case 'x': + kernfile = optarg; + break; case '?': default: usage(); } argc -= optind; argv += optind; + if (kernfile != NULL) { + kernconfdump(kernfile); + exit(EXIT_SUCCESS); + } + if (argc != 1) usage(); PREFIX = *argv; - fp = fopen(PREFIX, "r"); - if (fp == NULL) + /* + * We mark lack of DEFAULTS here. Once we hit EOF in PREFIX, yywrap() + * will try to bring DEFAULTS to the playground, if this exists. + */ + found_defaults = 0; + if (freopen(PREFIX, "r", stdin) == NULL) err(2, "%s", PREFIX); - fclose(fp); - if (freopen("DEFAULTS", "r", stdin) != NULL) { - found_defaults = 1; - yyfile = "DEFAULTS"; - } else { - if (freopen(PREFIX, "r", stdin) == NULL) - err(2, "%s", PREFIX); - yyfile = PREFIX; - } - + yyfile = PREFIX; if (*destdir != '\0') { len = strlen(destdir); while (len > 1 && destdir[len - 1] == '/') destdir[--len] = '\0'; get_srcdir(); } else { strlcpy(destdir, CDIR, sizeof(destdir)); strlcat(destdir, PREFIX, sizeof(destdir)); } p = path((char *)NULL); if (stat(p, &buf)) { if (mkdir(p, 0777)) err(2, "%s", p); } else if (!S_ISDIR(buf.st_mode)) errx(2, "%s isn't a directory", p); + SLIST_INIT(&cputype); + SLIST_INIT(&mkopt); + SLIST_INIT(&opt); + SLIST_INIT(&rmopts); + STAILQ_INIT(&cfgfiles); STAILQ_INIT(&dtab); STAILQ_INIT(&fntab); - SLIST_INIT(&cputype); STAILQ_INIT(&ftab); STAILQ_INIT(&hints); + STAILQ_INIT(&rmdtab); if (yyparse()) exit(3); /* * Ensure that required elements (machine, cpu, ident) are present. */ if (machinename == NULL) { printf("Specify machine type, e.g. ``machine i386''\n"); exit(1); } if (ident == NULL) { printf("no ident line specified\n"); exit(1); } if (SLIST_EMPTY(&cputype)) { printf("cpu type must be specified\n"); exit(1); } /* * make symbolic links in compilation directory * for "sys" (to make genassym.c work along with #include ) * and similarly for "machine". */ if (*srcdir == '\0') (void)snprintf(xxx, sizeof(xxx), "../../include"); else (void)snprintf(xxx, sizeof(xxx), "%s/%s/include", srcdir, machinename); (void) unlink(path("machine")); (void) symlink(xxx, path("machine")); if (strcmp(machinename, machinearch) != 0) { /* * make symbolic links in compilation directory for * machinearch, if it is different than machinename. */ if (*srcdir == '\0') (void)snprintf(xxx, sizeof(xxx), "../../../%s/include", machinearch); else (void)snprintf(xxx, sizeof(xxx), "%s/%s/include", srcdir, machinearch); (void) unlink(path(machinearch)); (void) symlink(xxx, path(machinearch)); } + configfile(); /* put config file into kernel*/ options(); /* make options .h files */ makefile(); /* build Makefile */ makeenv(); /* build env.c */ makehints(); /* build hints.c */ headers(); /* make a lot of .h files */ - configfile(); /* put config file into kernel*/ cleanheaders(p); printf("Kernel build directory is %s\n", p); printf("Don't forget to do ``make cleandepend && make depend''\n"); exit(0); } /* * get_srcdir * determine the root of the kernel source tree * and save that in srcdir. */ static void get_srcdir(void) { if (realpath("../..", srcdir) == NULL) errx(2, "Unable to find root of source tree"); } static void usage(void) { - fprintf(stderr, "usage: config [-Vgp] [-d destdir] sysname\n"); - exit(1); + fprintf(stderr, "usage: config [-CgpV] [-d destdir] sysname\n"); + fprintf(stderr, " config -x kernel\n"); + exit(EX_USAGE); } /* * get_word * returns EOF on end of file * NULL on end of line * pointer to the word otherwise */ char * get_word(FILE *fp) { static char line[80]; int ch; char *cp; int escaped_nl = 0; begin: while ((ch = getc(fp)) != EOF) if (ch != ' ' && ch != '\t') break; if (ch == EOF) return ((char *)EOF); if (ch == '\\'){ escaped_nl = 1; goto begin; } if (ch == '\n') { if (escaped_nl){ escaped_nl = 0; goto begin; } else return (NULL); } cp = line; *cp++ = ch; while ((ch = getc(fp)) != EOF) { if (isspace(ch)) break; *cp++ = ch; } *cp = 0; if (ch == EOF) return ((char *)EOF); (void) ungetc(ch, fp); return (line); } /* * get_quoted_word * like get_word but will accept something in double or single quotes * (to allow embedded spaces). */ char * get_quoted_word(FILE *fp) { static char line[256]; int ch; char *cp; int escaped_nl = 0; begin: while ((ch = getc(fp)) != EOF) if (ch != ' ' && ch != '\t') break; if (ch == EOF) return ((char *)EOF); if (ch == '\\'){ escaped_nl = 1; goto begin; } if (ch == '\n') { if (escaped_nl){ escaped_nl = 0; goto begin; } else return (NULL); } cp = line; if (ch == '"' || ch == '\'') { int quote = ch; while ((ch = getc(fp)) != EOF) { if (ch == quote) break; if (ch == '\n') { *cp = 0; printf("config: missing quote reading `%s'\n", line); exit(2); } *cp++ = ch; } } else { *cp++ = ch; while ((ch = getc(fp)) != EOF) { if (isspace(ch)) break; *cp++ = ch; } if (ch != EOF) (void) ungetc(ch, fp); } *cp = 0; if (ch == EOF) return ((char *)EOF); return (line); } /* * prepend the path to a filename */ char * path(const char *file) { char *cp = NULL; if (file) asprintf(&cp, "%s/%s", destdir, file); else cp = strdup(destdir); return (cp); } +/* + * Generate configuration file based on actual settings. With this mode, user + * will be able to obtain and build conifguration file with one command. + */ static void +configfile_dynamic(struct sbuf *sb) +{ + struct cputype *cput; + struct device *d; + struct opt *ol; + char *lend; + + asprintf(&lend, "\\n\\\n"); + assert(lend != NULL); + sbuf_printf(sb, "options\t%s%s", OPT_AUTOGEN, lend); + sbuf_printf(sb, "ident\t%s%s", ident, lend); + sbuf_printf(sb, "machine\t%s%s", machinename, lend); + SLIST_FOREACH(cput, &cputype, cpu_next) + sbuf_printf(sb, "cpu\t%s%s", cput->cpu_name, lend); + SLIST_FOREACH(ol, &mkopt, op_next) + sbuf_printf(sb, "makeoptions\t%s=%s%s", ol->op_name, + ol->op_value, lend); + SLIST_FOREACH(ol, &opt, op_next) { + if (strncmp(ol->op_name, "DEV_", 4) == 0) + continue; + sbuf_printf(sb, "options\t%s", ol->op_name); + if (ol->op_value != NULL) { + sbuf_printf(sb, "=%s%s", ol->op_value, lend); + } else { + sbuf_printf(sb, "%s", lend); + } + } + /* + * Mark this file as containing everything we need. + */ + STAILQ_FOREACH(d, &dtab, d_next) + sbuf_printf(sb, "device\t%s%s", d->d_name, lend); + free(lend); +} + +/* + * Generate file from the configuration files. + */ +static void +configfile_filebased(struct sbuf *sb) +{ + FILE *cff; + struct cfgfile *cf; + int i; + + STAILQ_FOREACH(cf, &cfgfiles, cfg_next) { + cff = fopen(cf->cfg_path, "r"); + if (cff == NULL) { + warn("Couldn't open file %s", cf->cfg_path); + continue; + } + while ((i = getc(cff)) != EOF) { + if (i == '\n') + sbuf_printf(sb, "\\n\\\n"); + else if (i == '"' || i == '\'') + sbuf_printf(sb, "\\%c", i); + else + sbuf_putc(sb, i); + } + fclose(cff); + } +} + +static void configfile(void) { - FILE *fi, *fo; + FILE *fo; + struct sbuf *sb; char *p; - int i; - - fi = fopen(PREFIX, "r"); - if (!fi) - err(2, "%s", PREFIX); - fo = fopen(p=path("config.c.new"), "w"); + + /* Add main configuration file to the list of files to be included */ + cfgfile_add(PREFIX); + p = path("config.c.new"); + fo = fopen(p, "w"); if (!fo) err(2, "%s", p); - fprintf(fo, "#include \"opt_config.h\"\n"); - fprintf(fo, "#ifdef INCLUDE_CONFIG_FILE \n"); - fprintf(fo, "const char config[] = \"\\\n"); - fprintf(fo, "START CONFIG FILE %s\\n\\\n___", PREFIX); - while (EOF != (i=getc(fi))) { - if (i == '\n') { - fprintf(fo, "\\n\\\n___"); - } else if (i == '\"') { - fprintf(fo, "\\\""); - } else if (i == '\\') { - fprintf(fo, "\\\\"); - } else { - putc(i, fo); - } + sb = sbuf_new(NULL, NULL, 2048, SBUF_AUTOEXTEND); + assert(sb != NULL); + sbuf_clear(sb); + /* + * Try to read all configuration files. Since those will be present as + * C string in the macro, we have to slash their ends then the line + * wraps. + */ + if (filebased) { + /* Is needed, can be used for backward compatibility. */ + configfile_filebased(sb); + } else { + configfile_dynamic(sb); } - fprintf(fo, "\\n\\\nEND CONFIG FILE %s\\n\\\n", PREFIX); - fprintf(fo, "\";\n"); - fprintf(fo, "\n#endif /* INCLUDE_CONFIG_FILE */\n"); - fclose(fi); + sbuf_finish(sb); + /* + * We print first part of the tamplate, replace our tag with + * configuration files content and later continue writing our + * template. + */ + p = strstr(kernconfstr, KERNCONFTAG); + if (p == NULL) + errx(EXIT_FAILURE, "Something went terribly wrong!"); + *p = '\0'; + fprintf(fo, "%s", kernconfstr); + fprintf(fo, "%s", sbuf_data(sb)); + p += strlen(KERNCONFTAG); + fprintf(fo, "%s", p); + sbuf_delete(sb); fclose(fo); moveifchanged(path("config.c.new"), path("config.c")); + cfgfile_removeall(); } /* * moveifchanged -- * compare two files; rename if changed. */ void moveifchanged(const char *from_name, const char *to_name) { char *p, *q; int changed; size_t tsize; struct stat from_sb, to_sb; int from_fd, to_fd; changed = 0; if ((from_fd = open(from_name, O_RDONLY)) < 0) err(EX_OSERR, "moveifchanged open(%s)", from_name); if ((to_fd = open(to_name, O_RDONLY)) < 0) changed++; if (!changed && fstat(from_fd, &from_sb) < 0) err(EX_OSERR, "moveifchanged fstat(%s)", from_name); if (!changed && fstat(to_fd, &to_sb) < 0) err(EX_OSERR, "moveifchanged fstat(%s)", to_name); if (!changed && from_sb.st_size != to_sb.st_size) changed++; tsize = (size_t)from_sb.st_size; if (!changed) { p = mmap(NULL, tsize, PROT_READ, MAP_SHARED, from_fd, (off_t)0); #ifndef MAP_FAILED #define MAP_FAILED ((caddr_t) -1) #endif if (p == MAP_FAILED) err(EX_OSERR, "mmap %s", from_name); q = mmap(NULL, tsize, PROT_READ, MAP_SHARED, to_fd, (off_t)0); if (q == MAP_FAILED) err(EX_OSERR, "mmap %s", to_name); changed = memcmp(p, q, tsize); munmap(p, tsize); munmap(q, tsize); } if (changed) { if (rename(from_name, to_name) < 0) err(EX_OSERR, "rename(%s, %s)", from_name, to_name); } else { if (unlink(from_name) < 0) err(EX_OSERR, "unlink(%s)", from_name); } } static void cleanheaders(char *p) { DIR *dirp; struct dirent *dp; struct file_list *fl; struct hdr_list *hl; int i; remember("y.tab.h"); remember("setdefs.h"); STAILQ_FOREACH(fl, &ftab, f_next) remember(fl->f_fn); /* * Scan the build directory and clean out stuff that looks like * it might have been a leftover NFOO header, etc. */ if ((dirp = opendir(p)) == NULL) err(EX_OSERR, "opendir %s", p); while ((dp = readdir(dirp)) != NULL) { i = dp->d_namlen - 2; /* Skip non-headers */ if (dp->d_name[i] != '.' || dp->d_name[i + 1] != 'h') continue; /* Skip special stuff, eg: bus_if.h, but check opt_*.h */ if (index(dp->d_name, '_') && strncmp(dp->d_name, "opt_", 4) != 0) continue; /* Check if it is a target file */ for (hl = htab; hl != NULL; hl = hl->h_next) { if (eq(dp->d_name, hl->h_name)) { break; } } if (hl) continue; printf("Removing stale header: %s\n", dp->d_name); if (unlink(path(dp->d_name)) == -1) warn("unlink %s", dp->d_name); } (void)closedir(dirp); } void remember(const char *file) { char *s; struct hdr_list *hl; if ((s = strrchr(file, '/')) != NULL) s = ns(s + 1); else s = ns(file); if (index(s, '_') && strncmp(s, "opt_", 4) != 0) { free(s); return; } for (hl = htab; hl != NULL; hl = hl->h_next) { if (eq(s, hl->h_name)) { free(s); return; } } hl = calloc(1, sizeof(*hl)); hl->h_name = s; hl->h_next = htab; htab = hl; +} + +/* + * This one is quick hack. Will be probably moved to elf(3) interface. + * It takes kernel configuration file name, passes it as an argument to + * elfdump -a, which output is parsed by some UNIX tools... + */ +static void +kernconfdump(const char *file) +{ + struct stat st; + FILE *fp, *pp; + int error, len, osz, r; + unsigned int off, size; + char *cmd, *o; + + r = open(file, O_RDONLY); + if (r == -1) + errx(EXIT_FAILURE, "Couldn't open file '%s'", file); + error = fstat(r, &st); + if (error == -1) + errx(EXIT_FAILURE, "fstat() failed"); + if (S_ISDIR(st.st_mode)) + errx(EXIT_FAILURE, "'%s' is a directory", file); + fp = fdopen(r, "r"); + if (fp == NULL) + errx(EXIT_FAILURE, "fdopen() failed"); + osz = 1024; + o = calloc(1, osz); + if (o == NULL) + errx(EXIT_FAILURE, "Couldn't allocate memory"); + /* ELF note section header. */ + asprintf(&cmd, "/usr/bin/elfdump -c %s | grep -A 5 kern_conf" + "| tail -2 | cut -d ' ' -f 2 | paste - - -", file); + if (cmd == NULL) + errx(EXIT_FAILURE, "asprintf() failed"); + pp = popen(cmd, "r"); + if (pp == NULL) + errx(EXIT_FAILURE, "popen() failed"); + free(cmd); + len = fread(o, osz, 1, pp); + pclose(pp); + r = sscanf(o, "%d\t%d", &off, &size); + free(o); + if (r != 2) + errx(EXIT_FAILURE, "File %s doesn't contain configuration " + "file. Either unsupported, or not compiled with " + "INCLUDE_CONFIG_FILE", file); + r = fseek(fp, off, SEEK_CUR); + if (r != 0) + errx(EXIT_FAILURE, "fseek() failed"); + while ((r = fgetc(fp)) != EOF && size-- > 0) + fputc(r, stdout); + fclose(fp); }