Module Name:    src
Committed By:   snj
Date:           Fri Mar  6 21:00:23 UTC 2015

Modified Files:
        src/usr.bin/config [netbsd-7]: Makefile config.1 config.5 defs.h
            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 sem.h util.c
Added Files:
        src/usr.bin/config [netbsd-7]: TODO

Log Message:
Pull up following revision(s) (requested by mrg in ticket #572):
        usr.bin/config/Makefile: up to 1.10
        usr.bin/config/TODO: up to 1.14
        usr.bin/config/config.1: up to 1.17
        usr.bin/config/config.5: up to 1.25
        usr.bin/config/defs.h: up to 1.64
        usr.bin/config/files.c: up to 1.18
        usr.bin/config/gram.y: up to 1.46
        usr.bin/config/hash.c: up to 1.11
        usr.bin/config/lint.c: up to 1.15
        usr.bin/config/main.c: up to 1.74
        usr.bin/config/mkdevsw.c: up to 1.12
        usr.bin/config/mkheaders.c: up to 1.26
        usr.bin/config/mkioconf.c: up to 1.28
        usr.bin/config/mkmakefile.c: up to 1.37
        usr.bin/config/mkswap.c: up to 1.8
        usr.bin/config/pack.c: up to 1.9
        usr.bin/config/scan.l: up to 1.22
        usr.bin/config/sem.c: up to 1.71
        usr.bin/config/sem.h: up to 1.19
        usr.bin/config/util.c: up to 1.19
sync config(1) with HEAD.


To generate a diff of this commit:
cvs rdiff -u -r1.8 -r1.8.54.1 src/usr.bin/config/Makefile
cvs rdiff -u -r0 -r1.14.2.2 src/usr.bin/config/TODO
cvs rdiff -u -r1.15 -r1.15.2.1 src/usr.bin/config/config.1
cvs rdiff -u -r1.24 -r1.24.2.1 src/usr.bin/config/config.5
cvs rdiff -u -r1.45 -r1.45.2.1 src/usr.bin/config/defs.h
cvs rdiff -u -r1.12 -r1.12.2.1 src/usr.bin/config/files.c
cvs rdiff -u -r1.39 -r1.39.2.1 src/usr.bin/config/gram.y
cvs rdiff -u -r1.8 -r1.8.10.1 src/usr.bin/config/hash.c
cvs rdiff -u -r1.14 -r1.14.10.1 src/usr.bin/config/lint.c
cvs rdiff -u -r1.54 -r1.54.2.1 src/usr.bin/config/main.c
cvs rdiff -u -r1.10 -r1.10.24.1 src/usr.bin/config/mkdevsw.c
cvs rdiff -u -r1.21 -r1.21.10.1 src/usr.bin/config/mkheaders.c \
    src/usr.bin/config/mkioconf.c
cvs rdiff -u -r1.15 -r1.15.10.1 src/usr.bin/config/mkmakefile.c
cvs rdiff -u -r1.7 -r1.7.26.1 src/usr.bin/config/mkswap.c
cvs rdiff -u -r1.8 -r1.8.24.1 src/usr.bin/config/pack.c
cvs rdiff -u -r1.17 -r1.17.10.1 src/usr.bin/config/scan.l
cvs rdiff -u -r1.43 -r1.43.2.1 src/usr.bin/config/sem.c
cvs rdiff -u -r1.10 -r1.10.10.1 src/usr.bin/config/sem.h
cvs rdiff -u -r1.16 -r1.16.4.1 src/usr.bin/config/util.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/usr.bin/config/Makefile
diff -u src/usr.bin/config/Makefile:1.8 src/usr.bin/config/Makefile:1.8.54.1
--- src/usr.bin/config/Makefile:1.8	Sun May 13 20:22:45 2007
+++ src/usr.bin/config/Makefile	Fri Mar  6 21:00:23 2015
@@ -1,7 +1,8 @@
-#	$NetBSD: Makefile,v 1.8 2007/05/13 20:22:45 veego Exp $
+#	$NetBSD: Makefile,v 1.8.54.1 2015/03/06 21:00:23 snj 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 \

Index: src/usr.bin/config/config.1
diff -u src/usr.bin/config/config.1:1.15 src/usr.bin/config/config.1:1.15.2.1
--- src/usr.bin/config/config.1:1.15	Mon May  5 20:52:45 2014
+++ src/usr.bin/config/config.1	Fri Mar  6 21:00:23 2015
@@ -1,4 +1,4 @@
-.\"	$NetBSD: config.1,v 1.15 2014/05/05 20:52:45 wiz Exp $
+.\"	$NetBSD: config.1,v 1.15.2.1 2015/03/06 21:00:23 snj Exp $
 .\"
 .\" Copyright (c) 1980, 1991, 1993
 .\"	The Regents of the University of California.  All rights reserved.
@@ -29,7 +29,7 @@
 .\"
 .\"     from: @(#)config.8	8.2 (Berkeley) 4/19/94
 .\"
-.Dd May 5, 2014
+.Dd October 10, 2014
 .Dt CONFIG 1
 .Os
 .Sh NAME
@@ -37,7 +37,7 @@
 .Nd build kernel compilation directories
 .Sh SYNOPSIS
 .Nm
-.Op Fl Ppv
+.Op Fl MPpv
 .Op Fl b Ar builddir
 .Op Fl D Ar var=value
 .Op Fl s Ar srcdir
@@ -121,6 +121,12 @@ 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

Index: src/usr.bin/config/config.5
diff -u src/usr.bin/config/config.5:1.24 src/usr.bin/config/config.5:1.24.2.1
--- src/usr.bin/config/config.5:1.24	Thu May 29 08:13:17 2014
+++ src/usr.bin/config/config.5	Fri Mar  6 21:00:23 2015
@@ -1,4 +1,4 @@
-.\" $NetBSD: config.5,v 1.24 2014/05/29 08:13:17 wiz Exp $
+.\" $NetBSD: config.5,v 1.24.2.1 2015/03/06 21:00:23 snj Exp $
 .\"
 .\"  Copyright (c) 2006, 2007 The NetBSD Foundation.
 .\"  All rights reserved.
@@ -24,7 +24,7 @@
 .\"  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 .\"  POSSIBILITY OF SUCH DAMAGE.
 .\"
-.Dd May 29, 2014
+.Dd October 30, 2014
 .Dt CONFIG 5
 .Os
 .Sh NAME
@@ -620,8 +620,10 @@ Un-selects the option
 If option
 .Ar name
 has not been previously selected, the statement produces an error.
-.It Oo Ic no Oc Ic file-system Ar name Op , Ar name Op , Ar ...
-Adds or removes support for all the listed file-systems.
+.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
@@ -696,6 +698,10 @@ again.
 .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.,

Index: src/usr.bin/config/defs.h
diff -u src/usr.bin/config/defs.h:1.45 src/usr.bin/config/defs.h:1.45.2.1
--- src/usr.bin/config/defs.h:1.45	Mon May  5 19:08:13 2014
+++ src/usr.bin/config/defs.h	Fri Mar  6 21:00:23 2015
@@ -1,4 +1,4 @@
-/*	$NetBSD: defs.h,v 1.45 2014/05/05 19:08:13 martin Exp $	*/
+/*	$NetBSD: defs.h,v 1.45.2.1 2015/03/06 21:00:23 snj Exp $	*/
 
 /*
  * Copyright (c) 1992, 1993
@@ -107,7 +107,7 @@ extern const char *progname;
  * 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		20140502
+#define CONFIG_VERSION		20141030
 #define CONFIG_MINVERSION	0
 
 /*
@@ -149,6 +149,19 @@ struct defoptlist {
 	struct nvlist *dl_depends;
 };
 
+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;
+	TAILQ_HEAD(, files)	m_files;
+	int			m_weight;
+};
+
 /*
  * Attributes.  These come in three flavors: "plain", "device class,"
  * and "interface".  Plain attributes (e.g., "ether") simply serve
@@ -165,15 +178,23 @@ struct defoptlist {
  * SCSI host adapter drivers such as the SPARC "esp").
  */
 struct attr {
-	const char *a_name;		/* name of this attribute */
+	/* 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 */
-	const char *a_devclass;		/* device class described */
 	struct	loclist *a_locs;	/* locators required */
 	int	a_loclen;		/* length of above list */
 	struct	nvlist *a_devs;		/* children */
 	struct	nvlist *a_refs;		/* parents */
-	struct	attrlist *a_deps;	/* we depend on these other attrs */
-	int	a_expanding;		/* to detect cycles in attr graph */
+
+	/* "device class" */
+	const char *a_devclass;		/* device class described */
 };
 
 /*
@@ -299,8 +320,8 @@ struct devi {
 
 	/* created during packing or ioconf.c generation */
 	short	i_collapsed;	/* set => this alias no longer needed */
-	short	i_cfindex;	/* our index in cfdata */
-	short	i_locoff;	/* offset in locators.vec */
+	u_short	i_cfindex;	/* our index in cfdata */
+	int	i_locoff;	/* offset in locators.vec */
 
 };
 /* special units */
@@ -319,10 +340,12 @@ struct filetype
 	char	fit_lastc;	/* last char from path */
 	const char *fit_path;	/* full file path */
 	const char *fit_prefix;	/* any file prefix */
+	size_t fit_len;		/* path string length */
+	int fit_suffix;		/* single char suffix */
+	struct attr *fit_attr;	/* owner attr */
+	TAILQ_ENTRY(files) fit_anext;	/* next file in attr */
 };
 /* Anything less than 0x10 is sub-type specific */
-#define FIT_NOPROLOGUE  0x10    /* Don't prepend $S/ */
-#define FIT_FORCESELECT 0x20    /* Always include this file */
 
 /*
  * Files.  Each file is either standard (always included) or optional,
@@ -350,6 +373,10 @@ struct files {
 #define fi_lastc   fi_fit.fit_lastc
 #define fi_path    fi_fit.fit_path
 #define fi_prefix  fi_fit.fit_prefix
+#define fi_suffix  fi_fit.fit_suffix
+#define fi_len     fi_fit.fit_len
+#define fi_attr    fi_fit.fit_attr
+#define fi_anext   fi_fit.fit_anext
 
 /* flags */
 #define	FI_SEL		0x01	/* selected */
@@ -476,6 +503,7 @@ struct	dlhash *defoptlint;	/* lint value
 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 */
 
@@ -502,6 +530,7 @@ SLIST_HEAD(, prefix)	prefixes,	/* prefix
 			allprefixes;	/* all 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 */
 
@@ -521,21 +550,27 @@ void	checkfiles(void);
 int	fixfiles(void);		/* finalize */
 int	fixobjects(void);
 int	fixdevsw(void);
-void	addfile(const char *, struct condexpr *, int, const char *);
-void	addobject(const char *, struct condexpr *, int);
+void	addfile(const char *, struct condexpr *, u_char, const char *);
+void	addobject(const char *, struct condexpr *, u_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 */
@@ -558,6 +593,7 @@ void	emit_options(void);
 void	emit_params(void);
 
 /* main.c */
+extern	int Mflag;
 void	addoption(const char *, const char *);
 void	addfsoption(const char *);
 void	addmkoption(const char *, const char *);
@@ -609,7 +645,7 @@ int	mkswap(void);
 void	pack(void);
 
 /* scan.l */
-int	currentline(void);
+u_short	currentline(void);
 int	firstfile(const char *);
 void	package(const char *);
 int	include(const char *, int, int, int);
@@ -622,6 +658,11 @@ int	onlist(struct nvlist *, void *);
 void	prefix_push(const char *);
 void	prefix_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 */

Index: src/usr.bin/config/files.c
diff -u src/usr.bin/config/files.c:1.12 src/usr.bin/config/files.c:1.12.2.1
--- src/usr.bin/config/files.c:1.12	Wed May 21 05:25:34 2014
+++ src/usr.bin/config/files.c	Fri Mar  6 21:00:23 2015
@@ -1,4 +1,4 @@
-/*	$NetBSD: files.c,v 1.12 2014/05/21 05:25:34 dholland Exp $	*/
+/*	$NetBSD: files.c,v 1.12.2.1 2015/03/06 21:00:23 snj Exp $	*/
 
 /*
  * Copyright (c) 1992, 1993
@@ -44,6 +44,9 @@
 #include "nbtool_config.h"
 #endif
 
+#include <sys/cdefs.h>
+__RCSID("$NetBSD: files.c,v 1.12.2.1 2015/03/06 21:00:23 snj Exp $");
+
 #include <sys/param.h>
 #include <errno.h>
 #include <stdio.h>
@@ -65,6 +68,7 @@ static struct hashtab *pathtab;		/* full
 
 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 *);
@@ -82,7 +86,7 @@ initfiles(void)
 }
 
 void
-addfile(const char *path, struct condexpr *optx, int flags, const char *rule)
+addfile(const char *path, struct condexpr *optx, u_char flags, const char *rule)
 {
 	struct files *fi;
 	const char *dotp, *tail;
@@ -111,7 +115,7 @@ addfile(const char *path, struct condexp
 		tail++;
 	dotp = strrchr(tail, '.');
 	if (dotp == NULL || dotp[1] == 0 ||
-	    (baselen = dotp - tail) >= sizeof(base)) {
+	    (baselen = (size_t)(dotp - tail)) >= sizeof(base)) {
 		cfgerror("invalid pathname `%s'", path);
 		goto bad;
 	}
@@ -154,9 +158,12 @@ addfile(const char *path, struct condexp
 	fi->fi_base = intern(base);
 	fi->fi_prefix = SLIST_EMPTY(&prefixes) ? NULL :
 			SLIST_FIRST(&prefixes)->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;
 	TAILQ_INSERT_TAIL(&allfiles, fi, fi_next);
 	return;
  bad:
@@ -166,7 +173,7 @@ addfile(const char *path, struct condexp
 }
 
 void
-addobject(const char *path, struct condexpr *optx, int flags)
+addobject(const char *path, struct condexpr *optx, u_char flags)
 {
 	struct objects *oi;
 
@@ -195,6 +202,20 @@ addobject(const char *path, struct conde
 	return;
 }     
 
+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
@@ -254,12 +275,10 @@ fixfiles(void)
 		if (fi->fi_flags & FI_HIDDEN)
 			continue;
 
-		/* Optional: see if it is to be included. */
-		if (fi->fi_flags & FIT_FORCESELECT)
-		{
-			/* include it */ ;
-		}
-		else if (fi->fi_optx != NULL) {
+		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,
@@ -284,7 +303,7 @@ fixfiles(void)
 				if (ht_replace(basetab, fi->fi_base, fi) != 1)
 					panic("fixfiles ht_replace(%s)",
 					    fi->fi_base);
-				ofi->fi_flags &= ~FI_SEL;
+				ofi->fi_flags &= (u_char)~FI_SEL;
 				ofi->fi_flags |= FI_HIDDEN;
 			} else {
 				cfgxerror(fi->fi_srcfile, fi->fi_srcline,
@@ -297,6 +316,14 @@ fixfiles(void)
 			}
 		}
 		fi->fi_flags |= FI_SEL;
+		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);
 	}
 	return (err);
 }

Index: src/usr.bin/config/gram.y
diff -u src/usr.bin/config/gram.y:1.39 src/usr.bin/config/gram.y:1.39.2.1
--- src/usr.bin/config/gram.y:1.39	Thu May 29 07:47:45 2014
+++ src/usr.bin/config/gram.y	Fri Mar  6 21:00:23 2015
@@ -1,5 +1,5 @@
 %{
-/*	$NetBSD: gram.y,v 1.39 2014/05/29 07:47:45 mrg Exp $	*/
+/*	$NetBSD: gram.y,v 1.39.2.1 2015/03/06 21:00:23 snj Exp $	*/
 
 /*
  * Copyright (c) 1992, 1993
@@ -41,6 +41,9 @@
  *	from: @(#)gram.y	8.1 (Berkeley) 6/6/93
  */
 
+#include <sys/cdefs.h>
+__RCSID("$NetBSD: gram.y,v 1.39.2.1 2015/03/06 21:00:23 snj Exp $");
+
 #include <sys/types.h>
 #include <sys/param.h>
 #include <ctype.h>
@@ -159,6 +162,9 @@ static struct loclist *namelocvals(const
 	const char *str;
 	struct	numconst num;
 	int64_t	val;
+	u_char	flag;
+	devmajor_t devmajor;
+	int32_t i32;
 }
 
 %token	AND AT ATTACH
@@ -175,7 +181,7 @@ static struct loclist *namelocvals(const
 %token	XOBJECT OBSOLETE ON OPTIONS
 %token	PACKAGE PLUSEQ PREFIX PSEUDO_DEVICE PSEUDO_ROOT
 %token	ROOT
-%token	SINGLE SOURCE
+%token	SELECT SINGLE SOURCE
 %token	TYPE
 %token	VECTOR VERSION
 %token	WITH
@@ -187,7 +193,7 @@ static struct loclist *namelocvals(const
 %type	<condexpr>	cond_or_expr cond_and_expr cond_prefix_expr
 %type	<condexpr>	 cond_base_expr
 %type	<str>	fs_spec
-%type	<val>	fflags fflag oflags oflag
+%type	<flag>	fflags fflag oflags oflag
 %type	<str>	rule
 %type	<attr>	depend
 %type	<devb>	devbase
@@ -204,9 +210,9 @@ static struct loclist *namelocvals(const
 %type	<str>	device_instance
 %type	<str>	attachment
 %type	<str>	value
-%type	<val>	major_minor npseudo
+%type	<val>	major_minor
 %type	<num>	signed_number
-%type	<val>	device_flags
+%type	<i32>	int32 npseudo device_flags
 %type	<str>	deffs
 %type	<list>	deffses
 %type	<defoptlist>	defopt
@@ -217,13 +223,13 @@ static struct loclist *namelocvals(const
 %type	<str>	optfile_opt
 %type	<list>	subarches
 %type	<str>	filename stringvalue locname mkvarname
-%type	<val>	device_major_block device_major_char
+%type	<devmajor>	device_major_block device_major_char
 %type	<list>	devnodes devnodetype devnodeflags devnode_dims
 
 %%
 
 /*
- * A complete configuration consists of both the configuration part (a
+ * A complete configuration consists of both the selection part (a
  * kernel config such as GENERIC or SKYNET, plus also the various
  * std.* files), which selects the material to be in the kernel, and
  * also the definition part (files, files.*, etc.) that declares what
@@ -254,7 +260,7 @@ static struct loclist *namelocvals(const
 
 /* Complete configuration. */
 configuration:
-	topthings machine_spec definition_part configuration_part
+	topthings machine_spec definition_part selection_part
 ;
 
 /* Sequence of zero or more topthings. */
@@ -307,44 +313,132 @@ definitions:
 
 /* A single definition. */
 definition:
-	  file
-	| object
-	| device_major			{ do_devsw = 1; }
-	| prefix
-	| DEVCLASS WORD			{ (void)defattr($2, NULL, NULL, 1); }
-	| DEFFS deffses optdepend_list	{ deffilesystem($2, $3); }
-	| DEFINE WORD interface_opt depend_list
-					{ (void)defattr($2, $3, $4, 0); }
-	| DEFOPT optfile_opt defopts optdepend_list
+	  define_file
+	| define_object
+	| define_device_major
+	| define_prefix
+	| define_devclass
+	| define_filesystems
+	| define_attribute
+	| define_option
+	| define_flag
+	| define_obsolete_flag
+	| define_param
+	| define_obsolete_param
+	| define_device
+	| define_device_attachment
+	| define_maxpartitions
+	| define_maxusers
+	| define_makeoptions
+	| define_pseudo
+	| define_pseudodev
+	| define_major
+	| define_version
+;
+
+/* source file: file foo/bar.c bar|baz needs-flag compile-with blah */
+define_file:
+	XFILE filename fopts fflags rule	{ addfile($2, $3, $4, $5); }
+;
+
+/* object file: object zot.o foo|zot needs-flag */
+define_object:
+	XOBJECT filename fopts oflags	{ addobject($2, $3, $4); }
+;
+
+/* device major declaration */
+define_device_major:
+	DEVICE_MAJOR WORD device_major_char device_major_block fopts devnodes
+					{
+		adddevm($2, $3, $4, $5, $6);
+		do_devsw = 1;
+	}
+;
+
+/* prefix delimiter */
+define_prefix:
+	  PREFIX filename		{ prefix_push($2); }
+	| PREFIX			{ prefix_pop(); }
+;
+
+define_devclass:
+	DEVCLASS WORD			{ (void)defdevclass($2, NULL, NULL, 1); }
+;
+
+define_filesystems:
+	DEFFS deffses optdepend_list	{ deffilesystem($2, $3); }
+;
+
+define_attribute:
+	DEFINE WORD interface_opt depend_list
+					{ (void)defattr0($2, $3, $4, 0); }
+;
+
+define_option:
+	DEFOPT optfile_opt defopts optdepend_list
 					{ defoption($2, $3, $4); }
-	| DEFFLAG optfile_opt defopts optdepend_list
+;
+
+define_flag:
+	DEFFLAG optfile_opt defopts optdepend_list
 					{ defflag($2, $3, $4, 0); }
-	| OBSOLETE DEFFLAG optfile_opt defopts
+;
+
+define_obsolete_flag:
+	OBSOLETE DEFFLAG optfile_opt defopts
 					{ defflag($3, $4, NULL, 1); }
-	| DEFPARAM optfile_opt defopts optdepend_list
+;
+
+define_param:
+	DEFPARAM optfile_opt defopts optdepend_list
 					{ defparam($2, $3, $4, 0); }
-	| OBSOLETE DEFPARAM optfile_opt defopts
+;
+
+define_obsolete_param:
+	OBSOLETE DEFPARAM optfile_opt defopts
 					{ defparam($3, $4, NULL, 1); }
-	| DEVICE devbase interface_opt depend_list
+;
+
+define_device:
+	DEVICE devbase interface_opt depend_list
 					{ defdev($2, $3, $4, 0); }
-	| ATTACH devbase AT atlist devattach_opt depend_list
+;
+
+define_device_attachment:
+	ATTACH devbase AT atlist devattach_opt depend_list
 					{ defdevattach($5, $2, $4, $6); }
-	| MAXPARTITIONS NUMBER		{ maxpartitions = $2.val; }
-	| MAXUSERS NUMBER NUMBER NUMBER
-				    { setdefmaxusers($2.val, $3.val, $4.val); }
-	| MAKEOPTIONS condmkopt_list
+;
+
+define_maxpartitions:
+	MAXPARTITIONS int32		{ maxpartitions = $2; }
+;
+
+define_maxusers:
+	MAXUSERS int32 int32 int32
+					{ setdefmaxusers($2, $3, $4); }
+;
+
+define_makeoptions:
+	MAKEOPTIONS condmkopt_list
+;
+
+define_pseudo:
 	/* interface_opt in DEFPSEUDO is for backwards compatibility */
-	| DEFPSEUDO devbase interface_opt depend_list
+	DEFPSEUDO devbase interface_opt depend_list
 					{ defdev($2, $3, $4, 1); }
-	| DEFPSEUDODEV devbase interface_opt depend_list
+;
+
+define_pseudodev:
+	DEFPSEUDODEV devbase interface_opt depend_list
 					{ defdev($2, $3, $4, 2); }
-	| MAJOR '{' majorlist '}'
-	| VERSION NUMBER		{ setversion($2.val); }
 ;
 
-/* source file: file foo/bar.c bar|baz needs-flag compile-with blah */
-file:
-	XFILE filename fopts fflags rule	{ addfile($2, $3, $4, $5); }
+define_major:
+	MAJOR '{' majorlist '}'
+;
+
+define_version:
+	VERSION int32		{ setversion($2); }
 ;
 
 /* file options: optional expression of conditions */
@@ -371,11 +465,6 @@ rule:
 	| COMPILE_WITH stringvalue	{ $$ = $2; }
 ;
 
-/* object file: object zot.o foo|zot needs-flag */
-object:
-	XOBJECT filename fopts oflags	{ addobject($2, $3, $4); }
-;
-
 /* zero or more flags for an object file */
 oflags:
 	  /* empty */			{ $$ = 0; }
@@ -387,22 +476,16 @@ oflag:
 	NEEDS_FLAG			{ $$ = OI_NEEDSFLAG; }
 ;
 
-/* device major declaration */
-device_major:
-	DEVICE_MAJOR WORD device_major_char device_major_block fopts devnodes
-					{ adddevm($2, $3, $4, $5, $6); }
-;
-
 /* char 55 */
 device_major_char:
 	  /* empty */			{ $$ = -1; }
-	| CHAR NUMBER			{ $$ = $2.val; }
+	| CHAR int32			{ $$ = $2; }
 ;
 
 /* block 33 */
 device_major_block:
 	  /* empty */			{ $$ = -1; }
-	| BLOCK NUMBER			{ $$ = $2.val; }
+	| BLOCK int32			{ $$ = $2; }
 ;
 
 /* device node specification */
@@ -435,12 +518,6 @@ devnodeflags:
 	LINKZERO			{ $$ = new_s("DEVNODE_FLAG_LINKZERO");}
 ;
 
-/* prefix delimiter */
-prefix:
-	  PREFIX filename		{ prefix_push($2); }
-	| PREFIX			{ prefix_pop(); }
-;
-
 /* one or more file system names */
 deffses:
 	  deffs				{ $$ = new_n($1); }
@@ -479,11 +556,11 @@ locdef:
 	  locname locdefault 		{ $$ = MK3(loc, $1, $2, 0); }
 	| locname			{ $$ = MK3(loc, $1, NULL, 0); }
 	| '[' locname locdefault ']'	{ $$ = MK3(loc, $2, $3, 1); }
-	| locname '[' NUMBER ']'	{ $$ = locarray($1, $3.val, NULL, 0); }
-	| locname '[' NUMBER ']' locdefaults
-					{ $$ = locarray($1, $3.val, $5, 0); }
-	| '[' locname '[' NUMBER ']' locdefaults ']'
-					{ $$ = locarray($2, $4.val, $6, 1); }
+	| locname '[' int32 ']'	{ $$ = locarray($1, $3, NULL, 0); }
+	| locname '[' int32 ']' locdefaults
+					{ $$ = locarray($1, $3, $5, 0); }
+	| '[' locname '[' int32 ']' locdefaults ']'
+					{ $$ = locarray($2, $4, $6, 1); }
 ;
 
 /* locator name */
@@ -516,7 +593,7 @@ depends:
 
 /* one depend item (which is an attribute) */
 depend:
-	WORD				{ $$ = getattr($1); }
+	WORD				{ $$ = refattr($1); }
 ;
 
 /* list of option depends, may be empty */
@@ -594,51 +671,142 @@ majorlist:
 
 /* one major number */
 majordef:
-	devbase '=' NUMBER		{ setmajor($1, $3.val); }
+	devbase '=' int32		{ setmajor($1, $3); }
+;
+
+int32:
+	NUMBER	{
+		if ($1.val > INT_MAX || $1.val < INT_MIN)
+			cfgerror("overflow %" PRId64, $1.val);
+		else
+			$$ = (int32_t)$1.val;
+	}
 ;
 
 /************************************************************/
 
 /*
- * The configuration grammar.
+ * The selection grammar.
  */
 
-/* Complete configuration part: all std.* files plus selected config. */
-configuration_part:
-	config_items
+/* Complete selection part: all std.* files plus selected config. */
+selection_part:
+	selections
 ;
 
 /* Zero or more config items. Trap errors. */
-config_items:
+selections:
 	  /* empty */
-	| config_items '\n'
-	| config_items config_item '\n'	{ wrap_continue(); }
-	| config_items error '\n'	{ wrap_cleanup(); }
+	| selections '\n'
+	| selections selection '\n'	{ wrap_continue(); }
+	| selections error '\n'		{ wrap_cleanup(); }
 ;
 
 /* One config item. */
-config_item:
+selection:
 	  definition
-	| NO FILE_SYSTEM no_fs_list
-	| FILE_SYSTEM fs_list
-	| NO MAKEOPTIONS no_mkopt_list
-	| MAKEOPTIONS mkopt_list
-	| NO OPTIONS no_opt_list
-	| OPTIONS opt_list
-	| MAXUSERS NUMBER		{ setmaxusers($2.val); }
-	| IDENT stringvalue		{ setident($2); }
-	| NO IDENT			{ setident(NULL); }
-	| CONFIG conf root_spec sysparam_list
+	| select_attr
+	| select_no_attr
+	| select_no_filesystems
+	| select_filesystems
+	| select_no_makeoptions
+	| select_makeoptions
+	| select_no_options
+	| select_options
+	| select_maxusers
+	| select_ident
+	| select_no_ident
+	| select_config
+	| select_no_config
+	| select_no_pseudodev
+	| select_pseudodev
+	| select_pseudoroot
+	| select_no_device_instance_attachment
+	| select_no_device_attachment
+	| select_no_device_instance
+	| select_device_instance
+;
+
+select_attr:
+	SELECT WORD			{ addattr($2); }
+;
+
+select_no_attr:
+	NO SELECT WORD			{ delattr($3); }
+;
+
+select_no_filesystems:
+	NO FILE_SYSTEM no_fs_list
+;
+
+select_filesystems:
+	FILE_SYSTEM fs_list
+;
+
+select_no_makeoptions:
+	NO MAKEOPTIONS no_mkopt_list
+;
+
+select_makeoptions:
+	MAKEOPTIONS mkopt_list
+;
+
+select_no_options:
+	NO OPTIONS no_opt_list
+;
+
+select_options:
+	OPTIONS opt_list
+;
+
+select_maxusers:
+	MAXUSERS int32			{ setmaxusers($2); }
+;
+
+select_ident:
+	IDENT stringvalue		{ setident($2); }
+;
+
+select_no_ident:
+	NO IDENT			{ setident(NULL); }
+;
+
+select_config:
+	CONFIG conf root_spec sysparam_list
 					{ addconf(&conf); }
-	| NO CONFIG WORD		{ delconf($3); }
-	| NO PSEUDO_DEVICE WORD		{ delpseudo($3); }
-	| PSEUDO_DEVICE WORD npseudo	{ addpseudo($2, $3); }
-	| PSEUDO_ROOT device_instance	{ addpseudoroot($2); }
-	| NO device_instance AT attachment
+;
+
+select_no_config:
+	NO CONFIG WORD			{ delconf($3); }
+;
+
+select_no_pseudodev:
+	NO PSEUDO_DEVICE WORD		{ delpseudo($3); }
+;
+
+select_pseudodev:
+	PSEUDO_DEVICE WORD npseudo	{ addpseudo($2, $3); }
+;
+
+select_pseudoroot:
+	PSEUDO_ROOT device_instance	{ addpseudoroot($2); }
+;
+
+select_no_device_instance_attachment:
+	NO device_instance AT attachment
 					{ deldevi($2, $4); }
-	| NO DEVICE AT attachment	{ deldeva($4); }
-	| NO device_instance		{ deldev($2); }
-	| device_instance AT attachment locators device_flags
+;
+
+select_no_device_attachment:
+	NO DEVICE AT attachment		{ deldeva($4); }
+;
+
+select_no_device_instance:
+	NO device_instance		{ deldev($2); }
+;
+
+select_device_instance:
+	device_instance AT attachment locators device_flags
 					{ adddev($1, $3, $4, $5); }
 ;
 
@@ -731,14 +899,16 @@ root_spec:
 
 /* device for root fs or dump */
 dev_spec:
-	  '?'				{ $$ = new_si(intern("?"), NODEV); }
-	| WORD				{ $$ = new_si($1, NODEV); }
+	  '?'				{ $$ = new_si(intern("?"),
+					    (long long)NODEV); }
+	| WORD				{ $$ = new_si($1,
+					    (long long)NODEV); }
 	| major_minor			{ $$ = new_si(NULL, $1); }
 ;
 
 /* major and minor device number */
 major_minor:
-	MAJOR NUMBER MINOR NUMBER	{ $$ = makedev($2.val, $4.val); }
+	MAJOR NUMBER MINOR NUMBER	{ $$ = (int64_t)makedev($2.val, $4.val); }
 ;
 
 /* filesystem type for root fs specification */
@@ -761,7 +931,7 @@ sysparam:
 /* number of pseudo devices to configure (which is optional) */
 npseudo:
 	  /* empty */			{ $$ = 1; }
-	| NUMBER			{ $$ = $1.val; }
+	| int32				{ $$ = $1; }
 ;
 
 /* name of a device to configure */
@@ -792,7 +962,7 @@ locator:
 /* optional device flags */
 device_flags:
 	  /* empty */			{ $$ = 0; }
-	| FLAGS NUMBER			{ $$ = $2.val; }
+	| FLAGS int32			{ $$ = $2; }
 ;
 
 /************************************************************/

Index: src/usr.bin/config/hash.c
diff -u src/usr.bin/config/hash.c:1.8 src/usr.bin/config/hash.c:1.8.10.1
--- src/usr.bin/config/hash.c:1.8	Mon Mar 12 02:58:55 2012
+++ src/usr.bin/config/hash.c	Fri Mar  6 21:00:23 2015
@@ -1,4 +1,4 @@
-/*	$NetBSD: hash.c,v 1.8 2012/03/12 02:58:55 dholland Exp $	*/
+/*	$NetBSD: hash.c,v 1.8.10.1 2015/03/06 21:00:23 snj Exp $	*/
 
 /*
  * Copyright (c) 1992, 1993
@@ -44,6 +44,9 @@
 #include "nbtool_config.h"
 #endif
 
+#include <sys/cdefs.h>
+__RCSID("$NetBSD: hash.c,v 1.8.10.1 2015/03/06 21:00:23 snj Exp $");
+
 #include <sys/param.h>
 #include <assert.h>
 #include <stdlib.h>
@@ -58,15 +61,18 @@
 struct hashent {
 	// XXXLUKEM: a SIMPLEQ might be more appropriate
 	TAILQ_ENTRY(hashent) h_next;
-	const char *h_name;		/* the string */
+	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) */
-	u_int	ht_mask;		/* == ht_size - 1 */
-	u_int	ht_used;		/* number of entries used */
-	u_int	ht_lim;			/* when to expand */
+	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;
 };
 
@@ -81,7 +87,8 @@ static struct hashtab strings;
 
 static void			ht_expand(struct hashtab *);
 static void			ht_init(struct hashtab *, size_t);
-static inline u_int		hash(const char *);
+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);
 
 /*
@@ -109,7 +116,7 @@ ht_expand(struct hashtab *ht)
 {
 	struct hashenthead *h, *oldh;
 	struct hashent *p;
-	u_int n, i;
+	size_t n, i;
 
 	n = ht->ht_size * 2;
 	h = emalloc(n * sizeof *h);
@@ -137,27 +144,51 @@ ht_expand(struct hashtab *ht)
  * otherwise allocate a new entry.
  */
 static inline struct hashent *
-newhashent(const char *name, u_int h)
+newhashent2(const char *name1, const char *name2, u_int h)
 {
 	struct hashent *hp;
 
 	hp = ecalloc(1, sizeof(*hp));
 
-	hp->h_name = name;
+	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(const char *str)
+hash(u_int h, const char *str)
 {
-	u_int h;
 
-	for (h = 0; *str;)
-		h = (h << 5) + h + *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);
 }
 
@@ -182,7 +213,7 @@ intern(const char *s)
 	char *p;
 
 	ht = &strings;
-	h = hash(s);
+	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)
@@ -231,22 +262,23 @@ ht_free(struct hashtab *ht)
  * Insert and/or replace.
  */
 int
-ht_insrep(struct hashtab *ht, const char *nam, void *val, int replace)
+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 = hash(nam);
+	h = hash2(0, nam1, nam2);
 	hpp = &ht->ht_tab[h & ht->ht_mask];
 	TAILQ_FOREACH(hp, hpp, h_next) {
-		if (hp->h_name == nam) {
+		if (hp->h_name1 == nam1 &&
+		    hp->h_name2 == nam2) {
 			if (replace)
 				hp->h_value = val;
 			return (1);
 		}
 	}
-	hp = newhashent(nam, h);
+	hp = newhashent2(nam1, nam2, h);
 	TAILQ_INSERT_TAIL(hpp, hp, h_next);
 	hp->h_value = val;
 	if (++ht->ht_used > ht->ht_lim)
@@ -254,21 +286,27 @@ ht_insrep(struct hashtab *ht, const char
 	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_remove(struct hashtab *ht, const char *name)
+ht_remove2(struct hashtab *ht, const char *name1, const char *name2)
 {
 	struct hashent *hp;
 	struct hashenthead *hpp;
 	u_int h;
 
-	h = hash(name);
+	h = hash2(0, name1, name2);
 	hpp = &ht->ht_tab[h & ht->ht_mask];
 
 	TAILQ_FOREACH(hp, hpp, h_next) {
-		if (hp->h_name != name)
+		if (hp->h_name1 != name1 || hp->h_name2 != name2)
 			continue;
 		TAILQ_REMOVE(hpp, hp, h_next);
 
@@ -279,21 +317,33 @@ ht_remove(struct hashtab *ht, const char
 	return (1);
 }
 
+int
+ht_remove(struct hashtab *ht, const char *name)
+{
+	return ht_remove2(ht, name, NULL);
+}
+
 void *
-ht_lookup(struct hashtab *ht, const char *nam)
+ht_lookup2(struct hashtab *ht, const char *nam1, const char *nam2)
 {
 	struct hashent *hp;
 	struct hashenthead *hpp;
 	u_int h;
 
-	h = hash(nam);
+	h = hash2(0, nam1, nam2);
 	hpp = &ht->ht_tab[h & ht->ht_mask];
 	TAILQ_FOREACH(hp, hpp, h_next)
-		if (hp->h_name == nam)
+		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
@@ -301,6 +351,22 @@ ht_lookup(struct hashtab *ht, const char
  */
 
 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;

Index: src/usr.bin/config/lint.c
diff -u src/usr.bin/config/lint.c:1.14 src/usr.bin/config/lint.c:1.14.10.1
--- src/usr.bin/config/lint.c:1.14	Tue Mar 20 20:34:57 2012
+++ src/usr.bin/config/lint.c	Fri Mar  6 21:00:23 2015
@@ -1,4 +1,4 @@
-/*	$NetBSD: lint.c,v 1.14 2012/03/20 20:34:57 matt Exp $	*/
+/*	$NetBSD: lint.c,v 1.14.10.1 2015/03/06 21:00:23 snj Exp $	*/
 
 /*
  *  Copyright (c) 2007 The NetBSD Foundation.
@@ -30,6 +30,9 @@
 #include "nbtool_config.h"
 #endif
 
+#include <sys/cdefs.h>
+__RCSID("$NetBSD: lint.c,v 1.14.10.1 2015/03/06 21:00:23 snj Exp $");
+
 #include <assert.h>
 #include <stdlib.h>
 

Index: src/usr.bin/config/main.c
diff -u src/usr.bin/config/main.c:1.54 src/usr.bin/config/main.c:1.54.2.1
--- src/usr.bin/config/main.c:1.54	Sat Aug  9 12:40:14 2014
+++ src/usr.bin/config/main.c	Fri Mar  6 21:00:23 2015
@@ -1,4 +1,4 @@
-/*	$NetBSD: main.c,v 1.54 2014/08/09 12:40:14 bad Exp $	*/
+/*	$NetBSD: main.c,v 1.54.2.1 2015/03/06 21:00:23 snj Exp $	*/
 
 /*
  * Copyright (c) 1992, 1993
@@ -44,6 +44,9 @@
 #include "nbtool_config.h"
 #endif
 
+#include <sys/cdefs.h>
+__RCSID("$NetBSD: main.c,v 1.54.2.1 2015/03/06 21:00:23 snj Exp $");
+
 #ifndef MAKE_BOOTSTRAP
 #include <sys/cdefs.h>
 #define	COPYRIGHT(x)	__COPYRIGHT(x)
@@ -86,6 +89,7 @@ COPYRIGHT("@(#) Copyright (c) 1992, 1993
 int	vflag;				/* verbose output */
 int	Pflag;				/* pack locators */
 int	Lflag;				/* lint config generation */
+int	Mflag;				/* modular build */
 int	handling_cmdlineopts;		/* currently processing -D/-U options */
 
 int	yyparse(void);
@@ -93,6 +97,7 @@ int	yyparse(void);
 #ifndef MAKE_BOOTSTRAP
 extern int yydebug;
 #endif
+int	dflag;
 
 static struct dlhash *obsopttab;
 static struct hashtab *mkopttab;
@@ -148,6 +153,7 @@ static	int	extract_config(const char *, 
 int badfilename(const char *fname);
 
 const char *progname;
+extern const char *yyfile;
 
 int
 main(int argc, char **argv)
@@ -160,14 +166,19 @@ main(int argc, char **argv)
 
 	pflag = 0;
 	xflag = 0;
-	while ((ch = getopt(argc, argv, "D:LPU:dgpvb:s:x")) != -1) {
+	while ((ch = getopt(argc, argv, "D:LMPU:dgpvb:s:x")) != -1) {
 		switch (ch) {
 
-#ifndef MAKE_BOOTSTRAP
 		case 'd':
+#ifndef MAKE_BOOTSTRAP
 			yydebug = 1;
-			break;
 #endif
+			dflag++;
+			break;
+
+		case 'M':
+			Mflag = 1;
+			break;
 
 		case 'L':
 			Lflag = 1;
@@ -281,8 +292,6 @@ main(int argc, char **argv)
 	minmaxusers = 1;
 	maxmaxusers = 10000;
 	initintern();
-	initfiles();
-	initsem();
 	ident = NULL;
 	devbasetab = ht_new();
 	devroottab = ht_new();
@@ -310,6 +319,8 @@ main(int argc, char **argv)
 	nextappmkopt = &appmkoptions;
 	nextcndmkopt = &condmkoptions;
 	nextfsopt = &fsoptions;
+	initfiles();
+	initsem();
 
 	/*
 	 * Handle profiling (must do this before we try to create any
@@ -401,16 +412,19 @@ main(int argc, char **argv)
 	/*
 	 * Handle command line overrides
 	 */
+	yyfile = "handle_cmdline_makeoptions";
 	handle_cmdline_makeoptions();
 
 	/*
 	 * Detect and properly ignore orphaned devices
 	 */
+	yyfile = "kill_orphans";
 	kill_orphans();
 
 	/*
 	 * Select devices and pseudo devices and their attributes
 	 */
+	yyfile = "fixdevis";
 	if (fixdevis())
 		stop();
 
@@ -418,33 +432,44 @@ main(int argc, char **argv)
 	 * If working on an ioconf-only config, process here and exit
 	 */
 	if (ioconfname) {
+		yyfile = "pack";
 		pack();
+		yyfile = "mkioconf";
 		mkioconf();
+		yyfile = "emitlocs";
 		emitlocs();
+		yyfile = "emitioconfh";
 		emitioconfh();
 		return 0;
 	}
 
+	yyfile = "dependattrs";
+	dependattrs();
+
 	/*
 	 * Deal with option dependencies.
 	 */
+	yyfile = "dependopts";
 	dependopts();
 
 	/*
 	 * Fix (as in `set firmly in place') files.
 	 */
+	yyfile = "fixfiles";
 	if (fixfiles())
 		stop();
 
 	/*
 	 * Fix objects and libraries.
 	 */
+	yyfile = "fixobjects";
 	if (fixobjects())
 		stop();
 
 	/*
 	 * Fix device-majors.
 	 */
+	yyfile = "fixdevsw";
 	if (fixdevsw())
 		stop();
 
@@ -468,10 +493,13 @@ main(int argc, char **argv)
 	 * Squeeze things down and finish cross-checks (STAR checks must
 	 * run after packing).
 	 */
+	yyfile = "pack";
 	pack();
+	yyfile = "badstar";
 	if (badstar())
 		stop();
 
+	yyfile = NULL;
 	/*
 	 * Ready to go.  Build all the various files.
 	 */
@@ -525,6 +553,8 @@ dependopts_one(const char *name)
 	if (fs != NULL) {
 		do_depends(fs->nv_ptr);
 	}
+
+	CFGDBG(3, "depend `%s' searched", name);
 }
 
 static void
@@ -548,6 +578,7 @@ do_depend(struct nvlist *nv)
 		 * If the dependency is an attribute, then just add
 		 * it to the selecttab.
 		 */
+		CFGDBG(3, "depend attr `%s'", nv->nv_name);
 		if ((a = ht_lookup(attrtab, nv->nv_name)) != NULL) {
 			if (a->a_iattr)
 				panic("do_depend(%s): dep `%s' is an iattr",
@@ -692,6 +723,13 @@ deffilesystem(struct nvlist *fses, struc
 			    nv->nv_name);
 
 		add_fs_dependencies(nv, deps);
+
+		/*
+		 * Implicit attribute definition for filesystem.
+		 */
+		const char *n; 
+		n = strtolower(nv->nv_name);
+		refattr(n);
 	}
 }
 
@@ -954,12 +992,14 @@ addoption(const char *name, const char *
 	/* make lowercase, then add to select table */
 	n = strtolower(name);
 	(void)ht_insert(selecttab, n, (void *)__UNCONST(n));
+	CFGDBG(3, "option selected `%s'", n);
 }
 
 void
 deloption(const char *name)
 {
 
+	CFGDBG(4, "deselecting opt `%s'", name);
 	if (undo_option(opttab, &options, &nextopt, name, "options"))
 		return;
 	if (undo_option(selecttab, NULL, NULL, strtolower(name), "options"))
@@ -993,6 +1033,14 @@ addfsoption(const char *name)
 
 	/* Add to select table. */
 	(void)ht_insert(selecttab, n, __UNCONST(n));
+	CFGDBG(3, "fs selected `%s'", name);
+
+	/*
+	 * Select attribute if one exists.
+	 */
+	struct attr *a;
+	if ((a = ht_lookup(attrtab, n)) != NULL)
+		selectattr(a);
 }
 
 void
@@ -1000,6 +1048,7 @@ delfsoption(const char *name)
 {
 	const char *n;
 
+	CFGDBG(4, "deselecting fs `%s'", name);
 	n = strtolower(name);
 	if (undo_option(fsopttab, &fsoptions, &nextfsopt, name, "file-system"))
 		return;
@@ -1021,6 +1070,7 @@ void
 delmkoption(const char *name)
 {
 
+	CFGDBG(4, "deselecting mkopt `%s'", name);
 	(void)undo_option(mkopttab, &mkoptions, &nextmkopt, name,
 	    "makeoptions");
 }
@@ -1097,8 +1147,10 @@ undo_option(struct hashtab *ht, struct n
 			cfgwarn("%s `%s' is not defined", type, name);
 		return (1);
 	}
-	if (npp == NULL)
+	if (npp == NULL) {
+		CFGDBG(2, "opt `%s' deselected", name);
 		return (0);
+	}
 
 	for ( ; *npp != NULL; npp = &(*npp)->nv_next) {
 		if ((*npp)->nv_name != name)
@@ -1106,6 +1158,7 @@ undo_option(struct hashtab *ht, struct n
 		if (next != NULL && *next == &(*npp)->nv_next)
 			*next = npp;
 		nv = (*npp)->nv_next;
+		CFGDBG(2, "opt `%s' deselected", (*npp)->nv_name);
 		nvfree(*npp);
 		*npp = nv;
 		return (0);
@@ -1501,11 +1554,11 @@ strtolower(const char *name)
 {
 	const char *n;
 	char *p, low[500];
-	unsigned char c;
+	char c;
 
 	for (n = name, p = low; (c = *n) != '\0'; n++)
-		*p++ = isupper(c) ? tolower(c) : c;
-	*p = 0;
+		*p++ = (char)(isupper((u_char)c) ? tolower((u_char)c) : c);
+	*p = '\0';
 	return (intern(low));
 }
 
@@ -1529,8 +1582,9 @@ static int
 extract_config(const char *kname, const char *cname, int cfd)
 {
 	char *ptr;
-	int found, kfd, i;
+	int found, kfd;
 	struct stat st;
+	off_t i;
 
 	found = 0;
 
@@ -1540,7 +1594,7 @@ extract_config(const char *kname, const 
 		err(EXIT_FAILURE, "cannot open %s", kname);
 	if (fstat(kfd, &st) == -1)
 		err(EXIT_FAILURE, "cannot stat %s", kname);
-	ptr = mmap(0, st.st_size, PROT_READ, MAP_FILE | MAP_SHARED,
+	ptr = mmap(0, (size_t)st.st_size, PROT_READ, MAP_FILE | MAP_SHARED,
 	    kfd, 0);
 	if (ptr == MAP_FAILED)
 		err(EXIT_FAILURE, "cannot mmap %s", kname);

Index: src/usr.bin/config/mkdevsw.c
diff -u src/usr.bin/config/mkdevsw.c:1.10 src/usr.bin/config/mkdevsw.c:1.10.24.1
--- src/usr.bin/config/mkdevsw.c:1.10	Fri Jul 30 16:23:49 2010
+++ src/usr.bin/config/mkdevsw.c	Fri Mar  6 21:00:23 2015
@@ -1,4 +1,4 @@
-/*	$NetBSD: mkdevsw.c,v 1.10 2010/07/30 16:23:49 cube Exp $	*/
+/*	$NetBSD: mkdevsw.c,v 1.10.24.1 2015/03/06 21:00:23 snj Exp $	*/
 
 /*
  * Copyright (c) 2002 The NetBSD Foundation, Inc.
@@ -33,6 +33,9 @@
 #include "nbtool_config.h"
 #endif
 
+#include <sys/cdefs.h>
+__RCSID("$NetBSD: mkdevsw.c,v 1.10.24.1 2015/03/06 21:00:23 snj Exp $");
+
 #include <stdio.h>
 #include <string.h>
 #include <errno.h>
@@ -86,37 +89,54 @@ emitheader(FILE *fp)
 		  "#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)
 {
-	struct devm *dm;
-	char mstr[16];
 	devmajor_t i;
 
 	fputs("\n/* device switch table for block device */\n", fp);
 
-	for (i = 0 ; i <= maxbdevm ; i++) {
-		(void)snprintf(mstr, sizeof(mstr), "%d", i);
-		if ((dm = ht_lookup(bdevmtab, intern(mstr))) == NULL)
-			continue;
-
-		fprintf(fp, "extern const struct bdevsw %s_bdevsw;\n",
-			    dm->dm_name);
-	}
+	for (i = 0; i <= maxbdevm ; i++)
+		dentry(fp, cdevmtab, i, 'b');
 
 	fputs("\nconst struct bdevsw *bdevsw0[] = {\n", fp);
 
-	for (i = 0 ; i <= maxbdevm ; i++) {
-		(void)snprintf(mstr, sizeof(mstr), "%d", i);
-		if ((dm = ht_lookup(bdevmtab, intern(mstr))) == NULL) {
-			fprintf(fp, "\tNULL,\n");
-		} else {
-			fprintf(fp, "\t&%s_bdevsw,\n", dm->dm_name);
-		}
-	}
+	for (i = 0; i <= maxbdevm; i++)
+		pentry(fp, bdevmtab, i, 'b');
 
 	fputs("};\n\nconst struct bdevsw **bdevsw = bdevsw0;\n", fp);
 
@@ -125,25 +145,13 @@ emitdevm(FILE *fp)
 
 	fputs("\n/* device switch table for character device */\n", fp);
 
-	for (i = 0 ; i <= maxcdevm ; i++) {
-		(void)snprintf(mstr, sizeof(mstr), "%d", i);
-		if ((dm = ht_lookup(cdevmtab, intern(mstr))) == NULL)
-			continue;
-
-		fprintf(fp, "extern const struct cdevsw %s_cdevsw;\n",
-			    dm->dm_name);
-	}
+	for (i = 0; i <= maxcdevm; i++)
+		dentry(fp, cdevmtab, i, 'c');
 
 	fputs("\nconst struct cdevsw *cdevsw0[] = {\n", fp);
 
-	for (i = 0 ; i <= maxcdevm ; i++) {
-		(void)snprintf(mstr, sizeof(mstr), "%d", i);
-		if ((dm = ht_lookup(cdevmtab, intern(mstr))) == NULL) {
-			fprintf(fp, "\tNULL,\n");
-		} else {
-			fprintf(fp, "\t&%s_cdevsw,\n", dm->dm_name);
-		}
-	}
+	for (i = 0; i <= maxcdevm; i++)
+		pentry(fp, cdevmtab, i, 'c');
 
 	fputs("};\n\nconst struct cdevsw **cdevsw = cdevsw0;\n", fp);
 
@@ -189,7 +197,9 @@ emitconv(FILE *fp)
 				d_flags = nv->nv_str;
 				break;
 			}
-			d_vec[i++] = nv->nv_num;
+			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",

Index: src/usr.bin/config/mkheaders.c
diff -u src/usr.bin/config/mkheaders.c:1.21 src/usr.bin/config/mkheaders.c:1.21.10.1
--- src/usr.bin/config/mkheaders.c:1.21	Mon Mar 12 02:58:55 2012
+++ src/usr.bin/config/mkheaders.c	Fri Mar  6 21:00:23 2015
@@ -1,4 +1,4 @@
-/*	$NetBSD: mkheaders.c,v 1.21 2012/03/12 02:58:55 dholland Exp $	*/
+/*	$NetBSD: mkheaders.c,v 1.21.10.1 2015/03/06 21:00:23 snj Exp $	*/
 
 /*
  * Copyright (c) 1992, 1993
@@ -44,6 +44,9 @@
 #include "nbtool_config.h"
 #endif
 
+#include <sys/cdefs.h>
+__RCSID("$NetBSD: mkheaders.c,v 1.21.10.1 2015/03/06 21:00:23 snj Exp $");
+
 #include <sys/param.h>
 #include <ctype.h>
 #include <errno.h>
@@ -137,10 +140,14 @@ fprint_global(FILE *fp, const char *name
 static unsigned int
 global_hash(const char *str)
 {
-        unsigned int h;
+	unsigned long h;
 	char *ep;
 
-	/* If the value is a valid numeric, just use it */
+	/*
+	 * 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 */
@@ -148,7 +155,7 @@ global_hash(const char *str)
 
 	/* Avoid colliding with the value used for undefined options. */
 	/* At least until I stop any options being set to zero */
-	return h != UNDEFINED ? h : DEFINED;
+	return (unsigned int)(h != UNDEFINED ? h : DEFINED);
 }
 
 static void
@@ -316,7 +323,7 @@ locators_print(const char *name, void *v
 		locdup = estrdup(name);
 		for (cp = locdup; *cp; cp++)
 			if (islower((unsigned char)*cp))
-				*cp = toupper((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)
@@ -328,7 +335,7 @@ locators_print(const char *name, void *v
 			namedup = estrdup(ll->ll_name);
 			for (cp = namedup; *cp; cp++)
 				if (islower((unsigned char)*cp))
-					*cp = toupper((unsigned char)*cp);
+					*cp = (char)toupper((unsigned char)*cp);
 				else if (*cp == ARRCHR)
 					*cp = '_';
 			fprintf(fp, "#define %sCF_%s %d\n", locdup, namedup, i);
@@ -520,13 +527,13 @@ static char *
 cntname(const char *src)
 {
 	char *dst;
-	unsigned char c;
+	char c;
 	static char buf[100];
 
 	dst = buf;
 	*dst++ = 'N';
 	while ((c = *src++) != 0)
-		*dst++ = islower(c) ? toupper(c) : c;
+		*dst++ = (char)(islower((u_char)c) ? toupper((u_char)c) : c);
 	*dst = 0;
 	return (buf);
 }
Index: src/usr.bin/config/mkioconf.c
diff -u src/usr.bin/config/mkioconf.c:1.21 src/usr.bin/config/mkioconf.c:1.21.10.1
--- src/usr.bin/config/mkioconf.c:1.21	Sun Mar 11 21:16:08 2012
+++ src/usr.bin/config/mkioconf.c	Fri Mar  6 21:00:23 2015
@@ -1,4 +1,4 @@
-/*	$NetBSD: mkioconf.c,v 1.21 2012/03/11 21:16:08 dholland Exp $	*/
+/*	$NetBSD: mkioconf.c,v 1.21.10.1 2015/03/06 21:00:23 snj Exp $	*/
 
 /*
  * Copyright (c) 1992, 1993
@@ -44,6 +44,9 @@
 #include "nbtool_config.h"
 #endif
 
+#include <sys/cdefs.h>
+__RCSID("$NetBSD: mkioconf.c,v 1.21.10.1 2015/03/06 21:00:23 snj Exp $");
+
 #include <sys/param.h>
 #include <err.h>
 #include <errno.h>
@@ -136,7 +139,7 @@ static void
 emithdr(FILE *ofp)
 {
 	FILE *ifp;
-	int n;
+	size_t n;
 	char ifnbuf[200], buf[BUFSIZ];
 	char *ifn;
 
@@ -174,12 +177,14 @@ cf_locators_print(const char *name, void
 	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\t{\n", name, a->a_loclen);
+		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,
@@ -319,10 +324,6 @@ emitloc(FILE *fp)
 		for (i = 0; i < locators.used; i++)
 			fprintf(fp, "%s%s,", SEP(i, 8), locators.vec[i]);
 		fprintf(fp, "\n};\n");
-	} else if (*packed != NULL) {
-		/* We need to have *something*. */
-		fprintf(fp, "\n/* locators */\n"
-			"static int loc[1] = { -1 };\n");
 	}
 }
 
@@ -375,7 +376,7 @@ emitcfdata(FILE *fp)
 		"\n"
 		"%sstruct cfdata cfdata%s%s[] = {\n"
 		"    /* driver           attachment    unit state "
-		"loc   flags pspec */\n",
+		"     loc   flags  pspec */\n",
 		    ioconfname ? "static " : "",
 		    ioconfname ? "_ioconf_" : "",
 		    ioconfname ? ioconfname : "");
@@ -428,9 +429,9 @@ emitcfdata(FILE *fp)
 			    i->i_locoff);
 			loc = locbuf;
 		} else
-			loc = "loc";
+			loc = "NULL";
 		fprintf(fp, "    { \"%s\",%s\"%s\",%s%2d, %s, %7s, %#6x, ",
-			    basename, strlen(basename) < 8 ? "\t\t"
+			    basename, strlen(basename) < 7 ? "\t\t"
 			    				   : "\t",
 			    attachment, strlen(attachment) < 5 ? "\t\t"
 			    				       : "\t",
@@ -441,7 +442,7 @@ emitcfdata(FILE *fp)
 			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");
+	    "NULL", "\t\t", "NULL", "\t\t", 0, "   0", "NULL", 0, "NULL");
 }
 
 /*
@@ -479,7 +480,7 @@ emitpseudo(FILE *fp)
 		fprintf(fp, "void %sattach(int);\n",
 		    i->i_base->d_name);
 	}
-	fputs("\nstruct pdevinit pdevinit[] = {\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",

Index: src/usr.bin/config/mkmakefile.c
diff -u src/usr.bin/config/mkmakefile.c:1.15 src/usr.bin/config/mkmakefile.c:1.15.10.1
--- src/usr.bin/config/mkmakefile.c:1.15	Fri Jun  8 08:56:45 2012
+++ src/usr.bin/config/mkmakefile.c	Fri Mar  6 21:00:23 2015
@@ -1,4 +1,4 @@
-/*	$NetBSD: mkmakefile.c,v 1.15 2012/06/08 08:56:45 martin Exp $	*/
+/*	$NetBSD: mkmakefile.c,v 1.15.10.1 2015/03/06 21:00:23 snj Exp $	*/
 
 /*
  * Copyright (c) 1992, 1993
@@ -44,6 +44,9 @@
 #include "nbtool_config.h"
 #endif
 
+#include <sys/cdefs.h>
+__RCSID("$NetBSD: mkmakefile.c,v 1.15.10.1 2015/03/06 21:00:23 snj Exp $");
+
 #include <sys/param.h>
 #include <ctype.h>
 #include <errno.h>
@@ -51,6 +54,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <err.h>
+#include <util.h>
 #include "defs.h"
 #include "sem.h"
 
@@ -68,6 +72,11 @@ static void emitdefs(FILE *);
 static void emitfiles(FILE *, int, int);
 
 static void emitobjs(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 *);
@@ -77,6 +86,8 @@ 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)
 {
@@ -86,13 +97,36 @@ mkmakefile(void)
 	char *ifname;
 	char line[BUFSIZ], buf[200];
 
-	/* Try a makefile for the port first.
+	/*
+	 * 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(buf, sizeof(buf), "conf/Makefile.kern.inc");
+	ifname = sourcepath(buf);
+	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(buf, sizeof(buf), "arch/%s/conf/Makefile.%s",
 	    machine, machine);
 	ifname = sourcepath(buf);
 	if ((ifp = fopen(ifname, "r")) == NULL) {
-		/* Try a makefile for the architecture second.
+		/*
+		 * Try a makefile for the architecture second.
 		 */
 		(void)snprintf(buf, sizeof(buf), "arch/%s/conf/Makefile.%s",
 		    machinearch, machinearch);
@@ -120,7 +154,7 @@ mkmakefile(void)
 			continue;
 		}
 		if (strcmp(line, "%OBJS\n") == 0)
-			fn = emitobjs;
+			fn = Mflag ? emitkobjs : emitobjs;
 		else if (strcmp(line, "%CFILES\n") == 0)
 			fn = emitcfiles;
 		else if (strcmp(line, "%SFILES\n") == 0)
@@ -224,11 +258,13 @@ emitsubs(FILE *fp, const char *line, con
 			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. */
+			/*
+			 * Otherwise it's not a selected option and we don't
+			 * output anything.
+			 */
 		}
 
-		line = nextpct+1;
+		line = nextpct + 1;
 	}
 }
 
@@ -261,52 +297,48 @@ srcpath(struct files *fi)
 static const char *
 filetype_prologue(struct filetype *fit)
 {
-	if (fit->fit_flags & FIT_NOPROLOGUE || *fit->fit_path == '/')
-		return ("");
-	else
-		return ("$S/");
+
+	return (*fit->fit_path == '/') ? "" : "$S/";
 }
 
 static const char *
 prefix_prologue(const char *path)
 {
-	if (*path == '/')
-		return ("");
-	else
-		return ("$S/");
+
+	return (*path == '/') ? "" : "$S/";
 }
 
 static void
 emitdefs(FILE *fp)
 {
 	struct nvlist *nv;
-	const char *sp;
 
 	fprintf(fp, "KERNEL_BUILD=%s\n", conffile);
-	fputs("IDENT=", fp);
-	sp = "";
+	fputs("IDENT= \\\n", fp);
 	for (nv = options; nv != NULL; nv = nv->nv_next) {
 
-		/* skip any options output to a header file */
+		/* Skip any options output to a header file */
 		if (DEFINED_OPTION(nv->nv_name))
 			continue;
-		fprintf(fp, "%s-D%s", sp, nv->nv_name);
-		if (nv->nv_str)
-		    fprintf(fp, "=\"%s\"", nv->nv_str);
-		sp = " ";
+		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, "PARAM=-DMAXUSERS=%d\n", maxusers);
 	fprintf(fp, "MACHINE=%s\n", machine);
-	if (*srcdir == '/' || *srcdir == '.') {
-		fprintf(fp, "S=\t%s\n", srcdir);
-	} else {
+
+	const char *subdir = "";
+	if (*srcdir != '/' && *srcdir != '.') {
 		/*
 		 * libkern and libcompat "Makefile.inc"s want relative S
 		 * specification to begin with '.'.
 		 */
-		fprintf(fp, "S=\t./%s\n", srcdir);
+		subdir = "./";
 	}
+	fprintf(fp, "S=\t%s%s\n", subdir, srcdir);
 	for (nv = mkoptions; nv != NULL; nv = nv->nv_next)
 		fprintf(fp, "%s=%s\n", nv->nv_name, nv->nv_str);
 }
@@ -316,62 +348,145 @@ emitobjs(FILE *fp)
 {
 	struct files *fi;
 	struct objects *oi;
-	int lpos, len, sp;
 
-	fputs("OBJS=", fp);
-	sp = '\t';
-	lpos = 7;
+	fputs("OBJS= \\\n", fp);
 	TAILQ_FOREACH(fi, &allfiles, fi_next) {
 		if ((fi->fi_flags & FI_SEL) == 0)
 			continue;
-		len = strlen(fi->fi_base) + 2;
-		if (lpos + len > 72) {
-			fputs(" \\\n", fp);
-			sp = '\t';
-			lpos = 7;
-		}
-		fprintf(fp, "%c%s.o", sp, fi->fi_base);
-		lpos += len + 1;
-		sp = ' ';
+		fprintf(fp, "\t%s.o \\\n", fi->fi_base);
 	}
 	TAILQ_FOREACH(oi, &allobjects, oi_next) {
+		const char *prologue, *prefix, *sep;
+
 		if ((oi->oi_flags & OI_SEL) == 0)
 			continue;
-		len = strlen(oi->oi_path);
-		if (*oi->oi_path != '/')
-		{
-			/* e.g. "$S/" */
- 			if (oi->oi_prefix != NULL)
-				len += strlen(prefix_prologue(oi->oi_path)) +
-				       strlen(oi->oi_prefix) + 1;
-			else
-				len += strlen(filetype_prologue(&oi->oi_fit));
-		}
-		if (lpos + len > 72) {
-			fputs(" \\\n", fp);
-			sp = '\t';
-			lpos = 7;
-		}
-		if (*oi->oi_path == '/') {
-			fprintf(fp, "%c%s", sp, oi->oi_path);
-		} else {
+		prologue = prefix = sep = "";
+		if (*oi->oi_path != '/') {
 			if (oi->oi_prefix != NULL) {
-				fprintf(fp, "%c%s%s/%s", sp,
-					    prefix_prologue(oi->oi_path),
-					    oi->oi_prefix, oi->oi_path);
+				prologue = prefix_prologue(oi->oi_path);
+				prefix = oi->oi_prefix;
+				sep = "/";
 			} else {
-				fprintf(fp, "%c%s%s", sp,
-				            filetype_prologue(&oi->oi_fit),
-				            oi->oi_path);
+				prologue = filetype_prologue(&oi->oi_fit);
 			}
 		}
-		lpos += len + 1;
-		sp = ' ';
+		fprintf(fp, "\t%s%s%s%s \\\n", prologue, prefix, sep,
+		    oi->oi_path);
 	}
 	putc('\n', fp);
 }
 
 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)
 {
 
@@ -389,49 +504,31 @@ static void
 emitfiles(FILE *fp, int suffix, int upper_suffix)
 {
 	struct files *fi;
-	int lpos, len, sp;
 	const char *fpath;
  	struct config *cf;
  	char swapname[100];
 
-	fprintf(fp, "%cFILES=", toupper(suffix));
-	sp = '\t';
-	lpos = 7;
+	fprintf(fp, "%cFILES= \\\n", toupper(suffix));
 	TAILQ_FOREACH(fi, &allfiles, fi_next) {
+		const char *prologue, *prefix, *sep;
+
 		if ((fi->fi_flags & FI_SEL) == 0)
 			continue;
 		fpath = srcpath(fi);
-		len = strlen(fpath);
-		if (fpath[len - 1] != suffix && fpath[len - 1] != upper_suffix)
+		if (fi->fi_suffix != suffix && fi->fi_suffix != upper_suffix)
 			continue;
-		if (*fpath != '/') {
-			/* "$S/" */
- 			if (fi->fi_prefix != NULL)
-				len += strlen(prefix_prologue(fi->fi_prefix)) +
-				       strlen(fi->fi_prefix) + 1;
-			else
-				len += strlen(filetype_prologue(&fi->fi_fit));
-		}
-		if (lpos + len > 72) {
-			fputs(" \\\n", fp);
-			sp = '\t';
-			lpos = 7;
-		}
-		if (*fi->fi_path == '/') {
-			fprintf(fp, "%c%s", sp, fpath);
-		} else {
+		prologue = prefix = sep = "";
+		if (*fi->fi_path != '/') {
 			if (fi->fi_prefix != NULL) {
-				fprintf(fp, "%c%s%s/%s", sp,
-					    prefix_prologue(fi->fi_prefix),
-					    fi->fi_prefix, fpath);
+				prologue = prefix_prologue(fi->fi_prefix);
+				prefix = fi->fi_prefix;
+				sep = "/";
 			} else {
-				fprintf(fp, "%c%s%s", sp,
-				            filetype_prologue(&fi->fi_fit),
-				            fpath);
+				prologue = filetype_prologue(&fi->fi_fit);
 			}
 		}
-		lpos += len + 1;
-		sp = ' ';
+		fprintf(fp, "\t%s%s%s%s \\\n",
+		    prologue, prefix, sep, fpath);
 	}
  	/*
  	 * The allfiles list does not include the configuration-specific
@@ -442,15 +539,7 @@ emitfiles(FILE *fp, int suffix, int uppe
  		TAILQ_FOREACH(cf, &allcf, cf_next) {
  			(void)snprintf(swapname, sizeof(swapname), "swap%s.c",
  			    cf->cf_name);
- 			len = strlen(swapname);
- 			if (lpos + len > 72) {
- 				fputs(" \\\n", fp);
- 				sp = '\t';
- 				lpos = 7;
- 			}
- 			fprintf(fp, "%c%s", sp, swapname);
- 			lpos += len + 1;
- 			sp = ' ';
+ 			fprintf(fp, "\t%s \\\n", swapname);
  		}
  	}
 	putc('\n', fp);
@@ -463,37 +552,30 @@ static void
 emitrules(FILE *fp)
 {
 	struct files *fi;
-	const char *cp, *fpath;
-	int ch;
+	const char *fpath;
 
 	TAILQ_FOREACH(fi, &allfiles, fi_next) {
+		const char *prologue, *prefix, *sep;
+
 		if ((fi->fi_flags & FI_SEL) == 0)
 			continue;
 		fpath = srcpath(fi);
-		if (*fpath == '/') {
-			fprintf(fp, "%s.o: %s\n", fi->fi_base, fpath);
-		} else {
+		prologue = prefix = sep = "";
+		if (*fpath != '/') {
 			if (fi->fi_prefix != NULL) {
-				fprintf(fp, "%s.o: %s%s/%s\n", fi->fi_base,
-					    prefix_prologue(fi->fi_prefix),
-					    fi->fi_prefix, fpath);
+				prologue = prefix_prologue(fi->fi_prefix);
+				prefix = fi->fi_prefix;
+				sep = "/";
 			} else {
-				fprintf(fp, "%s.o: %s%s\n",
-				            fi->fi_base,
-				            filetype_prologue(&fi->fi_fit),
-				            fpath);
+				prologue = filetype_prologue(&fi->fi_fit);
  			}
 		}
+		fprintf(fp, "%s.o: %s%s%s%s\n", fi->fi_base,
+		    prologue, prefix, sep, fpath);
 		if (fi->fi_mkrule != NULL) {
 			fprintf(fp, "\t%s\n\n", fi->fi_mkrule);
 		} else {
-			fputs("\t${NORMAL_", fp);
-			cp = strrchr(fpath, '.');
-			cp = cp == NULL ? fpath : cp + 1;
-			while ((ch = *cp++) != '\0') {
-				fputc(toupper(ch), fp);
-			}
-			fputs("}\n\n", fp);
+			fprintf(fp, "\t${NORMAL_%c}\n\n", toupper(fi->fi_suffix));
 		}
 	}
 }
@@ -507,9 +589,9 @@ static void
 emitload(FILE *fp)
 {
 	struct config *cf;
-	const char *nm, *swname;
 
-	fputs(".MAIN: all\nall:", fp);
+	fputs(".MAIN: all\n", fp);
+	fputs("all:", fp);
 	TAILQ_FOREACH(cf, &allcf, cf_next) {
 		fprintf(fp, " %s", cf->cf_name);
 		/*
@@ -521,20 +603,28 @@ emitload(FILE *fp)
 			fprintf(fp, " .WAIT");
 	}
 	fputs("\n\n", fp);
+	/*
+	 * 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} swap${.TARGET}.o\n"
+		    "\t${SYSTEM_LD_TAIL}\n"
+		    "\n");
+	}
+	/*
+	 * Generate per-kernel rules.
+	 */
 	TAILQ_FOREACH(cf, &allcf, cf_next) {
-		nm = cf->cf_name;
-		swname =
-		    cf->cf_root != NULL ? cf->cf_name : "generic";
-		fprintf(fp, "KERNELS+=%s\n", nm);
-		fprintf(fp, "%s: ${SYSTEM_DEP} swap${.TARGET}.o vers.o", nm);
-		fprintf(fp, "\n"
-			    "\t${SYSTEM_LD_HEAD}\n"
-			    "\t${SYSTEM_LD} swap${.TARGET}.o\n"
-			    "\t${SYSTEM_LD_TAIL}\n"
-			    "\n"
-			    "swap%s.o: swap%s.c\n"
-			    "\t${NORMAL_C}\n\n", swname, swname);
+		fprintf(fp, "KERNELS+=%s\n", cf->cf_name);
+		fprintf(fp, "%s: ${SYSTEM_DEP} swap%s.o vers.o build_kernel\n",
+		    cf->cf_name, cf->cf_name);
+		fprintf(fp, "swap%s.o: swap%s.c\n"
+		    "\t${NORMAL_C}\n\n", cf->cf_name, cf->cf_name);
 	}
+	fputs("\n", fp);
 }
 
 /*

Index: src/usr.bin/config/mkswap.c
diff -u src/usr.bin/config/mkswap.c:1.7 src/usr.bin/config/mkswap.c:1.7.26.1
--- src/usr.bin/config/mkswap.c:1.7	Tue Jan 20 18:20:48 2009
+++ src/usr.bin/config/mkswap.c	Fri Mar  6 21:00:23 2015
@@ -1,4 +1,4 @@
-/*	$NetBSD: mkswap.c,v 1.7 2009/01/20 18:20:48 drochner Exp $	*/
+/*	$NetBSD: mkswap.c,v 1.7.26.1 2015/03/06 21:00:23 snj Exp $	*/
 
 /*
  * Copyright (c) 1992, 1993
@@ -44,6 +44,9 @@
 #include "nbtool_config.h"
 #endif
 
+#include <sys/cdefs.h>
+__RCSID("$NetBSD: mkswap.c,v 1.7.26.1 2015/03/06 21:00:23 snj Exp $");
+
 #include <sys/param.h>
 #include <errno.h>
 #include <stdio.h>
@@ -114,7 +117,7 @@ mkoneswap(struct config *cf)
 		    cf->cf_root->nv_str);
 	fprintf(fp, "const char *rootspec = %s;\n", specinfo);
 	fprintf(fp, "dev_t\trootdev = %s;\t/* %s */\n\n",
-		mkdevstr(nv->nv_num),
+		mkdevstr((dev_t)nv->nv_num),
 		nv->nv_str == s_qmark ? "wildcarded" : nv->nv_str);
 
 	/*
@@ -127,7 +130,7 @@ mkoneswap(struct config *cf)
 		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(nv->nv_num) : "NODEV",
+		nv ? mkdevstr((dev_t)nv->nv_num) : "NODEV",
 		nv ? nv->nv_str : "unspecified");
 
 	/*

Index: src/usr.bin/config/pack.c
diff -u src/usr.bin/config/pack.c:1.8 src/usr.bin/config/pack.c:1.8.24.1
--- src/usr.bin/config/pack.c:1.8	Mon Mar  8 10:19:14 2010
+++ src/usr.bin/config/pack.c	Fri Mar  6 21:00:23 2015
@@ -1,4 +1,4 @@
-/*	$NetBSD: pack.c,v 1.8 2010/03/08 10:19:14 pooka Exp $	*/
+/*	$NetBSD: pack.c,v 1.8.24.1 2015/03/06 21:00:23 snj Exp $	*/
 
 /*
  * Copyright (c) 1992, 1993
@@ -44,6 +44,9 @@
 #include "nbtool_config.h"
 #endif
 
+#include <sys/cdefs.h>
+__RCSID("$NetBSD: pack.c,v 1.8.24.1 2015/03/06 21:00:23 snj Exp $");
+
 #include <sys/param.h>
 #include <stdlib.h>
 #include <string.h>
@@ -137,7 +140,7 @@ packdevi(void)
 {
 	struct devi *firststar, *i, **ip, *l, *p;
 	struct devbase *d;
-	int j, m, n;
+	u_short j, m, n;
 
 	/*
 	 * Sort all the cloning units to after the non-cloning units,

Index: src/usr.bin/config/scan.l
diff -u src/usr.bin/config/scan.l:1.17 src/usr.bin/config/scan.l:1.17.10.1
--- src/usr.bin/config/scan.l:1.17	Tue Mar 20 20:34:57 2012
+++ src/usr.bin/config/scan.l	Fri Mar  6 21:00:23 2015
@@ -1,5 +1,5 @@
 %{
-/*	$NetBSD: scan.l,v 1.17 2012/03/20 20:34:57 matt Exp $	*/
+/*	$NetBSD: scan.l,v 1.17.10.1 2015/03/06 21:00:23 snj Exp $	*/
 
 /*
  * Copyright (c) 1992, 1993
@@ -41,6 +41,9 @@
  *	from: @(#)scan.l	8.1 (Berkeley) 6/6/93
  */
 
+#include <sys/cdefs.h>
+__RCSID("$NetBSD: scan.l,v 1.17.10.1 2015/03/06 21:00:23 snj Exp $");
+
 #include <sys/param.h>
 #include <errno.h>
 #include <libgen.h>
@@ -108,12 +111,12 @@ static int getcurifdef(void);
 
 %}
 
-%option  noyywrap
+%option  noyywrap nounput noinput
 
 PATH	[A-Za-z_0-9]*[./][-A-Za-z_0-9./]*
-QCHARS	([^"\n]|\\\")+
+QCHARS	\"(\\.|[^\\"])*\" 
 WORD	[A-Za-z_][-A-Za-z_0-9]*
-FILENAME	({PATH}|\"{QCHARS}\")
+FILENAME	({PATH}|{QCHARS})
 RESTOFLINE	[ \t]*(#[^\n]*)?\n
 
 %x	IGNORED
@@ -164,6 +167,7 @@ prefix		return PREFIX;
 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;
@@ -319,12 +323,11 @@ package[ \t]+{FILENAME}{RESTOFLINE}	{
 		return EMPTYSTRING;
 	}
 
-\"{QCHARS}	{
-		tok = input();  /* eat closing quote */
-		if (tok != '"') {
-			cfgerror("closing quote missing\n");
-			unput(tok);
-		}
+{QCHARS}	{
+		size_t l = strlen(yytext);
+		if (l > 1 && yytext[l - 1] == '"')
+			yytext[l - 1] = '\0';
+
 		yylval.str = intern(yytext + 1);
 		return QSTRING;
 	}
@@ -335,7 +338,7 @@ package[ \t]+{FILENAME}{RESTOFLINE}	{
 	}
 0[xX][0-9a-fA-F]+ {
 		yylval.num.fmt = 16;
-		yylval.num.val = strtoull(yytext + 2, NULL, 16);
+		yylval.num.val = (long long)strtoull(yytext + 2, NULL, 16);
 		return NUMBER;
 	}
 [1-9][0-9]* {
@@ -397,8 +400,7 @@ curdir_push(const char *fname)
 			free(f);
 			return (-1);
 		}
-		p = emalloc(strlen(cwd) + strlen(d) + 2);
-		sprintf(p, "%s/%s", cwd, d);
+		easprintf(&p, "%s/%s", cwd, d);
 	}
 	free(f);
 	pf = ecalloc(1, sizeof(*pf));
@@ -498,8 +500,7 @@ include(const char *fname, int ateof, in
 		s = estrdup(fname);
 	else if (fname[0] == '.' && fname[1] == '/') {
 		struct prefix *pf = SLIST_FIRST(&curdirs);
-		s = emalloc(strlen(pf->pf_prefix) + strlen(fname));
-		sprintf(s, "%s/%s", pf->pf_prefix, fname + 2);
+		easprintf(&s, "%s/%s", pf->pf_prefix, fname + 2);
 	} else
 		s = sourcepath(fname);
 	if ((fp = fopen(s, "r")) == NULL) {
@@ -530,6 +531,7 @@ include(const char *fname, int ateof, in
 	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;
@@ -604,12 +606,12 @@ endinclude(void)
  * us to consume a newline, we have to subtract one.  yychar is yacc's
  * token lookahead, so we can tell.
  */
-int
+u_short
 currentline(void)
 {
 	extern int yychar;
 
-	return (yyline - (yychar == '\n'));
+	return (u_short)(yyline - (yychar == '\n'));
 }
 
 static int

Index: src/usr.bin/config/sem.c
diff -u src/usr.bin/config/sem.c:1.43 src/usr.bin/config/sem.c:1.43.2.1
--- src/usr.bin/config/sem.c:1.43	Thu May 29 07:47:45 2014
+++ src/usr.bin/config/sem.c	Fri Mar  6 21:00:23 2015
@@ -1,4 +1,4 @@
-/*	$NetBSD: sem.c,v 1.43 2014/05/29 07:47:45 mrg Exp $	*/
+/*	$NetBSD: sem.c,v 1.43.2.1 2015/03/06 21:00:23 snj Exp $	*/
 
 /*
  * Copyright (c) 1992, 1993
@@ -44,6 +44,9 @@
 #include "nbtool_config.h"
 #endif
 
+#include <sys/cdefs.h>
+__RCSID("$NetBSD: sem.c,v 1.43.2.1 2015/03/06 21:00:23 snj Exp $");
+
 #include <sys/param.h>
 #include <ctype.h>
 #include <stdio.h>
@@ -65,6 +68,8 @@ const char *s_none;
 
 static struct hashtab *cfhashtab;	/* for config lookup */
 struct hashtab *devitab;		/* etc */
+struct attr allattr;
+size_t nattrs;
 
 static struct attr errattr;
 static struct devbase errdev;
@@ -95,6 +100,13 @@ initsem(void)
 {
 
 	attrtab = ht_new();
+	attrdeptab = ht_new();
+
+	allattr.a_name = "netbsd";
+	TAILQ_INIT(&allattr.a_files);
+	(void)ht_insert(attrtab, allattr.a_name, &allattr);
+	selectattr(&allattr);
+
 	errattr.a_name = "<internal>";
 
 	TAILQ_INIT(&allbases);
@@ -121,11 +133,79 @@ initsem(void)
 /* Name of include file just ended (set in scan.l) */
 extern const char *lastfile;
 
+static struct attr *
+finddep(struct attr *a, const char *name)
+{
+	struct attrlist *al;
+
+	for (al = a->a_deps; al != NULL; al = al->al_next) {
+		struct attr *this = al->al_this;
+		if (strcmp(this->a_name, name) == 0)
+			return this;
+	}
+	return NULL;
+}
+
+static void
+mergedeps(const char *dname, const char *name)
+{
+	struct attr *a, *newa;
+
+	CFGDBG(4, "merging attr `%s' to devbase `%s'", name, dname);
+	a = refattr(dname);
+	if (finddep(a, name) == NULL) {
+		newa = refattr(name);
+		a->a_deps = attrlist_cons(a->a_deps, newa);
+		CFGDBG(3, "attr `%s' merged to attr `%s'", newa->a_name,
+		    a->a_name);
+	}
+}
+
+static void
+fixdev(struct devbase *dev)
+{
+	struct attrlist *al;
+	struct attr *devattr, *a;
+
+	devattr = refattr(dev->d_name);
+	if (devattr->a_devclass)
+		panic("%s: dev %s is devclass!", __func__, devattr->a_name);
+
+	CFGDBG(4, "fixing devbase `%s'", dev->d_name);
+	for (al = dev->d_attrs; al != NULL; al = al->al_next) {
+		a = al->al_this;
+		CFGDBG(4, "fixing devbase `%s' attr `%s'", dev->d_name, a->a_name);
+		if (a->a_iattr) {
+			a->a_refs = addtoattr(a->a_refs, dev);
+			CFGDBG(3, "device `%s' has iattr `%s'", dev->d_name,
+			    a->a_name);
+		} else if (a->a_devclass != NULL) {
+			if (dev->d_classattr != NULL && dev->d_classattr != a) {
+				cfgwarn("device `%s' has multiple classes "
+				    "(`%s' and `%s')",
+				    dev->d_name, dev->d_classattr->a_name,
+				    a->a_name);
+			}
+			if (dev->d_classattr == NULL) {
+				dev->d_classattr = a;
+				CFGDBG(3, "device `%s' is devclass `%s'", dev->d_name,
+				    a->a_name);
+			}
+		} else {
+			if (strcmp(dev->d_name, a->a_name) != 0) {
+				mergedeps(dev->d_name, a->a_name);
+			}
+		}
+	}
+}
+
 void
 enddefs(void)
 {
 	struct devbase *dev;
 
+	yyfile = "enddefs";
+
 	TAILQ_FOREACH(dev, &allbases, d_next) {
 		if (!dev->d_isdef) {
 			(void)fprintf(stderr,
@@ -134,6 +214,7 @@ enddefs(void)
 			errors++;
 			continue;
 		}
+		fixdev(dev);
 	}
 	if (errors) {
 		(void)fprintf(stderr, "*** Stop.\n");
@@ -197,19 +278,24 @@ setident(const char *i)
  * all locator lists include a dummy head node, which we discard here.
  */
 int
+defattr0(const char *name, struct loclist *locs, struct attrlist *deps,
+    int devclass)
+{
+
+	if (locs != NULL)
+		return defiattr(name, locs, deps, devclass);
+	else if (devclass)
+		return defdevclass(name, locs, deps, devclass);
+	else
+		return defattr(name, locs, deps, devclass);
+}
+
+int
 defattr(const char *name, struct loclist *locs, struct attrlist *deps,
     int devclass)
 {
 	struct attr *a, *dep;
 	struct attrlist *al;
-	struct loclist *ll;
-	int len;
-
-	if (locs != NULL && devclass)
-		panic("defattr(%s): locators and devclass", name);
-
-	if (deps != NULL && devclass)
-		panic("defattr(%s): dependencies and devclass", name);
 
 	/*
 	 * If this attribute depends on any others, make sure none of
@@ -222,56 +308,100 @@ defattr(const char *name, struct loclist
 			    "attribute", name, dep->a_name);
 			return (1);
 		}
+		(void)ht_insert2(attrdeptab, name, dep->a_name, NULL);
+		CFGDBG(2, "attr `%s' depends on attr `%s'", name, dep->a_name);
 	}
 
-	a = ecalloc(1, sizeof *a);
-	if (ht_insert(attrtab, name, a)) {
-		free(a);
+	if (getrefattr(name, &a)) {
 		cfgerror("attribute `%s' already defined", name);
 		loclist_destroy(locs);
 		return (1);
 	}
+	if (a == NULL)
+		a = mkattr(name);
 
-	a->a_name = name;
-	if (locs != NULL) {
-		a->a_iattr = 1;
-		/* unwrap */
-		a->a_locs = locs->ll_next;
-		locs->ll_next = NULL;
-		loclist_destroy(locs);
-	} else {
-		a->a_iattr = 0;
-		a->a_locs = NULL;
+	a->a_deps = deps;
+	expandattr(a, NULL);
+	CFGDBG(3, "attr `%s' defined", a->a_name);
+
+	return (0);
+}
+
+struct attr *
+mkattr(const char *name)
+{
+	struct attr *a;
+
+	a = ecalloc(1, sizeof *a);
+	if (ht_insert(attrtab, name, a)) {
+		free(a);
+		return NULL;
 	}
-	if (devclass) {
-		char classenum[256], *cp;
-		int errored = 0;
-
-		(void)snprintf(classenum, sizeof(classenum), "DV_%s", name);
-		for (cp = classenum + 3; *cp; cp++) {
-			if (!errored &&
-			    (!isalnum((unsigned char)*cp) ||
-			      (isalpha((unsigned char)*cp) && !islower((unsigned char)*cp)))) {
-				cfgerror("device class names must be "
-				    "lower-case alphanumeric characters");
-				errored = 1;
-			}
-			*cp = toupper((unsigned char)*cp);
-		}
-		a->a_devclass = intern(classenum);
-	} else
-		a->a_devclass = NULL;
+	a->a_name = name;
+	TAILQ_INIT(&a->a_files);
+	CFGDBG(3, "attr `%s' allocated", name);
+
+	return a;
+}
+
+/* "interface attribute" initialization */
+int
+defiattr(const char *name, struct loclist *locs, struct attrlist *deps,
+    int devclass)
+{
+	struct attr *a;
+	int len;
+	struct loclist *ll;
+
+	if (devclass)
+		panic("defattr(%s): locators and devclass", name);
+
+	if (defattr(name, locs, deps, devclass) != 0)
+		return (1);
+
+	a = getattr(name);
+	a->a_iattr = 1;
+	/* unwrap */
+	a->a_locs = locs->ll_next;
+	locs->ll_next = NULL;
+	loclist_destroy(locs);
 	len = 0;
 	for (ll = a->a_locs; ll != NULL; ll = ll->ll_next)
 		len++;
 	a->a_loclen = len;
-	a->a_devs = NULL;
-	a->a_refs = NULL;
-	a->a_deps = deps;
-	a->a_expanding = 0;
+	if (deps)
+		CFGDBG(2, "attr `%s' iface with deps", a->a_name);
+	return (0);
+}
 
-	/* Expand the attribute to check for cycles in the graph. */
-	expandattr(a, NULL);
+/* "device class" initialization */
+int
+defdevclass(const char *name, struct loclist *locs, struct attrlist *deps,
+    int devclass)
+{
+	struct attr *a;
+	char classenum[256], *cp;
+	int errored = 0;
+
+	if (deps)
+		panic("defattr(%s): dependencies and devclass", name);
+
+	if (defattr(name, locs, deps, devclass) != 0)
+		return (1);
+
+	a = getattr(name);
+	(void)snprintf(classenum, sizeof(classenum), "DV_%s", name);
+	for (cp = classenum + 3; *cp; cp++) {
+		if (!errored &&
+		    (!isalnum((unsigned char)*cp) ||
+		      (isalpha((unsigned char)*cp) && !islower((unsigned char)*cp)))) {
+			cfgerror("device class names must be "
+			    "lower-case alphanumeric characters");
+			errored = 1;
+		}
+		*cp = (char)toupper((unsigned char)*cp);
+	}
+	a->a_devclass = intern(classenum);
 
 	return (0);
 }
@@ -332,7 +462,6 @@ defdev(struct devbase *dev, struct locli
 {
 	struct loclist *ll;
 	struct attrlist *al;
-	struct attr *a;
 
 	if (dev == &errdev)
 		goto bad;
@@ -354,7 +483,7 @@ defdev(struct devbase *dev, struct locli
 	if (loclist != NULL) {
 		ll = loclist;
 		loclist = NULL;	/* defattr disposes of them for us */
-		if (defattr(dev->d_name, ll, NULL, 0))
+		if (defiattr(dev->d_name, ll, NULL, 0))
 			goto bad;
 		attrs = attrlist_cons(attrs, getattr(dev->d_name));
 		/* This used to be stored but was never used */
@@ -386,6 +515,12 @@ defdev(struct devbase *dev, struct locli
 	dev->d_ispseudo = ispseudo;
 	dev->d_attrs = attrs;
 	dev->d_classattr = NULL;		/* for now */
+	CFGDBG(3, "dev `%s' defined", dev->d_name);
+
+	/*
+	 * Implicit attribute definition for device.
+	 */
+	refattr(dev->d_name);
 
 	/*
 	 * For each interface attribute this device refers to, add this
@@ -397,18 +532,13 @@ defdev(struct devbase *dev, struct locli
 	 * device has two classes).
 	 */
 	for (al = attrs; al != NULL; al = al->al_next) {
-		a = al->al_this;
-		if (a->a_iattr)
-			a->a_refs = addtoattr(a->a_refs, dev);
-		if (a->a_devclass != NULL) {
-			if (dev->d_classattr != NULL) {
-				cfgerror("device `%s' has multiple classes "
-				    "(`%s' and `%s')",
-				    dev->d_name, dev->d_classattr->a_name,
-				    a->a_name);
-			}
-			dev->d_classattr = a;
-		}
+		/*
+		 * Implicit attribute definition for device dependencies.
+		 */
+		refattr(al->al_this->a_name);
+		(void)ht_insert2(attrdeptab, dev->d_name, al->al_this->a_name, NULL);
+		CFGDBG(2, "device `%s' depends on attr `%s'", dev->d_name,
+		    al->al_this->a_name);
 	}
 	return;
  bad:
@@ -453,6 +583,7 @@ getdevbase(const char *name)
 		TAILQ_INSERT_TAIL(&allbases, dev, d_next);
 		if (ht_insert(devbasetab, name, dev))
 			panic("getdevbase(%s)", name);
+		CFGDBG(3, "devbase defined `%s'", dev->d_name);
 	}
 	return (dev);
 }
@@ -504,6 +635,12 @@ defdevattach(struct deva *deva, struct d
 	deva->d_attrs = attrs;
 	deva->d_atlist = atlist;
 	deva->d_devbase = dev;
+	CFGDBG(3, "deva `%s' defined", deva->d_name);
+
+	/*
+	 * Implicit attribute definition for device attachment.
+	 */
+	refattr(deva->d_name);
 
 	/*
 	 * Turn the `at' list into interface attributes (map each
@@ -605,6 +742,41 @@ getattr(const char *name)
 }
 
 /*
+ * Implicit attribute definition.
+ */
+struct attr *
+refattr(const char *name)
+{
+	struct attr *a;
+
+	if ((a = ht_lookup(attrtab, name)) == NULL)
+		a = mkattr(name);
+	return a;
+}
+
+int
+getrefattr(const char *name, struct attr **ra)
+{
+	struct attr *a;
+
+	a = ht_lookup(attrtab, name);
+	if (a == NULL) {
+		*ra = NULL;
+		return (0);
+	}
+	/*
+	 * Check if the existing attr is only referenced, not really defined.
+	 */
+	if (a->a_deps == NULL &&
+	    a->a_iattr == 0 &&
+	    a->a_devclass == 0) {
+		*ra = a;
+		return (0);
+	}
+	return (1);
+}
+
+/*
  * Recursively expand an attribute and its dependencies, checking for
  * cycles, and invoking a callback for each attribute found.
  */
@@ -717,7 +889,7 @@ resolve(struct nvlist **nvp, const char 
 	const char *cp;
 	devmajor_t maj;
 	devminor_t min;
-	int i, l;
+	size_t i, l;
 	int unit;
 	char buf[NAMESIZE];
 
@@ -737,7 +909,7 @@ resolve(struct nvlist **nvp, const char 
 			cp = makedevstr(maj, min);
 		} else
 			cp = NULL;
-		*nvp = nv = newnv(NULL, cp, NULL, d, NULL);
+		*nvp = nv = newnv(NULL, cp, NULL, (long long)d, NULL);
 	}
 	if ((dev_t)nv->nv_num != NODEV) {
 		/*
@@ -784,7 +956,7 @@ resolve(struct nvlist **nvp, const char 
 	 * don't bother making a device number.
 	 */
 	if (has_attr(dev->d_attrs, s_ifnet)) {
-		nv->nv_num = NODEV;
+		nv->nv_num = (long long)NODEV;
 		nv->nv_ifunit = unit;	/* XXX XXX XXX */
 	} else {
 		maj = dev2major(dev);
@@ -793,7 +965,7 @@ resolve(struct nvlist **nvp, const char 
 			    name, what, nv->nv_str);
 			return (1);
 		}
-		nv->nv_num = makedev(maj, unit * maxpartitions + part);
+		nv->nv_num = (long long)makedev(maj, unit * maxpartitions + part);
 	}
 
 	nv->nv_name = dev->d_name;
@@ -877,6 +1049,7 @@ delconf(const char *name)
 {
 	struct config *cf;
 
+	CFGDBG(5, "deselecting config `%s'", name);
 	if (ht_lookup(cfhashtab, name) == NULL) {
 		cfgerror("configuration `%s' undefined", name);
 		return;
@@ -1075,6 +1248,7 @@ adddev(const char *name, const char *at,
 	i->i_pspec = p;
 	i->i_atdeva = iba;
 	i->i_cfflags = flags;
+	CFGDBG(3, "devi `%s' added", i->i_name);
 
 	*iba->d_ipp = i;
 	iba->d_ipp = &i->i_asame;
@@ -1093,6 +1267,7 @@ deldevi(const char *name, const char *at
 	int unit;
 	char base[NAMESIZE];
 
+	CFGDBG(5, "deselecting devi `%s'", name);
 	if (split(name, strlen(name), base, sizeof base, &unit)) {
 		cfgerror("invalid device name `%s'", name);
 		return;
@@ -1131,6 +1306,7 @@ remove_devi(struct devi *i)
 	struct devi *f, *j, **ppi;
 	struct deva *iba;
 
+	CFGDBG(5, "removing devi `%s'", i->i_name);
 	f = ht_lookup(devitab, i->i_name);
 	if (f == NULL)
 		panic("remove_devi(): instance %s disappeared from devitab",
@@ -1154,7 +1330,8 @@ remove_devi(struct devi *i)
 	 *      list.
 	 */
 	if (i != f) {
-		for (j = f; j->i_alias != i; j = j->i_alias);
+		for (j = f; j->i_alias != i; j = j->i_alias)
+			continue;
 		j->i_alias = i->i_alias;
 	} else {
 		if (i->i_alias == NULL) {
@@ -1177,7 +1354,8 @@ remove_devi(struct devi *i)
 		 */
 		for (ppi = &d->d_ihead;
 		    *ppi != NULL && *ppi != i && (*ppi)->i_bsame != i;
-		    ppi = &(*ppi)->i_bsame);
+		    ppi = &(*ppi)->i_bsame)
+			continue;
 		if (*ppi == NULL)
 			panic("deldev: dev (%s) doesn't list the devi"
 			    " (%s at %s)", d->d_name, i->i_name, i->i_at);
@@ -1203,7 +1381,8 @@ remove_devi(struct devi *i)
 	iba = i->i_atdeva;
 	for (ppi = &iba->d_ihead;
 	    *ppi != NULL && *ppi != i && (*ppi)->i_asame != i;
-	    ppi = &(*ppi)->i_asame);
+	    ppi = &(*ppi)->i_asame)
+		continue;
 	if (*ppi == NULL)
 		panic("deldev: deva (%s) doesn't list the devi (%s)",
 		    iba->d_name, i->i_name);
@@ -1267,7 +1446,8 @@ remove_devi(struct devi *i)
 			panic("remove_devi(%s) - can't add to deaddevitab",
 			    i->i_name);
 	} else {
-		for (j = f; j->i_alias != NULL; j = j->i_alias);
+		for (j = f; j->i_alias != NULL; j = j->i_alias)
+			continue;
 		j->i_alias = i;
 	}
 	/*
@@ -1295,13 +1475,18 @@ deldeva(const char *at)
 			if (i->i_at == NULL)
 				stack = newnv(NULL, NULL, i, 0, stack);
 	} else {
-		int l;
+		size_t l;
 
+		CFGDBG(5, "deselecting deva `%s'", at);
+		if (at[0] == '\0')
+			goto out;
+			
 		l = strlen(at) - 1;
 		if (at[l] == '?' || isdigit((unsigned char)at[l])) {
 			char base[NAMESIZE];
 
 			if (split(at, l+1, base, sizeof base, &unit)) {
+out:
 				cfgerror("invalid attachment name `%s'", at);
 				return;
 			}
@@ -1376,15 +1561,20 @@ deldeva(const char *at)
 void
 deldev(const char *name)
 {
-	int l;
+	size_t l;
 	struct devi *firsti, *i;
 	struct nvlist *nv, *stack = NULL;
 
+	CFGDBG(5, "deselecting dev `%s'", name);
+	if (name[0] == '\0')
+		goto out;
+
 	l = strlen(name) - 1;
 	if (name[l] == '*' || isdigit((unsigned char)name[l])) {
 		/* `no mydev0' or `no mydev*' */
 		firsti = ht_lookup(devitab, name);
 		if (firsti == NULL) {
+out:
 			cfgerror("unknown instance %s", name);
 			return;
 		}
@@ -1530,6 +1720,7 @@ delpseudo(const char *name)
 	struct devbase *d;
 	struct devi *i;
 
+	CFGDBG(5, "deselecting pseudo `%s'", name);
 	d = ht_lookup(devbasetab, name);
 	if (d == NULL) {
 		cfgerror("undefined pseudo-device %s", name);
@@ -1599,7 +1790,8 @@ fixdevis(void)
 	struct devi *i;
 	int error = 0;
 
-	TAILQ_FOREACH(i, &alldevi, i_next)
+	TAILQ_FOREACH(i, &alldevi, i_next) {
+		CFGDBG(3, "fixing devis `%s'", i->i_name);
 		if (i->i_active == DEVI_ACTIVE)
 			selectbase(i->i_base, i->i_atdeva);
 		else if (i->i_active == DEVI_ORPHAN) {
@@ -1616,6 +1808,7 @@ fixdevis(void)
 			cfgxwarn(i->i_srcfile, i->i_lineno, "ignoring "
 			    "explicitly orphaned instance `%s at %s'",
 			    i->i_name, i->i_at);
+	}
 
 	if (error)
 		return error;
@@ -1707,8 +1900,8 @@ concat(const char *name, int c)
 		len = sizeof(buf) - 2;
 	}
 	memmove(buf, name, len);
-	buf[len] = c;
-	buf[len + 1] = 0;
+	buf[len] = (char)c;
+	buf[len + 1] = '\0';
 	return (intern(buf));
 }
 
@@ -1761,10 +1954,73 @@ split(const char *name, size_t nlen, cha
 }
 
 void
+addattr(const char *name)
+{
+	struct attr *a;
+
+	a = refattr(name);
+	selectattr(a);
+}
+
+void
+delattr(const char *name)
+{
+	struct attr *a;
+
+	a = refattr(name);
+	deselectattr(a);
+}
+
+void
 selectattr(struct attr *a)
 {
+	struct attrlist *al;
+	struct attr *dep;
+
+	CFGDBG(5, "selecting attr `%s'", a->a_name);
+	for (al = a->a_deps; al != NULL; al = al->al_next) {
+		dep = al->al_this;
+		selectattr(dep);
+	}
+	if (ht_insert(selecttab, a->a_name, __UNCONST(a->a_name)) == 0)
+		nattrs++;
+	CFGDBG(3, "attr selected `%s'", a->a_name);
+}
+
+static int
+deselectattrcb2(const char *name1, const char *name2, void *v, void *arg)
+{
+	const char *name = arg;
+
+	if (strcmp(name, name2) == 0)
+		delattr(name1);
+	return 0;
+}
+
+void
+deselectattr(struct attr *a)
+{
 
-	(void)ht_insert(selecttab, a->a_name, __UNCONST(a->a_name));
+	CFGDBG(5, "deselecting attr `%s'", a->a_name);
+	ht_enumerate2(attrdeptab, deselectattrcb2, __UNCONST(a->a_name));
+	if (ht_remove(selecttab, a->a_name) == 0)
+		nattrs--;
+	CFGDBG(3, "attr deselected `%s'", a->a_name);
+}
+
+static int
+dumpattrdepcb2(const char *name1, const char *name2, void *v, void *arg)
+{
+
+	CFGDBG(3, "attr `%s' depends on attr `%s'", name1, name2);
+	return 0;
+}
+
+void
+dependattrs(void)
+{
+
+	ht_enumerate2(attrdeptab, dumpattrdepcb2, NULL);
 }
 
 /*
@@ -1778,17 +2034,27 @@ selectbase(struct devbase *d, struct dev
 	struct attrlist *al;
 
 	(void)ht_insert(selecttab, d->d_name, __UNCONST(d->d_name));
+	CFGDBG(3, "devbase selected `%s'", d->d_name);
+	CFGDBG(5, "selecting dependencies of devbase `%s'", d->d_name);
 	for (al = d->d_attrs; al != NULL; al = al->al_next) {
 		a = al->al_this;
 		expandattr(a, selectattr);
 	}
+
+	struct attr *devattr;
+	devattr = refattr(d->d_name);
+	expandattr(devattr, selectattr);
+	
 	if (da != NULL) {
 		(void)ht_insert(selecttab, da->d_name, __UNCONST(da->d_name));
+		CFGDBG(3, "devattr selected `%s'", da->d_name);
 		for (al = da->d_attrs; al != NULL; al = al->al_next) {
 			a = al->al_this;
 			expandattr(a, selectattr);
 		}
 	}
+
+	fixdev(d);
 }
 
 /*
@@ -1839,7 +2105,7 @@ fixloc(const char *name, struct attr *at
 	if (attr->a_loclen == 0)	/* e.g., "at root" */
 		lp = nullvec;
 	else
-		lp = emalloc((attr->a_loclen + 1) * sizeof(const char *));
+		lp = emalloc((size_t)(attr->a_loclen + 1) * sizeof(const char *));
 	for (n = got; n != NULL; n = n->ll_next)
 		n->ll_num = -1;
 	nmissing = 0;

Index: src/usr.bin/config/sem.h
diff -u src/usr.bin/config/sem.h:1.10 src/usr.bin/config/sem.h:1.10.10.1
--- src/usr.bin/config/sem.h:1.10	Sun Mar 11 21:16:08 2012
+++ src/usr.bin/config/sem.h	Fri Mar  6 21:00:23 2015
@@ -1,4 +1,4 @@
-/*	$NetBSD: sem.h,v 1.10 2012/03/11 21:16:08 dholland Exp $	*/
+/*	$NetBSD: sem.h,v 1.10.10.1 2015/03/06 21:00:23 snj Exp $	*/
 
 /*
  * Copyright (c) 1992, 1993
@@ -46,15 +46,25 @@ 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 *);
@@ -67,7 +77,7 @@ void		deldev(const char *);
 void		addpseudo(const char *, int);
 void		delpseudo(const char *);
 void		addpseudoroot(const char *);
-void		adddevm(const char *, int, int,
+void		adddevm(const char *, devmajor_t, devmajor_t,
 			struct condexpr *, struct nvlist *);
 int		fixdevis(void);
 const char     *ref(const char *);
@@ -78,3 +88,4 @@ int		has_attr(struct attrlist *, const c
 extern const char *s_qmark;
 extern const char *s_none;
 extern const char *s_ifnet;
+extern size_t nattrs;

Index: src/usr.bin/config/util.c
diff -u src/usr.bin/config/util.c:1.16 src/usr.bin/config/util.c:1.16.4.1
--- src/usr.bin/config/util.c:1.16	Fri Nov  1 21:39:13 2013
+++ src/usr.bin/config/util.c	Fri Mar  6 21:00:23 2015
@@ -1,4 +1,4 @@
-/*	$NetBSD: util.c,v 1.16 2013/11/01 21:39:13 christos Exp $	*/
+/*	$NetBSD: util.c,v 1.16.4.1 2015/03/06 21:00:23 snj Exp $	*/
 
 /*
  * Copyright (c) 1992, 1993
@@ -44,6 +44,9 @@
 #include "nbtool_config.h"
 #endif
 
+#include <sys/cdefs.h>
+__RCSID("$NetBSD: util.c,v 1.16.4.1 2015/03/06 21:00:23 snj Exp $");
+
 #include <sys/types.h>
 #include <assert.h>
 #include <ctype.h>
@@ -57,6 +60,8 @@
 
 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)
@@ -414,6 +419,17 @@ condexpr_destroy(struct condexpr *expr)
  */
 
 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;
@@ -435,6 +451,12 @@ cfgxwarn(const char *file, int line, con
 }
 
 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);

Added files:

Index: src/usr.bin/config/TODO
diff -u /dev/null src/usr.bin/config/TODO:1.14.2.2
--- /dev/null	Fri Mar  6 21:00:23 2015
+++ src/usr.bin/config/TODO	Fri Mar  6 21:00:23 2015
@@ -0,0 +1,264 @@
+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
+
+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 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 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.)

Reply via email to