execl命令的read()输出,仅使用write()syscall打印

我正在尝试使用/bin/tar -tf在tar文件上执行execl()。我希望它读取其内容,并仅通过main()系统调用将其打印到我的write()函数的终端屏幕上。

我下面的代码以某种方式读取内容并将其同时写入终端,而不必诉诸write()系统调用。

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/wait.h>

int pfd[2];

// Problem 1:
// ERROR : read() function reads and writes to the terminal.
// I would like to write the contents of the 'buffer' variable with the
// write(fd,buffer,strlen(buffer)) syscall to the terminal preferably
// in the main() function.
// Problem 2:
// is the 'status' variable along with the _exit function useful here?
// I am not sure if a pipe is needed?
int show_tar(pid_t *pid,char *buffer,int *bytes_read,char **tar_name)
{
    int status = 0;
    pipe(pfd);
    if ((*pid = fork()) == 0) {
        dup2(0,pfd[0]);
        execl("/bin/tar","tar","-tf",tar_name[1],(char *)NULL);
    } else {
        close(pfd[1]);
        *bytes_read = read(pfd[0],sizeof(buffer));
        wait(NULL);
    }
    _exit(status);
    return status;
}

int main(int argc,char **argv)
{
    char buffer[1024];
    int bytes_read = 0;
    pid_t pid;
    int status = show_tar(&pid,&bytes_read,argv);
    wait(&status);
    // write contents of 'buffer' to the terminal with the
    // write(fd,strlen(buffer)) function like so:
    // int ch;
    // while (1) {
    //     if ((ch = getchar()) == 27) // Press <Escape> to quit program
    //         break;
    //     else  
    //         write(1,strlen(buffer));
    // }
    return 0;
}

在Linux上以argv[1]作为压缩包进行编译和执行:

gcc buffer.c -o buffer && ./buffer "$HOME/<your tarball>.tar.gz"

输出显示了tarball的全部内容,而无需诉诸write() syscall。

lihonglian26 回答:execl命令的read()输出,仅使用write()syscall打印

编辑:这需要大量的工作,并且还没有真正完成,但这应该可以帮助您入门。

我认为您的管道有点混乱:它们是单向通道,可以在pfd[1]上读取pfd[0]上写的任何内容,因此它们没有正确使用管道。

父母和孩子应该始终关闭他们不使用的管道的“另一”端,并且您必须进行安排,以使写入管道的字面数字为1(stdout)。

int show_tar(pid_t *pid,char *buffer,int *bytes_read,char **tar_name)
{
    int status = 0;
    int buffer_size = *bytes_read;  // pass IN the buffer size
    int pfd[2];
    pipe(pfd);
    if ((*pid = fork()) == 0) {
        close(pfd[0]);  // child doesn't need read pipe
        dup2(pfd[1],1); // insure write pipe is at stdout (fd#1)
        dup2(pfd[1],2); // stderr goes to the pipe also (optional)
        close(pfd[1]);  // child doesn't need write pipe any more
        execl("/bin/tar","tar","-tf",tar_name[1],(char *)NULL);
        _exit(1);
    } else {
        close(pfd[1]);  // parent doesn't need write pipe
        *bytes_read = read(pfd[0],buffer,buffer_size);

        // insure NUL byte at the end
        if (*bytes_read >= 0) buffer[*bytes_read] = 0;

        wait(NULL);
    }
//  _exit(status);    // we don't need this!
    return status;
}

int main(int argc,char **argv)
{
    char buffer[1024];
    int bytes_read = sizeof buffer;
    pid_t pid;

    int status = show_tar(&pid,&bytes_read,argv);
    wait(&status);

    // print the value here
    return 0;
}

这在某种程度上简化了管道描述符的管理,因为如果在已关闭stdin / stdout的环境中运行该管道描述符,则该管道实际上可能使用fd#0和fd#1。

最后,有时您需要做一些棘手的事情,方法是检查文件描述符以查看它们是否已经是您想要的,然后dup处理冲突。但是,如果从终端会话运行,则可以开始使用它。

还:请注意,标准错误流(fd#2)仍连接到原始终端,因此来自tar的错误消息之类的内容将不会被此机制捕获。再次,更加棘手的管道描述符管理。

编辑:我只是注意到show_tar()中的所有路径都流经_exit(),所以它将永远不会返回。

编辑:将int pfd[2];的定义移到内部 show_tar()-不需要在文件范围内。

编辑:刚刚意识到sizeof(buffer)中的show_tar()并没有按照您的想法进行;指针的大小始终为4或8(取决于平台),而不是可用的字节数-这必须作为参数传递。我已经重载了*bytes_read参数,以向传入可用的字节数,并且您已经在使用它来向 back 传递读取的数字。

父级也必须循环,从管道读取字节直到文件结束,因为tar中的所有内容不太可能在一次读取中完成。

本文链接:https://www.f2er.com/3149402.html

大家都在问