aboutsummaryrefslogtreecommitdiff
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;
+}