Issue
I have a program which uses popen
and pclose
:
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/wait.h>
int main(void)
{
FILE *fp = NULL;
int ret_val = 0;
fp = popen("ls *", "r");
if (NULL == fp)
{
printf("popen error\n");
return 1;
}
ret_val = pclose(fp);
if (-1 == ret_val)
{
printf("pclose error\n");
return 1;
}
else
{
printf("%d,%d,%d\n",ret_val, WIFEXITED(ret_val), WEXITSTATUS(ret_val));
}
return 0;
}
The output of the program is:
./test
Broken Pipe
36096,1,141
My questions are:
- Why is there a "Broken pipe"?
- Why is the exit status code 141? I think "ls *" executed successfully and therefore, the exit status should be 0.
Solution
- "Broken pipe" is displayed by
ls
because the SIGPIPE signal is raised. - SIGPIPE is raised because
ls
is trying to output to a closed pipe. - The pipe is closed because your program immediately calls
pclose()
after yourpopen()
.
This behaviour of pclose
can be further understood by reading the documentation. Basically, pclose
will:
- Close a stream opened by a
popen()
call. - Wait for the command to terminate.
- Return the termination status of the command.
Since it closes the stream and then waits for the command to terminate, ls
can sometimes try to write to the stream after it was closed hence causing the mentioned scenario.
Additionally, as kingsindian pointed out, SIGPIPE may not be raised always. This is because the command can actually finish doing its work before the main process calls pclose()
. Since this behaviour is unpredictable, I suggest implementing some synchronization. You always want to know exactly what state your program is in at all times.
As a side note, pipes were meant for inter-process communication. If your main process just opens and closes a pipe, you might be better off using fork()
and exec()
.
Answered By - Anish Ramaswamy Answer Checked By - Senaida (WPSolving Volunteer)