0

So I am trying to use pipes to cat a file and to sed into a file called newfile.txt Currently the cat command works, using execvp, however it's outputing onto the command display. And then the program goes into an infinite loop when it goes to the sed command.

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

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

char *myargv2[]={"sed", "-e" "s/color/colour/g",  NULL};
char *myargv1[]={"cat", "colorfile.txt", NULL};

main()
{
    int f_des[2];
    int fd[2];
    int pipe(int filedes[2]);
    int file = open("newfile.txt",O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);

    if (file < 0)
        return 1;

    // create a pipe
    // Open a pipe and report error if it fails
    if (pipe(f_des)==-1)
    {
        perror("Pipe");
        exit(2);
    }

    //fork the process
    // Use switch for fork, because parent doesn't need child's pid.
    switch (fork())
    {
    case -1:  // Error
        perror("Fork");
        exit(2);

    case 0:   // Child
        printf("HERE1\n");
        //child will call dup2 to hook standard output to one end of the pipe. Then, execute the cat command using execvp
        dup2(fd[1], fileno(stdout));
        execvp(myargv1[0], myargv1);
        close(fd[1]);
        close(fd[0]);
        perror(myargv1[0]);
        close(fd[1]);
        close(fd[0]);
        printf("HERE12\n");

        exit(3);

    default:  // Parent
    {
        printf("HERE13\n");
        //parent will call dup2 to hook standard input to the other end of the pipe. Then, execute the sed command using execvp
        dup2(fd[0], fileno(stdin));
        execvp(myargv2[0], myargv2);
        perror(myargv2[0]);
        close(fd[1]);
        close(fd[0]);
        printf("HERE14\n");

        //parent will also call dup2 to hook standard output to the file called newfile.txt
        if(dup2(file,0 < 0))
            return 1;
    }

    exit(4);
    }

    return 0;
}

Obviously I'm struggling here. Can anyone point out what I'm doing wrong and/or point me to a good source of information on how to do this?

Thanks!

Eugene S
  • 3,092
  • 18
  • 34
  • 1
    it is better you first go through beginning linux programming easily available in net. If you start to study from chapter 10 then your each doubt will clear and I think this program is present on chapter 14. Check once this will very helpful for u. – asifaftab87 Mar 07 '14 at 01:41

1 Answers1

0

One primary problem is that you can't make up your mind whether to use f_des or fd for the pipe file descriptors. You have:

int f_des[2];
int fd[2];
int pipe(int filedes[2]);
…
if (pipe(f_des) == -1)
{
    perror("Pipe");
    exit(2);
}

The declaration of pipe() is not a good idea; that's what the system headers do. But the serious problem is that you create the pipe in f_des and thereafter work with fd.

The other problem is that you don't close the pipe file descriptors accurately. You also have a fair amount of superfluous code. This code works correctly:

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

static char *myargv2[]={"sed", "-e" "s/color/colour/g",  NULL};
static char *myargv1[]={"cat", "colorfile.txt", NULL};

int main(void)
{
    int fd[2];
    int pipe(int filedes[2]);
    int file = open("newfile.txt",O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);

    if (file < 0)
        return 1;

    if (pipe(fd)==-1)
    {
        perror("Pipe");
        exit(2);
    }

    switch (fork())
    {
    case -1:  // Error
        perror("Fork");
        exit(2);

    case 0:   // Child
        printf("HERE1\n");
        dup2(fd[1], fileno(stdout));
        close(fd[0]);  // Important (in general)
        close(fd[1]);  // Important (in general)
        execvp(myargv1[0], myargv1);
        perror(myargv1[0]);
        printf("HERE12\n");
        exit(3);

    default:  // Parent
        printf("HERE13\n");
        dup2(fd[0], fileno(stdin));
        close(fd[0]);  // Crucial
        close(fd[1]);  // Important (in general)
        execvp(myargv2[0], myargv2);
        perror(myargv2[0]);
        exit(4);
    }

    return 0;
}

A simple rule of thumb is:

  • If you dup() or dup2() one end of a pipe to standard input or standard output, you should close both of the raw pipe file descriptors.

Given input file colorfile.txt containing:

this is the color of danger
coloration is not important
end of file is.

The program's output is:

HERE13
HERE1
this is the colour of danger
colouration is not important
end of file is.

Interestingly, if the output of the program is piped to another program, the debugging information isn't printed. That's a consequence of default buffering.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278