- return __posix_spawnx(res, path, execv, fa, attr, argv, envp);
+ pid_t pid;
+ char stack[1024+PATH_MAX];
+ int ec=0, cs;
+ struct args args;
+
+ pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs);
+
+ args.path = path;
+ args.fa = fa;
+ args.attr = attr ? attr : &(const posix_spawnattr_t){0};
+ args.argv = argv;
+ args.envp = envp;
+ pthread_sigmask(SIG_BLOCK, SIGALL_SET, &args.oldmask);
+
+ /* The lock guards both against seeing a SIGABRT disposition change
+ * by abort and against leaking the pipe fd to fork-without-exec. */
+ LOCK(__abort_lock);
+
+ if (pipe2(args.p, O_CLOEXEC)) {
+ UNLOCK(__abort_lock);
+ ec = errno;
+ goto fail;
+ }
+
+ pid = __clone(child, stack+sizeof stack,
+ CLONE_VM|CLONE_VFORK|SIGCHLD, &args);
+ close(args.p[1]);
+ UNLOCK(__abort_lock);
+
+ if (pid > 0) {
+ if (read(args.p[0], &ec, sizeof ec) != sizeof ec) ec = 0;
+ else waitpid(pid, &(int){0}, 0);
+ } else {
+ ec = -pid;
+ }
+
+ close(args.p[0]);
+
+ if (!ec && res) *res = pid;
+
+fail:
+ pthread_sigmask(SIG_SETMASK, &args.oldmask, 0);
+ pthread_setcancelstate(cs, 0);
+
+ return ec;