> 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 *);

Reply via email to