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 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 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 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 280 memory_fatal () 281 { 282 fatal ("Out of memory"); 283 } 284 285 char * 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 * 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 * 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