+ if (attr->__flags & POSIX_SPAWN_SETPGROUP)
+ if ((ret=__syscall(SYS_setpgid, 0, attr->__pgrp)))
+ goto fail;
+
+ /* Use syscalls directly because pthread state because the
+ * library functions attempt to do a multi-threaded synchronized
+ * id-change, which would trash the parent's state. */
+ if (attr->__flags & POSIX_SPAWN_RESETIDS)
+ if ((ret=__syscall(SYS_setgid, __syscall(SYS_getgid))) ||
+ (ret=__syscall(SYS_setuid, __syscall(SYS_getuid))) )
+ goto fail;
+
+ if (fa && fa->__actions) {
+ struct fdop *op;
+ int fd;
+ for (op = fa->__actions; op->next; op = op->next);
+ for (; op; op = op->prev) {
+ /* It's possible that a file operation would clobber
+ * the pipe fd used for synchronizing with the
+ * parent. To avoid that, we dup the pipe onto
+ * an unoccupied fd. */
+ if (op->fd == p) {
+ ret = __syscall(SYS_dup, p);
+ if (ret < 0) goto fail;
+ __syscall(SYS_close, p);
+ p = ret;
+ }
+ switch(op->cmd) {
+ case FDOP_CLOSE:
+ if ((ret=__syscall(SYS_close, op->fd)))
+ goto fail;
+ break;
+ case FDOP_DUP2:
+ if ((ret=__syscall(SYS_dup2, op->srcfd, op->fd))<0)
+ goto fail;
+ break;
+ case FDOP_OPEN:
+ fd = __syscall(SYS_open, op->path,
+ op->oflag | O_LARGEFILE, op->mode);
+ if ((ret=fd) < 0) goto fail;
+ if (fd != op->fd) {
+ if ((ret=__syscall(SYS_dup2, fd, op->fd))<0)
+ goto fail;
+ __syscall(SYS_close, fd);
+ }
+ break;
+ }