popen2:阅读作品,写作没有

时间:2012-12-09 12:00:36

标签: c exec popen spawn

以下函数执行一个进程,返回其PID并提供用于读写的文件描述符:

pid_t popen2(const char **command, int *infp, int *outfp)
{
    int p_stdin[2], p_stdout[2];
    pid_t pid;

    if (pipe(p_stdin) != 0 || pipe(p_stdout) != 0) {
        return -1;
    }

    pid = fork();

    if (pid < 0) {
        return pid;
    } else if (pid == 0) {
        close(p_stdin[WRITE]);
        dup2(p_stdin[READ], READ);
        close(p_stdout[READ]);
        dup2(p_stdout[WRITE], WRITE);

        execvp(*command, command);
    }

    if (infp == NULL) {
       close(p_stdin[WRITE]);
    } else {
       *infp = p_stdin[WRITE];
    }

    if (outfp == NULL) {
        close(p_stdout[READ]);
    } else {
        *outfp = p_stdout[READ];
    }

    return pid;
}

我用

调用上面的函数
pid = popen2(..., &in, &out);

并使用

从文件描述符out中读取
nBytes = read(out, line, sizeof(line));

我读到的内容非常有意义。它是通常在控制台上显示的输出。但是,当我尝试向程序写一个命令时,通常会通过控制台用

来接收它
nBytes = write(in, cmd, strlen(cmd)+1);
没有任何反应。该计划没有任何反应。

我在这里缺少什么?

1 个答案:

答案 0 :(得分:0)

我确实改了一下,但它现在有用了。验证后删除fprintf(stderr,...

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <signal.h>

#define READ_END 0
#define WRITE_END 1

pid_t popen2(const char **command, int fdarray[]);
pid_t popen2(const char **command, int fdarray[])
{
    int p_stdin[2], p_stdout[2];
    pid_t pid;
    int rc;

    if (pipe(p_stdin) != 0 || pipe(p_stdout) != 0) {
        return -1;
    }
    pid = fork();

    if (pid < 0) {
        return pid;
    } else if (pid == 0) {
        close(p_stdin[WRITE_END]);
        dup2(p_stdin[READ_END], STDIN_FILENO);
        close(p_stdin[READ_END]);

        close(p_stdout[READ_END]);
        dup2(p_stdout[WRITE_END], STDOUT_FILENO);
        close(p_stdout[WRITE_END]);

        rc = execvp(*command, command);
        _exit(EXIT_FAILURE);
    }

    close(p_stdout[WRITE_END]);
    close(p_stdin[READ_END]);
    if (fdarray == NULL) {
        close(p_stdin[WRITE_END]);
        close(p_stdout[READ_END]);
    } else {
       fdarray[READ_END] = p_stdout[READ_END];
       fdarray[WRITE_END] = p_stdin[WRITE_END];
    }

    return pid;
}
#define BUFF_SIZE 1024
struct buff {
        size_t used;
        size_t size;
        char data[BUFF_SIZE];
        }
        ibuf = {0,BUFF_SIZE,}
        , obuf = {0,BUFF_SIZE,}
        ;

int readbuff(int fd, struct buff *bp);
int writebuff(int fd, struct buff *bp);

int readbuff(int fd, struct buff *bp)
{
size_t done;
int rc=0;

for (done=0; bp->used < bp->size; bp->used+=rc, done+=rc) {
        if (done) break;
        fprintf(stderr, "Read(%d,%zu)\n", fd, bp->size - bp->used );
        rc = read(fd, bp->data+bp->used, bp->size - bp->used);
        if (rc== -1) switch (errno) {
#if (EWOULDBLOCK != EAGAIN)
                case EWOULDBLOCK:
#endif
                case EAGAIN:
                case EINTR: rc=0; continue;
                default:
                        fprintf(stderr, "Error on readbuff: %d: %s\n", errno, strerror(errno));
                        goto failed;
                }
        fprintf(stderr, "Readbuff(%d) := %d\n", fd, rc);
        if (rc==0) { rc = -1; break; }
        }
failed:
return done ? done : rc;
}

int writebuff(int fd, struct buff *bp)
{
size_t done;
int rc= 0;

for (done=0; done < bp->used ; done+=rc) {
        if (done) break;
        fprintf(stderr, "Write(%d,%zu)\n", fd, bp->used - done);
        rc = write(fd, bp->data+done, bp->used - done);
        if (rc== -1) switch (errno) {
#if (EWOULDBLOCK != EAGAIN)
                case EWOULDBLOCK:
#endif
                case EINTR:
                case EAGAIN:rc=0; continue;
                default:
                fprintf(stderr, "Error on writebuff: %d: %s\n", errno, strerror(errno));
                goto failed;
                }
        fprintf(stderr, "Writebuff(%d) := %d\n", fd, rc);
        if (rc==0) { rc = -1; break; }
        }
failed:
if (done == bp->used ) bp->used =0;
else { memmove(bp->data, bp->data+done, bp->used - done); bp->used -= done; }
return done ? done : rc;
}

int main (void)
{
int pipes[2] = {-1,-1};
int rc1, rc2,err;
char *commands[] = { "tee", "teapot",  NULL};

// signal(SIGCHLD, SIG_IGN);
// signal(SIGPIPE, SIG_IGN);

rc1 = popen2( commands, pipes);
err = errno;

fprintf(stderr, "Rc=%d:%d(%s) pipes[0]=%d, pipes[1]=%d\n"
        , rc1 , rc1 == -1 ? err : 0
        , strerror(rc1 == -1?err:0)
        , pipes[0]
        , pipes[1]
        );
if (rc1 == -1) return EXIT_FAILURE;

while(1) {
        fprintf(stderr, "#----------------------------------------\n" );
        rc1 = readbuff(STDIN_FILENO, &ibuf);
#if 1
        if (rc1 == -1 && ibuf.used ==0) {
                fprintf(stderr, "Rc1=%d Close %d\n", rc1, pipes[WRITE_END]);
                close(pipes[WRITE_END]);
                }
        else
#endif
        writebuff(pipes[WRITE_END] , &ibuf);

        rc2 = readbuff(pipes[READ_END] , &obuf);
        writebuff(STDOUT_FILENO, &obuf);
        fprintf(stderr, "Rc=%d/%d Ibuf[0]=%zu/%zu, Obuf[0]=%zu/%zu\n"
                , rc1, rc2
                , ibuf.used, ibuf.size
                , obuf.used, obuf.size
                );
        if (rc1 < 0 && rc2 < 0) break;
        }
wait(NULL);

return 0;
}