/* Copyright (C) 2008 Andreas Baumann This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "port/sys_internal.h" #include "port/string.h" /* for memset */ #include "errors.h" #include "log/log.h" #include "log/messages.h" /* for i18n */ #include "daemon/signals.h" #include "port/unused.h" #define DEFAULT_TEXT_DOMAIN "libwolf" #include "i18n/gettext.h" /* for i18n */ #include /* for getpid, pipe, write, read */ #include /* for errno */ #include /* for ssize_t */ #include /* for FD_XX and select */ const char *wolf_signal_get_short_name( int sig ) { switch( sig ) { case SIGHUP: return "SIGHUP"; case SIGINT: return "SIGINT"; case SIGQUIT: return "SIGQUIT"; case SIGILL: return "SIGILL"; case SIGTRAP: return "SIGTRAP"; case SIGABRT: return "SIGABRT"; #if defined( SIGIOT ) #if SIGIOT != SIGABRT case SIGIOT: return "SIGIOT"; #endif #endif #if defined( SIGEMT ) case SIGEMT: return "SIGEMT"; #endif case SIGBUS: return "SIGBUS"; case SIGFPE: return "SIGFPE"; case SIGKILL: return "SIGKILL"; case SIGUSR1: return "SIGUSR1"; case SIGSEGV: return "SIGSEGV"; case SIGUSR2: return "SIGUSR2"; case SIGPIPE: return "SIGPIPE"; case SIGALRM: return "SIGALRM"; case SIGTERM: return "SIGTERM"; #if defined( SIGSTKFLT ) case SIGSTKFLT: return "SIGSTKFLT"; #endif #if defined( SIGCLD ) #if SIGCLD != SIGCHLD /* the SysV version */ case SIGCLD: return "SIGCLD"; #endif #endif /* the POSIX version */ case SIGCHLD: return "SIGCHLD"; case SIGCONT: return "SIGCONT"; case SIGSTOP: return "SIGSTOP"; case SIGTSTP: return "SIGTSTP"; case SIGTTIN: return "SIGTTIN"; case SIGTTOU: return "SIGTTOU"; case SIGURG: return "SIGURG"; case SIGXCPU: return "SIGXCPU"; case SIGXFSZ: return "SIGXFSZ"; case SIGVTALRM: return "SIGVTALRM"; case SIGPROF: return "SIGPROF"; #if defined( SIGWINCH ) case SIGWINCH: return "SIGWINCH"; #endif #if defined( SIGPOLL ) #if SIGPOLL != SIGIO /* SysV version of SIGIO */ case SIGPOLL: return "SIGPOLL"; #endif #endif #if defined( SIGIO ) case SIGIO: return "SIGIO"; #endif #if defined( SIGPWR ) case SIGPWR: return "SIGPWR"; #endif #if defined( SIGSYS ) case SIGSYS: return "SIGSYS"; #endif #if defined( SIGLOST ) case SIGLOST: return "SIGLOST"; #endif default: return NULL; } } const char *wolf_signal_get_long_name( int sig ) { /* we don't trust strsignal, needs _GNU_SOURCE, * naming comes from bits/signum.h on Linux 2.6 */ switch( sig ) { case SIGHUP: return _( "Hangup" ); case SIGINT: return _( "Interrupt" ); case SIGQUIT: return _( "Quit" ); case SIGILL: return _( "Illegal instruction" ); case SIGTRAP: return _( "Trace trap" ); case SIGABRT: return _( "Abort" ); #if defined( SIGIOT ) #if SIGIOT != SIGABRT case SIGIOT: return _( "IOT trap" ); #endif #endif #if defined( SIGEMT ) case SIGEMT: return _( "EMT instruction" ); #endif case SIGBUS: return _( "BUS error" ); case SIGFPE: return _( "Floating-point exception" ); case SIGKILL: return _( "Kill" ); case SIGUSR1: return _( "User-defined signal 1" ); case SIGSEGV: return _( "Segmentation violation" ); case SIGUSR2: return _( "User-defined signal 2" ); case SIGPIPE: return _( "Broken pipe" ); case SIGALRM: return _( "Alarm clock" ); case SIGTERM: return _( "Termination" ); #if defined( SIGSTKFLT ) case SIGSTKFLT: return _( "Stack fault" ); #endif #if defined( SIGCLD ) #if SIGCLD != SIGCHLD case SIGCLD: return _( "Child status has changed" ); #endif #endif case SIGCHLD: return _( "Child status has changed" ); case SIGCONT: return _( "Continue" ); case SIGSTOP: return _( "Stop" ); case SIGTSTP: return _( "Keyboard stop" ); case SIGTTIN: return _( "Background read from tty" ); case SIGTTOU: return _( "Background write to tty" ); case SIGURG: return _( "Urgent condition on socket" ); case SIGXCPU: return _( "CPU limit exceeded" ); case SIGXFSZ: return _( "File size limit exceeded" ); case SIGVTALRM: return _( "Virtual alarm clock" ); case SIGPROF: return _( "Profiling alarm clock" ); #if defined( SIGWINCH ) case SIGWINCH: return _( "Window size change" ); #endif #if defined( SIGPOLL ) #if SIGPOLL != SIGIO case SIGPOLL: return _( "Pollable event occurred" ); #endif #endif #if defined( SIGIO ) case SIGIO: return _( "I/O now possible" ); #endif #if defined( SIGPWR ) case SIGPWR: return _( "Power failure restart" ); #endif #if defined( SIGSYS ) case SIGSYS: return _( "Bad system call" ); #endif #if defined( SIGLOST ) case SIGLOST: return _( "Resource lost" ); #endif default: return NULL; } } static wolf_error_t vsignal_install_ignore( int sig, va_list ap ) { struct sigaction sa; char errbuf[1024]; install_ignore_again: if( sig == 0 ) return WOLF_OK; memset( &sa, 0, sizeof( struct sigaction ) ); sa.sa_handler = SIG_IGN; if( sigaction( sig, &sa, NULL ) < 0 ) { (void)strerror_r( errno, errbuf, 1024 ); wolf_log( WOLF_LOG_CRIT, WOLF_CATEGORY_DAEMON, WOLF_MSG_DAEMON_CANT_INSTALL_IGNORE_SIGNAL, _( "Can't ignore signal handler for signal '%s' (%s): %s" ), wolf_signal_get_long_name( sig ), wolf_signal_get_short_name( sig ), sig, errbuf ); return WOLF_ERR_PROGRAMMING; } wolf_log( WOLF_LOG_DEBUG, WOLF_CATEGORY_DAEMON, WOLF_MSG_DAEMON_IGNORE_SIGNAL, _( "Ignoring signal handler for signal '%s' (%s)" ), wolf_signal_get_long_name( sig ), wolf_signal_get_short_name( sig ) ); sig = va_arg( ap, int ); if( sig > 0 ) goto install_ignore_again; return WOLF_OK; } static void empty_handler( int sig ) { WOLF_UNUSED( sig ); } static wolf_error_t vsignal_install_empty( int sig, va_list ap ) { struct sigaction sa; char errbuf[1024]; install_empty_again: if( sig == 0 ) return WOLF_OK; memset( &sa, 0, sizeof( struct sigaction ) ); sa.sa_handler = empty_handler; if( sigaction( sig, &sa, NULL ) < 0 ) { (void)strerror_r( errno, errbuf, 1024 ); wolf_log( WOLF_LOG_CRIT, WOLF_CATEGORY_DAEMON, WOLF_MSG_DAEMON_CANT_INSTALL_CRITICAL_SIGNAL, _( "Can't install empty signal handler for signal '%s' (%s): %s" ), wolf_signal_get_long_name( sig ), wolf_signal_get_short_name( sig ), errbuf ); return WOLF_ERR_PROGRAMMING; } wolf_log( WOLF_LOG_DEBUG, WOLF_CATEGORY_DAEMON, WOLF_MSG_DAEMON_CRITICAL_SIGNAL, _( "Installed empty signal handler for signal '%s' (%s)" ), wolf_signal_get_long_name( sig ), wolf_signal_get_short_name( sig ) ); sig = va_arg( ap, int ); if( sig > 0 ) goto install_empty_again; return WOLF_OK; } static void fatal_handler( int sig ) { struct sigaction sa; /* reset default behaviour of the signal */ memset( &sa, 0, sizeof( struct sigaction ) ); sa.sa_handler = SIG_DFL; (void)sigaction( sig, &sa, NULL ); /* log what happened */ wolf_log( WOLF_LOG_ALERT, WOLF_CATEGORY_DAEMON, WOLF_MSG_DAEMON_GOT_SIGNAL, _( "Got signal '%s' (%s)" ), wolf_signal_get_long_name( sig ), wolf_signal_get_short_name( sig ) ); /* we are in one thread when we got the signal, now inform * all other threads too (see Apache mpm_common.c for this * trick) */ kill( getpid( ), sig ); } wolf_error_t vsignal_install_func( wolf_signal_func_t func, int sig, va_list ap ) { struct sigaction sa; char errbuf[1024]; install_func_again: memset( &sa, 0, sizeof( struct sigaction ) ); sa.sa_handler = func; sa.sa_flags = SA_RESTART; if( sigaction( sig, &sa, NULL ) < 0 ) { (void)strerror_r( errno, errbuf, 1024 ); wolf_log( WOLF_LOG_CRIT, WOLF_CATEGORY_DAEMON, WOLF_MSG_DAEMON_CANT_INSTALL_FUNC_SIGNAL, _( "Can't install signal handler for signal '%s' (%s): %s" ), wolf_signal_get_long_name( sig ), wolf_signal_get_short_name( sig ), errbuf ); return WOLF_ERR_PROGRAMMING; } wolf_log( WOLF_LOG_DEBUG, WOLF_CATEGORY_DAEMON, WOLF_MSG_DAEMON_FUNC_SIGNAL, _( "Installed signal handler for signal '%s' (%s)" ), wolf_signal_get_long_name( sig ), wolf_signal_get_short_name( sig ) ); sig = va_arg( ap, int ); if( sig > 0 ) goto install_func_again; return WOLF_OK; } wolf_error_t wolf_signal_install_func( wolf_signal_func_t func, int sig, ... ) { va_list ap; wolf_error_t error; va_start( ap, sig ); error = vsignal_install_func( func, sig, ap ); va_end( ap ); return error; } #define INSTALL_SIGNAL( MODE ) \ wolf_error_t wolf_signal_install_##MODE( int sig, ... ) { \ va_list ap; \ wolf_error_t error; \ va_start( ap, sig ); \ error = vsignal_install_##MODE( sig, ap ); \ va_end( ap ); \ return error; \ } INSTALL_SIGNAL( ignore ) INSTALL_SIGNAL( empty ) WOLF_SIGNALS_INSTALL_FUNC( fatal, fatal_handler )