I want to detect the kill signal of my program inorder to execute some C instruction before leaving my program. my program is running on linux
Is it possible to do that? If yes how I can do it?
You can register a signal handler using sigaction(). Note that you cannot handle SIGKILL or SIGSTOP though.
No, SIGKILL can not be handled, maybe you want to catch CTRL+C, then:
#include <stdio.h>
#include <signal.h>
volatile sig_atomic_t stop;
void
inthand(int signum)
{
stop = 1;
}
int
main(int argc, char **argv)
{
signal(SIGINT, inthand);
while (!stop)
printf("a");
printf("exiting safely\n");
return 0;
}
Will do the trick
If SIGKILL or SIGTERM is sent to your process you cannot mask or ignore the signal. Other signals you can handle and mask it.
Related
I need some help on C program - it is a reverse shell (https://github.com/arturgontijo/remoteShell/blob/master/reverseShell.c) I made few changes, like put that all in a loop and some sleep pattern + put some argument to pass directly IP and PORT now that thing works very good it's stable (problem that cannot autocomplete stuff with TAB I don't really care) BUT what I really care is that this thing will break if on target machine I press CTRL+C the program just exits itself. Now I used this example to block CTRL+C calls:
/* Signal Handler for SIGINT */
void sigintHandler(int sig_num)
{
/* Reset handler to catch SIGINT next time.
Refer http://en.cppreference.com/w/c/program/signal */
signal(SIGINT, sigintHandler);
printf("\n Cannot be terminated using Ctrl+C \n");
fflush(stdout);
}
signal(SIGINT, sigintHandler);
I got this example online and put it on my loop as well, but still from client pressing ctrl+C breaks program. I wonder dup2() is responsible for that or something because on simple C program this actually worked fine.
You can use the sigetops family of functions to manipulate the signals sent into your application.
So for your example you could use:
#include <signal.h>
#include <unistd.h>
int main(int argc, char **argv)
{
sigset_t block_set;
sigemptyset(&block_set);
sigaddset(&block_set, SIGINT);
sigprocmask(SIG_BLOCK, &block_set, NULL);
while(1) {
sleep(1);
}
}
Running Example: https://repl.it/repls/RelevantImaginarySearchservice
You can unblock the signal at a later time by calling
sigprocmask(SIG_UNBLOCK, &block_set, NULL);
I'm trying to make a C program that can continue running also after a CTRL+C.
I wrote this:
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
void acceptCommands();
void sighandle_int(int sign)
{
//system("^C;./a.out"); *out:* ^Csh: ^C: command not found
// how to protect here the app from being killed?
}
int main(int argc, char **argv)
{
signal(SIGINT, sighandle_int);
acceptCommands();
return 0;
}
how can i do?
Thank you
I'm trying to make a C program that can continue running also after a CTRL+C. ? when the process receives CTRL+C you set the handler for that using sigaction() and in that handler you can specify whether to continue or ignore or whatever you want.
May be you want like this
void sighandle_int(int sign) {
/*when process receives SIGINT this isr will be called,
here you can specify whether you want to continue or ignore,
by signal handler again */
signal(SIGINT,SIG_IGN);
//or
signal(SIGINT,sighandle_int);
}
Meanwhile use sigaction() instead of signal() as told here What is the difference between sigaction and signal?
static void AlarmHandler(int sig) ;
int i=0;
jmp_buf mark;
int main(int argc, char * argv[]){
setjmp(mark);
signal(SIGALRM, AlarmHandler);
alarm(2);
while(1);
return 0;
}
static void AlarmHandler(int sig) {
signal(SIGALRM, SIG_IGN);
printf("I am in AlarmHandler: %d \n",i);
i++;
longjmp(mark, 0);
}
When I run this code the program goes through the AlarmHandler only once and then it just stays trapped inside the while loop. Can someone explain why?
Your program might work as you expected on some POSIXy operating systems -- in fact, it does work as you expected on the computer I'm typing this on. However, it relies on a bunch of unspecified behavior relating to signals, and I think you've tripped over one of them: I think that on your computer, a signal is "blocked" — it can't be delivered again — while its handler is executing, and also, jumping out of the handler with longjmp does not unblock the signal. So you go around the loop once and then the second SIGALRM is never delivered because it's blocked. There are several other, related problems.
You can nail down all of the unspecified behavior and make the program reliable on all POSIXy operating systems, but you have to use different functions to set things up: sigsetjmp and sigaction. You should also get rid of the busy-waiting by using sigsuspend instead. A corrected program would look something like this:
#define _XOPEN_SOURCE 700
#include <signal.h>
#include <setjmp.h>
#include <stdio.h>
#include <unistd.h>
static jmp_buf mark;
static void
handle_SIGALRM(int sig)
{
static int signal_count;
signal_count++;
printf("SIGALRM #%u\n", signal_count);
siglongjmp(mark, signal_count);
}
int
main(void)
{
sigset_t mask, omask;
sigemptyset(&mask);
sigaddset(&mask, SIGALRM);
if (sigprocmask(SIG_BLOCK, &mask, &omask)) {
perror("sigprocmask");
return 1;
}
struct sigaction sa;
sigfillset(&sa.sa_mask);
sa.sa_flags = 0; // DO interrupt blocking system calls
sa.sa_handler = handle_SIGALRM;
if (sigaction(SIGALRM, &sa, 0)) {
perror("sigaction");
return 1;
}
if (sigsetjmp(mark, 1) >= 4)
return 0;
alarm(1);
sigsuspend(&omask);
perror("shouldn't ever get here");
return 1;
}
I should probably say a few words about signal safety: In this program, it is safe to call printf and siglongjmp from the signal handler, because I have arranged for the SIGALRM only to be deliverable while the main thread of execution is blocked on sigsuspend. (That's what the call to sigprocmask up top does.) If you had anything to do in your main thread of execution besides sleep waiting for the signal to arrive, you would have to be much more careful about what you did in the signal handler, and I would advocate for using pselect and/or the self-pipe trick instead of jumping out of the handler, if at all possible.
When you press Ctrl-C, foreground processes receive SIGINT:
$ bash -c 'sleep 100; echo program died'
^C
$ echo $?
130
However, if a program installs a SIGINT handler, parent program doesn't receive the signal. Why?
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <stdlib.h>
#include <stdio.h>
void sig_int(int sig_num)
{
exit(1);
}
static struct sigaction sigact = { .sa_handler=sig_int };
int main(int argc, char *argv[])
{
sigaction(SIGINT,&sigact,NULL);
sleep(100);
return 0;
}
bash didn't die:
$ bash -c './a.out; echo program died'
^Cprogram died
Related to Bash not trapping interrupts during rsync/subshell exec statements , but all answers there are workarounds.
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;
}
I am playing with the signal.h and unistd.h libraries, and I am having some issues. In the code below, when I send the SIGINT signal to my running program by calling CTRL-C, the signal is caught. However, when pressing CTRL-C again, the program terminates. As I understand it, the print statement "Received signal 2" should be printed every time I press CTRL-C.
Is my understanding of this signal incorrect, or is there a bug in my code?
Thanks for your input!
#include "handle_signals.h"
void sig_handler(int signum)
{
printf("\nReceived signal %d\n", signum);
}
int main()
{
signal(SIGINT, sig_handler);
while(1)
{
sleep(1);
}
return 0;
}
Terminal output:
xxx#ubuntu:~/Dropbox/xxx/handle_signals$ ./handle_signals
^C
Received signal 2
^C
xxx#ubuntu:~/Dropbox/xxx/handle_signals$
Edit: Here is the header I've included
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
void sig_handler(int signum);
Thanks for your responses. Reading through them now!
Don't use signal, use sigaction:
The behavior of signal() varies across UNIX versions, and has also varied historically across different versions of Linux. Avoid its use: use sigaction(2) instead.
http://man7.org/linux/man-pages/man2/signal.2.html
In the original UNIX systems, when a handler that was established using signal() was invoked by the delivery of a signal, the disposition of the signal would be reset to SIG_DFL, and the system did not block delivery of further instances of the signal.
Linux implements the same semantics: the handler is reset when the signal is delivered.
The behaviour of signal upon receiving the first signal varies on different implementation. Typically, it requires reinstalling the handler after receiving the signal as handler is reset to its default action:
void sig_handler(int signum)
{
signal(SIGINT, sig_handler);
printf("\nReceived signal %d\n", signum);
}
which is one of the reasons you shouldn't use signal anymore and use sigaction. You can see a bare bone example of using sigaction here.