0

Title is self-explanatory on what I want to do so here is my current code:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>

int main() {

  pid_t pid ;
  int fd[2], fd2[2];
  pipe(fd);
  pipe(fd2);
  pid = fork(); 

  if(pid == 0) {
    close(1);
    dup(fd[1]);
    close(fd[0]);
    close(fd[1]);

    char *exp[] = {"cat", "filename.txt", NULL};
    execvp("cat", exp);
    exit(EXIT_FAILURE);
  } 
  else if(pid > 0) {
    close(1);
    dup(fd2[1]);
    close(fd2[0]);
    close(fd2[1]);

    char *exp[] = {"grep", "-w", "stringname", NULL};
    execvp(exp[0], exp);

    pid_t pid2=fork();

    close(0);
    dup(fd[0]);
    close (fd[1]);
    close(fd[0]);

  char *exp2[] = {"grep", "-c", "stringname", NULL};
  execvp(exp2[0], exp2);

  exit(EXIT_FAILURE);
  }

  else {
    printf("Error in forking");
    exit(EXIT_FAILURE);
  }
  close(fd[0]);
  close(fd[1]);
  close(fd2[0]);
  close(fd2[1]);
  return 0;
}

Currently the program is compiling but not executing (it gets stuck somewhere on execution and I don't get any output), any help on what I am doing wrong and how can I fix it?

6
  • You aren’t closing enough file descriptors. Each process needs to close all four pipe file descriptors. Commented Apr 9, 2020 at 13:44
  • Just did that and still same result, also I think I should add a if(pid2>0) after creating the second process, will do that now
    – Sergio
    Commented Apr 9, 2020 at 13:49
  • Did that and it resulted in no changes as well.
    – Sergio
    Commented Apr 9, 2020 at 13:50
  • The grep that is writing into fd2 is blocked on a read. Commented Apr 9, 2020 at 13:54
  • @WilliamPursell so you meant that I remove the close(fd2[0]) in the start of parent process?
    – Sergio
    Commented Apr 9, 2020 at 14:35

1 Answer 1

1

There are some problems in your code:

  1. execvp(exp[0], exp); after the first grep would be executed before second fork(). This is a logic error.
  2. I don't quite understand how do you work with file descriptors of your pipes. You should replace stdin and stdout with appropriate ends of the pipes and close all other ends.

I rewrote your code with this changes, using dup2 to make it cleaner:

#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>

int main()
{
    int pipes[4];

    // Create two pipes
    pipe(pipes);
    pipe(pipes + 2);

    // Execute cat
    if (fork() == 0) {
        // Replace output with write end of first pipe
        dup2(pipes[1], 1);

        // Close all ends of pipes (we already copied it with `dup2`)
        close(pipes[0]);
        close(pipes[1]);
        close(pipes[2]);
        close(pipes[3]);

        char *exp[] = {"cat", "filename.txt", NULL};
        execvp(exp[0], exp);
        perror("cat failed");
        exit(EXIT_FAILURE);
    } else {
        // Execute first grep
        if (fork() == 0) {
            // Replace input with read end of 1st pipe
            dup2(pipes[0], 0);

            // Replace output with write end of 2nd pipe
            dup2(pipes[3], 1);

            // Close all ends of pipes
            close(pipes[0]);
            close(pipes[1]);
            close(pipes[2]);
            close(pipes[3]);

            char *exp[] = {"grep", "-w", "stringname", NULL};
            execvp(exp[0], exp);
            perror("first grep failed");
            exit(EXIT_FAILURE);
        } else {
            // Execute second grep
            if (fork() == 0) {
                // Replace input with read end of 2nd pipe
                dup2(pipes[2], 0);

                // Close all ends of pipes
                close(pipes[0]);
                close(pipes[1]);
                close(pipes[2]);
                close(pipes[3]);

                char *exp[] = {"grep", "-c", "stringname", NULL};
                execvp(exp[0], exp);
                perror("second grep failed");
                exit(EXIT_FAILURE);
            }
        }
    }

    // Close all ends of pipes
    close(pipes[0]);
    close(pipes[1]);
    close(pipes[2]);
    close(pipes[3]);

    for (int i = 0; i < 3; i++) {
        wait(NULL);
    }

    return 0;
}
2
  • what's the purpose of the for loop at the end of your code
    – Sergio
    Commented Apr 9, 2020 at 14:44
  • wait() is required because only parent process will reach this point. We need to wait all child processes created with fork() to make sure, that they was completed, and free resources.
    – jubnzv
    Commented Apr 9, 2020 at 14:50

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.