about summary refs log tree commit diff
path: root/REORG.TODO/nss
diff options
context:
space:
mode:
Diffstat (limited to 'REORG.TODO/nss')
-rw-r--r--REORG.TODO/nss/Depend2
-rw-r--r--REORG.TODO/nss/Makefile137
-rw-r--r--REORG.TODO/nss/Versions162
-rw-r--r--REORG.TODO/nss/XXX-lookup.c87
-rw-r--r--REORG.TODO/nss/alias-lookup.c21
-rw-r--r--REORG.TODO/nss/bug-erange.c52
-rw-r--r--REORG.TODO/nss/bug17079.c244
-rw-r--r--REORG.TODO/nss/databases.def42
-rw-r--r--REORG.TODO/nss/db-Makefile166
-rw-r--r--REORG.TODO/nss/digits_dots.c283
-rw-r--r--REORG.TODO/nss/ethers-lookup.c21
-rw-r--r--REORG.TODO/nss/function.def78
-rw-r--r--REORG.TODO/nss/getXXbyYY.c154
-rw-r--r--REORG.TODO/nss/getXXbyYY_r.c465
-rw-r--r--REORG.TODO/nss/getXXent.c94
-rw-r--r--REORG.TODO/nss/getXXent_r.c212
-rw-r--r--REORG.TODO/nss/getent.c960
-rw-r--r--REORG.TODO/nss/getnssent.c57
-rw-r--r--REORG.TODO/nss/getnssent_r.c236
-rw-r--r--REORG.TODO/nss/grp-lookup.c22
-rw-r--r--REORG.TODO/nss/hosts-lookup.c22
-rw-r--r--REORG.TODO/nss/key-lookup.c22
-rw-r--r--REORG.TODO/nss/makedb.c879
-rw-r--r--REORG.TODO/nss/netgrp-lookup.c21
-rw-r--r--REORG.TODO/nss/network-lookup.c22
-rw-r--r--REORG.TODO/nss/nss.h63
-rw-r--r--REORG.TODO/nss/nss_db/db-XXX.c311
-rw-r--r--REORG.TODO/nss/nss_db/db-init.c47
-rw-r--r--REORG.TODO/nss/nss_db/db-initgroups.c142
-rw-r--r--REORG.TODO/nss/nss_db/db-netgrp.c122
-rw-r--r--REORG.TODO/nss/nss_db/db-open.c67
-rw-r--r--REORG.TODO/nss/nss_db/nss_db.h69
-rw-r--r--REORG.TODO/nss/nss_files/files-XXX.c300
-rw-r--r--REORG.TODO/nss/nss_files/files-alias.c404
-rw-r--r--REORG.TODO/nss/nss_files/files-ethers.c67
-rw-r--r--REORG.TODO/nss/nss_files/files-grp.c44
-rw-r--r--REORG.TODO/nss/nss_files/files-hosts.c482
-rw-r--r--REORG.TODO/nss/nss_files/files-init.c64
-rw-r--r--REORG.TODO/nss/nss_files/files-initgroups.c142
-rw-r--r--REORG.TODO/nss/nss_files/files-key.c111
-rw-r--r--REORG.TODO/nss/nss_files/files-netgrp.c294
-rw-r--r--REORG.TODO/nss/nss_files/files-network.c88
-rw-r--r--REORG.TODO/nss/nss_files/files-parse.c335
-rw-r--r--REORG.TODO/nss/nss_files/files-proto.c46
-rw-r--r--REORG.TODO/nss/nss_files/files-pwd.c44
-rw-r--r--REORG.TODO/nss/nss_files/files-rpc.c46
-rw-r--r--REORG.TODO/nss/nss_files/files-service.c63
-rw-r--r--REORG.TODO/nss/nss_files/files-sgrp.c37
-rw-r--r--REORG.TODO/nss/nss_files/files-spwd.c37
-rw-r--r--REORG.TODO/nss/nss_test1.c154
-rw-r--r--REORG.TODO/nss/nsswitch.c931
-rw-r--r--REORG.TODO/nss/nsswitch.conf20
-rw-r--r--REORG.TODO/nss/nsswitch.h213
-rw-r--r--REORG.TODO/nss/proto-lookup.c21
-rw-r--r--REORG.TODO/nss/pwd-lookup.c22
-rw-r--r--REORG.TODO/nss/rewrite_field.c52
-rw-r--r--REORG.TODO/nss/rpc-lookup.c21
-rw-r--r--REORG.TODO/nss/service-lookup.c22
-rw-r--r--REORG.TODO/nss/sgrp-lookup.c23
-rw-r--r--REORG.TODO/nss/spwd-lookup.c23
-rw-r--r--REORG.TODO/nss/test-digits-dots.c38
-rw-r--r--REORG.TODO/nss/test-netdb.c340
-rw-r--r--REORG.TODO/nss/tst-cancel-getpwuid_r.c182
-rw-r--r--REORG.TODO/nss/tst-field.c101
-rw-r--r--REORG.TODO/nss/tst-nss-getpwent.c119
-rw-r--r--REORG.TODO/nss/tst-nss-static.c15
-rw-r--r--REORG.TODO/nss/tst-nss-test1.c72
-rw-r--r--REORG.TODO/nss/valid_field.c32
-rw-r--r--REORG.TODO/nss/valid_list_field.c36
69 files changed, 10323 insertions, 0 deletions
diff --git a/REORG.TODO/nss/Depend b/REORG.TODO/nss/Depend
new file mode 100644
index 0000000000..d755539902
--- /dev/null
+++ b/REORG.TODO/nss/Depend
@@ -0,0 +1,2 @@
+dlfcn
+resolv
diff --git a/REORG.TODO/nss/Makefile b/REORG.TODO/nss/Makefile
new file mode 100644
index 0000000000..430be8726f
--- /dev/null
+++ b/REORG.TODO/nss/Makefile
@@ -0,0 +1,137 @@
+# Copyright (C) 1996-2017 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, see
+# <http://www.gnu.org/licenses/>.
+
+#
+#	Makefile for name service switch.
+#
+subdir	:= nss
+
+include ../Makeconfig
+
+headers			:= nss.h
+
+# This is the trivial part which goes into libc itself.
+routines		= nsswitch getnssent getnssent_r digits_dots \
+			  valid_field valid_list_field rewrite_field \
+			  $(addsuffix -lookup,$(databases))
+
+# These are the databases that go through nss dispatch.
+# Caution: if you add a database here, you must add its real name
+# in databases.def, too.
+databases		= proto service hosts network grp pwd ethers \
+			  spwd netgrp alias sgrp
+
+ifneq (,$(filter sunrpc,$(subdirs)))
+databases		+= key rpc
+have-sunrpc		:= 1
+else
+have-sunrpc		:= 0
+endif
+CPPFLAGS-getent.c	= -DHAVE_SUNRPC=$(have-sunrpc)
+
+others                  := getent makedb
+install-bin             := getent makedb
+makedb-modules = xmalloc hash-string
+extra-objs		+= $(makedb-modules:=.o)
+
+tests-static            = tst-field
+tests-internal		= tst-field
+tests			= test-netdb tst-nss-test1 test-digits-dots \
+			  tst-nss-getpwent bug17079
+xtests			= bug-erange
+
+# If we have a thread library then we can test cancellation against
+# some routines like getpwuid_r.
+ifeq (yes,$(have-thread-library))
+tests += tst-cancel-getpwuid_r
+endif
+
+# Specify rules for the nss_* modules.  We have some services.
+services		:= files db
+
+extra-libs		= $(services:%=libnss_%)
+# These libraries will be built in the `others' pass rather than
+# the `lib' pass, because they depend on libc.so being built already.
+extra-libs-others	= $(extra-libs)
+
+# The sources are found in the appropriate subdir.
+subdir-dirs = $(services:%=nss_%)
+vpath %.c $(subdir-dirs) ../locale/programs ../intl
+
+
+libnss_files-routines	:= $(addprefix files-,$(databases)) \
+			   files-initgroups files-init
+
+libnss_db-dbs		:= $(addprefix db-,\
+				       $(filter-out hosts network key alias,\
+						    $(databases))) \
+			   db-initgroups
+libnss_db-routines	:= $(libnss_db-dbs) db-open db-init hash-string
+generated		+= $(filter-out db-alias.c db-netgrp.c, \
+					$(addsuffix .c,$(libnss_db-dbs)))
+
+install-others		+= $(inst_vardbdir)/Makefile
+
+# Build static module into libc if requested
+libnss_files-inhibit-o	= $(filter-out .os,$(object-suffixes))
+libnss_db-inhibit-o	= $(filter-out .os,$(object-suffixes))
+ifeq ($(build-static-nss),yes)
+routines                += $(libnss_files-routines)
+static-only-routines    += $(libnss_files-routines)
+tests-static		+= tst-nss-static
+endif
+extra-test-objs		+= nss_test1.os
+
+include ../Rules
+
+ifeq (yes,$(have-selinux))
+LDLIBS-makedb		:= -lselinux
+endif
+
+libnss-libc = $(common-objpfx)linkobj/libc.so
+# Target-specific variable setting to link objects using deprecated
+# RPC interfaces with the version of libc.so that makes them available
+# for new links:
+$(services:%=$(objpfx)libnss_%.so): libc-for-link = $(libnss-libc)
+
+$(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)
+
+$(inst_vardbdir)/Makefile: db-Makefile $(+force)
+	$(do-install)
+
+libof-nss_test1 = extramodules
+$(objpfx)/libnss_test1.so: $(objpfx)nss_test1.os $(link-libc-deps)
+	$(build-module)
+ifdef libnss_test1.so-version
+$(objpfx)/libnss_test1.so$(libnss_test1.so-version): $(objpfx)/libnss_test1.so
+	$(make-link)
+endif
+$(objpfx)tst-nss-test1.out: $(objpfx)/libnss_test1.so$(libnss_test1.so-version)
+
+ifeq (yes,$(have-thread-library))
+$(objpfx)tst-cancel-getpwuid_r: $(shared-thread-library)
+endif
diff --git a/REORG.TODO/nss/Versions b/REORG.TODO/nss/Versions
new file mode 100644
index 0000000000..f8ababccc7
--- /dev/null
+++ b/REORG.TODO/nss/Versions
@@ -0,0 +1,162 @@
+libc {
+  GLIBC_2.0 {
+     # functions used in other libraries
+    __nss_passwd_lookup; __nss_group_lookup; __nss_hosts_lookup; __nss_next;
+    __nss_database_lookup; __nss_configure_lookup;
+  }
+  GLIBC_2.2.2 {
+    __nss_hostname_digits_dots;
+  }
+  GLIBC_PRIVATE {
+    _nss_files_parse_grent; _nss_files_parse_pwent; _nss_files_parse_spent;
+    __nss_disable_nscd; __nss_lookup_function; _nss_files_parse_sgent;
+
+    __nss_passwd_lookup2; __nss_group_lookup2; __nss_hosts_lookup2;
+    __nss_services_lookup2; __nss_next2; __nss_lookup;
+  }
+}
+
+libnss_files {
+  GLIBC_PRIVATE {
+    _nss_files_setaliasent;
+    _nss_files_endaliasent;
+    _nss_files_getaliasbyname_r;
+    _nss_files_getaliasent_r;
+
+    _nss_files_setetherent;
+    _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;
+    _nss_files_getgrent_r;
+    _nss_files_getgrgid_r;
+    _nss_files_getgrnam_r;
+
+    _nss_files_sethostent;
+    _nss_files_endhostent;
+    _nss_files_gethostbyaddr_r;
+    _nss_files_gethostbyname2_r;
+    _nss_files_gethostbyname3_r;
+    _nss_files_gethostbyname4_r;
+    _nss_files_gethostbyname_r;
+    _nss_files_gethostent_r;
+
+    _nss_files_setnetent;
+    _nss_files_endnetent;
+    _nss_files_getnetbyaddr_r;
+    _nss_files_getnetbyname_r;
+    _nss_files_getnetent_r;
+    _nss_files_parse_netent;
+
+    _nss_files_setnetgrent;
+    _nss_files_endnetgrent;
+    _nss_files_getnetgrent_r;
+
+    _nss_files_setprotoent;
+    _nss_files_endprotoent;
+    _nss_files_getprotobyname_r;
+    _nss_files_getprotobynumber_r;
+    _nss_files_getprotoent_r;
+    _nss_files_parse_protoent;
+
+    _nss_files_setpwent;
+    _nss_files_endpwent;
+    _nss_files_getpwent_r;
+    _nss_files_getpwnam_r;
+    _nss_files_getpwuid_r;
+
+    _nss_files_setrpcent;
+    _nss_files_endrpcent;
+    _nss_files_getrpcbyname_r;
+    _nss_files_getrpcbynumber_r;
+    _nss_files_getrpcent_r;
+    _nss_files_parse_rpcent;
+
+    _nss_files_setservent;
+    _nss_files_endservent;
+    _nss_files_getservbyname_r;
+    _nss_files_getservbyport_r;
+    _nss_files_getservent_r;
+    _nss_files_parse_servent;
+
+    _nss_files_setspent;
+    _nss_files_endspent;
+    _nss_files_getspent_r;
+    _nss_files_getspnam_r;
+
+    _nss_files_setsgent;
+    _nss_files_endsgent;
+    _nss_files_getsgent_r;
+    _nss_files_getsgnam_r;
+
+    _nss_netgroup_parseline;
+    _nss_files_getpublickey;
+    _nss_files_getsecretkey;
+
+    _nss_files_initgroups_dyn;
+
+    _nss_files_init;
+  }
+}
+
+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;
+
+    _nss_db_initgroups_dyn;
+
+    _nss_db_init;
+  }
+}
diff --git a/REORG.TODO/nss/XXX-lookup.c b/REORG.TODO/nss/XXX-lookup.c
new file mode 100644
index 0000000000..5a37fdae08
--- /dev/null
+++ b/REORG.TODO/nss/XXX-lookup.c
@@ -0,0 +1,87 @@
+/* Copyright (C) 1996-2017 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, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include "nsswitch.h"
+
+/*******************************************************************\
+|* Here we assume one symbol to be defined:			   *|
+|* 								   *|
+|* DATABASE_NAME - name of the database the function accesses	   *|
+|*		   (e.g., hosts, services, ...)			   *|
+|* 								   *|
+|* One additional symbol may optionally be defined:		   *|
+|* 								   *|
+|* ALTERNATE_NAME - name of another service which is examined in   *|
+|*                  case DATABASE_NAME is not found                *|
+|* 								   *|
+|* DEFAULT_CONFIG - string for default conf (e.g. "dns files")	   *|
+|* 								   *|
+\*******************************************************************/
+
+#define DB_LOOKUP_FCT CONCAT3_1 (__nss_, DATABASE_NAME, _lookup2)
+#define DB_COMPAT_FCT CONCAT3_1 (__nss_, DATABASE_NAME, _lookup)
+#define CONCAT3_1(Pre, Name, Post) CONCAT3_2 (Pre, Name, Post)
+#define CONCAT3_2(Pre, Name, Post) Pre##Name##Post
+
+#define DATABASE_NAME_SYMBOL CONCAT3_1 (__nss_, DATABASE_NAME, _database)
+#define DATABASE_NAME_STRING STRINGIFY1 (DATABASE_NAME)
+#define STRINGIFY1(Name) STRINGIFY2 (Name)
+#define STRINGIFY2(Name) #Name
+
+#ifdef ALTERNATE_NAME
+#define ALTERNATE_NAME_STRING STRINGIFY1 (ALTERNATE_NAME)
+#else
+#define ALTERNATE_NAME_STRING NULL
+#endif
+
+#ifndef DEFAULT_CONFIG
+#define DEFAULT_CONFIG NULL
+#endif
+
+service_user *DATABASE_NAME_SYMBOL attribute_hidden;
+
+extern int DB_LOOKUP_FCT (service_user **ni, const char *fct_name,
+			  const char *fct2_name, void **fctp)
+  internal_function;
+libc_hidden_proto (DB_LOOKUP_FCT)
+
+int
+internal_function
+DB_LOOKUP_FCT (service_user **ni, const char *fct_name, const char *fct2_name,
+	       void **fctp)
+{
+  if (DATABASE_NAME_SYMBOL == NULL
+      && __nss_database_lookup (DATABASE_NAME_STRING, ALTERNATE_NAME_STRING,
+				DEFAULT_CONFIG, &DATABASE_NAME_SYMBOL) < 0)
+    return -1;
+
+  *ni = DATABASE_NAME_SYMBOL;
+
+  return __nss_lookup (ni, fct_name, fct2_name, fctp);
+}
+libc_hidden_def (DB_LOOKUP_FCT)
+
+
+#ifndef NO_COMPAT
+int
+internal_function attribute_compat_text_section
+DB_COMPAT_FCT (service_user **ni, const char *fct_name, void **fctp)
+{
+  return DB_LOOKUP_FCT (ni, fct_name, NULL, fctp);
+}
+#endif
diff --git a/REORG.TODO/nss/alias-lookup.c b/REORG.TODO/nss/alias-lookup.c
new file mode 100644
index 0000000000..4e7e5d5921
--- /dev/null
+++ b/REORG.TODO/nss/alias-lookup.c
@@ -0,0 +1,21 @@
+/* Copyright (C) 1996-2017 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, see
+   <http://www.gnu.org/licenses/>.  */
+
+#define DATABASE_NAME aliases
+
+#include "XXX-lookup.c"
diff --git a/REORG.TODO/nss/bug-erange.c b/REORG.TODO/nss/bug-erange.c
new file mode 100644
index 0000000000..b709418b5c
--- /dev/null
+++ b/REORG.TODO/nss/bug-erange.c
@@ -0,0 +1,52 @@
+/* Test case for gethostbyname_r bug when buffer expansion required.  */
+
+#include <netdb.h>
+#include <arpa/inet.h>
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+int
+main (void)
+{
+  const char *host = "www.gnu.org";
+
+  /* This code approximates the example code in the library manual.  */
+
+  struct hostent hostbuf, *hp;
+  size_t hstbuflen;
+  char *tmphstbuf;
+  int res;
+  int herr;
+
+  hstbuflen = 16;		/* Make it way small to ensure ERANGE.  */
+  /* Allocate buffer, remember to free it to avoid memory leakage.  */
+  tmphstbuf = malloc (hstbuflen);
+
+  while ((res = gethostbyname_r (host, &hostbuf, tmphstbuf, hstbuflen,
+                                 &hp, &herr)) == ERANGE)
+    {
+      /* Enlarge the buffer.  */
+      hstbuflen *= 2;
+      tmphstbuf = realloc (tmphstbuf, hstbuflen);
+    }
+
+  if (res != 0 || hp == NULL)
+    {
+      printf ("gethostbyname_r failed: %s (errno: %m)\n", strerror (res));
+
+      if (access ("/etc/resolv.conf", R_OK))
+	{
+	  puts ("DNS probably not set up");
+	  return 0;
+	}
+
+      return 1;
+    }
+
+  printf ("Got: %s %s\n", hp->h_name,
+	  inet_ntoa (*(struct in_addr *) hp->h_addr));
+  return 0;
+}
diff --git a/REORG.TODO/nss/bug17079.c b/REORG.TODO/nss/bug17079.c
new file mode 100644
index 0000000000..4171c7db55
--- /dev/null
+++ b/REORG.TODO/nss/bug17079.c
@@ -0,0 +1,244 @@
+/* Test for bug 17079: heap overflow in NSS with small buffers.
+   Copyright (C) 2015-2017 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, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <errno.h>
+#include <pwd.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* Check if two passwd structs contain the same data.  */
+static bool
+equal (const struct passwd *a, const struct passwd *b)
+{
+  return strcmp (a->pw_name, b->pw_name) == 0
+    && strcmp (a->pw_passwd, b->pw_passwd) == 0
+    && a->pw_uid == b->pw_uid
+    && a->pw_gid == b->pw_gid
+    && strcmp (a->pw_gecos, b->pw_gecos) == 0
+    && strcmp (a->pw_dir, b->pw_dir) == 0
+    && strcmp (a->pw_shell, b->pw_shell) == 0;
+}
+
+enum { MAX_TEST_ITEMS = 10 };
+static struct passwd test_items[MAX_TEST_ITEMS];
+static int test_count;
+
+/* Initialize test_items and test_count above, with data from the
+   passwd database.  */
+static bool
+init_test_items (void)
+{
+  setpwent ();
+  do
+    {
+      struct passwd *pwd = getpwent ();
+      if (pwd == NULL)
+        break;
+      struct passwd *target = test_items + test_count;
+      target->pw_name = strdup (pwd->pw_name);
+      target->pw_passwd = strdup (pwd->pw_passwd);
+      target->pw_uid = pwd->pw_uid;
+      target->pw_gid = pwd->pw_gid;
+      target->pw_gecos = strdup (pwd->pw_gecos);
+      target->pw_dir = strdup (pwd->pw_dir);
+      target->pw_shell = strdup (pwd->pw_shell);
+    }
+  while (++test_count < MAX_TEST_ITEMS);
+  endpwent ();
+
+  /* Filter out those test items which cannot be looked up by name or
+     UID.  */
+  bool found = false;
+  for (int i = 0; i < test_count; ++i)
+    {
+      struct passwd *pwd1 = getpwnam (test_items[i].pw_name);
+      struct passwd *pwd2 = getpwuid (test_items[i].pw_uid);
+      if (pwd1 == NULL || !equal (pwd1, test_items + i)
+          || pwd2 == NULL || !equal (pwd2, test_items + i))
+        {
+          printf ("info: skipping user \"%s\", UID %ld due to inconsistency\n",
+                  test_items[i].pw_name, (long) test_items[i].pw_uid);
+          test_items[i].pw_name = NULL;
+        }
+      else
+        found = true;
+    }
+
+  if (!found)
+    puts ("error: no accounts found which can be looked up by name and UID.");
+  return found;
+}
+
+/* Set to true if an error is encountered.  */
+static bool errors;
+
+/* Return true if the padding has not been tampered with.  */
+static bool
+check_padding (char *buffer, size_t size, char pad)
+{
+  char *end = buffer + size;
+  while (buffer < end)
+    {
+      if (*buffer != pad)
+        return false;
+      ++buffer;
+    }
+  return true;
+}
+
+/* Test one buffer size and padding combination.  */
+static void
+test_one (const struct passwd *item, size_t buffer_size,
+           char pad, size_t padding_size)
+{
+  char *buffer = malloc (buffer_size + padding_size);
+  if (buffer == NULL)
+    {
+      puts ("error: malloc failure");
+      errors = true;
+      return;
+    }
+
+  struct passwd pwd;
+  struct passwd *result;
+  int ret;
+
+  /* Test getpwname_r.  */
+  memset (buffer, pad, buffer_size + padding_size);
+  pwd = (struct passwd) {};
+  ret = getpwnam_r (item->pw_name, &pwd, buffer, buffer_size, &result);
+  if (!check_padding (buffer + buffer_size, padding_size, pad))
+    {
+      printf ("error: padding change: "
+              "name \"%s\", buffer size %zu, padding size %zu, pad 0x%02x\n",
+              item->pw_name, buffer_size, padding_size, (unsigned char) pad);
+      errors = true;
+    }
+  if (ret == 0)
+    {
+      if (result == NULL)
+        {
+          printf ("error: no data: name \"%s\", buffer size %zu\n",
+                  item->pw_name, buffer_size);
+          errors = true;
+        }
+      else if (!equal (item, result))
+        {
+          printf ("error: lookup mismatch: name \"%s\", buffer size %zu\n",
+                  item->pw_name, buffer_size);
+          errors = true;
+        }
+    }
+  else if (ret != ERANGE)
+    {
+      errno = ret;
+      printf ("error: lookup failure for name \"%s\": %m (%d)\n",
+              item->pw_name, ret);
+      errors = true;
+    }
+
+  /* Test getpwuid_r.  */
+  memset (buffer, pad, buffer_size + padding_size);
+  pwd = (struct passwd) {};
+  ret = getpwuid_r (item->pw_uid, &pwd, buffer, buffer_size, &result);
+  if (!check_padding (buffer + buffer_size, padding_size, pad))
+    {
+      printf ("error: padding change: "
+              "UID %ld, buffer size %zu, padding size %zu, pad 0x%02x\n",
+              (long) item->pw_uid, buffer_size, padding_size,
+              (unsigned char) pad);
+      errors = true;
+    }
+  if (ret == 0)
+    {
+      if (result == NULL)
+        {
+          printf ("error: no data: UID %ld, buffer size %zu\n",
+                  (long) item->pw_uid, buffer_size);
+          errors = true;
+        }
+      else if (!equal (item, result))
+        {
+          printf ("error: lookup mismatch: UID %ld, buffer size %zu\n",
+                  (long) item->pw_uid, buffer_size);
+          errors = true;
+        }
+    }
+  else if (ret != ERANGE)
+    {
+      errno = ret;
+      printf ("error: lookup failure for UID \"%ld\": %m (%d)\n",
+              (long) item->pw_uid, ret);
+      errors = true;
+    }
+
+  free (buffer);
+}
+
+/* Test one buffer size with different paddings.  */
+static void
+test_buffer_size (size_t buffer_size)
+{
+  for (int i = 0; i < test_count; ++i)
+    for (size_t padding_size = 0; padding_size < 3; ++padding_size)
+      {
+        /* Skip entries with inconsistent name/UID lookups.  */
+        if (test_items[i].pw_name == NULL)
+          continue;
+
+        test_one (test_items + i, buffer_size, '\0', padding_size);
+        if (padding_size > 0)
+          {
+            test_one (test_items + i, buffer_size, ':', padding_size);
+            test_one (test_items + i, buffer_size, '\n', padding_size);
+            test_one (test_items + i, buffer_size, '\xff', padding_size);
+            test_one (test_items + i, buffer_size, '@', padding_size);
+          }
+      }
+}
+
+int
+do_test (void)
+{
+  if (!init_test_items ())
+    return 1;
+  printf ("info: %d test items\n", test_count);
+
+  for (size_t buffer_size = 0; buffer_size <= 65; ++buffer_size)
+    test_buffer_size (buffer_size);
+  for (size_t buffer_size = 64 + 4; buffer_size < 256; buffer_size += 4)
+    test_buffer_size (buffer_size);
+  test_buffer_size (255);
+  test_buffer_size (257);
+  for (size_t buffer_size = 256; buffer_size < 512; buffer_size += 8)
+    test_buffer_size (buffer_size);
+  test_buffer_size (511);
+  test_buffer_size (513);
+  test_buffer_size (1024);
+  test_buffer_size (2048);
+
+  if (errors)
+    return 1;
+  else
+    return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/REORG.TODO/nss/databases.def b/REORG.TODO/nss/databases.def
new file mode 100644
index 0000000000..8a46839618
--- /dev/null
+++ b/REORG.TODO/nss/databases.def
@@ -0,0 +1,42 @@
+/* List of all databases defined for the NSS in GNU C Library.
+   Copyright (C) 1996-2017 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, see
+   <http://www.gnu.org/licenses/>.  */
+
+/* This list must be kept sorted!!!  If any long name is added the
+   field size for it must be increases.  */
+
+DEFINE_DATABASE (aliases)
+DEFINE_DATABASE (ethers)
+DEFINE_DATABASE (group)
+DEFINE_DATABASE (gshadow)
+DEFINE_DATABASE (hosts)
+DEFINE_DATABASE (initgroups)
+DEFINE_DATABASE (netgroup)
+DEFINE_DATABASE (networks)
+DEFINE_DATABASE (passwd)
+DEFINE_DATABASE (protocols)
+DEFINE_DATABASE (publickey)
+DEFINE_DATABASE (rpc)
+DEFINE_DATABASE (services)
+DEFINE_DATABASE (shadow)
+
+/*
+   Local Variables:
+    mode:C
+   End:
+ */
diff --git a/REORG.TODO/nss/db-Makefile b/REORG.TODO/nss/db-Makefile
new file mode 100644
index 0000000000..aa22ed0d5b
--- /dev/null
+++ b/REORG.TODO/nss/db-Makefile
@@ -0,0 +1,166 @@
+# Makefile to (re-)generate db versions of system database files.
+# Copyright (C) 1996-2017 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, see
+# <http://www.gnu.org/licenses/>.
+
+DATABASES = $(wildcard /etc/passwd /etc/group /etc/ethers /etc/protocols \
+		       /etc/rpc /etc/services /etc/shadow /etc/gshadow \
+		       /etc/netgroup)
+
+VAR_DB = /var/db
+
+AWK = awk
+MAKEDB = makedb --quiet
+
+all: $(patsubst %,$(VAR_DB)/%.db,$(notdir $(DATABASES)))
+
+
+$(VAR_DB)/passwd.db: /etc/passwd
+	@printf %s "$(patsubst %.db,%,$(@F))... "
+	@$(AWK) 'BEGIN { FS=":"; OFS=":" } \
+		 /^[ \t]*$$/ { next } \
+		 /^[ \t]*#/ { next } \
+		 /^[^#]/ { printf ".%s ", $$1; print; \
+			   printf "=%s ", $$3; print }' $^ | \
+	$(MAKEDB) -o $@ -
+	@echo "done."
+
+$(VAR_DB)/group.db: /etc/group
+	@printf %s "$(patsubst %.db,%,$(@F))... "
+	@$(AWK) 'BEGIN { FS=":"; OFS=":" } \
+		 /^[ \t]*$$/ { next } \
+		 /^[ \t]*#/ { next } \
+		 /^[^#]/ { printf ".%s ", $$1; 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."
+
+$(VAR_DB)/ethers.db: /etc/ethers
+	@printf %s "$(patsubst %.db,%,$(@F))... "
+	@$(AWK) '/^[ \t]*$$/ { next } \
+		 /^[ \t]*#/ { next } \
+		 /^[^#]/ { printf ".%s ", $$1; print; \
+			   printf "=%s ", $$2; print }' $^ | \
+	$(MAKEDB) -o $@ -
+	@echo "done."
+
+$(VAR_DB)/protocols.db: /etc/protocols
+	@printf %s "$(patsubst %.db,%,$(@F))... "
+	@$(AWK) '/^[ \t]*$$/ { next } \
+		 /^[ \t]*#/ { next } \
+		 /^[^#]/ { printf ".%s ", $$1; print; \
+			   printf "=%s ", $$2; print; \
+			   for (i = 3; i <= NF && !($$i ~ /^#/); ++i) \
+			     { printf ".%s ", $$i; print } }' $^ | \
+	$(MAKEDB) -o $@ -
+	@echo "done."
+
+$(VAR_DB)/rpc.db: /etc/rpc
+	@printf %s "$(patsubst %.db,%,$(@F))... "
+	@$(AWK) '/^[ \t]*$$/ { next } \
+		 /^[ \t]*#/ { next } \
+		 /^[^#]/ { printf ".%s ", $$1; print; \
+			   printf "=%s ", $$2; print; \
+			   for (i = 3; i <= NF && !($$i ~ /^#/); ++i) \
+			     { printf ".%s ", $$i; print } }' $^ | \
+	$(MAKEDB) -o $@ -
+	@echo "done."
+
+$(VAR_DB)/services.db: /etc/services
+	@printf %s "$(patsubst %.db,%,$(@F))... "
+	@$(AWK) 'BEGIN { FS="[ \t/]+" } \
+		 /^[ \t]*$$/ { next } \
+		 /^[ \t]*#/ { next } \
+		 /^[^#]/ { 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 } }' $^ | \
+	$(MAKEDB) -o $@ -
+	@echo "done."
+
+$(VAR_DB)/shadow.db: /etc/shadow
+	@printf %s "$(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 password 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)/gshadow.db: /etc/gshadow
+	@printf %s "$(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
+	@printf %s "$(patsubst %.db,%,$(@F))... "
+	@$(AWK) 'BEGIN { ini=1 } \
+		 /^[ \t]*$$/ { next } \
+		 /^[ \t]*#/ { next } \
+		 /^[^#]/ { if (sub(/[ \t]*\\$$/, " ") == 0) end="\n"; \
+			   else end=""; \
+			   gsub(/[ \t]+/, " "); \
+			   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/REORG.TODO/nss/digits_dots.c b/REORG.TODO/nss/digits_dots.c
new file mode 100644
index 0000000000..8dcbf9eb0a
--- /dev/null
+++ b/REORG.TODO/nss/digits_dots.c
@@ -0,0 +1,283 @@
+/* Copyright (C) 1997-2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by H.J. Lu <hjl@gnu.ai.mit.edu>, 1997.
+
+   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, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <wctype.h>
+#include <resolv/resolv-internal.h>
+#include <netdb.h>
+#include <arpa/inet.h>
+#include "nsswitch.h"
+
+#ifdef USE_NSCD
+# define inet_aton __inet_aton
+# include <nscd/nscd_proto.h>
+#endif
+
+int
+__nss_hostname_digits_dots (const char *name, struct hostent *resbuf,
+			    char **buffer, size_t *buffer_size,
+			    size_t buflen, struct hostent **result,
+			    enum nss_status *status, int af, int *h_errnop)
+{
+  int save;
+
+  /* We have to test for the use of IPv6 which can only be done by
+     examining `_res'.  */
+  if (__res_maybe_init (&_res, 0) == -1)
+    {
+      if (h_errnop)
+	*h_errnop = NETDB_INTERNAL;
+      if (buffer_size == NULL)
+	*status = NSS_STATUS_TRYAGAIN;
+      else
+	*result = NULL;
+      return -1;
+    }
+
+  /*
+   * disallow names consisting only of digits/dots, unless
+   * they end in a dot.
+   */
+  if (isdigit (name[0]) || isxdigit (name[0]) || name[0] == ':')
+    {
+      const char *cp;
+      char *hostname;
+      typedef unsigned char host_addr_t[16];
+      host_addr_t *host_addr;
+      typedef char *host_addr_list_t[2];
+      host_addr_list_t *h_addr_ptrs;
+      char **h_alias_ptr;
+      size_t size_needed;
+      int addr_size;
+
+      switch (af)
+	{
+	case AF_INET:
+	  addr_size = INADDRSZ;
+	  break;
+
+	case AF_INET6:
+	  addr_size = IN6ADDRSZ;
+	  break;
+
+	default:
+	  af = res_use_inet6 () ? AF_INET6 : AF_INET;
+	  addr_size = af == AF_INET6 ? IN6ADDRSZ : INADDRSZ;
+	  break;
+	}
+
+      size_needed = (sizeof (*host_addr)
+		     + sizeof (*h_addr_ptrs)
+		     + sizeof (*h_alias_ptr) + strlen (name) + 1);
+
+      if (buffer_size == NULL)
+        {
+	  if (buflen < size_needed)
+	    {
+	      *status = NSS_STATUS_TRYAGAIN;
+	      if (h_errnop != NULL)
+		*h_errnop = NETDB_INTERNAL;
+	      __set_errno (ERANGE);
+	      goto done;
+	    }
+	}
+      else if (buffer_size != NULL && *buffer_size < size_needed)
+	{
+	  char *new_buf;
+	  *buffer_size = size_needed;
+	  new_buf = (char *) realloc (*buffer, *buffer_size);
+
+	  if (new_buf == NULL)
+	    {
+	      save = errno;
+	      free (*buffer);
+	      *buffer = NULL;
+	      *buffer_size = 0;
+	      __set_errno (save);
+	      if (h_errnop != NULL)
+		*h_errnop = NETDB_INTERNAL;
+	      *result = NULL;
+	      goto done;
+	    }
+	  *buffer = new_buf;
+	}
+
+      memset (*buffer, '\0', size_needed);
+
+      host_addr = (host_addr_t *) *buffer;
+      h_addr_ptrs = (host_addr_list_t *)
+	((char *) host_addr + sizeof (*host_addr));
+      h_alias_ptr = (char **) ((char *) h_addr_ptrs + sizeof (*h_addr_ptrs));
+      hostname = (char *) h_alias_ptr + sizeof (*h_alias_ptr);
+
+      if (isdigit (name[0]))
+	{
+	  for (cp = name;; ++cp)
+	    {
+	      if (*cp == '\0')
+		{
+		  int ok;
+
+		  if (*--cp == '.')
+		    break;
+
+		  /* All-numeric, no dot at the end. Fake up a hostent as if
+		     we'd actually done a lookup.  What if someone types
+		     255.255.255.255?  The test below will succeed
+		     spuriously... ???  */
+		  if (af == AF_INET)
+		    ok = __inet_aton (name, (struct in_addr *) host_addr);
+		  else
+		    {
+		      assert (af == AF_INET6);
+		      ok = inet_pton (af, name, host_addr) > 0;
+		    }
+		  if (! ok)
+		    {
+		      *h_errnop = HOST_NOT_FOUND;
+		      if (buffer_size == NULL)
+			*status = NSS_STATUS_NOTFOUND;
+		      else
+			*result = NULL;
+		      goto done;
+		    }
+
+		  resbuf->h_name = strcpy (hostname, name);
+		  h_alias_ptr[0] = NULL;
+		  resbuf->h_aliases = h_alias_ptr;
+		  (*h_addr_ptrs)[0] = (char *) host_addr;
+		  (*h_addr_ptrs)[1] = NULL;
+		  resbuf->h_addr_list = *h_addr_ptrs;
+		  if (af == AF_INET && res_use_inet6 ())
+		    {
+		      /* We need to change the IP v4 address into the
+			 IP v6 address.  */
+		      char tmp[INADDRSZ];
+		      char *p = (char *) host_addr;
+		      int i;
+
+		      /* Save a copy of the IP v4 address. */
+		      memcpy (tmp, host_addr, INADDRSZ);
+		      /* Mark this ipv6 addr as a mapped ipv4. */
+		      for (i = 0; i < 10; i++)
+			*p++ = 0x00;
+		      *p++ = 0xff;
+		      *p++ = 0xff;
+		      /* Copy the IP v4 address. */
+		      memcpy (p, tmp, INADDRSZ);
+		      resbuf->h_addrtype = AF_INET6;
+		      resbuf->h_length = IN6ADDRSZ;
+		    }
+		  else
+		    {
+		      resbuf->h_addrtype = af;
+		      resbuf->h_length = addr_size;
+		    }
+		  if (h_errnop != NULL)
+		    *h_errnop = NETDB_SUCCESS;
+		  if (buffer_size == NULL)
+		    *status = NSS_STATUS_SUCCESS;
+		  else
+		    *result = resbuf;
+		  goto done;
+		}
+
+	      if (!isdigit (*cp) && *cp != '.')
+		break;
+	    }
+	}
+
+      if ((isxdigit (name[0]) && strchr (name, ':') != NULL) || name[0] == ':')
+	{
+	  switch (af)
+	    {
+	    default:
+	      af = res_use_inet6 () ? AF_INET6 : AF_INET;
+	      if (af == AF_INET6)
+		{
+		  addr_size = IN6ADDRSZ;
+		  break;
+		}
+	      /* FALLTHROUGH */
+
+	    case AF_INET:
+	      /* This is not possible.  We cannot represent an IPv6 address
+		 in an `struct in_addr' variable.  */
+	      *h_errnop = HOST_NOT_FOUND;
+	      if (buffer_size == NULL)
+		*status = NSS_STATUS_NOTFOUND;
+	      else
+		*result = NULL;
+	      goto done;
+
+	    case AF_INET6:
+	      addr_size = IN6ADDRSZ;
+	      break;
+	    }
+
+	  for (cp = name;; ++cp)
+	    {
+	      if (!*cp)
+		{
+		  if (*--cp == '.')
+		    break;
+
+		  /* All-IPv6-legal, no dot at the end. Fake up a
+		     hostent as if we'd actually done a lookup.  */
+		  if (inet_pton (AF_INET6, name, host_addr) <= 0)
+		    {
+		      *h_errnop = HOST_NOT_FOUND;
+		      if (buffer_size == NULL)
+			*status = NSS_STATUS_NOTFOUND;
+		      else
+			*result = NULL;
+		      goto done;
+		    }
+
+		  resbuf->h_name = strcpy (hostname, name);
+		  h_alias_ptr[0] = NULL;
+		  resbuf->h_aliases = h_alias_ptr;
+		  (*h_addr_ptrs)[0] = (char *) host_addr;
+		  (*h_addr_ptrs)[1] = (char *) 0;
+		  resbuf->h_addr_list = *h_addr_ptrs;
+		  resbuf->h_addrtype = AF_INET6;
+		  resbuf->h_length = addr_size;
+		  *h_errnop = NETDB_SUCCESS;
+		  if (buffer_size == NULL)
+		    *status = NSS_STATUS_SUCCESS;
+		  else
+		    *result = resbuf;
+		  goto done;
+		}
+
+	      if (!isxdigit (*cp) && *cp != ':' && *cp != '.')
+		break;
+	    }
+	}
+    }
+
+  return 0;
+
+done:
+  return 1;
+}
+libc_hidden_def (__nss_hostname_digits_dots)
diff --git a/REORG.TODO/nss/ethers-lookup.c b/REORG.TODO/nss/ethers-lookup.c
new file mode 100644
index 0000000000..ae073dd7a7
--- /dev/null
+++ b/REORG.TODO/nss/ethers-lookup.c
@@ -0,0 +1,21 @@
+/* Copyright (C) 1996-2017 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, see
+   <http://www.gnu.org/licenses/>.  */
+
+#define DATABASE_NAME ethers
+
+#include "XXX-lookup.c"
diff --git a/REORG.TODO/nss/function.def b/REORG.TODO/nss/function.def
new file mode 100644
index 0000000000..638fcc8126
--- /dev/null
+++ b/REORG.TODO/nss/function.def
@@ -0,0 +1,78 @@
+/* List of functions defined for static NSS in GNU C Library.
+   Copyright (C) 1996-2017 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, see
+   <http://www.gnu.org/licenses/>.  */
+
+/*
+  This is a minimal config.  Only services `files' and `dns' are supported.
+*/
+
+/* aliases */
+DEFINE_ENT (files, alias)
+DEFINE_GETBY (files, alias, name)
+
+/* ethers */
+DEFINE_ENT (files, ether)
+
+/* group */
+DEFINE_ENT (files, gr)
+DEFINE_GET (files, grgid)
+DEFINE_GET (files, grnam)
+
+/* hosts */
+DEFINE_ENT (files, host)
+DEFINE_GETBY (files, host, addr)
+DEFINE_GETBY (files, host, name)
+DEFINE_GETBY (files, host, name2)
+DEFINE_GET (files, hostton)
+DEFINE_GET (files, ntohost)
+DEFINE_GETBY (dns, host, addr)
+DEFINE_GETBY (dns, host, name)
+DEFINE_GETBY (dns, host, name2)
+
+/* netgroup */
+DEFINE_ENT (files, netgr)
+
+/* networks */
+DEFINE_ENT (files, net)
+DEFINE_GETBY (files, net, name)
+DEFINE_GETBY (files, net, addr)
+DEFINE_GETBY (dns, net, name)
+DEFINE_GETBY (dns, net, addr)
+
+/* protocols */
+DEFINE_ENT (files, proto)
+DEFINE_GETBY (files, proto, name)
+DEFINE_GETBY (files, proto, number)
+
+/* passwd */
+DEFINE_ENT (files, pw)
+DEFINE_GET (files, pwnam)
+DEFINE_GET (files, pwuid)
+
+/* rpc */
+DEFINE_ENT (files, rpc)
+DEFINE_GETBY (files, rpc, name)
+DEFINE_GETBY (files, rpc, number)
+
+/* services */
+DEFINE_ENT (files, serv)
+DEFINE_GETBY (files, serv, name)
+DEFINE_GETBY (files, serv, port)
+
+/* shadow */
+DEFINE_ENT (files, sp)
+DEFINE_GET (files, spnam)
diff --git a/REORG.TODO/nss/getXXbyYY.c b/REORG.TODO/nss/getXXbyYY.c
new file mode 100644
index 0000000000..d027b14250
--- /dev/null
+++ b/REORG.TODO/nss/getXXbyYY.c
@@ -0,0 +1,154 @@
+/* Copyright (C) 1996-2017 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, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <assert.h>
+#include <errno.h>
+#include <libc-lock.h>
+#include <stdlib.h>
+#include <resolv.h>
+
+#include "nsswitch.h"
+
+/*******************************************************************\
+|* Here we assume several symbols to be defined:		   *|
+|*								   *|
+|* LOOKUP_TYPE   - the return type of the function		   *|
+|*								   *|
+|* FUNCTION_NAME - name of the non-reentrant function		   *|
+|*								   *|
+|* DATABASE_NAME - name of the database the function accesses	   *|
+|*		   (e.g., host, services, ...)			   *|
+|*								   *|
+|* ADD_PARAMS    - additional parameter, can vary in number	   *|
+|*								   *|
+|* ADD_VARIABLES - names of additional parameter		   *|
+|*								   *|
+|* BUFLEN	 - length of buffer allocated for the non	   *|
+|*		   reentrant version				   *|
+|*								   *|
+|* Optionally the following vars can be defined:		   *|
+|*								   *|
+|* NEED_H_ERRNO  - an extra parameter will be passed to point to   *|
+|*		   the global `h_errno' variable.		   *|
+|*								   *|
+\*******************************************************************/
+
+/* To make the real sources a bit prettier.  */
+#define REENTRANT_NAME APPEND_R (FUNCTION_NAME)
+#define APPEND_R(name) APPEND_R1 (name)
+#define APPEND_R1(name) name##_r
+#define INTERNAL(name) INTERNAL1 (name)
+#define INTERNAL1(name) __##name
+
+/* Sometimes we need to store error codes in the `h_errno' variable.  */
+#ifdef NEED_H_ERRNO
+# define H_ERRNO_PARM , int *h_errnop
+# define H_ERRNO_VAR , &h_errno_tmp
+# define H_ERRNO_VAR_P &h_errno_tmp
+#else
+# define H_ERRNO_PARM
+# define H_ERRNO_VAR
+# define H_ERRNO_VAR_P NULL
+#endif
+
+#ifdef HAVE_AF
+# define AF_VAL af
+#else
+# define AF_VAL AF_INET
+#endif
+
+/* Prototype for reentrant version we use here.  */
+extern int INTERNAL (REENTRANT_NAME) (ADD_PARAMS, LOOKUP_TYPE *resbuf,
+				      char *buffer, size_t buflen,
+				      LOOKUP_TYPE **result H_ERRNO_PARM);
+
+/* We need to protect the dynamic buffer handling.  */
+__libc_lock_define_initialized (static, lock);
+
+/* This points to the static buffer used.  */
+libc_freeres_ptr (static char *buffer);
+
+
+LOOKUP_TYPE *
+FUNCTION_NAME (ADD_PARAMS)
+{
+  static size_t buffer_size;
+  static LOOKUP_TYPE resbuf;
+  LOOKUP_TYPE *result;
+#ifdef NEED_H_ERRNO
+  int h_errno_tmp = 0;
+#endif
+
+  /* Get lock.  */
+  __libc_lock_lock (lock);
+
+  if (buffer == NULL)
+    {
+      buffer_size = BUFLEN;
+      buffer = (char *) malloc (buffer_size);
+    }
+
+#ifdef HANDLE_DIGITS_DOTS
+  if (buffer != NULL)
+    {
+      if (__nss_hostname_digits_dots (name, &resbuf, &buffer,
+				      &buffer_size, 0, &result, NULL, AF_VAL,
+				      H_ERRNO_VAR_P))
+	goto done;
+    }
+#endif
+
+  while (buffer != NULL
+	 && (INTERNAL (REENTRANT_NAME) (ADD_VARIABLES, &resbuf, buffer,
+					buffer_size, &result H_ERRNO_VAR)
+	     == ERANGE)
+#ifdef NEED_H_ERRNO
+	 && h_errno_tmp == NETDB_INTERNAL
+#endif
+	 )
+    {
+      char *new_buf;
+      buffer_size *= 2;
+      new_buf = (char *) realloc (buffer, buffer_size);
+      if (new_buf == NULL)
+	{
+	  /* We are out of memory.  Free the current buffer so that the
+	     process gets a chance for a normal termination.  */
+	  free (buffer);
+	  __set_errno (ENOMEM);
+	}
+      buffer = new_buf;
+    }
+
+  if (buffer == NULL)
+    result = NULL;
+
+#ifdef HANDLE_DIGITS_DOTS
+done:
+#endif
+  /* Release lock.  */
+  __libc_lock_unlock (lock);
+
+#ifdef NEED_H_ERRNO
+  if (h_errno_tmp != 0)
+    __set_h_errno (h_errno_tmp);
+#endif
+
+  return result;
+}
+
+nss_interface_function (FUNCTION_NAME)
diff --git a/REORG.TODO/nss/getXXbyYY_r.c b/REORG.TODO/nss/getXXbyYY_r.c
new file mode 100644
index 0000000000..5962475737
--- /dev/null
+++ b/REORG.TODO/nss/getXXbyYY_r.c
@@ -0,0 +1,465 @@
+/* Copyright (C) 1996-2017 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, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <assert.h>
+#include <atomic.h>
+#include <errno.h>
+#include <stdbool.h>
+#include "nsswitch.h"
+#include "sysdep.h"
+#ifdef USE_NSCD
+# include <nscd/nscd_proto.h>
+#endif
+#ifdef NEED__RES_HCONF
+# include <resolv/res_hconf.h>
+#endif
+#ifdef NEED__RES
+# include <resolv.h>
+#endif
+/*******************************************************************\
+|* Here we assume several symbols to be defined:		   *|
+|*								   *|
+|* LOOKUP_TYPE   - the return type of the function		   *|
+|*								   *|
+|* FUNCTION_NAME - name of the non-reentrant function		   *|
+|*								   *|
+|* DATABASE_NAME - name of the database the function accesses	   *|
+|*		   (e.g., host, services, ...)			   *|
+|*								   *|
+|* ADD_PARAMS    - additional parameters, can vary in number	   *|
+|*								   *|
+|* ADD_VARIABLES - names of additional parameters		   *|
+|*								   *|
+|* Optionally the following vars can be defined:		   *|
+|*								   *|
+|* EXTRA_PARAMS  - optional parameters, can vary in number	   *|
+|*								   *|
+|* EXTRA_VARIABLES - names of optional parameter		   *|
+|*								   *|
+|* FUNCTION2_NAME - alternative name of the non-reentrant function *|
+|*								   *|
+|* NEED_H_ERRNO  - an extra parameter will be passed to point to   *|
+|*		   the global `h_errno' variable.		   *|
+|*								   *|
+|* NEED__RES     - the global _res variable might be used so we	   *|
+|*		   will have to initialize it if necessary	   *|
+|*								   *|
+|* PREPROCESS    - code run before anything else		   *|
+|*								   *|
+|* POSTPROCESS   - code run after the lookup			   *|
+|*								   *|
+\*******************************************************************/
+
+/* To make the real sources a bit prettier.  */
+#define REENTRANT_NAME APPEND_R (FUNCTION_NAME)
+#ifdef FUNCTION2_NAME
+# define REENTRANT2_NAME APPEND_R (FUNCTION2_NAME)
+#else
+# define REENTRANT2_NAME NULL
+#endif
+#define APPEND_R(name) APPEND_R1 (name)
+#define APPEND_R1(name) name##_r
+#define INTERNAL(name) INTERNAL1 (name)
+#define INTERNAL1(name) __##name
+#define NEW(name) NEW1 (name)
+#define NEW1(name) __new_##name
+
+#ifdef USE_NSCD
+# define NSCD_NAME ADD_NSCD (REENTRANT_NAME)
+# define ADD_NSCD(name) ADD_NSCD1 (name)
+# define ADD_NSCD1(name) __nscd_##name
+# define NOT_USENSCD_NAME ADD_NOT_NSCDUSE (DATABASE_NAME)
+# define ADD_NOT_NSCDUSE(name) ADD_NOT_NSCDUSE1 (name)
+# define ADD_NOT_NSCDUSE1(name) __nss_not_use_nscd_##name
+# define CONCAT2(arg1, arg2) CONCAT2_2 (arg1, arg2)
+# define CONCAT2_2(arg1, arg2) arg1##arg2
+#endif
+
+#define FUNCTION_NAME_STRING STRINGIZE (FUNCTION_NAME)
+#define REENTRANT_NAME_STRING STRINGIZE (REENTRANT_NAME)
+#ifdef FUNCTION2_NAME
+# define REENTRANT2_NAME_STRING STRINGIZE (REENTRANT2_NAME)
+#else
+# define REENTRANT2_NAME_STRING NULL
+#endif
+#define DATABASE_NAME_STRING STRINGIZE (DATABASE_NAME)
+#define STRINGIZE(name) STRINGIZE1 (name)
+#define STRINGIZE1(name) #name
+
+#ifndef DB_LOOKUP_FCT
+# define DB_LOOKUP_FCT CONCAT3_1 (__nss_, DATABASE_NAME, _lookup2)
+# define CONCAT3_1(Pre, Name, Post) CONCAT3_2 (Pre, Name, Post)
+# define CONCAT3_2(Pre, Name, Post) Pre##Name##Post
+#endif
+
+/* Sometimes we need to store error codes in the `h_errno' variable.  */
+#ifdef NEED_H_ERRNO
+# define H_ERRNO_PARM , int *h_errnop
+# define H_ERRNO_VAR , h_errnop
+# define H_ERRNO_VAR_P h_errnop
+#else
+# define H_ERRNO_PARM
+# define H_ERRNO_VAR
+# define H_ERRNO_VAR_P NULL
+#endif
+
+#ifndef EXTRA_PARAMS
+# define EXTRA_PARAMS
+#endif
+#ifndef EXTRA_VARIABLES
+# define EXTRA_VARIABLES
+#endif
+
+#ifdef HAVE_AF
+# define AF_VAL af
+#else
+# define AF_VAL AF_INET
+#endif
+
+
+/* Set defaults for merge functions that haven't been defined.  */
+#ifndef DEEPCOPY_FN
+static inline int
+__copy_einval (LOOKUP_TYPE a,
+	       const size_t b,
+	       LOOKUP_TYPE *c,
+	       char *d,
+	       char **e)
+{
+  return EINVAL;
+}
+# define DEEPCOPY_FN __copy_einval
+#endif
+
+#ifndef MERGE_FN
+static inline int
+__merge_einval (LOOKUP_TYPE *a,
+		char *b,
+		char *c,
+		size_t d,
+		LOOKUP_TYPE *e,
+		char *f)
+{
+  return EINVAL;
+}
+# define MERGE_FN __merge_einval
+#endif
+
+#define CHECK_MERGE(err, status)		\
+  ({						\
+    do						\
+      {						\
+	if (err)				\
+	  {					\
+	    __set_errno (err);			\
+	    if (err == ERANGE)			\
+	      status = NSS_STATUS_TRYAGAIN;	\
+	    else				\
+	      status = NSS_STATUS_UNAVAIL;	\
+	    break;				\
+	  }					\
+      }						\
+    while (0);					\
+  })
+
+/* Type of the lookup function we need here.  */
+typedef enum nss_status (*lookup_function) (ADD_PARAMS, LOOKUP_TYPE *, char *,
+					    size_t, int * H_ERRNO_PARM
+					    EXTRA_PARAMS);
+
+/* The lookup function for the first entry of this service.  */
+extern int DB_LOOKUP_FCT (service_user **nip, const char *name,
+			  const char *name2, void **fctp)
+     internal_function;
+libc_hidden_proto (DB_LOOKUP_FCT)
+
+
+int
+INTERNAL (REENTRANT_NAME) (ADD_PARAMS, LOOKUP_TYPE *resbuf, char *buffer,
+			   size_t buflen, LOOKUP_TYPE **result H_ERRNO_PARM
+			   EXTRA_PARAMS)
+{
+  static bool startp_initialized;
+  static service_user *startp;
+  static lookup_function start_fct;
+  service_user *nip;
+  int do_merge = 0;
+  LOOKUP_TYPE mergegrp;
+  char *mergebuf = NULL;
+  char *endptr = NULL;
+  union
+  {
+    lookup_function l;
+    void *ptr;
+  } fct;
+  int no_more, err;
+  enum nss_status status = NSS_STATUS_UNAVAIL;
+#ifdef USE_NSCD
+  int nscd_status;
+#endif
+#ifdef NEED_H_ERRNO
+  bool any_service = false;
+#endif
+
+#ifdef PREPROCESS
+  PREPROCESS;
+#endif
+
+#ifdef HANDLE_DIGITS_DOTS
+  switch (__nss_hostname_digits_dots (name, resbuf, &buffer, NULL,
+				      buflen, result, &status, AF_VAL,
+				      H_ERRNO_VAR_P))
+    {
+    case -1:
+      return errno;
+    case 1:
+#ifdef NEED_H_ERRNO
+      any_service = true;
+#endif
+      goto done;
+    }
+#endif
+
+#ifdef USE_NSCD
+  if (NOT_USENSCD_NAME > 0 && ++NOT_USENSCD_NAME > NSS_NSCD_RETRY)
+    NOT_USENSCD_NAME = 0;
+
+  if (!NOT_USENSCD_NAME
+      && !__nss_database_custom[CONCAT2 (NSS_DBSIDX_, DATABASE_NAME)])
+    {
+      nscd_status = NSCD_NAME (ADD_VARIABLES, resbuf, buffer, buflen, result
+			       H_ERRNO_VAR);
+      if (nscd_status >= 0)
+	return nscd_status;
+    }
+#endif
+
+  if (! startp_initialized)
+    {
+      no_more = DB_LOOKUP_FCT (&nip, REENTRANT_NAME_STRING,
+			       REENTRANT2_NAME_STRING, &fct.ptr);
+      if (no_more)
+	{
+	  void *tmp_ptr = (service_user *) -1l;
+#ifdef PTR_MANGLE
+	  PTR_MANGLE (tmp_ptr);
+#endif
+	  startp = tmp_ptr;
+	}
+      else
+	{
+#ifdef NEED__RES
+	  /* The resolver code will really be used so we have to
+	     initialize it.  */
+	  if (__res_maybe_init (&_res, 0) == -1)
+	    {
+	      *h_errnop = NETDB_INTERNAL;
+	      *result = NULL;
+	      return errno;
+	    }
+#endif /* need _res */
+#ifdef NEED__RES_HCONF
+	  _res_hconf_init ();
+#endif /* need _res_hconf */
+
+	  void *tmp_ptr = fct.l;
+#ifdef PTR_MANGLE
+	  PTR_MANGLE (tmp_ptr);
+#endif
+	  start_fct = tmp_ptr;
+	  tmp_ptr = nip;
+#ifdef PTR_MANGLE
+	  PTR_MANGLE (tmp_ptr);
+#endif
+	  startp = tmp_ptr;
+	}
+
+      /* Make sure start_fct and startp are written before
+	 startp_initialized.  */
+      atomic_write_barrier ();
+      startp_initialized = true;
+    }
+  else
+    {
+      fct.l = start_fct;
+      nip = startp;
+#ifdef PTR_DEMANGLE
+      PTR_DEMANGLE (fct.l);
+      PTR_DEMANGLE (nip);
+#endif
+      no_more = nip == (service_user *) -1l;
+    }
+
+  while (no_more == 0)
+    {
+#ifdef NEED_H_ERRNO
+      any_service = true;
+#endif
+
+      status = DL_CALL_FCT (fct.l, (ADD_VARIABLES, resbuf, buffer, buflen,
+				    &errno H_ERRNO_VAR EXTRA_VARIABLES));
+
+      /* The status is NSS_STATUS_TRYAGAIN and errno is ERANGE the
+	 provided buffer is too small.  In this case we should give
+	 the user the possibility to enlarge the buffer and we should
+	 not simply go on with the next service (even if the TRYAGAIN
+	 action tells us so).  */
+      if (status == NSS_STATUS_TRYAGAIN
+#ifdef NEED_H_ERRNO
+	  && *h_errnop == NETDB_INTERNAL
+#endif
+	  && errno == ERANGE)
+	break;
+
+      if (do_merge)
+	{
+
+	  if (status == NSS_STATUS_SUCCESS)
+	    {
+	      /* The previous loop saved a buffer for merging.
+		 Perform the merge now.  */
+	      err = MERGE_FN (&mergegrp, mergebuf, endptr, buflen, resbuf,
+			      buffer);
+	      CHECK_MERGE (err,status);
+	      do_merge = 0;
+	    }
+	  else
+	    {
+	      /* If the result wasn't SUCCESS, copy the saved buffer back
+	         into the result buffer and set the status back to
+	         NSS_STATUS_SUCCESS to match the previous pass through the
+	         loop.
+	          * If the next action is CONTINUE, it will overwrite the value
+	            currently in the buffer and return the new value.
+	          * If the next action is RETURN, we'll return the previously-
+	            acquired values.
+	          * If the next action is MERGE, then it will be added to the
+	            buffer saved from the previous source.  */
+	      err = DEEPCOPY_FN (mergegrp, buflen, resbuf, buffer, NULL);
+	      CHECK_MERGE (err, status);
+	      status = NSS_STATUS_SUCCESS;
+	    }
+	}
+
+      /* If we were are configured to merge this value with the next one,
+         save the current value of the group struct.  */
+      if (nss_next_action (nip, status) == NSS_ACTION_MERGE
+	  && status == NSS_STATUS_SUCCESS)
+	{
+	  /* Copy the current values into a buffer to be merged with the next
+	     set of retrieved values.  */
+	  if (mergebuf == NULL)
+	    {
+	      /* Only allocate once and reuse it for as many merges as we need
+	         to perform.  */
+	      mergebuf = malloc (buflen);
+	      if (mergebuf == NULL)
+		{
+		  __set_errno (ENOMEM);
+		  status = NSS_STATUS_UNAVAIL;
+		  break;
+		}
+	    }
+
+	  err = DEEPCOPY_FN (*resbuf, buflen, &mergegrp, mergebuf, &endptr);
+	  CHECK_MERGE (err, status);
+	  do_merge = 1;
+	}
+
+      no_more = __nss_next2 (&nip, REENTRANT_NAME_STRING,
+			     REENTRANT2_NAME_STRING, &fct.ptr, status, 0);
+    }
+  free (mergebuf);
+  mergebuf = NULL;
+
+#ifdef HANDLE_DIGITS_DOTS
+done:
+#endif
+  *result = status == NSS_STATUS_SUCCESS ? resbuf : NULL;
+#ifdef NEED_H_ERRNO
+  if (status == NSS_STATUS_UNAVAIL && !any_service && errno != ENOENT)
+    /* This happens when we weren't able to use a service for reasons other
+       than the module not being found.  In such a case, we'd want to tell the
+       caller that errno has the real reason for failure.  */
+    *h_errnop = NETDB_INTERNAL;
+  else if (status != NSS_STATUS_SUCCESS && !any_service)
+    /* We were not able to use any service.  */
+    *h_errnop = NO_RECOVERY;
+#endif
+#ifdef POSTPROCESS
+  POSTPROCESS;
+#endif
+
+  int res;
+  if (status == NSS_STATUS_SUCCESS || status == NSS_STATUS_NOTFOUND)
+    res = 0;
+  /* Don't pass back ERANGE if this is not for a too-small buffer.  */
+  else if (errno == ERANGE && status != NSS_STATUS_TRYAGAIN)
+    res = EINVAL;
+#ifdef NEED_H_ERRNO
+  /* These functions only set errno if h_errno is NETDB_INTERNAL.  */
+  else if (status == NSS_STATUS_TRYAGAIN && *h_errnop != NETDB_INTERNAL)
+    res = EAGAIN;
+#endif
+  else
+    return errno;
+
+  __set_errno (res);
+  return res;
+}
+
+
+#ifdef NO_COMPAT_NEEDED
+strong_alias (INTERNAL (REENTRANT_NAME), REENTRANT_NAME);
+#elif !defined FUNCTION2_NAME
+# include <shlib-compat.h>
+# if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_1_2)
+#  define OLD(name) OLD1 (name)
+#  define OLD1(name) __old_##name
+
+int
+attribute_compat_text_section
+OLD (REENTRANT_NAME) (ADD_PARAMS, LOOKUP_TYPE *resbuf, char *buffer,
+		      size_t buflen, LOOKUP_TYPE **result H_ERRNO_PARM)
+{
+  int ret = INTERNAL (REENTRANT_NAME) (ADD_VARIABLES, resbuf, buffer,
+				       buflen, result H_ERRNO_VAR);
+
+  if (ret != 0 || result == NULL)
+    ret = -1;
+
+  return ret;
+}
+
+#  define do_symbol_version(real, name, version) \
+  compat_symbol (libc, real, name, version)
+do_symbol_version (OLD (REENTRANT_NAME), REENTRANT_NAME, GLIBC_2_0);
+# endif
+
+/* As INTERNAL (REENTRANT_NAME) may be hidden, we need an alias
+   in between so that the REENTRANT_NAME@@GLIBC_2.1.2 is not
+   hidden too.  */
+strong_alias (INTERNAL (REENTRANT_NAME), NEW (REENTRANT_NAME));
+
+# define do_default_symbol_version(real, name, version) \
+  versioned_symbol (libc, real, name, version)
+do_default_symbol_version (NEW (REENTRANT_NAME),
+			   REENTRANT_NAME, GLIBC_2_1_2);
+#endif
+
+nss_interface_function (REENTRANT_NAME)
diff --git a/REORG.TODO/nss/getXXent.c b/REORG.TODO/nss/getXXent.c
new file mode 100644
index 0000000000..aad374197f
--- /dev/null
+++ b/REORG.TODO/nss/getXXent.c
@@ -0,0 +1,94 @@
+/* Copyright (C) 1996-2017 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, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <errno.h>
+#include <libc-lock.h>
+#include <stdlib.h>
+
+#include "nsswitch.h"
+
+/*******************************************************************\
+|* Here we assume several symbols to be defined:		   *|
+|*								   *|
+|* LOOKUP_TYPE   - the return type of the function		   *|
+|*								   *|
+|* GETFUNC_NAME  - name of the non-reentrant getXXXent function	   *|
+|*								   *|
+|* BUFLEN	 - size of static buffer			   *|
+|*								   *|
+|* Optionally the following vars can be defined:		   *|
+|*								   *|
+|* NEED_H_ERRNO  - an extra parameter will be passed to point to   *|
+|*		   the global `h_errno' variable.		   *|
+|*								   *|
+\*******************************************************************/
+
+/* To make the real sources a bit prettier.  */
+#define REENTRANT_GETNAME APPEND_R (GETFUNC_NAME)
+#define APPEND_R(name) APPEND_R1 (name)
+#define APPEND_R1(name) name##_r
+#define INTERNAL(name) INTERNAL1 (name)
+#define INTERNAL1(name) __##name
+
+/* Sometimes we need to store error codes in the `h_errno' variable.  */
+#ifdef NEED_H_ERRNO
+# define H_ERRNO_PARM , int *h_errnop
+# define H_ERRNO_VAR &h_errno
+#else
+# define H_ERRNO_PARM
+# define H_ERRNO_VAR NULL
+#endif
+
+/* Prototype of the reentrant version.  */
+extern int INTERNAL (REENTRANT_GETNAME) (LOOKUP_TYPE *resbuf, char *buffer,
+					 size_t buflen, LOOKUP_TYPE **result
+					 H_ERRNO_PARM);
+
+/* We need to protect the dynamic buffer handling.  */
+__libc_lock_define_initialized (static, lock);
+
+/* This points to the static buffer used.  */
+libc_freeres_ptr (static char *buffer);
+
+
+LOOKUP_TYPE *
+GETFUNC_NAME (void)
+{
+  static size_t buffer_size;
+  static union
+  {
+    LOOKUP_TYPE l;
+    void *ptr;
+  } resbuf;
+  LOOKUP_TYPE *result;
+  int save;
+
+  /* Get lock.  */
+  __libc_lock_lock (lock);
+
+  result = (LOOKUP_TYPE *)
+    __nss_getent ((getent_r_function) INTERNAL (REENTRANT_GETNAME),
+		  &resbuf.ptr, &buffer, BUFLEN, &buffer_size,
+		  H_ERRNO_VAR);
+
+  save = errno;
+  __libc_lock_unlock (lock);
+  __set_errno (save);
+  return result;
+}
+
+nss_interface_function (GETFUNC_NAME)
diff --git a/REORG.TODO/nss/getXXent_r.c b/REORG.TODO/nss/getXXent_r.c
new file mode 100644
index 0000000000..2710c1cd51
--- /dev/null
+++ b/REORG.TODO/nss/getXXent_r.c
@@ -0,0 +1,212 @@
+/* Copyright (C) 1996-2017 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, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <errno.h>
+#include <libc-lock.h>
+
+#include "nsswitch.h"
+
+/*******************************************************************\
+|* Here we assume several symbols to be defined:		   *|
+|* 								   *|
+|* LOOKUP_TYPE   - the return type of the function		   *|
+|* 								   *|
+|* SETFUNC_NAME  - name of the non-reentrant setXXXent function	   *|
+|* 								   *|
+|* GETFUNC_NAME  - name of the non-reentrant getXXXent function	   *|
+|* 								   *|
+|* ENDFUNC_NAME  - name of the non-reentrant endXXXent function	   *|
+|* 								   *|
+|* DATABASE_NAME - name of the database the function accesses	   *|
+|*		   (e.g., host, services, ...)			   *|
+|* 								   *|
+|* Optionally the following vars can be defined:		   *|
+|* 								   *|
+|* STAYOPEN      - variable declaration for setXXXent function	   *|
+|* 								   *|
+|* STAYOPEN_VAR  - variable name for setXXXent function		   *|
+|* 								   *|
+|* NEED_H_ERRNO  - an extra parameter will be passed to point to   *|
+|*		   the global `h_errno' variable.		   *|
+|* 								   *|
+\*******************************************************************/
+
+/* To make the real sources a bit prettier.  */
+#define REENTRANT_GETNAME APPEND_R (GETFUNC_NAME)
+#define APPEND_R(Name) CONCAT2_2 (Name, _r)
+#define INTERNAL(Name) CONCAT2_2 (__, Name)
+#define CONCAT2_1(Pre, Post) CONCAT2_2 (Pre, Post)
+#define CONCAT2_2(Pre, Post) Pre##Post
+#define NEW(name) NEW1 (name)
+#define NEW1(name) __new_##name
+
+#define SETFUNC_NAME_STRING STRINGIZE (SETFUNC_NAME)
+#define GETFUNC_NAME_STRING STRINGIZE (REENTRANT_GETNAME)
+#define ENDFUNC_NAME_STRING STRINGIZE (ENDFUNC_NAME)
+#define DATABASE_NAME_STRING STRINGIZE (DATABASE_NAME)
+#define STRINGIZE(Name) STRINGIZE1 (Name)
+#define STRINGIZE1(Name) #Name
+
+#ifndef DB_LOOKUP_FCT
+# define DB_LOOKUP_FCT CONCAT3_1 (__nss_, DATABASE_NAME, _lookup2)
+# define CONCAT3_1(Pre, Name, Post) CONCAT3_2 (Pre, Name, Post)
+# define CONCAT3_2(Pre, Name, Post) Pre##Name##Post
+#endif
+
+/* Sometimes we need to store error codes in the `h_errno' variable.  */
+#ifdef NEED_H_ERRNO
+# define H_ERRNO_PARM , int *h_errnop
+# define H_ERRNO_VAR , &h_errno
+# define H_ERRNO_VAR_P &h_errno
+#else
+# define H_ERRNO_PARM
+# define H_ERRNO_VAR
+# define H_ERRNO_VAR_P NULL
+#endif
+
+/* Some databases take the `stayopen' flag.  */
+#ifdef STAYOPEN
+# define STAYOPEN_TMP CONCAT2_1 (STAYOPEN, _tmp)
+# define STAYOPEN_TMPVAR &CONCAT2_1 (STAYOPEN_VAR, _tmp)
+#else
+# define STAYOPEN void
+# define STAYOPEN_VAR 0
+# define STAYOPEN_TMPVAR NULL
+#endif
+
+#ifndef NEED__RES
+# define NEED__RES 0
+#endif
+
+/* This handle for the NSS data base is shared between all
+   set/get/endXXXent functions.  */
+static service_user *nip;
+/* Remember the last service used since the last call to  `endXXent'.  */
+static service_user *last_nip;
+/* Remember the first service_entry, it's always the same.  */
+static service_user *startp;
+
+#ifdef STAYOPEN_TMP
+/* We need to remember the last `stayopen' flag given by the user
+   since the `setent' function is only called for the first available
+   service.  */
+static STAYOPEN_TMP;
+#endif
+
+/* Protect above variable against multiple uses at the same time.  */
+__libc_lock_define_initialized (static, lock)
+
+/* The lookup function for the first entry of this service.  */
+extern int DB_LOOKUP_FCT (service_user **nip, const char *name,
+			  const char *name2, void **fctp)
+     internal_function;
+libc_hidden_proto (DB_LOOKUP_FCT)
+
+void
+SETFUNC_NAME (STAYOPEN)
+{
+  int save;
+
+  __libc_lock_lock (lock);
+  __nss_setent (SETFUNC_NAME_STRING, DB_LOOKUP_FCT, &nip, &startp,
+		&last_nip, STAYOPEN_VAR, STAYOPEN_TMPVAR, NEED__RES);
+
+  save = errno;
+  __libc_lock_unlock (lock);
+  __set_errno (save);
+}
+
+
+void
+ENDFUNC_NAME (void)
+{
+  int save;
+
+  /* If the service has not been used before do not do anything.  */
+  if (startp != NULL)
+    {
+      __libc_lock_lock (lock);
+      __nss_endent (ENDFUNC_NAME_STRING, DB_LOOKUP_FCT, &nip, &startp,
+		    &last_nip, NEED__RES);
+      save = errno;
+      __libc_lock_unlock (lock);
+      __set_errno (save);
+    }
+}
+
+
+int
+INTERNAL (REENTRANT_GETNAME) (LOOKUP_TYPE *resbuf, char *buffer, size_t buflen,
+			      LOOKUP_TYPE **result H_ERRNO_PARM)
+{
+  int status;
+  int save;
+
+  __libc_lock_lock (lock);
+  status = __nss_getent_r (GETFUNC_NAME_STRING, SETFUNC_NAME_STRING,
+			   DB_LOOKUP_FCT, &nip, &startp, &last_nip,
+			   STAYOPEN_TMPVAR, NEED__RES, resbuf, buffer,
+			   buflen, (void **) result, H_ERRNO_VAR_P);
+  save = errno;
+  __libc_lock_unlock (lock);
+  __set_errno (save);
+  return status;
+}
+
+
+#ifdef NO_COMPAT_NEEDED
+strong_alias (INTERNAL (REENTRANT_GETNAME), REENTRANT_GETNAME);
+#else
+# include <shlib-compat.h>
+# if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_1_2)
+#  define OLD(name) OLD1 (name)
+#  define OLD1(name) __old_##name
+
+int
+attribute_compat_text_section
+OLD (REENTRANT_GETNAME) (LOOKUP_TYPE *resbuf, char *buffer, size_t buflen,
+			 LOOKUP_TYPE **result H_ERRNO_PARM)
+{
+  int ret = INTERNAL (REENTRANT_GETNAME) (resbuf, buffer, buflen,
+					  result H_ERRNO_VAR);
+
+  if (ret != 0)
+    ret = -1;
+
+  return ret;
+}
+
+#  define do_symbol_version(real, name, version) \
+  compat_symbol (libc, real, name, version)
+do_symbol_version (OLD (REENTRANT_GETNAME), REENTRANT_GETNAME, GLIBC_2_0);
+# endif
+
+/* As INTERNAL (REENTRANT_GETNAME) may be hidden, we need an alias
+   in between so that the REENTRANT_GETNAME@@GLIBC_2.1.2 is not
+   hidden too.  */
+strong_alias (INTERNAL (REENTRANT_GETNAME), NEW (REENTRANT_GETNAME));
+
+# define do_default_symbol_version(real, name, version) \
+  versioned_symbol (libc, real, name, version)
+do_default_symbol_version (NEW (REENTRANT_GETNAME),
+			   REENTRANT_GETNAME, GLIBC_2_1_2);
+#endif
+
+nss_interface_function (SETFUNC_NAME)
+nss_interface_function (ENDFUNC_NAME)
+nss_interface_function (REENTRANT_GETNAME)
diff --git a/REORG.TODO/nss/getent.c b/REORG.TODO/nss/getent.c
new file mode 100644
index 0000000000..8f8c3fe80a
--- /dev/null
+++ b/REORG.TODO/nss/getent.c
@@ -0,0 +1,960 @@
+/* Copyright (c) 1998-2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Thorsten Kukuk <kukuk@suse.de>, 1998.
+
+   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, see
+   <http://www.gnu.org/licenses/>.  */
+
+/* getent: get entries from administrative database.  */
+
+#include <aliases.h>
+#include <argp.h>
+#include <ctype.h>
+#include <error.h>
+#include <grp.h>
+#include <gshadow.h>
+#include <libintl.h>
+#include <locale.h>
+#include <mcheck.h>
+#include <netdb.h>
+#include <pwd.h>
+#include <shadow.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+#include <netinet/ether.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+
+/* Get libc version number.  */
+#include <version.h>
+
+#define PACKAGE _libc_intl_domainname
+
+/* Name and version of program.  */
+static void print_version (FILE *stream, struct argp_state *state);
+void (*argp_program_version_hook) (FILE *, struct argp_state *) = print_version;
+
+/* Short description of parameters.  */
+static const char args_doc[] = N_("database [key ...]");
+
+/* Supported options. */
+static const struct argp_option args_options[] =
+  {
+    { "service", 's', N_("CONFIG"), 0, N_("Service configuration to be used") },
+    { "no-idn", 'i', NULL, 0, N_("disable IDN encoding") },
+    { NULL, 0, NULL, 0, NULL },
+  };
+
+/* Short description of program.  */
+static const char doc[] = N_("Get entries from administrative database.");
+
+/* Prototype for option handler.  */
+static error_t parse_option (int key, char *arg, struct argp_state *state);
+
+/* Function to print some extra text in the help message.  */
+static char *more_help (int key, const char *text, void *input);
+
+/* Data structure to communicate with argp functions.  */
+static struct argp argp =
+  {
+    args_options, parse_option, args_doc, doc, NULL, more_help
+  };
+
+/* Additional getaddrinfo flags for IDN encoding.  */
+static int idn_flags = AI_IDN | AI_CANONIDN;
+
+/* Print the version information.  */
+static void
+print_version (FILE *stream, struct argp_state *state)
+{
+  fprintf (stream, "getent %s%s\n", PKGVERSION, VERSION);
+  fprintf (stream, gettext ("\
+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\
+"), "2017");
+  fprintf (stream, gettext ("Written by %s.\n"), "Thorsten Kukuk");
+}
+
+/* This is for aliases */
+static void
+print_aliases (struct aliasent *alias)
+{
+  unsigned int i = 0;
+
+  printf ("%s: ", alias->alias_name);
+  for  (i = strlen (alias->alias_name); i < 14; ++i)
+    fputs_unlocked (" ", stdout);
+
+  for (i = 0; i < alias->alias_members_len; ++i)
+    printf ("%s%s",
+	    alias->alias_members [i],
+	    i + 1 == alias->alias_members_len ? "\n" : ", ");
+}
+
+static int
+aliases_keys (int number, char *key[])
+{
+  int result = 0;
+  int i;
+  struct aliasent *alias;
+
+  if (number == 0)
+    {
+      setaliasent ();
+      while ((alias = getaliasent ()) != NULL)
+	print_aliases (alias);
+      endaliasent ();
+      return result;
+    }
+
+  for (i = 0; i < number; ++i)
+    {
+      alias = getaliasbyname (key[i]);
+
+      if (alias == NULL)
+	result = 2;
+      else
+	print_aliases (alias);
+    }
+
+  return result;
+}
+
+/* This is for ethers */
+static int
+ethers_keys (int number, char *key[])
+{
+  int result = 0;
+  int i;
+
+  if (number == 0)
+    {
+      fprintf (stderr, _("Enumeration not supported on %s\n"), "ethers");
+      return 3;
+    }
+
+  for (i = 0; i < number; ++i)
+    {
+      struct ether_addr *ethp, eth;
+      char buffer [1024], *p;
+
+      ethp = ether_aton (key[i]);
+      if (ethp != NULL)
+	{
+	  if (ether_ntohost (buffer, ethp))
+	    {
+	      result = 2;
+	      continue;
+	    }
+	  p = buffer;
+	}
+      else
+	{
+	  if (ether_hostton (key[i], &eth))
+	    {
+	      result = 2;
+	      continue;
+	    }
+	  p = key[i];
+	  ethp = &eth;
+	}
+      printf ("%s %s\n", ether_ntoa (ethp), p);
+    }
+
+  return result;
+}
+
+/* This is for group */
+static void
+print_group (struct group *grp)
+{
+  if (putgrent (grp, stdout) != 0)
+    fprintf (stderr, "error writing group entry: %m\n");
+}
+
+static int
+group_keys (int number, char *key[])
+{
+  int result = 0;
+  int i;
+  struct group *grp;
+
+  if (number == 0)
+    {
+      setgrent ();
+      while ((grp = getgrent ()) != NULL)
+	print_group (grp);
+      endgrent ();
+      return result;
+    }
+
+  for (i = 0; i < number; ++i)
+    {
+      errno = 0;
+      char *ep;
+      gid_t arg_gid = strtoul(key[i], &ep, 10);
+
+      if (errno != EINVAL && *key[i] != '\0' && *ep == '\0')
+	/* Valid numeric gid.  */
+	grp = getgrgid (arg_gid);
+      else
+	grp = getgrnam (key[i]);
+
+      if (grp == NULL)
+	result = 2;
+      else
+	print_group (grp);
+    }
+
+  return result;
+}
+
+/* This is for gshadow */
+static void
+print_gshadow (struct sgrp *sg)
+{
+  if (putsgent (sg, stdout) != 0)
+    fprintf (stderr, "error writing gshadow entry: %m\n");
+}
+
+static int
+gshadow_keys (int number, char *key[])
+{
+  int result = 0;
+  int i;
+
+  if (number == 0)
+    {
+      struct sgrp *sg;
+
+      setsgent ();
+      while ((sg = getsgent ()) != NULL)
+	print_gshadow (sg);
+      endsgent ();
+      return result;
+    }
+
+  for (i = 0; i < number; ++i)
+    {
+      struct sgrp *sg;
+
+      sg = getsgnam (key[i]);
+
+      if (sg == NULL)
+	result = 2;
+      else
+	print_gshadow (sg);
+    }
+
+  return result;
+}
+
+/* This is for hosts */
+static void
+print_hosts (struct hostent *host)
+{
+  unsigned int cnt;
+
+  for (cnt = 0; host->h_addr_list[cnt] != NULL; ++cnt)
+    {
+      char buf[INET6_ADDRSTRLEN];
+      const char *ip = inet_ntop (host->h_addrtype, host->h_addr_list[cnt],
+				  buf, sizeof (buf));
+
+      printf ("%-15s %s", ip, host->h_name);
+
+      unsigned int i;
+      for (i = 0; host->h_aliases[i] != NULL; ++i)
+	{
+	  putchar_unlocked (' ');
+	  fputs_unlocked (host->h_aliases[i], stdout);
+	}
+      putchar_unlocked ('\n');
+    }
+}
+
+static int
+hosts_keys (int number, char *key[])
+{
+  int result = 0;
+  int i;
+  struct hostent *host;
+
+  if (number == 0)
+    {
+      sethostent (0);
+      while ((host = gethostent ()) != NULL)
+	print_hosts (host);
+      endhostent ();
+      return result;
+    }
+
+  for (i = 0; i < number; ++i)
+    {
+      struct hostent *host = NULL;
+      char addr[IN6ADDRSZ];
+
+      if (inet_pton (AF_INET6, key[i], &addr) > 0)
+	host = gethostbyaddr (addr, IN6ADDRSZ, AF_INET6);
+      else if (inet_pton (AF_INET, key[i], &addr) > 0)
+	host = gethostbyaddr (addr, INADDRSZ, AF_INET);
+      else if ((host = gethostbyname2 (key[i], AF_INET6)) == NULL)
+	host = gethostbyname2 (key[i], AF_INET);
+
+      if (host == NULL)
+	result = 2;
+      else
+	print_hosts (host);
+    }
+
+  return result;
+}
+
+/* This is for hosts, but using getaddrinfo */
+static int
+ahosts_keys_int (int af, int xflags, int number, char *key[])
+{
+  int result = 0;
+  int i;
+  struct hostent *host;
+
+  if (number == 0)
+    {
+      sethostent (0);
+      while ((host = gethostent ()) != NULL)
+	print_hosts (host);
+      endhostent ();
+      return result;
+    }
+
+  struct addrinfo hint;
+  memset (&hint, '\0', sizeof (hint));
+  hint.ai_flags = (AI_V4MAPPED | AI_ADDRCONFIG | AI_CANONNAME
+		   | idn_flags | xflags);
+  hint.ai_family = af;
+
+  for (i = 0; i < number; ++i)
+    {
+      struct addrinfo *res;
+
+      if (getaddrinfo (key[i], NULL, &hint, &res) != 0)
+	result = 2;
+      else
+	{
+	  struct addrinfo *runp = res;
+
+	  while (runp != NULL)
+	    {
+	      char sockbuf[20];
+	      const char *sockstr;
+	      if (runp->ai_socktype == SOCK_STREAM)
+		sockstr = "STREAM";
+	      else if (runp->ai_socktype == SOCK_DGRAM)
+		sockstr = "DGRAM";
+	      else if (runp->ai_socktype == SOCK_RAW)
+		sockstr = "RAW";
+#ifdef SOCK_SEQPACKET
+	      else if (runp->ai_socktype == SOCK_SEQPACKET)
+		sockstr = "SEQPACKET";
+#endif
+#ifdef SOCK_RDM
+	      else if (runp->ai_socktype == SOCK_RDM)
+		sockstr = "RDM";
+#endif
+#ifdef SOCK_DCCP
+	      else if (runp->ai_socktype == SOCK_DCCP)
+		sockstr = "DCCP";
+#endif
+#ifdef SOCK_PACKET
+	      else if (runp->ai_socktype == SOCK_PACKET)
+		sockstr = "PACKET";
+#endif
+	      else
+		{
+		  snprintf (sockbuf, sizeof (sockbuf), "%d",
+			    runp->ai_socktype);
+		  sockstr = sockbuf;
+		}
+
+	      char buf[INET6_ADDRSTRLEN];
+	      printf ("%-15s %-6s %s\n",
+		      inet_ntop (runp->ai_family,
+				 runp->ai_family == AF_INET
+				 ? (void *) &((struct sockaddr_in *) runp->ai_addr)->sin_addr
+				 : (void *) &((struct sockaddr_in6 *) runp->ai_addr)->sin6_addr,
+				 buf, sizeof (buf)),
+		      sockstr,
+		      runp->ai_canonname ?: "");
+
+	      runp = runp->ai_next;
+	    }
+
+	  freeaddrinfo (res);
+	}
+    }
+
+  return result;
+}
+
+static int
+ahosts_keys (int number, char *key[])
+{
+  return ahosts_keys_int (AF_UNSPEC, 0, number, key);
+}
+
+static int
+ahostsv4_keys (int number, char *key[])
+{
+  return ahosts_keys_int (AF_INET, 0, number, key);
+}
+
+static int
+ahostsv6_keys (int number, char *key[])
+{
+  return ahosts_keys_int (AF_INET6, AI_V4MAPPED, number, key);
+}
+
+/* This is for netgroup */
+static int
+netgroup_keys (int number, char *key[])
+{
+  int result = 0;
+
+  if (number == 0)
+    {
+      fprintf (stderr, _("Enumeration not supported on %s\n"), "netgroup");
+      return 3;
+    }
+
+  if (number == 4)
+    {
+      char *host = strcmp (key[1], "*") == 0 ? NULL : key[1];
+      char *user = strcmp (key[2], "*") == 0 ? NULL : key[2];
+      char *domain = strcmp (key[3], "*") == 0 ? NULL : key[3];
+
+      printf ("%-21s (%s,%s,%s) = %d\n",
+	      key[0], host ?: "", user ?: "", domain ?: "",
+	      innetgr (key[0], host, user, domain));
+    }
+  else if (number == 1)
+    {
+      if (!setnetgrent (key[0]))
+	result = 2;
+      else
+	{
+	  char *p[3];
+
+	  printf ("%-21s", key[0]);
+
+	  while (getnetgrent (p, p + 1, p + 2))
+	    printf (" (%s,%s,%s)", p[0] ?: " ", p[1] ?: "", p[2] ?: "");
+	  putchar_unlocked ('\n');
+	}
+    }
+
+  endnetgrent ();
+
+  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);
+
+  if (number == 0)
+    {
+      fprintf (stderr, _("Enumeration not supported on %s\n"), "initgroups");
+      return 3;
+    }
+
+  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)
+{
+  unsigned int i;
+  struct in_addr ip;
+  ip.s_addr = htonl (net->n_net);
+
+  printf ("%-21s %s", net->n_name, inet_ntoa (ip));
+
+  i = 0;
+  while (net->n_aliases[i] != NULL)
+    {
+      putchar_unlocked (' ');
+      fputs_unlocked (net->n_aliases[i], stdout);
+      ++i;
+    }
+  putchar_unlocked ('\n');
+}
+
+static int
+networks_keys (int number, char *key[])
+{
+  int result = 0;
+  int i;
+  struct netent *net;
+
+  if (number == 0)
+    {
+      setnetent (0);
+      while ((net = getnetent ()) != NULL)
+	print_networks (net);
+      endnetent ();
+      return result;
+    }
+
+  for (i = 0; i < number; ++i)
+    {
+      if (isdigit (key[i][0]))
+	net = getnetbyaddr (ntohl (inet_addr (key[i])), AF_UNSPEC);
+      else
+	net = getnetbyname (key[i]);
+
+      if (net == NULL)
+	result = 2;
+      else
+	print_networks (net);
+    }
+
+  return result;
+}
+
+/* Now is all for passwd */
+static void
+print_passwd (struct passwd *pwd)
+{
+  if (putpwent (pwd, stdout) != 0)
+    fprintf (stderr, "error writing passwd entry: %m\n");
+}
+
+static int
+passwd_keys (int number, char *key[])
+{
+  int result = 0;
+  int i;
+  struct passwd *pwd;
+
+  if (number == 0)
+    {
+      setpwent ();
+      while ((pwd = getpwent ()) != NULL)
+	print_passwd (pwd);
+      endpwent ();
+      return result;
+    }
+
+  for (i = 0; i < number; ++i)
+    {
+      errno = 0;
+      char *ep;
+      uid_t arg_uid = strtoul(key[i], &ep, 10);
+
+      if (errno != EINVAL && *key[i] != '\0' && *ep == '\0')
+	/* Valid numeric uid.  */
+	pwd = getpwuid (arg_uid);
+      else
+	pwd = getpwnam (key[i]);
+
+      if (pwd == NULL)
+	result = 2;
+      else
+	print_passwd (pwd);
+    }
+
+  return result;
+}
+
+/* This is for protocols */
+static void
+print_protocols (struct protoent *proto)
+{
+  unsigned int i;
+
+  printf ("%-21s %d", proto->p_name, proto->p_proto);
+
+  i = 0;
+  while (proto->p_aliases[i] != NULL)
+    {
+      putchar_unlocked (' ');
+      fputs_unlocked (proto->p_aliases[i], stdout);
+      ++i;
+    }
+  putchar_unlocked ('\n');
+}
+
+static int
+protocols_keys (int number, char *key[])
+{
+  int result = 0;
+  int i;
+  struct protoent *proto;
+
+  if (number == 0)
+    {
+      setprotoent (0);
+      while ((proto = getprotoent ()) != NULL)
+	print_protocols (proto);
+      endprotoent ();
+      return result;
+    }
+
+  for (i = 0; i < number; ++i)
+    {
+      if (isdigit (key[i][0]))
+	proto = getprotobynumber (atol (key[i]));
+      else
+	proto = getprotobyname (key[i]);
+
+      if (proto == NULL)
+	result = 2;
+      else
+	print_protocols (proto);
+    }
+
+  return result;
+}
+
+#if HAVE_SUNRPC
+/* Now is all for rpc */
+static void
+print_rpc (struct rpcent *rpc)
+{
+  int i;
+
+  printf ("%-15s %d%s",
+	  rpc->r_name, rpc->r_number, rpc->r_aliases[0] ? " " : "");
+
+  for (i = 0; rpc->r_aliases[i]; ++i)
+    printf (" %s", rpc->r_aliases[i]);
+  putchar_unlocked ('\n');
+}
+
+static int
+rpc_keys (int number, char *key[])
+{
+  int result = 0;
+  int i;
+  struct rpcent *rpc;
+
+  if (number == 0)
+    {
+      setrpcent (0);
+      while ((rpc = getrpcent ()) != NULL)
+	print_rpc (rpc);
+      endrpcent ();
+      return result;
+    }
+
+  for (i = 0; i < number; ++i)
+    {
+      if (isdigit (key[i][0]))
+	rpc = getrpcbynumber (atol (key[i]));
+      else
+	rpc = getrpcbyname (key[i]);
+
+      if (rpc == NULL)
+	result = 2;
+      else
+	print_rpc (rpc);
+    }
+
+  return result;
+}
+#endif
+
+/* for services */
+static void
+print_services (struct servent *serv)
+{
+  unsigned int i;
+
+  printf ("%-21s %d/%s", serv->s_name, ntohs (serv->s_port), serv->s_proto);
+
+  i = 0;
+  while (serv->s_aliases[i] != NULL)
+    {
+      putchar_unlocked (' ');
+      fputs_unlocked (serv->s_aliases[i], stdout);
+      ++i;
+    }
+  putchar_unlocked ('\n');
+}
+
+static int
+services_keys (int number, char *key[])
+{
+  int result = 0;
+  int i;
+  struct servent *serv;
+
+  if (!number)
+    {
+      setservent (0);
+      while ((serv = getservent ()) != NULL)
+	print_services (serv);
+      endservent ();
+      return result;
+    }
+
+  for (i = 0; i < number; ++i)
+    {
+      struct servent *serv;
+      char *proto = strchr (key[i], '/');
+
+      if (proto != NULL)
+	*proto++ = '\0';
+
+      char *endptr;
+      long port = strtol (key[i], &endptr, 10);
+
+      if (isdigit (key[i][0]) && *endptr == '\0'
+	  && 0 <= port && port <= 65535)
+	serv = getservbyport (htons (port), proto);
+      else
+	serv = getservbyname (key[i], proto);
+
+      if (serv == NULL)
+	result = 2;
+      else
+	print_services (serv);
+    }
+
+  return result;
+}
+
+/* This is for shadow */
+static void
+print_shadow (struct spwd *sp)
+{
+  if (putspent (sp, stdout) != 0)
+    fprintf (stderr, "error writing shadow entry: %m\n");
+}
+
+static int
+shadow_keys (int number, char *key[])
+{
+  int result = 0;
+  int i;
+
+  if (number == 0)
+    {
+      struct spwd *sp;
+
+      setspent ();
+      while ((sp = getspent ()) != NULL)
+	print_shadow (sp);
+      endspent ();
+      return result;
+    }
+
+  for (i = 0; i < number; ++i)
+    {
+      struct spwd *sp;
+
+      sp = getspnam (key[i]);
+
+      if (sp == NULL)
+	result = 2;
+      else
+	print_shadow (sp);
+    }
+
+  return result;
+}
+
+struct
+  {
+    const char *name;
+    int (*func) (int number, char *key[]);
+  } databases[] =
+  {
+#define D(name) { #name, name ## _keys },
+D(ahosts)
+D(ahostsv4)
+D(ahostsv6)
+D(aliases)
+D(ethers)
+D(group)
+D(gshadow)
+D(hosts)
+D(initgroups)
+D(netgroup)
+D(networks)
+D(passwd)
+D(protocols)
+#if HAVE_SUNRPC
+D(rpc)
+#endif
+D(services)
+D(shadow)
+#undef D
+    { NULL, NULL }
+  };
+
+/* Handle arguments found by argp. */
+static error_t
+parse_option (int key, char *arg, struct argp_state *state)
+{
+  char *endp;
+  switch (key)
+    {
+    case 's':
+      endp = strchr (arg, ':');
+      if (endp == NULL)
+	/* No specific database, change them all.  */
+	for (int i = 0; databases[i].name != NULL; ++i)
+	  __nss_configure_lookup (databases[i].name, arg);
+      else
+	{
+	  int i;
+	  for (i = 0; databases[i].name != NULL; ++i)
+	    if (strncmp (databases[i].name, arg, endp - arg) == 0)
+	      {
+		__nss_configure_lookup (databases[i].name, endp + 1);
+		break;
+	      }
+	  if (databases[i].name == NULL)
+	    error (EXIT_FAILURE, 0, gettext ("Unknown database name"));
+	}
+      break;
+
+    case 'i':
+      idn_flags = 0;
+      break;
+
+    default:
+      return ARGP_ERR_UNKNOWN;
+    }
+
+  return 0;
+}
+
+
+static char *
+more_help (int key, const char *text, void *input)
+{
+  switch (key)
+    {
+      size_t len;
+      char *doc;
+      FILE *fp;
+
+    case ARGP_KEY_HELP_EXTRA:
+      /* We print some extra information.  */
+      fp = open_memstream (&doc, &len);
+      if (fp != NULL)
+	{
+	  fputs_unlocked (_("Supported databases:\n"), fp);
+
+	  for (int i = 0, col = 0; databases[i].name != NULL; ++i)
+	    {
+	      len = strlen (databases[i].name);
+	      if (i != 0)
+		{
+		  if (col + len > 72)
+		    {
+		      col = 0;
+		      fputc_unlocked ('\n', fp);
+		    }
+		  else
+		    fputc_unlocked (' ', fp);
+		}
+
+	      fputs_unlocked (databases[i].name, fp);
+	      col += len + 1;
+	    }
+
+	  fputs ("\n\n", fp);
+
+	  fprintf (fp, gettext ("\
+For bug reporting instructions, please see:\n\
+%s.\n"), REPORT_BUGS_TO);
+
+	  if (fclose (fp) == 0)
+	    return doc;
+	}
+      break;
+
+    default:
+      break;
+    }
+  return (char *) text;
+}
+
+
+/* the main function */
+int
+main (int argc, char *argv[])
+{
+  /* Debugging support.  */
+  mtrace ();
+
+  /* Set locale via LC_ALL.  */
+  setlocale (LC_ALL, "");
+  /* Set the text message domain.  */
+  textdomain (PACKAGE);
+
+  /* Parse and process arguments.  */
+  int remaining;
+  argp_parse (&argp, argc, argv, 0, &remaining, NULL);
+
+  if ((argc - remaining) < 1)
+    {
+      error (0, 0, gettext ("wrong number of arguments"));
+      argp_help (&argp, stdout, ARGP_HELP_SEE, program_invocation_short_name);
+      return 1;
+    }
+
+  for (int i = 0; databases[i].name; ++i)
+    if (argv[remaining][0] == databases[i].name[0]
+	&& !strcmp (argv[remaining], databases[i].name))
+      return databases[i].func (argc - remaining - 1, &argv[remaining + 1]);
+
+  fprintf (stderr, _("Unknown database: %s\n"), argv[remaining]);
+  argp_help (&argp, stdout, ARGP_HELP_SEE, program_invocation_short_name);
+  return 1;
+}
diff --git a/REORG.TODO/nss/getnssent.c b/REORG.TODO/nss/getnssent.c
new file mode 100644
index 0000000000..fdaeed1e7b
--- /dev/null
+++ b/REORG.TODO/nss/getnssent.c
@@ -0,0 +1,57 @@
+/* Copyright (C) 2000-2017 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, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <netdb.h>
+#include "nsswitch.h"
+
+void *
+__nss_getent (getent_r_function func, void **resbuf, char **buffer,
+	      size_t buflen, size_t *buffer_size, int *h_errnop)
+{
+  void *result;
+
+  if (*buffer == NULL)
+    {
+      *buffer_size = buflen;
+      *buffer = malloc (*buffer_size);
+    }
+
+  while (*buffer != NULL
+	 && func (resbuf, *buffer, *buffer_size, &result, h_errnop) == ERANGE
+	 && (h_errnop == NULL || *h_errnop == NETDB_INTERNAL))
+    {
+      char *new_buf;
+      *buffer_size *= 2;
+      new_buf = realloc (*buffer, *buffer_size);
+      if (new_buf == NULL)
+	{
+	  /* We are out of memory.  Free the current buffer so that the
+	     process gets a chance for a normal termination.  */
+	  int save = errno;
+	  free (*buffer);
+	  __set_errno (save);
+	}
+      *buffer = new_buf;
+    }
+
+  if (*buffer == NULL)
+    result = NULL;
+
+  return result;
+}
diff --git a/REORG.TODO/nss/getnssent_r.c b/REORG.TODO/nss/getnssent_r.c
new file mode 100644
index 0000000000..5fdbf3be00
--- /dev/null
+++ b/REORG.TODO/nss/getnssent_r.c
@@ -0,0 +1,236 @@
+/* Copyright (C) 2000-2017 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, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <errno.h>
+#include <netdb.h>
+#include "nsswitch.h"
+
+/* Set up NIP to run through the services.  If ALL is zero, use NIP's
+   current location if it's not nil.  Return nonzero if there are no
+   services (left).  */
+static int
+setup (const char *func_name, db_lookup_function lookup_fct,
+       void **fctp, service_user **nip, service_user **startp, int all)
+{
+  int no_more;
+  if (*startp == NULL)
+    {
+      no_more = lookup_fct (nip, func_name, NULL, fctp);
+      *startp = no_more ? (service_user *) -1l : *nip;
+    }
+  else if (*startp == (service_user *) -1l)
+    /* No services at all.  */
+    return 1;
+  else
+    {
+      if (all || !*nip)
+	/* Reset to the beginning of the service list.  */
+	*nip = *startp;
+      /* Look up the first function.  */
+      no_more = __nss_lookup (nip, func_name, NULL, fctp);
+    }
+  return no_more;
+}
+
+void
+__nss_setent (const char *func_name, db_lookup_function lookup_fct,
+	      service_user **nip, service_user **startp,
+	      service_user **last_nip, int stayopen, int *stayopen_tmp,
+	      int res)
+{
+  union
+  {
+    setent_function f;
+    void *ptr;
+  } fct;
+  int no_more;
+
+  if (res && __res_maybe_init (&_res, 0) == -1)
+    {
+      __set_h_errno (NETDB_INTERNAL);
+      return;
+    }
+
+  /* Cycle through the services and run their `setXXent' functions until
+     we find an available service.  */
+  no_more = setup (func_name, lookup_fct, &fct.ptr, nip,
+		   startp, 1);
+  while (! no_more)
+    {
+      int is_last_nip = *nip == *last_nip;
+      enum nss_status status;
+
+      if (stayopen_tmp)
+	status = DL_CALL_FCT (fct.f, (*stayopen_tmp));
+      else
+	status = DL_CALL_FCT (fct.f, (0));
+
+
+      /* This is a special-case.  When [SUCCESS=merge] is in play,
+         _nss_next2() will skip to the next database.  Due to the
+         implementation of that function, we can't know whether we're
+         in an enumeration or an individual lookup, which behaves
+         differently with regards to merging.  We'll treat SUCCESS as
+         an indication to start the enumeration at this database. */
+      if (nss_next_action (*nip, status) == NSS_ACTION_MERGE)
+	no_more = 1;
+      else
+	no_more = __nss_next2 (nip, func_name, NULL, &fct.ptr, status, 0);
+
+      if (is_last_nip)
+	*last_nip = *nip;
+    }
+
+  if (stayopen_tmp)
+    *stayopen_tmp = stayopen;
+}
+
+
+void
+__nss_endent (const char *func_name, db_lookup_function lookup_fct,
+	      service_user **nip, service_user **startp,
+	      service_user **last_nip, int res)
+{
+  union
+  {
+    endent_function f;
+    void *ptr;
+  } fct;
+  int no_more;
+
+  if (res && __res_maybe_init (&_res, 0) == -1)
+    {
+      __set_h_errno (NETDB_INTERNAL);
+      return;
+    }
+
+  /* Cycle through all the services and run their endXXent functions.  */
+  no_more = setup (func_name, lookup_fct, &fct.ptr, nip, startp, 1);
+  while (! no_more)
+    {
+      /* Ignore status, we force check in __NSS_NEXT.  */
+      DL_CALL_FCT (fct.f, ());
+
+      if (*nip == *last_nip)
+	/* We have processed all services which were used.  */
+	break;
+
+      no_more = __nss_next2 (nip, func_name, NULL, &fct.ptr, 0, 1);
+    }
+  *last_nip = *nip = NULL;
+}
+
+
+int
+__nss_getent_r (const char *getent_func_name,
+		const char *setent_func_name,
+		db_lookup_function lookup_fct,
+		service_user **nip, service_user **startp,
+		service_user **last_nip, int *stayopen_tmp, int res,
+		void *resbuf, char *buffer, size_t buflen,
+		void **result, int *h_errnop)
+{
+  union
+  {
+    getent_function f;
+    void *ptr;
+  } fct;
+  int no_more;
+  enum nss_status status;
+
+  if (res && __res_maybe_init (&_res, 0) == -1)
+    {
+      *h_errnop = NETDB_INTERNAL;
+      *result = NULL;
+      return errno;
+    }
+
+  /* Initialize status to return if no more functions are found.  */
+  status = NSS_STATUS_NOTFOUND;
+
+  /* Run through available functions, starting with the same function last
+     run.  We will repeat each function as long as it succeeds, and then go
+     on to the next service action.  */
+  no_more = setup (getent_func_name, lookup_fct, &fct.ptr, nip,
+		   startp, 0);
+  while (! no_more)
+    {
+      int is_last_nip = *nip == *last_nip;
+
+      status = DL_CALL_FCT (fct.f,
+			    (resbuf, buffer, buflen, &errno, &h_errno));
+
+      /* The status is NSS_STATUS_TRYAGAIN and errno is ERANGE the
+	 provided buffer is too small.  In this case we should give
+	 the user the possibility to enlarge the buffer and we should
+	 not simply go on with the next service (even if the TRYAGAIN
+	 action tells us so).  */
+      if (status == NSS_STATUS_TRYAGAIN
+	  && (h_errnop == NULL || *h_errnop == NETDB_INTERNAL)
+	  && errno == ERANGE)
+	break;
+
+      do
+	{
+        /* This is a special-case.  When [SUCCESS=merge] is in play,
+           _nss_next2() will skip to the next database.  Due to the
+           implementation of that function, we can't know whether we're
+           in an enumeration or an individual lookup, which behaves
+           differently with regards to merging.  We'll treat SUCCESS as
+           an indication to return the results here. */
+	  if (status == NSS_STATUS_SUCCESS
+	      && nss_next_action (*nip, status) == NSS_ACTION_MERGE)
+	    no_more = 1;
+	  else
+	    no_more = __nss_next2 (nip, getent_func_name, NULL, &fct.ptr,
+				   status, 0);
+
+	  if (is_last_nip)
+	    *last_nip = *nip;
+
+	  if (! no_more)
+	    {
+	      /* Call the `setXXent' function.  This wasn't done before.  */
+	      union
+	      {
+		setent_function f;
+		void *ptr;
+	      } sfct;
+
+	      no_more = __nss_lookup (nip, setent_func_name, NULL, &sfct.ptr);
+
+	      if (! no_more)
+	        {
+		  if (stayopen_tmp)
+		    status = DL_CALL_FCT (sfct.f, (*stayopen_tmp));
+		  else
+		    status = DL_CALL_FCT (sfct.f, (0));
+		}
+	      else
+		status = NSS_STATUS_NOTFOUND;
+	    }
+	}
+      while (! no_more && status != NSS_STATUS_SUCCESS);
+    }
+
+  *result = status == NSS_STATUS_SUCCESS ? resbuf : NULL;
+  return (status == NSS_STATUS_SUCCESS ? 0
+	  : status != NSS_STATUS_TRYAGAIN ? ENOENT
+	  /* h_errno functions only set errno if h_errno is NETDB_INTERNAL.  */
+	  : (h_errnop == NULL || *h_errnop == NETDB_INTERNAL) ? errno
+	  : EAGAIN);
+}
diff --git a/REORG.TODO/nss/grp-lookup.c b/REORG.TODO/nss/grp-lookup.c
new file mode 100644
index 0000000000..8cb00aa22f
--- /dev/null
+++ b/REORG.TODO/nss/grp-lookup.c
@@ -0,0 +1,22 @@
+/* Copyright (C) 1996-2017 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, see
+   <http://www.gnu.org/licenses/>.  */
+
+#define DATABASE_NAME group
+#define DEFAULT_CONFIG "compat [NOTFOUND=return] files"
+
+#include "XXX-lookup.c"
diff --git a/REORG.TODO/nss/hosts-lookup.c b/REORG.TODO/nss/hosts-lookup.c
new file mode 100644
index 0000000000..9fdf958a97
--- /dev/null
+++ b/REORG.TODO/nss/hosts-lookup.c
@@ -0,0 +1,22 @@
+/* Copyright (C) 1996-2017 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, see
+   <http://www.gnu.org/licenses/>.  */
+
+#define DATABASE_NAME hosts
+#define DEFAULT_CONFIG "dns [!UNAVAIL=return] files"
+
+#include "XXX-lookup.c"
diff --git a/REORG.TODO/nss/key-lookup.c b/REORG.TODO/nss/key-lookup.c
new file mode 100644
index 0000000000..cce0ddf1e7
--- /dev/null
+++ b/REORG.TODO/nss/key-lookup.c
@@ -0,0 +1,22 @@
+/* Copyright (C) 1996-2017 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, see
+   <http://www.gnu.org/licenses/>.  */
+
+#define DATABASE_NAME publickey
+#define DEFAULT_CONFIG "nis nisplus"
+
+#include "XXX-lookup.c"
diff --git a/REORG.TODO/nss/makedb.c b/REORG.TODO/nss/makedb.c
new file mode 100644
index 0000000000..542244dd35
--- /dev/null
+++ b/REORG.TODO/nss/makedb.c
@@ -0,0 +1,879 @@
+/* Create simple DB database from textual input.
+   Copyright (C) 1996-2017 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, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <argp.h>
+#include <assert.h>
+#include <ctype.h>
+#include <errno.h>
+#include <error.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <libintl.h>
+#include <locale.h>
+#include <search.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <sys/mman.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/uio.h>
+#include "nss_db/nss_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
+
+#ifndef MAP_POPULATE
+# define MAP_POPULATE 0
+#endif
+
+#define PACKAGE _libc_intl_domainname
+
+/* List of data bases.  */
+struct database
+{
+  char dbid;
+  bool extra_string;
+  struct database *next;
+  void *entries;
+  size_t nentries;
+  size_t nhashentries;
+  stridx_t *hashtable;
+  size_t keystrlen;
+  stridx_t *keyidxtab;
+  char *keystrtab;
+} *databases;
+static size_t ndatabases;
+static size_t nhashentries_total;
+static size_t valstrlen;
+static void *valstrtree;
+static char *valstrtab;
+static size_t extrastrlen;
+
+/* Database entry.  */
+struct dbentry
+{
+  stridx_t validx;
+  uint32_t hashval;
+  char str[0];
+};
+
+/* Stored string entry.  */
+struct valstrentry
+{
+  stridx_t idx;
+  bool extra_string;
+  char str[0];
+};
+
+
+/* True if any entry has been added.  */
+static bool any_dbentry;
+
+/* If non-zero convert key to lower case.  */
+static int to_lowercase;
+
+/* If non-zero print content of input file, one entry per line.  */
+static int do_undo;
+
+/* If non-zero do not print informational messages.  */
+static int be_quiet;
+
+/* Name of output file.  */
+static const char *output_name;
+
+/* Name and version of program.  */
+static void print_version (FILE *stream, struct argp_state *state);
+void (*argp_program_version_hook) (FILE *, struct argp_state *) = print_version;
+
+/* Definitions of arguments for argp functions.  */
+static const struct argp_option options[] =
+{
+  { "fold-case", 'f', NULL, 0, N_("Convert key to lower case") },
+  { "output", 'o', N_("NAME"), 0, N_("Write output to file NAME") },
+  { "quiet", 'q', NULL, 0,
+    N_("Do not print messages while building database") },
+  { "undo", 'u', NULL, 0,
+    N_("Print content of database file, one entry a line") },
+  { "generated", 'g', N_("CHAR"), 0,
+    N_("Generated line not part of iteration") },
+  { NULL, 0, NULL, 0, NULL }
+};
+
+/* Short description of program.  */
+static const char doc[] = N_("Create simple database from textual input.");
+
+/* Strings for arguments in help texts.  */
+static const char args_doc[] = N_("\
+INPUT-FILE OUTPUT-FILE\n-o OUTPUT-FILE INPUT-FILE\n-u INPUT-FILE");
+
+/* Prototype for option handler.  */
+static error_t parse_opt (int key, char *arg, struct argp_state *state);
+
+/* Function to print some extra text in the help message.  */
+static char *more_help (int key, const char *text, void *input);
+
+/* Data structure to communicate with argp functions.  */
+static struct argp argp =
+{
+  options, parse_opt, args_doc, doc, NULL, more_help
+};
+
+
+/* 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);
+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.  */
+#include <programs/xmalloc.h>
+
+
+int
+main (int argc, char *argv[])
+{
+  const char *input_name;
+  FILE *input_file;
+  int remaining;
+  int mode = 0644;
+
+  /* Set locale via LC_ALL.  */
+  setlocale (LC_ALL, "");
+
+  /* Set the text message domain.  */
+  textdomain (_libc_intl_domainname);
+
+  /* Initialize local variables.  */
+  input_name = NULL;
+
+  /* Parse and process arguments.  */
+  argp_parse (&argp, argc, argv, 0, &remaining, NULL);
+
+  /* Determine file names.  */
+  if (do_undo || output_name != NULL)
+    {
+      if (remaining + 1 != argc)
+	{
+	wrong_arguments:
+	  error (0, 0, gettext ("wrong number of arguments"));
+	  argp_help (&argp, stdout, ARGP_HELP_SEE,
+		     program_invocation_short_name);
+	  exit (1);
+	}
+      input_name = argv[remaining];
+    }
+  else
+    {
+      if (remaining + 2 != argc)
+	goto wrong_arguments;
+
+      input_name = argv[remaining++];
+      output_name = argv[remaining];
+    }
+
+  /* Special handling if we are asked to print the database.  */
+  if (do_undo)
+    {
+      int fd = open (input_name, O_RDONLY);
+      if (fd == -1)
+	error (EXIT_FAILURE, errno, gettext ("cannot open database file `%s'"),
+	       input_name);
+
+      int status = print_database (fd);
+
+      close (fd);
+
+      return status;
+    }
+
+  /* Open input file.  */
+  if (strcmp (input_name, "-") == 0 || strcmp (input_name, "/dev/stdin") == 0)
+    input_file = stdin;
+  else
+    {
+      struct stat64 st;
+
+      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 (fstat64 (fileno (input_file), &st) >= 0)
+	mode = st.st_mode & ACCESSPERMS;
+    }
+
+  /* Start the real work.  */
+  int status = process_input (input_file, input_name, to_lowercase, be_quiet);
+
+  /* Close files.  */
+  if (input_file != stdin)
+    fclose (input_file);
+
+  /* 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)
+    {
+      if (be_quiet)
+	return EXIT_SUCCESS;
+      else
+	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"));
+
+  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;
+}
+
+
+/* Handle program arguments.  */
+static error_t
+parse_opt (int key, char *arg, struct argp_state *state)
+{
+  struct db_option *newp;
+
+  switch (key)
+    {
+    case 'f':
+      to_lowercase = 1;
+      break;
+    case 'o':
+      output_name = arg;
+      break;
+    case 'q':
+      be_quiet = 1;
+      break;
+    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;
+    }
+  return 0;
+}
+
+
+static char *
+more_help (int key, const char *text, void *input)
+{
+  char *tp = NULL;
+  switch (key)
+    {
+    case ARGP_KEY_HELP_EXTRA:
+      /* We print some extra information.  */
+      if (asprintf (&tp, gettext ("\
+For bug reporting instructions, please see:\n\
+%s.\n"), REPORT_BUGS_TO) < 0)
+	return NULL;
+      return tp;
+    default:
+      break;
+    }
+  return (char *) text;
+}
+
+/* Print the version information.  */
+static void
+print_version (FILE *stream, struct argp_state *state)
+{
+  fprintf (stream, "makedb %s%s\n", PKGVERSION, VERSION);
+  fprintf (stream, gettext ("\
+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\
+"), "2017");
+  fprintf (stream, gettext ("Written by %s.\n"), "Ulrich Drepper");
+}
+
+
+static int
+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;
+
+  return strcmp (d1->str, d2->str);
+}
+
+
+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 (FILE *input, const char *inname, int to_lowercase, int be_quiet)
+{
+  char *line;
+  size_t linelen;
+  int status;
+  size_t linenr;
+
+  line = NULL;
+  linelen = 0;
+  status = EXIT_SUCCESS;
+  linenr = 0;
+
+  struct database *last_database = NULL;
+
+  while (!feof_unlocked (input))
+    {
+      ssize_t n = getline (&line, &linelen, input);
+      if (n < 0)
+	/* This means end of file or some bug.  */
+	break;
+      if (n == 0)
+	/* Short read.  Probably interrupted system call. */
+	continue;
+
+      ++linenr;
+
+      if (line[n - 1] == '\n')
+	/* Remove trailing newline.  */
+	line[--n] = '\0';
+
+      char *cp = line;
+      while (isspace (*cp))
+	++cp;
+
+      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;
+
+      /* 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)
+	    *cp = tolower (*cp);
+	  ++cp;
+	}
+
+      if (*cp == '\0')
+	/* It's a line without a value field.  */
+	continue;
+
+      *cp++ = '\0';
+      size_t keylen = cp - key;
+
+      while (isspace (*cp))
+	++cp;
+
+      char *data = cp;
+      size_t datalen = (&line[n] - cp) + 1;
+
+      /* Find the database.  */
+      if (last_database == NULL || last_database->dbid != key[0])
+	{
+	  last_database = databases;
+	  while (last_database != NULL && last_database->dbid != key[0])
+	    last_database = last_database->next;
+
+	  if (last_database == NULL)
+	    {
+	      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;
+	    }
+	}
+
+      /* Skip the database selector.  */
+      ++key;
+      --keylen;
+
+      /* Store the data.  */
+      struct valstrentry *nentry = xmalloc (sizeof (struct valstrentry)
+					    + datalen);
+      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,
+					    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
+	if (last_database->extra_string)
+	  extrastrlen += datalen;
+	else
+	  valstrlen += datalen;
+
+      /* Store the key.  */
+      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);
+      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_unlocked (input))
+    {
+      error (0, 0, gettext ("problems while reading `%s'"), inname);
+      status = EXIT_FAILURE;
+    }
+
+  return status;
+}
+
+
+static void
+copy_valstr (const void *nodep, const VISIT which, const int depth)
+{
+  if (which != leaf && which != postorder)
+    return;
+
+  const struct valstrentry *p = *(const struct valstrentry **) nodep;
+
+  strcpy (valstrtab + (p->extra_string ? valstrlen : 0) + p->idx, p->str);
+}
+
+
+/* Determine if the candidate is prime by using a modified trial division
+   algorithm. The candidate must be both odd and greater than 4.  */
+static int
+is_prime (size_t candidate)
+{
+  size_t divn = 3;
+  size_t sq = divn * divn;
+
+  assert (candidate > 4 && candidate % 2 != 0);
+
+  while (sq < candidate && candidate % divn != 0)
+    {
+      ++divn;
+      sq += 4 * divn;
+      ++divn;
+    }
+
+  return candidate % divn != 0;
+}
+
+
+static size_t
+next_prime (size_t seed)
+{
+  /* Make sure that we're always greater than 4.  */
+  seed = (seed + 4) | 1;
+
+  while (!is_prime (seed))
+    seed += 2;
+
+  return seed;
+}
+
+
+static void
+compute_tables (void)
+{
+  valstrtab = xmalloc (roundup (valstrlen + extrastrlen, sizeof (stridx_t)));
+  while ((valstrlen + extrastrlen) % sizeof (stridx_t) != 0)
+    valstrtab[valstrlen++] = '\0';
+  twalk (valstrtree, copy_valstr);
+
+  static struct database *db;
+  for (db = databases; db != NULL; db = db->next)
+    if (db->nentries != 0)
+      {
+	++ndatabases;
+
+	/* 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.  */
+#define TEST_RANGE 30
+	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;
+
+	db->hashtable = xmalloc (2 * nhashentries_max * sizeof (stridx_t)
+				 + db->keystrlen);
+	db->keyidxtab = db->hashtable + nhashentries_max;
+	db->keystrtab = (char *) (db->keyidxtab + nhashentries_max);
+
+	static size_t max_chainlength;
+	static char *wp;
+	static size_t nhashentries;
+	static bool copy_string;
+
+	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;
+	  if (copy_string)
+	    {
+	      stridx = wp - db->keystrtab;
+	      wp = stpcpy (wp, dbe->str) + 1;
+	    }
+	  else
+	    stridx = 0;
+
+	  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) >= nhashentries)
+		hidx -= nhashentries;
+	    }
+
+	  db->hashtable[hidx] = ((db->extra_string ? valstrlen : 0)
+				 + dbe->validx);
+	  db->keyidxtab[hidx] = stridx;
+
+	  max_chainlength = MAX (max_chainlength, chainlength);
+	}
+
+	copy_string = false;
+	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;
+
+	twalk (db->entries, add_key);
+
+	db->nhashentries = nhashentries_best;
+	nhashentries_total += nhashentries_best;
+    }
+}
+
+
+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 + ndatabases * 3];
+  iov[0].iov_base = header;
+  iov[0].iov_len = file_offset;
+
+  iov[1].iov_base = valstrtab;
+  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)
+    if (db->entries != NULL)
+      {
+	assert (file_offset % sizeof (stridx_t) == 0);
+	assert (filled_dbs < ndatabases);
+
+	header->dbs[filled_dbs].id = db->dbid;
+	memset (header->dbs[filled_dbs].pad, '\0',
+		sizeof (header->dbs[0].pad));
+	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);
+	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);
+	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_total * sizeof (stridx_t)));
+  header->allocate = file_offset;
+
+  if (writev (fd, iov, 2 + ndatabases * 3) != keydataoffset)
+    {
+      error (0, errno, gettext ("failed to write new database file"));
+      return EXIT_FAILURE;
+    }
+
+  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)
+    {
+      const stridx_t *stridxtab
+	= ((const stridx_t *) ((const char *) header
+			       + header->dbs[dbidx].keyidxoffset));
+      const char *keystrtab
+	= (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;
+}
+
+
+#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 () ? 1 : -1;
+  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)
+    {
+      if (setfscreatecon (ctx) != 0)
+	error (enforcing > 0 ? EXIT_FAILURE : 0, 0,
+	       gettext ("cannot set file creation context for `%s'"),
+	       outname);
+
+      freecon (ctx);
+    }
+}
+
+static void
+reset_file_creation_context (void)
+{
+  setfscreatecon (NULL);
+}
+#endif
diff --git a/REORG.TODO/nss/netgrp-lookup.c b/REORG.TODO/nss/netgrp-lookup.c
new file mode 100644
index 0000000000..d32e8b8e30
--- /dev/null
+++ b/REORG.TODO/nss/netgrp-lookup.c
@@ -0,0 +1,21 @@
+/* Copyright (C) 1996-2017 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, see
+   <http://www.gnu.org/licenses/>.  */
+
+#define DATABASE_NAME netgroup
+
+#include "XXX-lookup.c"
diff --git a/REORG.TODO/nss/network-lookup.c b/REORG.TODO/nss/network-lookup.c
new file mode 100644
index 0000000000..a5f5e38d61
--- /dev/null
+++ b/REORG.TODO/nss/network-lookup.c
@@ -0,0 +1,22 @@
+/* Copyright (C) 1996-2017 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, see
+   <http://www.gnu.org/licenses/>.  */
+
+#define DATABASE_NAME networks
+#define DEFAULT_CONFIG "dns [!UNAVAIL=return] files"
+
+#include "XXX-lookup.c"
diff --git a/REORG.TODO/nss/nss.h b/REORG.TODO/nss/nss.h
new file mode 100644
index 0000000000..fefdc4e44b
--- /dev/null
+++ b/REORG.TODO/nss/nss.h
@@ -0,0 +1,63 @@
+/* Copyright (C) 1996-2017 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, see
+   <http://www.gnu.org/licenses/>.  */
+
+/* Define interface to NSS.  This is meant for the interface functions
+   and for implementors of new services.  */
+
+#ifndef _NSS_H
+#define _NSS_H	1
+
+#include <features.h>
+#include <stdint.h>
+
+
+__BEGIN_DECLS
+
+/* Possible results of lookup using a nss_* function.  */
+enum nss_status
+{
+  NSS_STATUS_TRYAGAIN = -2,
+  NSS_STATUS_UNAVAIL,
+  NSS_STATUS_NOTFOUND,
+  NSS_STATUS_SUCCESS,
+  NSS_STATUS_RETURN
+};
+
+
+/* Data structure used for the 'gethostbyname4_r' function.  */
+struct gaih_addrtuple
+  {
+    struct gaih_addrtuple *next;
+    char *name;
+    int family;
+    uint32_t addr[4];
+    uint32_t scopeid;
+  };
+
+
+/* Overwrite service selection for database DBNAME using specification
+   in STRING.
+   This function should only be used by system programs which have to
+   work around non-existing services (e.e., while booting).
+   Attention: Using this function repeatedly will slowly eat up the
+   whole memory since previous selection data cannot be freed.  */
+extern int __nss_configure_lookup (const char *__dbname,
+				   const char *__string) __THROW;
+
+__END_DECLS
+
+#endif /* nss.h */
diff --git a/REORG.TODO/nss/nss_db/db-XXX.c b/REORG.TODO/nss/nss_db/db-XXX.c
new file mode 100644
index 0000000000..9849c36223
--- /dev/null
+++ b/REORG.TODO/nss/nss_db/db-XXX.c
@@ -0,0 +1,311 @@
+/* Common code for DB-based databases in nss_db module.
+   Copyright (C) 1996-2017 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, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <dlfcn.h>
+#include <fcntl.h>
+#include <stdint.h>
+#include <sys/mman.h>
+#include <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).
+   STRUCTURE -- struct name, define only if not ENTNAME (passwd, group).
+   DATABASE -- database file name, ("hosts", "passwd")
+
+   NEED_H_ERRNO - defined iff an arg `int *herrnop' is used.
+*/
+
+#define ENTNAME_r	CONCAT(ENTNAME,_r)
+
+#include <paths.h>
+#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))
+#else
+# define H_ERRNO_PROTO
+# define H_ERRNO_ARG
+# define H_ERRNO_SET(val) ((void) 0)
+#endif
+
+/* State for this database.  */
+static struct nss_db_map state;
+/* Lock to protect the state and global variables.  */
+__libc_lock_define (static , lock);
+
+/* Maintenance of the shared handle open on the database.  */
+static int keep_db;
+static const char *entidx;
+
+
+/* Open the database.  */
+enum nss_status
+CONCAT(_nss_db_set,ENTNAME) (int stayopen)
+{
+  enum nss_status status;
+
+  __libc_lock_lock (lock);
+
+  status = internal_setent (DBFILE, &state);
+
+  if (status == NSS_STATUS_SUCCESS)
+    {
+      /* Remember STAYOPEN flag.  */
+      keep_db |= stayopen;
+
+      /* Reset the sequential index.  */
+      entidx  = NULL;
+    }
+
+  __libc_lock_unlock (lock);
+
+  return status;
+}
+
+
+/* Close it again.  */
+enum nss_status
+CONCAT(_nss_db_end,ENTNAME) (void)
+{
+  __libc_lock_lock (lock);
+
+  internal_endent (&state);
+
+  /* Reset STAYOPEN flag.  */
+  keep_db = 0;
+
+  __libc_lock_unlock (lock);
+
+  return NSS_STATUS_SUCCESS;
+}
+
+
+/* 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. `("%d", id)'.
+
+   KEYSIZE gives the allocation size of a buffer to construct it in;
+   e.g. `1 + sizeof (id) * 4'.
+
+   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, 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)\
+{									      \
+  struct parser_data *data = (void *) buffer;				      \
+									      \
+  if (buflen < sizeof *data)						      \
+    {									      \
+      *errnop = ERANGE;							      \
+      H_ERRNO_SET (NETDB_INTERNAL);					      \
+      return NSS_STATUS_TRYAGAIN;					      \
+    }									      \
+									      \
+  struct nss_db_map state = { NULL, 0 };				      \
+  enum nss_status status = internal_setent (DBFILE, &state);		      \
+  if (status != NSS_STATUS_SUCCESS)					      \
+    {									      \
+      *errnop = errno;							      \
+      H_ERRNO_SET (NETDB_INTERNAL);					      \
+      return status;							      \
+    }									      \
+									      \
+  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);      \
+									      \
+      /* Advance before break_if_match, lest it uses continue to skip
+	 to the next entry.  */						      \
+      if ((hidx += hval2) >= header->dbs[i].hashsize)			      \
+	hidx -= header->dbs[i].hashsize;				      \
+									      \
+      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);					      \
+									      \
+ out:									      \
+  internal_endent (&state);						      \
+									      \
+  return status;							      \
+}
+
+#define KEYPRINTF(pattern, args...) snprintf (key, size, pattern ,##args)
+#define IGNOREPATTERN(pattern, arg1, args...) (char *) (uintptr_t) arg1
+
+
+
+
+/* Return the next entry from the database file, doing locking.  */
+enum nss_status
+CONCAT(_nss_db_get,ENTNAME_r) (struct STRUCTURE *result, char *buffer,
+			       size_t buflen, int *errnop H_ERRNO_PROTO)
+{
+  /* Return next entry in host file.  */
+  enum nss_status status;
+  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);
+
+  if (state.header == NULL)
+    {
+      status = internal_setent (DBFILE, &state);
+      if (status != NSS_STATUS_SUCCESS)
+	{
+	  *errnop = errno;
+	  H_ERRNO_SET (NETDB_INTERNAL);
+	  goto out;
+	}
+      entidx = NULL;
+    }
+
+  /* Start from the beginning if freshly initialized or reset
+     requested by set*ent.  */
+  if (entidx == NULL)
+    entidx = (const char *) state.header + state.header->valstroffset;
+
+  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 (NETDB_INTERNAL);
+	      status = NSS_STATUS_TRYAGAIN;
+	      break;
+	    }
+
+	  /* Continue with the next record, this one is ill-formed.  */
+	  entidx = next;
+	}
+    }
+
+ out:
+  __libc_lock_unlock (lock);
+
+  return status;
+}
diff --git a/REORG.TODO/nss/nss_db/db-init.c b/REORG.TODO/nss/nss_db/db-init.c
new file mode 100644
index 0000000000..1a65c59119
--- /dev/null
+++ b/REORG.TODO/nss/nss_db/db-init.c
@@ -0,0 +1,47 @@
+/* Initialization in nss_db module.
+   Copyright (C) 2011-2017 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, see
+   <http://www.gnu.org/licenses/>.  */
+
+#ifdef USE_NSCD
+
+#include <paths.h>
+#include <nscd/nscd.h>
+#include <string.h>
+
+#define PWD_FILENAME (_PATH_VARDB "passwd.db")
+define_traced_file (pwd, PWD_FILENAME);
+
+#define GRP_FILENAME (_PATH_VARDB "group.db")
+define_traced_file (grp, GRP_FILENAME);
+
+#define SERV_FILENAME (_PATH_VARDB "services.db")
+define_traced_file (serv, SERV_FILENAME);
+
+void
+_nss_db_init (void (*cb) (size_t, struct traced_file *))
+{
+  init_traced_file (&pwd_traced_file.file, PWD_FILENAME, 0);
+  cb (pwddb, &pwd_traced_file.file);
+
+  init_traced_file (&grp_traced_file.file, GRP_FILENAME, 0);
+  cb (grpdb, &grp_traced_file.file);
+
+  init_traced_file (&serv_traced_file.file, SERV_FILENAME, 0);
+  cb (servdb, &serv_traced_file.file);
+}
+
+#endif
diff --git a/REORG.TODO/nss/nss_db/db-initgroups.c b/REORG.TODO/nss/nss_db/db-initgroups.c
new file mode 100644
index 0000000000..11e6052453
--- /dev/null
+++ b/REORG.TODO/nss/nss_db/db-initgroups.c
@@ -0,0 +1,142 @@
+/* Initgroups handling in nss_db module.
+   Copyright (C) 2011-2017 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, see <http://www.gnu.org/licenses/>.  */
+
+#include <ctype.h>
+#include <errno.h>
+#include <grp.h>
+#include <limits.h>
+#include <paths.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <sys/param.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;
+}
diff --git a/REORG.TODO/nss/nss_db/db-netgrp.c b/REORG.TODO/nss/nss_db/db-netgrp.c
new file mode 100644
index 0000000000..25530cc206
--- /dev/null
+++ b/REORG.TODO/nss/nss_db/db-netgrp.c
@@ -0,0 +1,122 @@
+/* Netgroup file parser in nss_db modules.
+   Copyright (C) 1996-2017 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, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <ctype.h>
+#include <dlfcn.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <netgroup.h>
+#include <string.h>
+#include <stdint.h>
+#include <libc-lock.h>
+#include <paths.h>
+#include <stdlib.h>
+
+#include "nsswitch.h"
+#include "nss_db.h"
+
+/* The hashing function we use.  */
+#include "../intl/hash-string.h"
+
+
+#define DBFILE		_PATH_VARDB "netgroup.db"
+
+/* Maintenance of the shared handle open on the database.  */
+enum nss_status
+_nss_db_setnetgrent (const char *group, struct __netgrent *result)
+{
+  struct nss_db_map state;
+  enum nss_status status = internal_setent (DBFILE, &state);
+
+  if (status == NSS_STATUS_SUCCESS)
+    {
+      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);
+    }
+
+  return status;
+
+}
+
+
+enum nss_status
+_nss_db_endnetgrent (struct __netgrent *result)
+{
+  free (result->data);
+  result->data = NULL;
+  result->data_size = 0;
+  result->cursor = NULL;
+  return NSS_STATUS_SUCCESS;
+}
+
+
+extern enum nss_status _nss_netgroup_parseline (char **cursor,
+						struct __netgrent *result,
+						char *buffer, size_t buflen,
+						int *errnop);
+
+enum nss_status
+_nss_db_getnetgrent_r (struct __netgrent *result, char *buffer, size_t buflen,
+		       int *errnop)
+{
+  enum nss_status status;
+
+  status = _nss_netgroup_parseline (&result->cursor, result, buffer, buflen,
+				    errnop);
+
+  return status;
+}
diff --git a/REORG.TODO/nss/nss_db/db-open.c b/REORG.TODO/nss/nss_db/db-open.c
new file mode 100644
index 0000000000..1c58bd1c54
--- /dev/null
+++ b/REORG.TODO/nss/nss_db/db-open.c
@@ -0,0 +1,67 @@
+/* Common database routines for nss_db.
+   Copyright (C) 2000-2017 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, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <dlfcn.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <not-cancel.h>
+
+#include "nss_db.h"
+
+/* 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
+internal_setent (const char *file, struct nss_db_map *mapping)
+{
+  enum nss_status status = NSS_STATUS_UNAVAIL;
+
+  int fd = open_not_cancel_2 (file, O_RDONLY | O_LARGEFILE | O_CLOEXEC);
+  if (fd != -1)
+    {
+      struct nss_db_header header;
+
+      if (read (fd, &header, sizeof (header)) == sizeof (header))
+	{
+	  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;
+	}
+
+      close_not_cancel_no_status (fd);
+    }
+
+  return status;
+}
+
+
+/* Close the database.  */
+void
+internal_endent (struct nss_db_map *mapping)
+{
+  munmap (mapping->header, mapping->len);
+}
diff --git a/REORG.TODO/nss/nss_db/nss_db.h b/REORG.TODO/nss/nss_db/nss_db.h
new file mode 100644
index 0000000000..6978cead07
--- /dev/null
+++ b/REORG.TODO/nss/nss_db/nss_db.h
@@ -0,0 +1,69 @@
+/* Common database open/close routines for nss_db.
+   Copyright (C) 1999-2017 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, see
+   <http://www.gnu.org/licenses/>.  */
+
+#ifndef _NSS_DB_H
+#define _NSS_DB_H	1
+
+#include <nss.h>
+#include <stdint.h>
+#include <libc-lock.h>
+
+
+/* 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;
+  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
+{
+  struct nss_db_header *header;
+  size_t len;
+};
+
+
+/* Open the database stored in FILE.  If succesful, store the database
+   handle in *MAPPINGP or a file descriptor for the file in *FDP and
+   return NSS_STATUS_SUCCESS.  On failure, return the appropriate
+   lookup status.  */
+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/REORG.TODO/nss/nss_files/files-XXX.c b/REORG.TODO/nss/nss_files/files-XXX.c
new file mode 100644
index 0000000000..265331ef21
--- /dev/null
+++ b/REORG.TODO/nss/nss_files/files-XXX.c
@@ -0,0 +1,300 @@
+/* Common code for file-based databases in nss_files module.
+   Copyright (C) 1996-2017 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, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <libc-lock.h>
+#include "nsswitch.h"
+
+#include <kernel-features.h>
+
+/* These symbols are defined by the including source file:
+
+   ENTNAME -- database name of the structure and functions (hostent, pwent).
+   STRUCTURE -- struct name, define only if not ENTNAME (passwd, group).
+   DATABASE -- string of the database file's name ("hosts", "passwd").
+
+   NEED_H_ERRNO - defined iff an arg `int *herrnop' is used.
+
+   Also see files-parse.c.
+*/
+
+#define ENTNAME_r	CONCAT(ENTNAME,_r)
+
+#define DATAFILE	"/etc/" DATABASE
+
+#ifdef NEED_H_ERRNO
+# include <netdb.h>
+# 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)
+#endif
+
+#ifndef EXTRA_ARGS
+# define EXTRA_ARGS
+# define EXTRA_ARGS_DECL
+# define EXTRA_ARGS_VALUE
+#endif
+
+/* Locks the static variables in this file.  */
+__libc_lock_define_initialized (static, lock)
+
+/* Maintenance of the stream open on the database file.  For getXXent
+   operations the stream needs to be held open across calls, the other
+   getXXbyYY operations all use their own stream.  */
+
+static FILE *stream;
+
+/* Open database file if not already opened.  */
+static enum nss_status
+internal_setent (FILE **stream)
+{
+  enum nss_status status = NSS_STATUS_SUCCESS;
+
+  if (*stream == NULL)
+    {
+      *stream = fopen (DATAFILE, "rce");
+
+      if (*stream == NULL)
+	status = errno == EAGAIN ? NSS_STATUS_TRYAGAIN : NSS_STATUS_UNAVAIL;
+    }
+  else
+    rewind (*stream);
+
+  return status;
+}
+
+
+/* Thread-safe, exported version of that.  */
+enum nss_status
+CONCAT(_nss_files_set,ENTNAME) (int stayopen)
+{
+  enum nss_status status;
+
+  __libc_lock_lock (lock);
+
+  status = internal_setent (&stream);
+
+  __libc_lock_unlock (lock);
+
+  return status;
+}
+
+
+/* Close the database file.  */
+static void
+internal_endent (FILE **stream)
+{
+  if (*stream != NULL)
+    {
+      fclose (*stream);
+      *stream = NULL;
+    }
+}
+
+
+/* Thread-safe, exported version of that.  */
+enum nss_status
+CONCAT(_nss_files_end,ENTNAME) (void)
+{
+  __libc_lock_lock (lock);
+
+  internal_endent (&stream);
+
+  __libc_lock_unlock (lock);
+
+  return NSS_STATUS_SUCCESS;
+}
+
+
+typedef enum
+{
+  gcr_ok = 0,
+  gcr_error = -1,
+  gcr_overflow = -2
+} get_contents_ret;
+
+/* Hack around the fact that fgets only accepts int sizes.  */
+static get_contents_ret
+get_contents (char *linebuf, size_t len, FILE *stream)
+{
+  size_t remaining_len = len;
+  char *curbuf = linebuf;
+
+  do
+    {
+      int curlen = ((remaining_len > (size_t) INT_MAX) ? INT_MAX
+		    : remaining_len);
+
+      /* Terminate the line so that we can test for overflow.  */
+      ((unsigned char *) curbuf)[curlen - 1] = 0xff;
+
+      char *p = fgets_unlocked (curbuf, curlen, stream);
+
+      /* EOF or read error.  */
+      if (p == NULL)
+        return gcr_error;
+
+      /* Done reading in the line.  */
+      if (((unsigned char *) curbuf)[curlen - 1] == 0xff)
+        return gcr_ok;
+
+      /* Drop the terminating '\0'.  */
+      remaining_len -= curlen - 1;
+      curbuf += curlen - 1;
+    }
+  /* fgets copies one less than the input length.  Our last iteration is of
+     REMAINING_LEN and once that is done, REMAINING_LEN is decremented by
+     REMAINING_LEN - 1, leaving the result as 1.  */
+  while (remaining_len > 1);
+
+  /* This means that the current buffer was not large enough.  */
+  return gcr_overflow;
+}
+
+/* Parsing the database file into `struct STRUCTURE' data structures.  */
+static enum nss_status
+internal_getent (FILE *stream, struct STRUCTURE *result,
+		 char *buffer, size_t buflen, int *errnop H_ERRNO_PROTO
+		 EXTRA_ARGS_DECL)
+{
+  char *p;
+  struct parser_data *data = (void *) buffer;
+  size_t linebuflen = buffer + buflen - data->linebuffer;
+  int parse_result;
+
+  if (buflen < sizeof *data + 2)
+    {
+      *errnop = ERANGE;
+      H_ERRNO_SET (NETDB_INTERNAL);
+      return NSS_STATUS_TRYAGAIN;
+    }
+
+  do
+    {
+      get_contents_ret r = get_contents (data->linebuffer, linebuflen, stream);
+
+      if (r == gcr_error)
+	{
+	  /* End of file or read error.  */
+	  H_ERRNO_SET (HOST_NOT_FOUND);
+	  return NSS_STATUS_NOTFOUND;
+	}
+
+      if (r == gcr_overflow)
+	{
+	  /* The line is too long.  Give the user the opportunity to
+	     enlarge the buffer.  */
+	  *errnop = ERANGE;
+	  H_ERRNO_SET (NETDB_INTERNAL);
+	  return NSS_STATUS_TRYAGAIN;
+	}
+
+      /* Everything OK.  Now skip leading blanks.  */
+      p = data->linebuffer;
+      while (isspace (*p))
+	++p;
+    }
+  while (*p == '\0' || *p == '#' /* Ignore empty and comment lines.  */
+	 /* Parse the line.  If it is invalid, loop to get the next
+	    line of the file to parse.  */
+	 || ! (parse_result = parse_line (p, result, data, buflen, errnop
+					  EXTRA_ARGS)));
+
+  if (__glibc_unlikely (parse_result == -1))
+    {
+      H_ERRNO_SET (NETDB_INTERNAL);
+      return NSS_STATUS_TRYAGAIN;
+    }
+
+  /* Filled in RESULT with the next entry from the database file.  */
+  return NSS_STATUS_SUCCESS;
+}
+
+
+/* Return the next entry from the database file, doing locking.  */
+enum nss_status
+CONCAT(_nss_files_get,ENTNAME_r) (struct STRUCTURE *result, char *buffer,
+				  size_t buflen, int *errnop H_ERRNO_PROTO)
+{
+  /* Return next entry in host file.  */
+  enum nss_status status = NSS_STATUS_SUCCESS;
+
+  __libc_lock_lock (lock);
+
+  /* Be prepared that the set*ent function was not called before.  */
+  if (stream == NULL)
+    {
+      int save_errno = errno;
+
+      status = internal_setent (&stream);
+
+      __set_errno (save_errno);
+    }
+
+  if (status == NSS_STATUS_SUCCESS)
+    status = internal_getent (stream, result, buffer, buflen, errnop
+			      H_ERRNO_ARG EXTRA_ARGS_VALUE);
+
+  __libc_lock_unlock (lock);
+
+  return status;
+}
+
+/* Macro for defining lookup functions for this file-based database.
+
+   NAME is the name of the lookup; e.g. `hostbyname'.
+
+   DB_CHAR, KEYPATTERN, KEYSIZE are ignored here but used by db-XXX.c
+   e.g. `1 + sizeof (id) * 4'.
+
+   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, db_char, keysize, keypattern, break_if_match, proto...)\
+enum nss_status								      \
+_nss_files_get##name##_r (proto,					      \
+			  struct STRUCTURE *result, char *buffer,	      \
+			  size_t buflen, int *errnop H_ERRNO_PROTO)	      \
+{									      \
+  enum nss_status status;						      \
+  FILE *stream = NULL;							      \
+									      \
+  /* Open file.  */							      \
+  status = internal_setent (&stream);					      \
+									      \
+  if (status == NSS_STATUS_SUCCESS)					      \
+    {									      \
+      while ((status = internal_getent (stream, result, buffer, buflen, errnop \
+					H_ERRNO_ARG EXTRA_ARGS_VALUE))	      \
+	     == NSS_STATUS_SUCCESS)					      \
+	{ break_if_match }						      \
+									      \
+      internal_endent (&stream);					      \
+    }									      \
+									      \
+  return status;							      \
+}
diff --git a/REORG.TODO/nss/nss_files/files-alias.c b/REORG.TODO/nss/nss_files/files-alias.c
new file mode 100644
index 0000000000..cf872bb603
--- /dev/null
+++ b/REORG.TODO/nss/nss_files/files-alias.c
@@ -0,0 +1,404 @@
+/* Mail alias file parser in nss_files module.
+   Copyright (C) 1996-2017 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, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <aliases.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <libc-lock.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <kernel-features.h>
+
+#include "nsswitch.h"
+
+/* Locks the static variables in this file.  */
+__libc_lock_define_initialized (static, lock)
+
+/* Maintenance of the stream open on the database file.  For getXXent
+   operations the stream needs to be held open across calls, the other
+   getXXbyYY operations all use their own stream.  */
+
+static FILE *stream;
+
+
+static enum nss_status
+internal_setent (FILE **stream)
+{
+  enum nss_status status = NSS_STATUS_SUCCESS;
+
+  if (*stream == NULL)
+    {
+      *stream = fopen ("/etc/aliases", "rce");
+
+      if (*stream == NULL)
+	status = errno == EAGAIN ? NSS_STATUS_TRYAGAIN : NSS_STATUS_UNAVAIL;
+    }
+  else
+    rewind (*stream);
+
+  return status;
+}
+
+
+/* Thread-safe, exported version of that.  */
+enum nss_status
+_nss_files_setaliasent (void)
+{
+  enum nss_status status;
+
+  __libc_lock_lock (lock);
+
+  status = internal_setent (&stream);
+
+  __libc_lock_unlock (lock);
+
+  return status;
+}
+
+
+/* Close the database file.  */
+static void
+internal_endent (FILE **stream)
+{
+  if (*stream != NULL)
+    {
+      fclose (*stream);
+      *stream = NULL;
+    }
+}
+
+
+/* Thread-safe, exported version of that.  */
+enum nss_status
+_nss_files_endaliasent (void)
+{
+  __libc_lock_lock (lock);
+
+  internal_endent (&stream);
+
+  __libc_lock_unlock (lock);
+
+  return NSS_STATUS_SUCCESS;
+}
+
+/* Parsing the database file into `struct aliasent' data structures.  */
+static enum nss_status
+get_next_alias (FILE *stream, const char *match, struct aliasent *result,
+		char *buffer, size_t buflen, int *errnop)
+{
+  enum nss_status status = NSS_STATUS_NOTFOUND;
+  int ignore = 0;
+
+  result->alias_members_len = 0;
+
+  while (1)
+    {
+      /* Now we are ready to process the input.  We have to read a
+	 line and all its continuations and construct the array of
+	 string pointers.  This pointers and the names itself have to
+	 be placed in BUFFER.  */
+      char *first_unused = buffer;
+      size_t room_left = buflen - (buflen % __alignof__ (char *));
+      char *line;
+
+      /* Check whether the buffer is large enough for even trying to
+	 read something.  */
+      if (room_left < 2)
+	goto no_more_room;
+
+      /* Read the first line.  It must contain the alias name and
+	 possibly some alias names.  */
+      first_unused[room_left - 1] = '\xff';
+      line = fgets_unlocked (first_unused, room_left, stream);
+      if (line == NULL)
+	/* Nothing to read.  */
+	break;
+      else if (first_unused[room_left - 1] != '\xff')
+	{
+	  /* The line is too long for our buffer.  */
+	no_more_room:
+	  *errnop = ERANGE;
+	  status = NSS_STATUS_TRYAGAIN;
+	  break;
+	}
+      else
+	{
+	  char *cp;
+
+	  /* If we are in IGNORE mode and the first character in the
+	     line is a white space we ignore the line and start
+	     reading the next.  */
+	  if (ignore && isspace (*first_unused))
+	    continue;
+
+	  /* Terminate the line for any case.  */
+	  cp = strpbrk (first_unused, "#\n");
+	  if (cp != NULL)
+	    *cp = '\0';
+
+	  /* Skip leading blanks.  */
+	  while (isspace (*line))
+	    ++line;
+
+	  result->alias_name = first_unused;
+	  while (*line != '\0' && *line != ':')
+	    *first_unused++ = *line++;
+	  if (*line == '\0' || result->alias_name == first_unused)
+	    /* No valid name.  Ignore the line.  */
+	    continue;
+
+	  *first_unused++ = '\0';
+	  if (room_left < (size_t) (first_unused - result->alias_name))
+	    goto no_more_room;
+	  room_left -= first_unused - result->alias_name;
+	  ++line;
+
+	  /* When we search for a specific alias we can avoid all the
+	     difficult parts and compare now with the name we are
+	     looking for.  If it does not match we simply ignore all
+	     lines until the next line containing the start of a new
+	     alias is found.  */
+	  ignore = (match != NULL
+		    && __strcasecmp (result->alias_name, match) != 0);
+
+	  while (! ignore)
+	    {
+	      while (isspace (*line))
+		++line;
+
+	      cp = first_unused;
+	      while (*line != '\0' && *line != ',')
+		*first_unused++ = *line++;
+
+	      if (first_unused != cp)
+		{
+		  /* OK, we can have a regular entry or an include
+		     request.  */
+		  if (*line != '\0')
+		    ++line;
+		  *first_unused++ = '\0';
+
+		  if (strncmp (cp, ":include:", 9) != 0)
+		    {
+		      if (room_left < (first_unused - cp) + sizeof (char *))
+			goto no_more_room;
+		      room_left -= (first_unused - cp) + sizeof (char *);
+
+		      ++result->alias_members_len;
+		    }
+		  else
+		    {
+		      /* Oh well, we have to read the addressed file.  */
+		      FILE *listfile;
+		      char *old_line = NULL;
+
+		      first_unused = cp;
+
+		      listfile = fopen (&cp[9], "rce");
+		      /* If the file does not exist we simply ignore
+			 the statement.  */
+		      if (listfile != NULL
+			  && (old_line = strdup (line)) != NULL)
+			{
+			  while (! feof_unlocked (listfile))
+			    {
+			      first_unused[room_left - 1] = '\xff';
+			      line = fgets_unlocked (first_unused, room_left,
+						     listfile);
+			      if (line == NULL)
+				break;
+			      if (first_unused[room_left - 1] != '\xff')
+				{
+				  free (old_line);
+				  goto no_more_room;
+				}
+
+			      /* Parse the line.  */
+			      cp = strpbrk (line, "#\n");
+			      if (cp != NULL)
+				*cp = '\0';
+
+			      do
+				{
+				  while (isspace (*line))
+				    ++line;
+
+				  cp = first_unused;
+				  while (*line != '\0' && *line != ',')
+				    *first_unused++ = *line++;
+
+				  if (*line != '\0')
+				    ++line;
+
+				  if (first_unused != cp)
+				    {
+				      *first_unused++ = '\0';
+				      if (room_left < ((first_unused - cp)
+						       + __alignof__ (char *)))
+					{
+					  free (old_line);
+					  goto no_more_room;
+					}
+				      room_left -= ((first_unused - cp)
+						    + __alignof__ (char *));
+				      ++result->alias_members_len;
+				    }
+				}
+			      while (*line != '\0');
+			    }
+			  fclose (listfile);
+
+			  first_unused[room_left - 1] = '\0';
+			  strncpy (first_unused, old_line, room_left);
+
+			  free (old_line);
+			  line = first_unused;
+
+			  if (first_unused[room_left - 1] != '\0')
+			    goto no_more_room;
+			}
+		    }
+		}
+
+	      if (*line == '\0')
+		{
+		  /* Get the next line.  But we must be careful.  We
+		     must not read the whole line at once since it
+		     might belong to the current alias.  Simply read
+		     the first character.  If it is a white space we
+		     have a continuation line.  Otherwise it is the
+		     beginning of a new alias and we can push back the
+		     just read character.  */
+		  int ch;
+
+		  ch = fgetc_unlocked (stream);
+		  if (ch == EOF || ch == '\n' || !isspace (ch))
+		    {
+		      size_t cnt;
+
+		      /* Now prepare the return.  Provide string
+			 pointers for the currently selected aliases.  */
+		      if (ch != EOF)
+			ungetc (ch, stream);
+
+		      /* Adjust the pointer so it is aligned for
+			 storing pointers.  */
+		      first_unused += __alignof__ (char *) - 1;
+		      first_unused -= ((first_unused - (char *) 0)
+				       % __alignof__ (char *));
+		      result->alias_members = (char **) first_unused;
+
+		      /* 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);
+		      break;
+		    }
+
+		  /* The just read character is a white space and so
+		     can be ignored.  */
+		  first_unused[room_left - 1] = '\xff';
+		  line = fgets_unlocked (first_unused, room_left, stream);
+		  if (first_unused[room_left - 1] != '\xff')
+		    goto no_more_room;
+		  cp = strpbrk (line, "#\n");
+		  if (cp != NULL)
+		    *cp = '\0';
+		}
+	    }
+	}
+
+      if (status != NSS_STATUS_NOTFOUND)
+	/* We read something.  In any case break here.  */
+	break;
+    }
+
+  return status;
+}
+
+
+enum nss_status
+_nss_files_getaliasent_r (struct aliasent *result, char *buffer, size_t buflen,
+			  int *errnop)
+{
+  /* Return next entry in host file.  */
+  enum nss_status status = NSS_STATUS_SUCCESS;
+
+  __libc_lock_lock (lock);
+
+  /* Be prepared that the set*ent function was not called before.  */
+  if (stream == NULL)
+    status = internal_setent (&stream);
+
+  if (status == NSS_STATUS_SUCCESS)
+    {
+      result->alias_local = 1;
+
+      /* Read lines until we get a definite result.  */
+      do
+	status = get_next_alias (stream, NULL, result, buffer, buflen, errnop);
+      while (status == NSS_STATUS_RETURN);
+    }
+
+  __libc_lock_unlock (lock);
+
+  return status;
+}
+
+
+enum nss_status
+_nss_files_getaliasbyname_r (const char *name, struct aliasent *result,
+			     char *buffer, size_t buflen, int *errnop)
+{
+  /* Return next entry in host file.  */
+  enum nss_status status = NSS_STATUS_SUCCESS;
+  FILE *stream = NULL;
+
+  if (name == NULL)
+    {
+      __set_errno (EINVAL);
+      return NSS_STATUS_UNAVAIL;
+    }
+
+  /* Open the stream.  */
+  status = internal_setent (&stream);
+
+  if (status == NSS_STATUS_SUCCESS)
+    {
+      result->alias_local = 1;
+
+      /* Read lines until we get a definite result.  */
+      do
+	status = get_next_alias (stream, name, result, buffer, buflen, errnop);
+      while (status == NSS_STATUS_RETURN);
+    }
+
+  internal_endent (&stream);
+
+  return status;
+}
diff --git a/REORG.TODO/nss/nss_files/files-ethers.c b/REORG.TODO/nss/nss_files/files-ethers.c
new file mode 100644
index 0000000000..6f5c02636f
--- /dev/null
+++ b/REORG.TODO/nss/nss_files/files-ethers.c
@@ -0,0 +1,67 @@
+/* Copyright (C) 1996-2017 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, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <string.h>
+#include <netinet/ether.h>
+#include <netinet/if_ether.h>
+
+struct etherent_data {};
+
+#define ENTNAME		etherent
+#define DATABASE	"ethers"
+#include "files-parse.c"
+LINE_PARSER
+("#",
+ /* Read the ethernet address: 6 x 8bit hexadecimal number.  */
+ {
+   size_t cnt;
+
+   for (cnt = 0; cnt < 6; ++cnt)
+     {
+       unsigned int number;
+
+       if (cnt < 5)
+	 INT_FIELD (number, ISCOLON , 0, 16, (unsigned int))
+       else
+	 INT_FIELD (number, isspace, 1, 16, (unsigned int))
+
+       if (number > 0xff)
+	 return 0;
+       result->e_addr.ether_addr_octet[cnt] = number;
+     }
+ };
+ STRING_FIELD (result->e_name, isspace, 1);
+ )
+
+
+#include GENERIC
+
+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",
+			 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]),
+	   {
+	     if (memcmp (&result->e_addr, addr,
+			 sizeof (struct ether_addr)) == 0)
+	       break;
+	   }, const struct ether_addr *addr)
diff --git a/REORG.TODO/nss/nss_files/files-grp.c b/REORG.TODO/nss/nss_files/files-grp.c
new file mode 100644
index 0000000000..ff8b27f2b3
--- /dev/null
+++ b/REORG.TODO/nss/nss_files/files-grp.c
@@ -0,0 +1,44 @@
+/* Group file parser in nss_files module.
+   Copyright (C) 1996-2017 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, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <grp.h>
+
+#define STRUCTURE	group
+#define ENTNAME		grent
+#define DATABASE	"group"
+struct grent_data {};
+
+/* Our parser function is already defined in fgetgrent.c, so use that.
+   to parse lines from the database file.  */
+#define EXTERN_PARSER
+#include "files-parse.c"
+#include GENERIC
+
+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),
+	   {
+	     if (result->gr_gid == gid && result->gr_name[0] != '+'
+		 && result->gr_name[0] != '-')
+	       break;
+	   }, gid_t gid)
diff --git a/REORG.TODO/nss/nss_files/files-hosts.c b/REORG.TODO/nss/nss_files/files-hosts.c
new file mode 100644
index 0000000000..bccb6a5780
--- /dev/null
+++ b/REORG.TODO/nss/nss_files/files-hosts.c
@@ -0,0 +1,482 @@
+/* Hosts file parser in nss_files module.
+   Copyright (C) 1996-2017 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, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <assert.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+#include <netdb.h>
+#include <resolv/resolv-internal.h>
+
+
+/* Get implementation for some internal functions.  */
+#include "../resolv/mapv4v6addr.h"
+#include "../resolv/res_hconf.h"
+
+
+#define ENTNAME		hostent
+#define DATABASE	"hosts"
+#define NEED_H_ERRNO
+
+#define EXTRA_ARGS	 , af, flags
+#define EXTRA_ARGS_DECL	 , int af, int flags
+
+#define ENTDATA hostent_data
+struct hostent_data
+  {
+    unsigned char host_addr[16]; /* IPv4 or IPv6 address.  */
+    char *h_addr_ptrs[2];	/* Points to that and null terminator.  */
+  };
+
+#define TRAILING_LIST_MEMBER		h_aliases
+#define TRAILING_LIST_SEPARATOR_P	isspace
+#include "files-parse.c"
+LINE_PARSER
+("#",
+ {
+   char *addr;
+
+   STRING_FIELD (addr, isspace, 1);
+
+   /* Parse address.  */
+   if (inet_pton (af == AF_UNSPEC ? AF_INET : af, addr, entdata->host_addr)
+       > 0)
+     af = af == AF_UNSPEC ? AF_INET : af;
+   else
+     {
+       if (af == AF_INET6 && (flags & AI_V4MAPPED) != 0
+	   && inet_pton (AF_INET, addr, entdata->host_addr) > 0)
+	 map_v4v6_address ((char *) entdata->host_addr,
+			   (char *) entdata->host_addr);
+       else if (af == AF_INET
+		&& inet_pton (AF_INET6, addr, entdata->host_addr) > 0)
+	 {
+	   if (IN6_IS_ADDR_V4MAPPED (entdata->host_addr))
+	     memcpy (entdata->host_addr, entdata->host_addr + 12, INADDRSZ);
+	   else if (IN6_IS_ADDR_LOOPBACK (entdata->host_addr))
+	     {
+	       in_addr_t localhost = htonl (INADDR_LOOPBACK);
+	       memcpy (entdata->host_addr, &localhost, sizeof (localhost));
+	     }
+	   else
+	     /* Illegal address: ignore line.  */
+	     return 0;
+	 }
+       else if (af == AF_UNSPEC
+		&& inet_pton (AF_INET6, addr, entdata->host_addr) > 0)
+	 af = AF_INET6;
+       else
+	 /* Illegal address: ignore line.  */
+	 return 0;
+     }
+
+   /* We always return entries of the requested form.  */
+   result->h_addrtype = af;
+   result->h_length = af == AF_INET ? INADDRSZ : IN6ADDRSZ;
+
+   /* Store a pointer to the address in the expected form.  */
+   entdata->h_addr_ptrs[0] = (char *) entdata->host_addr;
+   entdata->h_addr_ptrs[1] = NULL;
+   result->h_addr_list = entdata->h_addr_ptrs;
+
+   STRING_FIELD (result->h_name, isspace, 1);
+ })
+
+#define EXTRA_ARGS_VALUE \
+  , (res_use_inet6 () ? AF_INET6 : AF_INET),		      \
+  (res_use_inet6 () ? AI_V4MAPPED : 0)
+#include "files-XXX.c"
+#undef EXTRA_ARGS_VALUE
+
+/* We only need to consider IPv4 mapped addresses if the input to the
+   gethostbyaddr() function is an IPv6 address.  */
+#define EXTRA_ARGS_VALUE \
+  , af, (len == IN6ADDRSZ ? AI_V4MAPPED : 0)
+DB_LOOKUP (hostbyaddr, ,,,
+	   {
+	     if (result->h_length == (int) len
+		 && ! memcmp (addr, result->h_addr_list[0], len))
+	       break;
+	   }, const void *addr, socklen_t len, int af)
+#undef EXTRA_ARGS_VALUE
+
+enum nss_status
+_nss_files_gethostbyname3_r (const char *name, int af, struct hostent *result,
+			     char *buffer, size_t buflen, int *errnop,
+			     int *herrnop, int32_t *ttlp, char **canonp)
+{
+  FILE *stream = NULL;
+  uintptr_t pad = -(uintptr_t) buffer % __alignof__ (struct hostent_data);
+  buffer += pad;
+  buflen = buflen > pad ? buflen - pad : 0;
+
+  /* Open file.  */
+  enum nss_status status = internal_setent (&stream);
+
+  if (status == NSS_STATUS_SUCCESS)
+    {
+      /* XXX Is using _res to determine whether we want to convert IPv4
+         addresses to IPv6 addresses really the right thing to do?  */
+      int flags = (res_use_inet6 () ? AI_V4MAPPED : 0);
+
+      while ((status = internal_getent (stream, result, buffer, buflen, errnop,
+					herrnop, af, flags))
+	     == NSS_STATUS_SUCCESS)
+	{
+	  LOOKUP_NAME_CASE (h_name, h_aliases)
+	}
+
+      if (status == NSS_STATUS_SUCCESS
+	  && _res_hconf.flags & HCONF_FLAG_MULTI)
+	{
+	  /* We have to get all host entries from the file.  */
+	  size_t tmp_buflen = MIN (buflen, 4096);
+	  char tmp_buffer_stack[tmp_buflen]
+	    __attribute__ ((__aligned__ (__alignof__ (struct hostent_data))));
+	  char *tmp_buffer = tmp_buffer_stack;
+	  struct hostent tmp_result_buf;
+	  int naddrs = 1;
+	  int naliases = 0;
+	  char *bufferend;
+	  bool tmp_buffer_malloced = false;
+
+	  while (result->h_aliases[naliases] != NULL)
+	    ++naliases;
+
+	  bufferend = (char *) &result->h_aliases[naliases + 1];
+
+	again:
+	  while ((status = internal_getent (stream, &tmp_result_buf, tmp_buffer,
+					    tmp_buflen, errnop, herrnop, af,
+					    flags))
+		 == NSS_STATUS_SUCCESS)
+	    {
+	      int matches = 1;
+	      struct hostent *old_result = result;
+	      result = &tmp_result_buf;
+	      /* The following piece is a bit clumsy but we want to use the
+		 `LOOKUP_NAME_CASE' value.  The optimizer should do its
+		 job.  */
+	      do
+		{
+		  LOOKUP_NAME_CASE (h_name, h_aliases)
+		  result = old_result;
+		}
+	      while ((matches = 0));
+
+	      if (matches)
+		{
+		  /* We could be very clever and try to recycle a few bytes
+		     in the buffer instead of generating new arrays.  But
+		     we are not doing this here since it's more work than
+		     it's worth.  Simply let the user provide a bit bigger
+		     buffer.  */
+		  char **new_h_addr_list;
+		  char **new_h_aliases;
+		  int newaliases = 0;
+		  size_t newstrlen = 0;
+		  int cnt;
+
+		  /* Count the new aliases and the length of the strings.  */
+		  while (tmp_result_buf.h_aliases[newaliases] != NULL)
+		    {
+		      char *cp = tmp_result_buf.h_aliases[newaliases];
+		      ++newaliases;
+		      newstrlen += strlen (cp) + 1;
+		    }
+		  /* If the real name is different add it also to the
+		     aliases.  This means that there is a duplication
+		     in the alias list but this is really the user's
+		     problem.  */
+		  if (strcmp (old_result->h_name,
+			      tmp_result_buf.h_name) != 0)
+		    {
+		      ++newaliases;
+		      newstrlen += strlen (tmp_result_buf.h_name) + 1;
+		    }
+
+		  /* Make sure bufferend is aligned.  */
+		  assert ((bufferend - (char *) 0) % sizeof (char *) == 0);
+
+		  /* Now we can check whether the buffer is large enough.
+		     16 is the maximal size of the IP address.  */
+		  if (bufferend + 16 + (naddrs + 2) * sizeof (char *)
+		      + roundup (newstrlen, sizeof (char *))
+		      + (naliases + newaliases + 1) * sizeof (char *)
+		      >= buffer + buflen)
+		    {
+		      *errnop = ERANGE;
+		      *herrnop = NETDB_INTERNAL;
+		      status = NSS_STATUS_TRYAGAIN;
+		      goto out;
+		    }
+
+		  new_h_addr_list =
+		    (char **) (bufferend
+			       + roundup (newstrlen, sizeof (char *))
+			       + 16);
+		  new_h_aliases =
+		    (char **) ((char *) new_h_addr_list
+			       + (naddrs + 2) * sizeof (char *));
+
+		  /* Copy the old data in the new arrays.  */
+		  for (cnt = 0; cnt < naddrs; ++cnt)
+		    new_h_addr_list[cnt] = old_result->h_addr_list[cnt];
+
+		  for (cnt = 0; cnt < naliases; ++cnt)
+		    new_h_aliases[cnt] = old_result->h_aliases[cnt];
+
+		  /* Store the new strings.  */
+		  cnt = 0;
+		  while (tmp_result_buf.h_aliases[cnt] != NULL)
+		    {
+		      new_h_aliases[naliases++] = bufferend;
+		      bufferend = (__stpcpy (bufferend,
+					     tmp_result_buf.h_aliases[cnt])
+				   + 1);
+		      ++cnt;
+		    }
+
+		  if (cnt < newaliases)
+		    {
+		      new_h_aliases[naliases++] = bufferend;
+		      bufferend = __stpcpy (bufferend,
+					    tmp_result_buf.h_name) + 1;
+		    }
+
+		  /* Final NULL pointer.  */
+		  new_h_aliases[naliases] = NULL;
+
+		  /* Round up the buffer end address.  */
+		  bufferend += (sizeof (char *)
+				- ((bufferend - (char *) 0)
+				   % sizeof (char *))) % sizeof (char *);
+
+		  /* Now the new address.  */
+		  new_h_addr_list[naddrs++] =
+		    memcpy (bufferend, tmp_result_buf.h_addr,
+			    tmp_result_buf.h_length);
+
+		  /* Also here a final NULL pointer.  */
+		  new_h_addr_list[naddrs] = NULL;
+
+		  /* Store the new array pointers.  */
+		  old_result->h_aliases = new_h_aliases;
+		  old_result->h_addr_list = new_h_addr_list;
+
+		  /* Compute the new buffer end.  */
+		  bufferend = (char *) &new_h_aliases[naliases + 1];
+		  assert (bufferend <= buffer + buflen);
+
+		  result = old_result;
+		}
+	    }
+
+	  if (status == NSS_STATUS_TRYAGAIN)
+	    {
+	      size_t newsize = 2 * tmp_buflen;
+	      if (tmp_buffer_malloced)
+		{
+		  char *newp = realloc (tmp_buffer, newsize);
+		  if (newp != NULL)
+		    {
+		      assert ((((uintptr_t) newp)
+			       & (__alignof__ (struct hostent_data) - 1))
+			      == 0);
+		      tmp_buffer = newp;
+		      tmp_buflen = newsize;
+		      goto again;
+		    }
+		}
+	      else if (!__libc_use_alloca (buflen + newsize))
+		{
+		  tmp_buffer = malloc (newsize);
+		  if (tmp_buffer != NULL)
+		    {
+		      assert ((((uintptr_t) tmp_buffer)
+			       & (__alignof__ (struct hostent_data) - 1))
+			      == 0);
+		      tmp_buffer_malloced = true;
+		      tmp_buflen = newsize;
+		      goto again;
+		    }
+		}
+	      else
+		{
+		  tmp_buffer
+		    = extend_alloca (tmp_buffer, tmp_buflen,
+				     newsize
+				     + __alignof__ (struct hostent_data));
+		  tmp_buffer = (char *) (((uintptr_t) tmp_buffer
+					  + __alignof__ (struct hostent_data)
+					  - 1)
+					 & ~(__alignof__ (struct hostent_data)
+					     - 1));
+		  goto again;
+		}
+	    }
+	  else
+	    status = NSS_STATUS_SUCCESS;
+	out:
+	  if (tmp_buffer_malloced)
+	    free (tmp_buffer);
+	}
+
+      internal_endent (&stream);
+    }
+
+  if (canonp && status == NSS_STATUS_SUCCESS)
+    *canonp = result->h_name;
+
+  return status;
+}
+
+enum nss_status
+_nss_files_gethostbyname_r (const char *name, struct hostent *result,
+			    char *buffer, size_t buflen, int *errnop,
+			    int *herrnop)
+{
+  int af = (res_use_inet6 () ? AF_INET6 : AF_INET);
+
+  return _nss_files_gethostbyname3_r (name, af, result, buffer, buflen,
+				      errnop, herrnop, NULL, NULL);
+}
+
+enum nss_status
+_nss_files_gethostbyname2_r (const char *name, int af, struct hostent *result,
+			     char *buffer, size_t buflen, int *errnop,
+			     int *herrnop)
+{
+  return _nss_files_gethostbyname3_r (name, af, result, buffer, buflen,
+				      errnop, herrnop, NULL, NULL);
+}
+
+enum nss_status
+_nss_files_gethostbyname4_r (const char *name, struct gaih_addrtuple **pat,
+			     char *buffer, size_t buflen, int *errnop,
+			     int *herrnop, int32_t *ttlp)
+{
+  FILE *stream = NULL;
+
+  /* Open file.  */
+  enum nss_status status = internal_setent (&stream);
+
+  if (status == NSS_STATUS_SUCCESS)
+    {
+      bool any = false;
+      bool got_canon = false;
+      while (1)
+	{
+	  /* Align the buffer for the next record.  */
+	  uintptr_t pad = (-(uintptr_t) buffer
+			   % __alignof__ (struct hostent_data));
+	  buffer += pad;
+	  buflen = buflen > pad ? buflen - pad : 0;
+
+	  struct hostent result;
+	  status = internal_getent (stream, &result, buffer, buflen, errnop,
+				    herrnop, AF_UNSPEC, 0);
+	  if (status != NSS_STATUS_SUCCESS)
+	    break;
+
+	  int naliases = 0;
+	  if (__strcasecmp (name, result.h_name) != 0)
+	    {
+	      for (; result.h_aliases[naliases] != NULL; ++naliases)
+		if (! __strcasecmp (name, result.h_aliases[naliases]))
+		  break;
+	      if (result.h_aliases[naliases] == NULL)
+		continue;
+
+	      /* We know this alias exist.  Count it.  */
+	      ++naliases;
+	    }
+
+	  /* Determine how much memory has been used so far.  */
+	  // XXX It is not necessary to preserve the aliases array
+	  while (result.h_aliases[naliases] != NULL)
+	    ++naliases;
+	  char *bufferend = (char *) &result.h_aliases[naliases + 1];
+	  assert (buflen >= bufferend - buffer);
+	  buflen -= bufferend - buffer;
+	  buffer = bufferend;
+
+	  /* We found something.  */
+	  any = true;
+
+	  /* Create the record the caller expects.  There is only one
+	     address.  */
+	  assert (result.h_addr_list[1] == NULL);
+	  if (*pat == NULL)
+	    {
+	      uintptr_t pad = (-(uintptr_t) buffer
+			       % __alignof__ (struct gaih_addrtuple));
+	      buffer += pad;
+	      buflen = buflen > pad ? buflen - pad : 0;
+
+	      if (__builtin_expect (buflen < sizeof (struct gaih_addrtuple),
+				    0))
+		{
+		  *errnop = ERANGE;
+		  *herrnop = NETDB_INTERNAL;
+		  status = NSS_STATUS_TRYAGAIN;
+		  break;
+		}
+
+	      *pat = (struct gaih_addrtuple *) buffer;
+	      buffer += sizeof (struct gaih_addrtuple);
+	      buflen -= sizeof (struct gaih_addrtuple);
+	    }
+
+	  (*pat)->next = NULL;
+	  (*pat)->name = got_canon ? NULL : result.h_name;
+	  got_canon = true;
+	  (*pat)->family = result.h_addrtype;
+	  memcpy ((*pat)->addr, result.h_addr_list[0], result.h_length);
+	  (*pat)->scopeid = 0;
+
+	  pat = &((*pat)->next);
+
+	  /* If we only look for the first matching entry we are done.  */
+	  if ((_res_hconf.flags & HCONF_FLAG_MULTI) == 0)
+	    break;
+	}
+
+      /* If we have to look for multiple records and found one, this
+	 is a success.  */
+      if (status == NSS_STATUS_NOTFOUND && any)
+	{
+	  assert ((_res_hconf.flags & HCONF_FLAG_MULTI) != 0);
+	  status = NSS_STATUS_SUCCESS;
+	}
+
+      internal_endent (&stream);
+    }
+  else if (status == NSS_STATUS_TRYAGAIN)
+    {
+      *errnop = errno;
+      *herrnop = TRY_AGAIN;
+    }
+  else
+    {
+      *errnop = errno;
+      *herrnop = NO_DATA;
+    }
+
+  return status;
+}
diff --git a/REORG.TODO/nss/nss_files/files-init.c b/REORG.TODO/nss/nss_files/files-init.c
new file mode 100644
index 0000000000..9243d86cc9
--- /dev/null
+++ b/REORG.TODO/nss/nss_files/files-init.c
@@ -0,0 +1,64 @@
+/* Initialization in nss_files module.
+   Copyright (C) 2011-2017 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, see
+   <http://www.gnu.org/licenses/>.  */
+
+#ifdef USE_NSCD
+
+#include <string.h>
+#include <nscd/nscd.h>
+
+#define PWD_FILENAME "/etc/passwd"
+define_traced_file (pwd, PWD_FILENAME);
+
+#define GRP_FILENAME "/etc/group"
+define_traced_file (grp, GRP_FILENAME);
+
+#define HST_FILENAME "/etc/hosts"
+define_traced_file (hst, HST_FILENAME);
+
+#define RESOLV_FILENAME "/etc/resolv.conf"
+define_traced_file (resolv, RESOLV_FILENAME);
+
+#define SERV_FILENAME "/etc/services"
+define_traced_file (serv, SERV_FILENAME);
+
+#define NETGR_FILENAME "/etc/netgroup"
+define_traced_file (netgr, NETGR_FILENAME);
+
+void
+_nss_files_init (void (*cb) (size_t, struct traced_file *))
+{
+  init_traced_file (&pwd_traced_file.file, PWD_FILENAME, 0);
+  cb (pwddb, &pwd_traced_file.file);
+
+  init_traced_file (&grp_traced_file.file, GRP_FILENAME, 0);
+  cb (grpdb, &grp_traced_file.file);
+
+  init_traced_file (&hst_traced_file.file, HST_FILENAME, 0);
+  cb (hstdb, &hst_traced_file.file);
+
+  init_traced_file (&resolv_traced_file.file, RESOLV_FILENAME, 1);
+  cb (hstdb, &resolv_traced_file.file);
+
+  init_traced_file (&serv_traced_file.file, SERV_FILENAME, 0);
+  cb (servdb, &serv_traced_file.file);
+
+  init_traced_file (&netgr_traced_file.file, NETGR_FILENAME, 0);
+  cb (netgrdb, &netgr_traced_file.file);
+}
+
+#endif
diff --git a/REORG.TODO/nss/nss_files/files-initgroups.c b/REORG.TODO/nss/nss_files/files-initgroups.c
new file mode 100644
index 0000000000..27cd8ece40
--- /dev/null
+++ b/REORG.TODO/nss/nss_files/files-initgroups.c
@@ -0,0 +1,142 @@
+/* Initgroups handling in nss_files module.
+   Copyright (C) 2011-2017 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, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <alloca.h>
+#include <errno.h>
+#include <grp.h>
+#include <nss.h>
+#include <stdio_ext.h>
+#include <string.h>
+#include <sys/param.h>
+#include <stdbool.h>
+#include <stdlib.h>
+
+enum nss_status
+_nss_files_initgroups_dyn (const char *user, gid_t group, long int *start,
+			   long int *size, gid_t **groupsp, long int limit,
+			   int *errnop)
+{
+  FILE *stream = fopen ("/etc/group", "rce");
+  if (stream == NULL)
+    {
+      *errnop = errno;
+      return *errnop == ENOMEM ? NSS_STATUS_TRYAGAIN : NSS_STATUS_UNAVAIL;
+    }
+
+  /* No other thread using this stream.  */
+  __fsetlocking (stream, FSETLOCKING_BYCALLER);
+
+  char *line = NULL;
+  size_t linelen = 0;
+  enum nss_status status = NSS_STATUS_SUCCESS;
+  bool any = false;
+
+  size_t buflen = 1024;
+  void *buffer = alloca (buflen);
+  bool buffer_use_malloc = false;
+
+  gid_t *groups = *groupsp;
+
+  /* We have to iterate over the entire file.  */
+  while (1)
+    {
+      fpos_t pos;
+      fgetpos (stream, &pos);
+      ssize_t n = getline (&line, &linelen, stream);
+      if (n < 0)
+	{
+	  if (! feof_unlocked (stream))
+	    status = ((*errnop = errno) == ENOMEM
+		      ? NSS_STATUS_TRYAGAIN : NSS_STATUS_UNAVAIL);
+	  break;
+	}
+
+      struct group grp;
+      int res = _nss_files_parse_grent (line, &grp, buffer, buflen, errnop);
+      if (res == -1)
+	{
+	  size_t newbuflen = 2 * buflen;
+	  if (buffer_use_malloc || ! __libc_use_alloca (buflen + newbuflen))
+	    {
+	      void *newbuf = realloc (buffer_use_malloc ? buffer : NULL,
+				      newbuflen);
+	      if (newbuf == NULL)
+		{
+		  *errnop = ENOMEM;
+		  status = NSS_STATUS_TRYAGAIN;
+		  goto out;
+		}
+	      buffer = newbuf;
+	      buflen = newbuflen;
+	      buffer_use_malloc = true;
+	    }
+	  else
+	    buffer = extend_alloca (buffer, buflen, newbuflen);
+	  /* Reread current line, the parser has clobbered it.  */
+	  fsetpos (stream, &pos);
+	  continue;
+	}
+
+      if (res > 0 && grp.gr_gid != group)
+	for (char **m = grp.gr_mem; *m != NULL; ++m)
+	  if (strcmp (*m, user) == 0)
+	    {
+	      /* Matches user.  Insert this group.  */
+	      if (*start == *size)
+		{
+		  /* Need a bigger buffer.  */
+		  if (limit > 0 && *size == limit)
+		    /* We reached the maximum.  */
+		    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] = grp.gr_gid;
+	      *start += 1;
+	      any = true;
+
+	      break;
+	    }
+    }
+
+ out:
+  /* Free memory.  */
+  if (buffer_use_malloc)
+    free (buffer);
+  free (line);
+
+  fclose (stream);
+
+  return status == NSS_STATUS_SUCCESS && !any ? NSS_STATUS_NOTFOUND : status;
+}
diff --git a/REORG.TODO/nss/nss_files/files-key.c b/REORG.TODO/nss/nss_files/files-key.c
new file mode 100644
index 0000000000..11a574a0b1
--- /dev/null
+++ b/REORG.TODO/nss/nss_files/files-key.c
@@ -0,0 +1,111 @@
+/* Public key file parser in nss_files module.
+   Copyright (C) 1996-2017 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, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <netdb.h>
+#include <rpc/key_prot.h>
+#include <rpc/des_crypt.h>
+#include "nsswitch.h"
+
+#define DATAFILE "/etc/publickey"
+
+
+static enum nss_status
+search (const char *netname, char *result, int *errnop, int secret)
+{
+  FILE *stream = fopen (DATAFILE, "rce");
+  if (stream == NULL)
+    return errno == EAGAIN ? NSS_STATUS_TRYAGAIN : NSS_STATUS_UNAVAIL;
+
+  for (;;)
+    {
+      char buffer[HEXKEYBYTES * 2 + KEYCHECKSUMSIZE + MAXNETNAMELEN + 17];
+      char *p;
+      char *save_ptr;
+
+      buffer[sizeof (buffer) - 1] = '\xff';
+      p = fgets_unlocked (buffer, sizeof (buffer), stream);
+      if (p == NULL)
+	{
+	  /* End of file or read error.  */
+	  *errnop = errno;
+	  fclose (stream);
+	  return NSS_STATUS_NOTFOUND;
+	}
+      else if (buffer[sizeof (buffer) - 1] != '\xff')
+	{
+	  /* Invalid line in file?  Skip remainder of line.  */
+	  if (buffer[sizeof (buffer) - 2] != '\0')
+	    while (getc_unlocked (stream) != '\n')
+	      continue;
+	  continue;
+	}
+
+      /* Parse line.  */
+      p = __strtok_r (buffer, "# \t:\n", &save_ptr);
+      if (p == NULL) /* Skip empty and comment lines.  */
+	continue;
+      if (strcmp (p, netname) != 0)
+	continue;
+
+      /* A hit!  Find the field we want and return.  */
+      p = __strtok_r (NULL, ":\n", &save_ptr);
+      if (p == NULL)  /* malformed line? */
+	continue;
+      if (secret)
+	p = __strtok_r (NULL, ":\n", &save_ptr);
+      if (p == NULL)  /* malformed line? */
+	continue;
+      fclose (stream);
+      strcpy (result, p);
+      return NSS_STATUS_SUCCESS;
+    }
+}
+
+enum nss_status
+_nss_files_getpublickey (const char *netname, char *pkey, int *errnop)
+{
+  return search (netname, pkey, errnop, 0);
+}
+
+enum nss_status
+_nss_files_getsecretkey (const char *netname, char *skey, char *passwd,
+			 int *errnop)
+{
+  enum nss_status status;
+  char buf[HEXKEYBYTES + KEYCHECKSUMSIZE + 16];
+
+  skey[0] = 0;
+
+  status = search (netname, buf, errnop, 1);
+  if (status != NSS_STATUS_SUCCESS)
+    return status;
+
+  if (!xdecrypt (buf, passwd))
+    return NSS_STATUS_SUCCESS;
+
+  if (memcmp (buf, &(buf[HEXKEYBYTES]), KEYCHECKSUMSIZE) != 0)
+    return NSS_STATUS_SUCCESS;
+
+  buf[HEXKEYBYTES] = 0;
+  strcpy (skey, buf);
+
+  return NSS_STATUS_SUCCESS;
+}
diff --git a/REORG.TODO/nss/nss_files/files-netgrp.c b/REORG.TODO/nss/nss_files/files-netgrp.c
new file mode 100644
index 0000000000..009ce02432
--- /dev/null
+++ b/REORG.TODO/nss/nss_files/files-netgrp.c
@@ -0,0 +1,294 @@
+/* Netgroup file parser in nss_files modules.
+   Copyright (C) 1996-2017 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, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <ctype.h>
+#include <errno.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <stdio_ext.h>
+#include <stdlib.h>
+#include <string.h>
+#include "nsswitch.h"
+#include "netgroup.h"
+
+#define DATAFILE	"/etc/netgroup"
+
+libnss_files_hidden_proto (_nss_files_endnetgrent)
+
+#define EXPAND(needed)							      \
+  do									      \
+    {									      \
+      size_t old_cursor = result->cursor - result->data;		      \
+      void *old_data = result->data;					      \
+									      \
+      result->data_size += 512 > 2 * needed ? 512 : 2 * needed;		      \
+      result->data = realloc (result->data, result->data_size);		      \
+									      \
+      if (result->data == NULL)						      \
+	{								      \
+	  free (old_data);						      \
+	  status = NSS_STATUS_UNAVAIL;					      \
+	  goto the_end;							      \
+	}								      \
+									      \
+      result->cursor = result->data + old_cursor;			      \
+    }									      \
+  while (0)
+
+
+enum nss_status
+_nss_files_setnetgrent (const char *group, struct __netgrent *result)
+{
+  FILE *fp;
+  enum nss_status status;
+
+  if (group[0] == '\0')
+    return NSS_STATUS_UNAVAIL;
+
+  /* Find the netgroups file and open it.  */
+  fp = fopen (DATAFILE, "rce");
+  if (fp == NULL)
+    status = errno == EAGAIN ? NSS_STATUS_TRYAGAIN : NSS_STATUS_UNAVAIL;
+  else
+    {
+      /* Read the file line by line and try to find the description
+	 GROUP.  We must take care for long lines.  */
+      char *line = NULL;
+      size_t line_len = 0;
+      const ssize_t group_len = strlen (group);
+
+      status = NSS_STATUS_NOTFOUND;
+      result->cursor = result->data;
+
+      __fsetlocking (fp, FSETLOCKING_BYCALLER);
+
+      while (!feof_unlocked (fp))
+	{
+	  ssize_t curlen = getline (&line, &line_len, fp);
+	  int found;
+
+	  if (curlen < 0)
+	    {
+	      status = NSS_STATUS_NOTFOUND;
+	      break;
+	    }
+
+	  found = (curlen > group_len && strncmp (line, group, group_len) == 0
+		   && isspace (line[group_len]));
+
+	  /* Read the whole line (including continuation) and store it
+	     if FOUND in nonzero.  Otherwise we don't need it.  */
+	  if (found)
+	    {
+	      /* Store the data from the first line.  */
+	      EXPAND (curlen - group_len);
+	      memcpy (result->cursor, &line[group_len + 1],
+		      curlen - group_len);
+	      result->cursor += (curlen - group_len) - 1;
+	    }
+
+	  while (curlen > 1 && line[curlen - 1] == '\n'
+		 && line[curlen - 2] == '\\')
+	    {
+	      /* Yes, we have a continuation line.  */
+	      if (found)
+		/* Remove these characters from the stored line.  */
+		result->cursor -= 2;
+
+	      /* Get next line.  */
+	      curlen = getline (&line, &line_len, fp);
+	      if (curlen <= 0)
+		break;
+
+	      if (found)
+		{
+		  /* Make sure we have enough room.  */
+		  EXPAND (1 + curlen + 1);
+
+		  /* Add separator in case next line starts immediately.  */
+		  *result->cursor++ = ' ';
+
+		  /* Copy new line.  */
+		  memcpy (result->cursor, line, curlen + 1);
+		  result->cursor += curlen;
+		}
+	    }
+
+	  if (found)
+	    {
+	      /* Now we have read the line.  */
+	      status = NSS_STATUS_SUCCESS;
+	      result->cursor = result->data;
+	      result->first = 1;
+	      break;
+	    }
+	}
+
+    the_end:
+      /* We don't need the file and the line buffer anymore.  */
+      free (line);
+      fclose (fp);
+
+      if (status != NSS_STATUS_SUCCESS)
+	_nss_files_endnetgrent (result);
+    }
+
+  return status;
+}
+
+
+enum nss_status
+_nss_files_endnetgrent (struct __netgrent *result)
+{
+  /* Free allocated memory for data if some is present.  */
+  free (result->data);
+  result->data = NULL;
+  result->data_size = 0;
+  result->cursor = NULL;
+  return NSS_STATUS_SUCCESS;
+}
+libnss_files_hidden_def (_nss_files_endnetgrent)
+
+static char *
+strip_whitespace (char *str)
+{
+  char *cp = str;
+
+  /* Skip leading spaces.  */
+  while (isspace (*cp))
+    cp++;
+
+  str = cp;
+  while (*cp != '\0' && ! isspace(*cp))
+    cp++;
+
+  /* Null-terminate, stripping off any trailing spaces.  */
+  *cp = '\0';
+
+  return *str == '\0' ? NULL : str;
+}
+
+enum nss_status
+_nss_netgroup_parseline (char **cursor, struct __netgrent *result,
+			 char *buffer, size_t buflen, int *errnop)
+{
+  enum nss_status status;
+  const char *host, *user, *domain;
+  char *cp = *cursor;
+
+  /* Some sanity checks.  */
+  if (cp == NULL)
+    return NSS_STATUS_NOTFOUND;
+
+  /* First skip leading spaces.  */
+  while (isspace (*cp))
+    ++cp;
+
+  if (*cp != '(')
+    {
+      /* We have a list of other netgroups.  */
+      char *name = cp;
+
+      while (*cp != '\0' && ! isspace (*cp))
+	++cp;
+
+      if (name != cp)
+	{
+	  /* It is another netgroup name.  */
+	  int last = *cp == '\0';
+
+	  result->type = group_val;
+	  result->val.group = name;
+	  *cp = '\0';
+	  if (! last)
+	    ++cp;
+	  *cursor = cp;
+	  result->first = 0;
+
+	  return NSS_STATUS_SUCCESS;
+	}
+
+      return result->first ? NSS_STATUS_NOTFOUND : NSS_STATUS_RETURN;
+    }
+
+  /* Match host name.  */
+  host = ++cp;
+  while (*cp != ',')
+    if (*cp++ == '\0')
+      return result->first ? NSS_STATUS_NOTFOUND : NSS_STATUS_RETURN;
+
+  /* Match user name.  */
+  user = ++cp;
+  while (*cp != ',')
+    if (*cp++ == '\0')
+      return result->first ? NSS_STATUS_NOTFOUND : NSS_STATUS_RETURN;
+
+  /* Match domain name.  */
+  domain = ++cp;
+  while (*cp != ')')
+    if (*cp++ == '\0')
+      return result->first ? NSS_STATUS_NOTFOUND : NSS_STATUS_RETURN;
+  ++cp;
+
+
+  /* When we got here we have found an entry.  Before we can copy it
+     to the private buffer we have to make sure it is big enough.  */
+  if (cp - host > buflen)
+    {
+      *errnop = ERANGE;
+      status = NSS_STATUS_TRYAGAIN;
+    }
+  else
+    {
+      memcpy (buffer, host, cp - host);
+      result->type = triple_val;
+
+      buffer[(user - host) - 1] = '\0';	/* Replace ',' with '\0'.  */
+      result->val.triple.host = strip_whitespace (buffer);
+
+      buffer[(domain - host) - 1] = '\0'; /* Replace ',' with '\0'.  */
+      result->val.triple.user = strip_whitespace (buffer + (user - host));
+
+      buffer[(cp - host) - 1] = '\0'; /* Replace ')' with '\0'.  */
+      result->val.triple.domain = strip_whitespace (buffer + (domain - host));
+
+      status = NSS_STATUS_SUCCESS;
+
+      /* Remember where we stopped reading.  */
+      *cursor = cp;
+
+      result->first = 0;
+    }
+
+  return status;
+}
+libnss_files_hidden_def (_nss_netgroup_parseline)
+
+
+enum nss_status
+_nss_files_getnetgrent_r (struct __netgrent *result, char *buffer,
+			  size_t buflen, int *errnop)
+{
+  enum nss_status status;
+
+  status = _nss_netgroup_parseline (&result->cursor, result, buffer, buflen,
+				    errnop);
+
+  return status;
+}
diff --git a/REORG.TODO/nss/nss_files/files-network.c b/REORG.TODO/nss/nss_files/files-network.c
new file mode 100644
index 0000000000..1fbd60fcf2
--- /dev/null
+++ b/REORG.TODO/nss/nss_files/files-network.c
@@ -0,0 +1,88 @@
+/* Networks file parser in nss_files module.
+   Copyright (C) 1996-2017 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, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <stdint.h>
+
+#define ENTNAME		netent
+#define DATABASE	"networks"
+#define NEED_H_ERRNO
+
+struct netent_data {};
+
+#define TRAILING_LIST_MEMBER		n_aliases
+#define TRAILING_LIST_SEPARATOR_P	isspace
+#include "files-parse.c"
+LINE_PARSER
+("#",
+ {
+   char *addr;
+   char *cp;
+   int n = 1;
+
+   STRING_FIELD (result->n_name, isspace, 1);
+
+   STRING_FIELD (addr, isspace, 1);
+   /* 'inet_network' does not add zeroes at the end if the network number
+      does not four byte values.  We add them outselves if necessary.  */
+   cp = strchr (addr, '.');
+   if (cp != NULL)
+     {
+       ++n;
+       cp = strchr (cp + 1, '.');
+       if (cp != NULL)
+	 {
+	   ++n;
+	   cp = strchr (cp + 1, '.');
+	   if (cp != NULL)
+	     ++n;
+	 }
+     }
+   if (n < 4)
+     {
+       char *newp = (char *) alloca (strlen (addr) + (4 - n) * 2 + 1);
+       cp = stpcpy (newp, addr);
+       do
+	 {
+	   *cp++ = '.';
+	   *cp++ = '0';
+	 }
+       while (++n < 4);
+       *cp = '\0';
+       addr = newp;
+     }
+   result->n_net = inet_network (addr);
+   result->n_addrtype = AF_INET;
+
+ })
+
+#include "files-XXX.c"
+
+DB_LOOKUP (netbyname, ,,,
+	   LOOKUP_NAME_CASE (n_name, n_aliases),
+	   const char *name)
+
+DB_LOOKUP (netbyaddr, ,,,
+	   {
+	     if ((type == AF_UNSPEC || result->n_addrtype == type)
+		 && result->n_net == net)
+	       /* Bingo!  */
+	       break;
+	   }, uint32_t net, int type)
diff --git a/REORG.TODO/nss/nss_files/files-parse.c b/REORG.TODO/nss/nss_files/files-parse.c
new file mode 100644
index 0000000000..b31ff9e17b
--- /dev/null
+++ b/REORG.TODO/nss/nss_files/files-parse.c
@@ -0,0 +1,335 @@
+/* Common code for file-based database parsers in nss_files module.
+   Copyright (C) 1996-2017 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, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <ctype.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdint.h>
+
+/* These symbols are defined by the including source file:
+
+   ENTNAME -- database name of the structure and functions (hostent, pwent).
+   STRUCTURE -- struct name, define only if not ENTNAME (passwd, group).
+   DATABASE -- string of the database file's name ("hosts", "passwd").
+
+   ENTDATA -- if defined, `struct ENTDATA' is used by the parser to store
+	      things pointed to by the resultant `struct STRUCTURE'.
+
+   NEED_H_ERRNO - defined iff an arg `int *herrnop' is used.
+
+   EXTRA_ARGS -- defined iff extra parameters must be passed to the parser
+   EXTRA_ARGS_DECL -- declaration for these extra parameters
+   EXTRA_ARGS_VALUE -- values to be passed for these parameters
+
+   Also see files-XXX.c.  */
+
+#ifndef EXTRA_ARGS
+# define EXTRA_ARGS
+# define EXTRA_ARGS_DECL
+# define EXTRA_ARGS_VALUE
+#endif
+
+#define CONCAT(a,b) CONCAT1(a,b)
+#define CONCAT1(a,b) a##b
+
+#ifndef STRUCTURE
+# define STRUCTURE ENTNAME
+#endif
+
+
+struct parser_data
+  {
+#ifdef ENTDATA
+    struct ENTDATA entdata;
+# define ENTDATA_DECL(data) struct ENTDATA *const entdata = &data->entdata;
+#else
+# define ENTDATA_DECL(data)
+#endif
+    char linebuffer[0];
+  };
+
+#ifdef ENTDATA
+/* The function can't be exported, because the entdata structure
+   is defined only in files-foo.c.  */
+# define parser_stclass static
+# define nss_files_parse_hidden_def(name)
+#else
+/* Export the line parser function so it can be used in nss_db.  */
+# define parser_stclass /* Global */
+# define parse_line CONCAT(_nss_files_parse_,ENTNAME)
+# if IS_IN (libc)
+/* We are defining one of the functions that actually lives in libc
+   because it is used to implement fget*ent and suchlike.  */
+#  define nss_files_parse_hidden_def(name) libc_hidden_def (name)
+# else
+#  define nss_files_parse_hidden_def(name) libnss_files_hidden_def (name)
+# endif
+#endif
+
+
+#ifdef EXTERN_PARSER
+
+/* The parser is defined in a different module.  */
+extern int parse_line (char *line, struct STRUCTURE *result,
+		       struct parser_data *data, size_t datalen, int *errnop
+		       EXTRA_ARGS_DECL);
+
+# define LINE_PARSER(EOLSET, BODY) /* Do nothing */
+
+#else
+
+/* Define a line parsing function.  */
+
+# define LINE_PARSER(EOLSET, BODY)					      \
+parser_stclass int							      \
+parse_line (char *line, struct STRUCTURE *result,			      \
+	    struct parser_data *data, size_t datalen, int *errnop	      \
+	    EXTRA_ARGS_DECL)						      \
+{									      \
+  ENTDATA_DECL (data)							      \
+  BUFFER_PREPARE							      \
+  char *p = strpbrk (line, EOLSET "\n");				      \
+  if (p != NULL)							      \
+    *p = '\0';								      \
+  BODY;									      \
+  TRAILING_LIST_PARSER;							      \
+  return 1;								      \
+}									      \
+nss_files_parse_hidden_def (parse_line)
+
+
+# define STRING_FIELD(variable, terminator_p, swallow)			      \
+  {									      \
+    variable = line;							      \
+    while (*line != '\0' && !terminator_p (*line))			      \
+      ++line;								      \
+    if (*line != '\0')							      \
+      {									      \
+	*line = '\0';							      \
+	do								      \
+	  ++line;							      \
+	while (swallow && terminator_p (*line));			      \
+      }									      \
+  }
+
+# define STRING_LIST(variable, terminator_c) \
+  {									      \
+    char **list = parse_list (&line, buf_start, buf_end, terminator_c,	      \
+			      errnop);					      \
+    if (list)								      \
+      variable = list;							      \
+    else								      \
+      return -1;		/* -1 indicates we ran out of space.  */      \
+									      \
+    /* Determine the new end of the buffer.  */				      \
+    while (*list != NULL)						      \
+      ++list;								      \
+    buf_start = (char *) (list + 1);					      \
+  }
+
+/* Helper function.  */
+static inline uint32_t
+__attribute__ ((always_inline))
+strtou32 (const char *nptr, char **endptr, int base)
+{
+  unsigned long int val = strtoul (nptr, endptr, base);
+
+  /* Match the 32-bit behavior on 64-bit platforms.  */
+  if (sizeof (long int) > 4 && val > 0xffffffff)
+    val = 0xffffffff;
+
+  return val;
+}
+
+# define INT_FIELD(variable, terminator_p, swallow, base, convert)	      \
+  {									      \
+    char *endp;								      \
+    variable = convert (strtou32 (line, &endp, base));			      \
+    if (endp == line)							      \
+      return 0;								      \
+    else if (terminator_p (*endp))					      \
+      do								      \
+	++endp;								      \
+      while (swallow && terminator_p (*endp));				      \
+    else if (*endp != '\0')						      \
+      return 0;								      \
+    line = endp;							      \
+  }
+
+# define INT_FIELD_MAYBE_NULL(variable, terminator_p, swallow, base, convert, default)	      \
+  {									      \
+    char *endp;								      \
+    if (*line == '\0')							      \
+      /* We expect some more input, so don't allow the string to end here. */ \
+      return 0;								      \
+    variable = convert (strtou32 (line, &endp, base));			      \
+    if (endp == line)							      \
+      variable = default;						      \
+    if (terminator_p (*endp))						      \
+      do								      \
+	++endp;								      \
+      while (swallow && terminator_p (*endp));				      \
+    else if (*endp != '\0')						      \
+      return 0;								      \
+    line = endp;							      \
+  }
+
+# define ISCOLON(c) ((c) == ':')
+
+
+# ifndef TRAILING_LIST_MEMBER
+#  define BUFFER_PREPARE /* Nothing to do.  */
+#  define TRAILING_LIST_PARSER /* Nothing to do.  */
+# else
+
+# define BUFFER_PREPARE \
+  char *buf_start = NULL;						      \
+  char *buf_end = (char *) data + datalen;				      \
+  if (line >= data->linebuffer && line < buf_end)			      \
+    /* Find the end of the line buffer, we will use the space in	      \
+       DATA after it for storing the vector of pointers.  */		      \
+    buf_start = strchr (line, '\0') + 1;				      \
+  else									      \
+    /* LINE does not point within DATA->linebuffer, so that space is	      \
+       not being used for scratch space right now.  We can use all of	      \
+       it for the pointer vector storage.  */				      \
+    buf_start = data->linebuffer;					      \
+
+#  define TRAILING_LIST_PARSER \
+{									      \
+  if (buf_start == NULL)						      \
+    {									      \
+      if (line >= data->linebuffer && line < buf_end)			      \
+	/* Find the end of the line buffer, we will use the space in	      \
+	   DATA after it for storing the vector of pointers.  */	      \
+	buf_start = strchr (line, '\0') + 1;				      \
+      else								      \
+	/* LINE does not point within DATA->linebuffer, so that space is      \
+	   not being used for scratch space right now.  We can use all of     \
+	   it for the pointer vector storage.  */			      \
+	buf_start = data->linebuffer;					      \
+    }									      \
+									      \
+  char **list = parse_list (&line, buf_start, buf_end, '\0', errnop);	      \
+  if (list)								      \
+    result->TRAILING_LIST_MEMBER = list;				      \
+  else									      \
+    return -1;		/* -1 indicates we ran out of space.  */	      \
+}
+
+static inline char **
+__attribute ((always_inline))
+parse_list (char **linep, char *eol, char *buf_end, int terminator_c,
+	    int *errnop)
+{
+  char *line = *linep;
+  char **list, **p;
+
+  /* Adjust the pointer so it is aligned for storing pointers.  */
+  eol += __alignof__ (char *) - 1;
+  eol -= (eol - (char *) 0) % __alignof__ (char *);
+  /* We will start the storage here for the vector of pointers.  */
+  list = (char **) eol;
+
+  p = list;
+  while (1)
+    {
+      if ((char *) (p + 2) > buf_end)
+	{
+	  /* We cannot fit another pointer in the buffer.  */
+	  *errnop = ERANGE;
+	  return NULL;
+	}
+
+      if (*line == '\0')
+	break;
+      if (*line == terminator_c)
+	{
+	  ++line;
+	  break;
+	}
+
+      /* Skip leading white space.  This might not be portable but useful.  */
+      while (isspace (*line))
+	++line;
+
+      char *elt = line;
+      while (1)
+	{
+	  if (*line == '\0' || *line == terminator_c
+	      || TRAILING_LIST_SEPARATOR_P (*line))
+	    {
+	      /* End of the next entry.  */
+	      if (line > elt)
+		/* We really found some data.  */
+		*p++ = elt;
+
+	      /* Terminate string if necessary.  */
+	      if (*line != '\0')
+		{
+		  char endc = *line;
+		  *line++ = '\0';
+		  if (endc == terminator_c)
+		    goto out;
+		}
+	      break;
+	    }
+	  ++line;
+	}
+    }
+ out:
+  *p = NULL;
+  *linep = line;
+
+  return list;
+}
+
+# endif	/* TRAILING_LIST_MEMBER */
+#endif	/* EXTERN_PARSER */
+
+
+#define LOOKUP_NAME(nameelt, aliaselt)					      \
+{									      \
+  char **ap;								      \
+  if (! strcmp (name, result->nameelt))					      \
+    break;								      \
+  for (ap = result->aliaselt; *ap; ++ap)				      \
+    if (! strcmp (name, *ap))						      \
+      break;								      \
+  if (*ap)								      \
+    break;								      \
+}
+
+#define LOOKUP_NAME_CASE(nameelt, aliaselt)				      \
+{									      \
+  char **ap;								      \
+  if (! __strcasecmp (name, result->nameelt))				      \
+    break;								      \
+  for (ap = result->aliaselt; *ap; ++ap)				      \
+    if (! __strcasecmp (name, *ap))					      \
+      break;								      \
+  if (*ap)								      \
+    break;								      \
+}
+
+
+/* This is defined by db-*.c to include "../nss_db/db-XXX.c" instead.  */
+#ifndef GENERIC
+# define GENERIC "files-XXX.c"
+#endif
diff --git a/REORG.TODO/nss/nss_files/files-proto.c b/REORG.TODO/nss/nss_files/files-proto.c
new file mode 100644
index 0000000000..5402a7a300
--- /dev/null
+++ b/REORG.TODO/nss/nss_files/files-proto.c
@@ -0,0 +1,46 @@
+/* Protocols file parser in nss_files module.
+   Copyright (C) 1996-2017 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, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <netdb.h>
+
+
+#define ENTNAME		protoent
+#define DATABASE	"protocols"
+
+struct protoent_data {};
+
+#define TRAILING_LIST_MEMBER		p_aliases
+#define TRAILING_LIST_SEPARATOR_P	isspace
+#include "files-parse.c"
+LINE_PARSER
+("#",
+ STRING_FIELD (result->p_name, isspace, 1);
+ INT_FIELD (result->p_proto, isspace, 1, 10,);
+ )
+
+#include GENERIC
+
+DB_LOOKUP (protobyname, '.', 0, ("%s", name),
+	   LOOKUP_NAME (p_name, p_aliases),
+	   const char *name)
+
+DB_LOOKUP (protobynumber, '=', 20, ("%zd", (ssize_t) proto),
+	   {
+	     if (result->p_proto == proto)
+	       break;
+	   }, int proto)
diff --git a/REORG.TODO/nss/nss_files/files-pwd.c b/REORG.TODO/nss/nss_files/files-pwd.c
new file mode 100644
index 0000000000..62c597703a
--- /dev/null
+++ b/REORG.TODO/nss/nss_files/files-pwd.c
@@ -0,0 +1,44 @@
+/* User file parser in nss_files module.
+   Copyright (C) 1996-2017 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, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <pwd.h>
+
+#define STRUCTURE	passwd
+#define ENTNAME		pwent
+#define DATABASE	"passwd"
+struct pwent_data {};
+
+/* Our parser function is already defined in fgetpwent_r.c, so use that
+   to parse lines from the database file.  */
+#define EXTERN_PARSER
+#include "files-parse.c"
+#include GENERIC
+
+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),
+	   {
+	     if (result->pw_uid == uid && result->pw_name[0] != '+'
+		 && result->pw_name[0] != '-')
+	       break;
+	   }, uid_t uid)
diff --git a/REORG.TODO/nss/nss_files/files-rpc.c b/REORG.TODO/nss/nss_files/files-rpc.c
new file mode 100644
index 0000000000..8ee0d19f32
--- /dev/null
+++ b/REORG.TODO/nss/nss_files/files-rpc.c
@@ -0,0 +1,46 @@
+/* SunRPC program number file parser in nss_files module.
+   Copyright (C) 1996-2017 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, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <rpc/netdb.h>
+
+
+#define ENTNAME		rpcent
+#define DATABASE	"rpc"
+
+struct rpcent_data {};
+
+#define TRAILING_LIST_MEMBER		r_aliases
+#define TRAILING_LIST_SEPARATOR_P	isspace
+#include "files-parse.c"
+LINE_PARSER
+("#",
+ STRING_FIELD (result->r_name, isspace, 1);
+ INT_FIELD (result->r_number, isspace, 1, 10,);
+ )
+
+#include GENERIC
+
+DB_LOOKUP (rpcbyname, '.', 0, ("%s", name),
+	   LOOKUP_NAME (r_name, r_aliases),
+	   const char *name)
+
+DB_LOOKUP (rpcbynumber, '=', 20, ("%zd", (ssize_t) number),
+	   {
+	     if (result->r_number == number)
+	       break;
+	   }, int number)
diff --git a/REORG.TODO/nss/nss_files/files-service.c b/REORG.TODO/nss/nss_files/files-service.c
new file mode 100644
index 0000000000..b6ae51082f
--- /dev/null
+++ b/REORG.TODO/nss/nss_files/files-service.c
@@ -0,0 +1,63 @@
+/* Services file parser in nss_files module.
+   Copyright (C) 1996-2017 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, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <netinet/in.h>
+#include <netdb.h>
+
+
+#define ENTNAME		servent
+#define DATABASE	"services"
+
+struct servent_data {};
+
+#define TRAILING_LIST_MEMBER		s_aliases
+#define TRAILING_LIST_SEPARATOR_P	isspace
+#include "files-parse.c"
+#define ISSLASH(c) ((c) == '/')
+LINE_PARSER
+("#",
+ STRING_FIELD (result->s_name, isspace, 1);
+ INT_FIELD (result->s_port, ISSLASH, 10, 0, htons);
+ STRING_FIELD (result->s_proto, isspace, 1);
+ )
+
+#include GENERIC
+
+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))
+	       /* A continue statement here breaks nss_db, because it
+		bypasses advancing to the next db entry, and it
+		doesn't make nss_files any more efficient.  */;
+	     else
+	       LOOKUP_NAME (s_name, s_aliases)
+	   },
+	   const char *name, const char *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
+		 && (proto == NULL
+		     || strcmp (result->s_proto, proto) == 0))
+	       break;
+	   }, int port, const char *proto)
diff --git a/REORG.TODO/nss/nss_files/files-sgrp.c b/REORG.TODO/nss/nss_files/files-sgrp.c
new file mode 100644
index 0000000000..03b7da5e2f
--- /dev/null
+++ b/REORG.TODO/nss/nss_files/files-sgrp.c
@@ -0,0 +1,37 @@
+/* User file parser in nss_files module.
+   Copyright (C) 2009-2017 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, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <gshadow.h>
+
+#define STRUCTURE	sgrp
+#define ENTNAME		sgent
+#define DATABASE	"gshadow"
+struct sgent_data {};
+
+/* Our parser function is already defined in sgetspent_r.c, so use that
+   to parse lines from the database file.  */
+#define EXTERN_PARSER
+#include "files-parse.c"
+#include GENERIC
+
+DB_LOOKUP (sgnam, '.', 0, ("%s", name),
+	   {
+	     if (name[0] != '+' && name[0] != '-'
+		 && ! strcmp (name, result->sg_namp))
+	       break;
+	   }, const char *name)
diff --git a/REORG.TODO/nss/nss_files/files-spwd.c b/REORG.TODO/nss/nss_files/files-spwd.c
new file mode 100644
index 0000000000..7f13562acb
--- /dev/null
+++ b/REORG.TODO/nss/nss_files/files-spwd.c
@@ -0,0 +1,37 @@
+/* User file parser in nss_files module.
+   Copyright (C) 1996-2017 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, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <shadow.h>
+
+#define STRUCTURE	spwd
+#define ENTNAME		spent
+#define DATABASE	"shadow"
+struct spent_data {};
+
+/* Our parser function is already defined in sgetspent_r.c, so use that
+   to parse lines from the database file.  */
+#define EXTERN_PARSER
+#include "files-parse.c"
+#include GENERIC
+
+DB_LOOKUP (spnam, '.', 0, ("%s", name),
+	   {
+	     if (name[0] != '+' && name[0] != '-'
+		 && ! strcmp (name, result->sp_namp))
+	       break;
+	   }, const char *name)
diff --git a/REORG.TODO/nss/nss_test1.c b/REORG.TODO/nss/nss_test1.c
new file mode 100644
index 0000000000..3beb488fcf
--- /dev/null
+++ b/REORG.TODO/nss/nss_test1.c
@@ -0,0 +1,154 @@
+#include <errno.h>
+#include <nss.h>
+#include <pthread.h>
+#include <string.h>
+
+
+#define COPY_IF_ROOM(s) \
+  ({ size_t len_ = strlen (s) + 1;		\
+     char *start_ = cp;				\
+     buflen - (cp - buffer) < len_		\
+     ? NULL					\
+     : (cp = mempcpy (cp, s, len_), start_); })
+
+
+/* Password handling.  */
+#include <pwd.h>
+
+static struct passwd pwd_data[] =
+  {
+#define PWD(u) \
+    { .pw_name = (char *) "name" #u, .pw_passwd = (char *) "*", .pw_uid = u,  \
+      .pw_gid = 100, .pw_gecos = (char *) "*", .pw_dir = (char *) "*",	      \
+      .pw_shell = (char *) "*" }
+    PWD (100),
+    PWD (30),
+    PWD (200),
+    PWD (60),
+    PWD (20000)
+  };
+#define npwd_data (sizeof (pwd_data) / sizeof (pwd_data[0]))
+
+static size_t pwd_iter;
+#define CURPWD pwd_data[pwd_iter]
+
+static pthread_mutex_t pwd_lock = PTHREAD_MUTEX_INITIALIZER;
+
+
+enum nss_status
+_nss_test1_setpwent (int stayopen)
+{
+  pwd_iter = 0;
+  return NSS_STATUS_SUCCESS;
+}
+
+
+enum nss_status
+_nss_test1_endpwent (void)
+{
+  return NSS_STATUS_SUCCESS;
+}
+
+
+enum nss_status
+_nss_test1_getpwent_r (struct passwd *result, char *buffer, size_t buflen,
+		       int *errnop)
+{
+  char *cp = buffer;
+  int res = NSS_STATUS_SUCCESS;
+
+  pthread_mutex_lock (&pwd_lock);
+
+  if (pwd_iter >= npwd_data)
+    res = NSS_STATUS_NOTFOUND;
+  else
+    {
+      result->pw_name = COPY_IF_ROOM (CURPWD.pw_name);
+      result->pw_passwd = COPY_IF_ROOM (CURPWD.pw_passwd);
+      result->pw_uid = CURPWD.pw_uid;
+      result->pw_gid = CURPWD.pw_gid;
+      result->pw_gecos = COPY_IF_ROOM (CURPWD.pw_gecos);
+      result->pw_dir = COPY_IF_ROOM (CURPWD.pw_dir);
+      result->pw_shell = COPY_IF_ROOM (CURPWD.pw_shell);
+
+      if (result->pw_name == NULL || result->pw_passwd == NULL
+	  || result->pw_gecos == NULL || result->pw_dir == NULL
+	  || result->pw_shell == NULL)
+	{
+	  *errnop = ERANGE;
+	  res = NSS_STATUS_TRYAGAIN;
+	}
+
+      ++pwd_iter;
+    }
+
+  pthread_mutex_unlock (&pwd_lock);
+
+  return res;
+}
+
+
+enum nss_status
+_nss_test1_getpwuid_r (uid_t uid, struct passwd *result, char *buffer,
+		       size_t buflen, int *errnop)
+{
+  for (size_t idx = 0; idx < npwd_data; ++idx)
+    if (pwd_data[idx].pw_uid == uid)
+      {
+	char *cp = buffer;
+	int res = NSS_STATUS_SUCCESS;
+
+	result->pw_name = COPY_IF_ROOM (pwd_data[idx].pw_name);
+	result->pw_passwd = COPY_IF_ROOM (pwd_data[idx].pw_passwd);
+	result->pw_uid = pwd_data[idx].pw_uid;
+	result->pw_gid = pwd_data[idx].pw_gid;
+	result->pw_gecos = COPY_IF_ROOM (pwd_data[idx].pw_gecos);
+	result->pw_dir = COPY_IF_ROOM (pwd_data[idx].pw_dir);
+	result->pw_shell = COPY_IF_ROOM (pwd_data[idx].pw_shell);
+
+	if (result->pw_name == NULL || result->pw_passwd == NULL
+	    || result->pw_gecos == NULL || result->pw_dir == NULL
+	    || result->pw_shell == NULL)
+	  {
+	    *errnop = ERANGE;
+	    res = NSS_STATUS_TRYAGAIN;
+	  }
+
+	return res;
+      }
+
+  return NSS_STATUS_NOTFOUND;
+}
+
+
+enum nss_status
+_nss_test1_getpwnam_r (const char *name, struct passwd *result, char *buffer,
+		       size_t buflen, int *errnop)
+{
+  for (size_t idx = 0; idx < npwd_data; ++idx)
+    if (strcmp (pwd_data[idx].pw_name, name) == 0)
+      {
+	char *cp = buffer;
+	int res = NSS_STATUS_SUCCESS;
+
+	result->pw_name = COPY_IF_ROOM (pwd_data[idx].pw_name);
+	result->pw_passwd = COPY_IF_ROOM (pwd_data[idx].pw_passwd);
+	result->pw_uid = pwd_data[idx].pw_uid;
+	result->pw_gid = pwd_data[idx].pw_gid;
+	result->pw_gecos = COPY_IF_ROOM (pwd_data[idx].pw_gecos);
+	result->pw_dir = COPY_IF_ROOM (pwd_data[idx].pw_dir);
+	result->pw_shell = COPY_IF_ROOM (pwd_data[idx].pw_shell);
+
+	if (result->pw_name == NULL || result->pw_passwd == NULL
+	    || result->pw_gecos == NULL || result->pw_dir == NULL
+	    || result->pw_shell == NULL)
+	  {
+	    *errnop = ERANGE;
+	    res = NSS_STATUS_TRYAGAIN;
+	  }
+
+	return res;
+      }
+
+  return NSS_STATUS_NOTFOUND;
+}
diff --git a/REORG.TODO/nss/nsswitch.c b/REORG.TODO/nss/nsswitch.c
new file mode 100644
index 0000000000..8f31658523
--- /dev/null
+++ b/REORG.TODO/nss/nsswitch.c
@@ -0,0 +1,931 @@
+/* Copyright (C) 1996-2017 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, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <ctype.h>
+#include <dlfcn.h>
+#include <errno.h>
+#include <netdb.h>
+#include <libc-lock.h>
+#include <search.h>
+#include <stdio.h>
+#include <stdio_ext.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <aliases.h>
+#include <grp.h>
+#include <netinet/ether.h>
+#include <pwd.h>
+#include <shadow.h>
+
+#if !defined DO_STATIC_NSS || defined SHARED
+# include <gnu/lib-names.h>
+#endif
+
+#include "nsswitch.h"
+#include "../nscd/nscd_proto.h"
+#include <sysdep.h>
+
+/* Prototypes for the local functions.  */
+static name_database *nss_parse_file (const char *fname) internal_function;
+static name_database_entry *nss_getline (char *line) internal_function;
+static service_user *nss_parse_service_list (const char *line)
+     internal_function;
+#if !defined DO_STATIC_NSS || defined SHARED
+static service_library *nss_new_service (name_database *database,
+					 const char *name) internal_function;
+#endif
+
+
+/* Declare external database variables.  */
+#define DEFINE_DATABASE(name)						      \
+  extern service_user *__nss_##name##_database attribute_hidden;	      \
+  weak_extern (__nss_##name##_database)
+#include "databases.def"
+#undef DEFINE_DATABASE
+
+/* Structure to map database name to variable.  */
+static const struct
+{
+  const char name[10];
+  service_user **dbp;
+} databases[] =
+{
+#define DEFINE_DATABASE(name)						      \
+  { #name, &__nss_##name##_database },
+#include "databases.def"
+#undef DEFINE_DATABASE
+};
+#define ndatabases (sizeof (databases) / sizeof (databases[0]))
+
+/* Flags whether custom rules for database is set.  */
+bool __nss_database_custom[NSS_DBSIDX_max];
+
+
+__libc_lock_define_initialized (static, lock)
+
+#if !defined DO_STATIC_NSS || defined SHARED
+/* String with revision number of the shared object files.  */
+static const char *const __nss_shlib_revision = LIBNSS_FILES_SO + 15;
+#endif
+
+/* The root of the whole data base.  */
+static name_database *service_table;
+
+/* List of default service lists that were generated by glibc because
+   /etc/nsswitch.conf did not provide a value.
+   The list is only maintained so we can free such service lists in
+   __libc_freeres.  */
+static name_database_entry *defconfig_entries;
+
+
+#if defined USE_NSCD && (!defined DO_STATIC_NSS || defined SHARED)
+/* Nonzero if this is the nscd process.  */
+static bool is_nscd;
+/* The callback passed to the init functions when nscd is used.  */
+static void (*nscd_init_cb) (size_t, struct traced_file *);
+#endif
+
+
+/* -1 == database not found
+    0 == database entry pointer stored */
+int
+__nss_database_lookup (const char *database, const char *alternate_name,
+		       const char *defconfig, service_user **ni)
+{
+  /* Prevent multiple threads to change the service table.  */
+  __libc_lock_lock (lock);
+
+  /* Reconsider database variable in case some other thread called
+     `__nss_configure_lookup' while we waited for the lock.  */
+  if (*ni != NULL)
+    {
+      __libc_lock_unlock (lock);
+      return 0;
+    }
+
+  /* Are we initialized yet?  */
+  if (service_table == NULL)
+    /* Read config file.  */
+    service_table = nss_parse_file (_PATH_NSSWITCH_CONF);
+
+  /* Test whether configuration data is available.  */
+  if (service_table != NULL)
+    {
+      /* Return first `service_user' entry for DATABASE.  */
+      name_database_entry *entry;
+
+      /* XXX Could use some faster mechanism here.  But each database is
+	 only requested once and so this might not be critical.  */
+      for (entry = service_table->entry; entry != NULL; entry = entry->next)
+	if (strcmp (database, entry->name) == 0)
+	  *ni = entry->service;
+
+      if (*ni == NULL && alternate_name != NULL)
+	/* We haven't found an entry so far.  Try to find it with the
+	   alternative name.  */
+	for (entry = service_table->entry; entry != NULL; entry = entry->next)
+	  if (strcmp (alternate_name, entry->name) == 0)
+	    *ni = entry->service;
+    }
+
+  /* No configuration data is available, either because nsswitch.conf
+     doesn't exist or because it doesn't have a line for this database.
+
+     DEFCONFIG specifies the default service list for this database,
+     or null to use the most common default.  */
+  if (*ni == NULL)
+    {
+      *ni = nss_parse_service_list (defconfig
+				    ?: "nis [NOTFOUND=return] files");
+      if (*ni != NULL)
+	{
+	  /* Record the memory we've just allocated in defconfig_entries list,
+	     so we can free it later.  */
+	  name_database_entry *entry;
+
+	  /* Allocate ENTRY plus size of name (1 here).  */
+	  entry = (name_database_entry *) malloc (sizeof (*entry) + 1);
+
+	  if (entry != NULL)
+	    {
+	      entry->next = defconfig_entries;
+	      entry->service = *ni;
+	      entry->name[0] = '\0';
+	      defconfig_entries = entry;
+	    }
+	}
+    }
+
+  __libc_lock_unlock (lock);
+
+  return *ni != NULL ? 0 : -1;
+}
+libc_hidden_def (__nss_database_lookup)
+
+
+/* -1 == not found
+    0 == function found
+    1 == finished */
+int
+__nss_lookup (service_user **ni, const char *fct_name, const char *fct2_name,
+	      void **fctp)
+{
+  *fctp = __nss_lookup_function (*ni, fct_name);
+  if (*fctp == NULL && fct2_name != NULL)
+    *fctp = __nss_lookup_function (*ni, fct2_name);
+
+  while (*fctp == NULL
+	 && nss_next_action (*ni, NSS_STATUS_UNAVAIL) == NSS_ACTION_CONTINUE
+	 && (*ni)->next != NULL)
+    {
+      *ni = (*ni)->next;
+
+      *fctp = __nss_lookup_function (*ni, fct_name);
+      if (*fctp == NULL && fct2_name != NULL)
+	*fctp = __nss_lookup_function (*ni, fct2_name);
+    }
+
+  return *fctp != NULL ? 0 : (*ni)->next == NULL ? 1 : -1;
+}
+libc_hidden_def (__nss_lookup)
+
+
+/* -1 == not found
+    0 == adjusted for next function
+    1 == finished */
+int
+__nss_next2 (service_user **ni, const char *fct_name, const char *fct2_name,
+	     void **fctp, int status, int all_values)
+{
+  if (all_values)
+    {
+      if (nss_next_action (*ni, NSS_STATUS_TRYAGAIN) == NSS_ACTION_RETURN
+	  && nss_next_action (*ni, NSS_STATUS_UNAVAIL) == NSS_ACTION_RETURN
+	  && nss_next_action (*ni, NSS_STATUS_NOTFOUND) == NSS_ACTION_RETURN
+	  && nss_next_action (*ni, NSS_STATUS_SUCCESS) == NSS_ACTION_RETURN)
+	return 1;
+    }
+  else
+    {
+      /* This is really only for debugging.  */
+      if (__builtin_expect (NSS_STATUS_TRYAGAIN > status
+			    || status > NSS_STATUS_RETURN, 0))
+	 __libc_fatal ("illegal status in __nss_next");
+
+       if (nss_next_action (*ni, status) == NSS_ACTION_RETURN)
+	 return 1;
+    }
+
+  if ((*ni)->next == NULL)
+    return -1;
+
+  do
+    {
+      *ni = (*ni)->next;
+
+      *fctp = __nss_lookup_function (*ni, fct_name);
+      if (*fctp == NULL && fct2_name != NULL)
+	*fctp = __nss_lookup_function (*ni, fct2_name);
+    }
+  while (*fctp == NULL
+	 && nss_next_action (*ni, NSS_STATUS_UNAVAIL) == NSS_ACTION_CONTINUE
+	 && (*ni)->next != NULL);
+
+  return *fctp != NULL ? 0 : -1;
+}
+libc_hidden_def (__nss_next2)
+
+
+int
+attribute_compat_text_section
+__nss_next (service_user **ni, const char *fct_name, void **fctp, int status,
+	    int all_values)
+{
+  return __nss_next2 (ni, fct_name, NULL, fctp, status, all_values);
+}
+
+
+int
+__nss_configure_lookup (const char *dbname, const char *service_line)
+{
+  service_user *new_db;
+  size_t cnt;
+
+  for (cnt = 0; cnt < ndatabases; ++cnt)
+    {
+      int cmp = strcmp (dbname, databases[cnt].name);
+      if (cmp == 0)
+	break;
+      if (cmp < 0)
+	{
+	  __set_errno (EINVAL);
+	  return -1;
+	}
+    }
+
+  if (cnt == ndatabases)
+    {
+      __set_errno (EINVAL);
+      return -1;
+    }
+
+  /* Test whether it is really used.  */
+  if (databases[cnt].dbp == NULL)
+    /* Nothing to do, but we could do.  */
+    return 0;
+
+  /* Try to generate new data.  */
+  new_db = nss_parse_service_list (service_line);
+  if (new_db == NULL)
+    {
+      /* Illegal service specification.  */
+      __set_errno (EINVAL);
+      return -1;
+    }
+
+  /* Prevent multiple threads to change the service table.  */
+  __libc_lock_lock (lock);
+
+  /* Install new rules.  */
+  *databases[cnt].dbp = new_db;
+  __nss_database_custom[cnt] = true;
+
+  __libc_lock_unlock (lock);
+
+  return 0;
+}
+
+
+/* Comparison function for searching NI->known tree.  */
+static int
+known_compare (const void *p1, const void *p2)
+{
+  return p1 == p2 ? 0 : strcmp (*(const char *const *) p1,
+				*(const char *const *) p2);
+}
+
+
+#if !defined DO_STATIC_NSS || defined SHARED
+/* Load library.  */
+static int
+nss_load_library (service_user *ni)
+{
+  if (ni->library == NULL)
+    {
+      /* This service has not yet been used.  Fetch the service
+	 library for it, creating a new one if need be.  If there
+	 is no service table from the file, this static variable
+	 holds the head of the service_library list made from the
+	 default configuration.  */
+      static name_database default_table;
+      ni->library = nss_new_service (service_table ?: &default_table,
+				     ni->name);
+      if (ni->library == NULL)
+	return -1;
+    }
+
+  if (ni->library->lib_handle == NULL)
+    {
+      /* Load the shared library.  */
+      size_t shlen = (7 + strlen (ni->name) + 3
+		      + strlen (__nss_shlib_revision) + 1);
+      int saved_errno = errno;
+      char shlib_name[shlen];
+
+      /* Construct shared object name.  */
+      __stpcpy (__stpcpy (__stpcpy (__stpcpy (shlib_name,
+					      "libnss_"),
+				    ni->name),
+			  ".so"),
+		__nss_shlib_revision);
+
+      ni->library->lib_handle = __libc_dlopen (shlib_name);
+      if (ni->library->lib_handle == NULL)
+	{
+	  /* Failed to load the library.  */
+	  ni->library->lib_handle = (void *) -1l;
+	  __set_errno (saved_errno);
+	}
+# ifdef USE_NSCD
+      else if (is_nscd)
+	{
+	  /* Call the init function when nscd is used.  */
+	  size_t initlen = (5 + strlen (ni->name)
+			    + strlen ("_init") + 1);
+	  char init_name[initlen];
+
+	  /* Construct the init function name.  */
+	  __stpcpy (__stpcpy (__stpcpy (init_name,
+					"_nss_"),
+			      ni->name),
+		    "_init");
+
+	  /* Find the optional init function.  */
+	  void (*ifct) (void (*) (size_t, struct traced_file *))
+	    = __libc_dlsym (ni->library->lib_handle, init_name);
+	  if (ifct != NULL)
+	    {
+	      void (*cb) (size_t, struct traced_file *) = nscd_init_cb;
+#  ifdef PTR_DEMANGLE
+	      PTR_DEMANGLE (cb);
+#  endif
+	      ifct (cb);
+	    }
+	}
+# endif
+    }
+
+  return 0;
+}
+#endif
+
+
+void *
+__nss_lookup_function (service_user *ni, const char *fct_name)
+{
+  void **found, *result;
+
+  /* We now modify global data.  Protect it.  */
+  __libc_lock_lock (lock);
+
+  /* Search the tree of functions previously requested.  Data in the
+     tree are `known_function' structures, whose first member is a
+     `const char *', the lookup key.  The search returns a pointer to
+     the tree node structure; the first member of the is a pointer to
+     our structure (i.e. what will be a `known_function'); since the
+     first member of that is the lookup key string, &FCT_NAME is close
+     enough to a pointer to our structure to use as a lookup key that
+     will be passed to `known_compare' (above).  */
+
+  found = __tsearch (&fct_name, &ni->known, &known_compare);
+  if (found == NULL)
+    /* This means out-of-memory.  */
+    result = NULL;
+  else if (*found != &fct_name)
+    {
+      /* The search found an existing structure in the tree.  */
+      result = ((known_function *) *found)->fct_ptr;
+#ifdef PTR_DEMANGLE
+      PTR_DEMANGLE (result);
+#endif
+    }
+  else
+    {
+      /* This name was not known before.  Now we have a node in the tree
+	 (in the proper sorted position for FCT_NAME) that points to
+	 &FCT_NAME instead of any real `known_function' structure.
+	 Allocate a new structure and fill it in.  */
+
+      known_function *known = malloc (sizeof *known);
+      if (! known)
+	{
+#if !defined DO_STATIC_NSS || defined SHARED
+	remove_from_tree:
+#endif
+	  /* Oops.  We can't instantiate this node properly.
+	     Remove it from the tree.  */
+	  __tdelete (&fct_name, &ni->known, &known_compare);
+	  free (known);
+	  result = NULL;
+	}
+      else
+	{
+	  /* Point the tree node at this new structure.  */
+	  *found = known;
+	  known->fct_name = fct_name;
+
+#if !defined DO_STATIC_NSS || defined SHARED
+	  /* Load the appropriate library.  */
+	  if (nss_load_library (ni) != 0)
+	    /* This only happens when out of memory.  */
+	    goto remove_from_tree;
+
+	  if (ni->library->lib_handle == (void *) -1l)
+	    /* Library not found => function not found.  */
+	    result = NULL;
+	  else
+	    {
+	      /* Get the desired function.  */
+	      size_t namlen = (5 + strlen (ni->name) + 1
+			       + strlen (fct_name) + 1);
+	      char name[namlen];
+
+	      /* Construct the function name.  */
+	      __stpcpy (__stpcpy (__stpcpy (__stpcpy (name, "_nss_"),
+					    ni->name),
+				  "_"),
+			fct_name);
+
+	      /* Look up the symbol.  */
+	      result = __libc_dlsym (ni->library->lib_handle, name);
+	    }
+#else
+	  /* We can't get function address dynamically in static linking. */
+	  {
+# define DEFINE_ENT(h,nm)						      \
+	    { #h"_get"#nm"ent_r", _nss_##h##_get##nm##ent_r },		      \
+	    { #h"_end"#nm"ent", _nss_##h##_end##nm##ent },		      \
+	    { #h"_set"#nm"ent", _nss_##h##_set##nm##ent },
+# define DEFINE_GET(h,nm)						      \
+	    { #h"_get"#nm"_r", _nss_##h##_get##nm##_r },
+# define DEFINE_GETBY(h,nm,ky)						      \
+	    { #h"_get"#nm"by"#ky"_r", _nss_##h##_get##nm##by##ky##_r },
+	    static struct fct_tbl { const char *fname; void *fp; } *tp, tbl[] =
+	      {
+# include "function.def"
+		{ NULL, NULL }
+	      };
+	    size_t namlen = (5 + strlen (ni->name) + 1
+			     + strlen (fct_name) + 1);
+	    char name[namlen];
+
+	    /* Construct the function name.  */
+	    __stpcpy (__stpcpy (__stpcpy (name, ni->name),
+				"_"),
+		      fct_name);
+
+	    result = NULL;
+	    for (tp = &tbl[0]; tp->fname; tp++)
+	      if (strcmp (tp->fname, name) == 0)
+		{
+		  result = tp->fp;
+		  break;
+		}
+	  }
+#endif
+
+	  /* Remember function pointer for later calls.  Even if null, we
+	     record it so a second try needn't search the library again.  */
+	  known->fct_ptr = result;
+#ifdef PTR_MANGLE
+	  PTR_MANGLE (known->fct_ptr);
+#endif
+	}
+    }
+
+  /* Remove the lock.  */
+  __libc_lock_unlock (lock);
+
+  return result;
+}
+libc_hidden_def (__nss_lookup_function)
+
+
+static name_database *
+internal_function
+nss_parse_file (const char *fname)
+{
+  FILE *fp;
+  name_database *result;
+  name_database_entry *last;
+  char *line;
+  size_t len;
+
+  /* Open the configuration file.  */
+  fp = fopen (fname, "rce");
+  if (fp == NULL)
+    return NULL;
+
+  /* No threads use this stream.  */
+  __fsetlocking (fp, FSETLOCKING_BYCALLER);
+
+  result = (name_database *) malloc (sizeof (name_database));
+  if (result == NULL)
+    {
+      fclose (fp);
+      return NULL;
+    }
+
+  result->entry = NULL;
+  result->library = NULL;
+  last = NULL;
+  line = NULL;
+  len = 0;
+  do
+    {
+      name_database_entry *this;
+      ssize_t n;
+
+      n = __getline (&line, &len, fp);
+      if (n < 0)
+	break;
+      if (line[n - 1] == '\n')
+	line[n - 1] = '\0';
+
+      /* Because the file format does not know any form of quoting we
+	 can search forward for the next '#' character and if found
+	 make it terminating the line.  */
+      *__strchrnul (line, '#') = '\0';
+
+      /* If the line is blank it is ignored.  */
+      if (line[0] == '\0')
+	continue;
+
+      /* Each line completely specifies the actions for a database.  */
+      this = nss_getline (line);
+      if (this != NULL)
+	{
+	  if (last != NULL)
+	    last->next = this;
+	  else
+	    result->entry = this;
+
+	  last = this;
+	}
+    }
+  while (!feof_unlocked (fp));
+
+  /* Free the buffer.  */
+  free (line);
+  /* Close configuration file.  */
+  fclose (fp);
+
+  return result;
+}
+
+
+/* Read the source names:
+	`( <source> ( "[" "!"? (<status> "=" <action> )+ "]" )? )*'
+   */
+static service_user *
+internal_function
+nss_parse_service_list (const char *line)
+{
+  service_user *result = NULL, **nextp = &result;
+
+  while (1)
+    {
+      service_user *new_service;
+      const char *name;
+
+      while (isspace (line[0]))
+	++line;
+      if (line[0] == '\0')
+	/* No source specified.  */
+	return result;
+
+      /* Read <source> identifier.  */
+      name = line;
+      while (line[0] != '\0' && !isspace (line[0]) && line[0] != '[')
+	++line;
+      if (name == line)
+	return result;
+
+
+      new_service = (service_user *) malloc (sizeof (service_user)
+					     + (line - name + 1));
+      if (new_service == NULL)
+	return result;
+
+      *((char *) __mempcpy (new_service->name, name, line - name)) = '\0';
+
+      /* Set default actions.  */
+      new_service->actions[2 + NSS_STATUS_TRYAGAIN] = NSS_ACTION_CONTINUE;
+      new_service->actions[2 + NSS_STATUS_UNAVAIL] = NSS_ACTION_CONTINUE;
+      new_service->actions[2 + NSS_STATUS_NOTFOUND] = NSS_ACTION_CONTINUE;
+      new_service->actions[2 + NSS_STATUS_SUCCESS] = NSS_ACTION_RETURN;
+      new_service->actions[2 + NSS_STATUS_RETURN] = NSS_ACTION_RETURN;
+      new_service->library = NULL;
+      new_service->known = NULL;
+      new_service->next = NULL;
+
+      while (isspace (line[0]))
+	++line;
+
+      if (line[0] == '[')
+	{
+	  /* Read criterions.  */
+	  do
+	    ++line;
+	  while (line[0] != '\0' && isspace (line[0]));
+
+	  do
+	    {
+	      int not;
+	      enum nss_status status;
+	      lookup_actions action;
+
+	      /* Grok ! before name to mean all statii but that one.  */
+	      not = line[0] == '!';
+	      if (not)
+		++line;
+
+	      /* Read status name.  */
+	      name = line;
+	      while (line[0] != '\0' && !isspace (line[0]) && line[0] != '='
+		     && line[0] != ']')
+		++line;
+
+	      /* Compare with known statii.  */
+	      if (line - name == 7)
+		{
+		  if (__strncasecmp (name, "SUCCESS", 7) == 0)
+		    status = NSS_STATUS_SUCCESS;
+		  else if (__strncasecmp (name, "UNAVAIL", 7) == 0)
+		    status = NSS_STATUS_UNAVAIL;
+		  else
+		    goto finish;
+		}
+	      else if (line - name == 8)
+		{
+		  if (__strncasecmp (name, "NOTFOUND", 8) == 0)
+		    status = NSS_STATUS_NOTFOUND;
+		  else if (__strncasecmp (name, "TRYAGAIN", 8) == 0)
+		    status = NSS_STATUS_TRYAGAIN;
+		  else
+		    goto finish;
+		}
+	      else
+		goto finish;
+
+	      while (isspace (line[0]))
+		++line;
+	      if (line[0] != '=')
+		goto finish;
+	      do
+		++line;
+	      while (isspace (line[0]));
+
+	      name = line;
+	      while (line[0] != '\0' && !isspace (line[0]) && line[0] != '='
+		     && line[0] != ']')
+		++line;
+
+	      if (line - name == 6 && __strncasecmp (name, "RETURN", 6) == 0)
+		action = NSS_ACTION_RETURN;
+	      else if (line - name == 8
+		       && __strncasecmp (name, "CONTINUE", 8) == 0)
+		action = NSS_ACTION_CONTINUE;
+	      else if (line - name == 5
+		       && __strncasecmp (name, "MERGE", 5) == 0)
+		action = NSS_ACTION_MERGE;
+	      else
+		goto finish;
+
+	      if (not)
+		{
+		  /* Save the current action setting for this status,
+		     set them all to the given action, and reset this one.  */
+		  const lookup_actions save = new_service->actions[2 + status];
+		  new_service->actions[2 + NSS_STATUS_TRYAGAIN] = action;
+		  new_service->actions[2 + NSS_STATUS_UNAVAIL] = action;
+		  new_service->actions[2 + NSS_STATUS_NOTFOUND] = action;
+		  new_service->actions[2 + NSS_STATUS_SUCCESS] = action;
+		  new_service->actions[2 + status] = save;
+		}
+	      else
+		new_service->actions[2 + status] = action;
+
+	      /* Skip white spaces.  */
+	      while (isspace (line[0]))
+		++line;
+	    }
+	  while (line[0] != ']');
+
+	  /* Skip the ']'.  */
+	  ++line;
+	}
+
+      *nextp = new_service;
+      nextp = &new_service->next;
+      continue;
+
+    finish:
+      free (new_service);
+      return result;
+    }
+}
+
+static name_database_entry *
+internal_function
+nss_getline (char *line)
+{
+  const char *name;
+  name_database_entry *result;
+  size_t len;
+
+  /* Ignore leading white spaces.  ATTENTION: this is different from
+     what is implemented in Solaris.  The Solaris man page says a line
+     beginning with a white space character is ignored.  We regard
+     this as just another misfeature in Solaris.  */
+  while (isspace (line[0]))
+    ++line;
+
+  /* Recognize `<database> ":"'.  */
+  name = line;
+  while (line[0] != '\0' && !isspace (line[0]) && line[0] != ':')
+    ++line;
+  if (line[0] == '\0' || name == line)
+    /* Syntax error.  */
+    return NULL;
+  *line++ = '\0';
+
+  len = strlen (name) + 1;
+
+  result = (name_database_entry *) malloc (sizeof (name_database_entry) + len);
+  if (result == NULL)
+    return NULL;
+
+  /* Save the database name.  */
+  memcpy (result->name, name, len);
+
+  /* Parse the list of services.  */
+  result->service = nss_parse_service_list (line);
+
+  result->next = NULL;
+  return result;
+}
+
+
+#if !defined DO_STATIC_NSS || defined SHARED
+static service_library *
+internal_function
+nss_new_service (name_database *database, const char *name)
+{
+  service_library **currentp = &database->library;
+
+  while (*currentp != NULL)
+    {
+      if (strcmp ((*currentp)->name, name) == 0)
+	return *currentp;
+      currentp = &(*currentp)->next;
+    }
+
+  /* We have to add the new service.  */
+  *currentp = (service_library *) malloc (sizeof (service_library));
+  if (*currentp == NULL)
+    return NULL;
+
+  (*currentp)->name = name;
+  (*currentp)->lib_handle = NULL;
+  (*currentp)->next = NULL;
+
+  return *currentp;
+}
+#endif
+
+
+#if defined SHARED && defined USE_NSCD
+/* Load all libraries for the service.  */
+static void
+nss_load_all_libraries (const char *service, const char *def)
+{
+  service_user *ni = NULL;
+
+  if (__nss_database_lookup (service, NULL, def, &ni) == 0)
+    while (ni != NULL)
+      {
+	nss_load_library (ni);
+	ni = ni->next;
+      }
+}
+
+
+/* Called by nscd and nscd alone.  */
+void
+__nss_disable_nscd (void (*cb) (size_t, struct traced_file *))
+{
+# ifdef PTR_MANGLE
+  PTR_MANGLE (cb);
+# endif
+  nscd_init_cb = cb;
+  is_nscd = true;
+
+  /* Find all the relevant modules so that the init functions are called.  */
+  nss_load_all_libraries ("passwd", "compat [NOTFOUND=return] files");
+  nss_load_all_libraries ("group", "compat [NOTFOUND=return] files");
+  nss_load_all_libraries ("hosts", "dns [!UNAVAIL=return] files");
+  nss_load_all_libraries ("services", NULL);
+
+  /* Disable all uses of NSCD.  */
+  __nss_not_use_nscd_passwd = -1;
+  __nss_not_use_nscd_group = -1;
+  __nss_not_use_nscd_hosts = -1;
+  __nss_not_use_nscd_services = -1;
+  __nss_not_use_nscd_netgroup = -1;
+}
+#endif
+
+static void
+free_database_entries (name_database_entry *entry)
+{
+  while (entry != NULL)
+    {
+      name_database_entry *olde = entry;
+      service_user *service = entry->service;
+
+      while (service != NULL)
+	{
+	  service_user *olds = service;
+
+	  if (service->known != NULL)
+	    __tdestroy (service->known, free);
+
+	  service = service->next;
+	  free (olds);
+	}
+
+      entry = entry->next;
+      free (olde);
+    }
+}
+
+/* Free all resources if necessary.  */
+libc_freeres_fn (free_defconfig)
+{
+  name_database_entry *entry = defconfig_entries;
+
+  if (entry == NULL)
+    /* defconfig was not used.  */
+    return;
+
+  /* Don't disturb ongoing other threads (if there are any).  */
+  defconfig_entries = NULL;
+
+  free_database_entries (entry);
+}
+
+libc_freeres_fn (free_mem)
+{
+  name_database *top = service_table;
+  service_library *library;
+
+  if (top == NULL)
+    /* Maybe we have not read the nsswitch.conf file.  */
+    return;
+
+  /* Don't disturb ongoing other threads (if there are any).  */
+  service_table = NULL;
+
+  free_database_entries (top->entry);
+
+  library = top->library;
+  while (library != NULL)
+    {
+      service_library *oldl = library;
+
+      if (library->lib_handle && library->lib_handle != (void *) -1l)
+	__libc_dlclose (library->lib_handle);
+
+      library = library->next;
+      free (oldl);
+    }
+
+  free (top);
+}
diff --git a/REORG.TODO/nss/nsswitch.conf b/REORG.TODO/nss/nsswitch.conf
new file mode 100644
index 0000000000..39ca88bf51
--- /dev/null
+++ b/REORG.TODO/nss/nsswitch.conf
@@ -0,0 +1,20 @@
+# /etc/nsswitch.conf
+#
+# Example configuration of GNU Name Service Switch functionality.
+#
+
+passwd:		db files
+group:		db files
+initgroups:	db [SUCCESS=continue] files
+shadow:		db files
+gshadow:	files
+
+hosts:		files dns
+networks:	files dns
+
+protocols:	db files
+services:	db files
+ethers:		db files
+rpc:		db files
+
+netgroup:	db files
diff --git a/REORG.TODO/nss/nsswitch.h b/REORG.TODO/nss/nsswitch.h
new file mode 100644
index 0000000000..f3e756b684
--- /dev/null
+++ b/REORG.TODO/nss/nsswitch.h
@@ -0,0 +1,213 @@
+/* Copyright (C) 1996-2017 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, see
+   <http://www.gnu.org/licenses/>.  */
+
+#ifndef _NSSWITCH_H
+#define _NSSWITCH_H	1
+
+/* This is an *internal* header.  */
+
+#include <arpa/nameser.h>
+#include <netinet/in.h>
+#include <nss.h>
+#include <resolv.h>
+#include <search.h>
+#include <dlfcn.h>
+#include <stdbool.h>
+
+/* Actions performed after lookup finished.  */
+typedef enum
+{
+  NSS_ACTION_CONTINUE,
+  NSS_ACTION_RETURN,
+  NSS_ACTION_MERGE
+} lookup_actions;
+
+
+typedef struct service_library
+{
+  /* Name of service (`files', `dns', `nis', ...).  */
+  const char *name;
+  /* Pointer to the loaded shared library.  */
+  void *lib_handle;
+  /* And the link to the next entry.  */
+  struct service_library *next;
+} service_library;
+
+
+/* For mapping a function name to a function pointer.  It is known in
+   nsswitch.c:nss_lookup_function that a string pointer for the lookup key
+   is the first member.  */
+typedef struct
+{
+  const char *fct_name;
+  void *fct_ptr;
+} known_function;
+
+
+typedef struct service_user
+{
+  /* And the link to the next entry.  */
+  struct service_user *next;
+  /* Action according to result.  */
+  lookup_actions actions[5];
+  /* Link to the underlying library object.  */
+  service_library *library;
+  /* Collection of known functions.  */
+  void *known;
+  /* Name of the service (`files', `dns', `nis', ...).  */
+  char name[0];
+} service_user;
+
+/* To access the action based on the status value use this macro.  */
+#define nss_next_action(ni, status) ((ni)->actions[2 + status])
+
+
+typedef struct name_database_entry
+{
+  /* And the link to the next entry.  */
+  struct name_database_entry *next;
+  /* List of service to be used.  */
+  service_user *service;
+  /* Name of the database.  */
+  char name[0];
+} name_database_entry;
+
+
+typedef struct name_database
+{
+  /* List of all known databases.  */
+  name_database_entry *entry;
+  /* List of libraries with service implementation.  */
+  service_library *library;
+} name_database;
+
+
+/* Indices into DATABASES in nsswitch.c and __NSS_DATABASE_CUSTOM.  */
+enum
+  {
+#define DEFINE_DATABASE(arg) NSS_DBSIDX_##arg,
+#include "databases.def"
+#undef DEFINE_DATABASE
+    NSS_DBSIDX_max
+  };
+
+/* Flags whether custom rules for database is set.  */
+extern bool __nss_database_custom[NSS_DBSIDX_max];
+
+/* Warning for NSS functions, which don't require dlopen if glibc
+   was built with --enable-static-nss.  */
+#ifdef DO_STATIC_NSS
+# define nss_interface_function(name)
+#else
+# define nss_interface_function(name) static_link_warning (name)
+#endif
+
+
+/* Interface functions for NSS.  */
+
+/* Get the data structure representing the specified database.
+   If there is no configuration for this database in the file,
+   parse a service list from DEFCONFIG and use that.  More
+   than one function can use the database.  */
+extern int __nss_database_lookup (const char *database,
+				  const char *alternative_name,
+				  const char *defconfig, service_user **ni);
+libc_hidden_proto (__nss_database_lookup)
+
+/* Put first function with name FCT_NAME for SERVICE in FCTP.  The
+   position is remembered in NI.  The function returns a value < 0 if
+   an error occurred or no such function exists.  */
+extern int __nss_lookup (service_user **ni, const char *fct_name,
+			 const char *fct2_name, void **fctp);
+libc_hidden_proto (__nss_lookup)
+
+/* Determine the next step in the lookup process according to the
+   result STATUS of the call to the last function returned by
+   `__nss_lookup' or `__nss_next'.  NI specifies the last function
+   examined.  The function return a value > 0 if the process should
+   stop with the last result of the last function call to be the
+   result of the entire lookup.  The returned value is 0 if there is
+   another function to use and < 0 if an error occurred.
+
+   If ALL_VALUES is nonzero, the return value will not be > 0 as long as
+   there is a possibility the lookup process can ever use following
+   services.  In other words, only if all four lookup results have
+   the action RETURN associated the lookup process stops before the
+   natural end.  */
+extern int __nss_next2 (service_user **ni, const char *fct_name,
+			const char *fct2_name, void **fctp, int status,
+			int all_values) attribute_hidden;
+libc_hidden_proto (__nss_next2)
+extern int __nss_next (service_user **ni, const char *fct_name, void **fctp,
+		       int status, int all_values);
+
+/* Search for the service described in NI for a function named FCT_NAME
+   and return a pointer to this function if successful.  */
+extern void *__nss_lookup_function (service_user *ni, const char *fct_name);
+libc_hidden_proto (__nss_lookup_function)
+
+
+/* Called by NSCD to disable recursive calls and enable special handling
+   when used in nscd.  */
+struct traced_file;
+extern void __nss_disable_nscd (void (*) (size_t, struct traced_file *));
+
+
+typedef int (*db_lookup_function) (service_user **, const char *, const char *,
+				   void **)
+     internal_function;
+typedef enum nss_status (*setent_function) (int);
+typedef enum nss_status (*endent_function) (void);
+typedef enum nss_status (*getent_function) (void *, char *, size_t,
+					    int *, int *);
+typedef int (*getent_r_function) (void *, char *, size_t,
+				  void **result, int *);
+
+extern void __nss_setent (const char *func_name,
+			  db_lookup_function lookup_fct,
+			  service_user **nip, service_user **startp,
+			  service_user **last_nip, int stayon,
+			  int *stayon_tmp, int res);
+extern void __nss_endent (const char *func_name,
+			  db_lookup_function lookup_fct,
+			  service_user **nip, service_user **startp,
+			  service_user **last_nip, int res);
+extern int __nss_getent_r (const char *getent_func_name,
+			   const char *setent_func_name,
+			   db_lookup_function lookup_fct,
+			   service_user **nip, service_user **startp,
+			   service_user **last_nip, int *stayon_tmp,
+			   int res,
+			   void *resbuf, char *buffer, size_t buflen,
+			   void **result, int *h_errnop);
+extern void *__nss_getent (getent_r_function func,
+			   void **resbuf, char **buffer, size_t buflen,
+			   size_t *buffer_size, int *h_errnop);
+struct hostent;
+extern int __nss_hostname_digits_dots (const char *name,
+				       struct hostent *resbuf, char **buffer,
+				       size_t *buffer_size, size_t buflen,
+				       struct hostent **result,
+				       enum nss_status *status, int af,
+				       int *h_errnop);
+libc_hidden_proto (__nss_hostname_digits_dots)
+
+/* Maximum number of aliases we allow.  */
+#define MAX_NR_ALIASES  48
+#define MAX_NR_ADDRS    48
+
+#endif	/* nsswitch.h */
diff --git a/REORG.TODO/nss/proto-lookup.c b/REORG.TODO/nss/proto-lookup.c
new file mode 100644
index 0000000000..bfad4202aa
--- /dev/null
+++ b/REORG.TODO/nss/proto-lookup.c
@@ -0,0 +1,21 @@
+/* Copyright (C) 1996-2017 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, see
+   <http://www.gnu.org/licenses/>.  */
+
+#define DATABASE_NAME protocols
+
+#include "XXX-lookup.c"
diff --git a/REORG.TODO/nss/pwd-lookup.c b/REORG.TODO/nss/pwd-lookup.c
new file mode 100644
index 0000000000..00040d4e30
--- /dev/null
+++ b/REORG.TODO/nss/pwd-lookup.c
@@ -0,0 +1,22 @@
+/* Copyright (C) 1996-2017 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, see
+   <http://www.gnu.org/licenses/>.  */
+
+#define DATABASE_NAME passwd
+#define DEFAULT_CONFIG "compat [NOTFOUND=return] files"
+
+#include "XXX-lookup.c"
diff --git a/REORG.TODO/nss/rewrite_field.c b/REORG.TODO/nss/rewrite_field.c
new file mode 100644
index 0000000000..c0ae3d23f2
--- /dev/null
+++ b/REORG.TODO/nss/rewrite_field.c
@@ -0,0 +1,52 @@
+/* Copyright (C) 2015-2017 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, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <nss.h>
+#include <string.h>
+
+/* Rewrite VALUE to a valid field value in the NSS database.  Invalid
+   characters are replaced with a single space character ' '.  If
+   VALUE is NULL, the empty string is returned.  *TO_BE_FREED is
+   overwritten with a pointer the caller has to free if the function
+   returns successfully.  On failure, return NULL.  */
+const char *
+internal_function
+__nss_rewrite_field (const char *value, char **to_be_freed)
+{
+  *to_be_freed = NULL;
+  if (value == NULL)
+    return "";
+
+  /* Search for non-allowed characters.  */
+  const char *p = strpbrk (value, __nss_invalid_field_characters);
+  if (p == NULL)
+    return value;
+  *to_be_freed = __strdup (value);
+  if (*to_be_freed == NULL)
+    return NULL;
+
+  /* Switch pointer to freshly-allocated buffer.  */
+  char *bad = *to_be_freed + (p - value);
+  do
+    {
+      *bad = ' ';
+      bad = strpbrk (bad + 1, __nss_invalid_field_characters);
+    }
+  while (bad != NULL);
+
+  return *to_be_freed;
+}
diff --git a/REORG.TODO/nss/rpc-lookup.c b/REORG.TODO/nss/rpc-lookup.c
new file mode 100644
index 0000000000..ea34c24927
--- /dev/null
+++ b/REORG.TODO/nss/rpc-lookup.c
@@ -0,0 +1,21 @@
+/* Copyright (C) 1996-2017 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, see
+   <http://www.gnu.org/licenses/>.  */
+
+#define DATABASE_NAME rpc
+
+#include "XXX-lookup.c"
diff --git a/REORG.TODO/nss/service-lookup.c b/REORG.TODO/nss/service-lookup.c
new file mode 100644
index 0000000000..3f230d606a
--- /dev/null
+++ b/REORG.TODO/nss/service-lookup.c
@@ -0,0 +1,22 @@
+/* Copyright (C) 1996-2017 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, see
+   <http://www.gnu.org/licenses/>.  */
+
+#define DATABASE_NAME services
+#define NO_COMPAT
+
+#include "XXX-lookup.c"
diff --git a/REORG.TODO/nss/sgrp-lookup.c b/REORG.TODO/nss/sgrp-lookup.c
new file mode 100644
index 0000000000..87c1480690
--- /dev/null
+++ b/REORG.TODO/nss/sgrp-lookup.c
@@ -0,0 +1,23 @@
+/* Copyright (C) 2009-2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>, 2009.
+
+   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, see
+   <http://www.gnu.org/licenses/>.  */
+
+#define DATABASE_NAME gshadow
+#define ALTERNATE_NAME group
+#define DEFAULT_CONFIG "files"
+
+#include "XXX-lookup.c"
diff --git a/REORG.TODO/nss/spwd-lookup.c b/REORG.TODO/nss/spwd-lookup.c
new file mode 100644
index 0000000000..319a7bb062
--- /dev/null
+++ b/REORG.TODO/nss/spwd-lookup.c
@@ -0,0 +1,23 @@
+/* Copyright (C) 1996-2017 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, see
+   <http://www.gnu.org/licenses/>.  */
+
+#define DATABASE_NAME shadow
+#define ALTERNATE_NAME passwd
+#define DEFAULT_CONFIG "compat [NOTFOUND=return] files"
+
+#include "XXX-lookup.c"
diff --git a/REORG.TODO/nss/test-digits-dots.c b/REORG.TODO/nss/test-digits-dots.c
new file mode 100644
index 0000000000..2685161e65
--- /dev/null
+++ b/REORG.TODO/nss/test-digits-dots.c
@@ -0,0 +1,38 @@
+/* Copyright (C) 2013-2017 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, see
+   <http://www.gnu.org/licenses/>.  */
+
+/* Testcase for BZ #15014 */
+
+#include <stdlib.h>
+#include <netdb.h>
+#include <errno.h>
+
+static int
+do_test (void)
+{
+  char buf[32];
+  struct hostent *result = NULL;
+  struct hostent ret;
+  int h_err = 0;
+  int err;
+
+  err = gethostbyname_r ("1.2.3.4", &ret, buf, sizeof (buf), &result, &h_err);
+  return err == ERANGE && h_err == NETDB_INTERNAL ? EXIT_SUCCESS : EXIT_FAILURE;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/REORG.TODO/nss/test-netdb.c b/REORG.TODO/nss/test-netdb.c
new file mode 100644
index 0000000000..319541bc03
--- /dev/null
+++ b/REORG.TODO/nss/test-netdb.c
@@ -0,0 +1,340 @@
+/* Copyright (C) 1998-2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Andreas Jaeger <aj@suse.de>, 1998.
+
+   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, see
+   <http://www.gnu.org/licenses/>.  */
+
+/*
+  Testing of some network related lookup functions.
+  The system databases looked up are:
+  - /etc/services
+  - /etc/hosts
+  - /etc/networks
+  - /etc/protocols
+  The tests try to be fairly generic and simple so that they work on
+  every possible setup (and might therefore not detect some possible
+  errors).
+*/
+
+#include <netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <unistd.h>
+#include <errno.h>
+#include "nss.h"
+
+/*
+  The following define is necessary for glibc 2.0.6
+*/
+#ifndef INET6_ADDRSTRLEN
+# define INET6_ADDRSTRLEN 46
+#endif
+
+int error_count;
+
+static void
+output_servent (const char *call, struct servent *sptr)
+{
+  char **pptr;
+
+  if (sptr == NULL)
+    printf ("Call: %s returned NULL\n", call);
+  else
+    {
+      printf ("Call: %s, returned: s_name: %s, s_port: %d, s_proto: %s\n",
+	      call, sptr->s_name, ntohs(sptr->s_port), sptr->s_proto);
+      for (pptr = sptr->s_aliases; *pptr != NULL; pptr++)
+	printf ("  alias: %s\n", *pptr);
+    }
+}
+
+
+static void
+test_services (void)
+{
+  struct servent *sptr;
+
+  sptr = getservbyname ("domain", "tcp");
+  output_servent ("getservbyname (\"domain\", \"tcp\")", sptr);
+
+  sptr = getservbyname ("domain", "udp");
+  output_servent ("getservbyname (\"domain\", \"udp\")", sptr);
+
+  sptr = getservbyname ("domain", NULL);
+  output_servent ("getservbyname (\"domain\", NULL)", sptr);
+
+  sptr = getservbyname ("not-existant", NULL);
+  output_servent ("getservbyname (\"not-existant\", NULL)", sptr);
+
+  /* This shouldn't return anything.  */
+  sptr = getservbyname ("", "");
+  output_servent ("getservbyname (\"\", \"\")", sptr);
+
+  sptr = getservbyname ("", "tcp");
+  output_servent ("getservbyname (\"\", \"tcp\")", sptr);
+
+  sptr = getservbyport (htons(53), "tcp");
+  output_servent ("getservbyport (htons(53), \"tcp\")", sptr);
+
+  sptr = getservbyport (htons(53), NULL);
+  output_servent ("getservbyport (htons(53), NULL)", sptr);
+
+  sptr = getservbyport (htons(1), "udp"); /* shouldn't exist */
+  output_servent ("getservbyport (htons(1), \"udp\")", sptr);
+
+  setservent (0);
+  do
+    {
+      sptr = getservent ();
+      output_servent ("getservent ()", sptr);
+    }
+  while (sptr != NULL);
+  endservent ();
+}
+
+
+static void
+output_hostent (const char *call, struct hostent *hptr)
+{
+  char **pptr;
+  char buf[INET6_ADDRSTRLEN];
+
+  if (hptr == NULL)
+    printf ("Call: %s returned NULL\n", call);
+  else
+    {
+      printf ("Call: %s returned: name: %s, addr_type: %d\n",
+	      call, hptr->h_name, hptr->h_addrtype);
+      if (hptr->h_aliases)
+	for (pptr = hptr->h_aliases; *pptr != NULL; pptr++)
+	  printf ("  alias: %s\n", *pptr);
+
+      for (pptr = hptr->h_addr_list; *pptr != NULL; pptr++)
+	printf ("  ip: %s\n",
+		inet_ntop (hptr->h_addrtype, *pptr, buf, sizeof (buf)));
+    }
+}
+
+static void
+test_hosts (void)
+{
+  struct hostent *hptr1, *hptr2;
+  char *name = NULL;
+  size_t namelen = 0;
+  struct in_addr ip;
+
+  hptr1 = gethostbyname ("localhost");
+  hptr2 = gethostbyname ("LocalHost");
+  if (hptr1 != NULL || hptr2 != NULL)
+    {
+      if (hptr1 == NULL)
+	{
+	  printf ("localhost not found - but LocalHost found:-(\n");
+	  ++error_count;
+	}
+      else if (hptr2 == NULL)
+	{
+	  printf ("LocalHost not found - but localhost found:-(\n");
+	  ++error_count;
+	}
+      else if (strcmp (hptr1->h_name, hptr2->h_name) != 0)
+	{
+	  printf ("localhost and LocalHost have different canoncial name\n");
+	  printf ("gethostbyname (\"localhost\")->%s\n", hptr1->h_name);
+	  printf ("gethostbyname (\"LocalHost\")->%s\n", hptr2->h_name);
+	  ++error_count;
+	}
+      else
+	output_hostent ("gethostbyname(\"localhost\")", hptr1);
+    }
+
+  hptr1 = gethostbyname ("127.0.0.1");
+  output_hostent ("gethostbyname (\"127.0.0.1\")", hptr1);
+
+  hptr1 = gethostbyname ("10.1234");
+  output_hostent ("gethostbyname (\"10.1234\")", hptr1);
+
+  hptr1 = gethostbyname2 ("localhost", AF_INET);
+  output_hostent ("gethostbyname2 (\"localhost\", AF_INET)", hptr1);
+
+  while (gethostname (name, namelen) < 0 && errno == ENAMETOOLONG)
+    {
+      namelen += 2;		/* tiny increments to test a lot */
+      name = realloc (name, namelen);
+    }
+  if (gethostname (name, namelen) == 0)
+    {
+      printf ("Hostname: %s\n", name);
+      if (name != NULL)
+	{
+	  hptr1 = gethostbyname (name);
+	  output_hostent ("gethostbyname (gethostname(...))", hptr1);
+	}
+    }
+
+  ip.s_addr = htonl (INADDR_LOOPBACK);
+  hptr1 = gethostbyaddr ((char *) &ip, sizeof(ip), AF_INET);
+  if (hptr1 != NULL)
+    {
+      printf ("official name of 127.0.0.1: %s\n", hptr1->h_name);
+    }
+
+  sethostent (0);
+  do
+    {
+      hptr1 = gethostent ();
+      output_hostent ("gethostent ()", hptr1);
+    }
+  while (hptr1 != NULL);
+  endhostent ();
+
+}
+
+
+static void
+output_netent (const char *call, struct netent *nptr)
+{
+  char **pptr;
+
+  if (nptr == NULL)
+    printf ("Call: %s returned NULL\n", call);
+  else
+    {
+      struct in_addr ip;
+
+      ip.s_addr = htonl(nptr->n_net);
+      printf ("Call: %s, returned: n_name: %s, network_number: %s\n",
+	      call, nptr->n_name, inet_ntoa (ip));
+
+      for (pptr = nptr->n_aliases; *pptr != NULL; pptr++)
+	printf ("  alias: %s\n", *pptr);
+    }
+}
+
+static void
+test_network (void)
+{
+  struct netent *nptr;
+  u_int32_t ip;
+
+  /*
+     This test needs the following line in /etc/networks:
+     loopback        127.0.0.0
+  */
+  nptr = getnetbyname ("loopback");
+  output_netent ("getnetbyname (\"loopback\")",nptr);
+
+  nptr = getnetbyname ("LoopBACK");
+  output_netent ("getnetbyname (\"LoopBACK\")",nptr);
+
+  ip = inet_network ("127.0.0.0");
+  nptr = getnetbyaddr (ip, AF_INET);
+  output_netent ("getnetbyaddr (inet_network (\"127.0.0.0\"), AF_INET)",nptr);
+
+  setnetent (0);
+  do
+    {
+      nptr = getnetent ();
+      output_netent ("getnetent ()", nptr);
+    }
+  while (nptr != NULL);
+  endnetent ();
+}
+
+
+static void
+output_protoent (const char *call, struct protoent *prptr)
+{
+  char **pptr;
+
+  if (prptr == NULL)
+    printf ("Call: %s returned NULL\n", call);
+  else
+    {
+      printf ("Call: %s, returned: p_name: %s, p_proto: %d\n",
+	      call, prptr->p_name, prptr->p_proto);
+      for (pptr = prptr->p_aliases; *pptr != NULL; pptr++)
+	printf ("  alias: %s\n", *pptr);
+    }
+}
+
+
+static void
+test_protocols (void)
+{
+  struct protoent *prptr;
+
+  prptr = getprotobyname ("IP");
+  output_protoent ("getprotobyname (\"IP\")", prptr);
+
+  prptr = getprotobynumber (1);
+  output_protoent ("getprotobynumber (1)", prptr);
+
+  setprotoent (0);
+  do
+    {
+      prptr = getprotoent ();
+      output_protoent ("getprotoent ()", prptr);
+    }
+  while (prptr != NULL);
+  endprotoent ();
+}
+
+
+/* Override /etc/nsswitch.conf for this program.  This is mainly
+   useful for developers. */
+static void  __attribute__ ((unused))
+setdb (const char *dbname)
+{
+  if (strcmp ("db", dbname))
+      {
+	/*
+	  db is not implemented for hosts, networks
+	*/
+	__nss_configure_lookup ("hosts", dbname);
+	__nss_configure_lookup ("networks", dbname);
+      }
+  __nss_configure_lookup ("protocols", dbname);
+  __nss_configure_lookup ("services", dbname);
+}
+
+
+static int
+do_test (void)
+{
+  /*
+    setdb ("db");
+  */
+
+  test_hosts ();
+  test_network ();
+  test_protocols ();
+  test_services ();
+
+  if (error_count)
+    printf ("\n %d errors occurred!\n", error_count);
+  else
+    printf ("No visible errors occurred!\n");
+
+  return (error_count != 0);
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/REORG.TODO/nss/tst-cancel-getpwuid_r.c b/REORG.TODO/nss/tst-cancel-getpwuid_r.c
new file mode 100644
index 0000000000..53de82985c
--- /dev/null
+++ b/REORG.TODO/nss/tst-cancel-getpwuid_r.c
@@ -0,0 +1,182 @@
+/* Test cancellation of getpwuid_r.
+   Copyright (C) 2016-2017 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, see
+   <http://www.gnu.org/licenses/>.  */
+
+/* Test if cancellation of getpwuid_r incorrectly leaves internal
+   function state locked resulting in hang of subsequent calls to
+   getpwuid_r.  The main thread creates a second thread which will do
+   the calls to getpwuid_r.  A semaphore is used by the second thread to
+   signal to the main thread that it is as close as it can be to the
+   call site of getpwuid_r.  The goal of the semaphore is to avoid any
+   cancellable function calls between the sem_post and the call to
+   getpwuid_r.  The main thread then attempts to cancel the second
+   thread.  Without the fixes the cancellation happens at any number of
+   calls to cancellable functions in getpuid_r, but with the fix the
+   cancellation either does not happen or happens only at expected
+   points where the internal state is consistent.  We use an explicit
+   pthread_testcancel call to terminate the loop in a timely fashion
+   if the implementation does not have a cancellation point.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include <pwd.h>
+#include <nss.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <semaphore.h>
+#include <errno.h>
+#include <support/support.h>
+
+sem_t started;
+char *wbuf;
+long wbufsz;
+
+void
+worker_free (void *arg)
+{
+  free (arg);
+}
+
+static void *
+worker (void *arg)
+{
+  int ret;
+  unsigned int iter = 0;
+  struct passwd pwbuf, *pw;
+  uid_t uid;
+
+  uid = geteuid ();
+
+  /* Use a reasonable sized buffer.  Note that _SC_GETPW_R_SIZE_MAX is
+     just a hint and not any kind of maximum value.  */
+  wbufsz = sysconf (_SC_GETPW_R_SIZE_MAX);
+  if (wbufsz == -1)
+    wbufsz = 1024;
+  wbuf = xmalloc (wbufsz);
+
+  pthread_cleanup_push (worker_free, wbuf);
+  sem_post (&started);
+  while (1)
+    {
+      iter++;
+
+      ret = getpwuid_r (uid, &pwbuf, wbuf, wbufsz, &pw);
+
+      /* The call to getpwuid_r may not cancel so we need to test
+	 for cancellation after some number of iterations of the
+	 function.  Choose an arbitrary 100,000 iterations of running
+	 getpwuid_r in a tight cancellation loop before testing for
+	 cancellation.  */
+      if (iter > 100000)
+	pthread_testcancel ();
+
+      if (ret == ERANGE)
+	{
+	  /* Increase the buffer size.  */
+	  free (wbuf);
+	  wbufsz = wbufsz * 2;
+	  wbuf = xmalloc (wbufsz);
+	}
+
+    }
+  pthread_cleanup_pop (1);
+
+  return NULL;
+}
+
+static int
+do_test (void)
+{
+  int ret;
+  char *buf;
+  long bufsz;
+  void *retval;
+  struct passwd pwbuf, *pw;
+  pthread_t thread;
+
+  /* Configure the test to only use files. We control the files plugin
+     as part of glibc so we assert that it should be deferred
+     cancellation safe.  */
+  __nss_configure_lookup ("passwd", "files");
+
+  /* Use a reasonable sized buffer.  Note that  _SC_GETPW_R_SIZE_MAX is
+     just a hint and not any kind of maximum value.  */
+  bufsz = sysconf (_SC_GETPW_R_SIZE_MAX);
+  if (bufsz == -1)
+    bufsz = 1024;
+  buf = xmalloc (bufsz);
+
+  sem_init (&started, 0, 0);
+
+  pthread_create (&thread, NULL, worker, NULL);
+
+  do
+  {
+    ret = sem_wait (&started);
+    if (ret == -1 && errno != EINTR)
+      {
+        printf ("FAIL: Failed to wait for second thread to start.\n");
+	exit (EXIT_FAILURE);
+      }
+  }
+  while (ret != 0);
+
+  printf ("INFO: Cancelling thread\n");
+  if ((ret = pthread_cancel (thread)) != 0)
+    {
+      printf ("FAIL: Failed to cancel thread. Returned %d\n", ret);
+      exit (EXIT_FAILURE);
+    }
+
+  printf ("INFO: Joining...\n");
+  pthread_join (thread, &retval);
+  if (retval != PTHREAD_CANCELED)
+    {
+      printf ("FAIL: Thread was not cancelled.\n");
+      exit (EXIT_FAILURE);
+    }
+  printf ("INFO: Joined, trying getpwuid_r call\n");
+
+  /* Before the fix in 312be3f9f5eab1643d7dcc7728c76d413d4f2640 for this
+     issue the cancellation point could happen in any number of internal
+     calls, and therefore locks would be left held and the following
+     call to getpwuid_r would block and the test would time out.  */
+  do
+    {
+      ret = getpwuid_r (geteuid (), &pwbuf, buf, bufsz, &pw);
+      if (ret == ERANGE)
+	{
+	  /* Increase the buffer size.  */
+	  free (buf);
+	  bufsz = bufsz * 2;
+	  buf = xmalloc (bufsz);
+	}
+    }
+  while (ret == ERANGE);
+
+  free (buf);
+
+  /* Before the fix we would never get here.  */
+  printf ("PASS: Canceled getpwuid_r successfully"
+	  " and called it again without blocking.\n");
+
+  return 0;
+}
+
+#define TIMEOUT 900
+#include <support/test-driver.c>
diff --git a/REORG.TODO/nss/tst-field.c b/REORG.TODO/nss/tst-field.c
new file mode 100644
index 0000000000..d80be681c2
--- /dev/null
+++ b/REORG.TODO/nss/tst-field.c
@@ -0,0 +1,101 @@
+/* Test for invalid field handling in file-style NSS databases.  [BZ #18724]
+   Copyright (C) 2015-2017 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, see
+   <http://www.gnu.org/licenses/>.  */
+
+/* This test needs to be statically linked because it access hidden
+   functions.  */
+
+#include <nss.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+static bool errors;
+
+static void
+check (const char *what, bool expr)
+{
+  if (!expr)
+    {
+      printf ("FAIL: %s\n", what);
+      errors = true;
+    }
+}
+
+#define CHECK(expr) check (#expr, (expr))
+
+static void
+check_rewrite (const char *input, const char *expected)
+{
+  char *to_free;
+  const char *result = __nss_rewrite_field (input, &to_free);
+  CHECK (result != NULL);
+  if (result != NULL && strcmp (result, expected) != 0)
+    {
+      printf ("FAIL: rewrite \"%s\" -> \"%s\", expected \"%s\"\n",
+	      input, result, expected);
+      errors = true;
+    }
+  free (to_free);
+}
+
+static int
+do_test (void)
+{
+  CHECK (__nss_valid_field (NULL));
+  CHECK (__nss_valid_field (""));
+  CHECK (__nss_valid_field ("+"));
+  CHECK (__nss_valid_field ("-"));
+  CHECK (__nss_valid_field (" "));
+  CHECK (__nss_valid_field ("abcdef"));
+  CHECK (__nss_valid_field ("abc def"));
+  CHECK (__nss_valid_field ("abc\tdef"));
+  CHECK (!__nss_valid_field ("abcdef:"));
+  CHECK (!__nss_valid_field ("abcde:f"));
+  CHECK (!__nss_valid_field (":abcdef"));
+  CHECK (!__nss_valid_field ("abcdef\n"));
+  CHECK (!__nss_valid_field ("\nabcdef"));
+  CHECK (!__nss_valid_field (":"));
+  CHECK (!__nss_valid_field ("\n"));
+
+  CHECK (__nss_valid_list_field (NULL));
+  CHECK (__nss_valid_list_field ((char *[]) {(char *) "good", NULL}));
+  CHECK (!__nss_valid_list_field ((char *[]) {(char *) "g,ood", NULL}));
+  CHECK (!__nss_valid_list_field ((char *[]) {(char *) "g\nood", NULL}));
+  CHECK (!__nss_valid_list_field ((char *[]) {(char *) "g:ood", NULL}));
+
+  check_rewrite (NULL, "");
+  check_rewrite ("", "");
+  check_rewrite ("abc", "abc");
+  check_rewrite ("abc\n", "abc ");
+  check_rewrite ("abc:", "abc ");
+  check_rewrite ("\nabc", " abc");
+  check_rewrite (":abc", " abc");
+  check_rewrite (":", " ");
+  check_rewrite ("\n", " ");
+  check_rewrite ("a:b:c", "a b c");
+  check_rewrite ("a\nb\nc", "a b c");
+  check_rewrite ("a\nb:c", "a b c");
+  check_rewrite ("aa\nbb\ncc", "aa bb cc");
+  check_rewrite ("aa\nbb:cc", "aa bb cc");
+
+  return errors;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/REORG.TODO/nss/tst-nss-getpwent.c b/REORG.TODO/nss/tst-nss-getpwent.c
new file mode 100644
index 0000000000..7bd69fc378
--- /dev/null
+++ b/REORG.TODO/nss/tst-nss-getpwent.c
@@ -0,0 +1,119 @@
+/* Copyright (C) 2015-2017 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, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <pwd.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+int
+do_test (void)
+{
+  /* Count the number of entries in the password database, and fetch
+     data from the first and last entries.  */
+  size_t count = 0;
+  struct passwd * pw;
+  char *first_name = NULL;
+  uid_t first_uid = 0;
+  char *last_name = NULL;
+  uid_t last_uid = 0;
+  setpwent ();
+  while ((pw  = getpwent ()) != NULL)
+    {
+      if (first_name == NULL)
+	{
+	  first_name = strdup (pw->pw_name);
+	  if (first_name == NULL)
+	    {
+	      printf ("strdup: %m\n");
+	      return 1;
+	    }
+	  first_uid = pw->pw_uid;
+	}
+
+      free (last_name);
+      last_name = strdup (pw->pw_name);
+      if (last_name == NULL)
+	{
+	  printf ("strdup: %m\n");
+	  return 1;
+	}
+      last_uid = pw->pw_uid;
+      ++count;
+    }
+  endpwent ();
+
+  if (count == 0)
+    {
+      printf ("No entries in the password database.\n");
+      return 0;
+    }
+
+  /* Try again, this time interleaving with name-based and UID-based
+     lookup operations.  The counts do not match if the interleaved
+     lookups affected the enumeration.  */
+  size_t new_count = 0;
+  setpwent ();
+  while ((pw  = getpwent ()) != NULL)
+    {
+      if (new_count == count)
+	{
+	  printf ("Additional entry in the password database.\n");
+	  return 1;
+	}
+      ++new_count;
+      struct passwd *pw2 = getpwnam (first_name);
+      if (pw2 == NULL)
+	{
+	  printf ("getpwnam (%s) failed: %m\n", first_name);
+	  return 1;
+	}
+      pw2 = getpwnam (last_name);
+      if (pw2 == NULL)
+	{
+	  printf ("getpwnam (%s) failed: %m\n", last_name);
+	  return 1;
+	}
+      pw2 = getpwuid (first_uid);
+      if (pw2 == NULL)
+	{
+	  printf ("getpwuid (%llu) failed: %m\n",
+		  (unsigned long long) first_uid);
+	  return 1;
+	}
+      pw2 = getpwuid (last_uid);
+      if (pw2 == NULL)
+	{
+	  printf ("getpwuid (%llu) failed: %m\n",
+		  (unsigned long long) last_uid);
+	  return 1;
+	}
+    }
+  endpwent ();
+  if (new_count < count)
+    {
+      printf ("Missing entry in the password database.\n");
+      return 1;
+    }
+
+  return 0;
+}
+
+#define TIMEOUT 300
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/REORG.TODO/nss/tst-nss-static.c b/REORG.TODO/nss/tst-nss-static.c
new file mode 100644
index 0000000000..98cf073deb
--- /dev/null
+++ b/REORG.TODO/nss/tst-nss-static.c
@@ -0,0 +1,15 @@
+/* glibc test for static NSS.  */
+#include <stdio.h>
+
+#define TEST_FUNCTION do_test ()
+static int
+do_test (void)
+{
+  struct passwd *pw;
+
+  pw = getpwuid(0);
+  return pw == NULL;
+}
+
+
+#include "../test-skeleton.c"
diff --git a/REORG.TODO/nss/tst-nss-test1.c b/REORG.TODO/nss/tst-nss-test1.c
new file mode 100644
index 0000000000..c5750e0956
--- /dev/null
+++ b/REORG.TODO/nss/tst-nss-test1.c
@@ -0,0 +1,72 @@
+#include <nss.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+static int
+do_test (void)
+{
+  int retval = 0;
+
+  __nss_configure_lookup ("passwd", "test1");
+
+  static const unsigned int pwdids[] = { 100, 30, 200, 60, 20000 };
+#define npwdids (sizeof (pwdids) / sizeof (pwdids[0]))
+  setpwent ();
+
+  const unsigned int *np = pwdids;
+  for (struct passwd *p = getpwent (); p != NULL; ++np, p = getpwent ())
+    if (p->pw_uid != *np || strncmp (p->pw_name, "name", 4) != 0
+	|| atol (p->pw_name + 4) != *np)
+      {
+	printf ("passwd entry %td wrong (%s, %u)\n",
+		np - pwdids, p->pw_name, p->pw_uid);
+	retval = 1;
+	break;
+      }
+
+  endpwent ();
+
+  for (int i = npwdids - 1; i >= 0; --i)
+    {
+      char buf[30];
+      snprintf (buf, sizeof (buf), "name%u", pwdids[i]);
+
+      struct passwd *p = getpwnam (buf);
+      if (p == NULL || p->pw_uid != pwdids[i] || strcmp (buf, p->pw_name) != 0)
+	{
+	  printf ("passwd entry \"%s\" wrong\n", buf);
+	  retval = 1;
+	}
+
+      p = getpwuid (pwdids[i]);
+      if (p == NULL || p->pw_uid != pwdids[i] || strcmp (buf, p->pw_name) != 0)
+	{
+	  printf ("passwd entry %u wrong\n", pwdids[i]);
+	  retval = 1;
+	}
+
+      snprintf (buf, sizeof (buf), "name%u", pwdids[i] + 1);
+
+      p = getpwnam (buf);
+      if (p != NULL)
+	{
+	  printf ("passwd entry \"%s\" wrong\n", buf);
+	  retval = 1;
+	}
+
+      p = getpwuid (pwdids[i] + 1);
+      if (p != NULL)
+	{
+	  printf ("passwd entry %u wrong\n", pwdids[i] + 1);
+	  retval = 1;
+	}
+    }
+
+  return retval;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/REORG.TODO/nss/valid_field.c b/REORG.TODO/nss/valid_field.c
new file mode 100644
index 0000000000..88c41a81a0
--- /dev/null
+++ b/REORG.TODO/nss/valid_field.c
@@ -0,0 +1,32 @@
+/* Copyright (C) 2015-2017 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, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <nss.h>
+#include <string.h>
+
+const char __nss_invalid_field_characters[] = NSS_INVALID_FIELD_CHARACTERS;
+
+/* Check that VALUE is either NULL or a NUL-terminated string which
+   does not contain characters not permitted in NSS database
+   fields.  */
+_Bool
+internal_function
+__nss_valid_field (const char *value)
+{
+  return value == NULL
+    || strpbrk (value, __nss_invalid_field_characters) == NULL;
+}
diff --git a/REORG.TODO/nss/valid_list_field.c b/REORG.TODO/nss/valid_list_field.c
new file mode 100644
index 0000000000..9763c89bcd
--- /dev/null
+++ b/REORG.TODO/nss/valid_list_field.c
@@ -0,0 +1,36 @@
+/* Copyright (C) 2015-2017 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, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <nss.h>
+#include <stdbool.h>
+#include <string.h>
+
+static const char invalid_characters[] = NSS_INVALID_FIELD_CHARACTERS ",";
+
+/* Check that all list members match the field syntax requirements and
+   do not contain the character ','.  */
+_Bool
+internal_function
+__nss_valid_list_field (char **list)
+{
+  if (list == NULL)
+    return true;
+  for (; *list != NULL; ++list)
+    if (strpbrk (*list, invalid_characters) != NULL)
+      return false;
+  return true;
+}