aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/stdlib.h2
-rw-r--r--lib/libc/stdlib/Makefile.inc3
-rw-r--r--lib/libc/stdlib/Symbol.map4
-rw-r--r--lib/libc/stdlib/getenv.320
-rw-r--r--lib/libc/stdlib/getenv.c25
-rw-r--r--lib/libc/tests/stdlib/Makefile1
-rw-r--r--lib/libc/tests/stdlib/clearenv_test.c176
7 files changed, 228 insertions, 3 deletions
diff --git a/include/stdlib.h b/include/stdlib.h
index ca96c06b83b7..bf1a612190ee 100644
--- a/include/stdlib.h
+++ b/include/stdlib.h
@@ -283,6 +283,8 @@ int cgetset(const char *);
int cgetstr(char *, const char *, char **);
int cgetustr(char *, const char *, char **);
+int clearenv(void);
+
int daemon(int, int);
int daemonfd(int, int);
char *devname(__dev_t, __mode_t);
diff --git a/lib/libc/stdlib/Makefile.inc b/lib/libc/stdlib/Makefile.inc
index 361761e73fdd..a658fd78e862 100644
--- a/lib/libc/stdlib/Makefile.inc
+++ b/lib/libc/stdlib/Makefile.inc
@@ -46,7 +46,8 @@ MAN+= a64l.3 abort.3 abs.3 alloca.3 atexit.3 atof.3 \
MLINKS+=a64l.3 l64a.3 a64l.3 l64a_r.3
MLINKS+=atol.3 atoll.3
MLINKS+=exit.3 _Exit.3
-MLINKS+=getenv.3 putenv.3 getenv.3 setenv.3 getenv.3 unsetenv.3
+MLINKS+=getenv.3 clearenv.3 getenv.3 putenv.3 getenv.3 setenv.3 \
+ getenv.3 unsetenv.3
MLINKS+=getopt_long.3 getopt_long_only.3
MLINKS+=hcreate.3 hdestroy.3 hcreate.3 hsearch.3
MLINKS+=hcreate.3 hcreate_r.3 hcreate.3 hdestroy_r.3 hcreate.3 hsearch_r.3
diff --git a/lib/libc/stdlib/Symbol.map b/lib/libc/stdlib/Symbol.map
index 2be23390e333..6524c6097b96 100644
--- a/lib/libc/stdlib/Symbol.map
+++ b/lib/libc/stdlib/Symbol.map
@@ -128,6 +128,10 @@ FBSD_1.6 {
srand;
};
+FBSD_1.7 {
+ clearenv;
+};
+
FBSDprivate_1.0 {
__system;
_system;
diff --git a/lib/libc/stdlib/getenv.3 b/lib/libc/stdlib/getenv.3
index e662b86d214b..5566d7b01dcd 100644
--- a/lib/libc/stdlib/getenv.3
+++ b/lib/libc/stdlib/getenv.3
@@ -32,10 +32,11 @@
.\" @(#)getenv.3 8.2 (Berkeley) 12/11/93
.\" $FreeBSD$
.\"
-.Dd June 20, 2007
+.Dd November 7, 2021
.Dt GETENV 3
.Os
.Sh NAME
+.Nm clearenv ,
.Nm getenv ,
.Nm putenv ,
.Nm setenv ,
@@ -45,6 +46,8 @@
.Lb libc
.Sh SYNOPSIS
.In stdlib.h
+.Ft int
+.Fn clearenv "void"
.Ft char *
.Fn getenv "const char *name"
.Ft int
@@ -59,6 +62,14 @@ host
.Em environment list .
.Pp
The
+.Fn clearenv
+function clears all environment variables.
+New variables can be added using
+.Fn setenv
+and
+.Fn putenv .
+.Pp
+The
.Fn getenv
function obtains the current value of the environment variable,
.Fa name .
@@ -128,7 +139,7 @@ is not in the current environment,
.Dv NULL
is returned.
.Pp
-.Rv -std setenv putenv unsetenv
+.Rv -std clearenv setenv putenv unsetenv
.Sh ERRORS
.Bl -tag -width Er
.It Bq Er EINVAL
@@ -211,6 +222,11 @@ This was changed to use
as the memory location of the ``name=value'' pair to follow the
.Tn POSIX
specification.
+.Pp
+The
+.Fn clearenv
+was added in
+.Fx 14 .
.Sh BUGS
Successive calls to
.Fn setenv
diff --git a/lib/libc/stdlib/getenv.c b/lib/libc/stdlib/getenv.c
index 5d445e18d93b..bf79cb6b0d79 100644
--- a/lib/libc/stdlib/getenv.c
+++ b/lib/libc/stdlib/getenv.c
@@ -691,3 +691,28 @@ unsetenv(const char *name)
return (0);
}
+
+/*
+ * Unset all variable by flagging them as inactive. No variable is
+ * ever freed.
+ */
+int
+clearenv(void)
+{
+ int ndx;
+
+ /* Initialize environment. */
+ if (__merge_environ() == -1 || (envVars == NULL && __build_env() == -1))
+ return (-1);
+
+ /* Remove from the end to not shuffle memory too much. */
+ for (ndx = envVarsTotal - 1; ndx >= 0; ndx--) {
+ envVars[ndx].active = false;
+ if (envVars[ndx].putenv)
+ __remove_putenv(ndx);
+ }
+
+ __rebuild_environ(0);
+
+ return (0);
+}
diff --git a/lib/libc/tests/stdlib/Makefile b/lib/libc/tests/stdlib/Makefile
index bd85efcb1b95..ffba83443a9e 100644
--- a/lib/libc/tests/stdlib/Makefile
+++ b/lib/libc/tests/stdlib/Makefile
@@ -2,6 +2,7 @@
.include <src.opts.mk>
+ATF_TESTS_C+= clearenv_test
ATF_TESTS_C+= dynthr_test
ATF_TESTS_C+= heapsort_test
ATF_TESTS_C+= mergesort_test
diff --git a/lib/libc/tests/stdlib/clearenv_test.c b/lib/libc/tests/stdlib/clearenv_test.c
new file mode 100644
index 000000000000..0c705bfece1e
--- /dev/null
+++ b/lib/libc/tests/stdlib/clearenv_test.c
@@ -0,0 +1,176 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (C) 2021 Mariusz Zaborski <oshogbo@FreeBSD.org>
+ *
+ * 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 AUTHOR 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 AUTHOR 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.
+ */
+
+/*
+ * Test for clearenv(3) routine.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <atf-c.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#define TEST_VARIABLE "TEST_VAR"
+#define TEST_SYSTEM_VARIABLE "PWD"
+
+extern char **environ;
+
+void
+create_multiple_variables(int num)
+{
+ char name[64];
+ char value[64];
+ int i;
+
+ for (i = 0; i < num; i++) {
+ snprintf(name, sizeof(name), "%s_%d", TEST_VARIABLE, i);
+ snprintf(value, sizeof(value), "%d", i);
+ ATF_CHECK(getenv(name) == NULL);
+ ATF_CHECK(setenv(name, value, 0) != -1);
+ ATF_CHECK_STREQ(getenv(name), value);
+ }
+}
+
+void
+check_if_nulled_variables(int num)
+{
+ char name[64];
+ int i;
+
+ for (i = 0; i < num; i++) {
+ snprintf(name, sizeof(name), "%s_%d", TEST_VARIABLE, i);
+ ATF_CHECK(getenv(name) == NULL);
+ }
+}
+
+ATF_TC_WITHOUT_HEAD(clearenv__single_var_test);
+ATF_TC_BODY(clearenv__single_var_test, tc)
+{
+
+ ATF_CHECK(setenv(TEST_VARIABLE, "true", 0) != -1);
+ ATF_CHECK_STREQ(getenv(TEST_VARIABLE), "true");
+ ATF_CHECK(clearenv() == 0);
+ ATF_CHECK(getenv(TEST_VARIABLE) == NULL);
+}
+
+ATF_TC_WITHOUT_HEAD(clearenv__multiple_vars_test);
+ATF_TC_BODY(clearenv__multiple_vars_test, tc)
+{
+
+ create_multiple_variables(10);
+ ATF_CHECK(clearenv() == 0);
+ check_if_nulled_variables(10);
+}
+
+ATF_TC_WITHOUT_HEAD(clearenv__recreated_vars_test);
+ATF_TC_BODY(clearenv__recreated_vars_test, tc)
+{
+
+ create_multiple_variables(10);
+ ATF_CHECK(clearenv() == 0);
+ check_if_nulled_variables(10);
+ create_multiple_variables(10);
+}
+
+ATF_TC_WITHOUT_HEAD(clearenv__system_var_test);
+ATF_TC_BODY(clearenv__system_var_test, tc)
+{
+
+ ATF_CHECK(getenv(TEST_SYSTEM_VARIABLE) != NULL);
+ ATF_CHECK(clearenv() == 0);
+ ATF_CHECK(getenv(TEST_SYSTEM_VARIABLE) == NULL);
+}
+
+ATF_TC_WITHOUT_HEAD(clearenv__recreated_system_var_test);
+ATF_TC_BODY(clearenv__recreated_system_var_test, tc)
+{
+
+ ATF_CHECK(getenv(TEST_SYSTEM_VARIABLE) != NULL);
+ ATF_CHECK(clearenv() == 0);
+ ATF_CHECK(getenv(TEST_SYSTEM_VARIABLE) == NULL);
+ ATF_CHECK(setenv(TEST_SYSTEM_VARIABLE, "test", 0) != -1);
+ ATF_CHECK_STREQ(getenv(TEST_SYSTEM_VARIABLE), "test");
+}
+
+ATF_TC_WITHOUT_HEAD(clearenv__double_clear_vars);
+ATF_TC_BODY(clearenv__double_clear_vars, tc)
+{
+
+ create_multiple_variables(10);
+ ATF_CHECK(clearenv() == 0);
+ check_if_nulled_variables(10);
+ ATF_CHECK(clearenv() == 0);
+ check_if_nulled_variables(10);
+ create_multiple_variables(10);
+}
+
+ATF_TC_WITHOUT_HEAD(clearenv__environ_null);
+ATF_TC_BODY(clearenv__environ_null, tc)
+{
+
+ ATF_CHECK(clearenv() == 0);
+ ATF_CHECK(environ == NULL);
+}
+
+ATF_TC_WITHOUT_HEAD(clearenv__putenv_vars);
+ATF_TC_BODY(clearenv__putenv_vars, tc)
+{
+ char buf[64], ref[64];
+
+ snprintf(buf, sizeof(buf), "%s=1", TEST_VARIABLE);
+ strcpy(ref, buf);
+
+ ATF_CHECK(getenv(TEST_VARIABLE) == NULL);
+ ATF_CHECK(putenv(buf) != -1);
+ ATF_CHECK(strcmp(getenv(TEST_VARIABLE), "1") == 0);
+
+ ATF_CHECK(clearenv() == 0);
+
+ ATF_CHECK(getenv(TEST_VARIABLE) == NULL);
+ ATF_CHECK(strcmp(buf, ref) == 0);
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+ ATF_TP_ADD_TC(tp, clearenv__single_var_test);
+ ATF_TP_ADD_TC(tp, clearenv__multiple_vars_test);
+ ATF_TP_ADD_TC(tp, clearenv__recreated_vars_test);
+
+ ATF_TP_ADD_TC(tp, clearenv__system_var_test);
+ ATF_TP_ADD_TC(tp, clearenv__recreated_system_var_test);
+
+ ATF_TP_ADD_TC(tp, clearenv__double_clear_vars);
+ ATF_TP_ADD_TC(tp, clearenv__environ_null);
+
+ ATF_TP_ADD_TC(tp, clearenv__putenv_vars);
+
+ return (atf_no_error());
+}