2

I am trying to create a child that calls sort. The parent sends data to the child through a pipe. My code compiles and runs, but there is no output. What am I doing wrong? Am I not closing the pipes correctly, writing the pipes or outputting the data correctly?

[eddit] On my system I need to call /bin/sort NOT /usr/bin/sort!

#include <sys/wait.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <ctype.h>

int main(void){
int pipes[2];
pid_t pid;
FILE *stream;

if(pipe(pipes) == -1)
    printf("could not create pipe\n");

switch(fork()){
    case -1:
        fprintf(stderr, "error forking\n");
        break;
    case 0:
        dup2(pipes[0], STDIN_FILENO);

        pid = getpid();
        printf("in child, pid=%d\n");

        if(close(pipes[1]) == -1)
            fprintf(stderr,"err closing write end pid=%d\n", pid);

        execl("/usr/bin/sort", "sort",  (char*) NULL);
        break;
    default:
        stream = fdopen(pipes[1], "w");
        pid = getpid();
        printf("in parent, pid=%d\n", pid);

        if (stream == NULL)
            fprintf(stderr, "could not create file streami\n");

        if(close(pipes[0]) == -1)
            printf("err closing read end pid=%d\n");

                   fputs("bob\n",stream);
        fputs("cat\n",stream);
        fputs("ace\n",stream);
        fputs("dog\n",stream);

        if(fclose(stream) == EOF)
            fprintf(stderr, "error while closing stream\n");
        break;
    }
    return 0;
}

[edit] Here is my working code. Thank you everyone

#include <sys/wait.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>

int main(void){
int pipes[2];
pid_t pid;
FILE *stream;

int stat;
if(pipe(pipes) == -1)
    printf("could not create pipe\n");

switch(fork()){
    case -1:
        fprintf(stderr, "error forking\n");
        break;
    case 0:
        dup2(pipes[0], STDIN_FILENO);

        pid = getpid();
        printf("in child, pid=%d\n", pid);

        if(close(pipes[1]) == -1)
            fprintf(stderr,"err closing write end pid=%d\n", pid);

        if(close(pipes[0]) == -1)
            fprintf(stderr,"err closing write end pid=%d\n", pid);

        execl("/bin/sort", "sort",  (char*) NULL);
        exit(EXIT_FAILURE);
        break;
    default:
        stream = fdopen(pipes[1], "w");
        pid = getpid();
        printf("in parent, pid=%d\n", pid);

        if (stream == NULL)
            fprintf(stderr, "could not create file streami\n");

        if(close(pipes[0]) == -1)
            printf("err closing read end pid=%d\n");

        fputs("bob\n",stream);
        fputs("cat\n",stream);
        fputs("ace\n",stream);
        fputs("dog\n",stream);

        if(fclose(stream) == EOF)
            fprintf(stderr, "error while closing stream\n");
        break;
}

wait(&stat);
return 0;
}   
cmartin0
  • 103
  • 1
  • 1
  • 7
  • 1
    Don't try to start with running "sort" in the child. First, make sure you can push data through the pipe from parent to child without any other issues to deal with. Also, I would suggest avoiding stdio initially and just use `read` and `write`, again to focus on getting the pipe working first. – Dale Hagglund Feb 13 '12 at 04:13
  • possible duplicate of [Having trouble with fork(), pipe(), dup2() and exec() in C](http://stackoverflow.com/questions/916900/having-trouble-with-fork-pipe-dup2-and-exec-in-c) - This is how to do it, and far more complete than my answer – Brian Roach Feb 13 '12 at 04:32
  • FWIW (not much) you only seem to need the `` and `` headers in the code as written. The others are superfluous in this program. – Jonathan Leffler Feb 13 '12 at 05:34

3 Answers3

8

You most certainly do not have enough close() calls in the code, which will lock the processes up.

Pseudo code:

Create pipe
Fork
In parent:
    Close read end of pipe
    Write data to be sorted down write end of pipe
    Close write end of pipe
    Wait for child to die
In child
    Close write end of pipe
    Duplicate read end of pipe to stdin
    Close read end of pipe
    Exec the sort program
    Exit with an error if the exec returns

Note that the pseudo code ends up closing all four ends of the pipe - the two in the parent and the two in the child. If you don't do that, you will run into deadlock.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • In parent I call fclose. This closes the stream along with the file descriptor fdopen used. I see that I am missing a close in the child. Thanks – cmartin0 Feb 13 '12 at 05:06
  • You have missing arguments to two `printf()` statements, which causes undefined behaviour...You don't close `pipe[0]` in the child, but I think that's actually harmless. Yes, I didn't notice that you closed the write stream - my bad. When I took your code and fixed the `printf()` statements and ran it on MacOS X 10.7.2, I got the expected 'ace', 'bob', 'cat', 'dog' output, albeit somewhat interleaved with shell prompts. It is always worth printing an error message after an `exec()`; if the `exec()` returns, it failed. – Jonathan Leffler Feb 13 '12 at 05:31
2

The only thing you're really missing is calling wait() or waitpid() at the end of the parent's code, so that it doesn't exit until the child has finished.

caf
  • 233,326
  • 40
  • 323
  • 462
0

No arguments to sort command. Simply running an execl will not work. A simple program to test would be:

int main(void){
execl("/bin/sort","/bin/sort","filename", (char*) NULL);
}

I will try to create a simple program for you to analyze the situation.

Here you go, try this code:

int main(void){
        int pipefd[2];
        pid_t pid = 0;
        int status;
        char data[100]={0};
        int fildes[2] ;
        int nbytes;
        char buf[100]={0};
        status = pipe(fildes);
        if (status == -1 ) {
         // handle eerrror.
        }

        switch (fork()) {
                case -1: /* Handle error */
                        break;
                case 0:  /* Child - reads from pipe */
                        close(fildes[1]);                       /* Write end is unused */
                        nbytes = read(fildes[0], buf, 100);   /* Get data from pipe */
                        fprintf(stderr,"Inside child val recieved is %s\n", buf);
                        /* At this point, a further read would see end of file ... */
                        execl("/bin/sort", "/bin/sort",buf,  (char*) NULL);
                        close(fildes[0]);                       /* Finished with pipe */
                        exit(0);
                default:  /* Parent - writes to pipe */
                        close(fildes[0]);                       /* Read end is unused */
                        write(fildes[1], "file", strlen("file"));  /* Write data on pipe */
                        close(fildes[1]);                       /* Child will see EOF */
                        exit(0);
        }
}

Here "file" is a file which need to be sorted.

Hope you can customize it as per your need.

Enjoy..!!!

  • from the man page for sort " With no FILE, or when FILE is -, read standard input." I am redirecting the standard input for sort to read from the pipe. – cmartin0 Feb 13 '12 at 04:46
  • The code after execl() is called only if excel() failed, so you should't put stuff their – Yuval Sep 26 '16 at 16:05