带有分叉的c程序中的错误文件描述符

时间:2018-02-19 21:16:58

标签: c fork dup2

这个程序应该模拟一个关于带管道命令的posix shell。我尝试模拟并想要工作的例子是" ls | nl",但它没有,我无法弄清楚原因。我已经调试了这段代码很长时间没有成功。

我收到错误:" nl:输入错误:文件描述符错误",当我尝试不关闭任何文件描述符或只关闭一些文件描述符时(或者只关闭一些文件描述符)分叉,或只有父母等...),错误改变,或它的工作,但然后nl一直在等待输入。无论如何,我非常确定错误位于fork_cmdfork_cmds,与close有关。

我已经包含了所有代码。我知道parser.h没有任何问题。我知道这是非常糟糕的代码,但我认为它应该仍然有效。

我可能会失明,但如果有人能帮助我搞清楚,我会非常感激。希望这是我和其他人可以从中学到的东西。

#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);
}

1 个答案:

答案 0 :(得分:1)

问题是其中一个括号位于fork_cmdfork_cmds的错误位置,当然应该是这样的:close(fds[i][WRITE])。这是原始代码:

for (int i = 0; i < n - 1; i++) {
    if (close(fds[i][READ]) == -1 || close(fds[i][WRITE] == -1))<--
    {
            close_error();
    }
}