|
|
@ -0,0 +1,191 @@ |
|
|
|
/* |
|
|
|
cleanup.c , Copyright 2006 Thomas Schmitt <scdbackup@gmx.net> |
|
|
|
|
|
|
|
A signal handler which cleans up an application and exits. |
|
|
|
|
|
|
|
Provided under GPL license within GPL projects, BSD license elsewise. |
|
|
|
*/ |
|
|
|
|
|
|
|
/* |
|
|
|
cc -g -o cleanup -DCleanup_standalonE cleanup.c |
|
|
|
*/ |
|
|
|
|
|
|
|
#include <sys/types.h> |
|
|
|
#include <stdlib.h> |
|
|
|
#include <unistd.h> |
|
|
|
#include <stdio.h> |
|
|
|
#include <string.h> |
|
|
|
#include <errno.h> |
|
|
|
|
|
|
|
#include <signal.h> |
|
|
|
typedef void (*sighandler_t)(int); |
|
|
|
|
|
|
|
|
|
|
|
#include "cleanup.h" |
|
|
|
|
|
|
|
/* Signals to be caught */ |
|
|
|
static int signal_list[]= { |
|
|
|
SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGABRT, |
|
|
|
SIGFPE, SIGSEGV, SIGPIPE, SIGALRM, SIGTERM, |
|
|
|
SIGUSR1, SIGUSR2, SIGXCPU, SIGTSTP, SIGTTIN, |
|
|
|
SIGTTOU, |
|
|
|
SIGBUS, SIGPOLL, SIGPROF, SIGSYS, SIGTRAP, |
|
|
|
SIGVTALRM, SIGXCPU, SIGXFSZ, -1 |
|
|
|
}; |
|
|
|
static char *signal_name_list[]= { |
|
|
|
"SIGHUP", "SIGINT", "SIGQUIT", "SIGILL", "SIGABRT", |
|
|
|
"SIGFPE", "SIGSEGV", "SIGPIPE", "SIGALRM", "SIGTERM", |
|
|
|
"SIGUSR1", "SIGUSR2", "SIGXCPU", "SIGTSTP", "SIGTTIN", |
|
|
|
"SIGTTOU", |
|
|
|
"SIGBUS", "SIGPOLL", "SIGPROF", "SIGSYS", "SIGTRAP", |
|
|
|
"SIGVTALRM", "SIGXCPU", "SIGXFSZ", "@" |
|
|
|
}; |
|
|
|
static int signal_list_count= 24; |
|
|
|
|
|
|
|
/* Signals not to be caught */ |
|
|
|
static int non_signal_list[]= { |
|
|
|
SIGKILL, SIGCHLD, SIGSTOP, SIGURG, -1 |
|
|
|
}; |
|
|
|
static int non_signal_list_count= 4; |
|
|
|
|
|
|
|
|
|
|
|
/* run time dynamic part */ |
|
|
|
static char cleanup_msg[4096]= {""}; |
|
|
|
static int cleanup_exiting= 0; |
|
|
|
|
|
|
|
static void *cleanup_app_handle= NULL; |
|
|
|
static Cleanup_app_handler_T cleanup_app_handler= NULL; |
|
|
|
static int cleanup_perform_app_handler_first= 0; |
|
|
|
|
|
|
|
|
|
|
|
static int Cleanup_handler_exit(int exit_value, int signum, int flag) |
|
|
|
{ |
|
|
|
int ret; |
|
|
|
|
|
|
|
if(cleanup_perform_app_handler_first) |
|
|
|
if(cleanup_app_handler!=NULL) { |
|
|
|
ret= (*cleanup_app_handler)(cleanup_app_handle,signum,0); |
|
|
|
if(ret==2 || ret==-2) |
|
|
|
return(2); |
|
|
|
} |
|
|
|
if(cleanup_exiting) { |
|
|
|
if(cleanup_msg[0]!=0) |
|
|
|
fprintf(stderr,"%s\n",cleanup_msg); |
|
|
|
fprintf(stderr,"cleanup: ABORT : repeat by pid=%d, signum=%d\n", |
|
|
|
getpid(),signum); |
|
|
|
return(0); |
|
|
|
} |
|
|
|
cleanup_exiting= 1; |
|
|
|
if(cleanup_msg[0]!=0) |
|
|
|
fprintf(stderr,"\n%s\n",cleanup_msg); |
|
|
|
alarm(0); |
|
|
|
if(!cleanup_perform_app_handler_first) |
|
|
|
if(cleanup_app_handler!=NULL) { |
|
|
|
ret= (*cleanup_app_handler)(cleanup_app_handle,signum,0); |
|
|
|
if(ret==2 || ret==-2) |
|
|
|
return(2); |
|
|
|
} |
|
|
|
exit(exit_value); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static void Cleanup_handler_generic(int signum) |
|
|
|
{ |
|
|
|
int i; |
|
|
|
|
|
|
|
sprintf(cleanup_msg,"UNIX-SIGNAL caught: %d errno= %d",signum,errno); |
|
|
|
for(i= 0; i<signal_list_count; i++) |
|
|
|
if(signum==signal_list[i]) { |
|
|
|
sprintf(cleanup_msg,"UNIX-SIGNAL: %s errno= %d", |
|
|
|
signal_name_list[i],errno); |
|
|
|
break; |
|
|
|
} |
|
|
|
Cleanup_handler_exit(1,signum,0); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
int Cleanup_set_handlers(void *handle, Cleanup_app_handler_T handler, int flag) |
|
|
|
/* |
|
|
|
bit0= set to default handlers |
|
|
|
bit1= set to ignore |
|
|
|
bit2= set cleanup_perform_app_handler_first |
|
|
|
bit3= set SIGABRT to handler (makes sense with bits 0 or 1) |
|
|
|
*/ |
|
|
|
{ |
|
|
|
int i,j,max_sig= -1,min_sig= 0x7fffffff; |
|
|
|
sighandler_t sig_handler; |
|
|
|
|
|
|
|
cleanup_msg[0]= 0; |
|
|
|
cleanup_app_handle= handle; |
|
|
|
cleanup_app_handler= handler; |
|
|
|
|
|
|
|
/* <<< make cleanup_exiting thread safe to get rid of this */ |
|
|
|
if(flag&4) |
|
|
|
cleanup_perform_app_handler_first= 1; |
|
|
|
|
|
|
|
|
|
|
|
if(flag&1) |
|
|
|
sig_handler= SIG_DFL; |
|
|
|
else if(flag&2) |
|
|
|
sig_handler= SIG_IGN; |
|
|
|
else |
|
|
|
sig_handler= Cleanup_handler_generic; |
|
|
|
/* set all signal numbers between the lowest and highest in the list |
|
|
|
except those in the non-signal list */ |
|
|
|
for(i= 0; i<signal_list_count; i++) { |
|
|
|
if(signal_list[i]>max_sig) |
|
|
|
max_sig= signal_list[i]; |
|
|
|
if(signal_list[i]<min_sig) |
|
|
|
min_sig= signal_list[i]; |
|
|
|
} |
|
|
|
for(i= min_sig; i<=max_sig; i++) { |
|
|
|
for(j= 0; j<non_signal_list_count; j++) |
|
|
|
if(i==non_signal_list[j]) |
|
|
|
break; |
|
|
|
if(j>=non_signal_list_count) { |
|
|
|
if(i==SIGABRT && (flag&8)) |
|
|
|
signal(i,Cleanup_handler_generic); |
|
|
|
else |
|
|
|
signal(i,sig_handler); |
|
|
|
} |
|
|
|
} |
|
|
|
return(1); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
#ifdef Cleanup_standalonE |
|
|
|
|
|
|
|
struct Demo_apP { |
|
|
|
char *msg; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
int Demo_app_handler(struct Demo_apP *demoapp, int signum, int flag) |
|
|
|
{ |
|
|
|
printf("Handling exit of demo application on signal %d. msg=\"%s\"\n", |
|
|
|
signum,demoapp->msg); |
|
|
|
return(1); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
main() |
|
|
|
{ |
|
|
|
struct Demo_apP demoapp; |
|
|
|
|
|
|
|
demoapp.msg= "Good Bye"; |
|
|
|
Cleanup_set_handlers(&demoapp,(Cleanup_app_handler_T) Demo_app_handler,0); |
|
|
|
|
|
|
|
if(1) { /* change to 0 in order to wait for external signals */ |
|
|
|
char *cpt= NULL,c; |
|
|
|
printf("Intentionally provoking SIGSEGV ...\n"); |
|
|
|
c= *cpt; |
|
|
|
} else { |
|
|
|
printf("killme: %d\n",getpid()); |
|
|
|
sleep(3600); |
|
|
|
} |
|
|
|
|
|
|
|
Cleanup_set_handlers(NULL,NULL,1); |
|
|
|
exit(0); |
|
|
|
} |
|
|
|
|
|
|
|
#endif /* Cleanup_standalonE */ |