示例#1
0
文件: spawnvex.c 项目: att/ast
static int restore(Spawnvex_t *vex, int i, int j, int fl) {
    if (j >= 0) {
        if (spawnvex_add(vex, i, j, 0, 0) < 0) return -1;
        if (fl == 0 && spawnvex_add(vex, j, j, 0, 0) < 0) return -1;
    }
    if (spawnvex_add(vex, i, -1, 0, 0) < 0) return -1;
    return 0;
}
示例#2
0
static pid_t _spawnveg(Shell_t *shp,const char *path, char* const argv[], char* const envp[], pid_t pgid)
{
	pid_t pid;
#ifdef SIGTSTP
	if(job.jobcontrol)
	{
		signal(SIGTTIN,SIG_DFL);
		signal(SIGTTOU,SIG_DFL);
	}
#endif /* SIGTSTP */

	while(1)
	{
		sh_stats(STAT_SPAWN);
#ifdef SPAWN_cwd
		{
			char *arg0 = argv[0], **av0= (char**)&argv[0];
			int fd;
			pid = spawnvex(path,argv,envp,shp->vex);
			*av0 = arg0;
			if(pid>0 && shp->comsub && (fd=sffileno(sfstdout))!=1 && fd>=0)
				spawnvex_add(shp->vex, fd, 1,0,0);
		}
#else
		pid = spawnveg(path,argv,envp,pgid);
#endif /* SPAWN_cwd */
		if(pid>=0 || errno!=EAGAIN)
			break;
	}
#ifdef SIGTSTP
	if(job.jobcontrol)
	{
		signal(SIGTTIN,SIG_IGN);
		signal(SIGTTOU,SIG_IGN);
	}
#endif /* SIGTSTP */
	return(pid);
}
示例#3
0
文件: args.c 项目: att/ast
struct argnod *sh_argprocsub(Shell_t *shp, struct argnod *argp) {
    // Argument of the form <(cmd) or >(cmd).
    struct argnod *ap;
    int nn, monitor, fd, pv[3];
    int subshell = shp->subshell;
    pid_t pid0;

    ap = (struct argnod *)stkseek(shp->stk, ARGVAL);
    ap->argflag |= ARG_MAKE;
    ap->argflag &= ~ARG_RAW;
    fd = argp->argflag & ARG_RAW;
    if (fd == 0 && shp->subshell) sh_subtmpfile(shp);
#if has_dev_fd
    sfwrite(shp->stk, e_devfdNN, 8);
    pv[2] = 0;
    sh_pipe(pv);
    sfputr(shp->stk, fmtbase((long)pv[fd], 10, 0), 0);
#else   // has_dev_fd
    pv[0] = -1;
    shp->fifo = ast_temp_path("ksh.fifo");
    if (mkfifo(shp->fifo, S_IRUSR | S_IWUSR)) abort();
    sfputr(shp->stk, shp->fifo, 0);
#endif  // has_dev_fd
    ap = (struct argnod *)stkfreeze(shp->stk, 0);
    shp->inpipe = shp->outpipe = NULL;
    monitor = (sh_isstate(shp, SH_MONITOR) != 0);
    if (monitor) sh_offstate(shp, SH_MONITOR);
    shp->subshell = 0;
#if has_dev_fd
#if USE_SPAWN
    if (shp->vex || (shp->vex = spawnvex_open(0))) {
        spawnvex_add(shp->vex, pv[fd], pv[fd], 0, 0);
    } else
#endif  // USE_SPAWN
        fcntl(pv[fd], F_SETFD, 0);
    shp->fdstatus[pv[fd]] &= ~IOCLEX;
#endif  // has_dev_fd
    pid0 = shp->procsub ? *shp->procsub : 0;
    if (fd) {
        if (!shp->procsub) {
            shp->nprocsub = 4;
            shp->procsub = procsub = calloc(1, shp->nprocsub * sizeof(pid_t));
        } else {
            nn = procsub - shp->procsub;
            if (nn >= shp->nprocsub) {
                shp->nprocsub += 3;
                shp->procsub = realloc(shp->procsub, shp->nprocsub * sizeof(pid_t));
                procsub = shp->procsub + nn;
            }
        }
        if (pid0) *shp->procsub = 0;
        shp->inpipe = pv;
        sh_exec(shp, (Shnode_t *)argp->argchn.ap, (int)sh_isstate(shp, SH_ERREXIT));
        if (pid0) *shp->procsub = pid0;
        *procsub++ = job.lastpost;
    } else {
        shp->outpipe = pv;
        sh_exec(shp, (Shnode_t *)argp->argchn.ap, (int)sh_isstate(shp, SH_ERREXIT));
    }
    shp->subshell = subshell;
    if (monitor) sh_onstate(shp, SH_MONITOR);
#if has_dev_fd
    sh_close(pv[1 - fd]);
    sh_iosave(shp, -pv[fd], shp->topfd, NULL);
#else
    free(shp->fifo);
    shp->fifo = NULL;
#endif  // has_dev_fd
    return ap;
}
示例#4
0
文件: spawnvex.c 项目: att/ast
pid_t spawnvex(const char *path, char *const argv[], char *const envv[], Spawnvex_t *vex) {
    int i;
    int op;
    unsigned int flags = 0;
    pid_t pid;
    int arg;
    int err;
    int fd;
    posix_spawnattr_t ax;
    posix_spawn_file_actions_t fx;
    Spawnvex_t *xev = NULL;
#if _lib_spawn_mode || _lib_spawn && _mem_pgroup_inheritance
    pid_t pgid;
    int arg;
    int j;
    int k;
    int m;
    int ic;
    int jc;
    Spawnvex_t *xev;
#if !_lib_spawn_mode
    int *map;
    int a;
    struct inheritance inherit;
#endif
#endif

    if (vex && vex->debug >= 0) {
        error(ERROR_OUTPUT, vex->debug, "spawnvex exe %4d %8d %p %4d \"%s\"", __LINE__, getpid(),
              vex, vex->cur, path);
    }
#if _lib_spawn_mode || _lib_spawn && _mem_pgroup_inheritance
    if (!envv) envv = environ;
    pid = -1;
    m = 0;
    if (vex) {
        vex->noexec = -1;
        vex->pgrp = -1;
        flags = vex->flags;
        if (!(xev = spawnvex_open(0))) goto bad;
        j = -1;
        for (i = 0; i < vex->cur;) {
            op = vex->op[i++].number;
            arg = vex->op[i++].number;
            if (op & 1) i += 2;
            op /= 2;
            if (op >= 0) {
                if (m < op) m = op + 1;
                if (m < arg) m = arg + 1;
            } else if (op == SPAWN_cwd)
                j = arg;
        }
        if (j >= 0) {
            if ((i = open(".", O_RDONLY)) < 0) goto bad;
            if ((i = save(i, &ic, m)) < 0) goto bad;
            if (spawnvex_add(xev, SPAWN_cwd, i, 0, 0) < 0 || restore(xev, i, -1, 0) < 0) {
                close(i);
                goto bad;
            }
            if (fchdir(j) < 0) goto bad;
            if ((i = save(j, &jc, m)) < 0) goto bad;
            if (restore(xev, i, j, jc) < 0) {
                close(i);
                goto bad;
            }
        }
    } else {
        flags = 0;
        xev = NULL;
    }
#if _lib_spawn_mode
    if (vex)
        for (i = 0; i < vex->cur;) {
            op = vex->op[i++].number;
            arg = vex->op[i++].number;
            if (op & 1) i += 2;
            switch (op /= 2) {
                case SPAWN_frame:
                    vex->frame = (unsigned int)arg;
                    break;
                case SPAWN_pgrp:
                    vex->pgrp = (pid_t)arg;
                    break;
                default:
                    if (op >= 0) {
                        if (arg < 0) {
                            if ((i = save(op, &ic, m)) < 0) {
                                if (i < -1) goto bad;
                            } else if (restore(xev, i, op, ic) < 0) {
                                close(i);
                                goto bad;
                            } else
                                close(op);
                        } else if (arg == op) {
                            if (spawnvex_add(xev, SPAWN_cloexec, arg, 0, 0) < 0) goto bad;
                            if (fcntl(arg, F_SETFD, 0) < 0) goto bad;
                        } else if ((j = save(arg, &jc, m)) < -1)
                            goto bad;
                        else {
                            close(arg);
                            if (fcntl(op, F_DUPFD, arg) >= 0) {
                                if ((i = save(op, &ic, m)) >= 0) {
                                    if (restore(xev, i, op, ic) >= 0) {
                                        close(op);
                                        if (j < 0 || restore(xev, j, arg, jc) >= 0) continue;
                                    }
                                    close(i);
                                }
                            }
                            if (j >= 0) {
                                fcntl(j, F_DUPFD, arg);
                                close(j);
                            }
                            goto bad;
                        }
                    }
                    break;
            }
        }
    pid = spawnve(vex && vex->pgrp >= 0 ? P_DETACH : P_NOWAIT, path, argv, envv);
#else
    inherit.flags = 0;
    map = 0;
    if (vex) {
        if (m) {
            map = calloc(1, m * sizeof(int));
            if (!map) goto bad;
            for (i = 0; i < m; i++) map[i] = i;
        }
        for (i = 0; i < vex->cur;) {
            op = vex->op[i++].number;
            a = i;
            arg = vex->op[i++].number;
            if (op & 1) i += 2;
            switch (op /= 2) {
                case SPAWN_noop:
                    break;
                case SPAWN_noexec:
                    break;
                case SPAWN_frame:
                    vex->frame = (unsigned int)arg;
                    break;
                case SPAWN_pgrp:
                    inherit.flags |= SPAWN_SETGROUP;
                    inherit.pgroup = arg ? arg : SPAWN_NEWPGROUP;
                    break;
                case SPAWN_sigdef:
                    inherit.flags |= SPAWN_SETSIGDEF;
                    sigemptyset(&inherit.sigdefault);
                    for (j = 1; j < 8 * sizeof(vex->op[a].number); j++)
                        if (vex->op[a].number & (1 << j)) sigaddset(&inherit.sigdefault, j);
                    break;
                case SPAWN_sigmask:
                    inherit.flags |= SPAWN_SETSIGMASK;
                    sigemptyset(&inherit.sigmask);
                    for (j = 1; j < 8 * sizeof(vex->op[a].number); j++)
                        if (vex->op[a].number & (1 << j)) sigaddset(&inherit.sigmask, j);
                    break;
                default:
                    if (op < 0) {
                        errno = EINVAL;
                        goto bad;
                    } else if (arg < 0)
                        map[op] = SPAWN_FDCLOSED;
                    else
                        map[op] = arg;
                    break;
            }
        }
    }
    pid = spawn(path, m, map, &inherit, (const char **)argv, (const char **)envv);
#endif
    if (pid >= 0 && vex) VEXINIT(vex);
bad:
    if (xev) {
        spawnvex_apply(xev, 0, SPAWN_FLUSH | SPAWN_NOCALL);
        spawnvex_close(xev);
    }
#if !_lib_spawn_mode
    if (map) free(map);
#endif
    return pid;

#else

#if _lib_spawnve
    if (!vex || !vex->cur && !vex->flags) return spawnve(path, argv, envv);
#endif
    if (vex && ((vex->set & (0
#if !_lib_posix_spawnattr_setfchdir
                             | VEXFLAG(SPAWN_cwd)
#endif
#if !_lib_posix_spawnattr_setsid
                             | VEXFLAG(SPAWN_sid)
#endif
#if !_lib_posix_spawnattr_setumask
                             | VEXFLAG(SPAWN_umask)
#endif
                                 ))
#if !_lib_posix_spawn
                || !(vex->flags & SPAWN_EXEC)
#endif
                    )) {
        int n;
        int m;
        Spawnvex_noexec_t nx;
        int msg[2];

        if (!envv) envv = environ;
        n = errno;
        if (pipe(msg) < 0) {
            msg[0] = msg[1] = -1;
        } else {
            (void)fcntl(msg[0], F_SETFD, FD_CLOEXEC);
            (void)fcntl(msg[1], F_SETFD, FD_CLOEXEC);
        }
        if (!(flags & SPAWN_FOREGROUND)) sigcritical(SIG_REG_EXEC | SIG_REG_PROC);
        pid = fork();
        if (pid == -1) {
            n = errno;
        } else if (!pid) {
            if (!(flags & SPAWN_FOREGROUND)) sigcritical(SIG_REG_POP);
            if (vex && (n = spawnvex_apply(vex, 0, SPAWN_FRAME | SPAWN_NOCALL))) {
                errno = n;
            } else {
                if (vex && vex->debug >= 0) {
                    error(ERROR_OUTPUT, vex->debug, "spawnvex exe %4d %8d %p %4d \"%s\"", __LINE__,
                          getpid(), vex, vex->cur, path);
                }
                execve(path, argv, envv);
                if (vex && vex->debug >= 0) {
                    error(ERROR_OUTPUT, vex->debug, "spawnvex exe %4d %8d %p %4d \"%s\" FAILED",
                          __LINE__, getpid(), vex, vex->cur, path);
                }
                if (vex && (i = vex->noexec) >= 0) {
                    nx.vex = vex;
                    nx.handle = vex->op[i + 3].handle;
                    nx.path = path;
                    nx.argv = argv;
                    nx.envv = envv;
#if _use_spawn_exec
                    /*
                     * setting SPAWN_EXEC here means that it is more efficient to
                     * exec(interpreter) on script than to fork() initialize and
                     * read script -- highly subjective, based on some ksh
                     * implementaions, and probably won't be set unless its a
                     * noticable win
                     */

                    nx.flags |= SPAWN_EXEC;
#endif
                    nx.msgfd = msg[1];
                    errno = (*vex->op[i + 2].callback)(&nx, SPAWN_noexec, errno);
                }
            }
            if (msg[1] != -1) {
                m = errno;
                write(msg[1], &m, sizeof(m));
            }
            _exit(errno == ENOENT ? EXIT_NOTFOUND : EXIT_NOEXEC);
        }
        if (msg[0] != -1) {
            close(msg[1]);
            if (pid != -1) {
                m = 0;
                while (read(msg[0], &m, sizeof(m)) == -1) {
                    if (errno != EINTR) {
                        m = errno;
                        break;
                    }
                }
                if (m) {
                    while (waitpid(pid, &n, 0) && errno == EINTR) {
                        ;
                    }
                    pid = -1;
                    n = m;
                }
            }
            close(msg[0]);
        }
        if (!(flags & SPAWN_FOREGROUND)) sigcritical(SIG_REG_POP);
        if (pid != -1 && vex) VEXINIT(vex);
        errno = n;
        return pid;
    }
    if (vex) {
        err = posix_spawnattr_init(&ax);
        if (err) goto nope;
        err = posix_spawn_file_actions_init(&fx);
        if (err) {
            posix_spawnattr_destroy(&ax);
            goto nope;
        }
        for (i = 0; i < vex->cur;) {
            op = vex->op[i++].number;
            arg = vex->op[i++].number;
            if (op & 1) i += 2;
            switch (op /= 2) {
                case SPAWN_noop:
                    break;
                case SPAWN_noexec:
                    break;
                case SPAWN_frame:
                    break;
#if _lib_posix_spawnattr_setfchdir
                case SPAWN_cwd:
                    err = posix_spawnattr_setfchdir(&ax, arg);
                    if (err) goto bad;
                    break;
#endif
                case SPAWN_pgrp:
                    err = posix_spawnattr_setpgroup(&ax, arg);
                    if (err) goto bad;
                    err = posix_spawnattr_setflags(&ax, POSIX_SPAWN_SETPGROUP);
                    if (err) goto bad;
                    break;
                case SPAWN_resetids:
                    err = posix_spawnattr_setflags(&ax, POSIX_SPAWN_RESETIDS);
                    if (err) goto bad;
                    break;
#if _lib_posix_spawnattr_setsid
                case SPAWN_sid:
                    err = posix_spawnattr_setsid(&ax, arg);
                    if (err) goto bad;
                    break;
#endif
                case SPAWN_sigdef:
                    break;
                case SPAWN_sigmask:
                    break;
#if _lib_posix_spawnattr_setumask
                case SPAWN_umask:
                    if (err = posix_spawnattr_setumask(&ax, arg)) goto bad;
                    break;
#endif
                default:
                    if (op < 0) {
                        err = EINVAL;
                        goto bad;
                    } else if (arg < 0) {
                        err = posix_spawn_file_actions_addclose(&fx, op);
                        if (err) goto bad;
                    } else if (arg == op) {
#ifdef F_DUPFD_CLOEXEC
                        if ((fd = fcntl(op, F_DUPFD_CLOEXEC, 0)) < 0)
#else
                        if ((fd = fcntl(op, F_DUPFD, 0)) < 0 ||
                            fcntl(fd, F_SETFD, FD_CLOEXEC) < 0 && (close(fd), 1))
#endif
                        {
                            err = errno;
                            goto bad;
                        }
                        if (!xev && !(xev = spawnvex_open(0))) goto bad;
                        spawnvex_add(xev, fd, -1, 0, 0);
                        err = posix_spawn_file_actions_adddup2(&fx, fd, op);
                        if (err) goto bad;
                    } else {
                        err = posix_spawn_file_actions_adddup2(&fx, op, arg);
                        if (err) goto bad;
                    }
                    break;
            }
        }

        // Ensure stdin, stdout, stderr are open in the child process.
        // See https://github.com/att/ast/issues/1117.
        for (int fd = 0; fd < 3; ++fd) {
            errno = 0;
            if (fcntl(fd, F_GETFD, NULL) == -1 || errno == EBADF) {
                err = posix_spawn_file_actions_addopen(&fx, fd, "/dev/null", O_RDWR, 0);
                if (err) goto bad;
            }
        }

        err = posix_spawn(&pid, path, &fx, &ax, argv, envv ? envv : environ);
        if (err) goto bad;
        posix_spawnattr_destroy(&ax);
        posix_spawn_file_actions_destroy(&fx);
        if (xev) {
            spawnvex_apply(xev, 0, SPAWN_NOCALL);
            spawnvex_close(xev);
        }
        if (vex->flags & SPAWN_CLEANUP) spawnvex_apply(vex, 0, SPAWN_FRAME | SPAWN_CLEANUP);
        VEXINIT(vex);
    } else {
        err = posix_spawn(&pid, path, NULL, NULL, argv, envv ? envv : environ);
        if (err) goto nope;
    }
    if (vex && vex->debug >= 0) {
        error(ERROR_OUTPUT, vex->debug, "spawnvex exe %4d %8d %p %4d \"%s\" %8d posix_spawn",
              __LINE__, getpid(), vex, vex->cur, path, pid);
    }
    return pid;
bad:
    posix_spawnattr_destroy(&ax);
    posix_spawn_file_actions_destroy(&fx);
    if (xev) {
        spawnvex_apply(xev, 0, SPAWN_NOCALL);
        spawnvex_close(xev);
    }
nope:
    errno = err;
    if (vex && vex->debug >= 0) {
        error(ERROR_OUTPUT, vex->debug, "spawnvex exe %4d %8d %p %4d \"%s\" %8d posix_spawn FAILED",
              __LINE__, getpid(), vex, vex->cur, path, -1);
    }
    return -1;
#endif
}