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