This is the mail archive of the glibc-cvs@sourceware.org mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

GNU C Library master sources branch, master, updated. glibc-2.14-27-g77fb911


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "GNU C Library master sources".

The branch, master has been updated
       via  77fb9117432a754388c52f6eb06c60a828975350 (commit)
       via  40c1b22cd76995f0b614745c3954755e462b7f56 (commit)
       via  9f2da732e7b03825027462dd1c46f8b4d18fc1f5 (commit)
       via  82e9a1f7df488c62a214ee63847b2c884dcba565 (commit)
       via  c41af17eed77f07983dab6f702a6347fcad9a619 (commit)
       via  a9e836b0406c259979fbb31eb6650d33c2bbefbc (commit)
       via  2666d441c2d8107b1987b869714189af64b954c6 (commit)
       via  9ee76b5ae861ff9891e5586fc6906c94c447a9e0 (commit)
      from  c71ca1f89c6e89d8c4145e4c2fdcce2fc78812bd (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
http://sources.redhat.com/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=77fb9117432a754388c52f6eb06c60a828975350

commit 77fb9117432a754388c52f6eb06c60a828975350
Author: Ulrich Drepper <drepper@gmail.com>
Date:   Wed Jun 15 21:26:56 2011 -0400

    Install db-Makefile

diff --git a/ChangeLog b/ChangeLog
index 33d9706..e7bfbb8 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,8 @@
 2011-06-15  Ulrich Drepper  <drepper@gmail.com>
 
+	* Makeconfig: Define vardbdir and inst_vardbdir.
+	* nss/Makefile: Add rules to install db-Makefile.
+
 	* nss/nss_db/db-XXX.c: Cleanup.
 
 	* nss/Makefile (libnss_db-dbs): Add db-initgroups.
diff --git a/Makeconfig b/Makeconfig
index b34cacf..cc5c3a9 100644
--- a/Makeconfig
+++ b/Makeconfig
@@ -291,6 +291,12 @@ sysconfdir = $(prefix)/etc
 endif
 inst_sysconfdir = $(install_root)$(sysconfdir)
 
+# Directory for the database files and Makefile for nss_db.
+ifndef vardbdir
+vardbdir = /var/db
+endif
+inst_vardbdir = $(install_root)$(vardbdir)
+
 # What timezone should be the installed default (e.g., US/Eastern).
 # Run `make -C time echo-zonenames' to see a list of available zone names.
 # The local timezone can be changed with `zic -l TIMEZONE' at any time.
diff --git a/nss/Makefile b/nss/Makefile
index f6065cc..60c6549 100644
--- a/nss/Makefile
+++ b/nss/Makefile
@@ -78,6 +78,8 @@ generated		+= $(filter-out db-alias.c db-netgrp.c, \
 					$(addsuffix .c,$(libnss_db-dbs)))
 distribute		+= $(addprefix nss_db/, db-XXX.c nss_db.h)
 
+install-others		+= $(inst_vardbdir)/Makefile
+
 # Build static module if requested
 ifneq ($(build-static-nss),yes)
 libnss_files-inhibit-o	= $(filter-out .os,$(object-suffixes))
@@ -114,6 +116,9 @@ $(libnss_db-dbs:%=$(objpfx)%.c): $(objpfx)db-%.c: nss_files/files-%.c
 
 $(objpfx)makedb: $(makedb-modules:%=$(objpfx)%.o)
 
+$(inst_vardbdir)/Makefile: db-Makefile $(+force)
+	$(do-install)
+
 distribute		+= nss_test1.c
 
 CFLAGS-nss_test1.c = -DNOT_IN_libc=1

http://sources.redhat.com/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=40c1b22cd76995f0b614745c3954755e462b7f56

commit 40c1b22cd76995f0b614745c3954755e462b7f56
Author: Ulrich Drepper <drepper@gmail.com>
Date:   Wed Jun 15 21:00:59 2011 -0400

    Cleanup of db-XXX.c

diff --git a/ChangeLog b/ChangeLog
index b580e29..33d9706 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,7 @@
 2011-06-15  Ulrich Drepper  <drepper@gmail.com>
 
+	* nss/nss_db/db-XXX.c: Cleanup.
+
 	* nss/Makefile (libnss_db-dbs): Add db-initgroups.
 	* nss/Versions [libnss_db]: Add _nss_db_initgroups_dyn for
 	GLIBC_PRIVATE.
diff --git a/nss/nss_db/db-XXX.c b/nss/nss_db/db-XXX.c
index 30026b1..3947893 100644
--- a/nss/nss_db/db-XXX.c
+++ b/nss/nss_db/db-XXX.c
@@ -122,8 +122,6 @@ enum nss_status								      \
  _nss_db_get##name##_r (proto, struct STRUCTURE *result,		      \
 			char *buffer, size_t buflen, int *errnop H_ERRNO_PROTO)\
 {									      \
-  enum nss_status status = NSS_STATUS_SUCCESS;				      \
-  struct nss_db_map state = { NULL, 0 };				      \
   struct parser_data *data = (void *) buffer;				      \
 									      \
   if (buflen < sizeof *data)						      \
@@ -133,7 +131,8 @@ enum nss_status								      \
       return NSS_STATUS_TRYAGAIN;					      \
     }									      \
 									      \
-  status = internal_setent (DBFILE, &state);				      \
+  struct nss_db_map state = { NULL, 0 };				      \
+  enum nss_status status = internal_setent (DBFILE, &state);		      \
   if (status != NSS_STATUS_SUCCESS)					      \
     {									      \
       *errnop = errno;							      \
@@ -141,77 +140,74 @@ enum nss_status								      \
       return status;							      \
     }									      \
 									      \
-  if (status == NSS_STATUS_SUCCESS)					      \
+  const struct nss_db_header *header = state.header;			      \
+  int i;								      \
+  for (i = 0; i < header->ndbs; ++i)					      \
+    if (header->dbs[i].id == db_char)					      \
+      break;								      \
+  if (i == header->ndbs)						      \
     {									      \
-      const struct nss_db_header *header = state.header;		      \
-      int i;								      \
-      for (i = 0; i < header->ndbs; ++i)				      \
-	if (header->dbs[i].id == db_char)				      \
-	  break;							      \
-      if (i == header->ndbs)						      \
-	{								      \
-	  status = NSS_STATUS_UNAVAIL;					      \
-	  goto out;							      \
-	}								      \
+      status = NSS_STATUS_UNAVAIL;					      \
+      goto out;								      \
+    }									      \
 									      \
-      char *key;							      \
-      if (db_char == '.')						      \
-	key = (char *) IGNOREPATTERN keypattern;			      \
-      else								      \
-	{								      \
-	  const size_t size = (keysize) + 1;				      \
-	  key = alloca (size);						      \
+  char *key;								      \
+  if (db_char == '.')							      \
+    key = (char *) IGNOREPATTERN keypattern;				      \
+  else									      \
+    {									      \
+      const size_t size = (keysize) + 1;				      \
+      key = alloca (size);						      \
 									      \
-	  KEYPRINTF keypattern;						      \
-	}								      \
+      KEYPRINTF keypattern;						      \
+    }									      \
 									      \
-      const stridx_t *hashtable						      \
-	= (const stridx_t *) ((const char *) header			      \
-			      + header->dbs[i].hashoffset);		      \
-      const char *valstrtab = (const char *) header + header->valstroffset;   \
-      uint32_t hashval = __hash_string (key);				      \
-      size_t hidx = hashval % header->dbs[i].hashsize;			      \
-      size_t hval2 = 1 + hashval % (header->dbs[i].hashsize - 2);	      \
+  const stridx_t *hashtable						      \
+    = (const stridx_t *) ((const char *) header				      \
+			  + header->dbs[i].hashoffset);			      \
+  const char *valstrtab = (const char *) header + header->valstroffset;	      \
+  uint32_t hashval = __hash_string (key);				      \
+  size_t hidx = hashval % header->dbs[i].hashsize;			      \
+  size_t hval2 = 1 + hashval % (header->dbs[i].hashsize - 2);		      \
 									      \
-      status = NSS_STATUS_NOTFOUND;					      \
-      while (hashtable[hidx] != ~((stridx_t) 0))			      \
+  status = NSS_STATUS_NOTFOUND;						      \
+  while (hashtable[hidx] != ~((stridx_t) 0))				      \
+    {									      \
+      const char *valstr = valstrtab + hashtable[hidx];			      \
+      size_t len = strlen (valstr) + 1;					      \
+      if (len > buflen)							      \
 	{								      \
-	  const char *valstr = valstrtab + hashtable[hidx];		      \
-	  size_t len = strlen (valstr) + 1;				      \
-	  if (len > buflen)						      \
-	    {								      \
-	      /* No room to copy the data to.  */			      \
-	      *errnop = ERANGE;						      \
-	      H_ERRNO_SET (NETDB_INTERNAL);				      \
-	      status = NSS_STATUS_TRYAGAIN;				      \
-	      break;							      \
-	    }								      \
-									      \
-	  /* Copy the string to a place where it can be modified.  */	      \
-	  char *p = memcpy (buffer, valstr, len);			      \
+	  /* No room to copy the data to.  */				      \
+	  *errnop = ERANGE;						      \
+	  H_ERRNO_SET (NETDB_INTERNAL);					      \
+	  status = NSS_STATUS_TRYAGAIN;					      \
+	  break;							      \
+	}								      \
 									      \
-	  int err = parse_line (p, result, data, buflen, errnop		      \
-				EXTRA_ARGS);				      \
-	  if (err > 0)							      \
-	    {								      \
-	      status = NSS_STATUS_SUCCESS;				      \
-	      break_if_match;						      \
-	      status = NSS_STATUS_NOTFOUND;				      \
-	    }								      \
-	  else if (err == -1)						      \
-	    {								      \
-	      H_ERRNO_SET (NETDB_INTERNAL);				      \
-	      status = NSS_STATUS_TRYAGAIN;				      \
-	      break;							      \
-	    }								      \
+      /* Copy the string to a place where it can be modified.  */	      \
+      char *p = memcpy (buffer, valstr, len);				      \
 									      \
-	  if ((hidx += hval2) >= header->dbs[i].hashsize)		      \
-	    hidx -= header->dbs[i].hashsize;				      \
+      int err = parse_line (p, result, data, buflen, errnop EXTRA_ARGS);      \
+      if (err > 0)							      \
+	{								      \
+	  status = NSS_STATUS_SUCCESS;					      \
+	  break_if_match;						      \
+	  status = NSS_STATUS_NOTFOUND;					      \
+	}								      \
+      else if (err == -1)						      \
+	{								      \
+	  H_ERRNO_SET (NETDB_INTERNAL);					      \
+	  status = NSS_STATUS_TRYAGAIN;					      \
+	  break;							      \
 	}								      \
 									      \
-      if (status == NSS_STATUS_NOTFOUND)				      \
-	H_ERRNO_SET (HOST_NOT_FOUND);					      \
+      if ((hidx += hval2) >= header->dbs[i].hashsize)			      \
+	hidx -= header->dbs[i].hashsize;				      \
     }									      \
+									      \
+  if (status == NSS_STATUS_NOTFOUND)					      \
+    H_ERRNO_SET (HOST_NOT_FOUND);					      \
+									      \
  out:									      \
   internal_endent (&state);						      \
 									      \

http://sources.redhat.com/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=9f2da732e7b03825027462dd1c46f8b4d18fc1f5

commit 9f2da732e7b03825027462dd1c46f8b4d18fc1f5
Author: Ulrich Drepper <drepper@gmail.com>
Date:   Wed Jun 15 21:00:21 2011 -0400

    Add initgroups lookups to nss_db

diff --git a/ChangeLog b/ChangeLog
index 49d85da..b580e29 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,14 @@
 2011-06-15  Ulrich Drepper  <drepper@gmail.com>
 
+	* nss/Makefile (libnss_db-dbs): Add db-initgroups.
+	* nss/Versions [libnss_db]: Add _nss_db_initgroups_dyn for
+	GLIBC_PRIVATE.
+	* nss/db-Makefile (groups.db): Emit entries for initgroups lookups.
+	* nss/makedb.c: Implement -g option to specify that value strings
+	are generated and should not be added to table iterated over for
+	get*ent calls.
+	* nss/nss_db/db-initgroups.c: New file.
+
 	* nss/getent.c: Add support for initgroups lookups through getgrouplist
 	interface.
 
diff --git a/NEWS b/NEWS
index ceadd18..dd00b7b 100644
--- a/NEWS
+++ b/NEWS
@@ -1,4 +1,4 @@
-GNU C Library NEWS -- history of user-visible changes.  2011-6-9
+GNU C Library NEWS -- history of user-visible changes.  2011-6-15
 Copyright (C) 1992-2009, 2010, 2011 Free Software Foundation, Inc.
 See the end for copying conditions.
 
@@ -9,6 +9,10 @@ Version 2.15
 
 * New program pldd to list loaded object of a process
   Implemented by Ulrich Drepper.
+
+* Add nss_db support back to glibc.  No more dependency on Berkeley db
+  and support for initgroups lookups.
+  Implemented by Ulrich Drepper.
 
 Version 2.14
 
diff --git a/nss/Makefile b/nss/Makefile
index a925cb5..f6065cc 100644
--- a/nss/Makefile
+++ b/nss/Makefile
@@ -71,7 +71,8 @@ distribute		+= files-XXX.c files-parse.c
 
 libnss_db-dbs		:= $(addprefix db-,\
 				       $(filter-out hosts network key alias,\
-						    $(databases)))
+						    $(databases))) \
+			   db-initgroups
 libnss_db-routines	:= $(libnss_db-dbs) db-open hash-string
 generated		+= $(filter-out db-alias.c db-netgrp.c, \
 					$(addsuffix .c,$(libnss_db-dbs)))
diff --git a/nss/Versions b/nss/Versions
index 2f3a671..9137512 100644
--- a/nss/Versions
+++ b/nss/Versions
@@ -151,5 +151,7 @@ libnss_db {
     _nss_db_endspent;
     _nss_db_getspent_r;
     _nss_db_getspnam_r;
+
+    _nss_db_initgroups_dyn;
   }
 }
diff --git a/nss/db-Makefile b/nss/db-Makefile
index 649e09c..13259c1 100644
--- a/nss/db-Makefile
+++ b/nss/db-Makefile
@@ -47,7 +47,19 @@ $(VAR_DB)/group.db: /etc/group
 		 /^[ \t]*$$/ { next } \
 		 /^[ \t]*#/ { next } \
 		 /^[^#]/ { printf ".%s ", $$1; print; \
-			   printf "=%s ", $$3; print }' $^ | \
+			   printf "=%s ", $$3; print; \
+			   if ($$4 != "") { \
+			     split($$4, grmems, ","); \
+			     for (memidx in grmems) { \
+			       mem=grmems[memidx]; \
+			       if (members[mem] == "") \
+				 members[mem]=$$3; \
+			       else \
+				 members[mem]=members[mem] "," $$3; \
+			     } \
+			     delete grmems; } } \
+		 END { for (mem in members) \
+			 printf ":%s $s %s\n", mem, mem, members[mem]; }' $^ | \
 	$(MAKEDB) -o $@ -
 	@echo "done."
 
diff --git a/nss/makedb.c b/nss/makedb.c
index ebb6215..8bbebc5 100644
--- a/nss/makedb.c
+++ b/nss/makedb.c
@@ -53,6 +53,7 @@
 struct database
 {
   char dbid;
+  bool extra_string;
   struct database *next;
   void *entries;
   size_t nentries;
@@ -67,6 +68,7 @@ static size_t nhashentries_total;
 static size_t valstrlen;
 static void *valstrtree;
 static char *valstrtab;
+static size_t extrastrlen;
 
 /* Database entry.  */
 struct dbentry
@@ -80,6 +82,7 @@ struct dbentry
 struct valstrentry
 {
   stridx_t idx;
+  bool extra_string;
   char str[0];
 };
 
@@ -112,7 +115,8 @@ static const struct argp_option options[] =
     N_("Do not print messages while building database") },
   { "undo", 'u', NULL, 0,
     N_("Print content of database file, one entry a line") },
-  { NULL, 0, NULL, 0, N_("Select index type") },
+  { "generated", 'g', N_("CHAR"), 0,
+    N_("Generated line not part of iteration") },
   { NULL, 0, NULL, 0, NULL }
 };
 
@@ -136,6 +140,14 @@ static struct argp argp =
 };
 
 
+/* List of databases which are not part of the iteration table.  */
+static struct db_option
+{
+  char dbid;
+  struct db_option *next;
+} *db_options;
+
+
 /* Prototypes for local functions.  */
 static int process_input (FILE *input, const char *inname,
 			  int to_lowercase, int be_quiet);
@@ -311,6 +323,8 @@ main (int argc, char *argv[])
 static error_t
 parse_opt (int key, char *arg, struct argp_state *state)
 {
+  struct db_option *newp;
+
   switch (key)
     {
     case 'f':
@@ -325,6 +339,12 @@ parse_opt (int key, char *arg, struct argp_state *state)
     case 'u':
       do_undo = 1;
       break;
+    case 'g':
+      newp = xmalloc (sizeof (*newp));
+      newp->dbid = arg[0];
+      newp->next = db_options;
+      db_options = newp;
+      break;
     default:
       return ARGP_ERR_UNKNOWN;
     }
@@ -463,11 +483,22 @@ process_input (input, inname, to_lowercase, be_quiet)
 	    {
 	      last_database = xmalloc (sizeof (*last_database));
 	      last_database->dbid = key[0];
+	      last_database->extra_string = false;
 	      last_database->next = databases;
 	      last_database->entries = NULL;
 	      last_database->nentries = 0;
 	      last_database->keystrlen = 0;
 	      databases = last_database;
+
+	      struct db_option *runp = db_options;
+	      while (runp != NULL)
+		if (runp->dbid == key[0])
+		  {
+		    last_database->extra_string = true;
+		    break;
+		  }
+		else
+		  runp = runp->next;
 	    }
 	}
 
@@ -478,7 +509,11 @@ process_input (input, inname, to_lowercase, be_quiet)
       /* Store the data.  */
       struct valstrentry *nentry = xmalloc (sizeof (struct valstrentry)
 					    + datalen);
-      nentry->idx = valstrlen;
+      if (last_database->extra_string)
+	nentry->idx = extrastrlen;
+      else
+	nentry->idx = valstrlen;
+      nentry->extra_string = last_database->extra_string;
       memcpy (nentry->str, data, datalen);
 
       struct valstrentry **fdata = tsearch (nentry, &valstrtree,
@@ -493,7 +528,10 @@ process_input (input, inname, to_lowercase, be_quiet)
 	  nentry = *fdata;
 	}
       else
-	valstrlen += datalen;
+	if (last_database->extra_string)
+	  extrastrlen += datalen;
+	else
+	  valstrlen += datalen;
 
       /* Store the key.  */
       struct dbentry *newp = xmalloc (sizeof (struct dbentry) + keylen);
@@ -538,7 +576,7 @@ copy_valstr (const void *nodep, const VISIT which, const int depth)
 
   const struct valstrentry *p = *(const struct valstrentry **) nodep;
 
-  strcpy (valstrtab + p->idx, p->str);
+  strcpy (valstrtab + (p->extra_string ? valstrlen : 0) + p->idx, p->str);
 }
 
 
@@ -576,8 +614,8 @@ next_prime (size_t seed)
 static void
 compute_tables (void)
 {
-  valstrtab = xmalloc (roundup (valstrlen, sizeof (stridx_t)));
-  while (valstrlen % sizeof (stridx_t) != 0)
+  valstrtab = xmalloc (roundup (valstrlen + extrastrlen, sizeof (stridx_t)));
+  while ((valstrlen + extrastrlen) % sizeof (stridx_t) != 0)
     valstrtab[valstrlen++] = '\0';
   twalk (valstrtree, copy_valstr);
 
@@ -590,9 +628,9 @@ compute_tables (void)
 	   elements to store in the hash table for the size.  This gives
 	   enough efficiency.  */
 #define TEST_RANGE 30
-	size_t nhashentries_min = next_prime (MAX (db->nentries,
-						   db->nentries
-						   * 2 - TEST_RANGE));
+	size_t nhashentries_min = next_prime (db->nentries < TEST_RANGE
+					      ? db->nentries
+					      : db->nentries * 2 - TEST_RANGE);
 	size_t nhashentries_max = MAX (nhashentries_min, db->nentries * 4);
 	size_t nhashentries_best = nhashentries_min;
 	size_t chainlength_best = db->nentries;
@@ -634,7 +672,8 @@ compute_tables (void)
 		hidx -= nhashentries;
 	    }
 
-	  db->hashtable[hidx] = dbe->validx;
+	  db->hashtable[hidx] = ((db->extra_string ? valstrlen : 0)
+				 + dbe->validx);
 	  db->keyidxtab[hidx] = stridx;
 
 	  max_chainlength = MAX (max_chainlength, chainlength);
@@ -702,8 +741,8 @@ write_output (int fd)
   iov[0].iov_len = file_offset;
 
   iov[1].iov_base = valstrtab;
-  iov[1].iov_len = valstrlen;
-  file_offset += valstrlen;
+  iov[1].iov_len = valstrlen + extrastrlen;
+  file_offset += iov[1].iov_len;
 
   size_t keydataoffset = file_offset + nhashentries_total * sizeof (stridx_t);
   for (struct database *db = databases; db != NULL; db = db->next)
diff --git a/nss/nss_db/db-initgroups.c b/nss/nss_db/db-initgroups.c
new file mode 100644
index 0000000..aa8163b
--- /dev/null
+++ b/nss/nss_db/db-initgroups.c
@@ -0,0 +1,138 @@
+/* Initgroups handling in nss_db module.
+   Copyright (C) 2011 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@gmail.com>.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include <ctype.h>
+#include <errno.h>
+#include <grp.h>
+#include <paths.h>
+
+#include "nss_db.h"
+
+/* The hashing function we use.  */
+#include "../intl/hash-string.h"
+
+
+enum nss_status
+_nss_db_initgroups_dyn (const char *user, gid_t group, long int *start,
+			long int *size, gid_t **groupsp, long int limit,
+			int *errnop)
+{
+  struct nss_db_map state = { NULL, 0 };
+  enum nss_status status = internal_setent (_PATH_VARDB "group.db", &state);
+  if (status != NSS_STATUS_SUCCESS)
+    {
+      *errnop = errno;
+      return status;
+    }
+
+  const struct nss_db_header *header = state.header;
+  int i;
+  for (i = 0; i < header->ndbs; ++i)
+    if (header->dbs[i].id == ':')
+      break;
+  if (i == header->ndbs)
+    {
+      status = NSS_STATUS_UNAVAIL;
+      goto out;
+    }
+
+  const stridx_t *hashtable
+    = (const stridx_t *) ((const char *) header
+			  + header->dbs[i].hashoffset);
+  const char *valstrtab = (const char *) header + header->valstroffset;
+  size_t userlen = strlen (user);
+  uint32_t hashval = __hash_string (user);
+  size_t hidx = hashval % header->dbs[i].hashsize;
+  size_t hval2 = 1 + hashval % (header->dbs[i].hashsize - 2);
+
+  gid_t *groups = *groupsp;
+
+  status = NSS_STATUS_NOTFOUND;
+  while (hashtable[hidx] != ~((stridx_t) 0))
+    {
+      const char *valstr = valstrtab + hashtable[hidx];
+      while (isblank (*valstr))
+	++valstr;
+
+      if (strncmp (valstr, user, userlen) == 0 && isblank (valstr[userlen]))
+	{
+	  valstr += userlen + 1;
+	  while (isblank (*valstr))
+	    ++valstr;
+
+	  while (*valstr != '\0')
+	    {
+	      errno = 0;
+	      char *endp;
+	      unsigned long int n = strtoul (valstr, &endp, 10);
+	      if (*endp != ',' && *endp != '\0')
+		break;
+	      valstr = *endp == '\0' ? endp : endp + 1;
+
+	      if (n != ULONG_MAX || errno != ERANGE)
+		{
+		  /* Insert the group.  */
+		  if (*start == *size)
+		    {
+		      /* Need a bigger buffer.  */
+		      if (limit > 0 && *size == limit)
+			{
+			  /* We reached the maximum.  */
+			  status = NSS_STATUS_SUCCESS;
+			  goto out;
+			}
+
+		      long int newsize;
+		      if (limit <= 0)
+			newsize = 2 * *size;
+		      else
+			newsize = MIN (limit, 2 * *size);
+
+		      gid_t *newgroups = realloc (groups,
+						  newsize * sizeof (*groups));
+		      if (newgroups == NULL)
+			{
+			  *errnop = ENOMEM;
+			  status = NSS_STATUS_TRYAGAIN;
+			  goto out;
+			}
+
+		      *groupsp = groups = newgroups;
+		      *size = newsize;
+		    }
+
+		  groups[*start] = n;
+		  *start += 1;
+		}
+	    }
+
+	  status = NSS_STATUS_SUCCESS;
+	  break;
+	}
+
+      if ((hidx += hval2) >= header->dbs[i].hashsize)
+	hidx -= header->dbs[i].hashsize;
+    }
+
+ out:
+  internal_endent (&state);
+
+  return status;
+}

http://sources.redhat.com/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=82e9a1f7df488c62a214ee63847b2c884dcba565

commit 82e9a1f7df488c62a214ee63847b2c884dcba565
Author: Ulrich Drepper <drepper@gmail.com>
Date:   Wed Jun 15 20:54:31 2011 -0400

    Add initgroups lookup support to getent

diff --git a/ChangeLog b/ChangeLog
index f741278..49d85da 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,8 @@
 2011-06-15  Ulrich Drepper  <drepper@gmail.com>
 
+	* nss/getent.c: Add support for initgroups lookups through getgrouplist
+	interface.
+
 	* grp/initgroups.c (__nss_initgroups_database): Renamed and exported.
 	(internal_getgrouplist): Adjust to name change.
 	Update use_initgroups_entry if this is not the first call.
diff --git a/nss/getent.c b/nss/getent.c
index a33bcb4..9d43e2f 100644
--- a/nss/getent.c
+++ b/nss/getent.c
@@ -501,6 +501,38 @@ netgroup_keys (int number, char *key[])
   return result;
 }
 
+/* This is for initgroups */
+static int
+initgroups_keys (int number, char *key[])
+{
+  int ngrps = 100;
+  size_t grpslen = ngrps * sizeof (gid_t);
+  gid_t *grps = alloca (grpslen);
+
+  for (int i = 0; i < number; ++i)
+    {
+      int no = ngrps;
+      int n;
+      while ((n = getgrouplist (key[i], -1, grps, &no)) == -1
+	     && no > ngrps)
+	{
+	  grps = extend_alloca (grps, grpslen, no * sizeof (gid_t));
+	  ngrps = no;
+	}
+
+      if (n == -1)
+	return 1;
+
+      printf ("%-21s", key[i]);
+      for (int j = 0; j < n; ++j)
+	if (grps[j] != -1)
+	  printf (" %ld", (long int) grps[j]);
+      putchar_unlocked ('\n');
+    }
+
+  return 0;
+}
+
 /* This is for networks */
 static void
 print_networks (struct netent *net)
@@ -829,6 +861,7 @@ D(ethers)
 D(group)
 D(gshadow)
 D(hosts)
+D(initgroups)
 D(netgroup)
 D(networks)
 D(passwd)

http://sources.redhat.com/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=c41af17eed77f07983dab6f702a6347fcad9a619

commit c41af17eed77f07983dab6f702a6347fcad9a619
Author: Ulrich Drepper <drepper@gmail.com>
Date:   Wed Jun 15 20:53:22 2011 -0400

    Fix handling of initgroups database.

diff --git a/ChangeLog b/ChangeLog
index ed75109..f741278 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,10 @@
 2011-06-15  Ulrich Drepper  <drepper@gmail.com>
 
+	* grp/initgroups.c (__nss_initgroups_database): Renamed and exported.
+	(internal_getgrouplist): Adjust to name change.
+	Update use_initgroups_entry if this is not the first call.
+	* nss/databases.def: Add initgroups entry.
+
 	* nss/makedb.c (compute_tables): Check result of multiple hash table
 	sizes to minimize maximum chain length.
 
diff --git a/grp/initgroups.c b/grp/initgroups.c
index dad30d5..48119ff 100644
--- a/grp/initgroups.c
+++ b/grp/initgroups.c
@@ -44,7 +44,7 @@ extern int __nss_group_lookup (service_user **nip, const char *name,
 extern void *__nss_lookup_function (service_user *ni, const char *fct_name);
 
 extern service_user *__nss_group_database attribute_hidden;
-static service_user *initgroups_database;
+service_user *__nss_initgroups_database;
 static bool use_initgroups_entry;
 
 
@@ -80,26 +80,31 @@ internal_getgrouplist (const char *user, gid_t group, long int *size,
   /* Start is one, because we have the first group as parameter.  */
   long int start = 1;
 
-  if (initgroups_database == NULL)
+  if (__nss_initgroups_database == NULL)
     {
       no_more = __nss_database_lookup ("initgroups", NULL, "",
-				       &initgroups_database);
-      if (no_more == 0 && initgroups_database == NULL)
+				       &__nss_initgroups_database);
+      if (no_more == 0 && __nss_initgroups_database == NULL)
 	{
 	  if (__nss_group_database == NULL)
 	    no_more = __nss_database_lookup ("group", NULL, "compat files",
 					     &__nss_group_database);
 
-	  initgroups_database = __nss_group_database;
+	  __nss_initgroups_database = __nss_group_database;
 	}
-      else if (initgroups_database != NULL)
+      else if (__nss_initgroups_database != NULL)
 	{
 	  assert (no_more == 0);
 	  use_initgroups_entry = true;
 	}
     }
+  else
+    /* __nss_initgroups_database might have been set through
+       __nss_configure_lookup in which case use_initgroups_entry was
+       not set here.  */
+    use_initgroups_entry = __nss_initgroups_database != __nss_group_database;
 
-  service_user *nip = initgroups_database;
+  service_user *nip = __nss_initgroups_database;
   while (! no_more)
     {
       long int prev_start = start;
diff --git a/nss/databases.def b/nss/databases.def
index c35d7f1..bc0c6f5 100644
--- a/nss/databases.def
+++ b/nss/databases.def
@@ -1,5 +1,5 @@
 /* List of all databases defined for the NSS in GNU C Library.
-   Copyright (C) 1996, 1997, 2005 Free Software Foundation, Inc.
+   Copyright (C) 1996, 1997, 2005, 2011 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
 
@@ -25,6 +25,7 @@ DEFINE_DATABASE (aliases)
 DEFINE_DATABASE (ethers)
 DEFINE_DATABASE (group)
 DEFINE_DATABASE (hosts)
+DEFINE_DATABASE (initgroups)
 DEFINE_DATABASE (netgroup)
 DEFINE_DATABASE (networks)
 DEFINE_DATABASE (passwd)

http://sources.redhat.com/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=a9e836b0406c259979fbb31eb6650d33c2bbefbc

commit a9e836b0406c259979fbb31eb6650d33c2bbefbc
Author: Ulrich Drepper <drepper@gmail.com>
Date:   Wed Jun 15 10:20:21 2011 -0400

    Optimize hash table generation in makedb

diff --git a/ChangeLog b/ChangeLog
index 60ad9ae..ed75109 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2011-06-15  Ulrich Drepper  <drepper@gmail.com>
+
+	* nss/makedb.c (compute_tables): Check result of multiple hash table
+	sizes to minimize maximum chain length.
+
 2011-06-14  Ulrich Drepper  <drepper@gmail.com>
 
 	* Versions.def: Add entry for libnss_db.
diff --git a/nss/makedb.c b/nss/makedb.c
index 687414b..ebb6215 100644
--- a/nss/makedb.c
+++ b/nss/makedb.c
@@ -63,7 +63,7 @@ struct database
   char *keystrtab;
 } *databases;
 static size_t ndatabases;
-static size_t nhashentries;
+static size_t nhashentries_total;
 static size_t valstrlen;
 static void *valstrtree;
 static char *valstrtab;
@@ -542,6 +542,37 @@ copy_valstr (const void *nodep, const VISIT which, const int depth)
 }
 
 
+static int
+is_prime (size_t candidate)
+{
+  /* No even number and none less than 10 will be passed here.  */
+  size_t divn = 3;
+  size_t sq = divn * divn;
+
+  while (sq < candidate && candidate % divn != 0)
+    {
+      ++divn;
+      sq += 4 * divn;
+      ++divn;
+    }
+
+  return candidate % divn != 0;
+}
+
+
+static size_t
+next_prime (size_t seed)
+{
+  /* Make it definitely odd.  */
+  seed |= 1;
+
+  while (!is_prime (seed))
+    seed += 2;
+
+  return seed;
+}
+
+
 static void
 compute_tables (void)
 {
@@ -558,15 +589,23 @@ compute_tables (void)
 	/* We simply use an odd number large than twice the number of
 	   elements to store in the hash table for the size.  This gives
 	   enough efficiency.  */
-	db->nhashentries = db->nentries * 2 + 1;
-	db->hashtable = xmalloc (db->nhashentries * sizeof (stridx_t));
-	memset (db->hashtable, '\xff', db->nhashentries * sizeof (stridx_t));
-	db->keyidxtab = xmalloc (db->nhashentries * sizeof (stridx_t));
-	memset (db->keyidxtab, '\xff', db->nhashentries * sizeof (stridx_t));
-	db->keystrtab = xmalloc (db->keystrlen);
-
-	size_t max_chainlength = 0;
-	char *wp = db->keystrtab;
+#define TEST_RANGE 30
+	size_t nhashentries_min = next_prime (MAX (db->nentries,
+						   db->nentries
+						   * 2 - TEST_RANGE));
+	size_t nhashentries_max = MAX (nhashentries_min, db->nentries * 4);
+	size_t nhashentries_best = nhashentries_min;
+	size_t chainlength_best = db->nentries;
+
+	db->hashtable = xmalloc (2 * nhashentries_max * sizeof (stridx_t)
+				 + db->keystrlen);
+	db->keyidxtab = db->hashtable + nhashentries_max;
+	db->keystrtab = (char *) (db->keyidxtab + nhashentries_max);
+
+	size_t max_chainlength;
+	char *wp;
+	size_t nhashentries;
+	bool copy_string = false;
 
 	void add_key(const void *nodep, const VISIT which, const int depth)
 	{
@@ -575,18 +614,24 @@ compute_tables (void)
 
 	  const struct dbentry *dbe = *(const struct dbentry **) nodep;
 
-	  ptrdiff_t stridx = wp - db->keystrtab;
-	  wp = stpcpy (wp, dbe->str) + 1;
+	  ptrdiff_t stridx;
+	  if (copy_string)
+	    {
+	      stridx = wp - db->keystrtab;
+	      wp = stpcpy (wp, dbe->str) + 1;
+	    }
+	  else
+	    stridx = 0;
 
-	  size_t hidx = dbe->hashval % db->nhashentries;
-	  size_t hval2 = 1 + dbe->hashval % (db->nhashentries - 2);
+	  size_t hidx = dbe->hashval % nhashentries;
+	  size_t hval2 = 1 + dbe->hashval % (nhashentries - 2);
 	  size_t chainlength = 0;
 
 	  while (db->hashtable[hidx] != ~((stridx_t) 0))
 	    {
 	      ++chainlength;
-	      if ((hidx += hval2) >= db->nhashentries)
-		hidx -= db->nhashentries;
+	      if ((hidx += hval2) >= nhashentries)
+		hidx -= nhashentries;
 	    }
 
 	  db->hashtable[hidx] = dbe->validx;
@@ -595,11 +640,45 @@ compute_tables (void)
 	  max_chainlength = MAX (max_chainlength, chainlength);
 	}
 
-	twalk (db->entries, add_key);
+	nhashentries = nhashentries_min;
+	for (size_t cnt = 0; cnt < TEST_RANGE; ++cnt)
+	  {
+	    memset (db->hashtable, '\xff', nhashentries * sizeof (stridx_t));
+
+	    max_chainlength = 0;
+	    wp = db->keystrtab;
+
+	    twalk (db->entries, add_key);
+
+	    if (max_chainlength == 0)
+	      {
+		/* No need to look further, this is as good as it gets.  */
+		nhashentries_best = nhashentries;
+		break;
+	      }
+
+	    if (max_chainlength < chainlength_best)
+	      {
+		chainlength_best = max_chainlength;
+		nhashentries_best = nhashentries;
+	      }
+
+	    nhashentries = next_prime (nhashentries + 1);
+	    if (nhashentries > nhashentries_max)
+	      break;
+	  }
+
+	/* Recompute the best table again, this time fill in the strings.  */
+	nhashentries = nhashentries_best;
+	memset (db->hashtable, '\xff',
+		2 * nhashentries_max * sizeof (stridx_t));
+	copy_string = true;
+	wp = db->keystrtab;
 
-	// XXX if hash length is too long resize table and start again
+	twalk (db->entries, add_key);
 
-	nhashentries += db->nhashentries;
+	db->nhashentries = nhashentries_best;
+	nhashentries_total += nhashentries_best;
     }
 }
 
@@ -626,7 +705,7 @@ write_output (int fd)
   iov[1].iov_len = valstrlen;
   file_offset += valstrlen;
 
-  size_t keydataoffset = file_offset + nhashentries * sizeof (stridx_t);
+  size_t keydataoffset = file_offset + nhashentries_total * sizeof (stridx_t);
   for (struct database *db = databases; db != NULL; db = db->next)
     if (db->entries != NULL)
       {
@@ -639,13 +718,13 @@ write_output (int fd)
 	header->dbs[filled_dbs].hashsize = db->nhashentries;
 
 	iov[2 + filled_dbs].iov_base = db->hashtable;
-	iov[2 + filled_dbs].iov_len = db-> nhashentries * sizeof (stridx_t);
+	iov[2 + filled_dbs].iov_len = db->nhashentries * sizeof (stridx_t);
 	header->dbs[filled_dbs].hashoffset = file_offset;
 	file_offset += iov[2 + filled_dbs].iov_len;
 
 	iov[2 + ndatabases + filled_dbs * 2].iov_base = db->keyidxtab;
 	iov[2 + ndatabases + filled_dbs * 2].iov_len
-	  = db-> nhashentries * sizeof (stridx_t);
+	  = db->nhashentries * sizeof (stridx_t);
 	header->dbs[filled_dbs].keyidxoffset = keydataoffset;
 	keydataoffset += iov[2 + ndatabases + filled_dbs * 2].iov_len;
 
@@ -659,7 +738,7 @@ write_output (int fd)
 
   assert (filled_dbs == ndatabases);
   assert (file_offset == (iov[0].iov_len + iov[1].iov_len
-			  + nhashentries * sizeof (stridx_t)));
+			  + nhashentries_total * sizeof (stridx_t)));
   header->allocate = file_offset;
 
   if (writev (fd, iov, 2 + ndatabases * 3) != keydataoffset)

http://sources.redhat.com/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=2666d441c2d8107b1987b869714189af64b954c6

commit 2666d441c2d8107b1987b869714189af64b954c6
Author: Ulrich Drepper <drepper@gmail.com>
Date:   Tue Jun 14 22:21:51 2011 -0400

    Reenable nss_db with a completely new implementation
    
    No longer is Berkeley db used.  Instead a simple hash function is used.
    The database files are not updated once they are created and therefore
    no complicated database is needed.

diff --git a/ChangeLog b/ChangeLog
index 9ce38a8..60ad9ae 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,35 @@
+2011-06-14  Ulrich Drepper  <drepper@gmail.com>
+
+	* Versions.def: Add entry for libnss_db.
+	* shlib-versions: Likewise.
+	* nss/Makefile: Add rules to build libnss_db.
+	* nss/Versions: Add libnss_db information.  Organize libnss_files
+	entries better.
+	* nss/db-Makefile: Add gshadow support.  Change rules for the new
+	makedb progra.  Some minor improvements to generate smaller files.
+	* nss/nss_db/nss_db.h: Move NSS database header data structures to
+	here from...
+	* nss/makedb.c: ...here.
+	Improve database format to be smaller and require less memory at
+	runtime.
+	* nss/nss_db/db-XXX.x: Adjust for new database format.  Don't use
+	db anymore.
+	* nss/nss_db/db-netgrp.c: Likewise.
+	* nss/nss_db/db-open.c: Likewise.
+	* nss/nss_files/flies-XXX.x: Adjust comments.
+	* nss/nss_files/files-ethers.c: Adjust for new DB_LOOKUP definition.
+	* nss/nss_files/files-grp.c: Likewise.
+	* nss/nss_files/files-hosts.c: Likewise.
+	* nss/nss_files/files-network.c: Likewise.
+	* nss/nss_files/files-proto.c: Likewise.
+	* nss/nss_files/files-pwd.c: Likewise.
+	* nss/nss_files/files-rpc.c: Likewise.
+	* nss/nss_files/files-service.c: Likewise.
+	* nss/nss_files/files-sgrp.c: Likewise.
+	* nss/nss_files/files-spwd.c: Likewise.
+	* nss/nss_db/db-alias.c: Removed.
+	* nss/nss_db/dummy-db.h: Removed.
+
 2011-06-02  Ulrich Drepper  <drepper@gmail.com>
 
 	* nss/makedb.c: Rewritten to not use database library.
diff --git a/Versions.def b/Versions.def
index e478fdd..666ea73 100644
--- a/Versions.def
+++ b/Versions.def
@@ -67,6 +67,9 @@ libnss_compat {
 libnss_dns {
   GLIBC_PRIVATE
 }
+libnss_db {
+  GLIBC_PRIVATE
+}
 libnss_files {
   GLIBC_PRIVATE
 }
diff --git a/nss/Makefile b/nss/Makefile
index 16578a3..a925cb5 100644
--- a/nss/Makefile
+++ b/nss/Makefile
@@ -53,7 +53,7 @@ otherlibs += $(nssobjdir)/libnss_files.a $(resolvobjdir)/libnss_dns.a \
 endif
 
 # Specify rules for the nss_* modules.  We have some services.
-services		:= files
+services		:= files db
 
 extra-libs		= $(services:%=libnss_%)
 # These libraries will be built in the `others' pass rather than
@@ -69,10 +69,18 @@ libnss_files-routines	:= $(addprefix files-,$(databases)) \
 			   files-initgroups files-have_o_cloexec
 distribute		+= files-XXX.c files-parse.c
 
+libnss_db-dbs		:= $(addprefix db-,\
+				       $(filter-out hosts network key alias,\
+						    $(databases)))
+libnss_db-routines	:= $(libnss_db-dbs) db-open hash-string
+generated		+= $(filter-out db-alias.c db-netgrp.c, \
+					$(addsuffix .c,$(libnss_db-dbs)))
+distribute		+= $(addprefix nss_db/, db-XXX.c nss_db.h)
 
 # Build static module if requested
 ifneq ($(build-static-nss),yes)
 libnss_files-inhibit-o	= $(filter-out .os,$(object-suffixes))
+libnss_db-inhibit-o	= $(filter-out .os,$(object-suffixes))
 endif
 
 include ../Rules
@@ -93,6 +101,15 @@ libnss-libc = $(common-objpfx)linkobj/libc.so
 $(services:%=$(objpfx)libnss_%.so): $(libnss-libc) \
 				    $(common-objpfx)libc_nonshared.a
 
+$(objpfx)libnss_db.so: $(objpfx)libnss_files.so
+
+$(libnss_db-dbs:%=$(objpfx)%.c): $(objpfx)db-%.c: nss_files/files-%.c
+	@rm -f $@.new
+	(echo '#define EXTERN_PARSER';\
+	 echo '#define GENERIC "../nss_db/db-XXX.c"';\
+	 echo '#include "$<"') > $@.new
+	mv -f $@.new $@
+
 
 $(objpfx)makedb: $(makedb-modules:%=$(objpfx)%.o)
 
diff --git a/nss/Versions b/nss/Versions
index 1c6fd68..2f3a671 100644
--- a/nss/Versions
+++ b/nss/Versions
@@ -27,6 +27,8 @@ libnss_files {
     _nss_files_endetherent;
     _nss_files_getetherent_r;
     _nss_files_parse_etherent;
+    _nss_files_gethostton_r;
+    _nss_files_getntohost_r;
 
     _nss_files_setgrent;
     _nss_files_endgrent;
@@ -41,14 +43,12 @@ libnss_files {
     _nss_files_gethostbyname4_r;
     _nss_files_gethostbyname_r;
     _nss_files_gethostent_r;
-    _nss_files_gethostton_r;
 
     _nss_files_setnetent;
     _nss_files_endnetent;
     _nss_files_getnetbyaddr_r;
     _nss_files_getnetbyname_r;
     _nss_files_getnetent_r;
-    _nss_files_getntohost_r;
     _nss_files_parse_netent;
 
     _nss_files_setnetgrent;
@@ -99,3 +99,57 @@ libnss_files {
     _nss_files_initgroups_dyn;
   }
 }
+
+libnss_db {
+  GLIBC_PRIVATE {
+    _nss_db_setetherent;
+    _nss_db_endetherent;
+    _nss_db_getetherent_r;
+    _nss_db_gethostton_r;
+    _nss_db_getntohost_r;
+
+    _nss_db_setgrent;
+    _nss_db_endgrent;
+    _nss_db_getgrent_r;
+    _nss_db_getgrgid_r;
+    _nss_db_getgrnam_r;
+
+    _nss_db_setnetgrent;
+    _nss_db_endnetgrent;
+    _nss_db_getnetgrent_r;
+
+    _nss_db_setprotoent;
+    _nss_db_endprotoent;
+    _nss_db_getprotoent_r;
+    _nss_db_getprotobyname_r;
+    _nss_db_getprotobynumber_r;
+
+    _nss_db_setpwent;
+    _nss_db_endpwent;
+    _nss_db_getpwent_r;
+    _nss_db_getpwnam_r;
+    _nss_db_getpwuid_r;
+
+    _nss_db_setrpcent;
+    _nss_db_endrpcent;
+    _nss_db_getrpcent_r;
+    _nss_db_getrpcbyname_r;
+    _nss_db_getrpcbynumber_r;
+
+    _nss_db_setservent;
+    _nss_db_endservent;
+    _nss_db_getservent_r;
+    _nss_db_getservbyname_r;
+    _nss_db_getservbyport_r;
+
+    _nss_db_setsgent;
+    _nss_db_endsgent;
+    _nss_db_getsgent_r;
+    _nss_db_getsgnam_r;
+
+    _nss_db_setspent;
+    _nss_db_endspent;
+    _nss_db_getspent_r;
+    _nss_db_getspnam_r;
+  }
+}
diff --git a/nss/db-Makefile b/nss/db-Makefile
index f9c6bd3..649e09c 100644
--- a/nss/db-Makefile
+++ b/nss/db-Makefile
@@ -1,5 +1,5 @@
 # Makefile to (re-)generate db versions of system database files.
-# Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
+# Copyright (C) 1996, 1997, 1998, 2011 Free Software Foundation, Inc.
 # This file is part of the GNU C Library.
 # Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
 #
@@ -20,7 +20,8 @@
 # 02111-1307 USA.
 
 DATABASES = $(wildcard /etc/passwd /etc/group /etc/ethers /etc/protocols \
-		       /etc/rpc /etc/services /etc/shadow /etc/netgroup)
+		       /etc/rpc /etc/services /etc/shadow /etc/gshadow \
+		       /etc/netgroup)
 
 VAR_DB = /var/db
 
@@ -32,10 +33,9 @@ all: $(patsubst %,$(VAR_DB)/%.db,$(notdir $(DATABASES)))
 
 $(VAR_DB)/passwd.db: /etc/passwd
 	@echo -n "$(patsubst %.db,%,$(@F))... "
-	@$(AWK) 'BEGIN { FS=":"; OFS=":"; cnt=0 } \
+	@$(AWK) 'BEGIN { FS=":"; OFS=":" } \
 		 /^[ \t]*$$/ { next } \
 		 /^[ \t]*#/ { next } \
-		 { printf "0%u ", cnt++; print } \
 		 /^[^#]/ { printf ".%s ", $$1; print; \
 			   printf "=%s ", $$3; print }' $^ | \
 	$(MAKEDB) -o $@ -
@@ -43,10 +43,9 @@ $(VAR_DB)/passwd.db: /etc/passwd
 
 $(VAR_DB)/group.db: /etc/group
 	@echo -n "$(patsubst %.db,%,$(@F))... "
-	@$(AWK) 'BEGIN { FS=":"; OFS=":"; cnt=0 } \
+	@$(AWK) 'BEGIN { FS=":"; OFS=":" } \
 		 /^[ \t]*$$/ { next } \
 		 /^[ \t]*#/ { next } \
-		 { printf "0%u ", cnt++; print } \
 		 /^[^#]/ { printf ".%s ", $$1; print; \
 			   printf "=%s ", $$3; print }' $^ | \
 	$(MAKEDB) -o $@ -
@@ -54,10 +53,8 @@ $(VAR_DB)/group.db: /etc/group
 
 $(VAR_DB)/ethers.db: /etc/ethers
 	@echo -n "$(patsubst %.db,%,$(@F))... "
-	@$(AWK) 'BEGIN { cnt=0 } \
-		 /^[ \t]*$$/ { next } \
+	@$(AWK) '/^[ \t]*$$/ { next } \
 		 /^[ \t]*#/ { next } \
-		 { printf "0%u ", cnt++; print } \
 		 /^[^#]/ { printf ".%s ", $$1; print; \
 			   printf "=%s ", $$2; print }' $^ | \
 	$(MAKEDB) -o $@ -
@@ -65,10 +62,8 @@ $(VAR_DB)/ethers.db: /etc/ethers
 
 $(VAR_DB)/protocols.db: /etc/protocols
 	@echo -n "$(patsubst %.db,%,$(@F))... "
-	@$(AWK) 'BEGIN { cnt=0 } \
-		 /^[ \t]*$$/ { next } \
+	@$(AWK) '/^[ \t]*$$/ { next } \
 		 /^[ \t]*#/ { next } \
-		 { printf "0%u ", cnt++; print } \
 		 /^[^#]/ { printf ".%s ", $$1; print; \
 			   printf "=%s ", $$2; print; \
 			   for (i = 3; i <= NF && !($$i ~ /^#/); ++i) \
@@ -78,10 +73,8 @@ $(VAR_DB)/protocols.db: /etc/protocols
 
 $(VAR_DB)/rpc.db: /etc/rpc
 	@echo -n "$(patsubst %.db,%,$(@F))... "
-	@$(AWK) 'BEGIN { cnt=0 } \
-		 /^[ \t]*$$/ { next } \
+	@$(AWK) '/^[ \t]*$$/ { next } \
 		 /^[ \t]*#/ { next } \
-		 { printf "0%u ", cnt++; print } \
 		 /^[^#]/ { printf ".%s ", $$1; print; \
 			   printf "=%s ", $$2; print; \
 			   for (i = 3; i <= NF && !($$i ~ /^#/); ++i) \
@@ -91,26 +84,25 @@ $(VAR_DB)/rpc.db: /etc/rpc
 
 $(VAR_DB)/services.db: /etc/services
 	@echo -n "$(patsubst %.db,%,$(@F))... "
-	@$(AWK) 'BEGIN { FS="[ \t/]+"; cnt=0 } \
+	@$(AWK) 'BEGIN { FS="[ \t/]+" } \
 		 /^[ \t]*$$/ { next } \
 		 /^[ \t]*#/ { next } \
-		 { printf "0%u ", cnt++; print } \
-		 /^[^#]/ { printf ".%s/%s ", $$1, $$3; print; \
-			   printf ".%s/ ", $$1; print; \
+		 /^[^#]/ { sub(/[ \t]*#.*$$/, "");\
+			   printf ":%s/%s ", $$1, $$3; print; \
+			   printf ":%s/ ", $$1; print; \
 			   printf "=%s/%s ", $$2, $$3; print; \
 			   printf "=%s/ ", $$2; print; \
 			   for (i = 4; i <= NF && !($$i ~ /^#/); ++i) \
-			     { printf ".%s/%s ", $$i, $$3; print; \
-			       printf ".%s/ ", $$i; print } }' $^ | \
+			     { printf ":%s/%s ", $$i, $$3; print; \
+			       printf ":%s/ ", $$i; print } }' $^ | \
 	$(MAKEDB) -o $@ -
 	@echo "done."
 
 $(VAR_DB)/shadow.db: /etc/shadow
 	@echo -n "$(patsubst %.db,%,$(@F))... "
-	@$(AWK) 'BEGIN { FS=":"; OFS=":"; cnt=0 } \
+	@$(AWK) 'BEGIN { FS=":"; OFS=":" } \
 		 /^[ \t]*$$/ { next } \
 		 /^[ \t]*#/ { next } \
-		 { printf "0%u ", cnt++; print } \
 		 /^[^#]/ { printf ".%s ", $$1; print }' $^ | \
 	(umask 077 && $(MAKEDB) -o $@ -)
 	@echo "done."
@@ -126,14 +118,38 @@ $(VAR_DB)/shadow.db: /etc/shadow
 	  echo; \
 	fi
 
+$(VAR_DB)/gshadow.db: /etc/gshadow
+	@echo -n "$(patsubst %.db,%,$(@F))... "
+	@$(AWK) 'BEGIN { FS=":"; OFS=":" } \
+		 /^[ \t]*$$/ { next } \
+		 /^[ \t]*#/ { next } \
+		 /^[^#]/ { printf ".%s ", $$1; print }' $^ | \
+	(umask 077 && $(MAKEDB) -o $@ -)
+	@echo "done."
+	@if chgrp shadow $@ 2>/dev/null; then \
+	  chmod g+r $@; \
+	else \
+	  chown 0 $@; chgrp 0 $@; chmod 600 $@; \
+	  echo; \
+	  echo "Warning: The shadow group database $@"; \
+	  echo "has been set to be readable only by root.  You may want"; \
+	  echo "to make it readable by the \`shadow' group depending"; \
+	  echo "on your configuration."; \
+	  echo; \
+	fi
+
 $(VAR_DB)/netgroup.db: /etc/netgroup
 	@echo -n "$(patsubst %.db,%,$(@F))... "
-	@$(AWK) 'BEGIN { cnt=0 } \
+	@$(AWK) 'BEGIN { ini=1 } \
 		 /^[ \t]*$$/ { next } \
 		 /^[ \t]*#/ { next } \
-		 { printf "0%u ", cnt++; print } \
-		 /^[^#]/ { end=sub(/\\/, " "); \
+		 /^[^#]/ { if (sub(/[ \t]*\\$$/, " ") == 0) end="\n"; \
+			   else end=""; \
 			   gsub(/[ \t]+/, " "); \
-			   if(end == 1) printf "%s", $$0; else print }' $^ | \
+			   sub(/^[ \t]*/, ""); \
+			   if (ini == 0) printf "%s%s", $$0, end; \
+			   else printf ".%s %s%s", $$1, $$0, end; \
+			   ini=end == "" ? 0 : 1; } \
+			   END { if (ini==0) printf "\n" }' $^ | \
 	$(MAKEDB) -o $@ -
 	@echo "done."
diff --git a/nss/makedb.c b/nss/makedb.c
index a01b235..687414b 100644
--- a/nss/makedb.c
+++ b/nss/makedb.c
@@ -34,7 +34,7 @@
 #include <unistd.h>
 #include <sys/mman.h>
 #include <sys/stat.h>
-#include "nss_db/dummy-db.h"
+#include "nss_db/nss_db.h"
 
 /* Get libc version number.  */
 #include "../version.h"
@@ -49,51 +49,21 @@
 
 #define PACKAGE _libc_intl_domainname
 
-/* String table index type.  */
-typedef uint32_t stridx_t;
-
-/* Database file header.  */
-struct nss_db_header
-{
-  uint32_t magic;
-#define NSS_DB_MAGIC 0xdd110601
-  uint32_t ndbs;
-  uint64_t valstroffset;
-  uint64_t valstrlen;
-  struct
-  {
-    char id;
-    enum nss_db_type { nss_db_type_hash = 0,
-		       nss_db_type_iterate,
-		       nss_db_type_int4 } type:8;
-    char pad[sizeof (uint32_t) - 2];
-    uint32_t hashsize;
-    uint64_t hashoffset;
-    uint64_t stroffset;
-  } dbs[0];
-};
-
-struct nss_db_entry
-{
-  stridx_t keyidx;
-  stridx_t dataidx;
-};
-
-
 /* List of data bases.  */
 struct database
 {
   char dbid;
-  enum nss_db_type type;
   struct database *next;
   void *entries;
   size_t nentries;
-  size_t keystrlen;
   size_t nhashentries;
-  struct nss_db_entry *hashtable;
+  stridx_t *hashtable;
+  size_t keystrlen;
+  stridx_t *keyidxtab;
   char *keystrtab;
 } *databases;
 static size_t ndatabases;
+static size_t nhashentries;
 static size_t valstrlen;
 static void *valstrtree;
 static char *valstrtab;
@@ -101,7 +71,6 @@ static char *valstrtab;
 /* Database entry.  */
 struct dbentry
 {
-  size_t keylen;
   stridx_t validx;
   uint32_t hashval;
   char str[0];
@@ -115,16 +84,6 @@ struct valstrentry
 };
 
 
-/* Database type specifiers.  */
-struct dbtype
-{
-  char dbid;
-  enum nss_db_type type;
-  struct dbtype *next;
-};
-static struct dbtype *dbtypes;
-
-
 /* True if any entry has been added.  */
 static bool any_dbentry;
 
@@ -154,10 +113,6 @@ static const struct argp_option options[] =
   { "undo", 'u', NULL, 0,
     N_("Print content of database file, one entry a line") },
   { NULL, 0, NULL, 0, N_("Select index type") },
-  { "iterate", 'I', "KEY", 0,
-    N_("Index identified by KEY used to iterate over database") },
-  { "binary", 'B', "KEY", 0,
-    N_("Index identified by KEY has binary key value") },
   { NULL, 0, NULL, 0, NULL }
 };
 
@@ -210,7 +165,7 @@ main (int argc, char *argv[])
   const char *input_name;
   FILE *input_file;
   int remaining;
-  int mode = 0666;
+  int mode = 0644;
 
   /* Set locale via LC_ALL.  */
   setlocale (LC_ALL, "");
@@ -292,7 +247,12 @@ main (int argc, char *argv[])
 
   /* Bail out if nothing is to be done.  */
   if (!any_dbentry)
-    error (EXIT_SUCCESS, 0, gettext ("no entries to be processed"));
+    {
+      if (be_quiet)
+	return EXIT_SUCCESS;
+      else
+	error (EXIT_SUCCESS, 0, gettext ("no entries to be processed"));
+    }
 
   /* Compute hash and string tables.  */
   compute_tables ();
@@ -308,7 +268,6 @@ main (int argc, char *argv[])
   reset_file_creation_context ();
   if (fd == -1)
     error (EXIT_FAILURE, errno, gettext ("cannot create temporary file"));
-  // XXX SELinux context
 
   status = write_output (fd);
 
@@ -352,7 +311,6 @@ main (int argc, char *argv[])
 static error_t
 parse_opt (int key, char *arg, struct argp_state *state)
 {
-  struct dbtype *newtype;
   switch (key)
     {
     case 'f':
@@ -367,17 +325,6 @@ parse_opt (int key, char *arg, struct argp_state *state)
     case 'u':
       do_undo = 1;
       break;
-    case 'I':
-    case 'B':
-      if (arg[0] == '\0' || arg[1] != '\0')
-	error (EXIT_FAILURE, 0, gettext ("\
-argument for option to specify database type must be a single-byte character"));
-      newtype = xmalloc (sizeof (struct dbtype));
-      newtype->dbid = arg[0];
-      newtype->type = key == 'I' ? nss_db_type_iterate : nss_db_type_int4;
-      newtype->next = dbtypes;
-      dbtypes = newtype;
-      break;
     default:
       return ARGP_ERR_UNKNOWN;
     }
@@ -424,13 +371,7 @@ dbentry_compare (const void *p1, const void *p2)
   if (d1->hashval != d2->hashval)
     return d1->hashval < d2->hashval ? -1 : 1;
 
-  if (d1->keylen < d2->keylen)
-    return -1;
-
-  if (d1->keylen > d2->keylen)
-    return 1;
-
-  return memcmp (d1->str, d2->str, d1->keylen);
+  return strcmp (d1->str, d2->str);
 }
 
 
@@ -522,22 +463,11 @@ process_input (input, inname, to_lowercase, be_quiet)
 	    {
 	      last_database = xmalloc (sizeof (*last_database));
 	      last_database->dbid = key[0];
-	      last_database->type = nss_db_type_hash;	/* Default.  */
 	      last_database->next = databases;
 	      last_database->entries = NULL;
 	      last_database->nentries = 0;
 	      last_database->keystrlen = 0;
 	      databases = last_database;
-
-	      struct dbtype *typeit = dbtypes;
-	      while (typeit != NULL)
-		if (typeit->dbid == last_database->dbid)
-		  {
-		    last_database->type = typeit->type;
-		    break;
-		  }
-		else
-		  typeit = typeit->next;
 	    }
 	}
 
@@ -545,24 +475,6 @@ process_input (input, inname, to_lowercase, be_quiet)
       ++key;
       --keylen;
 
-      /* Check the key value if it has to be numeric.  */
-      unsigned long int keyvalue = 0;
-      if (last_database->type != nss_db_type_hash)
-	{
-	  char *endp;
-	  errno = 0;
-	  keyvalue = strtoul (key, &endp, 0);
-	  if ((keyvalue == ULONG_MAX && errno == ERANGE)
-	      || keyvalue > ~((stridx_t) 0))
-	    error (EXIT_FAILURE, 0,
-		   gettext ("index value in line %zu too large"), linenr);
-
-	  if (*endp != '\0')
-	    error (EXIT_FAILURE, 0,
-		   gettext ("index value in line %zu is not a number"),
-		   linenr);
-	}
-
       /* Store the data.  */
       struct valstrentry *nentry = xmalloc (sizeof (struct valstrentry)
 					    + datalen);
@@ -584,24 +496,10 @@ process_input (input, inname, to_lowercase, be_quiet)
 	valstrlen += datalen;
 
       /* Store the key.  */
-      struct dbentry *newp;
-      if (last_database->type == nss_db_type_hash)
-	{
-	  newp = xmalloc (sizeof (struct dbentry) + keylen);
-	  newp->keylen = keylen;
-	  newp->validx = nentry->idx;
-	  newp->hashval = __hash_string (key);
-	  memcpy (newp->str, key, keylen);
-	}
-      else
-	{
-	  newp = xmalloc (sizeof (struct dbentry) + sizeof (stridx_t));
-	  newp->keylen = keylen = sizeof (stridx_t);
-	  newp->validx = nentry->idx;
-	  newp->hashval = keyvalue;
-	  stridx_t value = keyvalue;
-	  memcpy (newp->str, &value, sizeof (stridx_t));
-	}
+      struct dbentry *newp = xmalloc (sizeof (struct dbentry) + keylen);
+      newp->validx = nentry->idx;
+      newp->hashval = __hash_string (key);
+      memcpy (newp->str, key, keylen);
 
       struct dbentry **found = tsearch (newp, &last_database->entries,
 					dbentry_compare);
@@ -657,29 +555,14 @@ compute_tables (void)
       {
 	++ndatabases;
 
-	if (db->type == nss_db_type_iterate)
-	  {
-	    /* We need no hash table and no key value table in this case.  */
-	    db->nhashentries = 0;
-	    db->hashtable = NULL;
-	    db->keystrtab = NULL;
-	    db->keystrlen = 0;
-	    continue;
-	  }
-
-	if (db->keystrlen > ~((stridx_t) 0))
-	  error (EXIT_FAILURE, 0, gettext ("\
-table size too large; recompile with larger stridx_t"));
-
 	/* We simply use an odd number large than twice the number of
 	   elements to store in the hash table for the size.  This gives
 	   enough efficiency.  */
 	db->nhashentries = db->nentries * 2 + 1;
-	db->hashtable = xmalloc (db->nhashentries
-				 * sizeof (struct nss_db_entry));
-	memset (db->hashtable, '\xff',
-		db->nhashentries * sizeof (struct nss_db_entry));
-	db->keystrlen = roundup (db->keystrlen, sizeof (stridx_t));
+	db->hashtable = xmalloc (db->nhashentries * sizeof (stridx_t));
+	memset (db->hashtable, '\xff', db->nhashentries * sizeof (stridx_t));
+	db->keyidxtab = xmalloc (db->nhashentries * sizeof (stridx_t));
+	memset (db->keyidxtab, '\xff', db->nhashentries * sizeof (stridx_t));
 	db->keystrtab = xmalloc (db->keystrlen);
 
 	size_t max_chainlength = 0;
@@ -693,21 +576,21 @@ table size too large; recompile with larger stridx_t"));
 	  const struct dbentry *dbe = *(const struct dbentry **) nodep;
 
 	  ptrdiff_t stridx = wp - db->keystrtab;
-	  wp = mempcpy (wp, dbe->str, dbe->keylen);
+	  wp = stpcpy (wp, dbe->str) + 1;
 
 	  size_t hidx = dbe->hashval % db->nhashentries;
 	  size_t hval2 = 1 + dbe->hashval % (db->nhashentries - 2);
 	  size_t chainlength = 0;
 
-	  while (db->hashtable[hidx].keyidx != ~((stridx_t) 0))
+	  while (db->hashtable[hidx] != ~((stridx_t) 0))
 	    {
 	      ++chainlength;
 	      if ((hidx += hval2) >= db->nhashentries)
 		hidx -= db->nhashentries;
 	    }
 
-	  db->hashtable[hidx].keyidx = stridx;
-	  db->hashtable[hidx].dataidx = dbe->validx;
+	  db->hashtable[hidx] = dbe->validx;
+	  db->keyidxtab[hidx] = stridx;
 
 	  max_chainlength = MAX (max_chainlength, chainlength);
 	}
@@ -716,8 +599,7 @@ table size too large; recompile with larger stridx_t"));
 
 	// XXX if hash length is too long resize table and start again
 
-	while ((wp - db->keystrtab) % sizeof (stridx_t) != 0)
-	  *wp++ = '\0';
+	nhashentries += db->nhashentries;
     }
 }
 
@@ -736,7 +618,7 @@ write_output (int fd)
   header->valstrlen = valstrlen;
 
   size_t filled_dbs = 0;
-  struct iovec iov[2 + 2 * ndatabases];
+  struct iovec iov[2 + ndatabases * 3];
   iov[0].iov_base = header;
   iov[0].iov_len = file_offset;
 
@@ -744,6 +626,7 @@ write_output (int fd)
   iov[1].iov_len = valstrlen;
   file_offset += valstrlen;
 
+  size_t keydataoffset = file_offset + nhashentries * sizeof (stridx_t);
   for (struct database *db = databases; db != NULL; db = db->next)
     if (db->entries != NULL)
       {
@@ -751,28 +634,35 @@ write_output (int fd)
 	assert (filled_dbs < ndatabases);
 
 	header->dbs[filled_dbs].id = db->dbid;
-	header->dbs[filled_dbs].type = db->type;
 	memset (header->dbs[filled_dbs].pad, '\0',
 		sizeof (header->dbs[0].pad));
 	header->dbs[filled_dbs].hashsize = db->nhashentries;
 
-	iov[2 + filled_dbs * 2].iov_base = db->hashtable;
-	iov[2 + filled_dbs * 2].iov_len = (db->nhashentries
-					   * sizeof (struct nss_db_entry));
+	iov[2 + filled_dbs].iov_base = db->hashtable;
+	iov[2 + filled_dbs].iov_len = db-> nhashentries * sizeof (stridx_t);
 	header->dbs[filled_dbs].hashoffset = file_offset;
-	file_offset += iov[2 + filled_dbs * 2].iov_len;
+	file_offset += iov[2 + filled_dbs].iov_len;
 
-	iov[3 + filled_dbs * 2].iov_base = db->keystrtab;
-	iov[3 + filled_dbs * 2].iov_len = db->keystrlen;
-	header->dbs[filled_dbs].stroffset = file_offset;
-	file_offset += iov[3 + filled_dbs * 2].iov_len;
+	iov[2 + ndatabases + filled_dbs * 2].iov_base = db->keyidxtab;
+	iov[2 + ndatabases + filled_dbs * 2].iov_len
+	  = db-> nhashentries * sizeof (stridx_t);
+	header->dbs[filled_dbs].keyidxoffset = keydataoffset;
+	keydataoffset += iov[2 + ndatabases + filled_dbs * 2].iov_len;
+
+	iov[3 + ndatabases + filled_dbs * 2].iov_base = db->keystrtab;
+	iov[3 + ndatabases + filled_dbs * 2].iov_len = db->keystrlen;
+	header->dbs[filled_dbs].keystroffset = keydataoffset;
+	keydataoffset += iov[3 + ndatabases + filled_dbs * 2].iov_len;
 
 	++filled_dbs;
       }
 
   assert (filled_dbs == ndatabases);
+  assert (file_offset == (iov[0].iov_len + iov[1].iov_len
+			  + nhashentries * sizeof (stridx_t)));
+  header->allocate = file_offset;
 
-  if (writev (fd, iov, 2 + 2 * ndatabases) != file_offset)
+  if (writev (fd, iov, 2 + ndatabases * 3) != keydataoffset)
     {
       error (0, errno, gettext ("failed to write new database file"));
       return EXIT_FAILURE;
@@ -801,42 +691,21 @@ print_database (int fd)
 
   for (unsigned int dbidx = 0; dbidx < header->ndbs; ++dbidx)
     {
+      const stridx_t *stridxtab
+	= ((const stridx_t *) ((const char *) header
+			       + header->dbs[dbidx].keyidxoffset));
       const char *keystrtab
-	= (const char *) header + header->dbs[dbidx].stroffset;
-      const struct nss_db_entry *hashtab
-	= (const struct nss_db_entry *) ((const char *) header
-					 + header->dbs[dbidx].hashoffset);
-
-      if (header->dbs[dbidx].type == nss_db_type_hash)
-	{
-	  for (uint32_t hidx = 0; hidx < header->dbs[dbidx].hashsize; ++hidx)
-	    if (hashtab[hidx].keyidx != ~((stridx_t) 0))
-	      printf ("%c%s %s\n",
-		      header->dbs[dbidx].id,
-		      keystrtab + hashtab[hidx].keyidx,
-		      valstrtab + hashtab[hidx].dataidx);
-	}
-      else if (header->dbs[dbidx].type == nss_db_type_iterate)
-	{
-	  const char *endvalstrtab = valstrtab + header->valstrlen;
-	  const char *cp = valstrtab;
-	  unsigned int count = 0;
-	  while (cp < endvalstrtab && *cp != '\0')
-	    {
-	      printf ("%c%u %s\n", header->dbs[dbidx].id, count++, cp);
-	      cp = rawmemchr (cp, '\0') + 1;
-	    }
-	}
-      else
-	{
-	  assert (header->dbs[dbidx].type == nss_db_type_int4);
-	  for (uint32_t hidx = 0; hidx < header->dbs[dbidx].hashsize; ++hidx)
-	    if (hashtab[hidx].keyidx != ~((stridx_t) 0))
-	      printf ("%c%" PRIu32 " %s\n",
-		      header->dbs[dbidx].id,
-		      *((uint32_t *) (keystrtab + hashtab[hidx].keyidx)),
-		      valstrtab + hashtab[hidx].dataidx);
-	}
+	= (const char *) header + header->dbs[dbidx].keystroffset;
+      const stridx_t *hashtab
+	= (const stridx_t *) ((const char *) header
+			      + header->dbs[dbidx].hashoffset);
+
+      for (uint32_t hidx = 0; hidx < header->dbs[dbidx].hashsize; ++hidx)
+	if (hashtab[hidx] != ~((stridx_t) 0))
+	  printf ("%c%s %s\n",
+		  header->dbs[dbidx].id,
+		  keystrtab + stridxtab[hidx],
+		  valstrtab + hashtab[hidx]);
     }
 
   return EXIT_SUCCESS;
diff --git a/nss/nss_db/db-XXX.c b/nss/nss_db/db-XXX.c
index aa8cfd0..30026b1 100644
--- a/nss/nss_db/db-XXX.c
+++ b/nss/nss_db/db-XXX.c
@@ -1,5 +1,5 @@
 /* Common code for DB-based databases in nss_db module.
-   Copyright (C) 1996, 1997, 1998, 1999, 2000 Free Software Foundation, Inc.
+   Copyright (C) 1996-2000, 2011 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -19,10 +19,14 @@
 
 #include <dlfcn.h>
 #include <fcntl.h>
+#include <sys/mman.h>
 #include <bits/libc-lock.h>
 #include "nsswitch.h"
 #include "nss_db.h"
 
+/* The hashing function we use.  */
+#include "../intl/hash-string.h"
+
 /* These symbols are defined by the including source file:
 
    ENTNAME -- database name of the structure and functions (hostent, pwent).
@@ -38,25 +42,25 @@
 #define	DBFILE		_PATH_VARDB DATABASE ".db"
 
 #ifdef NEED_H_ERRNO
-#define H_ERRNO_PROTO	, int *herrnop
-#define H_ERRNO_ARG	, herrnop
-#define H_ERRNO_SET(val) (*herrnop = (val))
+# define H_ERRNO_PROTO	, int *herrnop
+# define H_ERRNO_ARG	, herrnop
+# define H_ERRNO_SET(val) (*herrnop = (val))
 #else
-#define H_ERRNO_PROTO
-#define H_ERRNO_ARG
-#define H_ERRNO_SET(val) ((void) 0)
+# define H_ERRNO_PROTO
+# define H_ERRNO_ARG
+# define H_ERRNO_SET(val) ((void) 0)
 #endif
 
-/* Locks the static variables in this file.  */
-__libc_lock_define_initialized (static, lock)
-
-/* Maintenance of the shared handle open on the database.  */
+/* State for this database.  */
+static struct nss_db_map state;
+/* Lock to protect the state and global variables.  */
+__libc_lock_define (static , lock);
 
-static NSS_DB *db;
+/* Maintenance of the shared handle open on the database.  */
 static int keep_db;
-static int entidx;
-
+static const char *entidx;
 
+
 /* Open the database.  */
 enum nss_status
 CONCAT(_nss_db_set,ENTNAME) (int stayopen)
@@ -65,13 +69,13 @@ CONCAT(_nss_db_set,ENTNAME) (int stayopen)
 
   __libc_lock_lock (lock);
 
-  status = internal_setent (DBFILE, &db);
+  status = internal_setent (DBFILE, &state);
 
   /* Remember STAYOPEN flag.  */
-  if (db != NULL)
+  if (status == NSS_STATUS_SUCCESS)
     keep_db |= stayopen;
   /* Reset the sequential index.  */
-  entidx = 0;
+  entidx  = (const char *) state.header + state.header->valstroffset;
 
   __libc_lock_unlock (lock);
 
@@ -85,7 +89,7 @@ CONCAT(_nss_db_end,ENTNAME) (void)
 {
   __libc_lock_lock (lock);
 
-  internal_endent (&db);
+  internal_endent (&state);
 
   /* Reset STAYOPEN flag.  */
   keep_db = 0;
@@ -94,132 +98,128 @@ CONCAT(_nss_db_end,ENTNAME) (void)
 
   return NSS_STATUS_SUCCESS;
 }
-
-/* Do a database lookup for KEY.  */
-static enum nss_status
-lookup (DBT *key, struct STRUCTURE *result,
-	void *buffer, size_t buflen, int *errnop H_ERRNO_PROTO EXTRA_ARGS_DECL)
-{
-  char *p;
-  enum nss_status status;
-  int err;
-  DBT value;
-
-  /* Open the database.  */
-  if (db == NULL)
-    {
-      status = internal_setent (DBFILE, &db);
-      if (status != NSS_STATUS_SUCCESS)
-	{
-	  *errnop = errno;
-	  H_ERRNO_SET (NETDB_INTERNAL);
-	  return status;
-	}
-    }
-
-  /* Succeed iff it matches a value that parses correctly.  */
-  value.flags = 0;
-  err = DL_CALL_FCT (db->get, (db->db, NULL, key, &value, 0));
-  if (err != 0)
-    {
-      if (err == db_notfound)
-	{
-	  H_ERRNO_SET (HOST_NOT_FOUND);
-	  status = NSS_STATUS_NOTFOUND;
-	}
-      else
-	{
-	  *errnop = err;
-	  H_ERRNO_SET (NETDB_INTERNAL);
-	  status = NSS_STATUS_UNAVAIL;
-	}
-    }
-  else if (buflen < value.size)
-    {
-      /* No room to copy the data to.  */
-      *errnop = ERANGE;
-      H_ERRNO_SET (NETDB_INTERNAL);
-      status = NSS_STATUS_TRYAGAIN;
-    }
-  else
-    {
-      /* Copy the result to a safe place.  */
-      p = (char *) memcpy (buffer, value.data, value.size);
-
-      /* Skip leading blanks.  */
-      while (isspace (*p))
-	++p;
-
-      err = parse_line (p, result, buffer, buflen, errnop EXTRA_ARGS);
-
-      if (err == 0)
-	{
-	  /* If the key begins with '0' we are trying to get the next
-	     entry.  We want to ignore unparsable lines in this case.  */
-	  if (((char *) key->data)[0] == '0')
-	    {
-	      /* Super magical return value.  We need to tell our caller
-		 that it should continue looping.  This value cannot
-		 happen in other cases.  */
-	      status = NSS_STATUS_RETURN;
-	    }
-	  else
-	    {
-	      H_ERRNO_SET (HOST_NOT_FOUND);
-	      status = NSS_STATUS_NOTFOUND;
-	    }
-	}
-      else if (err < 0)
-	{
-	  H_ERRNO_SET (NETDB_INTERNAL);
-	  status = NSS_STATUS_TRYAGAIN;
-	}
-      else
-	status = NSS_STATUS_SUCCESS;
-    }
-
-  if (! keep_db)
-    internal_endent (&db);
-
-  return status;
-}
 
 
 /* Macro for defining lookup functions for this DB-based database.
 
    NAME is the name of the lookup; e.g. `pwnam'.
 
+   DB_CHAR is index indicator for the database.
+
    KEYPATTERN gives `printf' args to construct a key string;
-   e.g. `(".%s", name)'.
+   e.g. `("%d", id)'.
 
    KEYSIZE gives the allocation size of a buffer to construct it in;
-   e.g. `1 + strlen (name)'.
+   e.g. `1 + sizeof (id) * 4'.
 
-   PROTO describes the arguments for the lookup key;
-   e.g. `const char *name'.
+   PROTO is the potentially empty list of other parameters.
 
-   BREAK_IF_MATCH is ignored, but used by ../nss_files/files-XXX.c.  */
+   BREAK_IF_MATCH is a block of code which compares `struct STRUCTURE *result'
+   to the lookup key arguments and does `break;' if they match.  */
 
-#define DB_LOOKUP(name, keysize, keypattern, break_if_match, proto...)	      \
+#define DB_LOOKUP(name, db_char, keysize, keypattern, break_if_match, proto...)\
 enum nss_status								      \
-_nss_db_get##name##_r (proto,						      \
-		       struct STRUCTURE *result,			      \
-		       char *buffer, size_t buflen, int *errnop H_ERRNO_PROTO)\
+ _nss_db_get##name##_r (proto, struct STRUCTURE *result,		      \
+			char *buffer, size_t buflen, int *errnop H_ERRNO_PROTO)\
 {									      \
-  DBT key;								      \
-  enum nss_status status;						      \
-  const size_t size = (keysize) + 1;					      \
-  key.data = __alloca (size);						      \
-  key.size = KEYPRINTF keypattern;					      \
-  key.flags = 0;							      \
-  __libc_lock_lock (lock);						      \
-  status = lookup (&key, result, buffer, buflen, errnop H_ERRNO_ARG	      \
-		   EXTRA_ARGS_VALUE);					      \
-  __libc_lock_unlock (lock);						      \
+  enum nss_status status = NSS_STATUS_SUCCESS;				      \
+  struct nss_db_map state = { NULL, 0 };				      \
+  struct parser_data *data = (void *) buffer;				      \
+									      \
+  if (buflen < sizeof *data)						      \
+    {									      \
+      *errnop = ERANGE;							      \
+      H_ERRNO_SET (NETDB_INTERNAL);					      \
+      return NSS_STATUS_TRYAGAIN;					      \
+    }									      \
+									      \
+  status = internal_setent (DBFILE, &state);				      \
+  if (status != NSS_STATUS_SUCCESS)					      \
+    {									      \
+      *errnop = errno;							      \
+      H_ERRNO_SET (NETDB_INTERNAL);					      \
+      return status;							      \
+    }									      \
+									      \
+  if (status == NSS_STATUS_SUCCESS)					      \
+    {									      \
+      const struct nss_db_header *header = state.header;		      \
+      int i;								      \
+      for (i = 0; i < header->ndbs; ++i)				      \
+	if (header->dbs[i].id == db_char)				      \
+	  break;							      \
+      if (i == header->ndbs)						      \
+	{								      \
+	  status = NSS_STATUS_UNAVAIL;					      \
+	  goto out;							      \
+	}								      \
+									      \
+      char *key;							      \
+      if (db_char == '.')						      \
+	key = (char *) IGNOREPATTERN keypattern;			      \
+      else								      \
+	{								      \
+	  const size_t size = (keysize) + 1;				      \
+	  key = alloca (size);						      \
+									      \
+	  KEYPRINTF keypattern;						      \
+	}								      \
+									      \
+      const stridx_t *hashtable						      \
+	= (const stridx_t *) ((const char *) header			      \
+			      + header->dbs[i].hashoffset);		      \
+      const char *valstrtab = (const char *) header + header->valstroffset;   \
+      uint32_t hashval = __hash_string (key);				      \
+      size_t hidx = hashval % header->dbs[i].hashsize;			      \
+      size_t hval2 = 1 + hashval % (header->dbs[i].hashsize - 2);	      \
+									      \
+      status = NSS_STATUS_NOTFOUND;					      \
+      while (hashtable[hidx] != ~((stridx_t) 0))			      \
+	{								      \
+	  const char *valstr = valstrtab + hashtable[hidx];		      \
+	  size_t len = strlen (valstr) + 1;				      \
+	  if (len > buflen)						      \
+	    {								      \
+	      /* No room to copy the data to.  */			      \
+	      *errnop = ERANGE;						      \
+	      H_ERRNO_SET (NETDB_INTERNAL);				      \
+	      status = NSS_STATUS_TRYAGAIN;				      \
+	      break;							      \
+	    }								      \
+									      \
+	  /* Copy the string to a place where it can be modified.  */	      \
+	  char *p = memcpy (buffer, valstr, len);			      \
+									      \
+	  int err = parse_line (p, result, data, buflen, errnop		      \
+				EXTRA_ARGS);				      \
+	  if (err > 0)							      \
+	    {								      \
+	      status = NSS_STATUS_SUCCESS;				      \
+	      break_if_match;						      \
+	      status = NSS_STATUS_NOTFOUND;				      \
+	    }								      \
+	  else if (err == -1)						      \
+	    {								      \
+	      H_ERRNO_SET (NETDB_INTERNAL);				      \
+	      status = NSS_STATUS_TRYAGAIN;				      \
+	      break;							      \
+	    }								      \
+									      \
+	  if ((hidx += hval2) >= header->dbs[i].hashsize)		      \
+	    hidx -= header->dbs[i].hashsize;				      \
+	}								      \
+									      \
+      if (status == NSS_STATUS_NOTFOUND)				      \
+	H_ERRNO_SET (HOST_NOT_FOUND);					      \
+    }									      \
+ out:									      \
+  internal_endent (&state);						      \
+									      \
   return status;							      \
 }
 
-#define KEYPRINTF(pattern, args...) snprintf (key.data, size, pattern ,##args)
+#define KEYPRINTF(pattern, args...) snprintf (key, size, pattern ,##args)
+#define IGNOREPATTERN(pattern, arg1, args...) (char *) (uintptr_t) arg1
 
 
 
@@ -231,30 +231,72 @@ CONCAT(_nss_db_get,ENTNAME_r) (struct STRUCTURE *result, char *buffer,
 {
   /* Return next entry in host file.  */
   enum nss_status status;
-  char buf[20];
-  DBT key;
+  struct parser_data *data = (void *) buffer;
+
+  if (buflen < sizeof *data)
+    {
+      *errnop = ERANGE;
+      H_ERRNO_SET (NETDB_INTERNAL);
+      return NSS_STATUS_TRYAGAIN;
+    }
 
   __libc_lock_lock (lock);
 
-  /* Loop until we find a valid entry or hit EOF.  See above for the
-     special meaning of the status value.  */
-  do
+  if (state.header == NULL)
     {
-      key.size = snprintf (key.data = buf, sizeof buf, "0%u", entidx++);
-      key.flags = 0;
-      status = lookup (&key, result, buffer, buflen, errnop H_ERRNO_ARG
-		       EXTRA_ARGS_VALUE);
-      if (status == NSS_STATUS_TRYAGAIN
-#ifdef NEED_H_ERRNO
-	  && *herrnop == NETDB_INTERNAL
-#endif
-	  && *errnop == ERANGE)
-	/* Give the user a chance to get the same entry with a larger
-	   buffer.  */
-	--entidx;
+      status = internal_setent (DBFILE, &state);
+      if (status != NSS_STATUS_SUCCESS)
+	{
+	  *errnop = errno;
+	  H_ERRNO_SET (NETDB_INTERNAL);
+	  goto out;
+	}
+    }
+
+  status = NSS_STATUS_UNAVAIL;
+  if (state.header != MAP_FAILED)
+    {
+      const char *const end = ((const char *) state.header
+			       + state.header->valstroffset
+			       + state.header->valstrlen);
+      while (entidx < end)
+	{
+	  const char *next = rawmemchr (entidx, '\0') + 1;
+	  size_t len = next - entidx;
+
+	  if (len > buflen)
+	    {
+	      /* No room to copy the data to.  */
+	      *errnop = ERANGE;
+	      H_ERRNO_SET (NETDB_INTERNAL);
+	      status = NSS_STATUS_TRYAGAIN;
+	      break;
+	    }
+
+	  /* Copy the string to a place where it can be modified.  */
+	  char *p = memcpy (buffer, entidx, len);
+
+	  int err = parse_line (p, result, data, buflen, errnop EXTRA_ARGS);
+
+	  if (err > 0)
+	    {
+	      status = NSS_STATUS_SUCCESS;
+	      entidx = next;
+	      break;
+	    }
+	  if (err < 0)
+	    {
+	      H_ERRNO_SET (HOST_NOT_FOUND);
+	      status = NSS_STATUS_NOTFOUND;
+	      break;
+	    }
+
+	  /* Continue with the next record, this one is ill-formed.  */
+	  entidx = next;
+	}
     }
-  while (status == NSS_STATUS_RETURN);
 
+ out:
   __libc_lock_unlock (lock);
 
   return status;
diff --git a/nss/nss_db/db-alias.c b/nss/nss_db/db-alias.c
deleted file mode 100644
index de468cc..0000000
--- a/nss/nss_db/db-alias.c
+++ /dev/null
@@ -1,215 +0,0 @@
-/* Mail alias file parser in nss_db module.
-   Copyright (C) 1996, 1997, 1998, 1999, 2000 Free Software Foundation, Inc.
-   This file is part of the GNU C Library.
-   Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, write to the Free
-   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
-   02111-1307 USA.  */
-
-#include <aliases.h>
-#include <alloca.h>
-#include <ctype.h>
-#include <dlfcn.h>
-#include <errno.h>
-#include <bits/libc-lock.h>
-#include <paths.h>
-#include <string.h>
-
-#include "nsswitch.h"
-#include "nss_db.h"
-
-/* Locks the static variables in this file.  */
-__libc_lock_define_initialized (static, lock)
-
-/* Maintenance of the shared handle open on the database.  */
-
-static NSS_DB *db;
-static int keep_db;
-static unsigned int entidx;	/* Index for `getaliasent_r'. */
-
-
-/* Open database.  */
-enum nss_status
-_nss_db_setaliasent (int stayopen)
-{
-  enum nss_status status;
-
-  __libc_lock_lock (lock);
-
-  status = internal_setent (_PATH_VARDB "aliases.db", &db);
-
-  /* Remember STAYOPEN flag.  */
-  if (db != NULL)
-    keep_db |= stayopen;
-
-  /* Reset the sequential index.  */
-  entidx = 0;
-
-  __libc_lock_unlock (lock);
-
-  return status;
-}
-
-
-/* Close it again.  */
-enum nss_status
-_nss_db_endaliasent (void)
-{
-  __libc_lock_lock (lock);
-
-  internal_endent (&db);
-
-  /* Reset STAYOPEN flag.  */
-  keep_db = 0;
-
-  __libc_lock_unlock (lock);
-
-  return NSS_STATUS_SUCCESS;
-}
-
-/* We provide the parse function here.  The parser in libnss_files
-   cannot be used.  The generation of the db file already resolved all
-   :include: statements so we simply have to parse the list and store
-   the result.  */
-static enum nss_status
-lookup (DBT *key, struct aliasent *result, char *buffer,
-	size_t buflen, int *errnop)
-{
-  enum nss_status status;
-  DBT value;
-
-  /* Open the database.  */
-  if (db == NULL)
-    {
-      status = internal_setent (_PATH_VARDB "aliases.db", &db);
-      if (status != NSS_STATUS_SUCCESS)
-	{
-	  *errnop = errno;
-	  return status;
-	}
-    }
-
-  value.flags = 0;
-  if (DL_CALL_FCT (db->get, (db->db, NULL, key, &value, 0)) == 0)
-    {
-      const char *src = value.data;
-      char *cp;
-      size_t cnt;
-
-      result->alias_members_len = 0;
-
-      /* We now have to fill the BUFFER with all the information. */
-      if (buflen < key->size + 1)
-	{
-	no_more_room:
-	  *errnop = ERANGE;
-	  return NSS_STATUS_TRYAGAIN;
-	}
-
-      buffer = stpncpy (buffer, key->data, key->size) + 1;
-      buflen -= key->size + 1;
-
-      while (*src != '\0')
-	{
-	  const char *end, *upto;
-	  while (isspace (*src))
-	    ++src;
-
-	  end = strchr (src, ',');
-	  if (end == NULL)
-	    end = strchr (src, '\0');
-	  for (upto = end; upto > src && isspace (upto[-1]); --upto);
-
-	  if (upto != src)
-	    {
-	      if ((upto - src) + __alignof__ (char *) > buflen)
-		goto no_more_room;
-	      buffer = stpncpy (buffer, src, upto - src) + 1;
-	      buflen -= (upto - src) + __alignof (char *);
-	      ++result->alias_members_len;
-	    }
-	  src = end + (*end != '\0');
-	}
-
-      /* Now prepare the return.  Provide string pointers for the
-	 currently selected aliases.  */
-
-      /* Adjust the pointer so it is aligned for storing pointers.  */
-      buffer += __alignof__ (char *) - 1;
-      buffer -= ((buffer - (char *) 0) % __alignof__ (char *));
-      result->alias_members = (char **) buffer;
-
-      /* Compute addresses of alias entry strings.  */
-      cp = result->alias_name;
-      for (cnt = 0; cnt < result->alias_members_len; ++cnt)
-	{
-	  cp = strchr (cp, '\0') + 1;
-	  result->alias_members[cnt] = cp;
-	}
-
-      status = (result->alias_members_len == 0
-		? NSS_STATUS_RETURN : NSS_STATUS_SUCCESS);
-    }
-  else
-    status = NSS_STATUS_NOTFOUND;
-
-  if (! keep_db)
-    internal_endent (&db);
-
-  return status;
-}
-
-enum nss_status
-_nss_db_getaliasent_r (struct aliasent *result, char *buffer, size_t buflen,
-		       int *errnop)
-{
-  /* Return next entry in alias file.  */
-  enum nss_status status;
-  char buf[20];
-  DBT key;
-
-  __libc_lock_lock (lock);
-  key.size = snprintf (key.data = buf, sizeof buf, "0%u", entidx++);
-  key.flags = 0;
-  status = lookup (&key, result, buffer, buflen, errnop);
-  if (status == NSS_STATUS_TRYAGAIN && *errnop == ERANGE)
-    /* Give the user a chance to get the same entry with a larger buffer.  */
-    --entidx;
-  __libc_lock_unlock (lock);
-
-  return status;
-}
-
-
-enum nss_status
-_nss_db_getaliasbyname_r (const char *name, struct aliasent *result,
-			  char *buffer, size_t buflen, int *errnop)
-{
-  DBT key;
-  enum nss_status status;
-
-  key.size = 1 + strlen (name);
-
-  key.data = __alloca (key.size);
-  ((char *) key.data)[0] = '.';
-  memcpy (&((char *) key.data)[1], name, key.size - 1);
-  key.flags = 0;
-
-  __libc_lock_lock (lock);
-  status = lookup (&key, result, buffer, buflen, errnop);
-  __libc_lock_unlock (lock);
-
-  return status;
-}
diff --git a/nss/nss_db/db-netgrp.c b/nss/nss_db/db-netgrp.c
index 47e845a..901d4f5 100644
--- a/nss/nss_db/db-netgrp.c
+++ b/nss/nss_db/db-netgrp.c
@@ -1,5 +1,5 @@
 /* Netgroup file parser in nss_db modules.
-   Copyright (C) 1996, 1997, 1999, 2000 Free Software Foundation, Inc.
+   Copyright (C) 1996, 1997, 1999, 2000, 2011 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
 
@@ -18,6 +18,7 @@
    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
    02111-1307 USA.  */
 
+#include <ctype.h>
 #include <dlfcn.h>
 #include <errno.h>
 #include <fcntl.h>
@@ -29,55 +30,75 @@
 #include "nsswitch.h"
 #include "nss_db.h"
 
-
-#define DBFILE		_PATH_VARDB "netgroup.db"
+/* The hashing function we use.  */
+#include "../intl/hash-string.h"
 
 
-/* Locks the static variables in this file.  */
-__libc_lock_define_initialized (static, lock)
+#define DBFILE		_PATH_VARDB "netgroup.db"
 
 /* Maintenance of the shared handle open on the database.  */
-static NSS_DB *db;
-static char *entry;
-static char *cursor;
-
 enum nss_status
-_nss_db_setnetgrent (const char *group)
+_nss_db_setnetgrent (const char *group, struct __netgrent *result)
 {
-  enum nss_status status;
-
-  __libc_lock_lock (lock);
-
-  status = internal_setent (DBFILE, &db);
+  struct nss_db_map state;
+  enum nss_status status = internal_setent (DBFILE, &state);
 
   if (status == NSS_STATUS_SUCCESS)
     {
-      DBT key = { data: (void *) group, size: strlen (group), flags: 0 };
-      DBT value;
-
-      value.flags = 0;
-      if (DL_CALL_FCT (db->get, (db->db, NULL, &key, &value, 0)) != 0)
-	status = NSS_STATUS_NOTFOUND;
-      else
-	cursor = entry = value.data;
+      const struct nss_db_header *header = state.header;
+      const stridx_t *hashtable
+	= (const stridx_t *) ((const char *) header
+			      + header->dbs[0].hashoffset);
+      const char *valstrtab = (const char *) header + header->valstroffset;
+      uint32_t hashval = __hash_string (group);
+      size_t grouplen = strlen (group);
+      size_t hidx = hashval % header->dbs[0].hashsize;
+      size_t hval2 = 1 + hashval % (header->dbs[0].hashsize - 2);
+
+      status = NSS_STATUS_NOTFOUND;
+      while (hashtable[hidx] != ~((stridx_t) 0))
+	{
+	  const char *valstr = valstrtab + hashtable[hidx];
+
+	  if (strncmp (valstr, group, grouplen) == 0
+	      && isblank (valstr[grouplen]))
+	    {
+	      const char *cp = &valstr[grouplen + 1];
+	      while (isblank (*cp))
+		++cp;
+	      if (*cp != '\0')
+		{
+		  result->data = strdup (cp);
+		  if (result->data == NULL)
+		    status = NSS_STATUS_TRYAGAIN;
+		  else
+		    {
+		      status = NSS_STATUS_SUCCESS;
+		      result->cursor = result->data;
+		    }
+		  break;
+		}
+	    }
+
+	  if ((hidx += hval2) >= header->dbs[0].hashsize)
+	    hidx -= header->dbs[0].hashsize;
+	}
+
+      internal_endent (&state);
     }
 
-  __libc_lock_unlock (lock);
-
   return status;
 
 }
 
 
 enum nss_status
-_nss_db_endnetgrent (void)
+_nss_db_endnetgrent (struct __netgrent *result)
 {
-  __libc_lock_lock (lock);
-
-  internal_endent (&db);
-
-  __libc_lock_unlock (lock);
-
+  free (result->data);
+  result->data = NULL;
+  result->data_size = 0;
+  result->cursor = NULL;
   return NSS_STATUS_SUCCESS;
 }
 
@@ -91,13 +112,10 @@ enum nss_status
 _nss_db_getnetgrent_r (struct __netgrent *result, char *buffer, size_t buflen,
 		       int *errnop)
 {
-  int status;
-
-  __libc_lock_lock (lock);
-
-  status = _nss_netgroup_parseline (&cursor, result, buffer, buflen, errnop);
+  enum nss_status status;
 
-  __libc_lock_unlock (lock);
+  status = _nss_netgroup_parseline (&result->cursor, result, buffer, buflen,
+				    errnop);
 
   return status;
 }
diff --git a/nss/nss_db/db-open.c b/nss/nss_db/db-open.c
index 94dfe5b..36ce494 100644
--- a/nss/nss_db/db-open.c
+++ b/nss/nss_db/db-open.c
@@ -1,5 +1,5 @@
 /* Common database routines for nss_db.
-   Copyright (C) 2000 Free Software Foundation, Inc.
+   Copyright (C) 2000, 2011 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -22,368 +22,51 @@
 #include <dlfcn.h>
 #include <stdlib.h>
 #include <string.h>
-#include <bits/libc-lock.h>
+#include <sys/mman.h>
+#include <not-cancel.h>
 
-#include "dummy-db.h"
+#include <kernel-features.h>
 #include "nss_db.h"
 
-/* This file contains the functions used to open and close the databases
-   read by the rest of libnss_db.  Not all of them are thread safe;
-   make sure the caller does the appropriate locking.
-
-   We dynamically load the database library, so that it does not have
-   to be present when glibc is compiled.  Once loaded, the database
-   library is never never unloaded again until the libnss_db module is
-   unloaded (from the free_mem routine in nsswitch.c) -- we catch the
-   unload by providing a shlib destructor.  (XXX Does that actually
-   work?)  */
-
-/* Handle for the shared Berkeley DB library.  If non-null, the
-   database library is completely loaded and ready to be used by
-   multithreaded code.  */
-static void *libdb_handle;
-
-/* The version of the Berkeley DB library we are using.  */
-enum {
-  nodb,
-  db24,
-  db27,
-  db30
-} libdb_version;
-
-/* Pointer to the db_open function.  For use with DB 2.x.  */
-static int (*libdb_db_open) (const char *, int,
-			     uint32_t, int, void *, void *, void **);
-
-/* Pointer to the db_create function.  For use with DB 3.x.  */
-static int (*libdb_db_create) (void *, void *, uint32_t);
-
-/* Constants which vary from version to version are actually variables
-   here.  */
-int db_first;
-int db_next;
-int db_nooverwrite;
-int db_truncate;
-int db_rdonly;
-/* Variables which keep track of the error values.  */
-int db_keyexist;
-int db_notfound;
-
-/* Locks the static variables in this file.  */
-__libc_lock_define_initialized (static, lock)
-
-/* Dynamically load the database library.  Return zero if successful,
-   non-zero if no suitable version of the library could be loaded.
-   Must be called with the above lock held if it might run in a
-   multithreaded context.
-
-   We try currently:
-   - libdb.so.3: the name used by glibc 2.1
-   - libdb-3.0.so: the name used by db-3.0.x
-   and maybe others in the future.  */
-
+/* Open the database stored in FILE.  If succesful, store either a
+   pointer to the mapped file or a file handle for the file in H and
+   return NSS_STATUS_SUCCESS.  On failure, return the appropriate
+   lookup status.  */
 enum nss_status
-load_db (void)
-{
-  static const char *libnames[] = { "libdb.so.3", "libdb-3.0.so" };
-  int x;
-
-  for (x = 0; x < sizeof (libnames) / sizeof (libnames[0]); ++x)
-    {
-      libdb_handle = dlopen (libnames[x], RTLD_LAZY);
-      if (libdb_handle == NULL)
-	continue;
-
-      /* DB 3.0 has db_create instead of db_open.  */
-      libdb_db_create = dlsym (libdb_handle, "db_create");
-
-      if (libdb_db_create == NULL)
-	/* DB 2.x uses db_open.  */
-	libdb_db_open = dlsym (libdb_handle, "db_open");
-
-      if (libdb_db_open != NULL || libdb_db_create != NULL)
-	{
-	  /* Alright, we got a library.  Now find out which version it is.  */
-	  const char *(*db_version) (int *, int *, int *);
-
-	  db_version = dlsym (libdb_handle, "db_version");
-	  if (db_version != NULL)
-	    {
-	      /* Call the function and get the information.  */
-	      int major, minor, subminor;
-
-	      DL_CALL_FCT (db_version, (&major, &minor, &subminor));
-	      switch (major)
-		{
-		case 2:
-		  /* Sanity check: Do we have db_open?  */
-		  if (libdb_db_open != NULL)
-		    {
-		      if (minor < 6 || (minor == 6 && subminor < 4))
-			{
-			  libdb_version = db24;
-			  db_first = DB24_FIRST;
-			  db_next = DB24_NEXT;
-			  db_nooverwrite = DB24_NOOVERWRITE;
-			  db_truncate = DB24_TRUNCATE;
-			}
-		      else
-			{
-			  libdb_version = db27;
-			  db_first = DB27_FIRST;
-			  db_next = DB27_NEXT;
-			  db_nooverwrite = DB27_NOOVERWRITE;
-			  db_truncate = DB27_TRUNCATE;
-			}
-		      db_keyexist = DB2x_KEYEXIST;
-		      db_notfound = DB2x_NOTFOUND;
-		      db_rdonly = DB2x_RDONLY;
-		    }
-		  break;
-
-		case 3:
-		  /* Sanity check: Do we have db_create?  */
-		  if (libdb_db_create != NULL)
-		    {
-		      libdb_version = db30;
-		      db_first = DB30_FIRST;
-		      db_next = DB30_NEXT;
-		      db_keyexist = DB30_KEYEXIST;
-		      db_notfound = DB30_NOTFOUND;
-		      db_rdonly = DB30_RDONLY;
-		    }
-		  break;
-
-		default:
-		  break;
-		}
-	    }
-
-	  if (libdb_version != nodb)
-	    return NSS_STATUS_SUCCESS;
-
-	  /* Clear variables.  */
-	  libdb_db_open = NULL;
-	  libdb_db_create = NULL;
-	}
-
-      dlclose (libdb_handle);
-    }
-
-  (void) dlerror ();
-  return NSS_STATUS_UNAVAIL;
-}
-
-/* Set the `FD_CLOEXEC' flag of FD.  Return 0 on success, or -1 on
-   error with `errno' set. */
-static int
-set_cloexec_flag (int fd)
+internal_setent (const char *file, struct nss_db_map *mapping)
 {
-  int oldflags = fcntl (fd, F_GETFD, 0);
-
-  if (oldflags < 0)
-    return oldflags;
-
-  oldflags |= FD_CLOEXEC;
-
-  return fcntl (fd, F_SETFD, oldflags);
-}
-
-/* Make sure we don't use the library anymore once we are shutting down.  */
-static void __attribute__ ((destructor))
-unload_db (void)
-{
-  if (libdb_handle != NULL)
+  enum nss_status status = NSS_STATUS_UNAVAIL;
+
+  int mode = O_RDONLY | O_LARGEFILE;
+#ifdef O_CLOEXEC
+  mode |= O_CLOEXEC;
+#endif
+  int fd = open_not_cancel_2 (file, mode);
+  if (fd != -1)
     {
-      libdb_db_open = NULL;
-      libdb_db_create = NULL;
-      libdb_version = nodb;
-      dlclose (libdb_handle);
-    }
-}
-
-/* Open the database stored in FILE.  If succesful, store the database
-   handle in *DBP and return NSS_STATUS_SUCCESS.  On failure, return
-   the appropriate lookup status.  */
-enum nss_status
-internal_setent (const char *file, NSS_DB **dbp)
-{
-  enum nss_status status = NSS_STATUS_SUCCESS;
+      struct nss_db_header header;
 
-  if (*dbp == NULL)
-    {
-      if (libdb_db_open == NULL && libdb_db_create == NULL)
+      if (read (fd, &header, sizeof (header)) == sizeof (header))
 	{
-	  __libc_lock_lock (lock);
-
-	  if (libdb_db_open == NULL && libdb_db_create == NULL)
-	    status = load_db ();
-
-	  __libc_lock_unlock (lock);
+	  mapping->header = mmap (NULL, header.allocate, PROT_READ,
+				  MAP_PRIVATE, fd, 0);
+	  mapping->len = header.allocate;
+	  if (mapping->header != MAP_FAILED)
+	    status = NSS_STATUS_SUCCESS;
+	  else if (errno == ENOMEM)
+	    status = NSS_STATUS_TRYAGAIN;
 	}
 
-      if (status == NSS_STATUS_SUCCESS)
-	status = dbopen (file, db_rdonly, 0, dbp);
+      close_not_cancel_no_status (fd);
     }
 
   return status;
 }
 
 
-/* Close the database *DBP.  */
+/* Close the database.  */
 void
-internal_endent (NSS_DB **dbp)
-{
-  NSS_DB *db = *dbp;
-
-  if (db != NULL)
-    {
-      DL_CALL_FCT (db->close, (db->db, 0));
-      *dbp = NULL;
-    }
-}
-
-/* Allocate a cursor for database DB and transaction TXN.  On success,
-   store the cursor in *DBCP and return zero.  Otherwise return an
-   error value.  */
-int
-db_cursor (void *db, void *txn, NSS_DBC **dbcp)
-{
-  NSS_DBC *dbc;
-  int ret;
-
-  dbc = (NSS_DBC *) malloc (sizeof (NSS_DBC));
-  if (dbc == NULL)
-    return ENOMEM;
-
-  switch (libdb_version)
-    {
-    case db24:
-      ret = ((struct db24 *) db)->cursor (db, txn, &dbc->cursor);
-
-      if (ret == 0)
-	dbc->c_get = ((struct dbc24 *) dbc->cursor)->c_get;
-      break;
-
-    case db27:
-      ret = ((struct db27 *) db)->cursor (db, txn, &dbc->cursor, 0);
-
-      if (ret == 0)
-	dbc->c_get = ((struct dbc27 *) dbc->cursor)->c_get;
-      break;
-
-    case db30:
-      ret = ((struct db30 *) db)->cursor (db, txn, &dbc->cursor, 0);
-
-      if (ret == 0)
-	dbc->c_get = ((struct dbc30 *) dbc->cursor)->c_get;
-      break;
-
-    default:
-      abort ();
-    }
-
-  if (ret != 0)
-    {
-      free (dbc);
-      return ret;
-    }
-
-  *dbcp = dbc;
-
-  return 0;
-}
-
-
-/* Open the database in FNAME, for access specified by FLAGS.  If
-   opening the database causes the file FNAME to be created, it is
-   created with MODE.  If succesful, store the database handle in *DBP
-   and return NSS_STATUS_SUCCESS.  On failure, return the appropriate
-   lookup status.  */
-int
-dbopen (const char *fname, int oper, int mode, NSS_DB **dbp)
+internal_endent (struct nss_db_map *mapping)
 {
-  int err;
-  int fd;
-  NSS_DB *db;
-
-  /* Construct the object we pass up.  */
-  db = (NSS_DB *) calloc (1, sizeof (NSS_DB));
-  if (db == NULL)
-    return NSS_STATUS_UNAVAIL;
-
-  /* Initialize the object.  */
-  db->cursor = db_cursor;
-
-  /* Actually open the database.  */
-  switch (libdb_version)
-    {
-    case db24:
-    case db27:
-      err = DL_CALL_FCT (libdb_db_open,
-			 (fname, DB_BTREE, oper, mode, NULL, NULL, &db->db));
-      if (err != 0)
-	goto fail;
-
-      if (libdb_version)
-	{
-	  db->close = ((struct db24 *) db->db)->close;
-	  db->fd = ((struct db24 *) db->db)->fd;
-	  db->get = ((struct db24 *) db->db)->get;
-	  db->put = ((struct db24 *) db->db)->put;
-	}
-      else
-	{
-	  db->close = ((struct db27 *) db->db)->close;
-	  db->fd = ((struct db27 *) db->db)->fd;
-	  db->get = ((struct db27 *) db->db)->get;
-	  db->put = ((struct db27 *) db->db)->put;
-	}
-      break;
-
-    case db30:
-      err = DL_CALL_FCT (libdb_db_create, (db->db, NULL, 0));
-      if (err != 0)
-	goto fail;
-
-      db->close = ((struct db30 *) db->db)->close;
-      db->fd = ((struct db30 *) db->db)->fd;
-      db->get = ((struct db30 *) db->db)->get;
-      db->put = ((struct db30 *) db->db)->put;
-
-      err = ((struct db30 *) db->db)->open (db->db, fname, NULL, DB_BTREE,
-					    oper, mode);
-      if (err != 0)
-	goto fail;
-      break;
-
-    default:
-      abort ();
-    }
-
-  /* We have to make sure the file is `closed on exec'.  */
-  err = DL_CALL_FCT (db->fd, (db->db, &fd));
-  if (err != 0)
-    goto fail;
-  if (set_cloexec_flag (fd) < 0)
-    goto fail;
-
-  *dbp = db;
-
-  return NSS_STATUS_UNAVAIL;
-
- fail:
-  /* Something went wrong.  Close the database if necessary.  */
-  if (db)
-    {
-      if (db->db && db->close)
-	DL_CALL_FCT (db->close, (db->db, 0));
-      free (db);
-    }
-
-  /* Make sure `errno' is set.  */
-  if (err)
-    __set_errno (err);
-
-  return err == EAGAIN ? NSS_STATUS_TRYAGAIN : NSS_STATUS_UNAVAIL;
+  munmap (mapping->header, mapping->len);
 }
diff --git a/nss/nss_db/dummy-db.h b/nss/nss_db/dummy-db.h
deleted file mode 100644
index c96bbd9..0000000
--- a/nss/nss_db/dummy-db.h
+++ /dev/null
@@ -1,333 +0,0 @@
-/* Constants and structures from the various Berkeley DB releases.
-   Copyright (C) 1999, 2000 Free Software Foundation, Inc.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, write to the Free
-   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
-   02111-1307 USA.  */
-
-#include <stdint.h>
-
-#include "nss_db.h"
-
-/* This file contains dummy definitions for various constants and
-   structures from the Berkeley release.  We only provide those
-   definitions that are actually needed.  In case of the structures,
-   we're only interested in the function pointers, since that's the
-   interface to the database.  Unfortunately the structures have been
-   changed several times.  */
-
-/* The value for the btree database type has not been changed (yet?).  */
-#define DB_BTREE	(1)
-
-/* Permission flags for all 2.x releases.  */
-#define DB2x_RDONLY	0x010000
-
-/* The error values for all 2.x releases.  */
-#define DB2x_KEYEXIST	( -3)
-#define DB2x_NOTFOUND	( -7)
-
-/* For all 2.x releases up to 2.6.3 we can use the same definitions.
-   We'll refer to them as 2.4 since that's the version distributed
-   with glibc 2.1.  */
-
-/* Access methods from version 2.4.  */
-#define DB24_FIRST		0x000020
-#define DB24_NEXT		0x000800
-#define DB24_NOOVERWRITE	0x001000
-
-/* Permission flags from version 2.4.  */
-#define DB24_TRUNCATE	0x080000
-
-/* The DB structure from version 2.4.  */
-struct db24
-{
-  void	*mutexp;
-  enum { dummy24 } type;
-  void *dbenv;
-  void *mp_dbenv;
-  void *master;
-  void *internal;
-  void *mp;
-  void *mpf;
-  struct
-  {
-    void *tqh_first;
-    void **tqh_last;
-  } curs_queue;
-  struct {
-    void *lh_first;
-  } handleq;
-  struct {
-    void *le_next;
-    void **le_prev;
-  } links;
-  uint32_t log_fileid;
-  void *txn;
-  uint32_t locker;
-  struct db24_dbt {
-    void *data;
-    uint32_t size;
-    uint32_t ulen;
-    uint32_t dlen;
-    uint32_t doff;
-    uint32_t flags;
-  } lock_dbt;
-  struct{
-    uint32_t pgno;
-    uint8_t fileid[20];
-  } lock;
-  size_t pgsize;
-  void *db_malloc;
-  /* Functions. */
-  int (*close) (void *, uint32_t);
-  int (*cursor) (void *, void *, void **);
-  int (*del) (void *, void *, DBT *, uint32_t);
-  int (*fd) (void *, int *);
-  int (*get) (void *, void *, DBT *, DBT *, uint32_t);
-  int (*put) (void *, void *, DBT *, DBT *, uint32_t);
-  int (*stat) (void *, void *, void *(*)(size_t), uint32_t);
-  int (*sync) (void *, uint32_t);
-  uint32_t flags;
-};
-
-/* The DBC structure for the 2.4 release.  */
-struct dbc24
-{
-  void *dbp;
-  void *txn;
-  struct
-  {
-    void *tqe_next;
-    void **tqe_prev;
-  } links;
-  void *internal;
-  void *c_close;
-  void *c_del;
-  int (*c_get) (void *, DBT *, DBT *, uint32_t);
-  void *c_put;
-};
-
-/* The 2.7 release is slighty different.  */
-
-/* Access methods from version 2.7.  */
-#define DB27_FIRST		7
-#define DB27_NEXT		15
-#define DB27_NOOVERWRITE	17
-
-/* Permission flags from version 2.7.  */
-#define DB27_TRUNCATE	0x020000
-
-/* The DB structure from version 2.7.  */
-struct db27
-{
-  void	*mutexp;
-  enum { dummy27 } type;
-  int byteswapped;
-  int saved_open_fd;
-  void *dbenv;
-  void *mp_dbenv;
-  void *internal;
-  void *mp;
-  void *mpf;
-  struct
-  {
-    void *tqh_first;
-    void **tqh_last;
-  } free_queue;
-  struct
-  {
-    void *tqh_first;
-    void **tqh_last;
-  } active_queue;
-  uint8_t fileid[20];
-  uint32_t log_fileid;
-  size_t pgsize;
-  void *db_malloc;
-  void *dup_compare;
-  void *h_hash;
-  /* Functions. */
-  int (*am_close) (void *);
-  int (*close) (void *, uint32_t);
-  int (*cursor) (void *, void *, void **, uint32_t);
-  int (*del) (void *, void *, DBT *, uint32_t);
-  int (*fd) (void *, int *);
-  int (*get) (void *, void *, DBT *, DBT *, uint32_t);
-  int (*join) (void *, void **, uint32_t, void **);
-  int (*put) (void *, void *, DBT *, DBT *, uint32_t);
-  int (*stat) (void *, void *, void *(*)(size_t), uint32_t);
-  int (*sync) (void *, uint32_t);
-  uint32_t flags;
-};
-
-/* The DBC structure for version 2.7.  */
-struct dbc27
-{
-  void *dbp;
-  void *txn;
-  struct
-  {
-    void *tqe_next;
-    void **tqe_prev;
-  } links;
-  uint32_t lid;
-  uint32_t locker;
-  DBT lock_dbt;
-  struct{
-    uint32_t pgno;
-    uint8_t fileid[20];
-  } lock;
-  size_t mylock;
-  DBT rkey;
-  DBT rdata;
-  void *c_am_close;
-  void *c_am_destroy;
-  void *c_close;
-  void *c_del;
-  int (*c_get) (void *, DBT *, DBT *, uint32_t);
-  void *c_put;
-  void *internal;
-  uint32_t flags;
-};
-
-/* Version 3.0 is mostly incompatible with 2.x.  */
-
-/* Access methods from version 3.0.  */
-#define DB30_FIRST		9
-#define DB30_NEXT		17
-#define DB30_NOOVERWRITE	20
-
-/* Error values from version 3.0.  */
-#define DB30_KEYEXIST	(-30997)
-#define DB30_NOTFOUND	(-30994)
-
-/* Permission flags from version 3.0.  */
-#define DB30_RDONLY	0x000010
-#define DB30_TRUNCATE	0x020000
-
-/* The DB structure from version 3.0.  */
-struct db30
-{
-  size_t pgsize;
-  void (*db_feedback) (void *, int, int);
-  void *(*db_malloc) (size_t);
-  void *(*db_realloc) (void *, size_t);
-  int (*dup_compare) (const DBT *, const DBT *);
-  void *dbenv;
-  enum { dummy30 } type;
-  void *mpf;
-  void	*mutexp;
-  u_int8_t fileid[20];
-  int32_t log_fileid;
-  void *open_txn;
-  void *saved_open_fhp;
-  struct
-  {
-    void *tqh_first;
-    void **tqh_last;
-  } free_queue;
-  struct
-  {
-    void *tqh_first;
-    void **tqh_last;
-  } active_queue;
-  void	*bt_internal;
-  void	*cj_internal;
-  void	*h_internal;
-  void	*q_internal;
-  void	*xa_internal;
-  /* Functions.  */
-  int  (*close) (void *, uint32_t);
-  int  (*cursor) (void *, void *, void **, uint32_t);
-  int  (*del) (void *, void *, DBT *, uint32_t);
-  void (*err) (void *, int, const char *, ...);
-  void (*errx) (void *, const char *, ...);
-  int  (*fd) (void *, int *);
-  int  (*get) (void *, void *, DBT *, DBT *, uint32_t);
-  int  (*get_byteswapped) (void *);
-  int (*get_type) (void *);
-  int  (*join) (void *, void **, void **, uint32_t);
-  int  (*open) (void *,	const char *, const char *, int, uint32_t, int);
-  int  (*put) (void *, void *, DBT *, DBT *, uint32_t);
-  int  (*remove) (void *, const char *, const char *, uint32_t);
-  int  (*set_cachesize) (void *, uint32_t, uint32_t, int);
-  int  (*set_dup_compare) (void *, int (*)(const DBT *, const DBT *));
-  void (*set_errcall) (void *, void (*)(const char *, char *));
-  void (*set_errfile) (void *, void *);
-  void (*set_errpfx) (void *, const char *);
-  void (*set_feedback) (void *, void (*)(void *, int, int));
-  int  (*set_flags) (void *, uint32_t);
-  int  (*set_lorder) (void *, int);
-  int  (*set_malloc) (void *, void *(*)(size_t));
-  int  (*set_pagesize) (void *, uint32_t);
-  void (*set_paniccall) (void *, void (*)(void *, int));
-  int  (*set_realloc) (void *, void *(*)(void *, size_t));
-  int  (*stat) (void *, void *, void *(*)(size_t), uint32_t);
-  int  (*sync) (void *, uint32_t);
-  int  (*upgrade) (void *, const char *, uint32_t);
-
-  int  (*set_bt_compare) (void *, int (*)(const DBT *, const DBT *));
-  int  (*set_bt_maxkey) (void *, uint32_t);
-  int  (*set_bt_minkey) (void *, uint32_t);
-  int  (*set_bt_prefix) (void *, size_t (*)(const DBT *, const DBT *));
-
-  int  (*set_h_ffactor) (void *, uint32_t);
-  int  (*set_h_hash) (void *, uint32_t (*)(const void *, uint32_t));
-  int  (*set_h_nelem) (void *, uint32_t);
-
-  int  (*set_re_delim) (void *, int);
-  int  (*set_re_len) (void *, uint32_t);
-  int  (*set_re_pad) (void *, int);
-  int  (*set_re_source) (void *, const char *);
-
-  uint32_t am_ok;
-  uint32_t flags;
-};
-
-/* The DBC structure from version 3.0.  */
-struct dbc30
-{
-  void *dbp;
-  void *txn;
-  struct
-  {
-    void *tqe_next;
-    void **tqe_prev;
-  } links;
-  uint32_t lid;			/* Default process' locker id. */
-  uint32_t locker;		/* Locker for this operation. */
-  DBT lock_dbt;		/* DBT referencing lock. */
-  struct
-  {
-    uint32_t pgno;
-    uint8_t fileid[20];
-  } lock;
-  struct
-  {
-    size_t off;
-    uint32_t ndx;
-    uint32_t gen;
-  } mylock;
-  DBT rkey;
-  DBT rdata;
-  int (*c_close) (void *);
-  int (*c_del) (void *, uint32_t);
-  int (*c_dup) (void *, void **, uint32_t);
-  int (*c_get) (void *, DBT *, DBT *, uint32_t);
-  int (*c_put) (void *, DBT *, DBT *, uint32_t);
-  int (*c_am_close) (void *);
-  int (*c_am_destroy) (void *);
-  void *internal;
-  uint32_t flags;
-};
diff --git a/nss/nss_db/nss_db.h b/nss/nss_db/nss_db.h
index 0edc9b6..a965ae3 100644
--- a/nss/nss_db/nss_db.h
+++ b/nss/nss_db/nss_db.h
@@ -1,5 +1,5 @@
 /* Common database open/close routines for nss_db.
-   Copyright (C) 1999, 2000 Free Software Foundation, Inc.
+   Copyright (C) 1999, 2000, 2011 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -22,73 +22,49 @@
 
 #include <nss.h>
 #include <stdint.h>
+#include <bits/libc-lock.h>
 
-/* Variables which keep track of the error values.  */
-extern int db_keyexist;
-extern int db_notfound;
 
-/* This flag is the same for all versions of the Berkeley DB library.  */
-#define DB_CREATE	0x000001
+/* String table index type.  */
+typedef uint32_t stridx_t;
 
-/* But constants which vary from version to version are actually
-   variables here.  */
-extern int db_first;
-extern int db_next;
-extern int db_nooverwrite;
-extern int db_truncate;
-extern int db_rdonly;
-
-/* The `DBT' type is the same in all versions we support.  */
-typedef struct
+/* Database file header.  */
+struct nss_db_header
 {
-  void *data;
-  uint32_t size;
-  uint32_t ulen;
-  uint32_t dlen;
-  uint32_t doff;
-  uint32_t flags;
-} DBT;
-
-/* But the cursor object is very different from version to version.  */
-typedef struct
+  uint32_t magic;
+#define NSS_DB_MAGIC 0xdd110601
+  uint32_t ndbs;
+  uint64_t valstroffset;
+  uint64_t valstrlen;
+  uint64_t allocate;
+  struct
+  {
+    char id;
+    char pad[sizeof (uint32_t) - 1];
+    uint32_t hashsize;
+    uint64_t hashoffset;
+    uint64_t keyidxoffset;
+    uint64_t keystroffset;
+  } dbs[0];
+};
+
+
+/* Information about mapped database.  */
+struct nss_db_map
 {
-  void *cursor;
-  int (*c_get) (void *, DBT *, DBT *, uint32_t);
-} NSS_DBC;
+  struct nss_db_header *header;
+  size_t len;
+};
 
-/* We need a helper function for it.  */
-extern int db_cursor (void *db, void *txn, NSS_DBC **dbcp);
-
-/* This is the wrapper we put around the `DB' structures to provide a
-   uniform interface to the higher-level functions.  */
-typedef struct
-{
-  void *db;
-  int (*close) (void *, uint32_t);
-  int (*cursor) (void *, void *, NSS_DBC **);
-  int (*fd) (void *, int *);
-  int (*get) (void *, void *, DBT *, DBT *, uint32_t);
-  int (*put) (void *, void *, DBT *, DBT *, uint32_t);
-} NSS_DB;
 
 /* Open the database stored in FILE.  If succesful, store the database
-   handle in *DBP and return NSS_STATUS_SUCCESS.  On failure, return
-   the appropriate lookup status.  */
-extern enum nss_status internal_setent (const char *file, NSS_DB **dbp);
-
-/* Close the database *DBP.  */
-extern void internal_endent (NSS_DB **dbp);
-
-/* Dynamically load the Berkeley DB library.  Return zero if
-   successful, non-zero if no suitable version of the library could be
-   loaded.  */
-extern enum nss_status load_db (void);
-
-/* Open the database in FNAME, for access specified by FLAGS.  If
-   opening the database causes the file FNAME to be created, it is
-   created with MODE.  If succesful, store the database handle in *DBP
-   and return NSS_STATUS_SUCCESS.  On failure, return the appropriate
+   handle in *MAPPINGP or a file descriptor for the file in *FDP and
+   return NSS_STATUS_SUCCESS.  On failure, return the appropriate
    lookup status.  */
-extern int dbopen (const char *fname, int oper, int mode, NSS_DB **dbp);
+enum nss_status internal_setent (const char *file,
+				 struct nss_db_map *mappingp);
+
+/* Close the database FD.  */
+extern void internal_endent (struct nss_db_map *mapping);
 
 #endif	/* nss_db.h */
diff --git a/nss/nss_files/files-XXX.c b/nss/nss_files/files-XXX.c
index 852b58a..1a6fa0d 100644
--- a/nss/nss_files/files-XXX.c
+++ b/nss/nss_files/files-XXX.c
@@ -1,5 +1,5 @@
 /* Common code for file-based databases in nss_files module.
-   Copyright (C) 1996-1999,2001,2002,2004,2007,2008
+   Copyright (C) 1996-1999,2001,2002,2004,2007,2008,2011
    Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
@@ -306,15 +306,15 @@ CONCAT(_nss_files_get,ENTNAME_r) (struct STRUCTURE *result, char *buffer,
 
    NAME is the name of the lookup; e.g. `hostbyname'.
 
-   KEYSIZE and KEYPATTERN are ignored here but used by ../nss_db/db-XXX.c.
+   DB_CHAR, KEYPATTERN, KEYSIZE are ignored here but used by db-XXX.c
+   e.g. `1 + sizeof (id) * 4'.
 
-   PROTO describes the arguments for the lookup key;
-   e.g. `const char *hostname'.
+   PROTO is the potentially empty list of other parameters.
 
    BREAK_IF_MATCH is a block of code which compares `struct STRUCTURE *result'
    to the lookup key arguments and does `break;' if they match.  */
 
-#define DB_LOOKUP(name, keysize, keypattern, break_if_match, proto...)	      \
+#define DB_LOOKUP(name, db_char, keysize, keypattern, break_if_match, proto...)\
 enum nss_status								      \
 _nss_files_get##name##_r (proto,					      \
 			  struct STRUCTURE *result, char *buffer,	      \
diff --git a/nss/nss_files/files-ethers.c b/nss/nss_files/files-ethers.c
index e662c1a..91363ba 100644
--- a/nss/nss_files/files-ethers.c
+++ b/nss/nss_files/files-ethers.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1996, 1997, 2000 Free Software Foundation, Inc.
+/* Copyright (C) 1996, 1997, 2000, 2011 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -51,13 +51,13 @@ LINE_PARSER
 
 #include GENERIC
 
-DB_LOOKUP (hostton, 1 + strlen (name), (".%s", name),
+DB_LOOKUP (hostton, '.', 0, ("%s", name),
 	   {
 	     if (__strcasecmp (result->e_name, name) == 0)
 	       break;
 	   }, const char *name)
 
-DB_LOOKUP (ntohost, 18, ("=%x:%x:%x:%x:%x:%x",
+DB_LOOKUP (ntohost, '=', 18, ("%x:%x:%x:%x:%x:%x",
 			 addr->ether_addr_octet[0], addr->ether_addr_octet[1],
 			 addr->ether_addr_octet[2], addr->ether_addr_octet[3],
 			 addr->ether_addr_octet[4], addr->ether_addr_octet[5]),
diff --git a/nss/nss_files/files-grp.c b/nss/nss_files/files-grp.c
index 1f205c1..30751ab 100644
--- a/nss/nss_files/files-grp.c
+++ b/nss/nss_files/files-grp.c
@@ -1,5 +1,5 @@
 /* Group file parser in nss_files module.
-   Copyright (C) 1996, 1997 Free Software Foundation, Inc.
+   Copyright (C) 1996, 1997, 2011 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -30,14 +30,14 @@ struct grent_data {};
 #include "files-parse.c"
 #include GENERIC
 
-DB_LOOKUP (grnam, 1 + strlen (name), (".%s", name),
+DB_LOOKUP (grnam, '.', 0, ("%s", name),
 	   {
 	     if (name[0] != '-' && name[0] != '+'
 		 && ! strcmp (name, result->gr_name))
 	       break;
 	   }, const char *name)
 
-DB_LOOKUP (grgid, 20, ("=%lu", (unsigned long int) gid),
+DB_LOOKUP (grgid, '=', 20, ("%lu", (unsigned long int) gid),
 	   {
 	     if (result->gr_gid == gid && result->gr_name[0] != '+'
 		 && result->gr_name[0] != '-')
diff --git a/nss/nss_files/files-hosts.c b/nss/nss_files/files-hosts.c
index 83de650..f6f960e 100644
--- a/nss/nss_files/files-hosts.c
+++ b/nss/nss_files/files-hosts.c
@@ -358,7 +358,7 @@ HOST_DB_LOOKUP (hostbyname2, ,,
    gethostbyaddr() function is an IPv6 address.  */
 #define EXTRA_ARGS_VALUE \
   , af, (len == IN6ADDRSZ ? AI_V4MAPPED : 0)
-DB_LOOKUP (hostbyaddr, ,,
+DB_LOOKUP (hostbyaddr, ,,,
 	   {
 	     if (result->h_length == (int) len
 		 && ! memcmp (addr, result->h_addr_list[0], len))
diff --git a/nss/nss_files/files-network.c b/nss/nss_files/files-network.c
index 92aea75..9017c54 100644
--- a/nss/nss_files/files-network.c
+++ b/nss/nss_files/files-network.c
@@ -1,5 +1,5 @@
 /* Networks file parser in nss_files module.
-   Copyright (C) 1996-1998, 2000, 2001, 2009 Free Software Foundation, Inc.
+   Copyright (C) 1996-1998, 2000, 2001, 2009, 2011 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -75,11 +75,11 @@ LINE_PARSER
 
 #include "files-XXX.c"
 
-DB_LOOKUP (netbyname, ,,
+DB_LOOKUP (netbyname, ,,,
 	   LOOKUP_NAME_CASE (n_name, n_aliases),
 	   const char *name)
 
-DB_LOOKUP (netbyaddr, ,,
+DB_LOOKUP (netbyaddr, ,,,
 	   {
 	     if ((type == AF_UNSPEC || result->n_addrtype == type)
 		 && result->n_net == net)
diff --git a/nss/nss_files/files-proto.c b/nss/nss_files/files-proto.c
index 0cede6e..5df325b 100644
--- a/nss/nss_files/files-proto.c
+++ b/nss/nss_files/files-proto.c
@@ -1,5 +1,5 @@
 /* Protocols file parser in nss_files module.
-   Copyright (C) 1996, 1997 Free Software Foundation, Inc.
+   Copyright (C) 1996, 1997, 2011 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -36,11 +36,11 @@ LINE_PARSER
 
 #include GENERIC
 
-DB_LOOKUP (protobyname, 1 + strlen (name), (".%s", name),
+DB_LOOKUP (protobyname, '.', 0, ("%s", name),
 	   LOOKUP_NAME (p_name, p_aliases),
 	   const char *name)
 
-DB_LOOKUP (protobynumber, 20, ("=%d", proto),
+DB_LOOKUP (protobynumber, '=', 20, ("%zd", (ssize_t) proto),
 	   {
 	     if (result->p_proto == proto)
 	       break;
diff --git a/nss/nss_files/files-pwd.c b/nss/nss_files/files-pwd.c
index 4913c31..4763f01 100644
--- a/nss/nss_files/files-pwd.c
+++ b/nss/nss_files/files-pwd.c
@@ -1,5 +1,5 @@
 /* User file parser in nss_files module.
-   Copyright (C) 1996, 1997 Free Software Foundation, Inc.
+   Copyright (C) 1996, 1997, 2011 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -30,14 +30,14 @@ struct pwent_data {};
 #include "files-parse.c"
 #include GENERIC
 
-DB_LOOKUP (pwnam, 1 + strlen (name), (".%s", name),
+DB_LOOKUP (pwnam, '.', 0, ("%s", name),
 	   {
 	     if (name[0] != '+' && name[0] != '-'
 		 && ! strcmp (name, result->pw_name))
 	       break;
 	   }, const char *name)
 
-DB_LOOKUP (pwuid, 20, ("=%lu", (unsigned long int) uid),
+DB_LOOKUP (pwuid, '=', 20, ("%lu", (unsigned long int) uid),
 	   {
 	     if (result->pw_uid == uid && result->pw_name[0] != '+'
 		 && result->pw_name[0] != '-')
diff --git a/nss/nss_files/files-rpc.c b/nss/nss_files/files-rpc.c
index b99ede3..2b41611 100644
--- a/nss/nss_files/files-rpc.c
+++ b/nss/nss_files/files-rpc.c
@@ -1,5 +1,5 @@
 /* SunRPC program number file parser in nss_files module.
-   Copyright (C) 1996, 1997 Free Software Foundation, Inc.
+   Copyright (C) 1996, 1997, 2011 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -36,11 +36,11 @@ LINE_PARSER
 
 #include GENERIC
 
-DB_LOOKUP (rpcbyname, 1 + strlen (name), (".%s", name),
+DB_LOOKUP (rpcbyname, '.', 0, ("%s", name),
 	   LOOKUP_NAME (r_name, r_aliases),
 	   const char *name)
 
-DB_LOOKUP (rpcbynumber, 20, ("=%d", number),
+DB_LOOKUP (rpcbynumber, '=', 20, ("%zd", (ssize_t) number),
 	   {
 	     if (result->r_number == number)
 	       break;
diff --git a/nss/nss_files/files-service.c b/nss/nss_files/files-service.c
index 13532dd..6f2b0e6 100644
--- a/nss/nss_files/files-service.c
+++ b/nss/nss_files/files-service.c
@@ -1,5 +1,5 @@
 /* Services file parser in nss_files module.
-   Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
+   Copyright (C) 1996, 1997, 1998, 2011 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -39,8 +39,9 @@ LINE_PARSER
 
 #include GENERIC
 
-DB_LOOKUP (servbyname, 2 + strlen (name) + (proto ? strlen (proto) : 0),
-	   (".%s/%s", name, proto ?: ""),
+DB_LOOKUP (servbyname, ':',
+	   strlen (name) + 2 + (proto == NULL ? 0 : strlen (proto)),
+	   ("%s/%s", name, proto ?: ""),
 	   {
 	     /* Must match both protocol (if specified) and name.  */
 	     if (proto != NULL && strcmp (result->s_proto, proto))
@@ -49,8 +50,8 @@ DB_LOOKUP (servbyname, 2 + strlen (name) + (proto ? strlen (proto) : 0),
 	   },
 	   const char *name, const char *proto)
 
-DB_LOOKUP (servbyport, 21 + (proto ? strlen (proto) : 0),
-	   ("=%d/%s", ntohs (port), proto ?: ""),
+DB_LOOKUP (servbyport, '=', 21 + (proto ? strlen (proto) : 0),
+	   ("%zd/%s", (ssize_t) ntohs (port), proto ?: ""),
 	   {
 	     /* Must match both port and protocol.  */
 	     if (result->s_port == port
diff --git a/nss/nss_files/files-sgrp.c b/nss/nss_files/files-sgrp.c
index 4e12cd8..684bacc 100644
--- a/nss/nss_files/files-sgrp.c
+++ b/nss/nss_files/files-sgrp.c
@@ -1,5 +1,5 @@
 /* User file parser in nss_files module.
-   Copyright (C) 2009 Free Software Foundation, Inc.
+   Copyright (C) 2009, 2011 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -30,7 +30,7 @@ struct sgent_data {};
 #include "files-parse.c"
 #include GENERIC
 
-DB_LOOKUP (sgnam, 1 + strlen (name), (".%s", name),
+DB_LOOKUP (sgnam, '.', 0, ("%s", name),
 	   {
 	     if (name[0] != '+' && name[0] != '-'
 		 && ! strcmp (name, result->sg_namp))
diff --git a/nss/nss_files/files-spwd.c b/nss/nss_files/files-spwd.c
index 1825d36..e227d71 100644
--- a/nss/nss_files/files-spwd.c
+++ b/nss/nss_files/files-spwd.c
@@ -1,5 +1,5 @@
 /* User file parser in nss_files module.
-   Copyright (C) 1996, 1997 Free Software Foundation, Inc.
+   Copyright (C) 1996, 1997, 2011 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -30,7 +30,7 @@ struct spent_data {};
 #include "files-parse.c"
 #include GENERIC
 
-DB_LOOKUP (spnam, 1 + strlen (name), (".%s", name),
+DB_LOOKUP (spnam, '.', 0, ("%s", name),
 	   {
 	     if (name[0] != '+' && name[0] != '-'
 		 && ! strcmp (name, result->sp_namp))
diff --git a/shlib-versions b/shlib-versions
index d3e8407..a7839de 100644
--- a/shlib-versions
+++ b/shlib-versions
@@ -113,6 +113,7 @@ alpha.*-.*-linux.*	libresolv=2.1
 .*-.*-.*		libnss_nisplus=2
 .*-.*-.*		libnss_ldap=2
 .*-.*-.*		libnss_hesiod=2
+.*-.*-.*		libnss_db=2
 
 # Tests for NSS.  They must have the same NSS_SHLIB_REVISION number as
 # the rest.

http://sources.redhat.com/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=9ee76b5ae861ff9891e5586fc6906c94c447a9e0

commit 9ee76b5ae861ff9891e5586fc6906c94c447a9e0
Author: Ulrich Drepper <drepper@gmail.com>
Date:   Thu Jun 2 14:43:16 2011 -0400

    Rewrite makedb to avoid using db library

diff --git a/ChangeLog b/ChangeLog
index b26c6b2..9ce38a8 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2011-06-02  Ulrich Drepper  <drepper@gmail.com>
+
+	* nss/makedb.c: Rewritten to not use database library.
+	* nss/Makefile: Update to build new makedb program.
+
 2011-06-14  Andreas Jaeger  <aj@suse.de>
 
 	* sysdeps/unix/sysv/linux/check_native.c: Include <string.h> for
diff --git a/nss/Makefile b/nss/Makefile
index c49f375..16578a3 100644
--- a/nss/Makefile
+++ b/nss/Makefile
@@ -37,8 +37,10 @@ routines		= nsswitch getnssent getnssent_r digits_dots \
 databases		= proto service hosts network grp pwd rpc ethers \
 			  spwd netgrp key alias sgrp
 
-others                  := getent
-install-bin             := getent
+others                  := getent makedb
+install-bin             := getent makedb
+makedb-modules = xmalloc hash-string
+extra-objs		+= $(makedb-modules:=.o)
 
 tests			= test-netdb tst-nss-test1
 xtests			= bug-erange
@@ -60,7 +62,7 @@ extra-libs-others	= $(extra-libs)
 
 # The sources are found in the appropriate subdir.
 subdir-dirs = $(services:%=nss_%)
-vpath %.c $(subdir-dirs)
+vpath %.c $(subdir-dirs) ../locale/programs ../intl
 
 
 libnss_files-routines	:= $(addprefix files-,$(databases)) \
@@ -80,6 +82,10 @@ ifeq (yes,$(build-static-nss))
 $(objpfx)getent: $(objpfx)libnss_files.a
 endif
 
+ifeq (yes,$(have-selinux))
+LDLIBS-makedb		:= -lselinux
+endif
+
 # Depend on libc.so so a DT_NEEDED is generated in the shared objects.
 # This ensures they will load libc.so for needed symbols if loaded by
 # a statically-linked program that hasn't already loaded it.
@@ -88,6 +94,8 @@ $(services:%=$(objpfx)libnss_%.so): $(libnss-libc) \
 				    $(common-objpfx)libc_nonshared.a
 
 
+$(objpfx)makedb: $(makedb-modules:%=$(objpfx)%.o)
+
 distribute		+= nss_test1.c
 
 CFLAGS-nss_test1.c = -DNOT_IN_libc=1
diff --git a/nss/makedb.c b/nss/makedb.c
index 5390dc1..a01b235 100644
--- a/nss/makedb.c
+++ b/nss/makedb.c
@@ -1,5 +1,5 @@
 /* Create simple DB database from textual input.
-   Copyright (C) 1996, 1997, 1998, 1999, 2000 Free Software Foundation, Inc.
+   Copyright (C) 1996-2000, 2011 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
 
@@ -19,25 +19,115 @@
    02111-1307 USA.  */
 
 #include <argp.h>
+#include <assert.h>
 #include <ctype.h>
-#include <dlfcn.h>
 #include <errno.h>
 #include <error.h>
 #include <fcntl.h>
+#include <inttypes.h>
 #include <libintl.h>
 #include <locale.h>
+#include <search.h>
 #include <stdio.h>
-#include <stdint.h>
 #include <stdlib.h>
 #include <string.h>
+#include <unistd.h>
+#include <sys/mman.h>
 #include <sys/stat.h>
 #include "nss_db/dummy-db.h"
 
 /* Get libc version number.  */
 #include "../version.h"
 
+/* The hashing function we use.  */
+#include "../intl/hash-string.h"
+
+/* SELinux support.  */
+#ifdef HAVE_SELINUX
+# include <selinux/selinux.h>
+#endif
+
 #define PACKAGE _libc_intl_domainname
 
+/* String table index type.  */
+typedef uint32_t stridx_t;
+
+/* Database file header.  */
+struct nss_db_header
+{
+  uint32_t magic;
+#define NSS_DB_MAGIC 0xdd110601
+  uint32_t ndbs;
+  uint64_t valstroffset;
+  uint64_t valstrlen;
+  struct
+  {
+    char id;
+    enum nss_db_type { nss_db_type_hash = 0,
+		       nss_db_type_iterate,
+		       nss_db_type_int4 } type:8;
+    char pad[sizeof (uint32_t) - 2];
+    uint32_t hashsize;
+    uint64_t hashoffset;
+    uint64_t stroffset;
+  } dbs[0];
+};
+
+struct nss_db_entry
+{
+  stridx_t keyidx;
+  stridx_t dataidx;
+};
+
+
+/* List of data bases.  */
+struct database
+{
+  char dbid;
+  enum nss_db_type type;
+  struct database *next;
+  void *entries;
+  size_t nentries;
+  size_t keystrlen;
+  size_t nhashentries;
+  struct nss_db_entry *hashtable;
+  char *keystrtab;
+} *databases;
+static size_t ndatabases;
+static size_t valstrlen;
+static void *valstrtree;
+static char *valstrtab;
+
+/* Database entry.  */
+struct dbentry
+{
+  size_t keylen;
+  stridx_t validx;
+  uint32_t hashval;
+  char str[0];
+};
+
+/* Stored string entry.  */
+struct valstrentry
+{
+  stridx_t idx;
+  char str[0];
+};
+
+
+/* Database type specifiers.  */
+struct dbtype
+{
+  char dbid;
+  enum nss_db_type type;
+  struct dbtype *next;
+};
+static struct dbtype *dbtypes;
+
+
+/* True if any entry has been added.  */
+static bool any_dbentry;
+
 /* If non-zero convert key to lower case.  */
 static int to_lowercase;
 
@@ -63,11 +153,16 @@ static const struct argp_option options[] =
     N_("Do not print messages while building database") },
   { "undo", 'u', NULL, 0,
     N_("Print content of database file, one entry a line") },
+  { NULL, 0, NULL, 0, N_("Select index type") },
+  { "iterate", 'I', "KEY", 0,
+    N_("Index identified by KEY used to iterate over database") },
+  { "binary", 'B', "KEY", 0,
+    N_("Index identified by KEY has binary key value") },
   { NULL, 0, NULL, 0, NULL }
 };
 
 /* Short description of program.  */
-static const char doc[] = N_("Create simple DB database from textual input.");
+static const char doc[] = N_("Create simple database from textual input.");
 
 /* Strings for arguments in help texts.  */
 static const char args_doc[] = N_("\
@@ -87,9 +182,26 @@ static struct argp argp =
 
 
 /* Prototypes for local functions.  */
-static int process_input (FILE *input, const char *inname, NSS_DB *output,
+static int process_input (FILE *input, const char *inname,
 			  int to_lowercase, int be_quiet);
-static int print_database (NSS_DB *db);
+static int print_database (int fd);
+static void compute_tables (void);
+static int write_output (int fd);
+
+/* SELinux support.  */
+#ifdef HAVE_SELINUX
+/* Set the SELinux file creation context for the given file. */
+static void set_file_creation_context (const char *outname, mode_t mode);
+static void reset_file_creation_context (void);
+#else
+# define set_file_creation_context(_outname,_mode)
+# define reset_file_creation_context()
+#endif
+
+
+/* External functions.  */
+extern void *xmalloc (size_t n) __attribute_malloc__;
+extern void *xcalloc (size_t n, size_t m) __attribute_malloc__;
 
 
 int
@@ -97,8 +209,6 @@ main (int argc, char *argv[])
 {
   const char *input_name;
   FILE *input_file;
-  NSS_DB *db_file;
-  int status;
   int remaining;
   int mode = 0666;
 
@@ -136,24 +246,17 @@ main (int argc, char *argv[])
       output_name = argv[remaining];
     }
 
-  /* First load the shared object to initialize version dependend
-     variables.  */
-  if (load_db () != NSS_STATUS_SUCCESS)
-    error (EXIT_FAILURE, 0, gettext ("No usable database library found."));
-
   /* Special handling if we are asked to print the database.  */
   if (do_undo)
     {
-      dbopen (input_name, db_rdonly, 0666, &db_file);
-      if (db_file == NULL)
-	error (EXIT_FAILURE, 0, gettext ("cannot open database file `%s': %s"),
-	       input_name,
-	       (errno == EINVAL ? gettext ("incorrectly formatted file")
-		: strerror (errno)));
+      int fd = open (input_name, O_RDONLY);
+      if (fd == -1)
+	error (EXIT_FAILURE, errno, gettext ("cannot open database file `%s'"),
+	       input_name);
 
-      status = print_database (db_file);
+      int status = print_database (fd);
 
-      db_file->close (db_file->db, 0);
+      close (fd);
 
       return status;
     }
@@ -163,34 +266,83 @@ main (int argc, char *argv[])
     input_file = stdin;
   else
     {
-      struct stat st;
+      struct stat64 st;
 
-      input_file = fopen (input_name, "r");
+      input_file = fopen64 (input_name, "r");
       if (input_file == NULL)
 	error (EXIT_FAILURE, errno, gettext ("cannot open input file `%s'"),
 	       input_name);
 
       /* Get the access rights from the source file.  The output file should
 	 have the same.  */
-      if (fstat (fileno (input_file), &st) >= 0)
+      if (fstat64 (fileno (input_file), &st) >= 0)
 	mode = st.st_mode & ACCESSPERMS;
     }
 
-  /* Open output file.  This must not be standard output so we don't
-     handle "-" and "/dev/stdout" special.  */
-  dbopen (output_name, DB_CREATE | db_truncate, mode, &db_file);
-  if (db_file == NULL)
-    error (EXIT_FAILURE, errno, gettext ("cannot open output file `%s'"),
-	   output_name);
-
   /* Start the real work.  */
-  status = process_input (input_file, input_name, db_file, to_lowercase,
-			  be_quiet);
+  int status = process_input (input_file, input_name, to_lowercase, be_quiet);
 
   /* Close files.  */
   if (input_file != stdin)
     fclose (input_file);
-  db_file->close (db_file->db, 0);
+
+  /* No need to continue when we did not read the file successfully.  */
+  if (status != EXIT_SUCCESS)
+    return status;
+
+  /* Bail out if nothing is to be done.  */
+  if (!any_dbentry)
+    error (EXIT_SUCCESS, 0, gettext ("no entries to be processed"));
+
+  /* Compute hash and string tables.  */
+  compute_tables ();
+
+  /* Open output file.  This must not be standard output so we don't
+     handle "-" and "/dev/stdout" special.  */
+  char *tmp_output_name;
+  if (asprintf (&tmp_output_name, "%s.XXXXXX", output_name) == -1)
+    error (EXIT_FAILURE, errno, gettext ("cannot create temporary file name"));
+
+  set_file_creation_context (output_name, mode);
+  int fd = mkstemp (tmp_output_name);
+  reset_file_creation_context ();
+  if (fd == -1)
+    error (EXIT_FAILURE, errno, gettext ("cannot create temporary file"));
+  // XXX SELinux context
+
+  status = write_output (fd);
+
+  if (status == EXIT_SUCCESS)
+    {
+      struct stat64 st;
+
+      if (fstat64 (fd, &st) == 0)
+	{
+	  if ((st.st_mode & ACCESSPERMS) != mode)
+	    /* We ignore problems with changing the mode.  */
+	    fchmod (fd, mode);
+	}
+      else
+	{
+	  error (0, errno, gettext ("cannot stat newly created file"));
+	  status = EXIT_FAILURE;
+	}
+    }
+
+  close (fd);
+
+  if (status == EXIT_SUCCESS)
+    {
+      if (rename (tmp_output_name, output_name) != 0)
+	{
+	  error (0, errno, gettext ("cannot rename temporary file"));
+	  status = EXIT_FAILURE;
+	  goto do_unlink;
+	}
+    }
+  else
+  do_unlink:
+    unlink (tmp_output_name);
 
   return status;
 }
@@ -200,6 +352,7 @@ main (int argc, char *argv[])
 static error_t
 parse_opt (int key, char *arg, struct argp_state *state)
 {
+  struct dbtype *newtype;
   switch (key)
     {
     case 'f':
@@ -214,6 +367,17 @@ parse_opt (int key, char *arg, struct argp_state *state)
     case 'u':
       do_undo = 1;
       break;
+    case 'I':
+    case 'B':
+      if (arg[0] == '\0' || arg[1] != '\0')
+	error (EXIT_FAILURE, 0, gettext ("\
+argument for option to specify database type must be a single-byte character"));
+      newtype = xmalloc (sizeof (struct dbtype));
+      newtype->dbid = arg[0];
+      newtype->type = key == 'I' ? nss_db_type_iterate : nss_db_type_int4;
+      newtype->next = dbtypes;
+      dbtypes = newtype;
+      break;
     default:
       return ARGP_ERR_UNKNOWN;
     }
@@ -246,16 +410,44 @@ print_version (FILE *stream, struct argp_state *state)
 Copyright (C) %s Free Software Foundation, Inc.\n\
 This is free software; see the source for copying conditions.  There is NO\n\
 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
-"), "2000");
+"), "2011");
   fprintf (stream, gettext ("Written by %s.\n"), "Ulrich Drepper");
 }
 
 
 static int
-process_input (input, inname, output, to_lowercase, be_quiet)
+dbentry_compare (const void *p1, const void *p2)
+{
+  const struct dbentry *d1 = (const struct dbentry *) p1;
+  const struct dbentry *d2 = (const struct dbentry *) p2;
+
+  if (d1->hashval != d2->hashval)
+    return d1->hashval < d2->hashval ? -1 : 1;
+
+  if (d1->keylen < d2->keylen)
+    return -1;
+
+  if (d1->keylen > d2->keylen)
+    return 1;
+
+  return memcmp (d1->str, d2->str, d1->keylen);
+}
+
+
+static int
+valstr_compare (const void *p1, const void *p2)
+{
+  const struct valstrentry *d1 = (const struct valstrentry *) p1;
+  const struct valstrentry *d2 = (const struct valstrentry *) p2;
+
+  return strcmp (d1->str, d2->str);
+}
+
+
+static int
+process_input (input, inname, to_lowercase, be_quiet)
      FILE *input;
      const char *inname;
-     NSS_DB *output;
      int to_lowercase;
      int be_quiet;
 {
@@ -269,14 +461,11 @@ process_input (input, inname, output, to_lowercase, be_quiet)
   status = EXIT_SUCCESS;
   linenr = 0;
 
-  while (!feof (input))
-    {
-      DBT key;
-      DBT val;
-      char *cp;
-      int n;
+  struct database *last_database = NULL;
 
-      n = getline (&line, &linelen, input);
+  while (!feof_unlocked (input))
+    {
+      ssize_t n = getline (&line, &linelen, input);
       if (n < 0)
 	/* This means end of file or some bug.  */
 	break;
@@ -290,15 +479,18 @@ process_input (input, inname, output, to_lowercase, be_quiet)
 	/* Remove trailing newline.  */
 	line[--n] = '\0';
 
-      cp = line;
+      char *cp = line;
       while (isspace (*cp))
 	++cp;
 
-      if (*cp == '#')
-	/* First non-space character in line '#': it's a comment.  */
+      if (*cp == '#' || *cp == '\0')
+	/* First non-space character in line '#': it's a comment.
+	   Also go to the next line if it is empty except for whitespaces. */
 	continue;
 
-      key.data = cp;
+      /* Skip over the character indicating the database so that it is not
+	 affected by TO_LOWERCASE.  */
+      char *key = cp++;
       while (*cp != '\0' && !isspace (*cp))
 	{
 	  if (to_lowercase)
@@ -306,44 +498,131 @@ process_input (input, inname, output, to_lowercase, be_quiet)
 	  ++cp;
 	}
 
-      if (key.data == cp)
-	/* It's an empty line.  */
+      if (*cp == '\0')
+	/* It's a line without a value field.  */
 	continue;
 
-      key.size = cp - (char *) key.data;
-      key.flags = 0;
+      *cp++ = '\0';
+      size_t keylen = cp - key;
 
       while (isspace (*cp))
 	++cp;
 
-      val.data = cp;
-      val.size = (&line[n] - cp) + 1;
-      val.flags = 0;
+      char *data = cp;
+      size_t datalen = (&line[n] - cp) + 1;
 
-      /* Store the value.  */
-      status = output->put (output->db, NULL, &key, &val, db_nooverwrite);
-      if (status != 0)
+      /* Find the database.  */
+      if (last_database == NULL || last_database->dbid != key[0])
 	{
-	  if (status == db_keyexist)
+	  last_database = databases;
+	  while (last_database != NULL && last_database->dbid != key[0])
+	    last_database = last_database->next;
+
+	  if (last_database == NULL)
 	    {
-	      if (!be_quiet)
-		error_at_line (0, 0, inname, linenr,
-			       gettext ("duplicate key"));
-	      /* This is no real error.  Just give a warning.  */
-	      status = 0;
-	      continue;
+	      last_database = xmalloc (sizeof (*last_database));
+	      last_database->dbid = key[0];
+	      last_database->type = nss_db_type_hash;	/* Default.  */
+	      last_database->next = databases;
+	      last_database->entries = NULL;
+	      last_database->nentries = 0;
+	      last_database->keystrlen = 0;
+	      databases = last_database;
+
+	      struct dbtype *typeit = dbtypes;
+	      while (typeit != NULL)
+		if (typeit->dbid == last_database->dbid)
+		  {
+		    last_database->type = typeit->type;
+		    break;
+		  }
+		else
+		  typeit = typeit->next;
 	    }
-	  else
-	    error (0, status, gettext ("while writing database file"));
+	}
 
-	  status = EXIT_FAILURE;
+      /* Skip the database selector.  */
+      ++key;
+      --keylen;
+
+      /* Check the key value if it has to be numeric.  */
+      unsigned long int keyvalue = 0;
+      if (last_database->type != nss_db_type_hash)
+	{
+	  char *endp;
+	  errno = 0;
+	  keyvalue = strtoul (key, &endp, 0);
+	  if ((keyvalue == ULONG_MAX && errno == ERANGE)
+	      || keyvalue > ~((stridx_t) 0))
+	    error (EXIT_FAILURE, 0,
+		   gettext ("index value in line %zu too large"), linenr);
+
+	  if (*endp != '\0')
+	    error (EXIT_FAILURE, 0,
+		   gettext ("index value in line %zu is not a number"),
+		   linenr);
+	}
+
+      /* Store the data.  */
+      struct valstrentry *nentry = xmalloc (sizeof (struct valstrentry)
+					    + datalen);
+      nentry->idx = valstrlen;
+      memcpy (nentry->str, data, datalen);
 
-	  clearerr (input);
-	  break;
+      struct valstrentry **fdata = tsearch (nentry, &valstrtree,
+					    valstr_compare);
+      if (fdata == NULL)
+	error (EXIT_FAILURE, errno, gettext ("cannot create search tree"));
+
+      if (*fdata != nentry)
+	{
+	  /* We can reuse a string.  */
+	  free (nentry);
+	  nentry = *fdata;
+	}
+      else
+	valstrlen += datalen;
+
+      /* Store the key.  */
+      struct dbentry *newp;
+      if (last_database->type == nss_db_type_hash)
+	{
+	  newp = xmalloc (sizeof (struct dbentry) + keylen);
+	  newp->keylen = keylen;
+	  newp->validx = nentry->idx;
+	  newp->hashval = __hash_string (key);
+	  memcpy (newp->str, key, keylen);
 	}
+      else
+	{
+	  newp = xmalloc (sizeof (struct dbentry) + sizeof (stridx_t));
+	  newp->keylen = keylen = sizeof (stridx_t);
+	  newp->validx = nentry->idx;
+	  newp->hashval = keyvalue;
+	  stridx_t value = keyvalue;
+	  memcpy (newp->str, &value, sizeof (stridx_t));
+	}
+
+      struct dbentry **found = tsearch (newp, &last_database->entries,
+					dbentry_compare);
+      if (found == NULL)
+	error (EXIT_FAILURE, errno, gettext ("cannot create search tree"));
+
+      if (*found != newp)
+	{
+	  free (newp);
+	  if (!be_quiet)
+	    error_at_line (0, 0, inname, linenr, gettext ("duplicate key"));
+	  continue;
+	}
+
+      ++last_database->nentries;
+      last_database->keystrlen += keylen;
+
+      any_dbentry = true;
     }
 
-  if (ferror (input))
+  if (ferror_unlocked (input))
     {
       error (0, 0, gettext ("problems while reading `%s'"), inname);
       status = EXIT_FAILURE;
@@ -353,38 +632,251 @@ process_input (input, inname, output, to_lowercase, be_quiet)
 }
 
 
-static int
-print_database (db)
-     NSS_DB *db;
+static void
+copy_valstr (const void *nodep, const VISIT which, const int depth)
 {
-  DBT key;
-  DBT val;
-  NSS_DBC *cursor;
-  int status;
+  if (which != leaf && which != postorder)
+    return;
+
+  const struct valstrentry *p = *(const struct valstrentry **) nodep;
+
+  strcpy (valstrtab + p->idx, p->str);
+}
+
+
+static void
+compute_tables (void)
+{
+  valstrtab = xmalloc (roundup (valstrlen, sizeof (stridx_t)));
+  while (valstrlen % sizeof (stridx_t) != 0)
+    valstrtab[valstrlen++] = '\0';
+  twalk (valstrtree, copy_valstr);
+
+  for (struct database *db = databases; db != NULL; db = db->next)
+    if (db->nentries != 0)
+      {
+	++ndatabases;
+
+	if (db->type == nss_db_type_iterate)
+	  {
+	    /* We need no hash table and no key value table in this case.  */
+	    db->nhashentries = 0;
+	    db->hashtable = NULL;
+	    db->keystrtab = NULL;
+	    db->keystrlen = 0;
+	    continue;
+	  }
+
+	if (db->keystrlen > ~((stridx_t) 0))
+	  error (EXIT_FAILURE, 0, gettext ("\
+table size too large; recompile with larger stridx_t"));
+
+	/* We simply use an odd number large than twice the number of
+	   elements to store in the hash table for the size.  This gives
+	   enough efficiency.  */
+	db->nhashentries = db->nentries * 2 + 1;
+	db->hashtable = xmalloc (db->nhashentries
+				 * sizeof (struct nss_db_entry));
+	memset (db->hashtable, '\xff',
+		db->nhashentries * sizeof (struct nss_db_entry));
+	db->keystrlen = roundup (db->keystrlen, sizeof (stridx_t));
+	db->keystrtab = xmalloc (db->keystrlen);
+
+	size_t max_chainlength = 0;
+	char *wp = db->keystrtab;
+
+	void add_key(const void *nodep, const VISIT which, const int depth)
+	{
+	  if (which != leaf && which != postorder)
+	    return;
+
+	  const struct dbentry *dbe = *(const struct dbentry **) nodep;
+
+	  ptrdiff_t stridx = wp - db->keystrtab;
+	  wp = mempcpy (wp, dbe->str, dbe->keylen);
+
+	  size_t hidx = dbe->hashval % db->nhashentries;
+	  size_t hval2 = 1 + dbe->hashval % (db->nhashentries - 2);
+	  size_t chainlength = 0;
+
+	  while (db->hashtable[hidx].keyidx != ~((stridx_t) 0))
+	    {
+	      ++chainlength;
+	      if ((hidx += hval2) >= db->nhashentries)
+		hidx -= db->nhashentries;
+	    }
+
+	  db->hashtable[hidx].keyidx = stridx;
+	  db->hashtable[hidx].dataidx = dbe->validx;
+
+	  max_chainlength = MAX (max_chainlength, chainlength);
+	}
 
-  status = db->cursor (db->db, NULL, &cursor);
-  if (status != 0)
+	twalk (db->entries, add_key);
+
+	// XXX if hash length is too long resize table and start again
+
+	while ((wp - db->keystrtab) % sizeof (stridx_t) != 0)
+	  *wp++ = '\0';
+    }
+}
+
+
+static int
+write_output (int fd)
+{
+  struct nss_db_header *header;
+  uint64_t file_offset = (sizeof (struct nss_db_header)
+			  + (ndatabases * sizeof (header->dbs[0])));
+  header = alloca (file_offset);
+
+  header->magic = NSS_DB_MAGIC;
+  header->ndbs = ndatabases;
+  header->valstroffset = file_offset;
+  header->valstrlen = valstrlen;
+
+  size_t filled_dbs = 0;
+  struct iovec iov[2 + 2 * ndatabases];
+  iov[0].iov_base = header;
+  iov[0].iov_len = file_offset;
+
+  iov[1].iov_base = valstrtab;
+  iov[1].iov_len = valstrlen;
+  file_offset += valstrlen;
+
+  for (struct database *db = databases; db != NULL; db = db->next)
+    if (db->entries != NULL)
+      {
+	assert (file_offset % sizeof (stridx_t) == 0);
+	assert (filled_dbs < ndatabases);
+
+	header->dbs[filled_dbs].id = db->dbid;
+	header->dbs[filled_dbs].type = db->type;
+	memset (header->dbs[filled_dbs].pad, '\0',
+		sizeof (header->dbs[0].pad));
+	header->dbs[filled_dbs].hashsize = db->nhashentries;
+
+	iov[2 + filled_dbs * 2].iov_base = db->hashtable;
+	iov[2 + filled_dbs * 2].iov_len = (db->nhashentries
+					   * sizeof (struct nss_db_entry));
+	header->dbs[filled_dbs].hashoffset = file_offset;
+	file_offset += iov[2 + filled_dbs * 2].iov_len;
+
+	iov[3 + filled_dbs * 2].iov_base = db->keystrtab;
+	iov[3 + filled_dbs * 2].iov_len = db->keystrlen;
+	header->dbs[filled_dbs].stroffset = file_offset;
+	file_offset += iov[3 + filled_dbs * 2].iov_len;
+
+	++filled_dbs;
+      }
+
+  assert (filled_dbs == ndatabases);
+
+  if (writev (fd, iov, 2 + 2 * ndatabases) != file_offset)
     {
-      error (0, status, gettext ("while reading database"));
+      error (0, errno, gettext ("failed to write new database file"));
       return EXIT_FAILURE;
     }
 
-  key.flags = 0;
-  val.flags = 0;
-  status = cursor->c_get (cursor->cursor, &key, &val, db_first);
-  while (status == 0)
+  return EXIT_SUCCESS;
+}
+
+
+static int
+print_database (int fd)
+{
+  struct stat64 st;
+  if (fstat64 (fd, &st) != 0)
+    error (EXIT_FAILURE, errno, gettext ("cannot stat database file"));
+
+  const struct nss_db_header *header = mmap (NULL, st.st_size, PROT_READ,
+					     MAP_PRIVATE|MAP_POPULATE, fd, 0);
+  if (header == MAP_FAILED)
+    error (EXIT_FAILURE, errno, gettext ("cannot map database file"));
+
+  if (header->magic != NSS_DB_MAGIC)
+    error (EXIT_FAILURE, 0, gettext ("file not a database file"));
+
+  const char *valstrtab = (const char *) header + header->valstroffset;
+
+  for (unsigned int dbidx = 0; dbidx < header->ndbs; ++dbidx)
     {
-      printf ("%.*s %s\n", (int) key.size, (char *) key.data,
-	      (char *) val.data);
+      const char *keystrtab
+	= (const char *) header + header->dbs[dbidx].stroffset;
+      const struct nss_db_entry *hashtab
+	= (const struct nss_db_entry *) ((const char *) header
+					 + header->dbs[dbidx].hashoffset);
 
-      status = cursor->c_get (cursor->cursor, &key, &val, db_next);
+      if (header->dbs[dbidx].type == nss_db_type_hash)
+	{
+	  for (uint32_t hidx = 0; hidx < header->dbs[dbidx].hashsize; ++hidx)
+	    if (hashtab[hidx].keyidx != ~((stridx_t) 0))
+	      printf ("%c%s %s\n",
+		      header->dbs[dbidx].id,
+		      keystrtab + hashtab[hidx].keyidx,
+		      valstrtab + hashtab[hidx].dataidx);
+	}
+      else if (header->dbs[dbidx].type == nss_db_type_iterate)
+	{
+	  const char *endvalstrtab = valstrtab + header->valstrlen;
+	  const char *cp = valstrtab;
+	  unsigned int count = 0;
+	  while (cp < endvalstrtab && *cp != '\0')
+	    {
+	      printf ("%c%u %s\n", header->dbs[dbidx].id, count++, cp);
+	      cp = rawmemchr (cp, '\0') + 1;
+	    }
+	}
+      else
+	{
+	  assert (header->dbs[dbidx].type == nss_db_type_int4);
+	  for (uint32_t hidx = 0; hidx < header->dbs[dbidx].hashsize; ++hidx)
+	    if (hashtab[hidx].keyidx != ~((stridx_t) 0))
+	      printf ("%c%" PRIu32 " %s\n",
+		      header->dbs[dbidx].id,
+		      *((uint32_t *) (keystrtab + hashtab[hidx].keyidx)),
+		      valstrtab + hashtab[hidx].dataidx);
+	}
     }
 
-  if (status != db_notfound)
+  return EXIT_SUCCESS;
+}
+
+
+#ifdef HAVE_SELINUX
+static void
+set_file_creation_context (const char *outname, mode_t mode)
+{
+  static int enabled;
+  static int enforcing;
+  security_context_t ctx;
+
+  /* Check if SELinux is enabled, and remember. */
+  if (enabled == 0)
+    enabled = is_selinux_enabled ();
+  if (enabled < 0)
+    return;
+
+  /* Check if SELinux is enforcing, and remember. */
+  if (enforcing == 0)
+    enforcing = security_getenforce () ? 1 : -1;
+
+  /* Determine the context which the file should have. */
+  ctx = NULL;
+  if (matchpathcon (outname, S_IFREG | mode, &ctx) == 0 && ctx != NULL)
     {
-      error (0, status, gettext ("while reading database"));
-      return EXIT_FAILURE;
+      if (setfscreatecon (ctx) != 0)
+	error (enforcing > 0 ? EXIT_FAILURE : 0, 0,
+	       gettext ("cannot set file creation context for `%s'"),
+	       outname);
+
+      freecon (ctx);
     }
+}
 
-  return EXIT_SUCCESS;
+static void
+reset_file_creation_context (void)
+{
+  setfscreatecon (NULL);
 }
+#endif

-----------------------------------------------------------------------

Summary of changes:
 ChangeLog                     |   64 ++++
 Makeconfig                    |    6 +
 NEWS                          |    6 +-
 Versions.def                  |    3 +
 grp/initgroups.c              |   19 +-
 nss/Makefile                  |   39 +++-
 nss/Versions                  |   60 ++++-
 nss/databases.def             |    3 +-
 nss/db-Makefile               |   84 ++++--
 nss/getent.c                  |   33 ++
 nss/makedb.c                  |  667 +++++++++++++++++++++++++++++++++++------
 nss/nss_db/db-XXX.c           |  328 +++++++++++---------
 nss/nss_db/db-alias.c         |  215 -------------
 nss/nss_db/db-initgroups.c    |  138 +++++++++
 nss/nss_db/db-netgrp.c        |   94 ++++---
 nss/nss_db/db-open.c          |  377 ++---------------------
 nss/nss_db/dummy-db.h         |  333 --------------------
 nss/nss_db/nss_db.h           |   96 +++----
 nss/nss_files/files-XXX.c     |   10 +-
 nss/nss_files/files-ethers.c  |    6 +-
 nss/nss_files/files-grp.c     |    6 +-
 nss/nss_files/files-hosts.c   |    2 +-
 nss/nss_files/files-network.c |    6 +-
 nss/nss_files/files-proto.c   |    6 +-
 nss/nss_files/files-pwd.c     |    6 +-
 nss/nss_files/files-rpc.c     |    6 +-
 nss/nss_files/files-service.c |   11 +-
 nss/nss_files/files-sgrp.c    |    4 +-
 nss/nss_files/files-spwd.c    |    4 +-
 shlib-versions                |    1 +
 30 files changed, 1325 insertions(+), 1308 deletions(-)
 delete mode 100644 nss/nss_db/db-alias.c
 create mode 100644 nss/nss_db/db-initgroups.c
 delete mode 100644 nss/nss_db/dummy-db.h


hooks/post-receive
-- 
GNU C Library master sources


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]