summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjimb <jimb@7b3dc134-2b1b-0410-93df-9e9f96275f8d>2007-07-13 18:29:54 +0000
committerjimb <jimb@7b3dc134-2b1b-0410-93df-9e9f96275f8d>2007-07-13 18:29:54 +0000
commit1decd60e6634c6092519d58acacb9475cd498f9f (patch)
tree116e8d0ad6f7f88a951184ecd0297ebf4f1f4909
parentb6a246fa0e6117a98a0d0486543921550a25cf86 (diff)
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. git-svn-id: svn://svn.eglibc.org/trunk@2816 7b3dc134-2b1b-0410-93df-9e9f96275f8d
-rw-r--r--libc/ChangeLog.eglibc27
-rw-r--r--libc/nss/Makefile47
-rw-r--r--libc/nss/fixed-nsswitch.conf22
-rw-r--r--libc/nss/fixed-nsswitch.functions121
-rw-r--r--libc/nss/gen-fixed-nsswitch.c710
-rw-r--r--libc/nss/nsswitch.c104
-rw-r--r--libc/nss/nsswitch.h18
-rw-r--r--libc/option-groups.def72
-rw-r--r--libc/option-groups.defaults1
9 files changed, 1102 insertions, 20 deletions
diff --git a/libc/ChangeLog.eglibc b/libc/ChangeLog.eglibc
index c73fa4122..c1ef913b7 100644
--- a/libc/ChangeLog.eglibc
+++ b/libc/ChangeLog.eglibc
@@ -1,5 +1,32 @@
2007-07-12 Jim Blandy <jimb@codesourcery.com>
+ 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.
diff --git a/libc/nss/Makefile b/libc/nss/Makefile
index 0936faa65..7cb74f567 100644
--- a/libc/nss/Makefile
+++ b/libc/nss/Makefile
@@ -26,7 +26,8 @@ subdir := nss
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 @@ ifneq ($(build-static-nss),yes)
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 @@ $(services:%=$(objpfx)libnss_%.so): $(common-objpfx)libc.so \
$(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)
diff --git a/libc/nss/fixed-nsswitch.conf b/libc/nss/fixed-nsswitch.conf
new file mode 100644
index 000000000..91bb675c8
--- /dev/null
+++ b/libc/nss/fixed-nsswitch.conf
@@ -0,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
diff --git a/libc/nss/fixed-nsswitch.functions b/libc/nss/fixed-nsswitch.functions
new file mode 100644
index 000000000..2f3fa833c
--- /dev/null
+++ b/libc/nss/fixed-nsswitch.functions
@@ -0,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)
diff --git a/libc/nss/gen-fixed-nsswitch.c b/libc/nss/gen-fixed-nsswitch.c
new file mode 100644
index 000000000..d8e24d4f3
--- /dev/null
+++ b/libc/nss/gen-fixed-nsswitch.c
@@ -0,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;
+}
diff --git a/libc/nss/nsswitch.c b/libc/nss/nsswitch.c
index 8d86e887f..fa360ff48 100644
--- a/libc/nss/nsswitch.c
+++ b/libc/nss/nsswitch.c
@@ -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 @@ static const struct
__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;
@@ -82,6 +94,20 @@ static const char *const __nss_shlib_revision = LIBNSS_FILES_SO + 15;
/* 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
0 == database entry pointer stored */
@@ -90,20 +116,22 @@ __nss_database_lookup (const char *database, const char *alternate_name,
const char *defconfig, service_user **ni)
{
/* Prevent multiple threads to change the service table. */
- __libc_lock_lock (lock);
+ 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 @@ __nss_database_lookup (const char *database, const char *alternate_name,
*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 @@ __nss_database_lookup (const char *database, const char *alternate_name,
if (*ni == NULL)
*ni = nss_parse_service_list (defconfig
?: "nis [NOTFOUND=return] files");
+#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
- __libc_lock_unlock (lock);
+ unlock_nsswitch;
return 0;
}
@@ -205,6 +244,7 @@ __nss_next (service_user **ni, const char *fct_name, void **fctp, int status,
libc_hidden_def (__nss_next)
+#ifdef OPTION_EGLIBC_NSSWITCH
int
__nss_configure_lookup (const char *dbname, const char *service_line)
{
@@ -244,12 +284,12 @@ __nss_configure_lookup (const char *dbname, const char *service_line)
}
/* 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 @@ __nss_lookup_function (service_user *ni, const char *fct_name)
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 @@ __nss_lookup_function (service_user *ni, const char *fct_name)
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 @@ __nss_lookup_function (service_user *ni, const char *fct_name)
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 @@ __nss_lookup_function (service_user *ni, const char *fct_name)
}
/* 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 @@ nss_parse_service_list (const char *line)
+ (line - name + 1));
if (new_service == NULL)
return result;
+ new_service->name = (char *) (new_service + 1);
- *((char *) __mempcpy (new_service->name, name, line - name)) = '\0';
+ *((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 @@ nss_parse_service_list (const char *line)
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 @@ nss_getline (char *line)
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 @@ nss_new_service (name_database *database, const char *name)
return *currentp;
}
+#endif /* OPTION_EGLIBC_NSSWITCH */
#ifdef OPTION_EGLIBC_INET
@@ -713,6 +787,7 @@ __nss_disable_nscd (void)
#endif /* OPTION_EGLIBC_INET */
+#ifdef OPTION_EGLIBC_NSSWITCH
/* Free all resources if necessary. */
libc_freeres_fn (free_mem)
{
@@ -737,8 +812,8 @@ libc_freeres_fn (free_mem)
{
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 @@ libc_freeres_fn (free_mem)
free (top);
}
+#endif /* OPTION_EGLIBC_NSSWITCH */
diff --git a/libc/nss/nsswitch.h b/libc/nss/nsswitch.h
index 96568c69a..6eb0ed0c1 100644
--- a/libc/nss/nsswitch.h
+++ b/libc/nss/nsswitch.h
@@ -65,10 +65,20 @@ typedef struct service_user
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 @@ typedef struct name_database_entry
/* List of service to be used. */
service_user *service;
/* Name of the database. */
- char name[0];
+ const char *name;
} name_database_entry;
diff --git a/libc/option-groups.def b/libc/option-groups.def
index 3a7a1af3a..46acf60b6 100644
--- a/libc/option-groups.def
+++ b/libc/option-groups.def
@@ -288,6 +288,78 @@ config OPTION_EGLIBC_LOCALE_CODE
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
diff --git a/libc/option-groups.defaults b/libc/option-groups.defaults
index 9f619c4c2..4eb930f68 100644
--- a/libc/option-groups.defaults
+++ b/libc/option-groups.defaults
@@ -14,4 +14,5 @@ OPTION_EGLIBC_INET = y
OPTION_EGLIBC_LIBM = y
OPTION_EGLIBC_LOCALES = y
OPTION_EGLIBC_LOCALE_CODE = y
+OPTION_EGLIBC_NSSWITCH = y
OPTION_POSIX_REGEXP = y