aboutsummaryrefslogtreecommitdiff
path: root/REORG.TODO/nss/nss_files
diff options
context:
space:
mode:
Diffstat (limited to 'REORG.TODO/nss/nss_files')
-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
17 files changed, 2604 insertions, 0 deletions
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)