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