// 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