Implemented setenv(3), putenv(3), getenv(3), clearenv(3), sortix_getenv(3),

unsetenv(3), envlength(3), getenvindexed(3), and environ(7).

This provides the user-space foundation for environmental variables.

Note that this works over fork(2), but not execve(2) yet.
This commit is contained in:
Jonas 'Sortie' Termansen 2012-04-03 20:15:34 +02:00
parent 5d59f0ed03
commit dd5157da6a
4 changed files with 213 additions and 11 deletions

View File

@ -50,6 +50,7 @@ start.o \
time.o \
random.o \
abs.o \
env.o \
integer.o \
c++.o \
memory.o \

192
libmaxsi/env.cpp Normal file
View File

@ -0,0 +1,192 @@
/*******************************************************************************
COPYRIGHT(C) JONAS 'SORTIE' TERMANSEN 2012.
This file is part of LibMaxsi.
LibMaxsi 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 3 of the License, or (at your option)
any later version.
LibMaxsi 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 LibMaxsi. If not, see <http://www.gnu.org/licenses/>.
env.cpp
Environmental variables utilities.
*******************************************************************************/
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
/* Since legacy applications rely on being able to modify the environ variable,
we have to keep track of whether it is what we expect and whether we know the
size of it. If it changed, we need to recount, as well as malloc a copy of it
if we wish to make changes. */
extern "C" { char** environ = NULL; }
static char** environ_malloced = NULL;
static char** environ_counted = NULL;
size_t environlen = 0;
size_t environroom = 0;
static inline bool environismalloced()
{
return environ && environ == environ_malloced;
}
extern "C" const char* const* getenviron(void)
{
return environ;
}
extern "C" size_t envlength(void)
{
if ( !environ ) { return 0; }
if ( environ_counted != environ )
{
size_t count = 0;
while ( environ[count] ) { count++; }
environ_counted = environ;
environlen = count;
}
return environlen;
}
extern "C" const char* getenvindexed(size_t index)
{
if ( envlength() <= index ) { errno = EBOUND; return NULL; }
return environ[index];
}
extern "C" const char* sortix_getenv(const char* name)
{
size_t equalpos = strcspn(name, "=");
if ( name[equalpos] == '=' ) { return NULL; }
size_t namelen = equalpos;
size_t envlen = envlength();
for ( size_t i = 0; i < envlen; i++ )
{
if ( strncmp(name, environ[i], namelen) ) { continue; }
if ( environ[i][namelen] != '=' ) { continue; }
return environ[i] + namelen + 1;
}
return NULL;
}
extern "C" char* getenv(const char* name)
{
return (char*) sortix_getenv(name);
}
static bool makeenvironmalloced()
{
if ( environismalloced() ) { return true; }
size_t envlen = envlength();
size_t newenvlen = envlen;
size_t newenvsize = sizeof(char*) * (newenvlen+1);
char** newenviron = (char**) malloc(newenvsize);
if ( !newenviron ) { return false; }
size_t sofar = 0;
for ( size_t i = 0; i < envlen; i++ )
{
newenviron[i] = strdup(environ[i]);
if ( !newenviron[i] ) { goto cleanup; }
sofar = i;
}
newenviron[envlen] = NULL;
environlen = environroom = newenvlen;
environ = environ_malloced = environ_counted = newenviron;
return true;
cleanup:
for ( size_t i = 0; i < sofar; i++ ) { free(newenviron[i]); }
free(newenviron);
return false;
}
extern "C" int clearenv(void)
{
if ( !environ ) { return 0; }
if ( environismalloced() )
{
for ( char** varp = environ; *varp; varp++ ) { free(*varp); }
free(environ);
}
environ = environ_counted = environ_malloced = NULL;
return 0;
}
static bool doputenv(char* str, char* freeme, bool overwrite)
{
if ( !makeenvironmalloced() ) { free(freeme); return false; }
size_t strvarnamelen = strcspn(str, "=");
for ( size_t i = 0; i < envlength(); i++ )
{
char* var = environ[i];
if ( strncmp(str, var, strvarnamelen) ) { continue; }
if ( !overwrite ) { free(freeme); return true; }
free(var);
environ[i] = str;
return true;
}
if ( environlen == environroom )
{
size_t newenvironroom = environroom ? 2 * environroom : 16;
size_t newenvironsize = sizeof(char*) * (newenvironroom+1);
char** newenviron = (char**) realloc(environ, newenvironsize);
if ( !newenviron ) { free(freeme); return false; }
environ = environ_malloced = environ_counted = newenviron;
environroom = newenvironroom;
}
environ[environlen++] = str;
environ[environlen] = NULL;
return true;
}
extern "C" int setenv(const char* name, const char* value, int overwrite)
{
if ( !name || !name[0] || strchr(name, '=') ) { errno = EINVAL; return -1; }
char* str = (char*) malloc(strlen(name) + 1 + strlen(value) + 1);
if ( !str ) { return -1; }
stpcpy(stpcpy(stpcpy(str, name), "="), value);
if ( !doputenv(str, str, overwrite) ) { return -1; }
return 0;
}
extern "C" int putenv(char* str)
{
if ( !strchr(str, '=') ) { errno = EINVAL; return -1; }
if ( !doputenv(str, NULL, true) ) { return -1; }
return 0;
}
extern "C" int unsetenv(const char* name)
{
size_t equalpos = strcspn(name, "=");
if ( name[equalpos] == '=' ) { return 0; }
size_t namelen = equalpos;
size_t envlen = envlength();
for ( size_t i = 0; i < envlen; i++ )
{
if ( strncmp(name, environ[i], namelen) ) { continue; }
if ( environ[i][namelen] != '=' ) { continue; }
if ( environismalloced() )
{
char* str = environ[i];
free(str);
}
if ( i < envlen-1 ) { environ[i] = environ[envlen-1]; }
environ[--environlen] = NULL;
return 0;
}
return 0;
}

View File

@ -56,20 +56,39 @@ void* calloc(size_t, size_t);
void exit(int);
void _Exit(int status);
void free(void*);
char* getenv(const char*);
long labs(long);
long long llabs(long long);
void* malloc(size_t);
#if !defined(_SORTIX_SOURCE)
char* mktemp(char* templ);
#endif
int putenv(char*);
void qsort(void*, size_t, size_t, int (*)(const void*, const void*));
int rand(void);
void* realloc(void*, size_t);
int setenv(const char*, const char*, int);
long strtol(const char* restrict, char** restrict, int);
unsigned long strtoul(const char* restrict, char** restrict, int);
unsigned long long strtoull(const char* restrict, char** restrict, int);
long long strtoll(const char* restrict, char** restrict, int);
int unsetenv(const char*);
#if defined(_SORTIX_SOURCE) || defined(_WANT_SORTIX_ENV)
const char* const* getenviron(void);
size_t envlength(void);
const char* getenvindexed(size_t index);
const char* sortix_getenv(const char* name);
#endif
#if (defined(_SOURCE_SOURCE) && __SORTIX_STDLIB_REDIRECTS) || \
defined(_WANT_SORTIX_ENV)
const char* getenv(const char* name) asm ("sortix_getenv");
#else
char* getenv(const char*);
#endif
#if defined(_SORTIX_SOURCE) || defined(_SVID_SOURCE) || defined(_XOPEN_SOURCE) \
|| defined(_GNU_SOURCE) || defined(_BSD_SOURCE)
int clearenv(void);
#endif
/* TODO: These are not implemented in libmaxsi/sortix yet. */
#if defined(__SORTIX_SHOW_UNIMPLEMENTED)
@ -99,11 +118,9 @@ long nrand48(unsigned short[3]);
int posix_memalign(void**, size_t, size_t);
int posix_openpt(int);
char* ptsname(int);
int putenv(char*);
long random(void);
char* realpath(const char* restrict, char* restrict);
unsigned short *seed48(unsigned short [3]);
int setenv(const char*, const char*, int);
void setkey(const char*);
char* setstate(char*);
void srand(unsigned);
@ -114,7 +131,6 @@ float strtof(const char* restrict, char** restrict);
long double strtold(const char* restrict, char** restrict);
int system(const char*);
int unlockpt(int);
int unsetenv(const char*);
size_t wcstombs(char* restrict, const wchar_t *restrict, size_t);
int wctomb(char*, wchar_t);

View File

@ -40,8 +40,6 @@ namespace Maxsi
DEFN_SYSCALL0(pid_t, SysGetParentPID, SYSCALL_GETPPID);
DEFN_SYSCALL3(pid_t, SysWait, SYSCALL_WAIT, pid_t, int*, int);
extern "C" char** environ = NULL;
void Abort()
{
// TODO: Send SIGABRT instead!
@ -102,11 +100,6 @@ namespace Maxsi
{
return waitpid(-1, status, 0);
}
extern "C" char* getenv(const char* name)
{
return NULL;
}
}
}