> Date: Tue, 4 Jul 2023 18:30:58 +0000 > From: Taylor R Campbell <campbell+netbsd-tech-userle...@mumble.net> > > Other low-hanging fruit I see would be to split getenv out of the > other environment variable operations, to get rid of locking and > rbtree stuff. But it's diminishing returns at this point -- not clear > the attached patchset/diff is worth committing. Gets me down to this: > > text data bss dec hex filename > 30744 3280 3376 37400 9218 main > > After that, maybe we could find a substitute for the syslog_ss stuff > in stack-protector -- but that's probably not worth the trouble, for > what is maybe another few kilobytes or so.
...actually attached
>From 14201a18296b67e2e254566ce0c5f3106c0b3e67 Mon Sep 17 00:00:00 2001 From: Taylor R Campbell <riastr...@netbsd.org> Date: Tue, 4 Jul 2023 18:16:08 +0000 Subject: [PATCH 1/3] rbtree(3): New RB_TREE_INITIALIZER macro. Allows static initialization of an rbtree. XXX pullup-10 --- sys/sys/rbtree.h | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/sys/sys/rbtree.h b/sys/sys/rbtree.h index b4a8ba3f7fc1..686cf2ed299a 100644 --- a/sys/sys/rbtree.h +++ b/sys/sys/rbtree.h @@ -125,12 +125,17 @@ TAILQ_HEAD(rb_node_qh, rb_node); #define RB_TAILQ_INSERT_HEAD(a, b, c) TAILQ_INSERT_HEAD(a, b, c) #define RB_TAILQ_INSERT_BEFORE(a, b, c) TAILQ_INSERT_BEFORE(a, b, c) #define RB_TAILQ_INSERT_AFTER(a, b, c, d) TAILQ_INSERT_AFTER(a, b, c, d) + +#define RBDEBUG_TREE_INITIALIZER(t) \ + .rbt_nodes = TAILQ_INITIALIZER((t).rbt_nodes), #else #define RB_TAILQ_REMOVE(a, b, c) do { } while (/*CONSTCOND*/0) #define RB_TAILQ_INIT(a) do { } while (/*CONSTCOND*/0) #define RB_TAILQ_INSERT_HEAD(a, b, c) do { } while (/*CONSTCOND*/0) #define RB_TAILQ_INSERT_BEFORE(a, b, c) do { } while (/*CONSTCOND*/0) #define RB_TAILQ_INSERT_AFTER(a, b, c, d) do { } while (/*CONSTCOND*/0) + +#define RBDEBUG_TREE_INITIALIZER(t) /* nothing */ #endif /* RBDEBUG */ /* @@ -181,6 +186,12 @@ typedef struct rb_tree { #define RBSTAT_DEC(v) do { } while (/*CONSTCOND*/0) #endif +#define RB_TREE_INITIALIZER(t, ops) (rb_tree_t) \ +{ \ + .rbt_ops = (ops), \ + RBDEBUG_TREE_INITIALIZER(t) \ +} + void rb_tree_init(rb_tree_t *, const rb_tree_ops_t *); void * rb_tree_insert_node(rb_tree_t *, void *); void * rb_tree_find_node(rb_tree_t *, const void *); >From ef18c568cb559da7e82e7951050cf7cd54b0a350 Mon Sep 17 00:00:00 2001 From: Taylor R Campbell <riastr...@netbsd.org> Date: Tue, 4 Jul 2023 18:17:23 +0000 Subject: [PATCH 2/3] libc: Use RB_TREE_INITIALIZER to nix initfini.c/_env.c coupling. XXX pullup-10 --- lib/libc/misc/initfini.c | 3 --- lib/libc/stdlib/_env.c | 10 ++-------- 2 files changed, 2 insertions(+), 11 deletions(-) diff --git a/lib/libc/misc/initfini.c b/lib/libc/misc/initfini.c index 9f5cec1d2cce..6d17c167c71e 100644 --- a/lib/libc/misc/initfini.c +++ b/lib/libc/misc/initfini.c @@ -132,7 +132,4 @@ _libc_init(void) /* Initialize the atexit mutexes */ __libc_atexit_init(); - - /* Initialize environment memory RB tree. */ - __libc_env_init(); } diff --git a/lib/libc/stdlib/_env.c b/lib/libc/stdlib/_env.c index 6608522790f8..316459356bf7 100644 --- a/lib/libc/stdlib/_env.c +++ b/lib/libc/stdlib/_env.c @@ -73,7 +73,8 @@ static const rb_tree_ops_t env_tree_ops = { }; /* The single instance of above tree. */ -static rb_tree_t env_tree; +static rb_tree_t env_tree = + RB_TREE_INITIALIZER(env_tree, &env_tree_ops); /* The allocated environment. */ static char **allocated_environ; @@ -401,10 +402,3 @@ __unlockenv(void) } #endif - -/* Initialize environment memory RB tree. */ -void __section(".text.startup") -__libc_env_init(void) -{ - rb_tree_init(&env_tree, &env_tree_ops); -} >From 1d295afec1bd9645c672d8702ce6ee7ad5c32304 Mon Sep 17 00:00:00 2001 From: Taylor R Campbell <riastr...@netbsd.org> Date: Tue, 4 Jul 2023 17:26:18 +0000 Subject: [PATCH 3/3] WIP: libc: Split read-only environment logic into a separate unit. The idea is to prune all the locking, rb, allocation, &c., from statically linked programs that just call getenv. Still WIP because I can't figure out how to make statically linked read-only access elide the locking. XXX pullup-10 (if we work out the issues) --- lib/libc/stdlib/Makefile.inc | 2 +- lib/libc/stdlib/_env.c | 107 ++-------------------------------- lib/libc/stdlib/_envlock.c | 90 +++++++++++++++++++++++++++++ lib/libc/stdlib/_findenv.c | 108 +++++++++++++++++++++++++++++++++++ lib/libc/stdlib/local.h | 2 + 5 files changed, 207 insertions(+), 102 deletions(-) create mode 100644 lib/libc/stdlib/_envlock.c create mode 100644 lib/libc/stdlib/_findenv.c diff --git a/lib/libc/stdlib/Makefile.inc b/lib/libc/stdlib/Makefile.inc index fcc13020a7e6..6b33e66abab5 100644 --- a/lib/libc/stdlib/Makefile.inc +++ b/lib/libc/stdlib/Makefile.inc @@ -4,7 +4,7 @@ # stdlib sources .PATH: ${ARCHDIR}/stdlib ${.CURDIR}/stdlib -SRCS+= _env.c _rand48.c \ +SRCS+= _env.c _envlock.c _findenv.c _rand48.c \ a64l.c abort.c atexit.c atof.c atoi.c atol.c atoll.c \ bsearch.c cxa_thread_atexit.c drand48.c exit.c \ getenv.c getopt.c getopt_long.c getsubopt.c \ diff --git a/lib/libc/stdlib/_env.c b/lib/libc/stdlib/_env.c index 316459356bf7..c4576a6901c6 100644 --- a/lib/libc/stdlib/_env.c +++ b/lib/libc/stdlib/_env.c @@ -82,11 +82,6 @@ static size_t allocated_environ_size; #define ENV_ARRAY_SIZE_MIN 16 -/* The lock protecting access to the environment. */ -#ifdef _REENTRANT -static rwlock_t env_lock = RWLOCK_INITIALIZER; -#endif - /* Compatibility function. */ char *__findenv(const char *name, int *offsetp); @@ -121,33 +116,6 @@ env_tree_compare_key(void *ctx, const void *node, const void *key) (const uint8_t *)key - offsetof(env_node_t, data)); } -/* - * Determine the of the name in an environment string. Return 0 if the - * name is not valid. - */ -size_t -__envvarnamelen(const char *str, bool withequal) -{ - size_t l_name; - - if (str == NULL) - return 0; - - l_name = strcspn(str, "="); - if (l_name == 0) - return 0; - - if (withequal) { - if (str[l_name] != '=') - return 0; - } else { - if (str[l_name] == '=') - return 0; - } - - return l_name; -} - /* * Free memory occupied by environment variable if possible. This function * must be called with the environment write locked. @@ -247,26 +215,19 @@ __scrubenv(void) /* * Get a (new) slot in the environment. This function must be called with - * the environment write locked. + * the environment locked, with a write-lock if allocate=true. */ ssize_t __getenvslot(const char *name, size_t l_name, bool allocate) { - size_t new_size, num_entries, required_size; + ssize_t num_entries; + size_t new_size, required_size; char **new_environ; /* Search for an existing environment variable of the given name. */ - num_entries = 0; - if (environ != NULL) { - while (environ[num_entries] != NULL) { - if (strncmp(environ[num_entries], name, l_name) == 0 && - environ[num_entries][l_name] == '=') { - /* We found a match. */ - return num_entries; - } - num_entries ++; - } - } + num_entries = __findenvslot(name, l_name); + if (num_entries < 0) + return -1; /* No match found, return if we don't want to allocate a new slot. */ if (!allocate) @@ -328,16 +289,6 @@ __getenvslot(const char *name, size_t l_name, bool allocate) return num_entries; } -/* Find a string in the environment. */ -char * -__findenvvar(const char *name, size_t l_name) -{ - ssize_t offset; - - offset = __getenvslot(name, l_name, false); - return (offset != -1) ? environ[offset] + l_name + 1 : NULL; -} - /* Compatibility interface, do *not* call this function. */ char * __findenv(const char *name, int *offsetp) @@ -356,49 +307,3 @@ __findenv(const char *name, int *offsetp) *offsetp = (int)offset; return environ[offset] + l_name + 1; } - -#ifdef _REENTRANT - -/* Lock the environment for read. */ -bool -__readlockenv(void) -{ - int error; - - error = rwlock_rdlock(&env_lock); - if (error == 0) - return true; - - errno = error; - return false; -} - -/* Lock the environment for write. */ -bool -__writelockenv(void) -{ - int error; - - error = rwlock_wrlock(&env_lock); - if (error == 0) - return true; - - errno = error; - return false; -} - -/* Unlock the environment for write. */ -bool -__unlockenv(void) -{ - int error; - - error = rwlock_unlock(&env_lock); - if (error == 0) - return true; - - errno = error; - return false; -} - -#endif diff --git a/lib/libc/stdlib/_envlock.c b/lib/libc/stdlib/_envlock.c new file mode 100644 index 000000000000..27c596fbabd5 --- /dev/null +++ b/lib/libc/stdlib/_envlock.c @@ -0,0 +1,90 @@ +/* $NetBSD: _env.c,v 1.13 2022/03/12 17:31:39 christos Exp $ */ + +/*- + * Copyright (c) 2010 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Matthias Scheler. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +#if defined(LIBC_SCCS) && !defined(lint) +__RCSID("$NetBSD: _env.c,v 1.13 2022/03/12 17:31:39 christos Exp $"); +#endif /* LIBC_SCCS and not lint */ + +#include "env.h" +#include "local.h" +#include "namespace.h" + +#include <errno.h> + +#ifdef _REENTRANT + +/* The lock protecting access to the environment. */ +static rwlock_t env_lock = RWLOCK_INITIALIZER; + +/* Lock the environment for read. */ +bool +__readlockenv(void) +{ + int error; + + error = rwlock_rdlock(&env_lock); + if (error == 0) + return true; + + errno = error; + return false; +} + +/* Lock the environment for write. */ +bool +__writelockenv(void) +{ + int error; + + error = rwlock_wrlock(&env_lock); + if (error == 0) + return true; + + errno = error; + return false; +} + +/* Unlock the environment for write. */ +bool +__unlockenv(void) +{ + int error; + + error = rwlock_unlock(&env_lock); + if (error == 0) + return true; + + errno = error; + return false; +} + +#endif diff --git a/lib/libc/stdlib/_findenv.c b/lib/libc/stdlib/_findenv.c new file mode 100644 index 000000000000..fa2cc89cec12 --- /dev/null +++ b/lib/libc/stdlib/_findenv.c @@ -0,0 +1,108 @@ +/* $NetBSD$ */ + +/*- + * Copyright (c) 2010 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Matthias Scheler. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * _findenv.c -- subroutines for read-only access to the environment + * + * Kept in a separate compilation unit from _env.c so that statically + * linked programs using only getenv(3) can omit code for the write + * access paths and skip the runtime overhead of locking. + */ + +#include <sys/cdefs.h> +__RCSID("$NetBSD$"); + +#include "env.h" +#include "local.h" +#include "namespace.h" + +#include <limits.h> +#include <stdbool.h> +#include <stddef.h> +#include <stdint.h> +#include <string.h> + +/* + * Determine the of the name in an environment string. Return 0 if the + * name is not valid. + */ +size_t +__envvarnamelen(const char *str, bool withequal) +{ + size_t l_name; + + if (str == NULL) + return 0; + + l_name = strcspn(str, "="); + if (l_name == 0) + return 0; + + if (withequal) { + if (str[l_name] != '=') + return 0; + } else { + if (str[l_name] == '=') + return 0; + } + + return l_name; +} + +/* + * Get an existing slot in the environment. This function must be + * called with the environment locked. + */ +ssize_t +__findenvslot(const char *name, size_t l_name) +{ + ssize_t num_entries; + + for (num_entries = 0; environ[num_entries] != NULL; num_entries++) { + if (strncmp(environ[num_entries], name, l_name) == 0 && + environ[num_entries][l_name] == '=') { + return num_entries; + } + if (num_entries == SSIZE_MAX) /* paranoia */ + return -1; + } + return -1; +} + +/* Find a string in the environment. */ +char * +__findenvvar(const char *name, size_t l_name) +{ + ssize_t offset; + + offset = __findenvslot(name, l_name); + return (offset != -1) ? environ[offset] + l_name + 1 : NULL; +} diff --git a/lib/libc/stdlib/local.h b/lib/libc/stdlib/local.h index 285a9b448614..c18f80245f6e 100644 --- a/lib/libc/stdlib/local.h +++ b/lib/libc/stdlib/local.h @@ -29,6 +29,8 @@ #include <sys/types.h> #include <stdbool.h> +extern ssize_t __findenvslot(const char *, size_t); + extern size_t __envvarnamelen(const char *str, bool withequal); extern void __freeenvvar(char *envvar);
diff --git a/lib/libc/misc/initfini.c b/lib/libc/misc/initfini.c index 9f5cec1d2cce..6d17c167c71e 100644 --- a/lib/libc/misc/initfini.c +++ b/lib/libc/misc/initfini.c @@ -132,7 +132,4 @@ _libc_init(void) /* Initialize the atexit mutexes */ __libc_atexit_init(); - - /* Initialize environment memory RB tree. */ - __libc_env_init(); } diff --git a/lib/libc/stdlib/Makefile.inc b/lib/libc/stdlib/Makefile.inc index fcc13020a7e6..6b33e66abab5 100644 --- a/lib/libc/stdlib/Makefile.inc +++ b/lib/libc/stdlib/Makefile.inc @@ -4,7 +4,7 @@ # stdlib sources .PATH: ${ARCHDIR}/stdlib ${.CURDIR}/stdlib -SRCS+= _env.c _rand48.c \ +SRCS+= _env.c _envlock.c _findenv.c _rand48.c \ a64l.c abort.c atexit.c atof.c atoi.c atol.c atoll.c \ bsearch.c cxa_thread_atexit.c drand48.c exit.c \ getenv.c getopt.c getopt_long.c getsubopt.c \ diff --git a/lib/libc/stdlib/_env.c b/lib/libc/stdlib/_env.c index 6608522790f8..c4576a6901c6 100644 --- a/lib/libc/stdlib/_env.c +++ b/lib/libc/stdlib/_env.c @@ -73,7 +73,8 @@ static const rb_tree_ops_t env_tree_ops = { }; /* The single instance of above tree. */ -static rb_tree_t env_tree; +static rb_tree_t env_tree = + RB_TREE_INITIALIZER(env_tree, &env_tree_ops); /* The allocated environment. */ static char **allocated_environ; @@ -81,11 +82,6 @@ static size_t allocated_environ_size; #define ENV_ARRAY_SIZE_MIN 16 -/* The lock protecting access to the environment. */ -#ifdef _REENTRANT -static rwlock_t env_lock = RWLOCK_INITIALIZER; -#endif - /* Compatibility function. */ char *__findenv(const char *name, int *offsetp); @@ -120,33 +116,6 @@ env_tree_compare_key(void *ctx, const void *node, const void *key) (const uint8_t *)key - offsetof(env_node_t, data)); } -/* - * Determine the of the name in an environment string. Return 0 if the - * name is not valid. - */ -size_t -__envvarnamelen(const char *str, bool withequal) -{ - size_t l_name; - - if (str == NULL) - return 0; - - l_name = strcspn(str, "="); - if (l_name == 0) - return 0; - - if (withequal) { - if (str[l_name] != '=') - return 0; - } else { - if (str[l_name] == '=') - return 0; - } - - return l_name; -} - /* * Free memory occupied by environment variable if possible. This function * must be called with the environment write locked. @@ -246,26 +215,19 @@ __scrubenv(void) /* * Get a (new) slot in the environment. This function must be called with - * the environment write locked. + * the environment locked, with a write-lock if allocate=true. */ ssize_t __getenvslot(const char *name, size_t l_name, bool allocate) { - size_t new_size, num_entries, required_size; + ssize_t num_entries; + size_t new_size, required_size; char **new_environ; /* Search for an existing environment variable of the given name. */ - num_entries = 0; - if (environ != NULL) { - while (environ[num_entries] != NULL) { - if (strncmp(environ[num_entries], name, l_name) == 0 && - environ[num_entries][l_name] == '=') { - /* We found a match. */ - return num_entries; - } - num_entries ++; - } - } + num_entries = __findenvslot(name, l_name); + if (num_entries < 0) + return -1; /* No match found, return if we don't want to allocate a new slot. */ if (!allocate) @@ -327,16 +289,6 @@ __getenvslot(const char *name, size_t l_name, bool allocate) return num_entries; } -/* Find a string in the environment. */ -char * -__findenvvar(const char *name, size_t l_name) -{ - ssize_t offset; - - offset = __getenvslot(name, l_name, false); - return (offset != -1) ? environ[offset] + l_name + 1 : NULL; -} - /* Compatibility interface, do *not* call this function. */ char * __findenv(const char *name, int *offsetp) @@ -355,56 +307,3 @@ __findenv(const char *name, int *offsetp) *offsetp = (int)offset; return environ[offset] + l_name + 1; } - -#ifdef _REENTRANT - -/* Lock the environment for read. */ -bool -__readlockenv(void) -{ - int error; - - error = rwlock_rdlock(&env_lock); - if (error == 0) - return true; - - errno = error; - return false; -} - -/* Lock the environment for write. */ -bool -__writelockenv(void) -{ - int error; - - error = rwlock_wrlock(&env_lock); - if (error == 0) - return true; - - errno = error; - return false; -} - -/* Unlock the environment for write. */ -bool -__unlockenv(void) -{ - int error; - - error = rwlock_unlock(&env_lock); - if (error == 0) - return true; - - errno = error; - return false; -} - -#endif - -/* Initialize environment memory RB tree. */ -void __section(".text.startup") -__libc_env_init(void) -{ - rb_tree_init(&env_tree, &env_tree_ops); -} diff --git a/lib/libc/stdlib/_envlock.c b/lib/libc/stdlib/_envlock.c new file mode 100644 index 000000000000..27c596fbabd5 --- /dev/null +++ b/lib/libc/stdlib/_envlock.c @@ -0,0 +1,90 @@ +/* $NetBSD: _env.c,v 1.13 2022/03/12 17:31:39 christos Exp $ */ + +/*- + * Copyright (c) 2010 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Matthias Scheler. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +#if defined(LIBC_SCCS) && !defined(lint) +__RCSID("$NetBSD: _env.c,v 1.13 2022/03/12 17:31:39 christos Exp $"); +#endif /* LIBC_SCCS and not lint */ + +#include "env.h" +#include "local.h" +#include "namespace.h" + +#include <errno.h> + +#ifdef _REENTRANT + +/* The lock protecting access to the environment. */ +static rwlock_t env_lock = RWLOCK_INITIALIZER; + +/* Lock the environment for read. */ +bool +__readlockenv(void) +{ + int error; + + error = rwlock_rdlock(&env_lock); + if (error == 0) + return true; + + errno = error; + return false; +} + +/* Lock the environment for write. */ +bool +__writelockenv(void) +{ + int error; + + error = rwlock_wrlock(&env_lock); + if (error == 0) + return true; + + errno = error; + return false; +} + +/* Unlock the environment for write. */ +bool +__unlockenv(void) +{ + int error; + + error = rwlock_unlock(&env_lock); + if (error == 0) + return true; + + errno = error; + return false; +} + +#endif diff --git a/lib/libc/stdlib/_findenv.c b/lib/libc/stdlib/_findenv.c new file mode 100644 index 000000000000..fa2cc89cec12 --- /dev/null +++ b/lib/libc/stdlib/_findenv.c @@ -0,0 +1,108 @@ +/* $NetBSD$ */ + +/*- + * Copyright (c) 2010 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Matthias Scheler. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * _findenv.c -- subroutines for read-only access to the environment + * + * Kept in a separate compilation unit from _env.c so that statically + * linked programs using only getenv(3) can omit code for the write + * access paths and skip the runtime overhead of locking. + */ + +#include <sys/cdefs.h> +__RCSID("$NetBSD$"); + +#include "env.h" +#include "local.h" +#include "namespace.h" + +#include <limits.h> +#include <stdbool.h> +#include <stddef.h> +#include <stdint.h> +#include <string.h> + +/* + * Determine the of the name in an environment string. Return 0 if the + * name is not valid. + */ +size_t +__envvarnamelen(const char *str, bool withequal) +{ + size_t l_name; + + if (str == NULL) + return 0; + + l_name = strcspn(str, "="); + if (l_name == 0) + return 0; + + if (withequal) { + if (str[l_name] != '=') + return 0; + } else { + if (str[l_name] == '=') + return 0; + } + + return l_name; +} + +/* + * Get an existing slot in the environment. This function must be + * called with the environment locked. + */ +ssize_t +__findenvslot(const char *name, size_t l_name) +{ + ssize_t num_entries; + + for (num_entries = 0; environ[num_entries] != NULL; num_entries++) { + if (strncmp(environ[num_entries], name, l_name) == 0 && + environ[num_entries][l_name] == '=') { + return num_entries; + } + if (num_entries == SSIZE_MAX) /* paranoia */ + return -1; + } + return -1; +} + +/* Find a string in the environment. */ +char * +__findenvvar(const char *name, size_t l_name) +{ + ssize_t offset; + + offset = __findenvslot(name, l_name); + return (offset != -1) ? environ[offset] + l_name + 1 : NULL; +} diff --git a/lib/libc/stdlib/local.h b/lib/libc/stdlib/local.h index 285a9b448614..c18f80245f6e 100644 --- a/lib/libc/stdlib/local.h +++ b/lib/libc/stdlib/local.h @@ -29,6 +29,8 @@ #include <sys/types.h> #include <stdbool.h> +extern ssize_t __findenvslot(const char *, size_t); + extern size_t __envvarnamelen(const char *str, bool withequal); extern void __freeenvvar(char *envvar); diff --git a/sys/sys/rbtree.h b/sys/sys/rbtree.h index b4a8ba3f7fc1..686cf2ed299a 100644 --- a/sys/sys/rbtree.h +++ b/sys/sys/rbtree.h @@ -125,12 +125,17 @@ TAILQ_HEAD(rb_node_qh, rb_node); #define RB_TAILQ_INSERT_HEAD(a, b, c) TAILQ_INSERT_HEAD(a, b, c) #define RB_TAILQ_INSERT_BEFORE(a, b, c) TAILQ_INSERT_BEFORE(a, b, c) #define RB_TAILQ_INSERT_AFTER(a, b, c, d) TAILQ_INSERT_AFTER(a, b, c, d) + +#define RBDEBUG_TREE_INITIALIZER(t) \ + .rbt_nodes = TAILQ_INITIALIZER((t).rbt_nodes), #else #define RB_TAILQ_REMOVE(a, b, c) do { } while (/*CONSTCOND*/0) #define RB_TAILQ_INIT(a) do { } while (/*CONSTCOND*/0) #define RB_TAILQ_INSERT_HEAD(a, b, c) do { } while (/*CONSTCOND*/0) #define RB_TAILQ_INSERT_BEFORE(a, b, c) do { } while (/*CONSTCOND*/0) #define RB_TAILQ_INSERT_AFTER(a, b, c, d) do { } while (/*CONSTCOND*/0) + +#define RBDEBUG_TREE_INITIALIZER(t) /* nothing */ #endif /* RBDEBUG */ /* @@ -181,6 +186,12 @@ typedef struct rb_tree { #define RBSTAT_DEC(v) do { } while (/*CONSTCOND*/0) #endif +#define RB_TREE_INITIALIZER(t, ops) (rb_tree_t) \ +{ \ + .rbt_ops = (ops), \ + RBDEBUG_TREE_INITIALIZER(t) \ +} + void rb_tree_init(rb_tree_t *, const rb_tree_ops_t *); void * rb_tree_insert_node(rb_tree_t *, void *); void * rb_tree_find_node(rb_tree_t *, const void *);