mirror of
				https://github.com/osmarks/ngircd.git
				synced 2025-10-30 21:42:59 +00:00 
			
		
		
		
	Add new 'delayed' signal handlers.
Allows to defer/queue signal processing for execution on the next event dispatch call, i.e. we can perform any signal action in normal, non-signal context. Example uses: - Reload everything on HUP without writing a global "SIGHUP_received" variable - Dump status of internal Lists on SIGUSR1, etc.
This commit is contained in:
		| @@ -159,7 +159,7 @@ AC_CHECK_FUNCS([ \ | ||||
| 	bind gethostbyaddr gethostbyname gethostname inet_ntoa \ | ||||
| 	setsid setsockopt socket strcasecmp waitpid],,AC_MSG_ERROR([required function missing!])) | ||||
|  | ||||
| AC_CHECK_FUNCS(getaddrinfo getnameinfo inet_aton isdigit sigaction snprintf \ | ||||
| AC_CHECK_FUNCS(getaddrinfo getnameinfo inet_aton isdigit sigaction sigprocmask snprintf \ | ||||
|  vsnprintf strdup strlcpy strlcat strtok_r) | ||||
|  | ||||
| # -- Configuration options -- | ||||
|   | ||||
| @@ -21,7 +21,7 @@ sbin_PROGRAMS = ngircd | ||||
| ngircd_SOURCES = ngircd.c array.c channel.c client.c conf.c conn.c conn-func.c \ | ||||
| 	conn-ssl.c conn-zip.c hash.c io.c irc.c irc-channel.c irc-info.c irc-login.c \ | ||||
| 	irc-mode.c irc-op.c irc-oper.c irc-server.c irc-write.c lists.c log.c \ | ||||
| 	match.c op.c numeric.c pam.c parse.c proc.c rendezvous.c resolve.c | ||||
| 	match.c op.c numeric.c pam.c parse.c proc.c rendezvous.c resolve.c sighandlers.c | ||||
|  | ||||
| ngircd_LDFLAGS = -L../portab -L../tool -L../ipaddr | ||||
|  | ||||
|   | ||||
| @@ -477,11 +477,6 @@ Conn_InitListeners( void ) | ||||
| 	unsigned int created = 0; | ||||
| 	char *copy, *listen_addr; | ||||
|  | ||||
| 	if (!io_library_init(CONNECTION_POOL)) { | ||||
| 		Log(LOG_EMERG, "Cannot initialize IO routines: %s", strerror(errno)); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	assert(Conf_ListenAddress); | ||||
|  | ||||
| 	/* can't use Conf_ListenAddress directly, see below */ | ||||
|   | ||||
| @@ -29,7 +29,6 @@ | ||||
| #include <time.h> | ||||
| #include <sys/types.h> | ||||
| #include <sys/stat.h> | ||||
| #include <sys/wait.h> | ||||
| #include <fcntl.h> | ||||
| #include <pwd.h> | ||||
| #include <grp.h> | ||||
| @@ -46,6 +45,8 @@ | ||||
| #include "lists.h" | ||||
| #include "log.h" | ||||
| #include "parse.h" | ||||
| #include "sighandlers.h" | ||||
| #include "io.h" | ||||
| #include "irc.h" | ||||
|  | ||||
| #ifdef ZEROCONF | ||||
| @@ -56,9 +57,6 @@ | ||||
| #include "ngircd.h" | ||||
|  | ||||
|  | ||||
| static void Initialize_Signal_Handler PARAMS(( void )); | ||||
| static void Signal_Handler PARAMS(( int Signal )); | ||||
|  | ||||
| static void Show_Version PARAMS(( void )); | ||||
| static void Show_Help PARAMS(( void )); | ||||
|  | ||||
| @@ -292,8 +290,15 @@ main( int argc, const char *argv[] ) | ||||
| 		 * when not running in "no daemon" mode: */ | ||||
| 		if( ! NGIRCd_NoDaemon ) Log_InitErrorfile( ); | ||||
| #endif | ||||
| 		if (!io_library_init(CONNECTION_POOL)) { | ||||
| 			Log(LOG_ALERT, "Fatal: Cannot initialize IO routines: %s", strerror(errno)); | ||||
| 			exit(1); | ||||
| 		} | ||||
|  | ||||
| 		Initialize_Signal_Handler( ); | ||||
| 		if (!Signals_Init()) { | ||||
| 			Log(LOG_ALERT, "Fatal: Could not set up signal handlers: %s", strerror(errno)); | ||||
| 			exit(1); | ||||
| 		} | ||||
|  | ||||
| 		/* | ||||
| 		 * create protocol and server identification. | ||||
| @@ -475,80 +480,6 @@ NGIRCd_Rehash( void ) | ||||
| } /* NGIRCd_Rehash */ | ||||
|  | ||||
|  | ||||
| /** | ||||
|  * Initialize the signal handler. | ||||
|  */ | ||||
| static void | ||||
| Initialize_Signal_Handler( void ) | ||||
| { | ||||
| #ifdef HAVE_SIGACTION | ||||
| 	struct sigaction saction; | ||||
|  | ||||
| 	memset( &saction, 0, sizeof( saction )); | ||||
| 	saction.sa_handler = Signal_Handler; | ||||
| #ifdef SA_RESTART | ||||
| 	saction.sa_flags |= SA_RESTART; | ||||
| #endif | ||||
| #ifdef SA_NOCLDWAIT | ||||
| 	saction.sa_flags |= SA_NOCLDWAIT; | ||||
| #endif | ||||
|  | ||||
| 	sigaction(SIGINT, &saction, NULL); | ||||
| 	sigaction(SIGQUIT, &saction, NULL); | ||||
| 	sigaction(SIGTERM, &saction, NULL); | ||||
| 	sigaction(SIGHUP, &saction, NULL); | ||||
| 	sigaction(SIGCHLD, &saction, NULL); | ||||
|  | ||||
| 	/* we handle write errors properly; ignore SIGPIPE */ | ||||
| 	saction.sa_handler = SIG_IGN; | ||||
| 	sigaction(SIGPIPE, &saction, NULL); | ||||
| #else | ||||
| 	signal(SIGINT, Signal_Handler); | ||||
| 	signal(SIGQUIT, Signal_Handler); | ||||
| 	signal(SIGTERM, Signal_Handler); | ||||
| 	signal(SIGHUP, Signal_Handler); | ||||
| 	signal(SIGCHLD, Signal_Handler); | ||||
|  | ||||
| 	signal(SIGPIPE, SIG_IGN); | ||||
| #endif | ||||
| } /* Initialize_Signal_Handler */ | ||||
|  | ||||
|  | ||||
| /** | ||||
|  * Signal handler of ngIRCd. | ||||
|  * This function is called whenever ngIRCd catches a signal sent by the | ||||
|  * user and/or the system to it. For example SIGTERM and SIGHUP. | ||||
|  * @param Signal Number of the signal to handle. | ||||
|  */ | ||||
| static void | ||||
| Signal_Handler( int Signal ) | ||||
| { | ||||
| 	switch( Signal ) | ||||
| 	{ | ||||
| 		case SIGTERM: | ||||
| 		case SIGINT: | ||||
| 		case SIGQUIT: | ||||
| 			/* shut down sever */ | ||||
| 			NGIRCd_SignalQuit = true; | ||||
| 			break; | ||||
| 		case SIGHUP: | ||||
| 			/* re-read configuration */ | ||||
| 			NGIRCd_SignalRehash = true; | ||||
| 			break; | ||||
| 		case SIGCHLD: | ||||
| 			/* child-process exited, avoid zombies */ | ||||
| 			while (waitpid( -1, NULL, WNOHANG) > 0) | ||||
| 				; | ||||
| 			break; | ||||
| #ifdef DEBUG | ||||
| 		default: | ||||
| 			/* unbekanntes bzw. unbehandeltes Signal */ | ||||
| 			Log( LOG_DEBUG, "Got signal %d! Ignored.", Signal ); | ||||
| #endif | ||||
| 	} | ||||
| } /* Signal_Handler */ | ||||
|  | ||||
|  | ||||
| /** | ||||
|  * Display copyright and version information of ngIRCd on the console. | ||||
|  */ | ||||
|   | ||||
| @@ -21,6 +21,8 @@ | ||||
|  | ||||
| #include "defines.h" | ||||
|  | ||||
| #define C_ARRAY_SIZE(x)	(sizeof(x)/sizeof((x)[0])) | ||||
|  | ||||
|  | ||||
| GLOBAL time_t NGIRCd_Start;		/* Startzeitpunkt des Daemon */ | ||||
| GLOBAL char NGIRCd_StartStr[64]; | ||||
|   | ||||
| @@ -120,8 +120,6 @@ static bool Validate_Args PARAMS(( CONN_ID Idx, REQUEST *Req, bool *Closed )); | ||||
|  | ||||
| static bool Handle_Request PARAMS(( CONN_ID Idx, REQUEST *Req )); | ||||
|  | ||||
| #define ARRAY_SIZE(x)	(sizeof(x)/sizeof((x)[0])) | ||||
|  | ||||
| /** | ||||
|  * Return the pointer to the global "IRC command structure". | ||||
|  * This structure, an array of type "COMMAND" describes all the IRC commands | ||||
| @@ -397,7 +395,7 @@ Handle_Numeric(CLIENT *client, REQUEST *Req) | ||||
| 		/* This server is the target of the numeric */ | ||||
| 		num = atoi(Req->command); | ||||
|  | ||||
| 		for (i = 0; i < (int) ARRAY_SIZE(Numerics); i++) { | ||||
| 		for (i = 0; i < (int) C_ARRAY_SIZE(Numerics); i++) { | ||||
| 			if (num == Numerics[i].numeric) { | ||||
| 				if (!Numerics[i].function) | ||||
| 					return CONNECTED; | ||||
|   | ||||
| @@ -26,6 +26,7 @@ | ||||
| #include "conn.h" | ||||
|  | ||||
| #include "exp.h" | ||||
| #include "sighandlers.h" | ||||
| #include "proc.h" | ||||
|  | ||||
| /** | ||||
| @@ -67,6 +68,7 @@ Proc_Fork(PROC_STAT *proc, int *pipefds, void (*cbfunc)(int, short), int timeout | ||||
| 		return -1; | ||||
| 	case 0: | ||||
| 		/* New child process: */ | ||||
| 		Signals_Exit(); | ||||
| 		signal(SIGTERM, Proc_GenericSignalHandler); | ||||
| 		signal(SIGALRM, Proc_GenericSignalHandler); | ||||
| 		close(pipefds[0]); | ||||
|   | ||||
							
								
								
									
										220
									
								
								src/ngircd/sighandlers.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										220
									
								
								src/ngircd/sighandlers.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,220 @@ | ||||
| /* | ||||
|  * ngIRCd -- The Next Generation IRC Daemon | ||||
|  * | ||||
|  * 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 2 of the License, or | ||||
|  * (at your option) any later version. | ||||
|  * Please read the file COPYING, README and AUTHORS for more information. | ||||
|  */ | ||||
|  | ||||
| #include "portab.h" | ||||
|  | ||||
| /** | ||||
|  * @file | ||||
|  * Signal Handlers: Actions to be performed when the program | ||||
|  * receives a signal. | ||||
|  */ | ||||
|  | ||||
| #include <errno.h> | ||||
| #include <unistd.h> | ||||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
| #include <signal.h> | ||||
| #include <sys/types.h> | ||||
| #include <sys/wait.h> | ||||
|  | ||||
| #include "imp.h" | ||||
| #include "io.h" | ||||
| #include "log.h" | ||||
| #include "ngircd.h" | ||||
| #include "sighandlers.h" | ||||
|  | ||||
| static int signalpipe[2]; | ||||
|  | ||||
| static void Signal_Block(int sig) | ||||
| { | ||||
| #ifdef HAVE_SIGPROCMASK | ||||
| 	sigset_t set; | ||||
|  | ||||
| 	sigemptyset(&set); | ||||
| 	sigaddset(&set, sig); | ||||
|  | ||||
| 	sigprocmask(SIG_BLOCK, &set, NULL); | ||||
| #endif | ||||
| } | ||||
|  | ||||
|  | ||||
| static void Signal_Unblock(int sig) | ||||
| { | ||||
| #ifdef HAVE_SIGPROCMASK | ||||
| 	sigset_t set; | ||||
|  | ||||
| 	sigemptyset(&set); | ||||
| 	sigaddset(&set, sig); | ||||
|  | ||||
| 	sigprocmask(SIG_UNBLOCK, &set, NULL); | ||||
| #endif | ||||
| } | ||||
|  | ||||
|  | ||||
| /** | ||||
|  * Signal handler of ngIRCd. | ||||
|  * This function is called whenever ngIRCd catches a signal sent by the | ||||
|  * user and/or the system to it. For example SIGTERM and SIGHUP. | ||||
|  * | ||||
|  * It blocks the signal and queues it for later execution by Signal_Handler_BH. | ||||
|  * @param Signal Number of the signal to handle. | ||||
|  */ | ||||
| static void Signal_Handler(int Signal) | ||||
| { | ||||
| 	switch (Signal) { | ||||
| 	case SIGTERM: | ||||
| 	case SIGINT: | ||||
| 	case SIGQUIT: | ||||
| 		/* shut down sever */ | ||||
| 		NGIRCd_SignalQuit = true; | ||||
| 		return; | ||||
| 	case SIGHUP: | ||||
| 		/* re-read configuration */ | ||||
| 		NGIRCd_SignalRehash = true; | ||||
| 		return; | ||||
| 	case SIGCHLD: | ||||
| 		/* child-process exited, avoid zombies */ | ||||
| 		while (waitpid( -1, NULL, WNOHANG) > 0) | ||||
| 			; | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	/* | ||||
| 	 * other signal: queue for later execution. | ||||
| 	 * This has the advantage that we are not restricted | ||||
| 	 * to functions that can be called safely from signal handlers. | ||||
| 	 */ | ||||
| 	if (write(signalpipe[1], &Signal, sizeof(Signal)) != -1) | ||||
| 		Signal_Block(Signal); | ||||
| } /* Signal_Handler */ | ||||
|  | ||||
|  | ||||
| /** | ||||
|  * Signal processing handler of ngIRCd. | ||||
|  * This function is called from the main conn event loop in (io_dispatch) | ||||
|  * whenever ngIRCd has queued a signal. | ||||
|  * | ||||
|  * This function runs in normal context, not from the real signal handler, | ||||
|  * thus its not necessary to only use functions that are signal safe. | ||||
|  * @param Signal Number of the signal that was queued. | ||||
|  */ | ||||
| static void Signal_Handler_BH(int Signal) | ||||
| { | ||||
| 	switch (Signal) { | ||||
| #ifdef DEBUG | ||||
| 	default: | ||||
| 		Log(LOG_DEBUG, "Got signal %d! Ignored.", Signal); | ||||
| #endif | ||||
| 	} | ||||
| 	Signal_Unblock(Signal); | ||||
| } | ||||
|  | ||||
| static void Sig_callback(int fd, short UNUSED what) | ||||
| { | ||||
| 	int sig, ret; | ||||
| 	(void) what; | ||||
|  | ||||
| 	do { | ||||
| 		ret = read(fd, &sig, sizeof(sig)); | ||||
| 		if (ret == sizeof(int)) | ||||
| 			Signal_Handler_BH(sig); | ||||
| 	} while (ret == sizeof(int)); | ||||
|  | ||||
| 	if (ret == -1) { | ||||
| 		if (errno == EAGAIN || errno == EINTR) | ||||
| 			return; | ||||
|  | ||||
| 		Log(LOG_EMERG, "read from signal pipe: %s", strerror(errno)); | ||||
| 		exit(1); | ||||
| 	} | ||||
|  | ||||
| 	Log(LOG_EMERG, "EOF on signal pipe"); | ||||
| 	exit(1); | ||||
| } | ||||
|  | ||||
|  | ||||
| static const int signals_catch[] = { SIGINT, SIGQUIT, SIGTERM, SIGHUP, SIGCHLD, SIGUSR1, SIGUSR2 }; | ||||
| /** | ||||
|  * Initialize the signal handlers, catch | ||||
|  * those signals we are interested in and sets SIGPIPE to be ignored. | ||||
|  * @return true if initialization was sucessful. | ||||
|  */ | ||||
| bool Signals_Init(void) | ||||
| { | ||||
| 	size_t i; | ||||
| #ifdef HAVE_SIGACTION | ||||
| 	struct sigaction saction; | ||||
| #endif | ||||
|  | ||||
| 	if (pipe(signalpipe)) | ||||
| 		return false; | ||||
|  | ||||
| 	if (!io_setnonblock(signalpipe[0]) || | ||||
| 	    !io_setnonblock(signalpipe[1])) | ||||
| 		return false; | ||||
| 	if (!io_setcloexec(signalpipe[0]) || | ||||
| 	    !io_setcloexec(signalpipe[1])) | ||||
| 		return false; | ||||
| #ifdef HAVE_SIGACTION | ||||
| 	memset( &saction, 0, sizeof( saction )); | ||||
| 	saction.sa_handler = Signal_Handler; | ||||
| #ifdef SA_RESTART | ||||
| 	saction.sa_flags |= SA_RESTART; | ||||
| #endif | ||||
| #ifdef SA_NOCLDWAIT | ||||
| 	saction.sa_flags |= SA_NOCLDWAIT; | ||||
| #endif | ||||
|  | ||||
| 	for (i=0; i < C_ARRAY_SIZE(signals_catch) ; i++) | ||||
| 		sigaction(signals_catch[i], &saction, NULL); | ||||
|  | ||||
| 	/* we handle write errors properly; ignore SIGPIPE */ | ||||
| 	saction.sa_handler = SIG_IGN; | ||||
| 	sigaction(SIGPIPE, &saction, NULL); | ||||
| #else | ||||
| 	for (i=0; i < C_ARRAY_SIZE(signals_catch) ; i++) | ||||
| 		signal(signals_catch[i], Signal_Handler); | ||||
|  | ||||
| 	signal(SIGPIPE, SIG_IGN); | ||||
| #endif | ||||
| 	return io_event_create(signalpipe[0], IO_WANTREAD, | ||||
| 					Sig_callback); | ||||
| } /* Initialize_Signal_Handler */ | ||||
|  | ||||
|  | ||||
| /** | ||||
|  * Restores signals to their default behaviour. | ||||
|  * | ||||
|  * This should be called after a fork() in the new | ||||
|  * child prodcess, especially when we are about to call | ||||
|  * 3rd party code (e.g. PAM). | ||||
|  */ | ||||
| void Signals_Exit(void) | ||||
| { | ||||
| 	size_t i; | ||||
| #ifdef HAVE_SIGACTION | ||||
| 	struct sigaction saction; | ||||
|  | ||||
| 	memset(&saction, 0, sizeof(saction)); | ||||
| 	saction.sa_handler = SIG_DFL; | ||||
|  | ||||
| 	for (i=0; i < C_ARRAY_SIZE(signals_catch) ; i++) | ||||
| 		sigaction(signals_catch[i], &saction, NULL); | ||||
| 	sigaction(SIGPIPE, &saction, NULL); | ||||
| #else | ||||
| 	for (i=0; i < C_ARRAY_SIZE(signals_catch) ; i++) | ||||
| 		sigaction(signals_catch[i], &saction, NULL); | ||||
| 	signal(SIGPIPE, SIG_DFL); | ||||
| #endif | ||||
| 	close(signalpipe[1]); | ||||
| 	close(signalpipe[0]); | ||||
| } | ||||
|  | ||||
| /* -eof- */ | ||||
							
								
								
									
										18
									
								
								src/ngircd/sighandlers.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								src/ngircd/sighandlers.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,18 @@ | ||||
| /* | ||||
|  * 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 2 of the License, or | ||||
|  * (at your option) any later version. | ||||
|  * Please read the file COPYING, README and AUTHORS for more information. | ||||
|  */ | ||||
|  | ||||
| #ifndef signals_included_ | ||||
| #define signals_included_ | ||||
|  | ||||
| #include "portab.h" | ||||
|  | ||||
| bool Signals_Init(void); | ||||
| void Signals_Exit(void); | ||||
|  | ||||
|  | ||||
| #endif | ||||
		Reference in New Issue
	
	Block a user
	 Florian Westphal
					Florian Westphal