about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/tls/deps-lib/s6tls1
-rw-r--r--src/tls/s6-tlsc.c38
-rw-r--r--src/tls/s6-tlsd.c38
-rw-r--r--src/tls/s6-ucspitlsc.c17
-rw-r--r--src/tls/s6-ucspitlsd.c10
-rw-r--r--src/tls/s6tls-internal.h7
-rw-r--r--src/tls/s6tls_io_spawn.c104
-rw-r--r--src/tls/s6tls_prep_tlscio.c10
-rw-r--r--src/tls/s6tls_prep_tlsdio.c10
-rw-r--r--src/tls/s6tls_sync_and_exec_app.c3
10 files changed, 153 insertions, 85 deletions
diff --git a/src/tls/deps-lib/s6tls b/src/tls/deps-lib/s6tls
index 07ad2f2..0ad4767 100644
--- a/src/tls/deps-lib/s6tls
+++ b/src/tls/deps-lib/s6tls
@@ -1,4 +1,5 @@
 s6tls_clean_and_exec.o
+s6tls_io_spawn.o
 s6tls_prep_tlscio.o
 s6tls_prep_tlsdio.o
 s6tls_sync_and_exec_app.o
diff --git a/src/tls/s6-tlsc.c b/src/tls/s6-tlsc.c
index 26703ba..dddb093 100644
--- a/src/tls/s6-tlsc.c
+++ b/src/tls/s6-tlsc.c
@@ -4,44 +4,27 @@
 #include <unistd.h>
 #include <fcntl.h>
 
-#include <skalibs/gccattributes.h>
 #include <skalibs/types.h>
 #include <skalibs/sgetopt.h>
 #include <skalibs/strerr.h>
-#include <skalibs/env.h>
 #include <skalibs/djbunix.h>
-#include <skalibs/exec.h>
 
 #include "s6tls-internal.h"
 
 #define USAGE "s6-tlsc [ -S | -s ]  [ -Y | -y ] [ -v verbosity ] [ -K timeout ] [ -k servername ] [ -Z | -z ] [ -6 fdr ] [ -7 fdw ] prog..."
 #define dieusage() strerr_dieusage(100, USAGE)
 
-static void child (int const [4][2], uint32_t, unsigned int, unsigned int, char const *) gccattr_noreturn ;
-static void child (int const p[4][2], uint32_t options, unsigned int verbosity, unsigned int kimeout, char const *servername)
-{
-  char const *newargv[S6TLS_PREP_IO_ARGC] ;
-  char buf[S6TLS_PREP_IO_BUFLEN] ;
-  PROG = "s6-tlsc (child)" ;
-  close(p[2][0]) ;
-  close(p[0][1]) ;
-  close(p[1][0]) ;
-  if (fd_move(0, p[3][0]) == -1 || fd_move(1, p[3][1]) == -1)
-    strerr_diefu1sys(111, "move network fds to stdin/stdout") ;
-  s6tls_prep_tlscio(newargv, buf, p[0][0], p[1][1], p[2][1], options, verbosity, kimeout, servername) ;
-  xexec(newargv) ;
-}
-
 int main (int argc, char const *const *argv)
 {
   unsigned int verbosity = 1 ;
   unsigned int kimeout = 0 ;
-  int p[4][2] = { [3] = { 6, 7 } } ;
+  int p[4][2] = { [3] = { [0] = 6, [1] = 7 } } ;
   uint32_t coptions = 0 ;
   uint32_t poptions = 1 ;
   pid_t pid ;
   char const *servername = 0 ;
-
+  char const *newargv[S6TLS_PREP_IO_ARGC] ;
+  char buf[S6TLS_PREP_IO_BUFLEN] ;
   PROG = "s6-tlsc" ;
   {
     subgetopt l = SUBGETOPT_ZERO ;
@@ -80,18 +63,15 @@ int main (int argc, char const *const *argv)
     argc -= l.ind ; argv += l.ind ;
   }
   if (!argc) dieusage() ;
+
   fd_sanitize() ;
-  if (fcntl(p[3][0], F_GETFD) < 0 || fcntl(p[3][1], F_GETFD) < 0)
+  if (fcntl(p[3][0], F_GETFD) == -1 || fcntl(p[3][1], F_GETFD) == -1)
     strerr_diefu1sys(111, "check network fds") ;
 
-  if (pipe(p[0]) < 0 || pipe(p[1]) < 0 || pipe(p[2]) < 0)
+  if (pipe(p[0]) == -1 || pipe(p[1]) == -1 || pipe(p[2]) == -1)
     strerr_diefu1sys(111, "pipe") ;
-  pid = fork() ;
-  switch (pid)
-  {
-    case -1 : strerr_diefu1sys(111, "fork") ;
-    case 0 : child(p, coptions, verbosity, kimeout, servername) ;
-    default : break ;
-  }
+  s6tls_prep_tlscio(newargv, buf, p, coptions, verbosity, kimeout, servername) ;
+  pid = s6tls_io_spawn(newargv, p) ;
+  if (!pid) strerr_diefu2sys(111, "spawn ", newargv[0]) ;
   s6tls_sync_and_exec_app(argv, p, pid, poptions) ;
 }
diff --git a/src/tls/s6-tlsd.c b/src/tls/s6-tlsd.c
index c9ef5d2..07716ea 100644
--- a/src/tls/s6-tlsd.c
+++ b/src/tls/s6-tlsd.c
@@ -3,43 +3,27 @@
 #include <stdint.h>
 #include <unistd.h>
 
-#include <skalibs/gccattributes.h>
 #include <skalibs/types.h>
 #include <skalibs/sgetopt.h>
 #include <skalibs/strerr.h>
-#include <skalibs/env.h>
-#include <skalibs/djbunix.h>
-#include <skalibs/exec.h>
 
 #include "s6tls-internal.h"
 
 #define USAGE "s6-tlsd [ -S | -s ] [ -Y | -y ] [ -k snilevel ] [ -v verbosity ] [ -K timeout ] [ -Z | -z ] prog..."
 #define dieusage() strerr_dieusage(100, USAGE)
 
-static void child (int const [4][2], uint32_t, unsigned int, unsigned int, unsigned int) gccattr_noreturn ;
-static void child (int const p[4][2], uint32_t options, unsigned int verbosity, unsigned int kimeout, unsigned int snilevel)
-{
-  char const *newargv[S6TLS_PREP_IO_ARGC] ;
-  char buf[S6TLS_PREP_IO_BUFLEN] ;
-  PROG = "s6-tlsd (child)" ;
-  close(p[2][0]) ;
-  close(p[0][1]) ;
-  close(p[1][0]) ;
-  s6tls_prep_tlsdio(newargv, buf, p[0][0], p[1][1], p[2][1], options, verbosity, kimeout, snilevel) ;
-  xexec(newargv) ;
-}
-
 int main (int argc, char const *const *argv)
 {
   unsigned int verbosity = 1 ;
   unsigned int kimeout = 0 ;
   unsigned int snilevel = 0 ;
-  int p[4][2] = { [3] = { 0, 1 } } ;
+  int p[4][2] = { [3] = { [0] = -1, [1] = -1 } } ;
   uint32_t coptions = 0 ;
   uint32_t poptions = 1 ;
   pid_t pid ;
-
-  PROG = "s6-tlsd (parent)" ;
+  char const *newargv[S6TLS_PREP_IO_ARGC] ;
+  char buf[S6TLS_PREP_IO_BUFLEN] ;
+  PROG = "s6-tlsd" ;
   {
     subgetopt l = SUBGETOPT_ZERO ;
     for (;;)
@@ -64,14 +48,10 @@ int main (int argc, char const *const *argv)
   }
   if (!argc) dieusage() ;
 
-  if (pipe(p[0]) < 0 || pipe(p[1]) < 0 || pipe(p[2]) < 0)
-    strerr_diefu1sys(111, "pipe") ;
-  pid = fork() ;
-  switch (pid)
-  {
-    case -1 : strerr_diefu1sys(111, "fork") ;
-    case 0 : child(p, coptions, verbosity, kimeout, snilevel) ;
-    default : break ;
-  }
+  if (pipe(p[0]) == -1 || pipe(p[1]) == -1 || pipe(p[2]) == -1)
+    strerr_diefu1sys(111, "create pipe") ;
+  s6tls_prep_tlsdio(newargv, buf, p, coptions, verbosity, kimeout, snilevel) ;
+  pid = s6tls_io_spawn(newargv, p) ;
+  if (!pid) strerr_diefu2sys(111, "spawn ", newargv[0]) ;
   s6tls_sync_and_exec_app(argv, p, pid, poptions) ;
 }
diff --git a/src/tls/s6-ucspitlsc.c b/src/tls/s6-ucspitlsc.c
index 2d728b5..4f284b7 100644
--- a/src/tls/s6-ucspitlsc.c
+++ b/src/tls/s6-ucspitlsc.c
@@ -21,17 +21,16 @@
 static inline void child (int [4][2], uint32_t, unsigned int, unsigned int, char const *, pid_t) gccattr_noreturn ;
 static inline void child (int p[4][2], uint32_t options, unsigned int verbosity, unsigned int kimeout, char const *servername, pid_t pid)
 {
+  ssize_t r ;
   char const *newargv[S6TLS_PREP_IO_ARGC] ;
   char buf[S6TLS_PREP_IO_BUFLEN] ;
-  ssize_t r ;
   char c ;
   PROG = "s6-ucspitlsc" ;
   close(p[2][0]) ;
-  close(p[0][1]) ;
   close(p[1][0]) ;
+  close(p[0][1]) ;
   if (fd_move(0, p[3][0]) == -1 || fd_move(1, p[3][1]) == -1)
     strerr_diefu1sys(111, "move network fds to stdin/stdout") ;
-  s6tls_prep_tlscio(newargv, buf, p[0][0], p[1][1], p[2][1], options, verbosity, kimeout, servername) ;
   r = read(p[2][1], &c, 1) ;
   if (r < 0) strerr_diefu1sys(111, "read from control socket") ;
   if (!r)
@@ -48,7 +47,7 @@ static inline void child (int p[4][2], uint32_t options, unsigned int verbosity,
   {
     case 'y' :
       close(p[2][1]) ;
-      p[2][1] = 0 ; /* we know 0 is open so it's a correct invalid value */
+      p[2][1] = 0 ; /* we know 0 is open so it's a suitable invalid value */
       break ;
     case 'Y' :
       fd_shutdown(p[2][1], 0) ;
@@ -56,6 +55,7 @@ static inline void child (int p[4][2], uint32_t options, unsigned int verbosity,
     default :
       strerr_dief1x(100, "unrecognized command on control socket") ;
   }
+  s6tls_prep_tlscio(newargv, buf, p, options, verbosity, kimeout, servername) ;
   if (verbosity >= 2)
   {
     char fmt[PID_FMT] ;
@@ -69,7 +69,7 @@ int main (int argc, char const *const *argv, char const *const *envp)
 {
   unsigned int verbosity = 1 ;
   unsigned int kimeout = 0 ;
-  int p[4][2] = { [3] = { 6, 7 } } ;
+  int p[4][2] = { [3] = { [0] = 6, [1] = 7 } } ;
   uint32_t coptions = 0 ;
   uint32_t poptions = 1 ;
   char const *servername = 0 ;
@@ -114,12 +114,13 @@ int main (int argc, char const *const *argv, char const *const *envp)
   }
   if (!argc) dieusage() ;
   fd_sanitize() ;
-  if (fcntl(p[3][0], F_GETFD) < 0 || fcntl(p[3][1], F_GETFD) < 0)
+  if (fcntl(p[3][0], F_GETFD) == -1 || fcntl(p[3][1], F_GETFD) == -1)
     strerr_diefu1sys(111, "check network fds") ;
 
-  if (ipc_pair_b(p[2]) < 0) strerr_diefu1sys(111, "ipc_pair") ;
-  if (pipe(p[0]) < 0 || pipe(p[1]) < 0) strerr_diefu1sys(111, "pipe") ;
+  if (ipc_pair_b(p[2]) == -1) strerr_diefu1sys(111, "ipc_pair") ;
+  if (pipe(p[0]) == -1 || pipe(p[1]) == -1) strerr_diefu1sys(111, "pipe") ;
   pid = getpid() ;
+
   switch (fork())
   {
     case -1 : strerr_diefu1sys(111, "fork") ;
diff --git a/src/tls/s6-ucspitlsd.c b/src/tls/s6-ucspitlsd.c
index ecce9d5..92450e3 100644
--- a/src/tls/s6-ucspitlsd.c
+++ b/src/tls/s6-ucspitlsd.c
@@ -20,15 +20,14 @@
 static inline void child (int [4][2], uint32_t, unsigned int, unsigned int, unsigned int, pid_t) gccattr_noreturn ;
 static inline void child (int p[4][2], uint32_t options, unsigned int verbosity, unsigned int kimeout, unsigned int snilevel, pid_t pid)
 {
+  ssize_t r ;
   char const *newargv[S6TLS_PREP_IO_ARGC] ;
   char buf[S6TLS_PREP_IO_BUFLEN] ;
-  ssize_t r ;
   char c ;
   PROG = "s6-ucspitlsd" ;
   close(p[2][0]) ;
   close(p[0][1]) ;
   close(p[1][0]) ;
-  s6tls_prep_tlsdio(newargv, buf, p[0][0], p[1][1], p[2][1], options, verbosity, kimeout, snilevel) ;
   r = read(p[2][1], &c, 1) ;
   if (r < 0) strerr_diefu1sys(111, "read from control socket") ;
   if (!r)
@@ -53,6 +52,7 @@ static inline void child (int p[4][2], uint32_t options, unsigned int verbosity,
     default :
       strerr_dief1x(100, "unrecognized command on control socket") ;
   }
+  s6tls_prep_tlsdio(newargv, buf, p, options, verbosity, kimeout, snilevel) ;
   if (verbosity >= 2)
   {
     char fmt[PID_FMT] ;
@@ -67,7 +67,7 @@ int main (int argc, char const *const *argv)
   unsigned int verbosity = 1 ;
   unsigned int kimeout = 0 ;
   unsigned int snilevel = 0 ;
-  int p[4][2] = { [3] = { 0, 1 } } ;
+  int p[4][2] = { [3] = { [0] = -1, [1] = -1 } } ;
   uint32_t coptions = 0 ;
   uint32_t poptions = 1 ;
   pid_t pid ;
@@ -97,8 +97,8 @@ int main (int argc, char const *const *argv)
   }
   if (!argc) dieusage() ;
 
-  if (ipc_pair_b(p[2]) < 0) strerr_diefu1sys(111, "ipc_pair") ;
-  if (pipe(p[0]) < 0 || pipe(p[1]) < 0) strerr_diefu1sys(111, "pipe") ;
+  if (ipc_pair_b(p[2]) == -1) strerr_diefu1sys(111, "ipc_pair") ;
+  if (pipe(p[0]) == -1 || pipe(p[1]) == -1) strerr_diefu1sys(111, "pipe") ;
   pid = getpid() ;
 
   switch (fork())
diff --git a/src/tls/s6tls-internal.h b/src/tls/s6tls-internal.h
index cd96e87..2870744 100644
--- a/src/tls/s6tls-internal.h
+++ b/src/tls/s6tls-internal.h
@@ -3,7 +3,7 @@
 #ifndef S6TLS_INTERNAL_H
 #define S6TLS_INTERNAL_H
 
-#include <stddef.h>
+#include <sys/types.h>
 #include <stdint.h>
 
 #include <skalibs/gccattributes.h>
@@ -12,8 +12,9 @@
 #define S6TLS_PREP_IO_ARGC 15
 #define S6TLS_PREP_IO_BUFLEN (5 * UINT_FMT)
 
-extern void s6tls_prep_tlscio (char const **, char *, int, int, int, uint32_t, unsigned int, unsigned int, char const *) ;
-extern void s6tls_prep_tlsdio (char const **, char *, int, int, int, uint32_t, unsigned int, unsigned int, unsigned int) ;
+extern pid_t s6tls_io_spawn (char const *const *argv, int const [4][2]) ;
+extern void s6tls_prep_tlscio (char const **, char *, int const [4][2], uint32_t, unsigned int, unsigned int, char const *) ;
+extern void s6tls_prep_tlsdio (char const **, char *, int const [4][2], uint32_t, unsigned int, unsigned int, unsigned int) ;
 extern void s6tls_sync_and_exec_app (char const *const *, int const [4][2], pid_t, uint32_t) gccattr_noreturn ;
 extern void s6tls_ucspi_exec_app (char const *const *, int const [4][2], uint32_t) gccattr_noreturn ;
 extern void s6tls_clean_and_exec (char const *const *, uint32_t, char const *, size_t) gccattr_noreturn ;
diff --git a/src/tls/s6tls_io_spawn.c b/src/tls/s6tls_io_spawn.c
new file mode 100644
index 0000000..e2d589a
--- /dev/null
+++ b/src/tls/s6tls_io_spawn.c
@@ -0,0 +1,104 @@
+/* ISC license. */
+
+#include <skalibs/sysdeps.h>
+
+#include <skalibs/djbunix.h>
+
+#include "s6tls-internal.h"
+
+#ifdef SKALIBS_HASPOSIXSPAWN
+
+#include <errno.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <spawn.h>
+
+#include <skalibs/config.h>
+#include <skalibs/posixplz.h>
+
+pid_t s6tls_io_spawn (char const *const *argv, int const p[4][2])
+{
+  pid_t pid ;
+  posix_spawn_file_actions_t actions ;
+  int e ;
+  int nopath = !getenv("PATH") ;
+#ifdef SKALIBS_HASPOSIXSPAWNEARLYRETURN
+  int eep[2] ;
+  if (pipecoe(eep) == -1) return 0 ;
+#endif
+  e = posix_spawn_file_actions_init(&actions) ;
+  if (e) goto err ;
+  e = posix_spawn_file_actions_addclose(&actions, p[0][1]) ;
+  if (e) goto erractions ;
+  e = posix_spawn_file_actions_addclose(&actions, p[1][0]) ;
+  if (e) goto erractions ;
+  e = posix_spawn_file_actions_addclose(&actions, p[2][0]) ;
+  if (e) goto erractions ;
+  if (p[3][0] >= 0)
+  {
+    e = posix_spawn_file_actions_adddup2(&actions, p[3][0], 0) ;
+    if (e) goto erractions ;
+    e = posix_spawn_file_actions_addclose(&actions, p[3][0]) ;
+    if (e) goto erractions ;
+  }
+  if (p[3][1] >= 0)
+  {
+    e = posix_spawn_file_actions_adddup2(&actions, p[3][1], 1) ;
+    if (e) goto erractions ;
+    e = posix_spawn_file_actions_addclose(&actions, p[3][1]) ;
+    if (e) goto erractions ;
+  }
+
+  if (nopath && (setenv("PATH", SKALIBS_DEFAULTPATH, 0) < 0)) { e = errno ; goto erractions ; }
+  e = posix_spawnp(&pid, argv[0], &actions, 0, (char *const *)argv, environ) ;
+  if (nopath) unsetenv("PATH") ;
+  if (e) goto erractions ;
+
+  posix_spawn_file_actions_destroy(&actions) ;
+#ifdef SKALIBS_HASPOSIXSPAWNEARLYRETURN
+  return child_spawn_workaround(pid, eep) ;
+#else
+  return pid ;
+#endif
+
+ erractions:
+  posix_spawn_file_actions_destroy(&actions) ;
+ err:
+#ifdef SKALIBS_HASPOSIXSPAWNEARLYRETURN
+  fd_close(eep[1]) ;
+  fd_close(eep[0]) ;
+#endif
+  errno = e ;
+  return 0 ;
+}
+
+#else
+
+#include <string.h>
+
+#include <skalibs/strerr.h>
+#include <skalibs/exec.h>
+
+pid_t s6tls_io_spawn (char const *const *argv, int const p[4][2])
+{
+  pid_t pid = fork() ;
+  if (pid == -1) return 0 ;
+  if (!pid)
+  {
+    size_t proglen = strlen(PROG) ;
+    char newprog[proglen + 9] ;
+    memcpy(newprog, PROG, proglen) ;
+    memcpy(newprog, " (child)", 9) ;
+    PROG = newprog ;
+    fd_close(p[0][1]) ;
+    fd_close(p[1][0]) ;
+    fd_close(p[2][0]) ;
+    if ((p[3][0] >= 0 && fd_move(0, p[3][0]) == -1)
+     || (p[3][1] >= 0 && fd_move(1, p[3][1]) == -1))
+      strerr_diefu1sys(111, "move network fds to stdin/stdout") ;
+    xexec(argv) ;
+  }
+  return pid ;
+}
+
+#endif
diff --git a/src/tls/s6tls_prep_tlscio.c b/src/tls/s6tls_prep_tlscio.c
index cf44511..1d25f65 100644
--- a/src/tls/s6tls_prep_tlscio.c
+++ b/src/tls/s6tls_prep_tlscio.c
@@ -5,7 +5,7 @@
 #include <s6-networking/config.h>
 #include "s6tls-internal.h"
 
-void s6tls_prep_tlscio (char const **argv, char *buf, int fdr, int fdw, int fdnotif, uint32_t options, unsigned int verbosity, unsigned int kimeout, char const *servername)
+void s6tls_prep_tlscio (char const **argv, char *buf, int const p[4][2], uint32_t options, unsigned int verbosity, unsigned int kimeout, char const *servername)
 {
   size_t m = 0 ;
   size_t n = 0 ;
@@ -18,11 +18,11 @@ void s6tls_prep_tlscio (char const **argv, char *buf, int fdr, int fdw, int fdno
     n += uint_fmt(buf + n, verbosity) ;
     buf[n++] = 0 ;
   }
-  if (fdnotif)
+  if (p[2][1])
   {
     argv[m++] = "-d" ;
     argv[m++] = buf + n ;
-    n += uint_fmt(buf + n, fdnotif) ;
+    n += uint_fmt(buf + n, p[2][1]) ;
     buf[n++] = 0 ;
   }
   argv[m++] = options & 4 ? "-S" : "-s" ;
@@ -41,10 +41,10 @@ void s6tls_prep_tlscio (char const **argv, char *buf, int fdr, int fdw, int fdno
   }
   argv[m++] = "--" ;
   argv[m++] = buf + n ;
-  n += uint_fmt(buf + n, fdr) ;
+  n += uint_fmt(buf + n, p[0][0]) ;
   buf[n++] = 0 ;
   argv[m++] = buf + n ;
-  n += uint_fmt(buf + n, fdw) ;
+  n += uint_fmt(buf + n, p[1][1]) ;
   buf[n++] = 0 ;
   argv[m++] = 0 ;
 }
diff --git a/src/tls/s6tls_prep_tlsdio.c b/src/tls/s6tls_prep_tlsdio.c
index 942425b..947cf70 100644
--- a/src/tls/s6tls_prep_tlsdio.c
+++ b/src/tls/s6tls_prep_tlsdio.c
@@ -5,7 +5,7 @@
 #include <s6-networking/config.h>
 #include "s6tls-internal.h"
 
-void s6tls_prep_tlsdio (char const **argv, char *buf, int fdr, int fdw, int fdnotif, uint32_t options, unsigned int verbosity, unsigned int kimeout, unsigned int snilevel)
+void s6tls_prep_tlsdio (char const **argv, char *buf, int const p[4][2], uint32_t options, unsigned int verbosity, unsigned int kimeout, unsigned int snilevel)
 {
   size_t m = 0 ;
   size_t n = 0 ;
@@ -18,11 +18,11 @@ void s6tls_prep_tlsdio (char const **argv, char *buf, int fdr, int fdw, int fdno
     n += uint_fmt(buf + n, verbosity) ;
     buf[n++] = 0 ;
   }
-  if (fdnotif)
+  if (p[2][1])
   {
     argv[m++] = "-d" ;
     argv[m++] = buf + n ;
-    n += uint_fmt(buf + n, fdnotif) ;
+    n += uint_fmt(buf + n, p[2][1]) ;
     buf[n++] = 0 ;
   }
   argv[m++] = options & 4 ? "-S" : "-s" ;
@@ -44,10 +44,10 @@ void s6tls_prep_tlsdio (char const **argv, char *buf, int fdr, int fdw, int fdno
   }
   argv[m++] = "--" ;
   argv[m++] = buf + n ;
-  n += uint_fmt(buf + n, fdr) ;
+  n += uint_fmt(buf + n, p[0][0]) ;
   buf[n++] = 0 ;
   argv[m++] = buf + n ;
-  n += uint_fmt(buf + n, fdw) ;
+  n += uint_fmt(buf + n, p[1][1]) ;
   buf[n++] = 0 ;
   argv[m++] = 0 ;
 }
diff --git a/src/tls/s6tls_sync_and_exec_app.c b/src/tls/s6tls_sync_and_exec_app.c
index dc16e9d..3fdd21c 100644
--- a/src/tls/s6tls_sync_and_exec_app.c
+++ b/src/tls/s6tls_sync_and_exec_app.c
@@ -16,7 +16,8 @@ void s6tls_sync_and_exec_app (char const *const *argv, int const p[4][2], pid_t
   close(p[2][1]) ;
   close(p[1][1]) ;
   close(p[0][0]) ;
-  if (fd_move(p[3][0], p[1][0]) < 0 || fd_move(p[3][1], p[0][1]) < 0)
+  if ((p[3][0] >= 0 && fd_move(p[3][0], p[1][0]) == -1)
+   || (p[3][1] >= 0 && fd_move(p[3][1], p[0][1]) == -1))
     strerr_diefu1sys(111, "move file descriptors") ;
   r = read(p[2][0], buf, MAXENVSIZE) ;
   if (r < 0) strerr_diefu1sys(111, "read from handshake notification pipe") ;