The shell ignore SIGINT if not sent directly from the terminal
This long post explain what is happening in details. Here I'll try to summarise the most important concepts and propose a working solution.
It turns out that the shell is programmed to ignore the SIGINT if it is not directly sent from the terminal (by hitting CTRL-C
). If a subprocess intercepts it then it must exit by explicitly killing itself with SIGINT, quoting the post:
"If you don't catch SIGINT, the system automatically does the right
thing for you: Your program exits and the calling program gets the
right "I-exited-on-SIGINT" status after waiting for your exit.
But once you catch SIGINT, you have to take care of the proper way to
exit after whatever cleanup you do in your SIGINT handler.
Decide whether the SIGINT is used for exit/abort purposes and hence a
shellscript calling this program should discontinue. This is hopefully
obvious. If you just need to do some cleanup on SIGINT, but then exit
immediately, the answer is "yes".
If so, you have to tell the calling program about it by exiting with
the "I-exited-on-SIGINT" status.
There is no other way of doing this than to kill yourself with a
SIGINT signal. Do it by resetting the SIGINT handler to SIG_DFL, then
send yourself the signal.
void sigint_handler(int sig)
{
[do some cleanup]
signal(SIGINT, SIG_DFL);
kill(getpid(), SIGINT);
}
SIGINT Handler
Here is a working version of the handler that intercepts the signal and correctly kill itself (and thus it doesn't print 'program died').
OTOH, If you send a different signal the handler run the exit
function and you will see again 'program died' printed on the screen.
void sig_int(int sig_num)
{
if (sig_num == SIGINT) {
printf("received SIGINT\n");
signal(SIGINT, SIG_DFL);
kill(getpid(), SIGINT);
} else {
exit(1);
}
}
static struct sigaction sigact = { .sa_handler=sig_int };
int main(int argc, char *argv[])
{
sigaction(SIGINT,&sigact,NULL);
printf("go to sleep\n");
sleep(3);
printf("awaken\n");
return 0;
}