File: [local] / acopm / src / signal.c (download)
Revision 1.1.1.1 (vendor branch), Sat May 8 15:42:17 2021 UTC (3 years, 2 months ago) by bountyht
Branch: alphachat, MAIN
CVS Tags: start, HEAD Changes since 1.1: +0 -0 lines
Initial import
|
/*
* Copyright (C) 2017 Aaron M. D. Jones <aaronmdjones@gmail.com>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following
* conditions are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE ARE DISCLAIMED.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "acopm-common.h"
#include <assert.h> /* assert() */
#include <errno.h> /* errno */
#include <signal.h> /* SIGCHLD, SIGHUP, SIGINT, SIGQUIT, SIGTERM */
#include <string.h> /* strerror() */
#include <sys/wait.h> /* waitpid(), WNOHANG */
#include <event2/event.h> /* event_*(), struct event */
#include "signal.h" /* decls for own functions */
#include "vars.h" /* global variable definitions */
#include "utils/log.h" /* acopm_log_*() */
static struct event *ev_sigchld = NULL;
static struct event *ev_sighup = NULL;
static struct event *ev_sigint = NULL;
static struct event *ev_sigquit = NULL;
static struct event *ev_sigterm = NULL;
static inline const char * acopm_attr_inline
acopm_signum_to_name(const int signum)
{
switch (signum)
{
case SIGCHLD:
return "SIGCHLD";
case SIGHUP:
return "SIGHUP";
case SIGINT:
return "SIGINT";
case SIGQUIT:
return "SIGQUIT";
case SIGTERM:
return "SIGTERM";
}
abort();
return NULL;
}
static void
acopm_sighandle_callback(const int signum, const short acopm_attr_unused events,
void acopm_attr_unused *const restrict context)
{
assert(signum == SIGHUP || signum == SIGINT || signum == SIGQUIT || signum == SIGTERM);
const char *const signame = acopm_signum_to_name(signum);
(void) acopm_log_notice("Caught signal %s", signame);
(void) acopm_irc_disconnect(acopm_irc_client);
(void) event_base_loopbreak(ev_base);
}
static void
acopm_sighandle_child_callback(const int signum, const short acopm_attr_unused events,
void acopm_attr_unused *const restrict context)
{
assert(signum == SIGCHLD);
const char *const signame = acopm_signum_to_name(signum);
(void) acopm_log_debug("Caught signal %s", signame);
int status = 0;
const int result = waitpid(-1, &status, WNOHANG);
if (result == -1 && errno != ECHILD)
(void) acopm_log_error("%s: waitpid: %s", __func__, strerror(errno));
if (result == -1 || result == 0)
return;
if (WIFEXITED(status) && WEXITSTATUS(status))
{
const int errnum = (int) WEXITSTATUS(status);
(void) acopm_log_warning("%s: a child process exited with status code %d", __func__, errnum);
if (*proxy_hit_log)
(void) acopm_log_warning("%s: check the contents of '%s'", __func__, proxy_hit_log);
}
else if (WIFSIGNALED(status) && WTERMSIG(status))
{
const int errsig = (int) WTERMSIG(status);
(void) acopm_log_warning("%s: a child process exited due to signal %d", __func__, errsig);
if (*proxy_hit_log)
(void) acopm_log_warning("%s: check the contents of '%s'", __func__, proxy_hit_log);
}
else
(void) acopm_log_warning("%s: something strange happened to a child process", __func__);
}
static inline bool acopm_attr_inline
acopm_sighandle_install(const int signum, struct event **const restrict ev, const event_callback_fn callback_func)
{
if (! (*ev = event_new(ev_base, signum, EV_SIGNAL, callback_func, NULL)))
{
(void) acopm_log_error("%s: event_new: %s", __func__, strerror(errno));
return false;
}
if (event_add(*ev, NULL) != 0)
{
(void) acopm_log_error("%s: event_add: %s", __func__, strerror(errno));
(void) event_free(*ev);
*ev = NULL;
return false;
}
return true;
}
bool
acopm_sighandle_init(void)
{
if (! acopm_sighandle_install(SIGCHLD, &ev_sigchld, acopm_sighandle_child_callback))
return false;
if (! acopm_sighandle_install(SIGHUP, &ev_sighup, acopm_sighandle_callback))
return false;
if (! acopm_sighandle_install(SIGINT, &ev_sigint, acopm_sighandle_callback))
return false;
if (! acopm_sighandle_install(SIGQUIT, &ev_sigquit, acopm_sighandle_callback))
return false;
if (! acopm_sighandle_install(SIGTERM, &ev_sigterm, acopm_sighandle_callback))
return false;
return true;
}
void
acopm_sighandle_free(void)
{
if (ev_sigchld)
{
(void) event_free(ev_sigchld);
ev_sigchld = NULL;
}
if (ev_sighup)
{
(void) event_free(ev_sighup);
ev_sighup = NULL;
}
if (ev_sigint)
{
(void) event_free(ev_sigint);
ev_sigint = NULL;
}
if (ev_sigquit)
{
(void) event_free(ev_sigquit);
ev_sigquit = NULL;
}
if (ev_sigterm)
{
(void) event_free(ev_sigterm);
ev_sigterm = NULL;
}
}