blob: 8da2fae5c6ddae6069f7f4e9f73e1736743ecb8b [file] [log] [blame]
lh9ed821d2023-04-07 01:36:19 -07001/* Copyright (C) 1992,95,96,97,98,99,2000,2001 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3
4 The GNU C Library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
8
9 The GNU C Library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public
15 License along with the GNU C Library; if not, write to the Free
16 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
17 02111-1307 USA.
18
19 modified for uClibc by Erik Andersen <andersen@codepoet.org>
20*/
21
22#include <features.h>
23#include <errno.h>
24#include <stdlib.h>
25#include <string.h>
26#include <unistd.h>
27
28
29#include <bits/uClibc_mutex.h>
30__UCLIBC_MUTEX_STATIC(mylock, PTHREAD_MUTEX_INITIALIZER);
31
32
33/* If this variable is not a null pointer we allocated the current
34 environment. */
35static char **last_environ;
36
37
38/* This function is used by `setenv' and `putenv'. The difference between
39 the two functions is that for the former must create a new string which
40 is then placed in the environment, while the argument of `putenv'
41 must be used directly. This is all complicated by the fact that we try
42 to reuse values once generated for a `setenv' call since we can never
43 free the strings. [in uclibc, we do not] */
44static int __add_to_environ(const char *name, const char *value,
45 int replace)
46{
47 register char **ep;
48 register size_t size;
49 char *var_val;
50 char **new_environ;
51 /* name may come from putenv() and thus may contain "=VAL" part */
52 const size_t namelen = strchrnul(name, '=') - name;
53 int rv = -1;
54
55 __UCLIBC_MUTEX_LOCK(mylock);
56
57 /* We have to get the pointer now that we have the lock and not earlier
58 since another thread might have created a new environment. */
59 ep = __environ;
60
61 size = 0;
62 if (ep != NULL) {
63 while (*ep != NULL) {
64 if (!strncmp(*ep, name, namelen) && (*ep)[namelen] == '=') {
65 /* Found */
66 if (!replace)
67 goto DONE_OK;
68 goto REPLACE;
69 }
70 ++size;
71 ++ep;
72 }
73 }
74
75 /* Not found, add at the end */
76
77 /* We allocated this space; we can extend it. */
78 new_environ = realloc(last_environ, (size + 2) * sizeof(char *));
79 if (new_environ == NULL) {
80 __set_errno(ENOMEM);
81 goto DONE;
82 }
83 if (__environ != last_environ) {
84 memcpy(new_environ, __environ, size * sizeof(char *));
85 }
86 last_environ = __environ = new_environ;
87
88 ep = &new_environ[size];
89 /* Ensure env is NULL terminated in case malloc below fails */
90 ep[0] = NULL;
91 ep[1] = NULL;
92
93 REPLACE:
94 var_val = (char*) name;
95 /* Build VAR=VAL if we called by setenv, not putenv. */
96 if (value != NULL) {
97 const size_t vallen = strlen(value) + 1;
98
99 var_val = malloc(namelen + 1 + vallen);
100 if (var_val == NULL) {
101 __set_errno(ENOMEM);
102 goto DONE;
103 }
104 memcpy(var_val, name, namelen);
105 var_val[namelen] = '=';
106 memcpy(&var_val[namelen + 1], value, vallen);
107 }
108 *ep = var_val;
109
110 DONE_OK:
111 rv = 0;
112
113 DONE:
114 __UCLIBC_MUTEX_UNLOCK(mylock);
115 return rv;
116}
117
118int setenv(const char *name, const char *value, int replace)
119{
120 /* NB: setenv("VAR", NULL, 1) inserts "VAR=" string */
121 return __add_to_environ(name, value ? value : "", replace);
122}
123libc_hidden_def(setenv)
124
125int unsetenv(const char *name)
126{
127 const char *eq;
128 size_t len;
129 char **ep;
130
131 if (name == NULL || *name == '\0'
132 || *(eq = strchrnul(name, '=')) == '='
133 ) {
134 __set_errno(EINVAL);
135 return -1;
136 }
137 len = eq - name; /* avoiding strlen this way */
138
139 __UCLIBC_MUTEX_LOCK(mylock);
140 ep = __environ;
141 /* NB: clearenv(); unsetenv("foo"); should not segfault */
142 if (ep) while (*ep != NULL) {
143 if (!strncmp(*ep, name, len) && (*ep)[len] == '=') {
144 /* Found it. Remove this pointer by moving later ones back. */
145 char **dp = ep;
146 do {
147 dp[0] = dp[1];
148 } while (*dp++);
149 /* Continue the loop in case NAME appears again. */
150 } else {
151 ++ep;
152 }
153 }
154 __UCLIBC_MUTEX_UNLOCK(mylock);
155 return 0;
156}
157libc_hidden_def(unsetenv)
158
159/* The `clearenv' was planned to be added to POSIX.1 but probably
160 never made it. Nevertheless the POSIX.9 standard (POSIX bindings
161 for Fortran 77) requires this function. */
162int clearenv(void)
163{
164 __UCLIBC_MUTEX_LOCK(mylock);
165 /* If we allocated this environment we can free it.
166 * If we did not allocate this environment, it's NULL already
167 * and is safe to free(). */
168 free(last_environ);
169 last_environ = NULL;
170 /* Clearing environ removes the whole environment. */
171 __environ = NULL;
172 __UCLIBC_MUTEX_UNLOCK(mylock);
173 return 0;
174}
175
176/* Put STRING, which is of the form "NAME=VALUE", in the environment. */
177int putenv(char *string)
178{
179 if (strchr(string, '=') != NULL) {
180 return __add_to_environ(string, NULL, 1);
181 }
182 return unsetenv(string);
183}