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