mirror of
https://sourceware.org/git/glibc.git
synced 2025-07-29 11:41:21 +03:00
Last minute change.
Mon Aug 12 04:33:09 1996 Ulrich Drepper <drepper@cygnus.com> * nss/nsswitch.c (__nss_database_lookup): Always release locks before returning. Reported by Miles Bader. (distributes): Add databases.def.
This commit is contained in:
118
nss/nsswitch.c
118
nss/nsswitch.c
@ -19,6 +19,7 @@ Boston, MA 02111-1307, USA. */
|
||||
|
||||
#include <ctype.h>
|
||||
#include <dlfcn.h>
|
||||
#include <errno.h>
|
||||
#include <netdb.h>
|
||||
#include <libc-lock.h>
|
||||
#include <search.h>
|
||||
@ -30,7 +31,6 @@ Boston, MA 02111-1307, USA. */
|
||||
#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);
|
||||
@ -39,6 +39,27 @@ static service_library *nss_new_service (name_database *database,
|
||||
const char *name);
|
||||
|
||||
|
||||
/* 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
|
||||
};
|
||||
|
||||
|
||||
__libc_lock_define_initialized (static, lock)
|
||||
|
||||
|
||||
@ -50,35 +71,29 @@ static int nss_initialized;
|
||||
static name_database *service_table;
|
||||
|
||||
|
||||
static void
|
||||
nss_init (void)
|
||||
{
|
||||
/* Prevent multiple threads to change the service table. */
|
||||
__libc_lock_lock (lock);
|
||||
|
||||
if (service_table == NULL)
|
||||
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;
|
||||
/* Prevent multiple threads to change the service table. */
|
||||
__libc_lock_lock (lock);
|
||||
|
||||
if (nss_initialized == 0)
|
||||
nss_init ();
|
||||
/* Reconsider database variable in case some other thread called
|
||||
`__nss_configure_lookup' while we waited for the lock. */
|
||||
if (*ni != NULL)
|
||||
return 0;
|
||||
|
||||
if (nss_initialized == 0 && service_table == NULL)
|
||||
/* Read config file. */
|
||||
service_table = nss_parse_file (_PATH_NSSWITCH_CONF);
|
||||
|
||||
/* 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. */
|
||||
@ -91,17 +106,14 @@ __nss_database_lookup (const char *database, const char *defconfig,
|
||||
}
|
||||
|
||||
/* 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,
|
||||
or null to use the most common default. */
|
||||
entry->service = nss_parse_service_list (defconfig ?:
|
||||
"compat [NOTFOUND=return] files");
|
||||
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. */
|
||||
*ni = nss_parse_service_list (defconfig ?: "compat [NOTFOUND=return] files");
|
||||
|
||||
__libc_lock_unlock (lock);
|
||||
|
||||
*ni = entry->service;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -168,6 +180,48 @@ __nss_next (service_user **ni, const char *fct_name, void **fctp, int status,
|
||||
}
|
||||
|
||||
|
||||
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)
|
||||
if (strcmp (dbname, databases[cnt].name) == 0)
|
||||
break;
|
||||
|
||||
if (cnt == sizeof databases)
|
||||
{
|
||||
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. */
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
nss_dlerror_run (void (*operate) (void))
|
||||
{
|
||||
@ -385,7 +439,9 @@ nss_parse_file (const char *fname)
|
||||
}
|
||||
|
||||
|
||||
/* Read the source names: `<source> ( "[" <status> "=" <action> "]" )*'. */
|
||||
/* Read the source names:
|
||||
`( <source> ( "[" "!"? (<status> "=" <action> )+ "]" )? )*'
|
||||
*/
|
||||
static service_user *
|
||||
nss_parse_service_list (const char *line)
|
||||
{
|
||||
|
Reference in New Issue
Block a user