带有forks的c程序中的错误文件描述符
这个程序应该模拟一个posix shell,它涉及到带有管道的命令。我尝试模拟并想让它工作的例子是ls | nl,但它没有,我也不知道为什么。我调试这段代码已经好几个小时了,但没有成功 我得到一个错误:nl:input error:Bad file descriptor,当我尝试不关闭任何文件描述符,或者只关闭部分文件描述符,或者只关闭其中一个分叉,或者只关闭父级文件描述符,等等,错误会发生变化,或者可以工作,但nl会一直等待输入。无论如何,我很确定错误在fork\u cmd或fork\u cmds中,并且与close有关 我已经包括了所有的代码。我知道解析器没有问题。我知道这是一个相当糟糕的代码,但我认为它仍然可以工作 我可能是瞎子,但如果有人能帮我弄清楚,我会非常感激的。希望这是我和其他人可以学习的东西带有forks的c程序中的错误文件描述符,c,fork,dup2,C,Fork,Dup2,这个程序应该模拟一个posix shell,它涉及到带有管道的命令。我尝试模拟并想让它工作的例子是ls | nl,但它没有,我也不知道为什么。我调试这段代码已经好几个小时了,但没有成功 我得到一个错误:nl:input error:Bad file descriptor,当我尝试不关闭任何文件描述符,或者只关闭部分文件描述符,或者只关闭其中一个分叉,或者只关闭父级文件描述符,等等,错误会发生变化,或者可以工作,但nl会一直等待输入。无论如何,我很确定错误在fork\u cmd或fork\u cm
#include "parser.h"
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <stdbool.h>
#define READ 0
#define WRITE 1
void fork_error() {
perror("fork() failed)");
exit(EXIT_FAILURE);
}
void close_error() {
perror("Couldn't close file descriptor");
exit(EXIT_FAILURE);
}
void fork_cmd(char* argv[], int n, int read_pipe[2], int write_pipe[2], int (*all_fds)[2]) {
pid_t pid;
switch (pid = fork()) {
case -1:
fork_error();
case 0:
if (read_pipe != NULL) {
if (dup2(read_pipe[READ], STDIN_FILENO) < 0) {
perror("Failed to redirect STDIN to pipe");
exit(EXIT_FAILURE);
}
}
if (write_pipe != NULL) {
if (dup2(write_pipe[WRITE], STDOUT_FILENO) < 0) {
perror("Failed to redirect STDOUT to pipe");
exit(EXIT_FAILURE);
}
}
for (int i = 0; i < n - 1; i++) {
if (close(all_fds[i][READ]) == -1 || close(all_fds[i][WRITE] == -1)) {
close_error();
}
}
execvp(argv[0], argv);
perror("execvp");
exit(EXIT_FAILURE);
default:
printf("Pid of %s: %d\n", argv[0], pid);
break;
}
}
void fork_cmds(char* argvs[MAX_COMMANDS][MAX_ARGV], int n, int (*fds)[2]) {
for (int i = 0; i < n; i++) {
if (n == 1) {
fork_cmd(argvs[i], n, NULL, NULL, fds);
}
// n > 1
else if (i == 0) {
fork_cmd(argvs[i], n, NULL, fds[i], fds);
}
else if (i == n - 1) {
fork_cmd(argvs[i], n, fds[i - 1], NULL, fds);
}
else {
fork_cmd(argvs[i], n, fds[i - 1], fds[i], fds);
}
}
for (int i = 0; i < n - 1; i++) {
if (close(fds[i][READ]) == -1 || close(fds[i][WRITE] == -1)) {
close_error();
}
}
}
void get_line(char* buffer, size_t size) {
getline(&buffer, &size, stdin);
buffer[strlen(buffer)-1] = '\0';
}
void wait_for_all_cmds(int n) {
// Not implemented yet!
for (int i = 0; i < n; i++) {
int status;
int pid;
if ((pid = wait(&status)) == -1) {
printf("Wait error");
} else {
printf("PARENT <%ld>: Child with PID = %ld and exit status = %d terminated.\n",
(long) getpid(), (long) pid, WEXITSTATUS(status));
}
}
}
int main() {
int n;
char* argvs[MAX_COMMANDS][MAX_ARGV];
size_t size = 128;
char line[size];
printf(" >> ");
get_line(line, size);
n = parse(line, argvs);
// Debug printouts.
printf("%d commands parsed.\n", n);
print_argvs(argvs);
int (*fds)[2] = malloc(sizeof(int) * 2 * (n - 1)); // should be pointer to arrays of size 2
for (int i = 0; i < n - 1; i++) {
if (pipe(fds[i]) == -1) {
perror("Creating pipe error"); // Creating pipe error: ...
exit(EXIT_FAILURE);
}
printf("pipe %d: read: %d, write: %d\n", i, fds[i][READ], fds[i][WRITE]);
}
fork_cmds(argvs, n, fds);
wait_for_all_cmds(n);
exit(EXIT_SUCCESS);
}
问题是其中一个括号在fork_cmd和fork_cmds中的位置都不正确,当然应该是这样的:closefds[i][WRITE]。这是原始代码:
for (int i = 0; i < n - 1; i++) {
if (close(fds[i][READ]) == -1 || close(fds[i][WRITE] == -1))<--
{
close_error();
}
}
你的get_line功能很危险。如果行长度超过127个字符,则getline将尝试为传递的缓冲区重新分配内存,并且它将失败,因为缓冲区未指向malloc/realloc分配的地址。你的函数会产生未定义的行为。是的,但这不会被任何人使用,所以它很好。不过谢谢你指出。为什么你要在fork发生之前用advanced创建管道而不是一个呢?我认为可能存在错误,但我必须首先进行测试。当询问有关运行时问题时,发布一条消息,这不是因为包含了自制的头文件:parse.h,但该文件的内容没有发布。发布的代码不会编译!缺少MAX_命令和MAX_ARGV的define语句