xjsc16x
xjsc16x

Reputation: 278

C - exec not outputting into pipe

I am making a program that will eventually be able to work for (theoretically) any shell command passed to it. My problem is that the exec that runs will not put its output into the pipe, and instead when run it seems as if the initial call is going into the pipe instead? I tried flushing the stdout first but it will not work. Any help is appreciated!

int main(int argc, char *argv[]) {

    int i=0, pid;
    int dataPipe[2];
    pipe(dataPipe);

    char *newArgs[5] = {"/bin/sh", "-c", "ls", "-a", NULL};

    if ((pid = fork()) < 0) {

        printf("Error: could not fork!");
        exit(2);
    }

    else if (pid == 0) {

        close(dataPipe[0]);
        fflush(stdout);

        dup2(dataPipe[1], 1);
        close(dataPipe[1]);

        if (execvp(newArgs[0], newArgs) < 0) {

            printf("Command Failed to exucute!");
            exit(3);
        }
    }

    else {

        char buf[BUFFER];
        close(dataPipe[1]);

        wait(0);
        printf("Command exexuted correctly!\n");

        while(read(dataPipe[0], buf, BUFFER) != 0) {
            printf("Here is the command's output:\n%s\n", buf);
        }

        exit(0);
    }

    return 0;
}

Here is the output:

$ ./doit ls -a                                       
Command exexuted correctly!
Here is the command's output:
d
@
Here is the command's output:
o
@
Here is the command's output:
i
@
Here is the command's output:
t
@
Here is the command's output:
@
Here is the command's output:
d
@
Here is the command's output:
o
@
Here is the command's output:
i
@
Here is the command's output:
t
@
Here is the command's output:
.
@
Here is the command's output:
c
@
Here is the command's output:


@

Upvotes: 3

Views: 1634

Answers (1)

R Sahu
R Sahu

Reputation: 206567

You have got everything correct. There are only couple of changes needed in your code to make everything work.

Change the lines:

    while(read(dataPipe[0], buf, BUFFER) != 0) {
        printf("Here is the command's output:\n%s\n", buf);
    }

to

    printf("Here is the command's output:\n");
    while( (count = read(dataPipe[0], buf, BUFFER)) != 0) {
       fwrite(buf, count, 1, stdout);
    }

The first change, moving the printing of "Here is the command's output:\n" should be obvious. You don't want to print that line every time some data is successfully read.

The second change is a little bit more subtle.

The line:

printf("%s\n", buf);

is quite different from the line:

fwrite(buf, count, 1, stdout);

There are couple of problems with the printf approach:

  1. In the printf call, you are introducing newlines to the output for every successful completion of read, which are not there in the output of the forked process.

  2. The printf command works only if buf is a null-terminated string. read does not create a null-terminated string. With read, you are getting an array of raw characters. By using buf in a place where a null-terminated string is expected, you are invoking undefined behavior.

Using fwrite instead of printf takes care of both issues. It does not print any additional newline characters. It only prints the exact numbers of bytes read from the pipe.

Upvotes: 5

Related Questions