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