-/* Copyright (C) 1996 Free Software Foundation, Inc.
-This file is part of the GNU C Library.
-Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
+/* 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 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.
+ 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. */
+ 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 <dlfcn.h>
+#include <errno.h>
#include <netdb.h>
-#include <libc-lock.h>
+#include <bits/libc-lock.h>
+#include <link.h> /* We need some help from ld.so. */
#include <search.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#if !defined DO_STATIC_NSS || defined PIC
+# include <gnu/lib-names.h>
+#endif
+
#include "nsswitch.h"
-#include "../elf/link.h" /* We need some help from ld.so. */
/* Prototypes for the local functions. */
-static void nss_init (void);
static void *nss_lookup_function (service_user *ni, const char *fct_name);
static name_database *nss_parse_file (const char *fname);
static name_database_entry *nss_getline (char *line);
const char *name);
-__libc_lock_define_initialized (static, lock);
+/* Declare external database variables. */
+#define DEFINE_DATABASE(name) \
+ extern service_user *__nss_##name##_database; \
+ weak_extern (__nss_##name##_database)
+#include "databases.def"
+#undef DEFINE_DATABASE
+/* Structure to map database name to variable. */
+static struct
+{
+ const char *name;
+ service_user **dbp;
+} databases[] =
+{
+#define DEFINE_DATABASE(name) \
+ { #name, &__nss_##name##_database },
+#include "databases.def"
+#undef DEFINE_DATABASE
+};
-/* Global variable. */
-struct __res_state _res;
+__libc_lock_define_initialized (static, lock)
-/* Nonzero if the sevices are already initialized. */
-static int nss_initialized;
+#if !defined DO_STATIC_NSS || defined PIC
+/* String with revision number of the shared object files. */
+static const char *const __nss_shlib_revision = LIBNSS_FILES_SO + 15;
+#endif
/* The root of the whole data base. */
static name_database *service_table;
-static void
-nss_init (void)
+/* -1 == database not found
+ 0 == database entry pointer stored */
+int
+__nss_database_lookup (const char *database, const char *alternate_name,
+ const char *defconfig, service_user **ni)
{
/* Prevent multiple threads to change the service table. */
__libc_lock_lock (lock);
+ /* Reconsider database variable in case some other thread called
+ `__nss_configure_lookup' while we waited for the lock. */
+ if (*ni != NULL)
+ {
+ __libc_lock_unlock (lock);
+ return 0;
+ }
+
+ /* Are we initialized yet? */
if (service_table == NULL)
+ /* Read config file. */
service_table = nss_parse_file (_PATH_NSSWITCH_CONF);
- __libc_lock_unlock (lock);
-}
-
-
-/* -1 == database not found
- 0 == database entry pointer stored */
-int
-__nss_database_lookup (const char *database, const char *defconfig,
- service_user **ni)
-{
- name_database_entry *entry;
-
- if (nss_initialized == 0)
- nss_init ();
-
/* Test whether configuration data is available. */
- if (service_table)
+ if (service_table != NULL)
{
- /* Return first `service_user' entry for DATABASE.
- XXX Will use perfect hashing function for known databases. */
+ /* Return first `service_user' entry for DATABASE. */
+ name_database_entry *entry;
/* XXX Could use some faster mechanism here. But each database is
only requested once and so this might not be critical. */
for (entry = service_table->entry; entry != NULL; entry = entry->next)
if (strcmp (database, entry->name) == 0)
- {
+ *ni = entry->service;
+
+ if (*ni == NULL && alternate_name != NULL)
+ /* We haven't found an entry so far. Try to find it with the
+ alternative name. */
+ for (entry = service_table->entry; entry != NULL; entry = entry->next)
+ if (strcmp (alternate_name, entry->name) == 0)
*ni = entry->service;
- return 0;
- }
}
/* No configuration data is available, either because nsswitch.conf
- doesn't exist or because it doesn't have a line for this database. */
- entry = malloc (sizeof *entry);
- if (entry == NULL)
- return -1;
- entry->name = database;
- /* DEFCONFIG specifies the default service list for this database,
+ doesn't exist or because it doesn't has a line for this database.
+
+ DEFCONFIG specifies the default service list for this database,
or null to use the most common default. */
- entry->service = nss_parse_service_list (defconfig ?:
- "compat [NOTFOUND=return] files");
+ if (*ni == NULL)
+ *ni = nss_parse_service_list (defconfig
+ ?: "nis [NOTFOUND=return] files");
+
+ __libc_lock_unlock (lock);
- *ni = entry->service;
return 0;
}
else
{
/* This is really only for debugging. */
- if (NSS_STATUS_TRYAGAIN > status || status > NSS_STATUS_SUCCESS)
+ if (NSS_STATUS_TRYAGAIN > status || status > NSS_STATUS_RETURN)
__libc_fatal ("illegal status in " __FUNCTION__);
if (nss_next_action (*ni, status) == NSS_ACTION_RETURN)
}
+int
+__nss_configure_lookup (const char *dbname, const char *service_line)
+{
+ service_user *new_db;
+ size_t cnt;
+
+ for (cnt = 0; cnt < sizeof databases; ++cnt)
+ {
+ int cmp = strcmp (dbname, databases[cnt].name);
+ if (cmp == 0)
+ break;
+ if (cmp < 0)
+ {
+ __set_errno (EINVAL);
+ return -1;
+ }
+ }
+
+ if (cnt == sizeof databases)
+ {
+ __set_errno (EINVAL);
+ return -1;
+ }
+
+ /* Test whether it is really used. */
+ if (databases[cnt].dbp == NULL)
+ /* Nothing to do, but we could do. */
+ return 0;
+
+ /* Try to generate new data. */
+ new_db = nss_parse_service_list (service_line);
+ if (new_db == NULL)
+ {
+ /* Illegal service specification. */
+ __set_errno (EINVAL);
+ return -1;
+ }
+
+ /* Prevent multiple threads to change the service table. */
+ __libc_lock_lock (lock);
+
+ /* Install new rules. */
+ *databases[cnt].dbp = new_db;
+
+ __libc_lock_unlock (lock);
+
+ return 0;
+}
+
+
+#if !defined DO_STATIC_NSS || defined PIC
static int
-nss_dlerror_run (void (*operate) (void))
+nss_dlerror_run (void (*operate) (void *), void *args)
{
- const char *last_errstring = NULL;
+ char *last_errstring = NULL;
const char *last_object_name = NULL;
+ int result;
+
+ (void) _dl_catch_error (&last_errstring, &last_object_name, operate, args);
+
+ result = last_errstring != NULL;
+ if (result)
+ free (last_errstring);
+
+ return result;
+}
+
- (void) _dl_catch_error (&last_errstring, &last_object_name, operate);
+struct do_open_args
+{
+ /* Argument to do_open. */
+ char *shlib_name;
+ service_user *ni;
+};
+
+struct get_sym_args
+{
+ /* Arguments to get_sym. */
+ struct link_map *map;
+ char *name;
- return last_errstring != NULL;
+ /* Return values of get_sym. */
+ ElfW(Addr) loadbase;
+ const ElfW(Sym) *ref;
+};
+
+static void
+do_open (void *a)
+{
+ struct do_open_args *args = (struct do_open_args *) a;
+ /* Open and relocate the shared object. */
+ args->ni->library->lib_handle = _dl_open (args->shlib_name, RTLD_LAZY);
}
+static void
+get_sym (void *a)
+{
+ struct get_sym_args *args = (struct get_sym_args *) a;
+ struct link_map *scope[2] = { args->map, NULL };
+ args->ref = NULL;
+ args->loadbase = _dl_lookup_symbol (args->name, &args->ref,
+ scope, args->map->l_name, 0);
+}
+#endif
/* Comparison function for searching NI->known tree. */
static int
}
}
+#if !defined DO_STATIC_NSS || defined PIC
if (ni->library->lib_handle == NULL)
{
/* Load the shared library. */
size_t shlen = (7 + strlen (ni->library->name) + 3
- + sizeof (NSS_SHLIB_REVISION));
- char shlib_name[shlen];
+ + strlen (__nss_shlib_revision) + 1);
- void do_open (void)
- {
- /* Open and relocate the shared object. */
- ni->library->lib_handle = _dl_open (shlib_name, RTLD_LAZY);
- }
+ struct do_open_args args;
+ args.shlib_name = __alloca (shlen);
+ args.ni = ni;
/* Construct shared object name. */
- __stpcpy (__stpcpy (__stpcpy (shlib_name, "libnss_"),
- ni->library->name),
- ".so" NSS_SHLIB_REVISION);
+ __stpcpy (__stpcpy (__stpcpy (__stpcpy (args.shlib_name,
+ "libnss_"),
+ ni->library->name),
+ ".so"),
+ __nss_shlib_revision);
- if (nss_dlerror_run (do_open) != 0)
+ if (nss_dlerror_run (do_open, &args) != 0)
/* Failed to load the library. */
- ni->library->lib_handle = (void *) -1;
+ ni->library->lib_handle = (void *) -1l;
}
- if (ni->library->lib_handle == (void *) -1)
+ if (ni->library->lib_handle == (void *) -1l)
/* Library not found => function not found. */
result = NULL;
else
/* Get the desired function. Again, GNU ld.so magic ahead. */
size_t namlen = (5 + strlen (ni->library->name) + 1
+ strlen (fct_name) + 1);
- char name[namlen];
- struct link_map *map = ni->library->lib_handle;
- ElfW(Addr) loadbase;
- const ElfW(Sym) *ref = NULL;
- void get_sym (void)
- {
- struct link_map *scope[2] = { map, NULL };
- loadbase = _dl_lookup_symbol (name, &ref,
- scope, map->l_name, 0, 0);
- }
+ struct get_sym_args args;
+ args.name = __alloca (namlen);
+ args.map = ni->library->lib_handle;
/* Construct the function name. */
- __stpcpy (__stpcpy (__stpcpy (__stpcpy (name, "_nss_"),
+ __stpcpy (__stpcpy (__stpcpy (__stpcpy (args.name, "_nss_"),
ni->library->name),
"_"),
fct_name);
/* Look up the symbol. */
- result = (nss_dlerror_run (get_sym)
- ? NULL : (void *) (loadbase + ref->st_value));
+ result = (nss_dlerror_run (get_sym, &args) ? NULL
+ : (void *) (args.loadbase + args.ref->st_value));
}
+#else
+ /* We can't get function address dynamically in static linking. */
+ {
+# define DEFINE_ENT(h,nm) \
+ extern void _nss_##h##_get##nm##ent_r (void); \
+ extern void _nss_##h##_end##nm##ent (void); \
+ extern void _nss_##h##_set##nm##ent (void);
+# define DEFINE_GET(h,nm) \
+ extern void _nss_##h##_get##nm##_r (void);
+# define DEFINE_GETBY(h,nm,ky) \
+ extern void _nss_##h##_get##nm##by##ky##_r (void);
+# include "function.def"
+# undef DEFINE_ENT
+# undef DEFINE_GET
+# undef DEFINE_GETBY
+# define DEFINE_ENT(h,nm) \
+ { #h"_get"#nm"ent_r", _nss_##h##_get##nm##ent_r }, \
+ { #h"_end"#nm"ent", _nss_##h##_end##nm##ent }, \
+ { #h"_set"#nm"ent", _nss_##h##_set##nm##ent },
+# define DEFINE_GET(h,nm) \
+ { #h"_get"#nm"_r", _nss_##h##_get##nm##_r },
+# define DEFINE_GETBY(h,nm,ky) \
+ { #h"_get"#nm"by"#ky"_r", _nss_##h##_get##nm##by##ky##_r },
+ static struct fct_tbl { const char *fname; void *fp; } *tp, tbl[] =
+ {
+# include "function.def"
+ { NULL, NULL }
+ };
+ size_t namlen = (5 + strlen (ni->library->name) + 1
+ + strlen (fct_name) + 1);
+ char name[namlen];
+
+ /* Construct the function name. */
+ __stpcpy (__stpcpy (__stpcpy (name, ni->library->name),
+ "_"),
+ fct_name);
+
+ result = NULL;
+ for (tp = &tbl[0]; tp->fname; tp++)
+ if (strcmp (tp->fname, name) == 0)
+ {
+ result = tp->fp;
+ break;
+ }
+ }
+#endif
/* Remember function pointer for later calls. Even if null, we
record it so a second try needn't search the library again. */
}
-/* Read the source names: `<source> ( "[" <status> "=" <action> "]" )*'. */
+/* Read the source names:
+ `( <source> ( "[" "!"? (<status> "=" <action> )+ "]" )? )*'
+ */
static service_user *
nss_parse_service_list (const char *line)
{
new_service->actions[2 + NSS_STATUS_UNAVAIL] = NSS_ACTION_CONTINUE;
new_service->actions[2 + NSS_STATUS_NOTFOUND] = NSS_ACTION_CONTINUE;
new_service->actions[2 + NSS_STATUS_SUCCESS] = NSS_ACTION_RETURN;
+ new_service->actions[2 + NSS_STATUS_RETURN] = NSS_ACTION_RETURN;
new_service->library = NULL;
new_service->known = NULL;
new_service->next = NULL;