setenv() is not async-signal-safe and as such should not be used
between fork/exec of a multi-threaded app: if one thread is
manipulating the current environment (which may entail obtaining a
malloc() mutex) when another thread calls fork(), the resulting
child's attempt to use setenv() could deadlock or see a broken environ
because the thread owning the lock no longer exists to release it.
Besides, it is more efficient to update the environment exactly once
in the parent, rather than after every fork().
While at it, check for (unlikely) failure of setenv.
Signed-off-by: Eric Blake <eblake(a)redhat.com>
---
plugins/sh/call.c | 3 ---
plugins/sh/sh.c | 6 ++++++
2 files changed, 6 insertions(+), 3 deletions(-)
diff --git a/plugins/sh/call.c b/plugins/sh/call.c
index 871de5c6..9b8b48e2 100644
--- a/plugins/sh/call.c
+++ b/plugins/sh/call.c
@@ -127,9 +127,6 @@ call3 (const char *wbuf, size_t wbuflen, /* sent to stdin */
/* Restore SIGPIPE back to SIG_DFL, since shell can't undo SIG_IGN */
signal (SIGPIPE, SIG_DFL);
- /* Set $tmpdir for the script. */
- setenv ("tmpdir", tmpdir, 1);
-
execvp (argv[0], (char **) argv);
perror (argv[0]);
_exit (EXIT_FAILURE);
diff --git a/plugins/sh/sh.c b/plugins/sh/sh.c
index 737c38cf..e3d3c2f1 100644
--- a/plugins/sh/sh.c
+++ b/plugins/sh/sh.c
@@ -60,6 +60,12 @@ sh_load (void)
nbdkit_error ("mkdtemp: /tmp: %m");
exit (EXIT_FAILURE);
}
+ /* Set $tmpdir for the script. */
+ if (setenv ("tmpdir", tmpdir, 1) == -1) {
+ nbdkit_error ("setenv: tmpdir=%s: %m", tmpdir);
+ exit (EXIT_FAILURE);
+ }
+
nbdkit_debug ("sh: load: tmpdir: %s", tmpdir);
}
--
2.20.1