From the POSIX specification for system()
:
The system() function ignores the SIGINT and SIGQUIT signals, and blocks the SIGCHLD signal, while waiting for the command to terminate. If this might cause the application to miss a signal that would have killed it, then the application should examine the return value from system() and take whatever action is appropriate to the application if the command terminated due to receipt of a signal.
So, in order to respond properly to signals, you need to examine the return value of system()
.
system() returns the termination status of the command language interpreter in the format specified by waitpid()
And the docs of waitpid()
refer to the docs for wait()
, which instruct you to use the following macros to find out why a process exited:
- WIFEXITED(stat_val)
Evaluates to a non-zero value if status was returned for a child process that terminated normally.
- WEXITSTATUS(stat_val)
If the value of WIFEXITED(stat_val) is non-zero, this macro evaluates to the low-order 8 bits of the status argument that the child process passed to _exit() or exit(), or the value the child process returned from main().
- WIFSIGNALED(stat_val)
Evaluates to non-zero value if status was returned for a child process that terminated due to the receipt of a signal that was not caught (see ).
- WTERMSIG(stat_val)
If the value of WIFSIGNALED(stat_val) is non-zero, this macro evaluates to the number of the signal that caused the termination of the child process.
- WIFSTOPPED(stat_val)
Evaluates to a non-zero value if status was returned for a child process that is currently stopped.
- WSTOPSIG(stat_val)
If the value of WIFSTOPPED(stat_val) is non-zero, this macro evaluates to the number of the signal that caused the child process to stop.
- WIFCONTINUED(stat_val)
Evaluates to a non-zero value if status was returned for a child process that has continued from a job control stop.
Here is an example of how you would use this information, without having to fork a separate process. Note that you won't actually receive the signal in the parent process, but you can determine the signal sent to the child process:
#include <stdlib.h>
#include <stdio.h>
int main(void)
{
while(1)
{
int result = system("ls 2>&1 1>/dev/null");
if (WIFEXITED(result)) {
printf("Exited normally with status %d\n", WEXITSTATUS(result));
} else if (WIFSIGNALED(result)) {
printf("Exited with signal %d\n", WTERMSIG(result));
exit(1);
} else {
printf("Not sure how we exited.\n");
}
}
return 0;
}
And if you run it, you get:
$ ./sys
Exited normally with status 0
Exited normally with status 0
Exited normally with status 0
Exited normally with status 0
Exited normally with status 0
Exited normally with status 0
^CExited with signal 2