Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 3 additions & 14 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ include (CheckTypeSize)
include (CheckStructHasMember)

# Default variables for some configuration options
mark_as_advanced(FORCE ZM_EXTRA_LIBS ZM_MYSQL_ENGINE ZM_NO_MMAP ZM_NO_CRASHTRACE CMAKE_INSTALL_FULL_BINDIR)
mark_as_advanced(FORCE ZM_EXTRA_LIBS ZM_MYSQL_ENGINE ZM_NO_MMAP CMAKE_INSTALL_FULL_BINDIR)
set(ZM_RUNDIR "/var/run/zm" CACHE PATH "Location of transient process files, default: /var/run/zm")
set(ZM_TMPDIR "/tmp/zm" CACHE PATH "Location of temporary files, default: /tmp/zm")
set(ZM_LOGDIR "/var/log/zm" CACHE PATH "Location of generated log files, default: /var/log/zm")
Expand All @@ -57,7 +57,6 @@ set(ZM_WEB_GROUP "" CACHE STRING "The group apache or the local web server runs
set(ZM_EXTRA_LIBS "" CACHE STRING "A list of optional libraries, separated by semicolons, e.g. ssl;theora")
set(ZM_MYSQL_ENGINE "InnoDB" CACHE STRING "MySQL engine to use with database, default: InnoDB")
set(ZM_NO_MMAP "OFF" CACHE BOOL "Set to ON to not use mmap shared memory. Shouldn't be enabled unless you experience problems with the shared memory. default: OFF")
set(ZM_NO_CRASHTRACE "OFF" CACHE BOOL "Set to ON to skip crash trace code. Useful if zm_signal.cpp fails to compile. default: OFF")
# Only required for cmakecacheimport:
set(CMAKE_INSTALL_FULL_BINDIR "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_BINDIR}" CACHE PATH "Override default binary directory")

Expand All @@ -72,19 +71,17 @@ set_property(GLOBAL PROPERTY FIND_LIBRARY_USE_LIB64_PATHS ON)
check_include_file("linux/videodev.h" HAVE_LINUX_VIDEODEV_H)
check_include_file("linux/videodev2.h" HAVE_LINUX_VIDEODEV2_H)
check_include_file("execinfo.h" HAVE_EXECINFO_H)
check_include_file("ucontext.h" HAVE_UCONTEXT_H)
check_include_file("sys/sendfile.h" HAVE_SYS_SENDFILE_H)
check_include_file("sys/syscall.h" HAVE_SYS_SYSCALL_H)
check_function_exists("syscall" HAVE_SYSCALL)
check_function_exists("sendfile" HAVE_SENDFILE)
check_function_exists("backtrace" HAVE_DECL_BACKTRACE)
check_function_exists("backtrace_symbols" HAVE_DECL_BACKTRACE_SYMBOLS)
check_function_exists("posix_memalign" HAVE_POSIX_MEMALIGN)
check_function_exists("strsignal" HAVE_STRSIGNAL)
check_prototype_definition("round" "double round (double x)" "0.0" "math.h" HAVE_DECL_ROUND)
check_type_size("siginfo_t" HAVE_SIGINFO_T)
check_type_size("ucontext_t" HAVE_UCONTEXT_T)
check_type_size("struct sigcontext" HAVE_STRUCT_SIGCONTEXT)
check_struct_has_member("struct sigcontext" eip signal.h HAVE_STRUCT_SIGCONTEXT_EIP)
check_struct_has_member("struct sigcontext" rip signal.h HAVE_STRUCT_SIGCONTEXT_RIP)

# *** LIBRARY CHECKS ***

Expand Down Expand Up @@ -275,14 +272,6 @@ if(HAVE_LIBCRYPTO AND HAVE_OPENSSL_MD5_H AND HAVE_MD5_OPENSSL)
set(HAVE_GNUTLS_OPENSSL_H 0)
endif(HAVE_LIBCRYPTO AND HAVE_OPENSSL_MD5_H AND HAVE_MD5_OPENSSL)

# Disable backtrace if not available
if((NOT ZM_NO_CRASHTRACE) AND ((NOT HAVE_DECL_BACKTRACE) OR (NOT HAVE_EXECINFO_H)))
message(AUTHOR_WARNING " Backtrace is not available. disabling")
set(ZM_NO_CRASHTRACE ON)
set(HAVE_EXECINFO_H 0)
set(HAVE_DECL_BACKTRACE 0)
endif((NOT ZM_NO_CRASHTRACE) AND ((NOT HAVE_DECL_BACKTRACE) OR (NOT HAVE_EXECINFO_H)))


if(NOT ZM_NO_MMAP)
set(ZM_MMAP_PERLPACKAGE "Sys::Mmap")
Expand Down
1 change: 0 additions & 1 deletion INSTALL
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@ Advanced:
ZM_EXTRA_LIBS A list of optional libraries, separated by semicolons, e.g. ssl;theora
ZM_MYSQL_ENGINE MySQL engine to use with database, default: InnoDB
ZM_NO_MMAP Set to ON to not use mmap shared memory. Shouldn't be enabled unless you experience problems with the shared memory. default: OFF
ZM_NO_CRASHTRACE Set to ON to skip crash trace code. Useful if zm_signal.cpp fails to compile. default: OFF


Useful configuration options provided by cmake:
Expand Down
6 changes: 3 additions & 3 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -235,8 +235,6 @@ AC_STRUCT_TM
AC_TYPE_SIGNAL

AC_CHECK_TYPES(siginfo_t,,,[#include <signal.h>])
AC_CHECK_TYPES(struct sigcontext,,,[#include <signal.h>])
AC_CHECK_MEMBERS([struct sigcontext.eip],,,[#include <signal.h>])
AC_CHECK_TYPES(ucontext_t,,,[#include <signal.h>])

# Checks for library functions.
Expand All @@ -248,7 +246,7 @@ AC_FUNC_STAT
AC_FUNC_STRFTIME
AC_FUNC_STRTOD
AC_FUNC_VPRINTF
AC_CHECK_FUNCS([gethostbyname gethostname gettimeofday memmove memset mkdir munmap posix_memalign putenv select sendfile socket sqrt strcasecmp strchr strcspn strerror strncasecmp strrchr strsignal strspn strstr strtol strtoull])
AC_CHECK_FUNCS([gethostbyname gethostname gettimeofday memmove memset mkdir munmap posix_memalign putenv select sendfile socket sqrt strcasecmp strchr strcspn strerror strncasecmp strrchr strspn strstr strtol strtoull])
AC_CHECK_FUNCS([syscall sleep usleep ioctl ioctlsocket sigaction])

# Other programs
Expand Down Expand Up @@ -302,6 +300,7 @@ AC_HEADER_STDC
AC_CHECK_HEADERS([fcntl.h limits.h memory.h stddef.h stdlib.h string.h strings.h sys/param.h sys/time.h syslog.h unistd.h values.h])
AC_CHECK_HEADERS([netdb.h netinet/in.h arpa/inet.h sys/ioctl.h sys/socket.h sys/un.h glob.h sys/sendfile.h])
AC_CHECK_HEADERS(execinfo.h,,,)
AC_CHECK_HEADERS(ucontext.h,,,)
AC_CHECK_HEADERS(sys/syscall.h,,,)
AC_CHECK_HEADERS(pthread.h,,,)
AC_CHECK_HEADERS(linux/videodev.h,AC_SUBST(ZM_HAS_V4L1,1),AC_SUBST(ZM_HAS_V4L1,0),)
Expand Down Expand Up @@ -345,6 +344,7 @@ AC_CHECK_DECLS(gnutls_fingerprint,,AC_MSG_ERROR([zm requires gnutls/gnutls.h - u
fi
fi
AC_CHECK_DECLS(backtrace,,,[#include <execinfo.h>])
AC_CHECK_DECLS(backtrace_symbols,,,[#include <execinfo.h>])

AC_SUBST(LDFLAGS)

Expand Down
3 changes: 2 additions & 1 deletion src/zm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,5 @@

#include "zm.h"

// This space intentionally left blank
/* This is our argv[0], we need it for backtrace */
const char* self = 0;
2 changes: 2 additions & 0 deletions src/zm.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,6 @@ double round(double);

#include <stdint.h>

extern const char* self;

#endif // ZM_H
210 changes: 94 additions & 116 deletions src/zm_signal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,174 +24,152 @@
#include <string.h>
#include <stdlib.h>

#define TRACE_SIZE 16

bool zm_reload = false;
bool zm_terminate = false;

RETSIGTYPE zm_hup_handler( int signal )
RETSIGTYPE zm_hup_handler(int signal)
{
#if HAVE_STRSIGNAL
Info( "Got signal %d (%s), reloading", signal, strsignal(signal) );
#else // HAVE_STRSIGNAL
Info( "Got HUP signal, reloading" );
#endif // HAVE_STRSIGNAL
Info("Got signal %d (%s), reloading", signal, strsignal(signal));
zm_reload = true;
}

bool zm_terminate = false;

RETSIGTYPE zm_term_handler( int signal )
RETSIGTYPE zm_term_handler(int signal)
{
#if HAVE_STRSIGNAL
Info( "Got signal %d (%s), exiting", signal, strsignal(signal) );
#else // HAVE_STRSIGNAL
Info( "Got TERM signal, exiting" );
#endif // HAVE_STRSIGNAL
Info("Got signal %d (%s), exiting", signal, strsignal(signal));
zm_terminate = true;
}

#define TRACE_SIZE 16

#if HAVE_STRUCT_SIGCONTEXT
RETSIGTYPE zm_die_handler( int signal, struct sigcontext context )
#elif ( HAVE_SIGINFO_T && HAVE_UCONTEXT_T )
#include <ucontext.h>
RETSIGTYPE zm_die_handler( int signal, siginfo_t *info, void *context )
#if ( HAVE_SIGINFO_T && HAVE_UCONTEXT_T )
RETSIGTYPE zm_die_handler(int signal, siginfo_t * info, void *context)
#else
RETSIGTYPE zm_die_handler( int signal )
RETSIGTYPE zm_die_handler(int signal)
#endif
{
if ( signal == SIGABRT )
{
#if HAVE_STRSIGNAL
Info( "Got signal %d (%s), exiting and forcing backtrace", signal, strsignal(signal) );
#else // HAVE_STRSIGNAL
Error( "Got signal %d, exiting and forcing backtrace", signal );
#endif // HAVE_STRSIGNAL
}
else
{
#if HAVE_STRSIGNAL
Info( "Got signal %d (%s), crashing", signal, strsignal(signal) );
#else // HAVE_STRSIGNAL
Error( "Got signal %d, crashing", signal );
#endif // HAVE_STRSIGNAL
}

#ifndef ZM_NO_CRASHTRACE
#if ( ( HAVE_SIGINFO_T && HAVE_UCONTEXT_T ) || HAVE_STRUCT_SIGCONTEXT )
void *trace[TRACE_SIZE];
int trace_size = 0;
void *cr2 = 0;
void *ip = 0;

#if HAVE_STRUCT_SIGCONTEXT_EIP
Error( "Signal address is %p, from %p", (void *)context.cr2, (void *)context.eip );
Error("Got signal %d (%s), crashing", signal, strsignal(signal));

trace_size = backtrace( trace, TRACE_SIZE );
// overwrite sigaction with caller's address
trace[1] = (void *)context.eip;
#elif HAVE_STRUCT_SIGCONTEXT
Error( "Signal address is %p, no eip", (void *)context.cr2 );
// Get more information if available
#if ( HAVE_SIGINFO_T && HAVE_UCONTEXT_T )
if (info && context) {

trace_size = backtrace( trace, TRACE_SIZE );
#else // HAVE_STRUCT_SIGCONTEXT
if ( info && context )
{
ucontext_t *uc = (ucontext_t *)context;
Debug(1,
"Signal information: number %d code %d errno %d pid %d uid %d status %d",
signal, info->si_code, info->si_errno, info->si_pid,
info->si_uid, info->si_status);

ucontext_t *uc = (ucontext_t *) context;
#if defined(__x86_64__)
cr2 = info->si_addr;
ip = (void *)(uc->uc_mcontext.gregs[REG_RIP]);
#else
cr2 = info->si_addr;
ip = (void *)(uc->uc_mcontext.gregs[REG_EIP]);
#endif // defined(__x86_64__)

// Print the signal address and instruction pointer if available
if (ip) {
Error("Signal address is %p, from %p", cr2, ip);
} else {
Error("Signal address is %p, no instruction pointer", cr2);
}
}
#endif // ( HAVE_SIGINFO_T && HAVE_UCONTEXT_T )

Error( "Signal address is %p, from %p", info->si_addr, uc->uc_mcontext.gregs[REG_EIP] );

trace_size = backtrace( trace, TRACE_SIZE );
// overwrite sigaction with caller's address
trace[1] = (void *) uc->uc_mcontext.gregs[REG_EIP];
// Print backtrace if enabled and available
#if ( !defined(ZM_NO_CRASHTRACE) && HAVE_DECL_BACKTRACE && HAVE_DECL_BACKTRACE_SYMBOLS )
void *trace[TRACE_SIZE];
int trace_size = 0;
trace_size = backtrace(trace, TRACE_SIZE);

char cmd[1024] = "addr2line -e ";
char *cmd_ptr = cmd + strlen(cmd);
cmd_ptr += snprintf(cmd_ptr, sizeof(cmd) - (cmd_ptr - cmd), "%s", self);

char **messages = backtrace_symbols(trace, trace_size);
// Print the full backtrace
for (int i = 0; i < trace_size; i++) {
Error("Backtrace %u: %s", i, messages[i]);
cmd_ptr +=
snprintf(cmd_ptr, sizeof(cmd) - (cmd_ptr - cmd), " %p",
trace[i]);
}
#endif // HAVE_STRUCT_SIGCONTEXT
#if HAVE_DECL_BACKTRACE
char cmd[1024] = "addr2line -e ";
char *cmd_ptr = cmd+strlen(cmd);
// Try and extract the binary path from the last backtrace frame
char **messages = backtrace_symbols( trace, trace_size );
if ( size_t offset = strcspn( messages[trace_size-1], " " ) )
{
snprintf( cmd_ptr, sizeof(cmd)-(cmd_ptr-cmd), "%s", messages[trace_size-1] );
cmd_ptr += offset;
}
else
{
cmd_ptr += snprintf( cmd_ptr, sizeof(cmd)-(cmd_ptr-cmd), "/path/to/%s", logId().c_str() );
}
// skip first stack frame (points here)
for ( int i=1; i < trace_size; i++ )
{
Error( "Backtrace: %s", messages[i] );
cmd_ptr += snprintf( cmd_ptr, sizeof(cmd)-(cmd_ptr-cmd), " %p", trace[i] );
}
Info( "Backtrace complete, please execute the following command for more information" );
Info( cmd );
#endif // HAVE_DECL_BACKTRACE
#endif // ( HAVE_SIGINFO_T && HAVE_UCONTEXT_T ) || HAVE_STRUCT_SIGCONTEXT
#endif // ZM_NO_CRASHTRACE

exit( signal );
free(messages);

Info("Backtrace complete, please execute the following command for more information");
Info(cmd);
#endif // ( !defined(ZM_NO_CRASHTRACE) && HAVE_DECL_BACKTRACE && HAVE_DECL_BACKTRACE_SYMBOLS )

exit(signal);
}

void zmSetHupHandler( SigHandler *handler )
void zmSetHupHandler(SigHandler * handler)
{
sigset_t block_set;
sigemptyset( &block_set );
sigemptyset(&block_set);
struct sigaction action, old_action;

action.sa_handler = (SigHandler *)handler;
action.sa_handler = (SigHandler *) handler;
action.sa_mask = block_set;
action.sa_flags = 0;
sigaction( SIGHUP, &action, &old_action );
action.sa_flags = SA_RESTART;
sigaction(SIGHUP, &action, &old_action);
}

void zmSetTermHandler( SigHandler *handler )
void zmSetTermHandler(SigHandler * handler)
{
sigset_t block_set;
sigemptyset( &block_set );
sigemptyset(&block_set);
struct sigaction action, old_action;

action.sa_handler = (SigHandler *)handler;
action.sa_handler = (SigHandler *) handler;
action.sa_mask = block_set;
action.sa_flags = 0;
sigaction( SIGTERM, &action, &old_action );
action.sa_flags = SA_RESTART;
sigaction(SIGTERM, &action, &old_action);
sigaction(SIGINT, &action, &old_action);
sigaction(SIGQUIT, &action, &old_action);
}

void zmSetDieHandler( SigHandler *handler )
void zmSetDieHandler(SigHandler * handler)
{
sigset_t block_set;
sigemptyset( &block_set );
sigemptyset(&block_set);
struct sigaction action, old_action;

action.sa_handler = (SigHandler *)handler;
action.sa_mask = block_set;
#if ( HAVE_SIGINFO_T && HAVE_UCONTEXT_T )
action.sa_sigaction = (void (*)(int, siginfo_t *, void *))handler;
action.sa_flags = SA_SIGINFO;
#else
action.sa_handler = (SigHandler *) handler;
action.sa_flags = 0;
#endif

sigaction( SIGBUS, &action, &old_action );
sigaction( SIGSEGV, &action, &old_action );
sigaction( SIGABRT, &action, &old_action );
sigaction( SIGILL, &action, &old_action );
sigaction( SIGFPE, &action, &old_action );
sigaction(SIGBUS, &action, &old_action);
sigaction(SIGSEGV, &action, &old_action);
sigaction(SIGABRT, &action, &old_action);
sigaction(SIGILL, &action, &old_action);
sigaction(SIGFPE, &action, &old_action);
}

void zmSetDefaultHupHandler()
{
zmSetHupHandler( (SigHandler *)zm_hup_handler );
zmSetHupHandler((SigHandler *) zm_hup_handler);
}

void zmSetDefaultTermHandler()
{
zmSetTermHandler( (SigHandler *)zm_term_handler );
zmSetTermHandler((SigHandler *) zm_term_handler);
}

void zmSetDefaultDieHandler()
{
if ( config.dump_cores )
{
// Do nothing
}
else
{
zmSetDieHandler( (SigHandler *)zm_die_handler );
}
if (config.dump_cores) {
// Do nothing
} else {
zmSetDieHandler((SigHandler *) zm_die_handler);
}
}

Loading