diff options
author | Florian Weimer <fweimer@redhat.com> | 2020-02-20 09:32:27 +0100 |
---|---|---|
committer | DJ Delorie <dj@redhat.com> | 2020-12-04 17:15:29 -0500 |
commit | fd5b9b4458ef662d1955459e22a11b15d16a5648 (patch) | |
tree | b550ba60f5c2591aa76929a2688ff645ef850d39 /nss/nss_action.c | |
parent | 171689dac7fcb979e7d3ffbd307eacae3c07c2d3 (diff) | |
download | glibc-fd5b9b4458ef662d1955459e22a11b15d16a5648.tar.gz glibc-fd5b9b4458ef662d1955459e22a11b15d16a5648.tar.xz glibc-fd5b9b4458ef662d1955459e22a11b15d16a5648.zip |
<nss_action.h>: New abstraction for combining NSS modules and NSS actions
nss_action manages a set of lists of actions; these are the portions of the lines in nsswitch.conf to the right of the colons, like "dns [!UNAVAIL=return] files". Each permutation of actions and conditionals is cached for reuse, which limits memory growth, and refers to the static list of modules managed by nss_modules. Reviewed-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
Diffstat (limited to 'nss/nss_action.c')
-rw-r--r-- | nss/nss_action.c | 116 |
1 files changed, 116 insertions, 0 deletions
diff --git a/nss/nss_action.c b/nss/nss_action.c new file mode 100644 index 0000000000..b9c3b93fea --- /dev/null +++ b/nss/nss_action.c @@ -0,0 +1,116 @@ +/* NSS actions, elements in a nsswitch.conf configuration line. + Copyright (c) 2020 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, see + <https://www.gnu.org/licenses/>. */ + +#include <nss_action.h> + +#include <string.h> +#include <libc-lock.h> + +/* Maintain a global list of NSS action lists. Since most databases + use the same list of actions, this list is usually short. + Deduplication in __nss_action_allocate ensures that the list does + not grow without bounds. */ + +struct nss_action_list_wrapper +{ + /* The next element of the list. */ + struct nss_action_list_wrapper *next; + + /* Number of elements in the list (excluding the terminator). */ + size_t count; + + /* NULL-terminated list of actions. */ + struct nss_action actions[]; +}; + +/* Toplevel list of allocated NSS action lists. */ +static struct nss_action_list_wrapper *nss_actions; + +/* Lock covers the nss_actions list. */ +__libc_lock_define (static, nss_actions_lock); + +/* Returns true if the actions are equal (same module, same actions + array). */ +static bool +actions_equal (const struct nss_action *a, const struct nss_action *b) +{ + return a->module == b->module && a->action_bits == b->action_bits; +} + + +/* Returns true if COUNT actions at A and B are equal (according to + actions_equal above). Caller must ensure that either A or B have at + least COUNT actions. */ +static bool +action_lists_equal (const struct nss_action *a, const struct nss_action *b, + size_t count) +{ + for (size_t i = 0; i < count; ++i) + if (!actions_equal (a + i, b + i)) + return false; + return true; +} + +/* Returns a pre-allocated action list for COUNT actions at ACTIONS, + or NULL if no such list exists. */ +static nss_action_list +find_allocated (struct nss_action *actions, size_t count) +{ + for (struct nss_action_list_wrapper *p = nss_actions; p != NULL; p = p->next) + if (p->count == count && action_lists_equal (p->actions, actions, count)) + return p->actions; + return NULL; +} + +nss_action_list +__nss_action_allocate (struct nss_action *actions, size_t count) +{ + nss_action_list result = NULL; + __libc_lock_lock (nss_actions_lock); + + result = find_allocated (actions, count); + if (result == NULL) + { + struct nss_action_list_wrapper *wrapper + = malloc (sizeof (*wrapper) + sizeof (*actions) * count); + if (wrapper != NULL) + { + wrapper->next = nss_actions; + wrapper->count = count; + memcpy (wrapper->actions, actions, sizeof (*actions) * count); + nss_actions = wrapper; + result = wrapper->actions; + } + } + + __libc_lock_unlock (nss_actions_lock); + return result; +} + +void __libc_freeres_fn_section +__nss_action_freeres (void) +{ + struct nss_action_list_wrapper *current = nss_actions; + while (current != NULL) + { + struct nss_action_list_wrapper *next = current->next; + free (current); + current = next; + } + nss_actions = NULL; +} |