/*-
 * redshift-ng - Automatically adjust display colour temperature according the Sun
 * 
 * Copyright (c) 2009-2018        Jon Lund Steffensen <jonlst@gmail.com>
 * Copyright (c) 2014-2016, 2025  Mattias Andrée <m@maandree.se>
 * 
 * redshift-ng 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.
 * 
 * redshift-ng 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 redshift-ng.  If not, see <http://www.gnu.org/licenses/>.
 */
#include "common.h"


volatile sig_atomic_t exiting = 0;
volatile sig_atomic_t disable = 0;


/**
 * Signal handler for exit signals (SIGINT, SIGTERM, SIGQUIT)
 * 
 * @param  signo  The received signal
 */
static void
sigexit(int signo)
{
	exiting = 1;
#ifdef WINDOWS
	signal(signo, &sigexit);
#endif
	(void) signo;
}


/**
 * Signal handler for disable signal (SIGUSR1)
 * 
 * @param  signo  The received signal
 */
#ifndef WINDOWS
static void
sigdisable(int signo)
{
	disable = 1;
	(void) signo;
}
#endif


/**
 * Signal handler for forceful exiting; installed by
 * `install_forceful_exit_signal_handlers`
 * 
 * @param  signo  The received signal
 */
#ifndef WINDOWS
static void
sigalrm(int signo)
{
	if (exiting || signo == SIGALRM)
		exit(0);
	exiting = 1;
	alarm(1U);
}
#endif


void
install_signal_handlers(void)
{
#ifdef WINDOWS
	if (signal(SIGINT, &sigexit) == SIG_ERR)
		eprintf("signal SIGINT <function pointer>:");
	if (signal(SIGTERM, &sigexit) == SIG_ERR)
		eprintf("signal SIGTERM <function pointer>:");

#else
	struct sigaction sigact;
	sigset_t sigset;

	memset(&sigact, 0, sizeof(sigact));
	sigemptyset(&sigset);
	sigact.sa_mask = sigset;
	sigact.sa_flags = 0;

	sigact.sa_handler = &sigexit;
	if (sigaction(SIGINT, &sigact, NULL))
		eprintf("sigaction SIGINT &{.sa_handler=<function pointer>, .sa_mask={}, .sa_flags=0} NULL:");
	if (sigaction(SIGTERM, &sigact, NULL))
		eprintf("sigaction SIGTERM &{.sa_handler=<function pointer>, .sa_mask={}, .sa_flags=0} NULL:");
	if (sigaction(SIGQUIT, &sigact, NULL))
		eprintf("sigaction SIGQUIT &{.sa_handler=<function pointer>, .sa_mask={}, .sa_flags=0} NULL:");

	sigact.sa_handler = &sigdisable;
	if (sigaction(SIGUSR1, &sigact, NULL))
		eprintf("sigaction SIGUSR1 &{.sa_handler=<function pointer>, .sa_mask={}, .sa_flags=0} NULL:");

	sigact.sa_handler = SIG_IGN; /* cause child processes (hooks) to be reaped automatically */
	if (sigaction(SIGCHLD, &sigact, NULL))
		eprintf("sigaction SIGCHLD &{.sa_handler=SIG_IGN, .sa_mask={}, .sa_flags=0} NULL:");
#endif
}


#ifndef WINDOWS
void
install_forceful_exit_signal_handlers(void)
{
	struct sigaction sigact;
	sigset_t sigset;

	exiting = 0;
	memset(&sigact, 0, sizeof(sigact));
	sigemptyset(&sigset);
	sigact.sa_mask = sigset;
	sigact.sa_flags = 0;
	sigact.sa_handler = &sigalrm;
	if (sigaction(SIGINT, &sigact, NULL))
		eprintf("sigaction SIGINT &{.sa_handler=<function pointer>, .sa_mask={}, .sa_flags=0} NULL:");
	if (sigaction(SIGTERM, &sigact, NULL))
		eprintf("sigaction SIGTERM &{.sa_handler=<function pointer>, .sa_mask={}, .sa_flags=0} NULL:");
	if (sigaction(SIGQUIT, &sigact, NULL))
		eprintf("sigaction SIGQUIT &{.sa_handler=<function pointer>, .sa_mask={}, .sa_flags=0} NULL:");
	if (sigaction(SIGALRM, &sigact, NULL))
		eprintf("sigaction SIGALRM &{.sa_handler=<function pointer>, .sa_mask={}, .sa_flags=0} NULL:");
}
#endif