[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