[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[commits] r2816 - in /trunk/libc: ./ nss/



Author: jimb
Date: Fri Jul 13 11:29:54 2007
New Revision: 2816

Log:
Implement the OPTION_EGLIBC_NSSWITCH option group.
* option-groups.def (OPTION_EGLIBC_NSSWITCH): New entry.
* option-groups.defaults (OPTION_EGLIBC_NSSWITCH): Initialize.
* nss/fixed-nsswitch.conf, nss/fixed-nsswitch.functions: Sample
configuration files.
* nss/nsswitch.h (service_user): Change the known function table
to a union, with appropriate types for tsearch and for fixed
nsswitch.  Make the name a pointer.
(name_database_entry): Make the name a pointer.
* nss/nsswitch.c (nss_parse_file, nss_getline)
(nss_parse_service_list, nss_new_service, databases, ndatabases)
(lock, lock_nsswitch, unlock_nsswitch)
(__nss_shlib_revision, service_table):
If OPTION_EGLIBC_NSSWITCH is disabled, include statically
generated configuration data; remove code for parsing the
configuration file and reconfiguring individual databases
dynamically; initialize database and service name pointers;
simplify functions for looking up databases and query functions;
avoid locking and freeing, since no data changes at runtime.
* nss/gen-fixed-nsswitch.c: New program.
* nss/Makefile (before-compile, generated): Generate
fixed-nsswitch.h.
($(objfix)fixed-nsswitch.h, $(objpfx)gen-fixed-nsswitch)
(gen-fixed-nsswitch-CFLAGS): Rules for generating
fixed-nsswitch.h.
(CFLAGS-nsswitch.c): Define OPTION_EGLIBC_NSSWITCH as appropriate.

Added:
    trunk/libc/nss/fixed-nsswitch.conf
    trunk/libc/nss/fixed-nsswitch.functions
    trunk/libc/nss/gen-fixed-nsswitch.c
Modified:
    trunk/libc/ChangeLog.eglibc
    trunk/libc/nss/Makefile
    trunk/libc/nss/nsswitch.c
    trunk/libc/nss/nsswitch.h
    trunk/libc/option-groups.def
    trunk/libc/option-groups.defaults

Modified: trunk/libc/ChangeLog.eglibc
==============================================================================
--- trunk/libc/ChangeLog.eglibc (original)
+++ trunk/libc/ChangeLog.eglibc Fri Jul 13 11:29:54 2007
@@ -1,5 +1,32 @@
 2007-07-12  Jim Blandy  <jimb@xxxxxxxxxxxxxxxx>
 
+	Implement the OPTION_EGLIBC_NSSWITCH option group.
+	* option-groups.def (OPTION_EGLIBC_NSSWITCH): New entry.
+	* option-groups.defaults (OPTION_EGLIBC_NSSWITCH): Initialize.
+	* nss/fixed-nsswitch.conf, nss/fixed-nsswitch.functions: Sample
+	configuration files.
+	* nss/nsswitch.h (service_user): Change the known function table
+	to a union, with appropriate types for tsearch and for fixed
+	nsswitch.  Make the name a pointer.
+	(name_database_entry): Make the name a pointer.
+	* nss/nsswitch.c (nss_parse_file, nss_getline)
+	(nss_parse_service_list, nss_new_service, databases, ndatabases)
+	(lock, lock_nsswitch, unlock_nsswitch)
+	(__nss_shlib_revision, service_table):
+	If OPTION_EGLIBC_NSSWITCH is disabled, include statically
+	generated configuration data; remove code for parsing the
+	configuration file and reconfiguring individual databases
+	dynamically; initialize database and service name pointers;
+	simplify functions for looking up databases and query functions;
+	avoid locking and freeing, since no data changes at runtime.
+	* nss/gen-fixed-nsswitch.c: New program.
+	* nss/Makefile (before-compile, generated): Generate
+	fixed-nsswitch.h.
+	($(objfix)fixed-nsswitch.h, $(objpfx)gen-fixed-nsswitch)
+	(gen-fixed-nsswitch-CFLAGS): Rules for generating
+	fixed-nsswitch.h.
+	(CFLAGS-nsswitch.c): Define OPTION_EGLIBC_NSSWITCH as appropriate.
+	
 	* include/netdb.h (DECLARE_NSS_PROTOTYPES): Also declare
 	_nss_SERVICE_gethostbyname3_r.
 

Modified: trunk/libc/nss/Makefile
==============================================================================
--- trunk/libc/nss/Makefile (original)
+++ trunk/libc/nss/Makefile Fri Jul 13 11:29:54 2007
@@ -26,7 +26,8 @@
 headers			:= nss.h
 distribute		:= nsswitch.h XXX-lookup.c getXXbyYY.c getXXbyYY_r.c \
 			   getXXent.c getXXent_r.c databases.def \
-			   nsswitch.conf digits_dots.c function.def
+			   nsswitch.conf digits_dots.c function.def \
+			   gen-fixed-nsswitch.c
 
 # These are the databases that go through nss dispatch.
 # Caution: if you add a database here, you must add its real name
@@ -76,6 +77,45 @@
 libnss_files-inhibit-o	= $(filter-out .os,$(object-suffixes))
 endif
 
+ifneq ($(OPTION_EGLIBC_NSSWITCH),y)
+
+ifndef OPTION_EGLIBC_NSSWITCH_FIXED_CONFIG
+$(error OPTION_EGLIBC_NSSWITCH_FIXED_CONFIG variable left unset)
+endif
+
+ifndef OPTION_EGLIBC_NSSWITCH_FIXED_FUNCTIONS
+$(error OPTION_EGLIBC_NSSWITCH_FIXED_FUNCTIONS variable left unset)
+endif
+
+ifeq (,$(wildcard $(common-objpfx)$(OPTION_EGLIBC_NSSWITCH_FIXED_CONFIG)))
+$(warning OPTION_EGLIBC_NSSWITCH is disabled, but fixed config file)
+$(error does not exist: $(OPTION_EGLIBC_NSSWITCH_FIXED_CONFIG))
+endif
+
+ifeq (,$(wildcard $(common-objpfx)$(OPTION_EGLIBC_NSSWITCH_FIXED_FUNCTIONS)))
+$(warning OPTION_EGLIBC_NSSWITCH is disabled, but fixed functions file)
+oooo$(error does not exist: $(OPTION_EGLIBC_NSSWITCH_FIXED_FUNCTIONS))
+endif
+
+before-compile := $(objpfx)fixed-nsswitch.h
+generated := fixed-nsswitch.h
+$(objpfx)fixed-nsswitch.h $(objfpx)fixed-nsswitch-libs:		\
+    $(objpfx)gen-fixed-nsswitch					\
+    $(common-objpfx)$(OPTION_EGLIBC_NSSWITCH_FIXED_CONFIG)
+	$< $(objpfx)fixed-nsswitch.h					\
+	   $(objpfx)fixed-nsswitch-libs					\
+	   $(common-objpfx)$(OPTION_EGLIBC_NSSWITCH_FIXED_CONFIG)
+
+$(objpfx)gen-fixed-nsswitch: gen-fixed-nsswitch.c		\
+    $(common-objpfx)option-groups.config			\
+    $(common-objpfx)$(OPTION_EGLIBC_NSSWITCH_FIXED_FUNCTIONS)
+	$(native-compile)
+gen-fixed-nsswitch-CFLAGS = \
+	-g3 -O -Wall \
+	-I $(objpfx) \
+	-DFIXED_FUNCTIONS='"$(common-objpfx)$(OPTION_EGLIBC_NSSWITCH_FIXED_FUNCTIONS)"'
+endif
+
 include ../Rules
 
 
@@ -90,7 +130,10 @@
 				    $(common-objpfx)libc_nonshared.a
 
 OPTION_EGLIBC_INET-CFLAGS-$(OPTION_EGLIBC_INET) = -DOPTION_EGLIBC_INET=1
+OPTION_EGLIBC_NSSWITCH-CFLAGS-$(OPTION_EGLIBC_NSSWITCH) \
+	= -DOPTION_EGLIBC_NSSWITCH=1
 
-CFLAGS-nsswitch.c    = $(OPTION_EGLIBC_INET-CFLAGS-y)
+CFLAGS-nsswitch.c    = $(OPTION_EGLIBC_INET-CFLAGS-y) \
+		       $(OPTION_EGLIBC_NSSWITCH-CFLAGS-y)
 CFLAGS-getnssent_r.c = $(OPTION_EGLIBC_INET-CFLAGS-y)
 CFLAGS-getent.c      = $(OPTION_EGLIBC_INET-CFLAGS-y)

Added: trunk/libc/nss/fixed-nsswitch.conf
==============================================================================
--- trunk/libc/nss/fixed-nsswitch.conf (added)
+++ trunk/libc/nss/fixed-nsswitch.conf Fri Jul 13 11:29:54 2007
@@ -1,0 +1,22 @@
+# /etc/nsswitch.conf
+#
+# Example configuration for fixed name service.
+# See the description of OPTION_EGLIBC_NSSWITCH in option-groups.def
+# for details.
+#
+
+aliases:        files
+
+passwd:         files
+group:          files
+shadow:         files
+
+hosts:          files dns
+networks:       files dns
+
+protocols:      files
+services:       files
+ethers:         files
+rpc:            files
+
+netgroup:       files

Added: trunk/libc/nss/fixed-nsswitch.functions
==============================================================================
--- trunk/libc/nss/fixed-nsswitch.functions (added)
+++ trunk/libc/nss/fixed-nsswitch.functions Fri Jul 13 11:29:54 2007
@@ -1,0 +1,121 @@
+/* List of functions defined for fixed NSS in GNU C Library.
+   Copyright (C) 1996, 1997, 1998, 2005 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+/* When OPTION_EGLIBC_NSSWITCH is disabled (see option-groups.def),
+   EGLIBC does not use the 'dlopen' and 'dlsym' functions to look for
+   database query functions in the individual name service libraries.
+   Instead, it uses a set of functions chosen at compile time, as
+   directed by the OPTION_EGLIBC_NSSWITCH_FIXED_FUNCTIONS file.  This
+   file is a sample of what you might use there.
+
+   This file is C source code; it should only contain invocations of
+   the following macros:
+
+   - DEFINE_ENT (DATABASE, SERVICE, X)
+
+     Declare the 'setXent', 'getXent_r', and 'endXent' functions that
+     query DATABASE using the service library 'libnss_SERVICE.so.2'.
+     DATABASE should be the full name of the database as it appears in
+     'nsswitch.conf', like 'passwd' or 'aliases'.
+
+     (The non-reentrant 'getXent' functions are implemented in terms
+     of the reentrant 'getXent_r' functions, so there is no need to
+     refer to them explicitly here.)
+
+   - DEFINE_GETBY (DATABASE, SERVICE, X, KEY)
+
+     Declare the 'getXbyKEY_r' functions that query DATABASE using
+     SERVICE.  DATABASE and SERVICE are as described above.
+
+     (The non-reentrant 'getXbyKEY' functions are implemented in terms
+     of the reentrant 'getXbyKEY_r' functions, so there is no need to
+     refer to them explicitly here.)
+
+     Use the special key 'name3' for the service library function that
+     implements the 'getaddrinfo' function.
+
+   - DEFINE_GET (DATABASE, SERVICE, QUERY)
+
+     Declare the 'getQUERY_r' functions that query DATABASE using
+     SERVICE.  This is used for functions like 'getpwnam'.
+
+     (The non-reentrant 'getQUERY' functions are implemented in terms
+     of the reentrant 'getQUERY_r' functions, so there is no need to
+     refer to them explicitly here.)
+
+   This sample file only includes functions that consult the files in
+   '/etc', and the Domain Name System (DNS).  */
+
+/* aliases */
+DEFINE_ENT (aliases, files, alias)
+DEFINE_GETBY (aliases, files, alias, name)
+
+/* ethers */
+DEFINE_ENT (ethers, files, ether)
+
+/* group */
+DEFINE_ENT (group, files, gr)
+DEFINE_GET (group, files, grgid)
+DEFINE_GET (group, files, grnam)
+
+/* hosts */
+DEFINE_ENT (hosts, files, host)
+DEFINE_GETBY (hosts, files, host, addr)
+DEFINE_GETBY (hosts, files, host, name)
+DEFINE_GETBY (hosts, files, host, name2)
+DEFINE_GET (hosts, files, hostton)
+DEFINE_GET (hosts, files, ntohost)
+DEFINE_GETBY (hosts, dns, host, addr)
+DEFINE_GETBY (hosts, dns, host, name)
+DEFINE_GETBY (hosts, dns, host, name2)
+DEFINE_GETBY (hosts, dns, host, name3)
+
+/* netgroup */
+DEFINE_ENT (netgroup, files, netgr)
+
+/* networks */
+DEFINE_ENT (networks, files, net)
+DEFINE_GETBY (networks, files, net, name)
+DEFINE_GETBY (networks, files, net, addr)
+DEFINE_GETBY (networks, dns, net, name)
+DEFINE_GETBY (networks, dns, net, addr)
+
+/* protocols */
+DEFINE_ENT (protocols, files, proto)
+DEFINE_GETBY (protocols, files, proto, name)
+DEFINE_GETBY (protocols, files, proto, number)
+
+/* passwd */
+DEFINE_ENT (passwd, files, pw)
+DEFINE_GET (passwd, files, pwnam)
+DEFINE_GET (passwd, files, pwuid)
+
+/* rpc */
+DEFINE_ENT (rpc, files, rpc)
+DEFINE_GETBY (rpc, files, rpc, name)
+DEFINE_GETBY (rpc, files, rpc, number)
+
+/* services */
+DEFINE_ENT (services, files, serv)
+DEFINE_GETBY (services, files, serv, name)
+DEFINE_GETBY (services, files, serv, port)
+
+/* shadow */
+DEFINE_ENT (shadow, files, sp)
+DEFINE_GET (shadow, files, spnam)

Added: trunk/libc/nss/gen-fixed-nsswitch.c
==============================================================================
--- trunk/libc/nss/gen-fixed-nsswitch.c (added)
+++ trunk/libc/nss/gen-fixed-nsswitch.c Fri Jul 13 11:29:54 2007
@@ -1,0 +1,710 @@
+/* gen-fixed-nsswitch.c --- generate fixed name service data structures
+   Copyright (C) 1996-1999, 2001-2006, 2007 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#define _GNU_SOURCE
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <stdarg.h>
+#include <assert.h>
+#include <ctype.h>
+
+#define libc_hidden_proto(func)
+
+#include "nsswitch.h"
+#include "gnu/lib-names.h"
+
+
+/* Simple utilities.  */
+
+void __attribute__ ((noreturn))
+error (const char *message)
+{
+  fprintf (stderr, "%s\n", message);
+  exit (1);
+}
+
+
+void *
+check_alloc (void *p)
+{
+  if (p)
+    return p;
+  else
+    error ("out of memory");
+}
+
+void *
+xmalloc (size_t size)
+{
+  return check_alloc (malloc (size));
+}
+
+
+/* Format ARGS according to FORMAT, and return the result as a
+   malloc'ed string.  */
+char *
+saprintf (const char *format, ...)
+{
+  va_list args;
+  size_t len;
+  char *buf;
+  
+  va_start (args, format);
+  len = vsnprintf (NULL, 0, format, args);
+  va_end (args);
+
+  buf = xmalloc (len + 1);
+  va_start (args, format);
+  assert (len == vsnprintf (buf, len + 1, format, args));
+  va_end (args);
+
+  return buf;
+}
+
+
+
+/* Gathering the contents of the FIXED_FUNCTIONS file.  */
+
+/* It should be possible to generate this list automatically by
+   looking at the services and databases used in the nsswitch.conf
+   file, and having a hard-coded set of queries supported on each
+   database.  */
+
+/* We #include the FIXED_FUNCTIONS file several times to build an
+   array of function structures holding its data.  */
+enum function_kind {
+  fk_end = 0,                   /* Last entry.  */
+  fk_setent,                    /* Like setpwent.  */
+  fk_getent,                    /* Like getpwent.  */
+  fk_endent,                    /* Like endpwent.  */
+  fk_getby,                     /* Like gethostbyname.  */
+  fk_get                        /* Like getpwnam.  */
+};
+
+
+struct function {
+  /* What kind of function this is.  */
+  enum function_kind kind;
+
+  /* The database and service of the function being hardwired in.  */
+  char *database, *service;
+
+  /* The kind of entry being queried, for 'fk_setent', 'fk_getent',
+     'fk_endent', and 'fk_getby' functions.  */
+  char *entry;
+
+  /* The key, for 'fk_getby' entries.  */
+  char *key;
+
+  /* The value and key, for 'fk_get' entries.  */
+  char *value_and_key;
+};
+
+
+const struct function functions[] =
+  {
+
+#define DEFINE_ENT(database, service, entry)    \
+    { fk_setent, #database, #service, #entry }, \
+    { fk_getent, #database, #service, #entry }, \
+    { fk_endent, #database, #service, #entry },
+#define DEFINE_GETBY(database, service, entry, key)   \
+    { fk_getby, #database, #service, #entry, #key },
+#define DEFINE_GET(database, service, value_and_key)     \
+    { fk_get, #database, #service, NULL, NULL, #value_and_key },
+
+#include FIXED_FUNCTIONS
+
+#undef DEFINE_ENT
+#undef DEFINE_GETBY
+#undef DEFINE_GET
+
+    { fk_end }
+  };
+
+
+/* Parsing the config file.  Functions copied from nsswitch.c.  */
+
+#define __strchrnul strchrnul
+#define __getline getline
+#define __strncasecmp strncasecmp
+
+/* Prototypes for the local functions.  */
+static name_database *nss_parse_file (const char *fname) internal_function;
+static name_database_entry *nss_getline (char *line) internal_function;
+static service_user *nss_parse_service_list (const char *line)
+     internal_function;
+
+static name_database *
+internal_function
+nss_parse_file (const char *fname)
+{
+  FILE *fp;
+  name_database *result;
+  name_database_entry *last;
+  char *line;
+  size_t len;
+
+  /* Open the configuration file.  */
+  fp = fopen (fname, "rc");
+  if (fp == NULL)
+    return NULL;
+
+  // /* No threads use this stream.  */
+  // __fsetlocking (fp, FSETLOCKING_BYCALLER);
+
+  result = (name_database *) xmalloc (sizeof (name_database));
+
+  result->entry = NULL;
+  result->library = NULL;
+  last = NULL;
+  line = NULL;
+  len = 0;
+  do
+    {
+      name_database_entry *this;
+      ssize_t n;
+
+      n = __getline (&line, &len, fp);
+      if (n < 0)
+	break;
+      if (line[n - 1] == '\n')
+	line[n - 1] = '\0';
+
+      /* Because the file format does not know any form of quoting we
+	 can search forward for the next '#' character and if found
+	 make it terminating the line.  */
+      *__strchrnul (line, '#') = '\0';
+
+      /* If the line is blank it is ignored.  */
+      if (line[0] == '\0')
+	continue;
+
+      /* Each line completely specifies the actions for a database.  */
+      this = nss_getline (line);
+      if (this != NULL)
+	{
+	  if (last != NULL)
+	    last->next = this;
+	  else
+	    result->entry = this;
+
+	  last = this;
+	}
+    }
+  while (!feof_unlocked (fp));
+
+  /* Free the buffer.  */
+  free (line);
+  /* Close configuration file.  */
+  fclose (fp);
+
+  return result;
+}
+
+
+/* Read the source names:
+	`( <source> ( "[" "!"? (<status> "=" <action> )+ "]" )? )*'
+   */
+static service_user *
+internal_function
+nss_parse_service_list (const char *line)
+{
+  service_user *result = NULL, **nextp = &result;
+
+  while (1)
+    {
+      service_user *new_service;
+      const char *name;
+
+      while (isspace (line[0]))
+	++line;
+      if (line[0] == '\0')
+	/* No source specified.  */
+	return result;
+
+      /* Read <source> identifier.  */
+      name = line;
+      while (line[0] != '\0' && !isspace (line[0]) && line[0] != '[')
+	++line;
+      if (name == line)
+	return result;
+
+
+      new_service = (service_user *) xmalloc (sizeof (*new_service));
+      new_service->name = (char *) xmalloc (line - name + 1);
+
+      *((char *) __mempcpy ((char *) new_service->name, name, line - name))
+        = '\0';
+
+      /* Set default actions.  */
+      new_service->actions[2 + NSS_STATUS_TRYAGAIN] = NSS_ACTION_CONTINUE;
+      new_service->actions[2 + NSS_STATUS_UNAVAIL] = NSS_ACTION_CONTINUE;
+      new_service->actions[2 + NSS_STATUS_NOTFOUND] = NSS_ACTION_CONTINUE;
+      new_service->actions[2 + NSS_STATUS_SUCCESS] = NSS_ACTION_RETURN;
+      new_service->actions[2 + NSS_STATUS_RETURN] = NSS_ACTION_RETURN;
+      new_service->library = NULL;
+      new_service->known.tree = NULL;
+      new_service->next = NULL;
+
+      while (isspace (line[0]))
+	++line;
+
+      if (line[0] == '[')
+	{
+	  /* Read criterions.  */
+	  do
+	    ++line;
+	  while (line[0] != '\0' && isspace (line[0]));
+
+	  do
+	    {
+	      int not;
+	      enum nss_status status;
+	      lookup_actions action;
+
+	      /* Grok ! before name to mean all statii but that one.  */
+	      not = line[0] == '!';
+	      if (not)
+		++line;
+
+	      /* Read status name.  */
+	      name = line;
+	      while (line[0] != '\0' && !isspace (line[0]) && line[0] != '='
+		     && line[0] != ']')
+		++line;
+
+	      /* Compare with known statii.  */
+	      if (line - name == 7)
+		{
+		  if (__strncasecmp (name, "SUCCESS", 7) == 0)
+		    status = NSS_STATUS_SUCCESS;
+		  else if (__strncasecmp (name, "UNAVAIL", 7) == 0)
+		    status = NSS_STATUS_UNAVAIL;
+		  else
+		    return result;
+		}
+	      else if (line - name == 8)
+		{
+		  if (__strncasecmp (name, "NOTFOUND", 8) == 0)
+		    status = NSS_STATUS_NOTFOUND;
+		  else if (__strncasecmp (name, "TRYAGAIN", 8) == 0)
+		    status = NSS_STATUS_TRYAGAIN;
+		  else
+		    return result;
+		}
+	      else
+		return result;
+
+	      while (isspace (line[0]))
+		++line;
+	      if (line[0] != '=')
+		return result;
+	      do
+		++line;
+	      while (isspace (line[0]));
+
+	      name = line;
+	      while (line[0] != '\0' && !isspace (line[0]) && line[0] != '='
+		     && line[0] != ']')
+		++line;
+
+	      if (line - name == 6 && __strncasecmp (name, "RETURN", 6) == 0)
+		action = NSS_ACTION_RETURN;
+	      else if (line - name == 8
+		       && __strncasecmp (name, "CONTINUE", 8) == 0)
+		action = NSS_ACTION_CONTINUE;
+	      else
+		return result;
+
+	      if (not)
+		{
+		  /* Save the current action setting for this status,
+		     set them all to the given action, and reset this one.  */
+		  const lookup_actions save = new_service->actions[2 + status];
+		  new_service->actions[2 + NSS_STATUS_TRYAGAIN] = action;
+		  new_service->actions[2 + NSS_STATUS_UNAVAIL] = action;
+		  new_service->actions[2 + NSS_STATUS_NOTFOUND] = action;
+		  new_service->actions[2 + NSS_STATUS_SUCCESS] = action;
+		  new_service->actions[2 + status] = save;
+		}
+	      else
+		new_service->actions[2 + status] = action;
+
+	      /* Skip white spaces.  */
+	      while (isspace (line[0]))
+		++line;
+	    }
+	  while (line[0] != ']');
+
+	  /* Skip the ']'.  */
+	  ++line;
+	}
+
+      *nextp = new_service;
+      nextp = &new_service->next;
+    }
+}
+
+static name_database_entry *
+internal_function
+nss_getline (char *line)
+{
+  const char *name;
+  name_database_entry *result;
+  size_t len;
+
+  /* Ignore leading white spaces.  ATTENTION: this is different from
+     what is implemented in Solaris.  The Solaris man page says a line
+     beginning with a white space character is ignored.  We regard
+     this as just another misfeature in Solaris.  */
+  while (isspace (line[0]))
+    ++line;
+
+  /* Recognize `<database> ":"'.  */
+  name = line;
+  while (line[0] != '\0' && !isspace (line[0]) && line[0] != ':')
+    ++line;
+  if (line[0] == '\0' || name == line)
+    /* Syntax error.  */
+    return NULL;
+  *line++ = '\0';
+
+  len = strlen (name) + 1;
+
+  result = (name_database_entry *) xmalloc (sizeof (*result));
+  result->name = (char *) xmalloc (len);
+
+  /* Save the database name.  */
+  memcpy ((char *) result->name, name, len);
+
+  /* Parse the list of services.  */
+  result->service = nss_parse_service_list (line);
+
+  result->next = NULL;
+  return result;
+}
+
+
+
+/* Generating code for statically initialized nsswitch structures.  */
+
+
+/* Return the service-neutral suffix of the name of the service
+   library function referred to by the function F.  The result is
+   allocated with malloc.  */
+char *
+known_function_suffix (const struct function *f)
+{
+  switch (f->kind)
+    {
+    case fk_setent:
+      return saprintf ("set%sent", f->entry);
+
+    case fk_getent:
+      return saprintf ("get%sent_r", f->entry);
+
+    case fk_endent:
+      return saprintf ("end%sent", f->entry);
+
+    case fk_getby:
+      return saprintf ("get%sby%s_r", f->entry, f->key);
+
+    case fk_get:
+      return saprintf ("get%s_r", f->value_and_key);
+
+    default:
+      abort ();
+    }
+}
+
+
+/* Return the name of the service library function referred to by the
+   function F.  The result is allocated with malloc.  */
+char *
+known_function_name (const struct function *f)
+{
+  return saprintf ("_nss_%s_%s", f->service, known_function_suffix (f));
+}
+
+
+/* Write initialized known_function structures to OUT for
+   all the functions we'll use.  */
+void
+generate_known_functions (FILE *out)
+{
+  int i;
+
+  /* First, generate weak references to the functions.  The service
+     libraries depend on libc, and if these references weren't weak,
+     we'd be making libc depend circularly on the service
+     libraries.  */
+  for (i = 0; functions[i].kind; i++)
+    {
+      char *name = known_function_name (&functions[i]);
+      fprintf (out, "typeof (%s) %s __attribute__ ((weak));\n",
+               name, name);
+    }
+  fputs ("\n", out);
+
+  /* Then, a table mapping names to functions.  */
+  fputs ("static const known_function fixed_known_functions[] = {\n",
+         out);
+  for (i = 0; functions[i].kind; i++)
+    {
+      const struct function *f = &functions[i];
+      char *suffix = known_function_suffix (f);
+
+      fprintf (out, "  /* %2d */ { \"%s\", _nss_%s_%s },\n",
+               i, suffix, f->service, suffix);
+    }
+  fputs ("};\n", out);
+  fputs ("\n", out);
+}
+
+
+/* Print code to OUT for an initialized array of pointers to the
+   'known_function' structures needed for USER, which is for
+   DATABASE.  Return its name, allocated with malloc.  */
+char *
+generate_known_function_list (FILE *out,
+                              const name_database_entry *database,
+                              const service_user *user)
+{
+  char *list_name = saprintf ("fixed_%s_%s_known_funcs",
+                              database->name, user->name);
+  fprintf (out, "static const known_function *%s[] = {\n",
+           list_name);
+  int i;
+  for (i = 0; functions[i].kind; i++)
+    if (strcmp (functions[i].database, database->name) == 0
+        && strcmp (functions[i].service, user->name) == 0)
+      fprintf (out, "  &fixed_known_functions[%d], /* %s */\n",
+               i, known_function_name (&functions[i]));
+  fputs ("  NULL\n", out);
+  fputs ("};\n", out);
+  fputs ("\n", out);
+
+  return list_name;
+}
+
+
+/* Return the name of the status value STATUS, as a statically
+   allocated string.  */
+const char *
+lookup_status_name (enum nss_status status)
+{
+  switch (status)
+    {
+    case NSS_STATUS_TRYAGAIN: return "NSS_STATUS_TRYAGAIN";
+    case NSS_STATUS_UNAVAIL: return "NSS_STATUS_UNAVAIL";
+    case NSS_STATUS_NOTFOUND: return "NSS_STATUS_NOTFOUND";
+    case NSS_STATUS_SUCCESS: return "NSS_STATUS_SUCCESS";
+    case NSS_STATUS_RETURN: return "NSS_STATUS_RETURN";
+    default: abort ();
+    };
+}
+
+
+/* Return the name of ACTION as a statically allocated string.  */
+const char *
+lookup_action_name (lookup_actions action)
+{
+  switch (action)
+    {
+    case NSS_ACTION_CONTINUE: return "NSS_ACTION_CONTINUE";
+    case NSS_ACTION_RETURN: return "NSS_ACTION_RETURN";
+    default: abort ();
+    }
+}
+
+
+/* Print code to OUT for the list of service_user structures starting
+   with USER, which are all for DATABASE.  Return the name of the 
+   first structure in that list, or zero if USER is NULL.  */
+char *
+generate_service_user_list (FILE *out,
+                            name_database_entry *database,
+                            service_user *user)
+{
+  if (user)
+    {
+      /* Generate the tail of the list.  */
+      char *next_name = generate_service_user_list (out, database, user->next);
+      /* Generate our known function list.  */
+      char *known_function_list_name =
+        generate_known_function_list (out, database, user);
+
+      char *name = saprintf ("fixed_%s_%s_user", database->name, user->name);
+
+      fprintf (out, "static const service_user %s = {\n", name);
+      if (next_name)
+        fprintf (out, "  (service_user *) &%s,\n", next_name);
+      else
+        fprintf (out, "  NULL, /* no next entry */\n");
+      fputs ("  {\n", out);
+      int i;
+      for (i = 0; i < sizeof (user->actions) / sizeof (user->actions[0]); i++)
+        fprintf (out, "    %s, /* %s */\n",
+                 lookup_action_name (user->actions[i]),
+                 lookup_status_name (i - 2));
+      fputs ("  },\n", out);
+      fprintf (out, "  NULL,  /* we never need the service library */\n");
+      fprintf (out, "  { .array = %s },\n", known_function_list_name);
+      fprintf (out, "  \"%s\"\n", user->name);
+      fputs ("};\n", out);
+      fputs ("\n", out);
+      
+      return name;
+    }
+  else
+    return NULL;
+}
+
+
+/* Print code to OUT for the list of name_database_entry structures
+   starting with DATABASE.  Return the name of the first structure 
+   in that list, or zero if DATABASE is NULL.  */
+char *
+generate_name_database_entries (FILE *out, name_database_entry *database)
+{
+  if (database)
+    {
+      char *next_name = generate_name_database_entries (out, database->next);
+      char *service_user_name
+        = generate_service_user_list (out, database, database->service);
+      char *name = saprintf ("fixed_%s_name_database", database->name);
+
+      fprintf (out, "static const name_database_entry %s = {\n", name);
+
+      if (next_name)
+        fprintf (out, "  (name_database_entry *) &%s,\n", next_name);
+      else
+        fprintf (out, "  NULL,\n");
+      
+      if (service_user_name)
+        fprintf (out, "  (service_user *) &%s,\n", service_user_name);
+      else
+        fprintf (out, "  NULL,\n");
+
+      fprintf (out, "  \"%s\"\n", database->name);
+      fprintf (out, "};\n");
+      fputs ("\n", out);
+
+      return name;
+    }
+  else
+    return NULL;
+}
+
+
+void
+generate_name_database (FILE *out, name_database *service_table)
+{
+  /* Produce a linked list of the known name_database_entry
+     structures.  */
+  char *entries = generate_name_database_entries (out, service_table->entry);
+
+  /* Now produce the main structure that points to them all.  */
+  fprintf (out, "static const name_database fixed_name_database = {\n");
+  if (entries)
+    fprintf (out, "  (name_database_entry *) &%s,\n", entries);
+  else
+    fprintf (out, "  NULL,\n");
+  fputs ("  NULL /* we don't need the libraries */\n"
+         "};\n",
+         out);
+}
+
+
+
+/* Generating the list of service libraries we generate references to.  */
+
+/* String with revision number of the shared object files.  */
+static const char *const nss_shlib_revision = LIBNSS_FILES_SO + 15;
+
+void
+generate_service_lib_list (FILE *out, name_database *service_table)
+{
+  int i, j;
+  int printed_any = 0;
+
+  for (i = 0; functions[i].kind; i++)
+    {
+      /* Mention each service library only once.  */
+      for (j = 0; j < i; j++)
+        if (strcmp (functions[i].service, functions[j].service) == 0)
+          break;
+
+      if (j >= i)
+        {
+          if (printed_any)
+            putc (' ', out);
+          fprintf (out, "libnss_%s.so%s",
+                   functions[i].service,
+                   nss_shlib_revision);
+          printed_any = 1;
+        }
+    }
+}
+
+
+/* Main.  */
+
+int
+main (int argc, char **argv)
+{
+  if (argc != 4)
+    {
+      fprintf (stderr, "usage: gen-fixed-nsswitch HEADER SERVLIBS CONFIG\n");
+      exit (1);
+    }
+  
+  name_database *service_table = nss_parse_file (argv[3]);
+  
+  FILE *header = fopen (argv[1], "w");
+  if (! header)
+    {
+      fprintf (stderr,
+               "gen-fixed-nsswitch: couldn't open output file %s: %s\n",
+               argv[1], strerror (errno));
+      exit (1);
+    }
+  fputs ("/* Generated by nss/gen-fixed-nsswitch.c.  */\n", header);
+  fputs ("\n", header);
+  generate_known_functions (header);
+  generate_name_database (header, service_table);
+  fclose (header);
+
+  FILE *service_lib_list = fopen (argv[2], "w");
+  if (! service_lib_list)
+    {
+      fprintf (stderr,
+               "gen-fixed-nsswitch: couldn't open output file %s: %s\n",
+               argv[2], strerror (errno));
+      exit (1);
+    }
+  generate_service_lib_list (service_lib_list, service_table);
+  fclose (service_lib_list);
+
+  return 0;
+}

Modified: trunk/libc/nss/nsswitch.c
==============================================================================
--- trunk/libc/nss/nsswitch.c (original)
+++ trunk/libc/nss/nsswitch.c Fri Jul 13 11:29:54 2007
@@ -41,6 +41,15 @@
 #include "nsswitch.h"
 #include "../nscd/nscd_proto.h"
 
+/* When OPTION_EGLIBC_NSSWITCH is disabled, we use fixed tables of
+   databases and services, generated at library build time.  Thus:
+   - We can't reconfigure individual databases, so we don't need a
+     name-to-database map.
+   - We never add databases or service libraries, or look up functions
+     at runtime, so there's no need for a lock to protect our tables.
+   See ../option-groups.def for the details.  */
+#ifdef OPTION_EGLIBC_NSSWITCH
+
 /* Prototypes for the local functions.  */
 static name_database *nss_parse_file (const char *fname) internal_function;
 static name_database_entry *nss_getline (char *line) internal_function;
@@ -74,6 +83,9 @@
 
 __libc_lock_define_initialized (static, lock)
 
+#define lock_nsswitch (__libc_lock_lock (lock))
+#define unlock_nsswitch (__libc_lock_unlock (lock))
+
 #if !defined DO_STATIC_NSS || defined SHARED
 /* String with revision number of the shared object files.  */
 static const char *const __nss_shlib_revision = LIBNSS_FILES_SO + 15;
@@ -81,6 +93,20 @@
 
 /* The root of the whole data base.  */
 static name_database *service_table;
+
+#else /* OPTION_EGLIBC_NSSWITCH */
+
+/* Bring in the statically initialized service table we generated at
+   build time.  */
+#include "fixed-nsswitch.h"
+
+const static name_database *service_table = &fixed_name_database;
+
+/* Nothing ever changes, so there's no need to lock anything.  */
+#define lock_nsswitch (0)
+#define unlock_nsswitch (0)
+
+#endif /* OPTION_EGLIBC_NSSWITCH */
 
 
 /* -1 == database not found
@@ -90,20 +116,22 @@
 		       const char *defconfig, service_user **ni)
 {
   /* Prevent multiple threads to change the service table.  */
-  __libc_lock_lock (lock);
+  lock_nsswitch;
 
   /* Reconsider database variable in case some other thread called
      `__nss_configure_lookup' while we waited for the lock.  */
   if (*ni != NULL)
     {
-      __libc_lock_unlock (lock);
+      unlock_nsswitch;
       return 0;
     }
 
+#ifdef OPTION_EGLIBC_NSSWITCH
   /* Are we initialized yet?  */
   if (service_table == NULL)
     /* Read config file.  */
     service_table = nss_parse_file (_PATH_NSSWITCH_CONF);
+#endif
 
   /* Test whether configuration data is available.  */
   if (service_table != NULL)
@@ -125,6 +153,7 @@
 	    *ni = entry->service;
     }
 
+#ifdef OPTION_EGLIBC_NSSWITCH
   /* No configuration data is available, either because nsswitch.conf
      doesn't exist or because it doesn't has a line for this database.
 
@@ -133,8 +162,18 @@
   if (*ni == NULL)
     *ni = nss_parse_service_list (defconfig
 				  ?: "nis [NOTFOUND=return] files");
-
-  __libc_lock_unlock (lock);
+#else
+  /* Without the dynamic behavior, we can't process defconfig.  The
+     databases the user specified at library build time are all you
+     get.  */
+  if (*ni == NULL)
+    {
+      unlock_nsswitch;
+      return -1;
+    }
+#endif
+
+  unlock_nsswitch;
 
   return 0;
 }
@@ -205,6 +244,7 @@
 libc_hidden_def (__nss_next)
 
 
+#ifdef OPTION_EGLIBC_NSSWITCH
 int
 __nss_configure_lookup (const char *dbname, const char *service_line)
 {
@@ -244,12 +284,12 @@
     }
 
   /* Prevent multiple threads to change the service table.  */
-  __libc_lock_lock (lock);
+  lock_nsswitch;
 
   /* Install new rules.  */
   *databases[cnt].dbp = new_db;
 
-  __libc_lock_unlock (lock);
+  unlock_nsswitch;
 
   return 0;
 }
@@ -270,7 +310,7 @@
   void **found, *result;
 
   /* We now modify global data.  Protect it.  */
-  __libc_lock_lock (lock);
+  lock_nsswitch;
 
   /* Search the tree of functions previously requested.  Data in the
      tree are `known_function' structures, whose first member is a
@@ -281,7 +321,7 @@
      enough to a pointer to our structure to use as a lookup key that
      will be passed to `known_compare' (above).  */
 
-  found = __tsearch (&fct_name, (void **) &ni->known, &known_compare);
+  found = __tsearch (&fct_name, &ni->known.tree, &known_compare);
   if (*found != &fct_name)
     /* The search found an existing structure in the tree.  */
     result = ((known_function *) *found)->fct_ptr;
@@ -298,7 +338,7 @@
 	remove_from_tree:
 	  /* Oops.  We can't instantiate this node properly.
 	     Remove it from the tree.  */
-	  __tdelete (&fct_name, (void **) &ni->known, &known_compare);
+	  __tdelete (&fct_name, &ni->known.tree, &known_compare);
 	  result = NULL;
 	}
       else
@@ -411,13 +451,43 @@
     }
 
   /* Remove the lock.  */
-  __libc_lock_unlock (lock);
+  unlock_nsswitch;
 
   return result;
 }
 libc_hidden_def (__nss_lookup_function)
 
 
+#else /* below if ! defined (OPTION_EGLIBC_NSSWITCH) */
+
+
+int
+__nss_configure_lookup (const char *dbname, const char *service_line)
+{
+  /* We can't dynamically configure lookup without
+     OPTION_EGLIBC_NSSWITCH.  */
+  __set_errno (EINVAL);
+  return -1;
+}
+
+
+void *
+__nss_lookup_function (service_user *ni, const char *fct_name)
+{
+  int i;
+  const known_function **known = ni->known.array;
+
+  for (i = 0; known[i]; i++)
+    if (strcmp (fct_name, known[i]->fct_name) == 0)
+      return known[i]->fct_ptr;
+
+  return NULL;
+}
+libc_hidden_def (__nss_lookup_function)
+#endif
+
+
+#ifdef OPTION_EGLIBC_NSSWITCH
 static name_database *
 internal_function
 nss_parse_file (const char *fname)
@@ -520,8 +590,10 @@
 					     + (line - name + 1));
       if (new_service == NULL)
 	return result;
-
-      *((char *) __mempcpy (new_service->name, name, line - name)) = '\0';
+      new_service->name = (char *) (new_service + 1);
+
+      *((char *) __mempcpy ((char *) new_service->name, name, line - name))
+        = '\0';
 
       /* Set default actions.  */
       new_service->actions[2 + NSS_STATUS_TRYAGAIN] = NSS_ACTION_CONTINUE;
@@ -530,7 +602,7 @@
       new_service->actions[2 + NSS_STATUS_SUCCESS] = NSS_ACTION_RETURN;
       new_service->actions[2 + NSS_STATUS_RETURN] = NSS_ACTION_RETURN;
       new_service->library = NULL;
-      new_service->known = NULL;
+      new_service->known.tree = NULL;
       new_service->next = NULL;
 
       while (isspace (line[0]))
@@ -661,9 +733,10 @@
   result = (name_database_entry *) malloc (sizeof (name_database_entry) + len);
   if (result == NULL)
     return NULL;
+  result->name = (char *) (result + 1);
 
   /* Save the database name.  */
-  memcpy (result->name, name, len);
+  memcpy ((char *) result->name, name, len);
 
   /* Parse the list of services.  */
   result->service = nss_parse_service_list (line);
@@ -697,6 +770,7 @@
 
   return *currentp;
 }
+#endif /* OPTION_EGLIBC_NSSWITCH */
 
 
 #ifdef OPTION_EGLIBC_INET
@@ -713,6 +787,7 @@
 #endif /* OPTION_EGLIBC_INET */
 
 
+#ifdef OPTION_EGLIBC_NSSWITCH
 /* Free all resources if necessary.  */
 libc_freeres_fn (free_mem)
 {
@@ -737,8 +812,8 @@
 	{
 	  service_user *olds = service;
 
-	  if (service->known != NULL)
-	    __tdestroy (service->known, free);
+	  if (service->known.tree != NULL)
+	    __tdestroy (service->known.tree, free);
 
 	  service = service->next;
 	  free (olds);
@@ -762,3 +837,4 @@
 
   free (top);
 }
+#endif /* OPTION_EGLIBC_NSSWITCH */

Modified: trunk/libc/nss/nsswitch.h
==============================================================================
--- trunk/libc/nss/nsswitch.h (original)
+++ trunk/libc/nss/nsswitch.h Fri Jul 13 11:29:54 2007
@@ -65,10 +65,20 @@
   lookup_actions actions[5];
   /* Link to the underlying library object.  */
   service_library *library;
-  /* Collection of known functions.  */
-  struct entry *known;
+  /* Collection of known functions.
+
+     With OPTION_EGLIBC_NSSWITCH enabled, this is the root of a
+     'tsearch'-style tree.
+
+     With OPTION_EGLIBC_NSSWITCH disabled, this is an array of
+     pointers to known_function structures, NULL-terminated.  */
+  union
+  {
+    void *tree;
+    const known_function **array;
+  } known;
   /* Name of the service (`files', `dns', `nis', ...).  */
-  char name[0];
+  const char *name;
 } service_user;
 
 /* To access the action based on the status value use this macro.  */
@@ -82,7 +92,7 @@
   /* List of service to be used.  */
   service_user *service;
   /* Name of the database.  */
-  char name[0];
+  const char *name;
 } name_database_entry;
 
 

Modified: trunk/libc/option-groups.def
==============================================================================
--- trunk/libc/option-groups.def (original)
+++ trunk/libc/option-groups.def Fri Jul 13 11:29:54 2007
@@ -288,6 +288,78 @@
        group; if you disable OPTION_EGLIBC_LOCALE_CODE, you must also
        disable OPTION_EGLIBC_CATGETS.
 
+config OPTION_EGLIBC_NSSWITCH
+   bool "Name service switch (nsswitch) support"
+   help
+
+       This option group includes support for the 'nsswitch' facility.
+       With this option group enabled, all EGLIBC functions for
+       accessing various system databases (passwords and groups;
+       networking; aliases; public keys; and so on) consult the
+       '/etc/nsswitch.conf' configuration file to decide how to handle
+       queries.
+
+       With this option group disabled, EGLIBC uses a fixed list of
+       services to satisfy queries on each database, as requested by
+       configuration files specified when EGLIBC is built.  Your
+       'option-groups.config' file must set the following two
+       variables:
+
+       OPTION_EGLIBC_NSSWITCH_FIXED_CONFIG
+
+          Set this to the name of a file whose contents observe the
+          same syntax as an ordinary '/etc/nsswitch.conf' file.  The
+          EGLIBC build process parses this file just as EGLIBC would
+          at run time if OPTION_EGLIBC_NSSWITCH were enabled, and
+          produces a C library that uses the nsswitch service
+          libraries to search for database entries as this file
+          specifies, instead of consulting '/etc/nsswitch.conf' at run
+          time.
+
+          This should be a relative file name; EGLIBC will look for it
+          in the top build directory, along with the
+          'option-groups.config' file.
+
+          The EGLIBC source tree includes a sample configuration file
+          named 'nss/fixed-nsswitch.conf'; for simple configurations,
+          you will probably want to delete references to databases not
+          needed on your system.
+
+       OPTION_EGLIBC_NSSWITCH_FIXED_FUNCTIONS
+
+          The EGLIBC build process uses this file to decide which
+          functions to make available from which service libraries.
+          The file 'nss/fixed-nsswitch.functions' serves as a sample
+          configuration file for this setting, and explains its syntax
+          and meaning in more detail.
+
+          This should be a relative file name; EGLIBC will look for it
+          in the top build directory, along with the
+          'option-groups.config' file.
+
+          Be sure to mention each function in each service you wish to
+          use.  If you do not mention a service's function here, the
+          EGLIBC database access functions will not find it, even if
+          it is listed in the OPTION_EGLIBC_NSSWITCH_FIXED_CONFIG
+          file.
+
+       In this arrangement, EGLIBC will not use the 'dlopen' and
+       'dlsym' functions to find database access functions.  Instead,
+       libc hard-codes references to the service libraries' database
+       access functions.  You must explicitly link your program
+       against the name service libraries (those whose names start
+       with 'libnss_', in the sysroot's '/lib' directory) whose
+       functions you intend to use.  This arrangement helps
+       system-wide static analysis tools decide which functions a
+       system actually uses.
+
+       Note that some nsswitch service libraries require other option
+       groups to be enabled; for example, the OPTION_EGLIBC_INET
+       option group must be enabled to use the 'libnss_dns.so.2' or
+       'libnss_nis.so.2' service libraries, which use the Domain Name
+       System and Network Information Service network protocols to
+       answer queries.
+
 config OPTION_POSIX_REGEXP
     bool "Regular expressions"
     help

Modified: trunk/libc/option-groups.defaults
==============================================================================
--- trunk/libc/option-groups.defaults (original)
+++ trunk/libc/option-groups.defaults Fri Jul 13 11:29:54 2007
@@ -14,4 +14,5 @@
 OPTION_EGLIBC_LIBM = y
 OPTION_EGLIBC_LOCALES = y
 OPTION_EGLIBC_LOCALE_CODE = y
+OPTION_EGLIBC_NSSWITCH = y
 OPTION_POSIX_REGEXP = y