I'm using popen
to read the output of a third party program. I'd like to detect and restart things if the sub-program fails.
How would I do that? If the child dies, the process didn't exit normally and therefore can't use WEXITSTATUS
to check.
Is there another way?
Here's a simple example:
PINGER.C
#include <string.h>
#include <stdio.h>
#include <unistd.h>
int
main(int argc, char **argv)
{
int i = 0;
while (1)
{
//fprintf(stderr, "StdErr %d\n", i);
printf("stdout %d\n", i++);
fflush(stdout);
if (i == 5)
i = i / 0; // Die a horrible death
sleep(1);
}
}
WATCHER.C
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
int
main(int argc, char **argv)
{
char *cmd = "./pinger";
printf("Running '%s'\n", cmd);
FILE *fp = popen(cmd, "r");
if (!fp)
{
perror("popen failed:");
exit(1);
}
char inLine[1024];
int bytesRead = 0;
int i = 0;
while (fgets(inLine, sizeof(inLine), fp) != NULL)
{
int len = strlen(inLine);
if (inLine[len-1] == '\n')
inLine[len-1] = '\0';
printf("Received: '%s'\n", inLine);
}
printf("feof=%d ferror=%d: %s\n", feof(fp), ferror(fp), strerror(errno));
int rc = pclose(fp);
printf("pclose returned: %d. IFEXITED=%d\n", rc, WIFEXITED(rc));
}
Here's the output:
$ ./popenTest
calling popen
Running './pinger'
pipe open
Received: 'stdout 0'
Received: 'stdout 1'
Received: 'stdout 2'
Received: 'stdout 3'
Received: 'stdout 4'
feof=1 ferror=0: Success
pclose returned: 8. IFEXITED=0 EXITSTATUS=0
(According to this post, you actually can't use WEXITSTATUS
if the command didn't exit normally, but I tried anyway)
A process returns an exit status by returning from its main() with an exit code, or by calling _exit(statuscode). If the process is terminated abnormally, for example due to a signal or a fault, the process never gets a chance to do any of those, so there is no exitstatus.
In that case, all you can know is that the process terminates with an error.
If you want to restart on all cases where a program terminates on error, you need to check both WIFEXITED and WEXITSTATUS:
Read the POSIX specification of
pclose()
(andpopen()
too). It says:Thus, you can get the exit status of the process indirectly via the return value of
pclose()
. That will be a number between 0 and 255. Shells often report the 'death of a child by signal' by returning the value128 + signal_number
. The specification outlines circumstances in which the status may not be available (your program calledwait()
and got the information for the process opened bypopen()
before you calledpclose()
, for example). Reading the specification ofpopen()
explains the use of 'the command language interpreter' in the specification ofpclose()
.