1 /*
2    BAREOS® - Backup Archiving REcovery Open Sourced
3 
4    Copyright (C) 2000-2012 Free Software Foundation Europe e.V.
5 
6    This program is Free Software; you can redistribute it and/or
7    modify it under the terms of version three of the GNU Affero General Public
8    License as published by the Free Software Foundation and included
9    in the file LICENSE.
10 
11    This program is distributed in the hope that it will be useful, but
12    WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14    Affero General Public License for more details.
15 
16    You should have received a copy of the GNU Affero General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19    02110-1301, USA.
20 */
21 /*
22  * Signal handlers for BAREOS daemons
23  *
24  * Kern Sibbald, April 2000
25  *
26  * Note, we probably should do a core dump for the serious
27  * signals such as SIGBUS, SIGPFE, ...
28  * Also, for SIGHUP and SIGUSR1, we should re-read the
29  * configuration file.  However, since this is a "general"
30  * routine, we leave it to the individual daemons to
31  * tweak their signals after calling this routine.
32  */
33 
34 #ifndef HAVE_WIN32
35 #include "include/bareos.h"
36 #include "lib/watchdog.h"
37 #include "lib/berrno.h"
38 #include "lib/bsignal.h"
39 
40 #ifndef _NSIG
41 #define BA_NSIG 100
42 #else
43 #define BA_NSIG _NSIG
44 #endif
45 
46 extern char my_name[];
47 extern char* exepath;
48 extern char* exename;
49 extern bool prt_kaboom;
50 
51 static const char* sig_names[BA_NSIG + 1];
52 
53 typedef void(SIG_HANDLER)(int sig);
54 static SIG_HANDLER* exit_handler;
55 
56 /* main process id */
57 static pid_t main_pid = 0;
58 
get_signal_name(int sig)59 const char* get_signal_name(int sig)
60 {
61   if (sig < 0 || sig > BA_NSIG || !sig_names[sig]) {
62     return _("Invalid signal number");
63   } else {
64     return sig_names[sig];
65   }
66 }
67 
68 /* defined in jcr.c */
69 extern void DbgPrintJcr(FILE* fp);
70 /* defined in plugins.c */
71 extern void DbgPrintPlugin(FILE* fp);
72 
73 /*
74  * !!! WARNING !!!
75  *
76  * This function should be used ONLY after a violent signal. We walk through the
77  * JobControlRecord chain without locking, BAREOS should not be running.
78  */
dbg_print_bareos()79 static void dbg_print_bareos()
80 {
81   char buf[512];
82 
83   snprintf(buf, sizeof(buf), "%s/%s.%d.bactrace", working_directory, my_name,
84            (int)getpid());
85   FILE* fp = fopen(buf, "a+");
86   if (!fp) { fp = stderr; }
87 
88   fprintf(stderr, "Dumping: %s\n", buf);
89 
90   /* Print also BareosDb and RWLOCK structure
91    * Can add more info about JobControlRecord with DbgJcrAddHook()
92    */
93   DbgPrintJcr(fp);
94   DbgPrintPlugin(fp);
95 
96   if (fp != stderr) {
97     if (prt_kaboom) {
98       rewind(fp);
99       printf("\n\n ==== bactrace output ====\n\n");
100       while (fgets(buf, (int)sizeof(buf), fp) != NULL) { printf("%s", buf); }
101       printf(" ==== End baktrace output ====\n\n");
102     }
103     fclose(fp);
104   }
105 }
106 
107 /*
108  * Handle signals here
109  */
SignalHandler(int sig)110 extern "C" void SignalHandler(int sig)
111 {
112   static int already_dead = 0;
113   int chld_status = -1;
114 
115   /*
116    * If we come back more than once, get out fast!
117    */
118   if (already_dead) { exit(1); }
119   Dmsg2(900, "sig=%d %s\n", sig, sig_names[sig]);
120 
121   /*
122    * Ignore certain signals -- SIGUSR2 used to interrupt threads
123    */
124   if (sig == SIGCHLD || sig == SIGUSR2) { return; }
125   already_dead++;
126 
127   /*
128    * Don't use Emsg here as it may lock and thus block us
129    */
130   if (sig == SIGTERM) {
131     syslog(LOG_DAEMON | LOG_ERR, "Shutting down BAREOS service: %s ...\n",
132            my_name);
133   } else {
134     fprintf(stderr, _("BAREOS interrupted by signal %d: %s\n"), sig,
135             get_signal_name(sig));
136     syslog(LOG_DAEMON | LOG_ERR, _("BAREOS interrupted by signal %d: %s\n"),
137            sig, get_signal_name(sig));
138   }
139 
140   if (sig != SIGTERM) {
141     struct sigaction sigdefault;
142     static char* argv[5];
143     static char pid_buf[20];
144     static char btpath[400];
145     char buf[400];
146     pid_t pid;
147     int exelen = strlen(exepath);
148 
149     fprintf(stderr, _("%s, %s got signal %d - %s. Attempting traceback.\n"),
150             exename, my_name, sig, get_signal_name(sig));
151     fprintf(stderr, _("exepath=%s\n"), exepath);
152 
153     if (exelen + 12 > (int)sizeof(btpath)) {
154       bstrncpy(btpath, "btraceback", sizeof(btpath));
155     } else {
156       bstrncpy(btpath, exepath, sizeof(btpath));
157       if (IsPathSeparator(btpath[exelen - 1])) { btpath[exelen - 1] = 0; }
158       bstrncat(btpath, "/btraceback", sizeof(btpath));
159     }
160     if (!IsPathSeparator(exepath[exelen - 1])) { strcat(exepath, "/"); }
161     strcat(exepath, exename);
162     if (!working_directory) {
163       working_directory = buf;
164       *buf = 0;
165     }
166     if (*working_directory == 0) { strcpy((char*)working_directory, "/tmp/"); }
167     if (chdir(working_directory) != 0) { /* dump in working directory */
168       BErrNo be;
169       Pmsg2(000, "chdir to %s failed. ERR=%s\n", working_directory,
170             be.bstrerror());
171       strcpy((char*)working_directory, "/tmp/");
172     }
173     SecureErase(NULL, "./core"); /* get rid of any old core file */
174 
175 #ifdef DEVELOPER /* When DEVELOPER not set, this is done below */
176     /*
177      * Print information about the current state into working/<file>.bactrace
178      */
179     dbg_print_bareos();
180 #endif
181 
182     sprintf(pid_buf, "%d", (int)main_pid);
183     Dmsg1(300, "Working=%s\n", working_directory);
184     Dmsg1(300, "btpath=%s\n", btpath);
185     Dmsg1(300, "exepath=%s\n", exepath);
186     switch (pid = fork()) {
187       case -1: /* error */
188         fprintf(stderr, _("Fork error: ERR=%s\n"), strerror(errno));
189         break;
190       case 0:              /* child */
191         argv[0] = btpath;  /* path to btraceback */
192         argv[1] = exepath; /* path to exe */
193         argv[2] = pid_buf;
194         argv[3] = (char*)working_directory;
195         argv[4] = (char*)NULL;
196         fprintf(stderr, _("Calling: %s %s %s %s\n"), btpath, exepath, pid_buf,
197                 working_directory);
198         if (execv(btpath, argv) != 0) {
199           BErrNo be;
200           printf(_("execv: %s failed: ERR=%s\n"), btpath, be.bstrerror());
201         }
202         exit(-1);
203       default: /* parent */
204         break;
205     }
206 
207     /*
208      * Parent continue here, waiting for child
209      */
210     sigdefault.sa_flags = 0;
211     sigdefault.sa_handler = SIG_DFL;
212     sigfillset(&sigdefault.sa_mask);
213 
214     sigaction(sig, &sigdefault, NULL);
215     if (pid > 0) {
216       Dmsg0(500, "Doing waitpid\n");
217       waitpid(pid, &chld_status, 0); /* wait for child to produce dump */
218       Dmsg0(500, "Done waitpid\n");
219     } else {
220       Dmsg0(500, "Doing sleep\n");
221       Bmicrosleep(30, 0);
222     }
223     if (WEXITSTATUS(chld_status) == 0) {
224       fprintf(stderr, _("It looks like the traceback worked...\n"));
225     } else {
226       fprintf(stderr, _("The btraceback call returned %d\n"),
227               WEXITSTATUS(chld_status));
228     }
229 
230     /*
231      * If we want it printed, do so
232      */
233     if (prt_kaboom) {
234       FILE* fd;
235 
236       snprintf(buf, sizeof(buf), "%s/bareos.%s.traceback", working_directory,
237                pid_buf);
238       fd = fopen(buf, "r");
239       if (fd != NULL) {
240         printf("\n\n ==== Traceback output ====\n\n");
241         while (fgets(buf, (int)sizeof(buf), fd) != NULL) { printf("%s", buf); }
242         fclose(fd);
243         printf(" ==== End traceback output ====\n\n");
244       }
245     }
246 #ifndef DEVELOPER /* When DEVELOPER set, this is done above */
247     /*
248      * Print information about the current state into working/<file>.bactrace
249      */
250     dbg_print_bareos();
251 #endif
252   }
253   exit_handler(sig);
254   Dmsg0(500, "Done exit_handler\n");
255 }
256 
257 /*
258  * Init stack dump by saving main process id -- needed by debugger to attach to
259  * this program.
260  */
InitStackDump(void)261 void InitStackDump(void) { main_pid = getpid(); /* save main thread's pid */ }
262 
263 /*
264  * Initialize signals
265  */
InitSignals(void Terminate (int sig))266 void InitSignals(void Terminate(int sig))
267 {
268   struct sigaction sighandle;
269   struct sigaction sigignore;
270   struct sigaction sigdefault;
271 #ifdef _sys_nsig
272   int i;
273 
274   exit_handler = Terminate;
275   if (BA_NSIG < _sys_nsig) {
276     Emsg2(M_ABORT, 0, _("BA_NSIG too small (%d) should be (%d)\n"), BA_NSIG,
277           _sys_nsig);
278   }
279 
280   for (i = 0; i < _sys_nsig; i++) { sig_names[i] = _sys_siglist[i]; }
281 #else
282   exit_handler = Terminate;
283   sig_names[0] = _("UNKNOWN SIGNAL");
284   sig_names[SIGHUP] = _("Hangup");
285   sig_names[SIGINT] = _("Interrupt");
286   sig_names[SIGQUIT] = _("Quit");
287   sig_names[SIGILL] = _("Illegal instruction");
288   sig_names[SIGTRAP] = _("Trace/Breakpoint trap");
289   sig_names[SIGABRT] = _("Abort");
290 #ifdef SIGEMT
291   sig_names[SIGEMT] = _("EMT instruction (Emulation Trap)");
292 #endif
293 #ifdef SIGIOT
294   sig_names[SIGIOT] = _("IOT trap");
295 #endif
296   sig_names[SIGBUS] = _("BUS error");
297   sig_names[SIGFPE] = _("Floating-point exception");
298   sig_names[SIGKILL] = _("Kill, unblockable");
299   sig_names[SIGUSR1] = _("User-defined signal 1");
300   sig_names[SIGSEGV] = _("Segmentation violation");
301   sig_names[SIGUSR2] = _("User-defined signal 2");
302   sig_names[SIGPIPE] = _("Broken pipe");
303   sig_names[SIGALRM] = _("Alarm clock");
304   sig_names[SIGTERM] = _("Termination");
305 #ifdef SIGSTKFLT
306   sig_names[SIGSTKFLT] = _("Stack fault");
307 #endif
308   sig_names[SIGCHLD] = _("Child status has changed");
309   sig_names[SIGCONT] = _("Continue");
310   sig_names[SIGSTOP] = _("Stop, unblockable");
311   sig_names[SIGTSTP] = _("Keyboard stop");
312   sig_names[SIGTTIN] = _("Background read from tty");
313   sig_names[SIGTTOU] = _("Background write to tty");
314   sig_names[SIGURG] = _("Urgent condition on socket");
315   sig_names[SIGXCPU] = _("CPU limit exceeded");
316   sig_names[SIGXFSZ] = _("File size limit exceeded");
317   sig_names[SIGVTALRM] = _("Virtual alarm clock");
318   sig_names[SIGPROF] = _("Profiling alarm clock");
319   sig_names[SIGWINCH] = _("Window size change");
320   sig_names[SIGIO] = _("I/O now possible");
321 #ifdef SIGPWR
322   sig_names[SIGPWR] = _("Power failure restart");
323 #endif
324 #ifdef SIGWAITING
325   sig_names[SIGWAITING] = _("No runnable lwp");
326 #endif
327 #ifdef SIGLWP
328   sig_names[SIGLWP] = _("SIGLWP special signal used by thread library");
329 #endif
330 #ifdef SIGFREEZE
331   sig_names[SIGFREEZE] = _("Checkpoint Freeze");
332 #endif
333 #ifdef SIGTHAW
334   sig_names[SIGTHAW] = _("Checkpoint Thaw");
335 #endif
336 #ifdef SIGCANCEL
337   sig_names[SIGCANCEL] = _("Thread Cancellation");
338 #endif
339 #ifdef SIGLOST
340   sig_names[SIGLOST] = _("Resource Lost (e.g. record-lock lost)");
341 #endif
342 #endif
343 
344   /*
345    * Now setup signal handlers
346    */
347   sighandle.sa_flags = 0;
348   sighandle.sa_handler = SignalHandler;
349   sigfillset(&sighandle.sa_mask);
350   sigignore.sa_flags = 0;
351   sigignore.sa_handler = SIG_IGN;
352   sigfillset(&sigignore.sa_mask);
353   sigdefault.sa_flags = 0;
354   sigdefault.sa_handler = SIG_DFL;
355   sigfillset(&sigdefault.sa_mask);
356 
357   sigaction(SIGPIPE, &sigignore, NULL);
358   sigaction(SIGCHLD, &sighandle, NULL);
359   sigaction(SIGCONT, &sigignore, NULL);
360   sigaction(SIGPROF, &sigignore, NULL);
361   sigaction(SIGWINCH, &sigignore, NULL);
362   sigaction(SIGIO, &sighandle, NULL);
363   sigaction(SIGINT, &sigdefault, NULL);
364   sigaction(SIGXCPU, &sigdefault, NULL);
365   sigaction(SIGXFSZ, &sigdefault, NULL);
366   sigaction(SIGHUP, &sigignore, NULL);
367   sigaction(SIGQUIT, &sighandle, NULL);
368   sigaction(SIGILL, &sighandle, NULL);
369   sigaction(SIGTRAP, &sighandle, NULL);
370   sigaction(SIGABRT, &sighandle, NULL);
371 #ifdef SIGEMT
372   sigaction(SIGEMT, &sighandle, NULL);
373 #endif
374 #ifdef SIGIOT
375   sigaction(SIGIOT, &sighandle, NULL);
376 #endif
377   sigaction(SIGBUS, &sighandle, NULL);
378   sigaction(SIGFPE, &sighandle, NULL);
379   sigaction(SIGUSR1, &sighandle, NULL);
380   sigaction(SIGSEGV, &sighandle, NULL);
381   sigaction(SIGUSR2, &sighandle, NULL);
382   sigaction(SIGALRM, &sighandle, NULL);
383   sigaction(SIGTERM, &sighandle, NULL);
384 #ifdef SIGSTKFLT
385   sigaction(SIGSTKFLT, &sighandle, NULL);
386 #endif
387   sigaction(SIGTSTP, &sigdefault, NULL);
388   sigaction(SIGTTIN, &sighandle, NULL);
389   sigaction(SIGTTOU, &sighandle, NULL);
390   sigaction(SIGURG, &sighandle, NULL);
391   sigaction(SIGVTALRM, &sighandle, NULL);
392 #ifdef SIGPWR
393   sigaction(SIGPWR, &sighandle, NULL);
394 #endif
395 #ifdef SIGWAITING
396   sigaction(SIGWAITING, &sighandle, NULL);
397 #endif
398 #ifdef SIGLWP
399   sigaction(SIGLWP, &sighandle, NULL);
400 #endif
401 #ifdef SIGFREEZE
402   sigaction(SIGFREEZE, &sighandle, NULL);
403 #endif
404 #ifdef SIGTHAW
405   sigaction(SIGTHAW, &sighandle, NULL);
406 #endif
407 #ifdef SIGCANCEL
408   sigaction(SIGCANCEL, &sighandle, NULL);
409 #endif
410 #ifdef SIGLOST
411   sigaction(SIGLOST, &sighandle, NULL);
412 #endif
413 }
414 
TimeoutHandler(int sig)415 extern "C" void TimeoutHandler(int sig)
416 {
417   return; /* thus interrupting the function */
418 }
419 
SetTimeoutHandler()420 void SetTimeoutHandler()
421 {
422   struct sigaction sigtimer;
423   sigtimer.sa_flags = 0;
424   sigtimer.sa_handler = TimeoutHandler;
425   sigfillset(&sigtimer.sa_mask);
426   sigaction(TIMEOUT_SIGNAL, &sigtimer, nullptr);
427 }
428 #else   // HAVE_WIN32
SetTimeoutHandler()429 void SetTimeoutHandler() {}
430 #endif  // !HAVE_WIN32
431