From 319b9ad4bccedb2a6b1a222cf446e873b2bc6de1 Mon Sep 17 00:00:00 2001 From: Ulrich Drepper Date: Mon, 11 Jul 2011 14:50:24 -0400 Subject: Generalize framework to register monitoring of files in nscd nscd can clear caches when certain files change. The list of files was hardcoded so far and worked for nss_files and nss_dns and those modules which need no monitoring. nss_db, for instance, has its own set of files to monitor. Now the NSS modules themselves can request that certain files are monitored. --- ChangeLog | 42 ++++++++++ nscd/cache.c | 46 +++++++---- nscd/connections.c | 165 +++++++++++++++++++-------------------- nscd/nscd.c | 18 ++++- nscd/nscd.h | 19 ++++- nss/Makefile | 4 +- nss/Versions | 4 + nss/nss_db/db-init.c | 54 +++++++++++++ nss/nss_files/files-init.c | 72 +++++++++++++++++ nss/nsswitch.c | 165 +++++++++++++++++++++++++++++---------- nss/nsswitch.h | 8 +- sysdeps/unix/sysv/linux/Makefile | 8 +- 12 files changed, 446 insertions(+), 159 deletions(-) create mode 100644 nss/nss_db/db-init.c create mode 100644 nss/nss_files/files-init.c diff --git a/ChangeLog b/ChangeLog index 953e879f89..31902a0a3f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,45 @@ +2011-07-11 Ulrich Drepper + + * nscd/nscd.h (struct traced_file): Define. + (struct database_dyn): Remove inotify_descr, reset_res, and filename + elements. Add traced_files. + (inotify_fd): Declare. + (register_traced_file): Declare. + * nscd/connections.c (dbs): Remove reset_res and filename initializers. + (inotify_fd): Export. + (resolv_conf_descr): Remove. + (nscd_init): Move inotify descriptor creation to main. + Don't register files for notification here. + (register_traced_file): New function. + (invalidate_cache): Don't use reset_res to determine whether to call + res_init, go through the list of registered files. + (main_loop_poll): The inotify descriptors are now stored in the + structures for the traced files. + (main_loop_epoll): Likewise + * nscd/nscd.c (main): Create inotify socket here. Pass extra argument + to __nss_disable_nscd. + * nscd/cache.c (prune_cache): There is no single inotify descriptor + for a database anymore. Check the records for all the registered + files instead. + * nss/Makefile (libnss_files-routines): Add files-init. + (libnss_db-routines): Add db-init. + * nss/Versions [libnss_files] (GLIBC_PRIVATE): Add _nss_files_init. + [libnss_db] (GLIBC_PRIVATE): Add _nss_db_init. + * nss/nss_db/db-init.c: New file. + * nss/nss_files/files-init.c: New file. + * nss/nsswitch.c (nss_load_library): New function. Broken out of + __nss_lookup_function. + (__nss_lookup_function): Call nss_load_library. + (nss_load_all_libraries): New function. + (__nss_disable_nscd): Take parameter with callback function for files + to register. Set is_nscd. Load all the DSOs for the NSS modules + used for the cached services. + * nss/nsswitch.h (__nss_disable_nscd): Adjust prototype. + * sysdeps/unix/sysv/linux/Makefile [subdir=nscd]: Pass the various -D + options for features to all the files in nscd. + + * nss/nsswitch.c (nss_parse_file): Add missing fclose. + 2011-07-10 Roland McGrath * csu/elf-init.c (__libc_csu_init): Comment typo. diff --git a/nscd/cache.c b/nscd/cache.c index ebc6e4c0d6..58f0bcc5f1 100644 --- a/nscd/cache.c +++ b/nscd/cache.c @@ -264,28 +264,40 @@ prune_cache (struct database_dyn *table, time_t now, int fd) /* If we check for the modification of the underlying file we invalidate the entries also in this case. */ - if (table->inotify_descr < 0 && table->check_file && now != LONG_MAX) + if (table->check_file && now != LONG_MAX) { - struct stat64 st; + struct traced_file *runp = table->traced_files; - if (stat64 (table->filename, &st) < 0) + while (runp != NULL) { - char buf[128]; - /* We cannot stat() the file, disable file checking if the - file does not exist. */ - dbg_log (_("cannot stat() file `%s': %s"), - table->filename, strerror_r (errno, buf, sizeof (buf))); - if (errno == ENOENT) - table->check_file = 0; - } - else - { - if (st.st_mtime != table->file_mtime) +#ifdef HAVE_INOTIFY + if (runp->inotify_descr == -1) +#endif { - /* The file changed. Invalidate all entries. */ - now = LONG_MAX; - table->file_mtime = st.st_mtime; + struct stat64 st; + + if (stat64 (runp->fname, &st) < 0) + { + char buf[128]; + /* We cannot stat() the file, disable file checking if the + file does not exist. */ + dbg_log (_("cannot stat() file `%s': %s"), + runp->fname, strerror_r (errno, buf, sizeof (buf))); + if (errno == ENOENT) + table->check_file = 0; + } + else + { + if (st.st_mtime != table->file_mtime) + { + /* The file changed. Invalidate all entries. */ + now = LONG_MAX; + table->file_mtime = st.st_mtime; + } + } } + + runp = runp->next; } } diff --git a/nscd/connections.c b/nscd/connections.c index 1e47931bd2..6e48869c68 100644 --- a/nscd/connections.c +++ b/nscd/connections.c @@ -117,8 +117,6 @@ struct database_dyn dbs[lastdb] = .shared = 0, .max_db_size = DEFAULT_MAX_DB_SIZE, .suggested_module = DEFAULT_SUGGESTED_MODULE, - .reset_res = 0, - .filename = "/etc/passwd", .db_filename = _PATH_NSCD_PASSWD_DB, .disabled_iov = &pwd_iov_disabled, .postimeout = 3600, @@ -138,8 +136,6 @@ struct database_dyn dbs[lastdb] = .shared = 0, .max_db_size = DEFAULT_MAX_DB_SIZE, .suggested_module = DEFAULT_SUGGESTED_MODULE, - .reset_res = 0, - .filename = "/etc/group", .db_filename = _PATH_NSCD_GROUP_DB, .disabled_iov = &grp_iov_disabled, .postimeout = 3600, @@ -159,8 +155,6 @@ struct database_dyn dbs[lastdb] = .shared = 0, .max_db_size = DEFAULT_MAX_DB_SIZE, .suggested_module = DEFAULT_SUGGESTED_MODULE, - .reset_res = 1, - .filename = "/etc/hosts", .db_filename = _PATH_NSCD_HOSTS_DB, .disabled_iov = &hst_iov_disabled, .postimeout = 3600, @@ -180,8 +174,6 @@ struct database_dyn dbs[lastdb] = .shared = 0, .max_db_size = DEFAULT_MAX_DB_SIZE, .suggested_module = DEFAULT_SUGGESTED_MODULE, - .reset_res = 0, - .filename = "/etc/services", .db_filename = _PATH_NSCD_SERVICES_DB, .disabled_iov = &serv_iov_disabled, .postimeout = 28800, @@ -232,10 +224,7 @@ static int sock; #ifdef HAVE_INOTIFY /* Inotify descriptor. */ -static int inotify_fd = -1; - -/* Watch descriptor for resolver configuration file. */ -static int resolv_conf_descr = -1; +int inotify_fd = -1; #endif #ifndef __ASSUME_SOCK_CLOEXEC @@ -523,19 +512,6 @@ nscd_init (void) /* No configuration for this value, assume a default. */ nthreads = 4; -#ifdef HAVE_INOTIFY - /* Use inotify to recognize changed files. */ - inotify_fd = inotify_init1 (IN_NONBLOCK); -# ifndef __ASSUME_IN_NONBLOCK - if (inotify_fd == -1 && errno == ENOSYS) - { - inotify_fd = inotify_init (); - if (inotify_fd != -1) - fcntl (inotify_fd, F_SETFL, O_RDONLY | O_NONBLOCK); - } -# endif -#endif - for (size_t cnt = 0; cnt < lastdb; ++cnt) if (dbs[cnt].enabled) { @@ -840,40 +816,6 @@ cannot set socket to close on exec: %s; disabling paranoia mode"), dbs[cnt].shared = 0; assert (dbs[cnt].ro_fd == -1); } - - dbs[cnt].inotify_descr = -1; - if (dbs[cnt].check_file) - { -#ifdef HAVE_INOTIFY - if (inotify_fd < 0 - || (dbs[cnt].inotify_descr - = inotify_add_watch (inotify_fd, dbs[cnt].filename, - IN_DELETE_SELF | IN_MODIFY)) < 0) - /* We cannot notice changes in the main thread. */ -#endif - { - /* We need the modification date of the file. */ - struct stat64 st; - - if (stat64 (dbs[cnt].filename, &st) < 0) - { - /* We cannot stat() the file, disable file checking. */ - dbg_log (_("cannot stat() file `%s': %s"), - dbs[cnt].filename, strerror (errno)); - dbs[cnt].check_file = 0; - } - else - dbs[cnt].file_mtime = st.st_mtime; - } - } - -#ifdef HAVE_INOTIFY - if (cnt == hstdb && inotify_fd >= -1) - /* We also monitor the resolver configuration file. */ - resolv_conf_descr = inotify_add_watch (inotify_fd, - _PATH_RESCONF, - IN_DELETE_SELF | IN_MODIFY); -#endif } /* Create the socket. */ @@ -940,12 +882,50 @@ cannot set socket to close on exec: %s; disabling paranoia mode"), exit (1); } - /* Change to unprivileged uid/gid/groups if specifed in config file */ + /* Change to unprivileged uid/gid/groups if specified in config file */ if (server_user != NULL) finish_drop_privileges (); } +void +register_traced_file (size_t dbidx, struct traced_file *finfo) +{ + if (! dbs[dbidx].check_file) + return; + + if (__builtin_expect (debug_level > 0, 0)) + dbg_log (_("register trace file %s for database %s"), + finfo->fname, dbnames[dbidx]); + +#ifdef HAVE_INOTIFY + if (inotify_fd < 0 + || (finfo->inotify_descr = inotify_add_watch (inotify_fd, finfo->fname, + IN_DELETE_SELF + | IN_MODIFY)) < 0) +#endif + { + /* We need the modification date of the file. */ + struct stat64 st; + + if (stat64 (finfo->fname, &st) < 0) + { + /* We cannot stat() the file, disable file checking. */ + dbg_log (_("cannot stat() file `%s': %s"), + finfo->fname, strerror (errno)); + return; + } + + finfo->inotify_descr = -1; + finfo->mtime = st.st_mtime; + } + + /* Queue up the file name. */ + finfo->next = dbs[dbidx].traced_files; + dbs[dbidx].traced_files = finfo; +} + + /* Close the connections. */ void close_sockets (void) @@ -963,11 +943,20 @@ invalidate_cache (char *key, int fd) for (number = pwddb; number < lastdb; ++number) if (strcmp (key, dbnames[number]) == 0) { - if (dbs[number].reset_res) - res_init (); - + if (number == hstdb) + { + struct traced_file *runp = dbs[hstdb].traced_files; + while (runp != NULL) + if (runp->call_res_init) + { + res_init (); + break; + } + else + runp = runp->next; + } break; - } + } if (number == lastdb) { @@ -1913,16 +1902,21 @@ disabled inotify after read error %d"), /* Check which of the files changed. */ for (size_t dbcnt = 0; dbcnt < lastdb; ++dbcnt) - if (inev.i.wd == dbs[dbcnt].inotify_descr) - { - to_clear[dbcnt] = true; - goto next; - } - - if (inev.i.wd == resolv_conf_descr) { - res_init (); - to_clear[hstdb] = true; + struct traced_file *finfo = dbs[dbcnt].traced_files; + + while (finfo != NULL) + { + if (finfo->inotify_descr == inev.i.wd) + { + to_clear[dbcnt] = true; + if (finfo->call_res_init) + res_init (); + goto next; + } + + finfo = finfo->next; + } } next:; } @@ -2089,7 +2083,7 @@ main_loop_epoll (int efd) while (1) { ssize_t nb = TEMP_FAILURE_RETRY (read (inotify_fd, &inev, - sizeof (inev))); + sizeof (inev))); if (nb < (ssize_t) sizeof (struct inotify_event)) { if (__builtin_expect (nb == -1 && errno != EAGAIN, 0)) @@ -2108,16 +2102,21 @@ main_loop_epoll (int efd) /* Check which of the files changed. */ for (size_t dbcnt = 0; dbcnt < lastdb; ++dbcnt) - if (inev.i.wd == dbs[dbcnt].inotify_descr) - { - to_clear[dbcnt] = true; - goto next; - } - - if (inev.i.wd == resolv_conf_descr) { - res_init (); - to_clear[hstdb] = true; + struct traced_file *finfo = dbs[dbcnt].traced_files; + + while (finfo != NULL) + { + if (finfo->inotify_descr == inev.i.wd) + { + to_clear[dbcnt] = true; + if (finfo->call_res_init) + res_init (); + goto next; + } + + finfo = finfo->next; + } } next:; } diff --git a/nscd/nscd.c b/nscd/nscd.c index c3d9fe6cef..4894cb2faa 100644 --- a/nscd/nscd.c +++ b/nscd/nscd.c @@ -46,6 +46,9 @@ #include "selinux.h" #include "../nss/nsswitch.h" #include +#ifdef HAVE_INOTIFY +# include +#endif /* Get libc version number. */ #include @@ -272,8 +275,21 @@ main (int argc, char **argv) /* Cleanup files created by a previous 'bind'. */ unlink (_PATH_NSCDSOCKET); +#ifdef HAVE_INOTIFY + /* Use inotify to recognize changed files. */ + inotify_fd = inotify_init1 (IN_NONBLOCK); +# ifndef __ASSUME_IN_NONBLOCK + if (inotify_fd == -1 && errno == ENOSYS) + { + inotify_fd = inotify_init (); + if (inotify_fd != -1) + fcntl (inotify_fd, F_SETFL, O_RDONLY | O_NONBLOCK); + } +# endif +#endif + /* Make sure we do not get recursive calls. */ - __nss_disable_nscd (); + __nss_disable_nscd (register_traced_file); /* Init databases. */ nscd_init (); diff --git a/nscd/nscd.h b/nscd/nscd.h index 5e3c865a29..c15e88bb6f 100644 --- a/nscd/nscd.h +++ b/nscd/nscd.h @@ -62,6 +62,17 @@ typedef enum #define MAX_STACK_USE ((8 * NSCD_THREAD_STACKSIZE) / 10) +/* Registered filename used to fill database. */ +struct traced_file +{ + time_t mtime; + struct traced_file *next; + int call_res_init; + int inotify_descr; + char fname[]; +}; + + /* Structure describing dynamic part of one database. */ struct database_dyn { @@ -73,13 +84,11 @@ struct database_dyn int enabled; int check_file; - int inotify_descr; int clear_cache; int persistent; int shared; int propagate; - int reset_res; - const char filename[16]; + struct traced_file *traced_files; const char *db_filename; time_t file_mtime; size_t suggested_module; @@ -147,6 +156,9 @@ extern int nthreads; /* Maximum number of threads to use. */ extern int max_nthreads; +/* Inotify descriptor. */ +extern int inotify_fd; + /* User name to run server processes as. */ extern const char *server_user; @@ -191,6 +203,7 @@ extern int nscd_open_socket (void); /* connections.c */ extern void nscd_init (void); +extern void register_traced_file (size_t dbidx, struct traced_file *finfo); extern void close_sockets (void); extern void start_threads (void) __attribute__ ((__noreturn__)); diff --git a/nss/Makefile b/nss/Makefile index 60c65492ff..fb6428345b 100644 --- a/nss/Makefile +++ b/nss/Makefile @@ -66,14 +66,14 @@ vpath %.c $(subdir-dirs) ../locale/programs ../intl libnss_files-routines := $(addprefix files-,$(databases)) \ - files-initgroups files-have_o_cloexec + files-initgroups files-have_o_cloexec files-init distribute += files-XXX.c files-parse.c libnss_db-dbs := $(addprefix db-,\ $(filter-out hosts network key alias,\ $(databases))) \ db-initgroups -libnss_db-routines := $(libnss_db-dbs) db-open hash-string +libnss_db-routines := $(libnss_db-dbs) db-open db-init hash-string generated += $(filter-out db-alias.c db-netgrp.c, \ $(addsuffix .c,$(libnss_db-dbs))) distribute += $(addprefix nss_db/, db-XXX.c nss_db.h) diff --git a/nss/Versions b/nss/Versions index 913751217f..666915d6bf 100644 --- a/nss/Versions +++ b/nss/Versions @@ -97,6 +97,8 @@ libnss_files { _nss_files_getsecretkey; _nss_files_initgroups_dyn; + + _nss_files_init; } } @@ -153,5 +155,7 @@ libnss_db { _nss_db_getspnam_r; _nss_db_initgroups_dyn; + + _nss_db_init; } } diff --git a/nss/nss_db/db-init.c b/nss/nss_db/db-init.c new file mode 100644 index 0000000000..8228d61f57 --- /dev/null +++ b/nss/nss_db/db-init.c @@ -0,0 +1,54 @@ +/* Initialization in nss_db module. + Copyright (C) 2011 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. */ + +#include +#include + + +static union +{ + struct traced_file file; + char buf[sizeof (struct traced_file) + sizeof (_PATH_VARDB "passwd.db")]; +} pwd_traced_file; + +static union +{ + struct traced_file file; + char buf[sizeof (struct traced_file) + sizeof (_PATH_VARDB "group.db")]; +} grp_traced_file; + +static union +{ + struct traced_file file; + char buf[sizeof (struct traced_file) + sizeof (_PATH_VARDB "services.db")]; +} serv_traced_file; + + +void +_nss_db_init (void (*cb) (size_t, struct traced_file *)) +{ + strcpy (pwd_traced_file.file.fname,_PATH_VARDB "passwd.db"); + cb (pwddb, &pwd_traced_file.file); + + strcpy (grp_traced_file.file.fname, _PATH_VARDB "group.db"); + cb (grpdb, &grp_traced_file.file); + + strcpy (serv_traced_file.file.fname, _PATH_VARDB "services.db"); + cb (servdb, &serv_traced_file.file); +} diff --git a/nss/nss_files/files-init.c b/nss/nss_files/files-init.c new file mode 100644 index 0000000000..cc6822d305 --- /dev/null +++ b/nss/nss_files/files-init.c @@ -0,0 +1,72 @@ +/* Initialization in nss_files module. + Copyright (C) 2011 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. */ + +#include + + +static union +{ + struct traced_file file; + char buf[sizeof (struct traced_file) + sizeof ("/etc/passwd")]; +} pwd_traced_file; + +static union +{ + struct traced_file file; + char buf[sizeof (struct traced_file) + sizeof ("/etc/group")]; +} grp_traced_file; + +static union +{ + struct traced_file file; + char buf[sizeof (struct traced_file) + sizeof ("/etc/hosts")]; +} hst_traced_file; + +static union +{ + struct traced_file file; + char buf[sizeof (struct traced_file) + sizeof ("/etc/resolv.conf")]; +} resolv_traced_file; + +static union +{ + struct traced_file file; + char buf[sizeof (struct traced_file) + sizeof ("/etc/services")]; +} serv_traced_file; + + +void +_nss_files_init (void (*cb) (size_t, struct traced_file *)) +{ + strcpy (pwd_traced_file.file.fname, "/etc/passwd"); + cb (pwddb, &pwd_traced_file.file); + + strcpy (grp_traced_file.file.fname, "/etc/group"); + cb (grpdb, &grp_traced_file.file); + + strcpy (hst_traced_file.file.fname, "/etc/hosts"); + cb (hstdb, &hst_traced_file.file); + + resolv_traced_file.file.call_res_init = 1; + strcpy (resolv_traced_file.file.fname, "/etc/resolv.conf"); + cb (hstdb, &resolv_traced_file.file); + + strcpy (serv_traced_file.file.fname, "/etc/services"); + cb (servdb, &serv_traced_file.file); +} diff --git a/nss/nsswitch.c b/nss/nsswitch.c index 92e6f5f91f..6c15c3a83f 100644 --- a/nss/nsswitch.c +++ b/nss/nsswitch.c @@ -1,4 +1,5 @@ -/* Copyright (C) 1996-1999,2001-2007,2009,2010 Free Software Foundation, Inc. +/* Copyright (C) 1996-1999,2001-2007,2009,2010,2011 + Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Ulrich Drepper , 1996. @@ -40,6 +41,7 @@ #include "nsswitch.h" #include "../nscd/nscd_proto.h" +#include /* Prototypes for the local functions. */ static name_database *nss_parse_file (const char *fname) internal_function; @@ -86,6 +88,12 @@ static const char *const __nss_shlib_revision = LIBNSS_FILES_SO + 15; static name_database *service_table; +/* Nonzero if this is the nscd process. */ +static bool is_nscd; +/* The callback passed to the init functions when nscd is used. */ +static void (*nscd_init_cb) (size_t, struct traced_file *); + + /* -1 == database not found 0 == database entry pointer stored */ int @@ -129,7 +137,7 @@ __nss_database_lookup (const char *database, const char *alternate_name, } /* No configuration data is available, either because nsswitch.conf - doesn't exist or because it doesn't has a line for this database. + doesn't exist or because it doesn't have a line for this database. DEFCONFIG specifies the default service list for this database, or null to use the most common default. */ @@ -285,6 +293,79 @@ known_compare (const void *p1, const void *p2) } +#if !defined DO_STATIC_NSS || defined SHARED +/* Load library. */ +static int +nss_load_library (service_user *ni) +{ + if (ni->library == NULL) + { + /* This service has not yet been used. Fetch the service + library for it, creating a new one if need be. If there + is no service table from the file, this static variable + holds the head of the service_library list made from the + default configuration. */ + static name_database default_table; + ni->library = nss_new_service (service_table ?: &default_table, + ni->name); + if (ni->library == NULL) + return -1; + } + + if (ni->library->lib_handle == NULL) + { + /* Load the shared library. */ + size_t shlen = (7 + strlen (ni->library->name) + 3 + + strlen (__nss_shlib_revision) + 1); + int saved_errno = errno; + char shlib_name[shlen]; + + /* Construct shared object name. */ + __stpcpy (__stpcpy (__stpcpy (__stpcpy (shlib_name, + "libnss_"), + ni->library->name), + ".so"), + __nss_shlib_revision); + + ni->library->lib_handle = __libc_dlopen (shlib_name); + if (ni->library->lib_handle == NULL) + { + /* Failed to load the library. */ + ni->library->lib_handle = (void *) -1l; + __set_errno (saved_errno); + } + else if (is_nscd) + { + /* Call the init function when nscd is used. */ + size_t initlen = (5 + strlen (ni->library->name) + + strlen ("_init") + 1); + char init_name[initlen]; + + /* Construct the init function name. */ + __stpcpy (__stpcpy (__stpcpy (init_name, + "_nss_"), + ni->library->name), + "_init"); + + /* Find the optional init function. */ + void (*ifct) (void (*) (size_t, struct traced_file *)) + = __libc_dlsym (ni->library->lib_handle, init_name); + if (ifct != NULL) + { + void (*cb) (size_t, struct traced_file *) = nscd_init_cb; +# ifdef PTR_DEMANGLE + PTR_DEMANGLE (cb); +# endif + ifct (cb); + } + } + } + + return 0; +} +#endif + + void * __nss_lookup_function (service_user *ni, const char *fct_name) { @@ -331,47 +412,13 @@ __nss_lookup_function (service_user *ni, const char *fct_name) *found = known; known->fct_name = fct_name; - if (ni->library == NULL) - { - /* This service has not yet been used. Fetch the service - library for it, creating a new one if need be. If there - is no service table from the file, this static variable - holds the head of the service_library list made from the - default configuration. */ - static name_database default_table; - ni->library = nss_new_service (service_table ?: &default_table, - ni->name); - if (ni->library == NULL) - { - /* This only happens when out of memory. */ - free (known); - goto remove_from_tree; - } - } - #if !defined DO_STATIC_NSS || defined SHARED - if (ni->library->lib_handle == NULL) + /* Load the appropriate library. */ + if (nss_load_library (ni) != 0) { - /* Load the shared library. */ - size_t shlen = (7 + strlen (ni->library->name) + 3 - + strlen (__nss_shlib_revision) + 1); - int saved_errno = errno; - char shlib_name[shlen]; - - /* Construct shared object name. */ - __stpcpy (__stpcpy (__stpcpy (__stpcpy (shlib_name, - "libnss_"), - ni->library->name), - ".so"), - __nss_shlib_revision); - - ni->library->lib_handle = __libc_dlopen (shlib_name); - if (ni->library->lib_handle == NULL) - { - /* Failed to load the library. */ - ni->library->lib_handle = (void *) -1l; - __set_errno (saved_errno); - } + /* This only happens when out of memory. */ + free (known); + goto remove_from_tree; } if (ni->library->lib_handle == (void *) -1l) @@ -463,7 +510,10 @@ nss_parse_file (const char *fname) result = (name_database *) malloc (sizeof (name_database)); if (result == NULL) - return NULL; + { + fclose (fp); + return NULL; + } result->entry = NULL; result->library = NULL; @@ -724,16 +774,45 @@ nss_new_service (name_database *database, const char *name) } +#ifdef SHARED +/* Load all libraries for the service. */ +static void +nss_load_all_libraries (const char *service, const char *def) +{ + service_user *ni = NULL; + + if (__nss_database_lookup (service, NULL, def, &ni) == 0) + while (ni != NULL) + { + nss_load_library (ni); + ni = ni->next; + } +} + + /* Called by nscd and nscd alone. */ void -__nss_disable_nscd (void) +__nss_disable_nscd (void (*cb) (size_t, struct traced_file *)) { +# ifdef PTR_MANGLE + PTR_MANGLE (cb); +# endif + nscd_init_cb = cb; + is_nscd = true; + + /* Find all the relevant modules so that the init functions are called. */ + nss_load_all_libraries ("passwd", "compat [NOTFOUND=return] files"); + nss_load_all_libraries ("group", "compat [NOTFOUND=return] files"); + nss_load_all_libraries ("hosts", "dns [!UNAVAIL=return] files"); + nss_load_all_libraries ("services", NULL); + /* Disable all uses of NSCD. */ __nss_not_use_nscd_passwd = -1; __nss_not_use_nscd_group = -1; __nss_not_use_nscd_hosts = -1; __nss_not_use_nscd_services = -1; } +#endif /* Free all resources if necessary. */ diff --git a/nss/nsswitch.h b/nss/nsswitch.h index ae5657e889..3e37bc8bd8 100644 --- a/nss/nsswitch.h +++ b/nss/nsswitch.h @@ -1,4 +1,4 @@ -/* Copyright (C) 1996-1999,2001,2002,2003,2004,2007,2010 +/* Copyright (C) 1996-1999,2001,2002,2003,2004,2007,2010,2011 Free Software Foundation, Inc. This file is part of the GNU C Library. @@ -153,8 +153,10 @@ extern void *__nss_lookup_function (service_user *ni, const char *fct_name); libc_hidden_proto (__nss_lookup_function) -/* Called by NSCD to disable recursive calls. */ -extern void __nss_disable_nscd (void); +/* Called by NSCD to disable recursive calls and enable special handling + when used in nscd. */ +struct traced_file; +extern void __nss_disable_nscd (void (*) (size_t, struct traced_file *)); typedef int (*db_lookup_function) (service_user **, const char *, const char *, diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile index f626a22579..63ef597461 100644 --- a/sysdeps/unix/sysv/linux/Makefile +++ b/sysdeps/unix/sysv/linux/Makefile @@ -161,12 +161,6 @@ CFLAGS-mq_receive.c += -fexceptions endif ifeq ($(subdir),nscd) -CFLAGS-connections.c += -DHAVE_EPOLL -DHAVE_SENDFILE -DHAVE_INOTIFY -CFLAGS-pwdcache.c += -DHAVE_SENDFILE -CFLAGS-grpcache.c += -DHAVE_SENDFILE -CFLAGS-hstcache.c += -DHAVE_SENDFILE -CFLAGS-aicache.c += -DHAVE_SENDFILE -CFLAGS-initgrcache.c += -DHAVE_SENDFILE -CFLAGS-servicescache.c += -DHAVE_SENDFILE +sysdep-CFLAGS += -DHAVE_EPOLL -DHAVE_SENDFILE -DHAVE_INOTIFY CFLAGS-gai.c += -DNEED_NETLINK endif -- cgit v1.2.3