1 //
2 // ZoneMinder Signal Handling Implementation, $Date$, $Revision$
3 // Copyright (C) 2001-2008 Philip Coombes
4 //
5 // This program is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU General Public License
7 // as published by the Free Software Foundation; either version 2
8 // of the License, or (at your option) any later version.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software
17 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 //
19
20 #include "zm_signal.h"
21
22 #include "zm.h"
23 #include "zm_logger.h"
24 #include <cstring>
25
26 #define TRACE_SIZE 16
27
28 bool zm_reload = false;
29 bool zm_terminate = false;
30
zm_hup_handler(int signal)31 RETSIGTYPE zm_hup_handler(int signal) {
32 // Shouldn't do complex things in signal handlers, logging is complex and can block due to mutexes.
33 //Info("Got signal %d (%s), reloading", signal, strsignal(signal));
34 zm_reload = true;
35 }
36
zm_term_handler(int signal)37 RETSIGTYPE zm_term_handler(int signal) {
38 // Shouldn't do complex things in signal handlers, logging is complex and can block due to mutexes.
39 //Info("Got signal %d (%s), exiting", signal, strsignal(signal));
40 zm_terminate = true;
41 }
42
43 #if ( HAVE_SIGINFO_T && HAVE_UCONTEXT_T )
zm_die_handler(int signal,siginfo_t * info,void * context)44 RETSIGTYPE zm_die_handler(int signal, siginfo_t * info, void *context)
45 #else
46 RETSIGTYPE zm_die_handler(int signal)
47 #endif
48 {
49 Error("Got signal %d (%s), crashing", signal, strsignal(signal));
50 #if (defined(__i386__) || defined(__x86_64__))
51 // Get more information if available
52 #if ( HAVE_SIGINFO_T && HAVE_UCONTEXT_T )
53 void *ip = nullptr;
54 void *cr2 = nullptr;
55 if ( info && context ) {
56 Debug(1,
57 "Signal information: number %d code %d errno %d pid %d uid %d status %d",
58 signal, info->si_code, info->si_errno, info->si_pid,
59 info->si_uid, info->si_status);
60
61 ucontext_t *uc = (ucontext_t *) context;
62 cr2 = info->si_addr;
63 #if defined(__x86_64__)
64 #if defined(__FreeBSD_kernel__) || defined(__FreeBSD__)
65 ip = (void *)(uc->uc_mcontext.mc_rip);
66 #else
67 ip = (void *)(uc->uc_mcontext.gregs[REG_RIP]);
68 #endif
69 #else
70 #if defined(__FreeBSD_kernel__) || defined(__FreeBSD__)
71 ip = (void *)(uc->uc_mcontext.mc_eip);
72 #else
73 ip = (void *)(uc->uc_mcontext.gregs[REG_EIP]);
74 #endif
75 #endif // defined(__x86_64__)
76
77 // Print the signal address and instruction pointer if available
78 if ( ip ) {
79 Error("Signal address is %p, from %p", cr2, ip);
80 } else {
81 Error("Signal address is %p, no instruction pointer", cr2);
82 }
83 }
84 #endif // ( HAVE_SIGINFO_T && HAVE_UCONTEXT_T )
85
86
87 // Print backtrace if enabled and available
88 #if ( !defined(ZM_NO_CRASHTRACE) && HAVE_DECL_BACKTRACE && HAVE_DECL_BACKTRACE_SYMBOLS )
89 void *trace[TRACE_SIZE];
90 int trace_size = 0;
91 trace_size = backtrace(trace, TRACE_SIZE);
92
93 char cmd[1024] = "addr2line -e ";
94 char *cmd_ptr = cmd + strlen(cmd);
95 cmd_ptr += snprintf(cmd_ptr, sizeof(cmd) - (cmd_ptr - cmd), "%s", self);
96
97 char **messages = backtrace_symbols(trace, trace_size);
98 // Print the full backtrace
99 for (int i = 0; i < trace_size; i++) {
100 Error("Backtrace %u: %s", i, messages[i]);
101 cmd_ptr +=
102 snprintf(cmd_ptr, sizeof(cmd) - (cmd_ptr - cmd), " %p",
103 trace[i]);
104 }
105 free(messages);
106
107 Info("Backtrace complete, please execute the following command for more information: %s", cmd);
108 #endif // ( !defined(ZM_NO_CRASHTRACE) && HAVE_DECL_BACKTRACE && HAVE_DECL_BACKTRACE_SYMBOLS )
109 #endif // (defined(__i386__) || defined(__x86_64__)
110 exit(signal);
111 }
112
zmSetHupHandler(SigHandler * handler)113 void zmSetHupHandler(SigHandler * handler) {
114 sigset_t block_set;
115 sigemptyset(&block_set);
116 struct sigaction action, old_action;
117
118 action.sa_handler = (SigHandler *) handler;
119 action.sa_mask = block_set;
120 action.sa_flags = SA_RESTART;
121 sigaction(SIGHUP, &action, &old_action);
122 }
123
zmSetTermHandler(SigHandler * handler)124 void zmSetTermHandler(SigHandler * handler) {
125 sigset_t block_set;
126 sigemptyset(&block_set);
127 struct sigaction action, old_action;
128
129 action.sa_handler = (SigHandler *) handler;
130 action.sa_mask = block_set;
131 action.sa_flags = SA_RESTART;
132 sigaction(SIGTERM, &action, &old_action);
133 sigaction(SIGINT, &action, &old_action);
134 sigaction(SIGQUIT, &action, &old_action);
135 }
136
zmSetDieHandler(SigHandler * handler)137 void zmSetDieHandler(SigHandler * handler) {
138 sigset_t block_set;
139 sigemptyset(&block_set);
140 struct sigaction action, old_action;
141
142 action.sa_mask = block_set;
143 #if ( HAVE_SIGINFO_T && HAVE_UCONTEXT_T )
144 action.sa_sigaction = (void (*)(int, siginfo_t *, void *))handler;
145 action.sa_flags = SA_SIGINFO;
146 #else
147 action.sa_handler = (SigHandler *) handler;
148 action.sa_flags = 0;
149 #endif
150
151 sigaction(SIGBUS, &action, &old_action);
152 sigaction(SIGSEGV, &action, &old_action);
153 sigaction(SIGABRT, &action, &old_action);
154 sigaction(SIGILL, &action, &old_action);
155 sigaction(SIGFPE, &action, &old_action);
156 }
157
zmSetDefaultHupHandler()158 void zmSetDefaultHupHandler() {
159 zmSetHupHandler((SigHandler *) zm_hup_handler);
160 }
161
zmSetDefaultTermHandler()162 void zmSetDefaultTermHandler() {
163 zmSetTermHandler((SigHandler *) zm_term_handler);
164 }
165
zmSetDefaultDieHandler()166 void zmSetDefaultDieHandler() {
167 if ( config.dump_cores ) {
168 // Do nothing
169 } else {
170 zmSetDieHandler((SigHandler *) zm_die_handler);
171 }
172 }
173