@@ -79,6 +79,7 @@ routines := \
getcontext \
getentropy \
getenv \
+ getenvarray \
getrandom \
getsubopt \
jrand48 \
new file mode 100644
@@ -0,0 +1,64 @@
+/* Obtain a consistent copy of the environ array.
+ Copyright (C) 2024 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 <atomic.h>
+#include <setenv.h>
+#include <unistd.h>
+
+size_t
+__getenvarray (char **result, size_t length)
+{
+ while (true)
+ {
+ /* The snapshotting approach follows getenv. Duplicates are
+ filtered out explicitly. */
+ environ_counter start_counter = atomic_load_acquire (&__environ_counter);
+ char **start_environ = atomic_load_relaxed (&__environ);
+ if (start_environ == NULL)
+ return 0;
+
+ const char *previous = NULL;
+ size_t count = 0;
+ for (char *const *ep = start_environ; ; ++ep)
+ {
+ char *entry = atomic_load_relaxed (ep);
+ if (entry == NULL)
+ break;
+ if (entry == previous)
+ /* Filter out a duplicate created by concurrent unsetenv. */
+ continue;
+ if (count < length)
+ result[count] = entry;
+ ++count;
+ previous = entry;
+ }
+
+ atomic_thread_fence_acquire ();
+
+ if (atomic_load_acquire (&__environ_counter) != start_counter)
+ /* Retry if there has been more than one write to the array
+ from within unsetenv. Writes in setenv/putenv do not
+ matter because they do not change the key, so they cannot
+ introduce duplicates. */
+ continue;
+
+ if (count < length)
+ result[count] = NULL;
+ return count;
+ }
+}
@@ -47,6 +47,13 @@ __environ_is_from_array_list (char **ep)
return eal != NULL && &eal->array[0] == ep;
}
+/* Make a copy of the environ array. Writes up to LENGTH pointers to
+ *RESULT, including a terminating null pointer if there is room.
+ *Returns the total number of non-null elements in the environ
+ *array. This number can be larger than LENGTH. */
+size_t __getenvarray (char **result, size_t length)
+ __attr_access ((__write_only__, 1, 2)) attribute_hidden;
+
/* Counter for detecting concurrent modification in unsetenv.
Ideally, this should be a 64-bit counter that cannot wrap around,
but given that counter wrapround is probably impossible to hit