summaryrefslogtreecommitdiff
path: root/glibc-compat/nss_files
diff options
context:
space:
mode:
authorRoland McGrath <roland@gnu.org>2004-09-22 21:21:10 +0000
committerRoland McGrath <roland@gnu.org>2004-09-22 21:21:10 +0000
commitb5707b44d25d7af61b0338c2a2206c036eaf7337 (patch)
treed8b9e865cbc78d64835a63959370865a2a043223 /glibc-compat/nss_files
parent4ff389feb39f2eb649530b843d478c80c27ab4cf (diff)
Changes and additions migrated from cvs.devel.redhat.com:/cvs/devel/glibc to fedora-branch
Diffstat (limited to 'glibc-compat/nss_files')
-rw-r--r--glibc-compat/nss_files/files-XXX.c311
-rw-r--r--glibc-compat/nss_files/files-alias.c451
-rw-r--r--glibc-compat/nss_files/files-ethers.c75
-rw-r--r--glibc-compat/nss_files/files-grp.c45
-rw-r--r--glibc-compat/nss_files/files-hosts.c107
-rw-r--r--glibc-compat/nss_files/files-netgrp.c268
-rw-r--r--glibc-compat/nss_files/files-network.c56
-rw-r--r--glibc-compat/nss_files/files-parse.c252
-rw-r--r--glibc-compat/nss_files/files-proto.c47
-rw-r--r--glibc-compat/nss_files/files-pwd.c45
-rw-r--r--glibc-compat/nss_files/files-rpc.c47
-rw-r--r--glibc-compat/nss_files/files-service.c60
-rw-r--r--glibc-compat/nss_files/files-spwd.c38
13 files changed, 1802 insertions, 0 deletions
diff --git a/glibc-compat/nss_files/files-XXX.c b/glibc-compat/nss_files/files-XXX.c
new file mode 100644
index 0000000000..fde75a87b4
--- /dev/null
+++ b/glibc-compat/nss_files/files-XXX.c
@@ -0,0 +1,311 @@
+/* Common code for file-based databases in nss_files module.
+ Copyright (C) 1996, 1997, 1998 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 Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <errno.h>
+#include <bits/libc-lock.h>
+#include "nsswitch.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 <glibc-compat/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
+
+/* Locks the static variables in this file. */
+__libc_lock_define_initialized (static, lock)
+
+/* Maintenance of the shared stream open on the database file. */
+
+static FILE *stream;
+static fpos_t position;
+static enum { none, getent, getby } last_use;
+static int keep_stream;
+
+/* Open database file if not already opened. */
+static enum nss_status
+internal_setent (int stayopen)
+{
+ enum nss_status status = NSS_STATUS_SUCCESS;
+
+ if (stream == NULL)
+ {
+ stream = fopen (DATAFILE, "r");
+
+ if (stream == NULL)
+ status = errno == EAGAIN ? NSS_STATUS_TRYAGAIN : NSS_STATUS_UNAVAIL;
+ else
+ {
+ /* We have to make sure the file is `closed on exec'. */
+ int result, flags;
+
+ result = flags = fcntl (fileno (stream), F_GETFD, 0);
+ if (result >= 0)
+ {
+ flags |= FD_CLOEXEC;
+ result = fcntl (fileno (stream), F_SETFD, flags);
+ }
+ if (result < 0)
+ {
+ /* Something went wrong. Close the stream and return a
+ failure. */
+ fclose (stream);
+ stream = NULL;
+ status = NSS_STATUS_UNAVAIL;
+ }
+ }
+ }
+ else
+ rewind (stream);
+
+ /* Remember STAYOPEN flag. */
+ if (stream != NULL)
+ keep_stream |= stayopen;
+
+ 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 (stayopen);
+
+ if (status == NSS_STATUS_SUCCESS && fgetpos (stream, &position) < 0)
+ {
+ fclose (stream);
+ stream = NULL;
+ status = NSS_STATUS_UNAVAIL;
+ }
+
+ last_use = getent;
+
+ __libc_lock_unlock (lock);
+
+ return status;
+}
+
+
+/* Close the database file. */
+static void
+internal_endent (void)
+{
+ 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 ();
+
+ /* Reset STAYOPEN flag. */
+ keep_stream = 0;
+
+ __libc_lock_unlock (lock);
+
+ return NSS_STATUS_SUCCESS;
+}
+
+/* Parsing the database file into `struct STRUCTURE' data structures. */
+
+static enum nss_status
+internal_getent (struct STRUCTURE *result,
+ char *buffer, int buflen H_ERRNO_PROTO)
+{
+ char *p;
+ struct parser_data *data = (void *) buffer;
+ int linebuflen = buffer + buflen - data->linebuffer;
+ int parse_result;
+
+ if (buflen < (int) sizeof *data + 1)
+ {
+ __set_errno (ERANGE);
+ H_ERRNO_SET (NETDB_INTERNAL);
+ return NSS_STATUS_TRYAGAIN;
+ }
+
+ do
+ {
+ /* Terminate the line so that we can test for overflow. */
+ data->linebuffer[linebuflen - 1] = '\xff';
+
+ p = fgets (data->linebuffer, linebuflen, stream);
+ if (p == NULL && feof (stream))
+ {
+ /* End of file or read error. */
+ __set_errno (ENOENT);
+ H_ERRNO_SET (HOST_NOT_FOUND);
+ return NSS_STATUS_NOTFOUND;
+ }
+ else if (p == NULL || data->linebuffer[linebuflen - 1] != '\xff')
+ {
+ /* The line is too long. Give the user the opportunity to
+ enlarge the buffer. */
+ __set_errno (ERANGE);
+ H_ERRNO_SET (NETDB_INTERNAL);
+ return NSS_STATUS_TRYAGAIN;
+ }
+
+ /* Skip leading blanks. */
+ 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)));
+
+ /* Filled in RESULT with the next entry from the database file. */
+ return parse_result == -1 ? NSS_STATUS_TRYAGAIN : 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 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)
+ {
+ status = internal_setent (0);
+
+ if (status == NSS_STATUS_SUCCESS && fgetpos (stream, &position) < 0)
+ {
+ fclose (stream);
+ stream = NULL;
+ status = NSS_STATUS_UNAVAIL;
+ }
+ }
+
+ if (status == NSS_STATUS_SUCCESS)
+ {
+ /* If the last use was not by the getent function we need the
+ position the stream. */
+ if (last_use != getent)
+ {
+ if (fsetpos (stream, &position) < 0)
+ status = NSS_STATUS_UNAVAIL;
+ else
+ last_use = getent;
+ }
+
+ if (status == NSS_STATUS_SUCCESS)
+ {
+ status = internal_getent (result, buffer, buflen H_ERRNO_ARG);
+
+ /* Remember this position if we were successful. If the
+ operation failed we give the user a chance to repeat the
+ operation (perhaps the buffer was too small). */
+ if (status == NSS_STATUS_SUCCESS)
+ fgetpos (stream, &position);
+ else
+ /* We must make sure we reposition the stream the next call. */
+ last_use = none;
+ }
+ }
+
+ __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'.
+
+ KEYSIZE and KEYPATTERN are ignored here but used by ../nss_db/db-XXX.c.
+
+ PROTO describes the arguments for the lookup key;
+ e.g. `const char *hostname'.
+
+ BREAK_IF_MATCH is a block of code which compares `struct STRUCTURE *result'
+ to the lookup key arguments and does `break;' if they match. */
+
+#define DB_LOOKUP(name, keysize, keypattern, break_if_match, proto...) \
+enum nss_status \
+_nss_files_get##name##_r (proto, \
+ struct STRUCTURE *result, \
+ char *buffer, size_t buflen H_ERRNO_PROTO) \
+{ \
+ enum nss_status status; \
+ \
+ __libc_lock_lock (lock); \
+ \
+ /* Reset file pointer to beginning or open file. */ \
+ status = internal_setent (keep_stream); \
+ \
+ if (status == NSS_STATUS_SUCCESS) \
+ { \
+ /* Tell getent function that we have repositioned the file pointer. */ \
+ last_use = getby; \
+ \
+ while ((status = internal_getent (result, buffer, buflen H_ERRNO_ARG)) \
+ == NSS_STATUS_SUCCESS) \
+ { break_if_match } \
+ \
+ if (! keep_stream) \
+ internal_endent (); \
+ } \
+ \
+ __libc_lock_unlock (lock); \
+ \
+ return status; \
+}
diff --git a/glibc-compat/nss_files/files-alias.c b/glibc-compat/nss_files/files-alias.c
new file mode 100644
index 0000000000..d9e5549998
--- /dev/null
+++ b/glibc-compat/nss_files/files-alias.c
@@ -0,0 +1,451 @@
+/* Mail alias file parser in nss_files module.
+ Copyright (C) 1996, 1997, 1998 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 Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <glibc-compat/include/aliases.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <bits/libc-lock.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "nsswitch.h"
+
+/* Locks the static variables in this file. */
+__libc_lock_define_initialized (static, lock)
+
+/* Maintenance of the shared stream open on the database file. */
+
+static FILE *stream;
+static fpos_t position;
+static enum { none, getent, getby } last_use;
+
+
+static enum nss_status
+internal_setent (void)
+{
+ enum nss_status status = NSS_STATUS_SUCCESS;
+
+ if (stream == NULL)
+ {
+ stream = fopen ("/etc/aliases", "r");
+
+ if (stream == NULL)
+ status = errno == EAGAIN ? NSS_STATUS_TRYAGAIN : NSS_STATUS_UNAVAIL;
+ else
+ {
+ /* We have to make sure the file is `closed on exec'. */
+ int result, flags;
+
+ result = flags = fcntl (fileno (stream), F_GETFD, 0);
+ if (result >= 0)
+ {
+ flags |= FD_CLOEXEC;
+ result = fcntl (fileno (stream), F_SETFD, flags);
+ }
+ if (result < 0)
+ {
+ /* Something went wrong. Close the stream and return a
+ failure. */
+ fclose (stream);
+ stream = NULL;
+ status = 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 ();
+
+ if (status == NSS_STATUS_SUCCESS && fgetpos (stream, &position) < 0)
+ {
+ fclose (stream);
+ stream = NULL;
+ status = NSS_STATUS_UNAVAIL;
+ }
+
+ last_use = getent;
+
+ __libc_lock_unlock (lock);
+
+ return status;
+}
+
+
+/* Close the database file. */
+static void
+internal_endent (void)
+{
+ 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 ();
+
+ __libc_lock_unlock (lock);
+
+ return NSS_STATUS_SUCCESS;
+}
+
+/* Parsing the database file into `struct aliasent' data structures. */
+static enum nss_status
+get_next_alias (const char *match, struct aliasent *result,
+ char *buffer, size_t buflen)
+{
+ 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;
+
+ /* Read the first line. It must contain the alias name and
+ possibly some alias names. */
+ first_unused[room_left - 1] = '\xff';
+ line = fgets (first_unused, room_left, stream);
+ if (line == NULL && feof (stream))
+ /* Nothing to read. */
+ break;
+ else if (line == NULL || first_unused[room_left - 1] != '\xff')
+ {
+ /* The line is too long for our buffer. */
+ no_more_room:
+ __set_errno (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], "r");
+ /* If the file does not exist we simply ignore
+ the statement. */
+ if (listfile != NULL
+ && (old_line = strdup (line)) != NULL)
+ {
+ while (! feof (listfile))
+ {
+ first_unused[room_left - 1] = '\xff';
+ line = fgets (first_unused, room_left, listfile);
+ if (line == NULL && feof (listfile))
+ break;
+ if (line == NULL
+ || 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);
+
+ if (old_line != NULL)
+ free (old_line);
+
+ 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 (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 (first_unused, room_left, stream);
+ if (line == NULL && feof (stream))
+ break;
+ if (line == NULL || 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)
+{
+ /* 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 ();
+
+ if (status == NSS_STATUS_SUCCESS)
+ {
+ /* If the last use was not by the getent function we need the
+ position the stream. */
+ if (last_use != getent)
+ {
+ if (fsetpos (stream, &position) < 0)
+ status = NSS_STATUS_UNAVAIL;
+ else
+ last_use = getent;
+ }
+
+ if (status == NSS_STATUS_SUCCESS)
+ {
+ result->alias_local = 1;
+
+ /* Read lines until we get a definite result. */
+ do
+ status = get_next_alias (NULL, result, buffer, buflen);
+ while (status == NSS_STATUS_RETURN);
+
+ /* If we successfully read an entry remember this position. */
+ if (status == NSS_STATUS_SUCCESS)
+ fgetpos (stream, &position);
+ else
+ last_use = none;
+ }
+ }
+
+ __libc_lock_unlock (lock);
+
+ return status;
+}
+
+
+enum nss_status
+_nss_files_getaliasbyname_r (const char *name, struct aliasent *result,
+ char *buffer, size_t buflen)
+{
+ /* Return next entry in host file. */
+ enum nss_status status = NSS_STATUS_SUCCESS;
+
+ if (name == NULL)
+ {
+ __set_errno (EINVAL);
+ return NSS_STATUS_UNAVAIL;
+ }
+
+ __libc_lock_lock (lock);
+
+ /* Open the stream or rest it. */
+ status = internal_setent ();
+ last_use = getby;
+
+ if (status == NSS_STATUS_SUCCESS)
+ {
+ result->alias_local = 1;
+
+ /* Read lines until we get a definite result. */
+ do
+ status = get_next_alias (name, result, buffer, buflen);
+ while (status == NSS_STATUS_RETURN);
+ }
+
+ internal_endent ();
+
+ __libc_lock_unlock (lock);
+
+ return status;
+}
diff --git a/glibc-compat/nss_files/files-ethers.c b/glibc-compat/nss_files/files-ethers.c
new file mode 100644
index 0000000000..290d931c97
--- /dev/null
+++ b/glibc-compat/nss_files/files-ethers.c
@@ -0,0 +1,75 @@
+/* Copyright (C) 1996 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 Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+The GNU C Library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+#include <string.h>
+#include <netinet/if_ether.h>
+
+/* Because the `ethers' lookup does not fit so well in the scheme so
+ we define a dummy struct here which helps us to use the available
+ functions. */
+struct etherent
+{
+ const char *e_name;
+ struct ether_addr e_addr;
+};
+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, 0, 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, 1 + strlen (name), (".%s", name),
+ {
+ if (strcmp (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;
+ }, struct ether_addr *addr)
diff --git a/glibc-compat/nss_files/files-grp.c b/glibc-compat/nss_files/files-grp.c
new file mode 100644
index 0000000000..ac9b632d42
--- /dev/null
+++ b/glibc-compat/nss_files/files-grp.c
@@ -0,0 +1,45 @@
+/* Group file parser in nss_files module.
+ Copyright (C) 1996, 1997 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 Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <glibc-compat/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, 1 + strlen (name), (".%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/glibc-compat/nss_files/files-hosts.c b/glibc-compat/nss_files/files-hosts.c
new file mode 100644
index 0000000000..1b96f74b35
--- /dev/null
+++ b/glibc-compat/nss_files/files-hosts.c
@@ -0,0 +1,107 @@
+/* Hosts file parser in nss_files module.
+ Copyright (C) 1996, 1997, 1998 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 Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+#include <glibc-compat/include/netdb.h>
+#include <resolv.h>
+
+
+/* Get implementation for some internal functions. */
+#include "../resolv/mapv4v6addr.h"
+
+
+#define ENTNAME hostent
+#define DATABASE "hosts"
+#define NEED_H_ERRNO
+
+#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_INET, addr, entdata->host_addr) > 0)
+ {
+ if (_res.options & RES_USE_INET6)
+ {
+ map_v4v6_address ((char *) entdata->host_addr,
+ (char *) entdata->host_addr);
+ result->h_addrtype = AF_INET6;
+ result->h_length = IN6ADDRSZ;
+ }
+ else
+ {
+ result->h_addrtype = AF_INET;
+ result->h_length = INADDRSZ;
+ }
+ }
+ else if (inet_pton (AF_INET6, addr, entdata->host_addr) > 0)
+ {
+ result->h_addrtype = AF_INET6;
+ result->h_length = IN6ADDRSZ;
+ }
+ else
+ /* Illegal address: ignore line. */
+ return 0;
+
+ /* Store a pointer to the address in the expected form. */
+ entdata->h_addr_ptrs[0] = entdata->host_addr;
+ entdata->h_addr_ptrs[1] = NULL;
+ result->h_addr_list = entdata->h_addr_ptrs;
+
+ STRING_FIELD (result->h_name, isspace, 1);
+ })
+
+#include "files-XXX.c"
+
+DB_LOOKUP (hostbyname, ,,
+ {
+ if (result->h_addrtype != ((_res.options & RES_USE_INET6)
+ ? AF_INET6 : AF_INET))
+ continue;
+ LOOKUP_NAME_CASE (h_name, h_aliases)
+ }, const char *name)
+
+DB_LOOKUP (hostbyname2, ,,
+ {
+ if (result->h_addrtype != af)
+ continue;
+ LOOKUP_NAME_CASE (h_name, h_aliases)
+ }, const char *name, int af)
+
+DB_LOOKUP (hostbyaddr, ,,
+ {
+ if (result->h_addrtype == type && result->h_length == len &&
+ ! memcmp (addr, result->h_addr_list[0], len))
+ break;
+ }, const char *addr, int len, int type)
diff --git a/glibc-compat/nss_files/files-netgrp.c b/glibc-compat/nss_files/files-netgrp.c
new file mode 100644
index 0000000000..8820e6a02c
--- /dev/null
+++ b/glibc-compat/nss_files/files-netgrp.c
@@ -0,0 +1,268 @@
+/* Netgroup file parser in nss_files modules.
+ Copyright (C) 1996, 1997 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 Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <ctype.h>
+#include <errno.h>
+#include <glibc-compat/include/netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "nsswitch.h"
+#include "netgroup.h"
+
+#define DATAFILE "/etc/netgroup"
+
+
+#define EXPAND(needed) \
+ do \
+ { \
+ size_t old_cursor = result->cursor - result->data; \
+ \
+ result->data_size += 512 > 2 * needed ? 512 : 2 * needed; \
+ result->data = realloc (result->data, result->data_size); \
+ \
+ if (result->data == NULL) \
+ { \
+ 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, "r");
+ 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;
+
+ while (!feof (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 (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);
+ }
+
+ return status;
+}
+
+
+int
+_nss_files_endnetgrent (struct __netgrent *result)
+{
+ /* Free allocated memory for data if some is present. */
+ if (result->data != NULL)
+ {
+ free (result->data);
+ result->data = NULL;
+ result->data_size = 0;
+ result->cursor = NULL;
+ }
+
+ return NSS_STATUS_SUCCESS;
+}
+
+
+enum nss_status
+_nss_netgroup_parseline (char **cursor, struct __netgrent *result,
+ char *buffer, int buflen)
+{
+ 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)
+ {
+ __set_errno (ERANGE);
+ status = NSS_STATUS_UNAVAIL;
+ }
+ else
+ {
+ memcpy (buffer, host, cp - host);
+ result->type = triple_val;
+
+ buffer[(user - host) - 1] = '\0';
+ result->val.triple.host = *host == ',' ? NULL : buffer;
+
+ buffer[(domain - host) - 1] = '\0';
+ result->val.triple.user = *user == ',' ? NULL : buffer + (user - host);
+
+ buffer[(cp - host) - 1] = '\0';
+ result->val.triple.domain =
+ *domain == ')' ? NULL : buffer + (domain - host);
+
+ status = NSS_STATUS_SUCCESS;
+
+ /* Remember where we stopped reading. */
+ *cursor = cp;
+
+ result->first = 0;
+ }
+
+ return status;
+}
+
+
+enum nss_status
+_nss_files_getnetgrent_r (struct __netgrent *result, char *buffer, int buflen)
+{
+ enum nss_status status;
+
+ status = _nss_netgroup_parseline (&result->cursor, result, buffer, buflen);
+
+ return status;
+}
diff --git a/glibc-compat/nss_files/files-network.c b/glibc-compat/nss_files/files-network.c
new file mode 100644
index 0000000000..45ded2fedf
--- /dev/null
+++ b/glibc-compat/nss_files/files-network.c
@@ -0,0 +1,56 @@
+/* Networks file parser in nss_files module.
+ Copyright (C) 1996, 1997, 1998 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 Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <glibc-compat/include/netdb.h>
+
+#define ENTNAME netent
+#define DATABASE "networks"
+
+struct netent_data {};
+
+#define TRAILING_LIST_MEMBER n_aliases
+#define TRAILING_LIST_SEPARATOR_P isspace
+#include "files-parse.c"
+LINE_PARSER
+("#",
+ {
+ char *addr;
+
+ STRING_FIELD (result->n_name, isspace, 1);
+
+ STRING_FIELD (addr, isspace, 1);
+ 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 (result->n_addrtype == type && result->n_net == net)
+ /* Bingo! */
+ break;
+ }, unsigned long int net, int type)
diff --git a/glibc-compat/nss_files/files-parse.c b/glibc-compat/nss_files/files-parse.c
new file mode 100644
index 0000000000..49c08153c9
--- /dev/null
+++ b/glibc-compat/nss_files/files-parse.c
@@ -0,0 +1,252 @@
+/* Common code for file-based database parsers in nss_files module.
+ Copyright (C) 1996, 1997, 1998 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 Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <ctype.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.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.
+
+ Also see files-XXX.c. */
+
+#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
+#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)
+#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);
+
+# 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) \
+{ \
+ ENTDATA_DECL (data) \
+ char *p = strpbrk (line, EOLSET "\n"); \
+ if (p != NULL) \
+ *p = '\0'; \
+ BODY; \
+ TRAILING_LIST_PARSER; \
+ return 1; \
+}
+
+
+# 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 INT_FIELD(variable, terminator_p, swallow, base, convert) \
+ { \
+ char *endp; \
+ variable = convert (strtoul (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 (strtoul (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 TRAILING_LIST_PARSER /* Nothing to do. */
+# else
+
+# define TRAILING_LIST_PARSER \
+{ \
+ char **list = parse_list (line, data, datalen); \
+ 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 *line, struct parser_data *data, size_t datalen)
+{
+ char *eol, **list, **p;
+
+ if (line >= data->linebuffer && line < (char *) data + datalen)
+ /* Find the end of the line buffer, we will use the space in DATA after
+ it for storing the vector of pointers. */
+ eol = 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. */
+ eol = data->linebuffer;
+ /* 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)
+ {
+ char *elt;
+
+ if ((size_t) ((char *) &p[1] - (char *) data) > datalen)
+ {
+ /* We cannot fit another pointer in the buffer. */
+ __set_errno (ERANGE);
+ return NULL;
+ }
+ if (*line == '\0')
+ break;
+
+ /* Skip leading white space. This might not be portable but useful. */
+ while (isspace (*line))
+ ++line;
+
+ elt = line;
+ while (1)
+ {
+ if (*line == '\0' || 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')
+ *line++ = '\0';
+ break;
+ }
+ ++line;
+ }
+ }
+ *p = NULL;
+
+ 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/glibc-compat/nss_files/files-proto.c b/glibc-compat/nss_files/files-proto.c
new file mode 100644
index 0000000000..6c53cce6a1
--- /dev/null
+++ b/glibc-compat/nss_files/files-proto.c
@@ -0,0 +1,47 @@
+/* Protocols file parser in nss_files module.
+ Copyright (C) 1996, 1997 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 Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <glibc-compat/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, 1 + strlen (name), (".%s", name),
+ LOOKUP_NAME (p_name, p_aliases),
+ const char *name)
+
+DB_LOOKUP (protobynumber, 20, ("=%d", proto),
+ {
+ if (result->p_proto == proto)
+ break;
+ }, int proto)
diff --git a/glibc-compat/nss_files/files-pwd.c b/glibc-compat/nss_files/files-pwd.c
new file mode 100644
index 0000000000..621d70e065
--- /dev/null
+++ b/glibc-compat/nss_files/files-pwd.c
@@ -0,0 +1,45 @@
+/* User file parser in nss_files module.
+ Copyright (C) 1996, 1997 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 Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <glibc-compat/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, 1 + strlen (name), (".%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/glibc-compat/nss_files/files-rpc.c b/glibc-compat/nss_files/files-rpc.c
new file mode 100644
index 0000000000..4e73e0e06b
--- /dev/null
+++ b/glibc-compat/nss_files/files-rpc.c
@@ -0,0 +1,47 @@
+/* SunRPC program number file parser in nss_files module.
+ Copyright (C) 1996, 1997 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 Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <glibc-compat/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, 1 + strlen (name), (".%s", name),
+ LOOKUP_NAME (r_name, r_aliases),
+ const char *name)
+
+DB_LOOKUP (rpcbynumber, 20, ("=%d", number),
+ {
+ if (result->r_number == number)
+ break;
+ }, int number)
diff --git a/glibc-compat/nss_files/files-service.c b/glibc-compat/nss_files/files-service.c
new file mode 100644
index 0000000000..96255dd223
--- /dev/null
+++ b/glibc-compat/nss_files/files-service.c
@@ -0,0 +1,60 @@
+/* Services file parser in nss_files module.
+ Copyright (C) 1996, 1997, 1998 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 Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <netinet/in.h>
+#include <glibc-compat/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, 2 + strlen (name) + (proto ? strlen (proto) : 0),
+ (".%s/%s", name, proto ?: ""),
+ {
+ /* Must match both protocol (if specified) and name. */
+ if (proto != NULL && strcmp (result->s_proto, proto))
+ continue;
+ LOOKUP_NAME (s_name, s_aliases)
+ },
+ const char *name, const char *proto)
+
+DB_LOOKUP (servbyport, 21 + (proto ? strlen (proto) : 0),
+ ("=%d/%s", 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/glibc-compat/nss_files/files-spwd.c b/glibc-compat/nss_files/files-spwd.c
new file mode 100644
index 0000000000..f7f25fd304
--- /dev/null
+++ b/glibc-compat/nss_files/files-spwd.c
@@ -0,0 +1,38 @@
+/* User file parser in nss_files module.
+ Copyright (C) 1996, 1997 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 Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <glibc-compat/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, 1 + strlen (name), (".%s", name),
+ {
+ if (name[0] != '+' && name[0] != '-'
+ && ! strcmp (name, result->sp_namp))
+ break;
+ }, const char *name)