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