0

I'm building a simple command line interpreter in C, and I've encountered an issue with handling file descriptors when using pipes. The interpreter is supposed to support piped commands, but I'm running into problems with closing file descriptors correctly. Here’s a snippet of the main loop that executes commands:

for (i = 0; i < params.cnt_prog; i++) {
    len = proc_len(lst);
    char* buf[len + 1];
    lst2buf(&lst, buf);
    buf[len] = NULL;

    if (i < params.cnt_prog - 1) {
        pipe(i % 2 == 0 ? fd1 : fd2);
    }

    pid = fork();
    if (pid == 0) {
        /* Set child input */
        if (i > 0) { 
            if (i % 2 == 1) { 
                dup2(fd1[0], 0);
                close(fd1[0]);
                close(fd1[1]);
            } else {
                dup2(fd2[0], 0);
                close(fd2[0]);
                close(fd2[1]);
            }
        } else {
            close(fd1[0]);
            if (!redirect_in(&params)) {
                exit(1);
            }
        }

        /* Set output */
        if (i < params.cnt_prog - 1) { 
            if (i % 2 == 1) {
                dup2(fd2[1], 1);
                close(fd2[1]);
                close(fd2[0]);
            } else {
                dup2(fd1[1], 1);
                close(fd1[1]);
                close(fd1[0]);
            }
        } else {
            close(fd1[1]);
            close(fd2[1]);
            if (!redirect_out(&params)) 
                exit(1);
        } 

        execvp(buf[0], buf);
        perror(buf[0]);
        exit(1);
    }

    if (i > 0) {
        if (i % 2 == 1) {
            close(fd1[0]);
            close(fd1[1]);
        } else {
            close(fd2[0]);
            close(fd2[1]);
        }
    }
}
  • params.cnt_prog is the number of commands in the pipeline (e.g., ls | grep ".c" has 2 commands), executed from command line (ls | grep ".c" will produce 2)
  • I’m confident that the logic converting the list to an array (lst2buf) is correct, so the problem likely lies with how I'm managing the pipe file descriptors in the parent and child processes.

Output examples:

> ls | grep .c
grep: (standard input): Bad file descriptor

> cat main.c | wc
wc: 'standard input': Bad file descriptor
0 0 0
wc: -: Bad file descriptor
3
  • 1
    Why do you need fd1 and fd2? There should just be one pipe -- you use the same pipe as the stdout of ls and the stdin of grep. Commented Aug 21, 2024 at 19:34
  • 1
    If it's for longer pipelines like cmd1 | cmd2 | cmd3 then you should have an array of pipes, since the pipeline can be arbitrarily long. Commented Aug 21, 2024 at 19:36
  • Your code is incomplete; in particular, it seems to be missing a main() function and at least one #include. Please edit your code so it's a minimal reproducible example of your problem (including any necessary inputs, but preferably not needing any), then we can try to reproduce and solve it. You should also read How to Ask. Commented Aug 22, 2024 at 9:20

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.