Advanced Programming in UNIX Environment Episode 86

popen and pclose Functions

Since a common operation is to create a pipe to another process to either read its output or send it input, the standard I/O library has historically provided the popen and pclose functions.

#include 
FILE *popen(const char *cmdstring, const char *type);
int pclose(FILE *fp);

The cmdstring is executed by the Bourne shell, as in

sh -c cmdstring

This means that the shell expands any of its special characters in cmdstring. This allows us to say, for example,

fp = popen("ls *.c", "r");

or

fp = popen("cmd 2>&1", "r");
#include "apue.h"
#include 

#define PAGER "${PAGER:-more}"

int main(int argc, char *argv[])
{
    char line[MAXLINE];
    FILE *fpin, *fpout;

    if(argc!=2)
        err_quit("usage: a.out ");
    if((fpi=fopen(argv[1],"r"))==NULL)
        err_sys("can't opne %s", argv[1]);
    
    if((fpout=popen(PAGER,"w"))==NULL)
        err_sys("popen error");
    
    while(fgets(line,MAXLINE,fpin)!=NULL)
    {
        if(fputs(line,fpout)==EOF)
            err_sys("fputs error to pipe");
        if(pclose(fpout)==-1)
            err_sys("pclose error");
    }

    return 0;
}

Copy file to pager program using popen

#include "apue.h"
#include 
#include 
#include 

static pid_t *childpid=NULL;

static int maxfd;

FILE *popen(const char *cmdstring, const char *type)
{
    int i;
    int pfd[2];
    pid_t pid;
    FILE *fp;

    if((type[0]!='r'&&type[0]!='w')||type[1]!=0)
    {
        errno=EINVAL;
        return NULL;
    }

    if(childpid==NULL)
    {
        maxfd=open_max();
        if((childpid=calloc(maxfd, sizeof(pid_t))==NULL))
            return NULL;
    }

    if(pipe(pfd)<0)
        return NULL;
    if(pfd[0]>=maxfd||pfd[1]>=maxfd)
    {
        close(pfd[0]);
        close(pfd[1]);
        errno=EMFILE;
        return NULL;
    }

    if((pid=fork())<0)
    {
        return NULL;
    }
    else if(pid==0)
    {
        if(*type=='r')
        {
            close(pfd[0]);
            if(pfd[1]!=STDOUT_FILENO)
            {
                dup2(pfd[1],STDOUT_FILENO);
                close(pfd[1]);
            }
        }
        else
        {
            close(pfd[1]);
            if(pfd[0]!=STDIN_FILENO)
            {
                dup2(pfd[0],STDIN_FILENO);
                close(pfd[0]);
            }
        }

        for(i=0;i0)
                close(i);

        execl("/bin/sh", "sh", "-c",cmdstring, (char *0));
        _exit(127);
    }

    if(*type=='r')
    {
        close(pfd[1]);
        if((fp==fdopen(pfd[0],type))==NULL)
            return NULL;
    }
    else
    {
        close(pfd[0]);
        if((fp==fdopen(pfd[1],type))==NULL)
            return NULL;
    }

    childpid[fileno(fp)]=pid;
    return fp;
}

int pclose(FILE *fp)
{
    int fd, stat;
    pid_t pid;

    if(childpid==NULL)
    {
        errno=EINVAL;
        return -1;
    }

    fd=fileno;
    if(fd>=maxfd)
    {
        errno=EINVAL;
        return -1;
    }

    if((pid=childpid[fd])==0)
    {
        errno=EINVAL;
        return -1;
    }

    childpid[fd]=0;
    if(close(fp)==EOF)
        return -1;

    while(waitpid(pid,&stat, 0)<0)
        if(errno!=EINTR)
            return -1;
    
    return stat;
}

The popen and pclose functions

你可能感兴趣的:(Advanced,Programming,in,the,Unix,Environment)