我正在周二学习OS考试。 为了准备,我试图通过C程序模拟命令行pipe道。
该程序非常简单。 我做了一个pipe道,然后fork一个subprocess。
subprocess将标准输出redirect到pipe道的写入端,closurespipe道的文件描述符,然后执行一个命令(本例中为ls
)。
父进程等待subprocess退出,将标准inputredirect到pipe道的读端,closurespipe道的文件描述符,然后执行命令(本例中为grep 'school'
)。
当我通过命令行使用ls | grep 'school'
执行命令时 ls | grep 'school'
有一条线,说“学校”打印到标准输出,这是有道理的,因为目录中有一个目录,我正在运行程序中的名称。
当我运行我制作的程序时,我没有收到任何错误消息,但是它不会产生任何输出。
我唯一能想到的就是阻止这个工作,就是在subprocess中redirect标准输出会以某种方式影响父进程命令的输出,但是我几乎肯定不应该是这样。
这里是代码:
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <errno.h> int main() { int fds[2]; int pipe_val, close_val, write_val, dup_val, status; pid_t pid; char *error; pipe_val = pipe(fds); if (pipe_val) { fprintf(stderr, "Failed to prepare pipe.\n"); return -1; } pid = fork(); if (pid == -1) { fprintf(stderr, "Failed to fork a child process.\n"); return -1; } else if (pid == 0) { dup_val = dup2(fds[1], STDOUT_FILENO); if (dup_val) { error = strerror(errno); fprintf(stderr, "Failed to redirect standard output in child process because %s\n", error); exit(1); } close_val = close(fds[0]); if (close_val) { fprintf(stderr, "Failed to close read-end of pipe in child process.\n"); exit(1); } close_val = close(fds[1]); if (close_val) { fprintf(stderr, "Failed to close write-end of pipe in child process.\n"); exit(1); } execl("/bin/ls", "ls", NULL); fprintf(stderr, "Failed to execute command in child process.\n"); exit(1); } else { wait(&status); dup_val = dup2(fds[0], STDIN_FILENO); if (dup_val) { error = strerror(errno); fprintf(stderr, "Failed to redirect standard input in parent process because %s.\n", error); return -1; } close_val = close(fds[0]); if (close_val) { fprintf(stderr, "Failed to close read-end of the pipe in the parent process.\n"); return -1; } close_val = close(fds[1]); if (close_val) { fprintf(stderr, "Failed to close write-end of the pipe in the parent process.\n"); return -1; } execl("/bin/grep", "grep", "school", NULL); fprintf(stderr, "Failed to execute the command in the parent process.\n"); return -1; } }
你的第一个问题是,你没有包含你所使用的函数的所有必要的头文件。 strerror
需要<string.h>
, wait
需要<sys/wait.h>
。
如果你用gcc编译,总是使用gcc -Wall
并读取警告。 在这种情况下,它会抱怨strerror
的隐含声明。
由于strerror
没有声明,编译器假定它返回一个int
,这是错误的。 如果您在64位Linux x86上运行该程序,则int
的大小与strerror
返回的指针大小不同 。 当你以%s
格式将strerror
的结果传递给fprintf
时,这将成为一个致命的问题,因为指针被错误地解释为int,然后转换回指针,最终导致伪造值。 fprintf
错误,你永远不会看到你的错误信息。
包括正确的标题,你会看到一个错误信息,这将导致你需要解决的下一个问题。