summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--stdlib/doc-syms.tl1
-rw-r--r--stream.c23
-rw-r--r--sysif.c20
-rw-r--r--sysif.h3
-rw-r--r--tests/018/process.tl14
-rw-r--r--txr.139
6 files changed, 95 insertions, 5 deletions
diff --git a/stdlib/doc-syms.tl b/stdlib/doc-syms.tl
index 9cc7068e..b51932ba 100644
--- a/stdlib/doc-syms.tl
+++ b/stdlib/doc-syms.tl
@@ -14,6 +14,7 @@
("*args*" "N-03DEE18A")
("*args-eff*" "N-03DEE18A")
("*args-full*" "N-03DEE18A")
+ ("*child-env*" "N-01BB2097")
("*doc-url*" "N-0003D10B")
("*filters*" "N-00E6A902")
("*gensym-counter*" "N-0387B1B1")
diff --git a/stream.c b/stream.c
index 10511ca7..95547e03 100644
--- a/stream.c
+++ b/stream.c
@@ -4516,8 +4516,12 @@ static val open_subprocess(val name, val mode_str, val args, val fun)
if (fun)
funcall(fun);
- if (argv)
+ if (argv) {
+ val ch_env = child_env;
+ if (ch_env != t)
+ replace_env(ch_env);
execvp(argv[0], argv);
+ }
_exit(errno);
} else {
int whichfd;
@@ -4747,6 +4751,7 @@ static val run(val command, val args)
val iter;
int i, nargs, status = 0;
struct save_fds sfds;
+ volatile val save_env, ch_env = child_env;
args = default_null_arg(args);
nargs = c_num(length(args), self) + 1;
@@ -4762,23 +4767,32 @@ static val run(val command, val args)
if (nargs < 0 || nargs == INT_MAX)
uw_throwf(error_s, lit("~a: argument list overflow"), self, nao);
+ if (ch_env != t) {
+ save_env = env();
+ replace_env(ch_env, nil);
+ }
+
wargv = coerce(const wchar_t **, chk_xalloc(nargs + 1, sizeof *wargv, self));
for (i = 0, iter = cons(command, args); iter; i++, iter = cdr(iter))
wargv[i] = c_str(car(iter), self);
wargv[i] = 0;
+ if (status == 0) {
#if HAVE_WSPAWN
- status = _wspawnvp(_P_WAIT, c_str(command, self), wargv);
+ status = _wspawnvp(_P_WAIT, c_str(command, self), wargv);
#else
- status = w_spawnvp(_P_WAIT, c_str(command, self), nargs, wargv);
+ status = w_spawnvp(_P_WAIT, c_str(command, self), nargs, wargv);
#endif
+ }
free(strip_qual(wchar_t **, wargv));
gc_hint(args);
uw_unwind {
+ if (ch_env != t)
+ replace_env(save_env, nil);
fds_restore(&sfds);
}
@@ -4833,7 +4847,10 @@ static val run(val name, val args)
}
if (pid == 0) {
+ val ch_env = child_env;
fds_clobber(&sfds, FDS_IN | FDS_OUT | FDS_ERR);
+ if (ch_env != t)
+ replace_env(ch_env);
execvp(argv[0], argv);
_exit(errno);
} else {
diff --git a/sysif.c b/sysif.c
index d1fefdce..6f4ad727 100644
--- a/sysif.c
+++ b/sysif.c
@@ -128,6 +128,8 @@ val atime_s, mtime_s, ctime_s;
val atime_nsec_s, mtime_nsec_s, ctime_nsec_s;
val path_s, dir_s, dirent_s;
+val child_env_s;
+
#if HAVE_PWUID || HAVE_GRGID
val passwd_s;
#endif
@@ -1173,7 +1175,9 @@ val exec_wrap(val file, val args_opt)
self, nao), convert(char **, 0)),
coerce(char **, chk_xalloc(nargs + 1, sizeof *argv, self)));
val iter;
- int i;
+ val ch_env = child_env;
+ val save_env = nil;
+ int res, i;
for (i = 0, iter = cons(file, args); iter; i++, iter = cdr(iter)) {
val arg = car(iter);
@@ -1181,7 +1185,17 @@ val exec_wrap(val file, val args_opt)
}
argv[i] = 0;
- if (execvp(argv[0], argv) < 0)
+ if (ch_env != t) {
+ save_env = env();
+ replace_env(ch_env);
+ }
+
+ res = execvp(argv[0], argv);
+
+ if (ch_env != t)
+ replace_env(save_env);
+
+ if (res < 0)
uw_ethrowf(process_error_s, lit("~s ~a: ~d/~s"),
self, file, num(errno), errno_to_str(errno), nao);
uw_throwf(process_error_s, lit("~s ~a returned"), self, file, nao);
@@ -2588,6 +2602,7 @@ void sysif_init(void)
len_s = intern(lit("len"), user_package);
pid_s = intern(lit("pid"), user_package);
#endif
+ child_env_s = intern(lit("*child-env*"), user_package);
dir_cls = cobj_register(dir_s);
@@ -2989,6 +3004,7 @@ void sysif_init(void)
reg_fun(intern(lit("setenv"), user_package), func_n3o(setenv_wrap, 2));
reg_fun(intern(lit("unsetenv"), user_package), func_n1(unsetenv_wrap));
#endif
+ reg_var(child_env_s, t);
#if HAVE_GETEUID
reg_fun(intern(lit("getuid"), user_package), func_n0(getuid_wrap));
diff --git a/sysif.h b/sysif.h
index 6dc150e2..2da92a32 100644
--- a/sysif.h
+++ b/sysif.h
@@ -36,6 +36,9 @@ extern val atime_s, mtime_s, ctime_s;
extern val atime_nsec_s, mtime_nsec_s, ctime_nsec_s;
extern val path_s;
+extern val child_env_s;
+#define child_env (deref(lookup_var_l(nil, child_env_s)))
+
val errno_to_file_error(int err);
val env(void);
val replace_env(val env_list);
diff --git a/tests/018/process.tl b/tests/018/process.tl
index 07ecfb64..a1970738 100644
--- a/tests/018/process.tl
+++ b/tests/018/process.tl
@@ -25,3 +25,17 @@
(mtest
(fcmd (let ((*stdout* *stdnull*)) (sh "echo foo"))) ""
(fcmd (let ((*stderr* *stdout*)) (sh "echo foo 1>&2"))) "foo\n")))
+
+(mtest
+ (let ((*child-env* '("a=b")))
+ (get-lines (open-process "/usr/bin/env" "r")))
+ ("a=b")
+ (let ((*child-env* nil))
+ (get-lines (open-process "/usr/bin/env" "r")))
+ nil)
+
+(test
+ (fcmd
+ (let ((*child-env* '("a=b")))
+ (run "/usr/bin/env")))
+ "a=b\n")
diff --git a/txr.1 b/txr.1
index dc8b6cf0..acda3fd2 100644
--- a/txr.1
+++ b/txr.1
@@ -66094,6 +66094,45 @@ the original environment can be restored by passing that retained
list to
.codn replace-env .
+.coNP Special variable @ *child-env*
+.desc
+The
+.code *child-env*
+variable specifies the list of command line variables established for programs
+executed via the functions
+.codn exec ,
+.codn run ,
+.codn sh ,
+.code open-command
+and
+.codn open-process .
+
+The initial top-level value of this variable is the symbol
+.code t
+which indicates that
+.code *child-env*
+is to be ignored, such that the executed program
+inherits the current set of environment variables.
+
+If
+.code *child-env*
+has any other value, it must be a possibly empty list of environment
+variables, in the same format as what is returned by
+.code env
+function and accepted by
+.codn replace-env .
+That value completely specifies the environment that executed programs
+shall receive.
+
+.TP* Example:
+
+.verb
+ (let ((*child-env* '("a=b")))
+ ;; /usr/bin/env sees only "a" environment variable
+ (get-lines (open-process "/usr/bin/env" "r")))
+ -> ("a=b")
+.brev
+
.SS* Command-Line-Option Processing
\*(TL provides a support for recognizing, extracting and validating