toybox/lib/env.c
<<
>>
Prefs
   1// Can't trust libc not to leak enviornment variable memory, so...
   2
   3#include "toys.h"
   4
   5// In libc, populated by start code,used by getenv() and exec() and friends.
   6extern char **environ;
   7
   8// Returns the number of bytes taken by the environment variables. For use
   9// when calculating the maximum bytes of environment+argument data that can
  10// be passed to exec for find(1) and xargs(1).
  11long environ_bytes()
  12{
  13  long bytes = sizeof(char *);
  14  char **ev;
  15
  16  for (ev = environ; *ev; ev++) bytes += sizeof(char *) + strlen(*ev) + 1;
  17
  18  return bytes;
  19}
  20
  21// This will clear the inherited environment if called first thing.
  22// Use this instead of envc so we keep track of what needs to be freed.
  23void xclearenv(void)
  24{
  25  toys.envc = 0;
  26  *environ = 0;
  27}
  28
  29// Frees entries we set earlier. Use with libc getenv but not setenv/putenv.
  30// if name has an equals and !val, act like putenv (name=val must be malloced!)
  31// if !val unset name. (Name with = and val is an error)
  32void xsetenv(char *name, char *val)
  33{
  34  unsigned i, len, envc;
  35  char *new;
  36
  37  // If we haven't snapshot initial environment state yet, do so now.
  38  if (!toys.envc) {
  39    // envc is size +1 so even if env empty it's nonzero after initialization
  40    while (environ[toys.envc++]);
  41    memcpy(new = xmalloc(((toys.envc|0xff)+1)*sizeof(char *)),
  42      environ, toys.envc*sizeof(char *));
  43    environ = (void *)new;
  44  }
  45
  46  new = strchr(name, '=');
  47  if (new) {
  48    len = new-name;
  49    if (val) error_exit("xsetenv %s to %s", name, val);
  50    new = name;
  51  } else {
  52    len = strlen(name);
  53    if (val) new = xmprintf("%s=%s", name, val);
  54  }
  55
  56  envc = toys.envc-1;  // compensate for size +1 above
  57  for (i = 0; environ[i]; i++) {
  58    // Drop old entry, freeing as appropriate. Assumes no duplicates.
  59    if (!memcmp(name, environ[i], len) && environ[i][len]=='=') {
  60      if (i>=envc) free(environ[i]);
  61      else {
  62        // move old entries down, add at end of old data
  63        toys.envc = envc--;
  64        for (; new ? i<envc : !!environ[i]; i++) environ[i] = environ[i+1];
  65        i = envc;
  66      }
  67      break;
  68    }
  69  }
  70
  71  if (!new) return;
  72
  73  // resize and null terminate if expanding
  74  if (!environ[i]) {
  75    len = i+1;
  76    if (!(len&255)) environ = xrealloc(environ, len*sizeof(char *));
  77    environ[len] = 0;
  78  }
  79  environ[i] = new;
  80}
  81
  82void xunsetenv(char *name)
  83{
  84  if (strchr(name, '=')) error_exit("xunsetenv %s name has =", name);
  85  xsetenv(name, 0);
  86}
  87
  88// reset environment for a user, optionally clearing most of it
  89void reset_env(struct passwd *p, int clear)
  90{
  91  int i;
  92
  93  if (clear) {
  94    char *s, *stuff[] = {"TERM", "DISPLAY", "COLORTERM", "XAUTHORITY"};
  95
  96    for (i=0; i<ARRAY_LEN(stuff); i++)
  97      stuff[i] = (s = getenv(stuff[i])) ? xmprintf("%s=%s", stuff[i], s) : 0;
  98    xclearenv();
  99    for (i=0; i < ARRAY_LEN(stuff); i++) if (stuff[i]) xsetenv(stuff[i], 0);
 100    if (chdir(p->pw_dir)) {
 101      perror_msg("chdir %s", p->pw_dir);
 102      xchdir("/");
 103    }
 104  } else {
 105    char **ev1, **ev2;
 106
 107    // remove LD_*, IFS, ENV, and BASH_ENV from environment
 108    for (ev1 = ev2 = environ;;) {
 109      while (*ev2 && (strstart(ev2, "LD_") || strstart(ev2, "IFS=") ||
 110        strstart(ev2, "ENV=") || strstart(ev2, "BASH_ENV="))) ev2++;
 111      if (!(*ev1++ = *ev2++)) break;
 112    }
 113  }
 114
 115  setenv("PATH", _PATH_DEFPATH, 1);
 116  setenv("HOME", p->pw_dir, 1);
 117  setenv("SHELL", p->pw_shell, 1);
 118  setenv("USER", p->pw_name, 1);
 119  setenv("LOGNAME", p->pw_name, 1);
 120}
 121