env.c 3.9 KB

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