Reputation: 278
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
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:
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.
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