I try to write a program in C language that takes a simple Linux command in input like "ls /home". This command is executed in child process with "execvp" and sent to the parent process to be displayed on the screen..
My problem is that the program is running and display nothing and don't give back the prompt. I have to quit with "ctrl + C".
Is the problem in the while loop or my pipe send my command nowhere?
Thanks for your feedback
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
int main(int argc, char* argv[])
{
int fd[2];
int pid;
pipe(fd);
if((pid = fork()) == -1)
{
perror("fork");
exit(1);
}
if(pid == 0)
{
close(fd[0]);
dup2(fd[1], STDOUT_FILENO);
close(fd[1]);
execvp(argv[1], &argv[1]);
}
else
{
close(fd[1]);
dup2(fd[0], STDIN_FILENO);
close(fd[0]);
char result;
while(read(fd[0], &result, sizeof(result) > 0))
{
write(fd[1], &result, sizeof(result));
}
wait(NULL);
}
close(fd[1]);
close(fd[0]);
return(0);
}
In the parent , the read loop has problems. Compare
while(read(fd[0], &result, sizeof(result) > 0))
to
while(read(fd[0], &result, sizeof(result)) > 0)
The former, in your program, is using the result of the comparison sizeof(result) > 0
as the size of the buffer, and looping as long as read
returns a nonzero value.
Note that result
is a char
, and sizeof (char)
is guaranteed to be 1
.
1 > 0
is 1
, which just happens to be the size of your buffer, so this partially works. The loop will continue on error ( -1
) though, and will continue to attempt writing output.
It is also trying to read from fd[0]
, which was closed after
dup2(fd[0], STDIN_FILENO);
close(fd[0]);
This duplication is not needed.
Additionally,
write(fd[1], &result, sizeof(result));
is attempting to write the output back into the pipe. That said, the parent closed this file descriptor earlier ( close(fd[1]);
).
Note the close(fd[1]);
outside of the else
block is redundant (and redundant closes can be a source of bugs in more complex programs).
In the child , you should handle the event that execvp
fails, because if the function succeeds, it never returns. Anything expected to run after execvp
is operating in a failure state (in your program, that is the lines after the else block).
A cursory example:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
int main(int argc, char **argv)
{
int fd[2];
pid_t pid;
if (argc < 2) {
fprintf(stderr, "too few arguments\n");
exit(EXIT_FAILURE);
}
if (-1 == pipe(fd)) {
perror("pipe");
exit(EXIT_FAILURE);
}
if (-1 == (pid = fork())) {
perror("fork");
exit(EXIT_FAILURE);
}
if (pid == 0) {
/* child */
close(fd[0]);
dup2(fd[1], STDOUT_FILENO);
close(fd[1]);
argv++;
execvp(*argv, argv);
perror("execvp");
exit(EXIT_FAILURE);
}
/* parent */
char result;
close(fd[1]);
while (read(fd[0], &result, 1) > 0)
write(STDOUT_FILENO, &result, 1);
close(fd[0]);
wait(NULL);
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.