summaryrefslogtreecommitdiff
path: root/usr/src/lib/libast/common/comp/spawnveg.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/lib/libast/common/comp/spawnveg.c')
-rw-r--r--usr/src/lib/libast/common/comp/spawnveg.c270
1 files changed, 270 insertions, 0 deletions
diff --git a/usr/src/lib/libast/common/comp/spawnveg.c b/usr/src/lib/libast/common/comp/spawnveg.c
new file mode 100644
index 0000000000..fd6768c6b9
--- /dev/null
+++ b/usr/src/lib/libast/common/comp/spawnveg.c
@@ -0,0 +1,270 @@
+/***********************************************************************
+* *
+* This software is part of the ast package *
+* Copyright (c) 1985-2007 AT&T Knowledge Ventures *
+* and is licensed under the *
+* Common Public License, Version 1.0 *
+* by AT&T Knowledge Ventures *
+* *
+* A copy of the License is available at *
+* http://www.opensource.org/licenses/cpl1.0.txt *
+* (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
+* *
+* Information and Software Systems Research *
+* AT&T Research *
+* Florham Park NJ *
+* *
+* Glenn Fowler <gsf@research.att.com> *
+* David Korn <dgk@research.att.com> *
+* Phong Vo <kpv@research.att.com> *
+* *
+***********************************************************************/
+#pragma prototyped
+
+/*
+ * spawnveg -- spawnve with process group or session control
+ *
+ * pgid <0 setsid() [session group leader]
+ * 0 nothing [retain session and process group]
+ * 1 setpgid(0,0) [process group leader]
+ * >1 setpgid(0,pgid) [join process group]
+ */
+
+#include <ast.h>
+
+#if _lib_spawnveg
+
+NoN(spawnveg)
+
+#else
+
+#if _lib_posix_spawn > 1 /* reports underlying exec() errors */
+
+#include <spawn.h>
+#include <error.h>
+#include <wait.h>
+
+pid_t
+spawnveg(const char* path, char* const argv[], char* const envv[], pid_t pgid)
+{
+ int err;
+ pid_t pid;
+ posix_spawnattr_t attr;
+
+ if (err = posix_spawnattr_init(&attr))
+ goto bad;
+ if (pgid)
+ {
+ if (pgid <= 1)
+ pgid = 0;
+ if (err = posix_spawnattr_setpgroup(&attr, pgid))
+ goto bad;
+ if (err = posix_spawnattr_setflags(&attr, POSIX_SPAWN_SETPGROUP))
+ goto bad;
+ }
+ if (err = posix_spawn(&pid, path, NiL, &attr, argv, envv ? envv : environ))
+ goto bad;
+ posix_spawnattr_destroy(&attr);
+#if _lib_posix_spawn < 2
+ if (waitpid(pid, &err, WNOHANG|WNOWAIT) == pid && EXIT_STATUS(err) == 127)
+ {
+ while (waitpid(pid, NiL, 0) == -1 && errno == EINTR);
+ if (!access(path, X_OK))
+ errno = ENOEXEC;
+ pid = -1;
+ }
+#endif
+ return pid;
+ bad:
+ errno = err;
+ return -1;
+}
+
+#else
+
+#if _lib_spawn_mode
+
+#include <process.h>
+
+#ifndef P_NOWAIT
+#define P_NOWAIT _P_NOWAIT
+#endif
+#ifndef P_DETACH
+#define P_DETACH _P_DETACH
+#endif
+
+pid_t
+spawnveg(const char* path, char* const argv[], char* const envv[], pid_t pgid)
+{
+ return spawnve(pgid ? P_DETACH : P_NOWAIT, path, argv, envv ? envv : environ);
+}
+
+#else
+
+#if _lib_spawn && _hdr_spawn && _mem_pgroup_inheritance
+
+#include <spawn.h>
+
+/*
+ * open-edition/mvs/zos fork+exec+(setpgid)
+ */
+
+pid_t
+spawnveg(const char* path, char* const argv[], char* const envv[], pid_t pgid)
+{
+ struct inheritance inherit;
+
+ inherit.flags = 0;
+ if (pgid)
+ {
+ inherit.flags |= SPAWN_SETGROUP;
+ inherit.pgroup = (pgid > 1) ? pgid : SPAWN_NEWPGROUP;
+ }
+ return spawn(path, 0, (int*)0, &inherit, (const char**)argv, (const char**)envv);
+}
+
+#else
+
+#include <error.h>
+#include <wait.h>
+#include <sig.h>
+#include <ast_vfork.h>
+
+#ifndef ENOSYS
+#define ENOSYS EINVAL
+#endif
+
+#if _lib_spawnve && _hdr_process
+#include <process.h>
+#if defined(P_NOWAIT) || defined(_P_NOWAIT)
+#undef _lib_spawnve
+#endif
+#endif
+
+#if !_lib_vfork
+#undef _real_vfork
+#endif
+
+/*
+ * fork+exec+(setsid|setpgid)
+ */
+
+pid_t
+spawnveg(const char* path, char* const argv[], char* const envv[], pid_t pgid)
+{
+#if _lib_fork || _lib_vfork
+ int n;
+ int m;
+ pid_t pid;
+ pid_t rid;
+#if _real_vfork
+ volatile int exec_errno;
+ volatile int* volatile exec_errno_ptr;
+#else
+ int err[2];
+#endif
+#endif
+
+#if 0
+ if (access(path, X_OK))
+ return -1;
+#endif
+ if (!envv)
+ envv = environ;
+#if _lib_spawnve
+#if _lib_fork || _lib_vfork
+ if (!pgid)
+#endif
+ return spawnve(path, argv, envv);
+#endif
+#if _lib_fork || _lib_vfork
+ n = errno;
+#if _real_vfork
+ exec_errno = 0;
+ exec_errno_ptr = &exec_errno;
+#else
+ if (pipe(err) < 0)
+ err[0] = -1;
+ else
+ {
+ fcntl(err[0], F_SETFD, FD_CLOEXEC);
+ fcntl(err[1], F_SETFD, FD_CLOEXEC);
+ }
+#endif
+ sigcritical(1);
+#if _lib_vfork
+ pid = vfork();
+#else
+ pid = fork();
+#endif
+ sigcritical(0);
+ if (!pid)
+ {
+ if (pgid < 0)
+ setsid();
+ else if (pgid > 0)
+ {
+ if (pgid == 1)
+ pgid = 0;
+ if (setpgid(0, pgid) < 0 && pgid && errno == EPERM)
+ setpgid(0, 0);
+ }
+ execve(path, argv, envv);
+#if _real_vfork
+ *exec_errno_ptr = errno;
+#else
+ if (err[0] != -1)
+ {
+ n = errno;
+ write(err[1], &n, sizeof(n));
+ }
+#endif
+ _exit(errno == ENOENT ? EXIT_NOTFOUND : EXIT_NOEXEC);
+ }
+ rid = pid;
+#if _real_vfork
+ if (pid != -1 && (m = *exec_errno_ptr))
+ {
+ while (waitpid(pid, NiL, 0) == -1 && errno == EINTR);
+ rid = pid = -1;
+ n = m;
+ }
+#else
+ if (pid != -1 && err[0] != -1)
+ {
+ close(err[1]);
+ if (read(err[0], &m, sizeof(m)) == sizeof(m) && m)
+ {
+ while (waitpid(pid, NiL, 0) == -1 && errno == EINTR);
+ rid = pid = -1;
+ n = m;
+ }
+ close(err[0]);
+ }
+#endif
+ if (pid != -1 && pgid > 0)
+ {
+ /*
+ * parent and child are in a race here
+ */
+
+ if (pgid == 1)
+ pgid = pid;
+ if (setpgid(pid, pgid) < 0 && pid != pgid && errno == EPERM)
+ setpgid(pid, pid);
+ }
+ errno = n;
+ return rid;
+#else
+ errno = ENOSYS;
+ return -1;
+#endif
+}
+
+#endif
+
+#endif
+
+#endif
+
+#endif