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