1 /*
2  cleanup.c , Copyright 2006 - 2011 Thomas Schmitt <scdbackup@gmx.net>
3 
4  A signal handler which cleans up an application and exits.
5 
6  Provided under GPLv2+ license within GPL projects, BSD license elsewise.
7 */
8 
9 /*
10  cc -g -o cleanup -DCleanup_standalonE cleanup.c
11 */
12 
13 #ifdef HAVE_CONFIG_H
14 #include "../config.h"
15 #endif
16 
17 #include <sys/types.h>
18 #include <stdlib.h>
19 #include <unistd.h>
20 #include <stdio.h>
21 #include <string.h>
22 #include <errno.h>
23 
24 #include <signal.h>
25 typedef void (*sighandler_t)(int);
26 
27 
28 #include "cleanup.h"
29 
30 
31 #ifndef Cleanup_has_no_libburn_os_H
32 
33 
34 #include "../libburn/os.h"
35 
36 /* see os.h for name of particular os-*.h where this is defined */
37 static int signal_list[]=        { BURN_OS_SIGNAL_MACRO_LIST , -1};
38 static char *signal_name_list[]= { BURN_OS_SIGNAL_NAME_LIST , "@"};
39 static int signal_list_count=      BURN_OS_SIGNAL_COUNT;
40 static int non_signal_list[]=    { BURN_OS_NON_SIGNAL_MACRO_LIST, -1};
41 static int non_signal_list_count=  BURN_OS_NON_SIGNAL_COUNT;
42 
43 
44 #else /* ! Cleanup_has_no_libburn_os_H */
45 
46 
47 /* Outdated. GNU/Linux only.
48    For backward compatibility with pre-libburn-0.2.3 */
49 
50 /* Signals to be caught */
51 static int signal_list[]= {
52  SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGABRT,
53  SIGFPE, SIGSEGV, SIGPIPE, SIGALRM, SIGTERM,
54  SIGUSR1, SIGUSR2, SIGXCPU, SIGTSTP, SIGTTIN,
55  SIGTTOU,
56  SIGBUS, SIGPOLL, SIGPROF, SIGSYS, SIGTRAP,
57  SIGVTALRM, SIGXCPU, SIGXFSZ, -1
58 };
59 static char *signal_name_list[]= {
60  "SIGHUP", "SIGINT", "SIGQUIT", "SIGILL", "SIGABRT",
61  "SIGFPE", "SIGSEGV", "SIGPIPE", "SIGALRM", "SIGTERM",
62  "SIGUSR1", "SIGUSR2", "SIGXCPU", "SIGTSTP", "SIGTTIN",
63  "SIGTTOU",
64  "SIGBUS", "SIGPOLL", "SIGPROF", "SIGSYS", "SIGTRAP",
65  "SIGVTALRM", "SIGXCPU", "SIGXFSZ", "@"
66 };
67 static int signal_list_count= 24;
68 
69 /* Signals not to be caught */
70 static int non_signal_list[]= {
71   SIGKILL, SIGCHLD, SIGSTOP, SIGURG, SIGWINCH, -1
72 };
73 static int non_signal_list_count= 5;
74 
75 
76 #endif /* Cleanup_has_no_libburn_os_H */
77 
78 
79 
80 /* run time dynamic part */
81 static char cleanup_msg[4096]= {""};
82 static int cleanup_exiting= 0;
83 static int cleanup_has_reported= -1234567890;
84 
85 static void *cleanup_app_handle= NULL;
86 static Cleanup_app_handler_T cleanup_app_handler= NULL;
87 static int cleanup_perform_app_handler_first= 0;
88 
89 
Cleanup_handler_exit(int exit_value,int signum,int flag)90 static int Cleanup_handler_exit(int exit_value, int signum, int flag)
91 {
92  int ret;
93 
94  if(cleanup_msg[0]!=0 && cleanup_has_reported!=signum) {
95    fprintf(stderr,"\n%s\n",cleanup_msg);
96    cleanup_has_reported= signum;
97  }
98  if(cleanup_perform_app_handler_first)
99    if(cleanup_app_handler!=NULL) {
100      ret= (*cleanup_app_handler)(cleanup_app_handle,signum,0);
101      if(ret==2 || ret==-2)
102        return(2);
103    }
104  if(cleanup_exiting) {
105    fprintf(stderr,"cleanup: ABORT : repeat by pid=%.f, signum=%d\n",
106            (double) getpid(), signum);
107    return(0);
108  }
109  cleanup_exiting= 1;
110  alarm(0);
111  if(!cleanup_perform_app_handler_first)
112    if(cleanup_app_handler!=NULL) {
113      ret= (*cleanup_app_handler)(cleanup_app_handle,signum,0);
114      if(ret==2 || ret==-2)
115        return(2);
116    }
117  exit(exit_value);
118 }
119 
120 
Cleanup_handler_generic(int signum)121 static void Cleanup_handler_generic(int signum)
122 {
123  int i;
124 
125  sprintf(cleanup_msg,"UNIX-SIGNAL caught:  %d  errno= %d",signum,errno);
126  for(i= 0; i<signal_list_count; i++)
127    if(signum==signal_list[i]) {
128      sprintf(cleanup_msg,"UNIX-SIGNAL:  %s  errno= %d",
129              signal_name_list[i],errno);
130  break;
131    }
132  Cleanup_handler_exit(1,signum,0);
133 }
134 
135 
Cleanup_signo_to_name(int signo)136 static char *Cleanup_signo_to_name(int signo)
137 {
138  int i;
139  for(i= 0; i < signal_list_count; i++)
140    if(signal_list[i] == signo)
141      return(signal_name_list[i]);
142  return("");
143 }
144 
145 
Cleanup_set_handlers(void * handle,Cleanup_app_handler_T handler,int flag)146 int Cleanup_set_handlers(void *handle, Cleanup_app_handler_T handler, int flag)
147 /*
148  bit0= set to default handlers
149  bit1= set to ignore
150  bit2= set cleanup_perform_app_handler_first
151  bit3= set SIGABRT to handler (makes sense with bits 0 or 1)
152  bit8= set SIGPIPE to SIGIGN
153 */
154 {
155  int i,j,max_sig= -1,min_sig= 0x7fffffff;
156  char *sig_name;
157  sighandler_t sig_handler;
158 
159  cleanup_msg[0]= 0;
160  cleanup_app_handle= handle;
161  cleanup_app_handler= handler;
162 
163  /* <<< make cleanup_exiting thread safe to get rid of this */
164  if(flag&4)
165    cleanup_perform_app_handler_first= 1;
166 
167 
168  if(flag&1)
169    sig_handler= SIG_DFL;
170  else if(flag&2)
171    sig_handler= SIG_IGN;
172  else
173    sig_handler= Cleanup_handler_generic;
174  /* set all signal numbers between the lowest and highest in the list
175     except those in the non-signal list */
176  for(i= 0; i<signal_list_count; i++) {
177    if(signal_list[i]>max_sig)
178      max_sig= signal_list[i];
179    if(signal_list[i]<min_sig)
180      min_sig= signal_list[i];
181  }
182  for(i= min_sig; i<=max_sig; i++) {
183    for(j= 0; j<non_signal_list_count; j++)
184      if(i==non_signal_list[j])
185    break;
186    if(j>=non_signal_list_count) {
187      /* Avoid to use particular SIG macros which might not be defined.
188         If they are defined, then their names are in the name list.
189      */
190      if(flag & (8 | 256))
191        sig_name= Cleanup_signo_to_name(i);
192      else
193        sig_name= "";
194      if((flag & 8) && strcmp(sig_name, "SIGABRT") == 0)
195        signal(i,Cleanup_handler_generic);
196      else if((flag & 256) && strcmp(sig_name, "SIGPIPE") == 0)
197        signal(i, SIG_IGN);
198      else
199        signal(i,sig_handler);
200    }
201  }
202  return(1);
203 }
204 
205 
206 #ifdef Cleanup_standalonE
207 
208 struct Demo_apP {
209  char *msg;
210 };
211 
212 
Demo_app_handler(struct Demo_apP * demoapp,int signum,int flag)213 int Demo_app_handler(struct Demo_apP *demoapp, int signum, int flag)
214 {
215  printf("Handling exit of demo application on signal %d. msg=\"%s\"\n",
216         signum,demoapp->msg);
217  return(1);
218 }
219 
220 
main()221 main()
222 {
223  struct Demo_apP demoapp;
224 
225  demoapp.msg= "Good Bye";
226  Cleanup_set_handlers(&demoapp,(Cleanup_app_handler_T) Demo_app_handler,0);
227 
228  if(1) { /* change to 0 in order to wait for external signals */
229    char *cpt= NULL, c= ' ';
230    printf("Intentionally provoking SIGSEGV ...\n");
231    c= *cpt;
232    printf("Strange: The system ignored a SIGSEGV: c= %u\n", (unsigned int) c);
233  } else {
234    printf("killme: %d\n",getpid());
235    sleep(3600);
236  }
237 
238  Cleanup_set_handlers(NULL,NULL,1);
239  exit(0);
240 }
241 
242 #endif /* Cleanup_standalonE */
243