1 /* env.c - manipulate environment and execute a program
2 in that environment
3 Mly 861126
4
5 Copyright (C) 1986 Free Software Foundation, Inc.
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 1, or (at your option)
10 any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20
21 In other words, you are welcome to use, share and improve this program.
22 You are forbidden to forbid anyone else to use, share and improve
23 what you give them. Help stamp out software-hoarding! */
24
25 /*
26
27 If first argument is "-", then a new environment is constructed
28 from scratch; otherwise the environment is inherited from the parent
29 process, except as modified by other options.
30
31 So, "env - foo" will invoke the "foo" program in a null environment,
32 whereas "env foo" would invoke "foo" in the same environment as that
33 passed to "env" itself.
34
35 Subsequent arguments are interpreted as follows:
36
37 * "variable=value" (ie an arg containing a "=" character)
38 means to set the specified environment variable to that value.
39 `value' may be of zero length ("variable="). Note that setting
40 a variable to a zero-length value is different from unsetting it.
41
42 * "-u variable" or "-unset variable"
43 means to unset that variable
44 If that variable isn't set, does nothing.
45
46 * "-s variable value" or "-set variable value"
47 same as "variable=value"
48
49 * "-" or "--"
50 are used to indicate that the following argument is the program
51 to invoke. This is only necessary when the program's name
52 begins with "-" or contains a "="
53
54 * anything else
55 The first remaining argument specifies a program to invoke
56 (it is searched for according to the specification of the PATH
57 environment variable) and any arguments following that are
58 passed as arguments to that program
59
60 If no program-name is specified following the environment
61 specifications the the resulting environment is printed
62 (The is like specifying a program-name of "printenv")
63
64 Examples:
65 If the environment passed to "env" is
66 { USER=rms EDITOR=emacs PATH=.:/gnubin:/hacks }
67
68 * "env DISPLAY=gnu:0 nemacs"
69 calls "nemacs" in the envionment
70 { EDITOR=emacs USER=rms DISPLAY=gnu }
71
72 * "env - USER=foo /hacks/hack bar baz"
73 will call the "hack" program on arguments "bar" and "baz"
74 in an environment in which the only variable is "USER"
75 Note that the "-" option will clear out the PATH variable,
76 so one should be careful to specify in which directory
77 to find the program to call
78
79 * "env -u EDITOR USER=foo PATH=/energy -- e=mc2 bar baz"
80 The program "/energy/e=mc2" is called with environment
81 { USER=foo PATH=/energy }
82
83 */
84
85 #ifdef EMACS
86 #define NO_SHORTNAMES
87 #include "../src/config.h"
88 #endif /* EMACS */
89
90 #include <stdio.h>
91 #include <errno.h>
92
93 extern int execvp ();
94 extern char *index ();
95
96 char *xmalloc (), *xrealloc ();
97 char *concat ();
98
99 extern char **environ;
100
101 char **nenv;
102 int nenv_size;
103
104 char *progname;
105 void setenv ();
106 void fatal ();
107
main(argc,argv,envp)108 main (argc, argv, envp)
109 register int argc;
110 register char **argv;
111 char **envp;
112 {
113 register char *tem;
114
115 progname = argv[0];
116 argc--;
117 argv++;
118
119 nenv_size = 100;
120 nenv = (char **) xmalloc (nenv_size * sizeof (char *));
121 *nenv = (char *) 0;
122
123 /* "-" flag means to not inherit parent's environment */
124 if (argc && !strcmp (*argv, "-"))
125 {
126 argc--;
127 argv++;
128 }
129 else
130 /* Else pass on existing env vars. */
131 for (; *envp; envp++)
132 {
133 tem = index (*envp, '=');
134 if (tem)
135 {
136 *tem = '\000';
137 setenv (*envp, tem + 1);
138 }
139 }
140
141 while (argc > 0)
142 {
143 tem = index (*argv, '=');
144 if (tem)
145 /* If arg contains a "=" it specifies to set a variable */
146 {
147 *tem = '\000';
148 setenv (*argv, tem + 1);
149 argc--; argv++;
150 continue;
151 }
152
153 if (**argv != '-')
154 /* Remaining args are program name and args to pass it */
155 break;
156
157 if (argc < 2)
158 fatal ("No argument following \"%s\" switch", *argv);
159 if (!strcmp (*argv, "-u") ||
160 !strcmp (*argv, "-unset"))
161 /* Unset a variable */
162 {
163 argc--; argv++;
164 setenv (*argv, 0);
165 argc--; argv++;
166 }
167 else if (!strcmp (*argv, "-s") ||
168 !strcmp (*argv, "-set"))
169 /* Set a variable */
170 {
171 argc--; argv++;
172 tem = *argv;
173 if (argc < 2)
174 fatal ("No value specified for variable \"%s\"",
175 tem);
176 argc--; argv++;
177 setenv (tem, *argv);
178 argc--; argv++;
179 }
180 else if (!strcmp (*argv, "-") || !strcmp (*argv, "--"))
181 {
182 argc--; argv++;
183 break;
184 }
185 else
186 {
187 fatal ("unknown switch \"%s\"", *argv);
188 }
189 }
190
191 /* If no program specified print the environment and exit */
192 if (argc <= 0)
193 {
194 while (*nenv)
195 printf ("%s\n", *nenv++);
196 exit (0);
197 }
198 else
199 {
200 #ifndef BSD4_4
201 extern int errno, sys_nerr;
202 extern char *sys_errlist[];
203 #endif
204
205 environ = nenv;
206 (void) execvp (*argv, argv);
207
208 fprintf (stderr, "%s: Cannot execute \"%s\"",
209 progname, *argv);
210 if (errno < sys_nerr)
211 fprintf (stderr, ": %s\n" , sys_errlist[errno]);
212 else
213 putc ('\n', stderr);
214 exit (errno != 0 ? errno : 1);
215 }
216 }
217
218 void
setenv(var,val)219 setenv (var, val)
220 register char *var, *val;
221 {
222 register char **e;
223 int len = strlen (var);
224
225 {
226 register char *tem = index (var, '=');
227 if (tem)
228 fatal ("Environment variable names may not contain \"=\": %s",
229 var);
230 else if (*var == '\000')
231 fatal ("Zero-length environment variable name specified.");
232 }
233
234 for (e = nenv; *e; e++)
235 if (!strncmp (var, *e, len) &&
236 (*e)[len] == '=')
237 {
238 if (val)
239 goto set;
240 else
241 do { *e = *(e + 1); } while (*e++);
242 return;
243 }
244
245 if (!val)
246 return; /* Nothing to unset */
247
248 len = e - nenv;
249 if (len + 1 >= nenv_size)
250 {
251 nenv_size += 100;
252 nenv = (char **) xrealloc (nenv, nenv_size * sizeof (char *));
253 e = nenv + len;
254 }
255
256 set:
257 val = concat (var, "=", val);
258 if (*e)
259 free (*e);
260 else
261 *(e + 1) = (char *) 0;
262 *e = val;
263 return;
264 }
265
266 void
fatal(msg,arg1,arg2)267 fatal (msg, arg1, arg2)
268 char *msg, *arg1, *arg2;
269 {
270 fprintf (stderr, "%s: ", progname);
271 fprintf (stderr, msg, arg1, arg2);
272 putc ('\n', stderr);
273 exit (1);
274 }
275
276
277 extern char *malloc (), *realloc ();
278
279 void
memory_fatal()280 memory_fatal ()
281 {
282 fatal ("Out of memory");
283 }
284
285 char *
xmalloc(size)286 xmalloc (size)
287 int size;
288 {
289 register char *value;
290 value = (char *) malloc (size);
291 if (!value) memory_fatal ();
292 return (value);
293 }
294
295 char *
xrealloc(ptr,size)296 xrealloc (ptr, size)
297 char *ptr;
298 int size;
299 {
300 register char *value;
301 value = (char *) realloc (ptr, size);
302 if (!value) memory_fatal ();
303 return (value);
304 }
305
306 /* Return a newly-allocated string whose contents concatenate those of s1, s2, s3. */
307
308 char *
concat(s1,s2,s3)309 concat (s1, s2, s3)
310 char *s1, *s2, *s3;
311 {
312 int len1 = strlen (s1), len2 = strlen (s2), len3 = strlen (s3);
313 char *result = (char *) xmalloc (len1 + len2 + len3 + 1);
314
315 strcpy (result, s1);
316 strcpy (result + len1, s2);
317 strcpy (result + len1 + len2, s3);
318 *(result + len1 + len2 + len3) = 0;
319
320 return result;
321 }
322
323
324 /*
325 * Local variables:
326 * compile-command: "cc -g -o env env.c"
327 * end:
328 */
329