Input redirection problem while using execvp?
I have Implemented a simple program which simulates $ls -l | wc -c
command execution using simple pipes and execvp calls.
Now After redirecting stdin and stdout ,when executes the program , shell prompt disappears and it waits for the enter key to be pressed.
Any way of solving this issue . Plz criticize my code also..
Thanks
/* Create pipe */
ret_val=pipe(pipe_fd);
/*Error check */
if(ERROR==ret_val)
{
perror("Pipe creation error \n");
_exit(FAILURE);
}
/*Fork First Child */
pid_one = fork() ;
if( 0 == pid_one ) /*child process block */
{
/* First sub process */
/*printf("First sub process is %d \n",getpid());*/
/* redirect stdout to pipe's write end for sub process one*/
dup2(pipe_fd[1],1);
/*close pipe read end */
close(pipe_fd[0]);
execvp(cmd_one_tokens[0],cmd_one_tokens);
/* if execvp returns then if must have failed */
printf("Unknown Command \n ");
//exit(10);
}
else /*main process block */
{
/*printf(" Main process is %d \n",getpid());*/
/*Wait for first sub process to finish */
//wait(&status);
/*printf("Exit status of first child is %d \n ", WEXITSTATUS(status) );*/
/*Fork second subprocess */
pid_two = fork();
if( 0 == pid_two ) /*second child process block */
{
/* redirect stdin to pipe's read end for sub process two */
dup2(pipe_fd[0],0);
// close(0); /* close normal stdin */
// dup(pipe_fd[0]); /* make stdib same as pfds[0] */
/*close pipe write end */
close(pipe_fd[1]);
/* Second sub process */
/*printf("Second sub process is %d \n",getpid()); */
execvp(cmd_two_tokens[0] , cmd_two_tokens);
/* if execvp returns then if must have failed */
printf("Unknown Command \n ");
}
else /*main process block */
{
/* printf(" Main process is %d \n",getpid()); */
status=-1; /*reset status */
/*Waiting for the second sub process to finish in No hang fashion */
waitpid ( -1 , &status ,WNOHANG);
开发者_运维技巧 /*printf("Exit status of second child is %d \n ", WEXITSTATUS(status) ); */
}
}
You have to close the pipe file descriptors in the main process, after the second is forked. Until you have closed them, the child process (wc
) will wait for input on the pipe which the main process still has open. You must be very careful to close all the unneeded ends of the pipe.
Your code does not do what you describe you want to do:
You create a pipe, fork a new process, redirect it's stdout to the pipe and make it execute some program (so far so good), then in the parent process you wait for your child to finish and only then fork second process, redirect it's stdin to the pipe other end and make it execute another program.
This is not what "ls | wc" does - in the shell they are running concurrently. Remove the first wait().
pid_one = fork() ; if( 0 == pid_one ) /*child process block */
You're not checking fork(2)
for an error return, which is a very real possibility. (The user could be bumping up against their RLIMIT_NPROC
limit, kernel.threads-max
, run out of memory for holding task structures, etc.)
More idiomatic use of fork(2)
looks like this:
if(-1 == (pid = fork()) {
perror("fork");
exit(1); /* or return -1 or similar */
} else if (0 == pid) {
/* executing as child */
} else {
/* parent, pid is child */
}
execvp(cmd_two_tokens[0] , cmd_two_tokens); /* if execvp returns then if must have failed */ printf("Unknown Command \n ");
Note that there are many reasons why execvp(3)
can fail; simply printing "Unknown Command" may leave your users very confused in the future. It'd be better to call perror("execvp");
and give your users a chance to discover the real reason why their execvp(3)
call failed.
waitpid ( -1 , &status ,WNOHANG);
Use of WNOHANG
here might be dangerous; if the system is running "just right", your parent might get to this code before the child has even had a chance to begin executing. Because you've asked for it to return immediately if no child has exited, the child will probably be turned into a zombie when it finally does exit -- your code doesn't take the opportunity to wait for the child again.
I'm not sure what the best solution is: if you use SA_NOCLDWAIT
to sigaction(2)
to avoid creating zombies completely, you won't have an opportunity to ever collect the child's exit status. Installing a SIGCHLD
signal handler might interfere with the rest of the process; your clients might have reason to set it themselves. Using a blocking waitpid(2)
might stall processing elsewhere. And using a non-blocking waitpid(2)
means you still have to collect the child's status sometime, possibly through polling. (But you can't use -1
for the pid
in that case, as you might accidentally reap another child process.)
精彩评论