bug-make
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH 2/2] job.c: implementing child_execute_job() using posix_spawn(),


From: Aron Barath
Subject: [PATCH 2/2] job.c: implementing child_execute_job() using posix_spawn(), and use it if present
Date: Mon, 9 Jul 2018 09:05:31 +0200

---
 src/job.c | 166 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 166 insertions(+)

diff --git a/src/job.c b/src/job.c
index 47ce73d..1c94d4a 100644
--- a/src/job.c
+++ b/src/job.c
@@ -137,6 +137,10 @@ extern int wait3 ();
 # endif /* Have wait3.  */
 #endif /* Have waitpid.  */
 
+#ifdef HAVE_SPAWN_H
+# include <spawn.h>
+#endif /* have spawn.h */
+
 #if !defined (wait) && !defined (POSIX)
 int wait ();
 #endif
@@ -2240,6 +2244,11 @@ child_execute_job (struct output *out, int good_stdin, 
char **argv, char **envp)
   int fderr = FD_STDERR;
   int r;
   pid_t pid;
+#if HAVE_POSIX_SPAWN
+  short flags = 0;
+  posix_spawnattr_t attr;
+  posix_spawn_file_actions_t fa;
+#endif /* have posix_spawn() */
 
   /* Divert child output if we want to capture it.  */
   if (out && out->syncout)
@@ -2250,6 +2259,9 @@ child_execute_job (struct output *out, int good_stdin, 
char **argv, char **envp)
         fderr = out->err;
     }
 
+#if ! HAVE_POSIX_SPAWN
+  /* does not have posix_spawn() */
+
   pid = vfork();
   if (pid != 0)
     return pid;
@@ -2274,6 +2286,160 @@ child_execute_job (struct output *out, int good_stdin, 
char **argv, char **envp)
 
   /* Run the command.  */
   exec_command (argv, envp);
+
+#else /* have posix_spawn() */
+
+  if (posix_spawnattr_init (&attr) != 0)
+    return -1;
+
+  if (posix_spawn_file_actions_init (&fa) != 0) {
+    posix_spawnattr_destroy (&attr);
+    return -1;
+
+  error:;
+    posix_spawn_file_actions_destroy (&fa);
+    posix_spawnattr_destroy (&attr);
+    return -1;
+  }
+
+  /* Unblock all signals.  */
+#ifdef HAVE_POSIX_SPAWNATTR_SETSIGMASK
+  {
+    sigset_t mask;
+    sigemptyset (&mask);
+    if (posix_spawnattr_setsigmask (&attr, &mask) != 0)
+      goto error;
+    flags |= POSIX_SPAWN_SETSIGMASK;
+  }
+#endif /* have posix_spawnattr_setsigmask() */
+
+#ifdef SET_STACK_SIZE
+  /* Do not bother about stack limit.  */
+#endif
+
+  /* For any redirected FD, dup2() it to the standard FD.
+     They are all marked close-on-exec already.  */
+  if (fdin >= 0 && fdin != FD_STDIN)
+    if (posix_spawn_file_actions_adddup2 (&fa, fdin, FD_STDIN) != 0)
+      goto error;
+  if (fdout != FD_STDOUT)
+    if (posix_spawn_file_actions_adddup2 (&fa, fdout, FD_STDOUT) != 0)
+      goto error;
+  if (fderr != FD_STDERR)
+    if (posix_spawn_file_actions_adddup2 (&fa, fderr, FD_STDERR) != 0)
+      goto error;
+
+  /* -------- Here start the replacement for exec_command() */
+
+  /* Be the user, permanently.  */
+  flags |= POSIX_SPAWN_RESETIDS;
+
+  /* Apply the spawn flags.  */
+  if (posix_spawnattr_setflags(&attr, flags) != 0)
+    goto error;
+
+  /* Run the program.  */
+  r = posix_spawnp(&pid, argv[0], &fa, &attr, argv, envp);
+  if (r == 0) {
+    posix_spawn_file_actions_destroy (&fa);
+    posix_spawnattr_destroy (&attr);
+    return pid;
+  }
+
+  errno = r; /* for later perror()s */
+  switch (r)
+    {
+    case ENOENT:
+      /* We are in the child: don't use the output buffer.
+         It's not right to run fprintf() here!  */
+      if (makelevel == 0)
+        fprintf (stderr, _("%s: %s: Command not found\n"), program, argv[0]);
+      else
+        fprintf (stderr, _("%s[%u]: %s: Command not found\n"),
+                 program, makelevel, argv[0]);
+      break;
+    case ENOEXEC:
+      {
+        /* The file is not executable.  Try it as a shell script.  */
+        const char *shell;
+        char **new_argv;
+        int argc;
+        int i=1;
+
+# ifdef __EMX__
+        /* Do not use $SHELL from the environment */
+        struct variable *p = lookup_variable ("SHELL", 5);
+        if (p)
+          shell = p->value;
+        else
+          shell = 0;
+# else
+        shell = getenv ("SHELL");
+# endif
+        if (shell == 0)
+          shell = default_shell;
+
+        argc = 1;
+        while (argv[argc] != 0)
+          ++argc;
+
+# ifdef __EMX__
+        if (!unixy_shell)
+          ++argc;
+# endif
+
+        new_argv = alloca ((1 + argc + 1) * sizeof (char *));
+        new_argv[0] = (char *)shell;
+
+# ifdef __EMX__
+        if (!unixy_shell)
+          {
+            new_argv[1] = "/c";
+            ++i;
+            --argc;
+          }
+# endif
+
+        new_argv[i] = argv[0];
+        while (argc > 0)
+          {
+            new_argv[i + argc] = argv[argc];
+            --argc;
+          }
+
+        r = posix_spawnp(&pid, shell, &fa, &attr, new_argv, envp);
+        if (r == 0) {
+          posix_spawn_file_actions_destroy (&fa);
+          posix_spawnattr_destroy (&attr);
+          return pid;
+        }
+
+        errno = r; /* for later perror()s */
+        if (errno == ENOENT)
+          OS (error, NILF, _("%s: Shell program not found"), shell);
+        else
+          perror_with_name ("execvp: ", shell);
+        break;
+      }
+
+# ifdef __EMX__
+    case EINVAL:
+      /* this nasty error was driving me nuts :-( */
+      O (error, NILF, _("spawnvpe: environment space might be exhausted"));
+      /* FALLTHROUGH */
+# endif
+
+    default:
+      perror_with_name ("execvp: ", argv[0]);
+      break;
+    }
+
+  /* We could not spawn our program. Let's clean up, and exit.  */
+  posix_spawn_file_actions_destroy (&fa);
+  posix_spawnattr_destroy (&attr);
+  return -1;
+
+#endif /* have posix_spawn() */
 }
 #endif /* !AMIGA && !__MSDOS__ && !VMS */
 #endif /* !WINDOWS32 */
-- 
2.18.0




reply via email to

[Prev in Thread] Current Thread [Next in Thread]