Subversion Repositories planix.SVN

Rev

Rev 2 | Blame | Compare with Previous | Last modification | View Log | RSS feed

#include "common.h"

/* make a stream to a child process */
extern stream *
instream(void)
{
        stream *rv;
        int pfd[2];

        if ((rv = (stream *)malloc(sizeof(stream))) == 0)
                return 0;
        memset(rv, 0, sizeof(stream));
        if (pipe(pfd) < 0)
                return 0;
        if(Binit(&rv->bb, pfd[1], OWRITE) < 0){
                close(pfd[0]);
                close(pfd[1]);
                return 0;
        }
        rv->fp = &rv->bb;
        rv->fd = pfd[0];        
        return rv;
}

/* make a stream from a child process */
extern stream *
outstream(void)
{
        stream *rv;
        int pfd[2];

        if ((rv = (stream *)malloc(sizeof(stream))) == 0)
                return 0;
        memset(rv, 0, sizeof(stream));
        if (pipe(pfd) < 0)
                return 0;
        if (Binit(&rv->bb, pfd[0], OREAD) < 0){
                close(pfd[0]);
                close(pfd[1]);
                return 0;
        }
        rv->fp = &rv->bb;
        rv->fd = pfd[1];
        return rv;
}

extern void
stream_free(stream *sp)
{
        int fd;

        close(sp->fd);
        fd = Bfildes(sp->fp);
        Bterm(sp->fp);
        close(fd);
        free((char *)sp);
}

/* start a new process */
extern process *
noshell_proc_start(char **av, stream *inp, stream *outp, stream *errp, int newpg, char *who)
{
        process *pp;
        int i, n;

        if ((pp = (process *)malloc(sizeof(process))) == 0) {
                if (inp != 0)
                        stream_free(inp);
                if (outp != 0)
                        stream_free(outp);
                if (errp != 0)
                        stream_free(errp);
                return 0;
        }
        pp->std[0] = inp;
        pp->std[1] = outp;
        pp->std[2] = errp;
        switch (pp->pid = fork()) {
        case -1:
                proc_free(pp);
                return 0;
        case 0:
                if(newpg)
                        sysdetach();
                for (i=0; i<3; i++)
                        if (pp->std[i] != 0){
                                close(Bfildes(pp->std[i]->fp));
                                while(pp->std[i]->fd < 3)
                                        pp->std[i]->fd = dup(pp->std[i]->fd, -1);
                        }
                for (i=0; i<3; i++)
                        if (pp->std[i] != 0)
                                dup(pp->std[i]->fd, i);
                for (n = sysfiles(); i < n; i++)
                        close(i);
                if(who)
                        become(av, who);
                exec(av[0], av);
                perror("proc_start");
                exits("proc_start");
        default:
                for (i=0; i<3; i++)
                        if (pp->std[i] != 0) {
                                close(pp->std[i]->fd);
                                pp->std[i]->fd = -1;
                        }
                return pp;
        }
}

/* start a new process under a shell */
extern process *
proc_start(char *cmd, stream *inp, stream *outp, stream *errp, int newpg, char *who)
{
        char *av[4];

        av[0] = SHELL;
        av[1] = "-c";
        av[2] = cmd;
        av[3] = 0;
        return noshell_proc_start(av, inp, outp, errp, newpg, who);
}

/* wait for a process to stop */
extern int
proc_wait(process *pp)
{
        Waitmsg *status;
        char err[Errlen];

        for(;;){
                status = wait();
                if(status == nil){
                        rerrstr(err, sizeof(err));
                        if(strstr(err, "interrupt") == 0)
                                break;
                }
                if (status->pid==pp->pid)
                        break;
        }
        pp->pid = -1;
        if(status == nil)
                pp->status = -1;
        else
                pp->status = status->msg[0];
        pp->waitmsg = status;
        return pp->status;
}

/* free a process */
extern int
proc_free(process *pp)
{
        int i;

        if(pp->std[1] == pp->std[2])
                pp->std[2] = 0;         /* avoid freeing it twice */
        for (i = 0; i < 3; i++)
                if (pp->std[i])
                        stream_free(pp->std[i]);
        if (pp->pid >= 0)
                proc_wait(pp);
        free(pp->waitmsg);
        free((char *)pp);
        return 0;
}

/* kill a process */
extern int
proc_kill(process *pp)
{
        return syskill(pp->pid);
}