You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
146 lines
3.9 KiB
146 lines
3.9 KiB
// Can't trust libc not to leak enviornment variable memory, so...
|
|
|
|
#include "toys.h"
|
|
|
|
// In libc, populated by start code, used by getenv() and exec() and friends.
|
|
extern char **environ;
|
|
|
|
// Returns the number of bytes taken by the environment variables. For use
|
|
// when calculating the maximum bytes of environment+argument data that can
|
|
// be passed to exec for find(1) and xargs(1).
|
|
long environ_bytes(void)
|
|
{
|
|
long bytes = sizeof(char *);
|
|
char **ev;
|
|
|
|
for (ev = environ; *ev; ev++) bytes += sizeof(char *) + strlen(*ev) + 1;
|
|
|
|
return bytes;
|
|
}
|
|
|
|
// This will clear the inherited environment if called first thing.
|
|
// Use this instead of envc so we keep track of what needs to be freed.
|
|
void xclearenv(void)
|
|
{
|
|
if (toys.envc) {
|
|
int i;
|
|
|
|
for (i = 0; environ[i]; i++) if (i>=toys.envc) free(environ[i]);
|
|
} else environ = xmalloc(256*sizeof(char *));
|
|
toys.envc = 1;
|
|
*environ = 0;
|
|
}
|
|
|
|
// Frees entries we set earlier. Use with libc getenv but not setenv/putenv.
|
|
// if name has an equals and !val, act like putenv (name=val must be malloced!)
|
|
// if !val unset name. (Name with = and val is an error)
|
|
// returns pointer to new name=value environment string, NULL if none
|
|
char *xsetenv(char *name, char *val)
|
|
{
|
|
unsigned i, j = 0, len;
|
|
char *new;
|
|
|
|
// If we haven't snapshot initial environment state yet, do so now.
|
|
if (!toys.envc) {
|
|
|
|
// envc is size +1 so even if env empty it's nonzero after initialization
|
|
while (environ[toys.envc++]);
|
|
memcpy(new = xmalloc(((toys.envc|31)+1)*sizeof(char *)), environ,
|
|
toys.envc*sizeof(char *));
|
|
environ = (void *)new;
|
|
}
|
|
|
|
if (!(new = strchr(name, '='))) {
|
|
len = strlen(name);
|
|
if (val) new = xmprintf("%s=%s", name, val);
|
|
} else {
|
|
len = new-name;
|
|
if (val) error_exit("xsetenv %s to %s", name, val);
|
|
new = name;
|
|
}
|
|
|
|
for (i = 0; environ[i]; i++) {
|
|
// Drop old entry, freeing as appropriate. Assumes no duplicates.
|
|
if (!memcmp(name, environ[i], len) && environ[i][len]=='=') {
|
|
if (i<toys.envc-1) toys.envc--;
|
|
else free(environ[i]);
|
|
j++;
|
|
}
|
|
|
|
// move data down to fill hole, including null terminator
|
|
if (j && !(environ[i] = environ[i+1])) break;
|
|
}
|
|
|
|
if (!new) return 0;
|
|
|
|
// resize and null terminate if expanding
|
|
if (!j && !environ[i]) {
|
|
len = i+1;
|
|
if (!(len&31)) environ = xrealloc(environ, (len+32)*sizeof(char *));
|
|
environ[len] = 0;
|
|
}
|
|
|
|
return environ[i] = new;
|
|
}
|
|
|
|
void xunsetenv(char *name)
|
|
{
|
|
if (strchr(name, '=')) error_exit("xunsetenv %s name has =", name);
|
|
xsetenv(name, 0);
|
|
}
|
|
|
|
// remove entry and return pointer instead of freeing
|
|
char *xpop_env(char *name)
|
|
{
|
|
int len, i;
|
|
char *s = 0;
|
|
|
|
for (len = 0; name[len] && name[len]!='='; len++);
|
|
for (i = 0; environ[i]; i++) {
|
|
if (!s && !strncmp(name, environ[i], len) && environ[i][len] == '=') {
|
|
s = environ[i];
|
|
if (toys.envc-1>i) {
|
|
s = xstrdup(s);
|
|
toys.envc--;
|
|
}
|
|
}
|
|
if (s) environ[i] = environ[i+1];
|
|
}
|
|
|
|
return s;
|
|
}
|
|
|
|
// reset environment for a user, optionally clearing most of it
|
|
void reset_env(struct passwd *p, int clear)
|
|
{
|
|
int i;
|
|
|
|
if (clear) {
|
|
char *s, *stuff[] = {"TERM", "DISPLAY", "COLORTERM", "XAUTHORITY"};
|
|
|
|
for (i=0; i<ARRAY_LEN(stuff); i++)
|
|
stuff[i] = (s = getenv(stuff[i])) ? xmprintf("%s=%s", stuff[i], s) : 0;
|
|
xclearenv();
|
|
for (i=0; i < ARRAY_LEN(stuff); i++) if (stuff[i]) xsetenv(stuff[i], 0);
|
|
if (chdir(p->pw_dir)) {
|
|
perror_msg("chdir %s", p->pw_dir);
|
|
xchdir("/");
|
|
}
|
|
} else {
|
|
char **ev1, **ev2;
|
|
|
|
// remove LD_*, IFS, ENV, and BASH_ENV from environment
|
|
for (ev1 = ev2 = environ;;) {
|
|
while (*ev2 && (strstart(ev2, "LD_") || strstart(ev2, "IFS=") ||
|
|
strstart(ev2, "ENV=") || strstart(ev2, "BASH_ENV="))) ev2++;
|
|
if (!(*ev1++ = *ev2++)) break;
|
|
}
|
|
}
|
|
|
|
setenv("PATH", _PATH_DEFPATH, 1);
|
|
setenv("HOME", p->pw_dir, 1);
|
|
setenv("SHELL", p->pw_shell, 1);
|
|
setenv("USER", p->pw_name, 1);
|
|
setenv("LOGNAME", p->pw_name, 1);
|
|
}
|