#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)setenv.c 8.1 (Berkeley) 6/4/93";
#endif
#include <sys/cdefs.h>
__FBSDID("$FreeBSD: src/lib/libc/stdlib/setenv.c,v 1.9 2002/03/22 21:53:10 obrien Exp $");
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <crt_externs.h>
#include <errno.h>
#include <sys/types.h>
#include <fcntl.h>
#include <malloc/malloc.h>
#define ZONE_OWNS_PTR(zone, ptr) (malloc_zone_from_ptr((ptr)) == zone)
extern malloc_zone_t *__zone0;
extern void __malloc_check_env_name(const char *);
__private_extern__ char *__findenv(const char *, int *, char **);
__private_extern__ int __setenv(const char *, const char *, int, int, char ***, malloc_zone_t *);
__private_extern__ void __unsetenv(const char *, char **, malloc_zone_t *);
#ifndef BUILDING_VARIANT
__private_extern__ int
init__zone0(int should_set_errno)
{
if (__zone0) return (0);
__zone0 = malloc_create_zone(0, 0);
if (!__zone0) {
if (should_set_errno) {
errno = ENOMEM;
}
return (-1);
}
malloc_set_zone_name(__zone0, "environ");
return (0);
}
__private_extern__ int
__setenv(name, value, rewrite, copy, environp, envz)
const char *name;
const char *value;
int rewrite, copy;
char ***environp;
malloc_zone_t *envz;
{
char *c;
int offset;
if ((c = __findenv(name, &offset, *environp))) {
char *e;
if (!rewrite)
return (0);
e = (*environp)[offset];
if (copy > 0 && ZONE_OWNS_PTR(envz, e)) {
size_t l_value = strlen(value);
if (strlen(c) < l_value) {
char *r;
size_t len = c - e;
if ((r = realloc(e, l_value + len + 1)) == NULL)
return (-1);
if (r != e) {
(*environp)[offset] = r;
c = r + len;
}
}
while ( (*c++ = *value++) );
return (0);
}
} else {
int cnt;
char **p;
for (p = *environp, cnt = 0; *p; ++p, ++cnt);
if (ZONE_OWNS_PTR(envz, *environp)) {
p = (char **)realloc((char *)*environp,
(size_t)(sizeof(char *) * (cnt + 2)));
if (!p)
return (-1);
*environp = p;
}
else {
p = malloc_zone_malloc(envz, (size_t)(sizeof(char *) * (cnt + 2)));
if (!p)
return (-1);
bcopy(*environp, p, cnt * sizeof(char *));
*environp = p;
}
(*environp)[cnt + 1] = NULL;
offset = cnt;
}
if (copy > 0) {
for (c = (char *)name; *c && *c != '='; ++c);
if (!((*environp)[offset] =
malloc_zone_malloc(envz, (size_t)((int)(c - name) + strlen(value) + 2))))
return (-1);
for (c = (*environp)[offset]; (*c = *name++) && *c != '='; ++c);
for (*c++ = '='; (*c++ = *value++); );
} else {
if (copy < 0) {
size_t len = strlen(name);
if((c = malloc_zone_malloc(envz, len + 1)) == NULL)
return (-1);
memcpy(c, name, len + 1);
name = c;
}
if ((*environp)[offset] != NULL && ZONE_OWNS_PTR(envz, (*environp)[offset]))
free((*environp)[offset]);
(*environp)[offset] = (char *)name;
}
return (0);
}
__private_extern__ void
__unsetenv(const char *name, char **environ, malloc_zone_t *envz)
{
char **p;
int offset;
while (__findenv(name, &offset, environ)) {
if (ZONE_OWNS_PTR(envz, environ[offset]))
free(environ[offset]);
for (p = &environ[offset];; ++p)
if (!(*p = *(p + 1)))
break;
}
}
void *
_allocenvstate(void)
{
malloc_zone_t *zone;
zone = malloc_create_zone(1000 , 0 );
if (zone) {
malloc_set_zone_name(zone, "environ");
}
return (void *)zone;
}
char **
_copyenv(char **env)
{
char **p;
int cnt = 1;
if (env)
for (p = env; *p; ++p, ++cnt);
p = (char **)malloc((size_t)(sizeof(char *) * cnt));
if (!p)
return (NULL);
if (env)
bcopy(env, p, cnt * sizeof(char *));
else
*p = NULL;
return p;
}
int
_deallocenvstate(void *state)
{
malloc_zone_t *envz;
if (!(envz = (malloc_zone_t *)state) || envz == __zone0) {
errno = EINVAL;
return -1;
}
malloc_destroy_zone(envz);
return 0;
}
int
_setenvp(const char *name, const char *value, int rewrite, char ***envp, void *state)
{
if (init__zone0(1)) return (-1);
return (__setenv(name, value, rewrite, 1, envp, (state ? (malloc_zone_t *)state : __zone0)));
}
int
_unsetenvp(const char *name, char ***envp, void *state)
{
if (init__zone0(1)) return (-1);
__unsetenv(name, *envp, (state ? (malloc_zone_t *)state : __zone0));
return 0;
}
#endif
int
setenv(name, value, rewrite)
const char *name;
const char *value;
int rewrite;
{
if(name == NULL || *name == 0) {
errno = EINVAL;
return (-1);
}
#if __DARWIN_UNIX03
if (strchr(name, '=')) {
errno = EINVAL;
return (-1);
}
#endif
if (*value == '=')
++value;
if (init__zone0(1)) return (-1);
__malloc_check_env_name(name);
return (__setenv(name, value, rewrite, 1, _NSGetEnviron(), __zone0));
}
#if __DARWIN_UNIX03
int
#else
void
#endif
unsetenv(name)
const char *name;
{
#if __DARWIN_UNIX03
if(name == NULL || *name == 0) {
errno = EINVAL;
return (-1);
}
if (strchr(name, '=')) {
errno = EINVAL;
return (-1);
}
if (init__zone0(1)) return (-1);
#else
if(name == NULL || *name == 0)
return;
if (init__zone0(0)) return;
#endif
__malloc_check_env_name(name);
__unsetenv(name, *_NSGetEnviron(), __zone0);
#if __DARWIN_UNIX03
return 0;
#endif
}