Implementing pipe in C

I am trying to implement pipe in C. eg - $ ls | wc | wc

I have written the following code -

#include<stdio.h>
#include<stdlib.h>
#include <unistd.h>

void run_cmd(char *cmd, int* fd_in, int* fd_out)
{
    int c = fork();

    if (c==0)
    {
        if (fd_in != NULL)
        {
            close(fd_in[1]);
            dup2(fd_in[0], 0);
        }
        if (fd_out != NULL)
        {
            close(fd_out[0]);
            dup2(fd_out[1],1);
        }
        execlp(cmd, cmd, NULL);
    }
}

int main(int argc, char **argv)
{
    int fd_1[2], fd_2[2], i;
    pipe(fd_1);
    pipe(fd_2);

    run_cmd(argv[1], NULL, fd_1);

    for( i=2; i<argc-1; i++)
    {
        if (i%2 == 0)
            run_cmd(argv[i], fd_1, fd_2);
        else
            run_cmd(argv[i], fd_2, fd_1);
    }
    if (i%2 == 0)
        run_cmd(argv[i], fd_1, NULL);
    else
        run_cmd(argv[i], fd_2, NULL);
}

This works fine with two arguments, eg - $./a.out ls wc

But when I try with more than two arguments it does not work.

Would anyone please tell me what's wrong with my code, or any other way to do this?


This does virtually no error checking, but why so complicated?

int main (int argc, char ** argv) {
    int i;

    for( i=1; i<argc-1; i++)
    {
        int pd[2];
        pipe(pd);

        if (!fork()) {
            dup2(pd[1], 1); // remap output back to parent
            execlp(argv[i], argv[i], NULL);
            perror("exec");
            abort();
        }

        // remap output from previous child to input
        dup2(pd[0], 0);
        close(pd[1]);
    }

    execlp(argv[i], argv[i], NULL);
    perror("exec");
    abort();
}

If your are still interested in why your source didn't work (Sergey's solution is better anyway):

The problem is not closing the write side of fd_1 in the parent process. Thus both argv[1] and parent have been writers to that pipe and that caused the confusion. Please don't ask for more details (esp. why the prob doesn't occur if you use only one pipe) but your original source will run with tree processes if you just add a close( fd_1[1] ); after the first call of run_cmd()