mirror of
https://github.com/weechat/weechat.git
synced 2026-06-27 05:16:38 +02:00
329 lines
7.2 KiB
C
329 lines
7.2 KiB
C
/*
|
|
* core-signal.c - signal functions
|
|
*
|
|
* Copyright (C) 2021-2024 Sébastien Helleu <flashcode@flashtux.org>
|
|
*
|
|
* This file is part of WeeChat, the extensible chat client.
|
|
*
|
|
* WeeChat 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.
|
|
*
|
|
* WeeChat 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 WeeChat. If not, see <https://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <string.h>
|
|
#include <signal.h>
|
|
|
|
#include "weechat.h"
|
|
#include "core-signal.h"
|
|
#include "core-config.h"
|
|
#include "core-debug.h"
|
|
#include "core-eval.h"
|
|
#include "core-hook.h"
|
|
#include "core-input.h"
|
|
#include "core-log.h"
|
|
#include "core-string.h"
|
|
#include "../gui/gui-buffer.h"
|
|
#include "../gui/gui-window.h"
|
|
#include "../plugins/plugin.h"
|
|
|
|
|
|
struct t_signal signal_list[] =
|
|
{ { SIGHUP, "hup" },
|
|
{ SIGINT, "int" },
|
|
{ SIGQUIT, "quit" },
|
|
{ SIGKILL, "kill" },
|
|
{ SIGTERM, "term" },
|
|
{ SIGUSR1, "usr1" },
|
|
{ SIGUSR2, "usr2" },
|
|
{ 0, NULL },
|
|
};
|
|
|
|
volatile sig_atomic_t signal_sighup_count = 0;
|
|
volatile sig_atomic_t signal_sigquit_count = 0;
|
|
volatile sig_atomic_t signal_sigterm_count = 0;
|
|
volatile sig_atomic_t signal_sigusr1_count = 0;
|
|
volatile sig_atomic_t signal_sigusr2_count = 0;
|
|
|
|
|
|
/*
|
|
* Callback for system signal SIGHUP.
|
|
*/
|
|
|
|
void
|
|
signal_sighup_cb ()
|
|
{
|
|
signal_sighup_count++;
|
|
}
|
|
|
|
/*
|
|
* Callback for system signal SIGQUIT.
|
|
*/
|
|
|
|
void
|
|
signal_sigquit_cb ()
|
|
{
|
|
signal_sigquit_count++;
|
|
}
|
|
|
|
/*
|
|
* Callback for system signal SIGTERM.
|
|
*/
|
|
|
|
void
|
|
signal_sigterm_cb ()
|
|
{
|
|
signal_sigterm_count++;
|
|
}
|
|
|
|
/*
|
|
* Callback for system signal SIGUSR1.
|
|
*/
|
|
|
|
void
|
|
signal_sigusr1_cb ()
|
|
{
|
|
signal_sigusr1_count++;
|
|
}
|
|
|
|
/*
|
|
* Callback for system signal SIGUSR2.
|
|
*/
|
|
|
|
void
|
|
signal_sigusr2_cb ()
|
|
{
|
|
signal_sigusr2_count++;
|
|
}
|
|
|
|
/*
|
|
* Gets a signal index with a signal number; only some commonly used signal
|
|
* names are supported here (see declaration of signal_list[]).
|
|
*
|
|
* Returns the index of signal in structure string_signal, -1 if not found.
|
|
*/
|
|
|
|
int
|
|
signal_search_number (int signal_number)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; signal_list[i].name; i++)
|
|
{
|
|
if (signal_list[i].signal == signal_number)
|
|
return i;
|
|
}
|
|
|
|
/* signal not found */
|
|
return -1;
|
|
}
|
|
|
|
/*
|
|
* Gets a signal number with a name; only some commonly used signal names are
|
|
* supported here (see declaration of signal_list[]).
|
|
*
|
|
* Returns the signal number, -1 if not found.
|
|
*/
|
|
|
|
int
|
|
signal_search_name (const char *name)
|
|
{
|
|
int i;
|
|
|
|
if (!name)
|
|
return -1;
|
|
|
|
for (i = 0; signal_list[i].name; i++)
|
|
{
|
|
if (string_strcasecmp (signal_list[i].name, name) == 0)
|
|
return signal_list[i].signal;
|
|
}
|
|
|
|
/* signal not found */
|
|
return -1;
|
|
}
|
|
|
|
/*
|
|
* Catches a system signal.
|
|
*/
|
|
|
|
void
|
|
signal_catch (int signum, void (*handler)(int))
|
|
{
|
|
struct sigaction act;
|
|
|
|
sigemptyset (&act.sa_mask);
|
|
act.sa_flags = 0;
|
|
act.sa_handler = handler;
|
|
sigaction (signum, &act, NULL);
|
|
}
|
|
|
|
/*
|
|
* Sends a WeeChat signal on a system signal received.
|
|
*
|
|
* Returns:
|
|
* WEECHAT_RC_OK: the WeeChat handler must be executed
|
|
* WEECHAT_RC_OK_EAT: signal eaten, the WeeChat handler must NOT be executed
|
|
*/
|
|
|
|
int
|
|
signal_send_to_weechat (int signal_index)
|
|
{
|
|
int rc;
|
|
char str_signal[32];
|
|
|
|
if (signal_index < 0)
|
|
return WEECHAT_RC_OK;
|
|
|
|
snprintf (str_signal, sizeof (str_signal),
|
|
"signal_sig%s", signal_list[signal_index].name);
|
|
|
|
rc = hook_signal_send (str_signal, WEECHAT_HOOK_SIGNAL_STRING, NULL);
|
|
|
|
return (rc == WEECHAT_RC_OK_EAT) ? WEECHAT_RC_OK_EAT : WEECHAT_RC_OK;
|
|
}
|
|
|
|
/*
|
|
* Evaluates and executes the command bound to a signal.
|
|
*/
|
|
|
|
void
|
|
signal_exec_command (int signal_index, const char *command)
|
|
{
|
|
char str_signal[32], *signal_upper, **commands, **ptr_command;
|
|
char *command_eval;
|
|
|
|
if (!command || !command[0])
|
|
return;
|
|
|
|
snprintf (str_signal, sizeof (str_signal),
|
|
"sig%s", signal_list[signal_index].name);
|
|
|
|
commands = string_split_command (command, ';');
|
|
if (commands)
|
|
{
|
|
for (ptr_command = commands; *ptr_command; ptr_command++)
|
|
{
|
|
command_eval = eval_expression (*ptr_command, NULL, NULL, NULL);
|
|
if (command_eval)
|
|
{
|
|
signal_upper = string_toupper (str_signal);
|
|
log_printf ("Signal %s received, executing command: \"%s\"",
|
|
(signal_upper) ? signal_upper : str_signal,
|
|
command_eval);
|
|
free (signal_upper);
|
|
(void) input_data (gui_buffer_search_main (),
|
|
command_eval, NULL, 0, 0);
|
|
free (command_eval);
|
|
}
|
|
}
|
|
string_free_split_command (commands);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Handles a specific signal received:
|
|
*/
|
|
|
|
void
|
|
signal_handle_number (int signal_number, int count, const char *command)
|
|
{
|
|
int i, signal_index, rc;
|
|
|
|
if (count == 0)
|
|
return;
|
|
|
|
signal_index = signal_search_number (signal_number);
|
|
if (signal_index < 0)
|
|
return;
|
|
|
|
for (i = 0; i < count; i++)
|
|
{
|
|
rc = signal_send_to_weechat (signal_index);
|
|
if (rc == WEECHAT_RC_OK_EAT)
|
|
continue;
|
|
signal_exec_command (signal_index, command);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Handles signals received: sends WeeChat signal and executes the configured
|
|
* command (is signal not eaten).
|
|
*/
|
|
|
|
void
|
|
signal_handle ()
|
|
{
|
|
/* SIGUSR1 */
|
|
signal_handle_number (SIGUSR1, signal_sigusr1_count,
|
|
CONFIG_STRING(config_signal_sigusr1));
|
|
signal_sigusr1_count = 0;
|
|
|
|
/* SIGUSR2 */
|
|
signal_handle_number (SIGUSR2, signal_sigusr2_count,
|
|
CONFIG_STRING(config_signal_sigusr2));
|
|
signal_sigusr2_count = 0;
|
|
|
|
/* SIGHUP */
|
|
signal_handle_number (SIGHUP, signal_sighup_count,
|
|
CONFIG_STRING(config_signal_sighup));
|
|
signal_sighup_count = 0;
|
|
|
|
/* SIGQUIT */
|
|
signal_handle_number (SIGQUIT, signal_sigquit_count,
|
|
CONFIG_STRING(config_signal_sigquit));
|
|
signal_sigquit_count = 0;
|
|
|
|
/* SIGTERM */
|
|
signal_handle_number (SIGTERM, signal_sigterm_count,
|
|
CONFIG_STRING(config_signal_sigterm));
|
|
signal_sigterm_count = 0;
|
|
}
|
|
|
|
/*
|
|
* Suspends WeeChat process.
|
|
*/
|
|
|
|
void
|
|
signal_suspend ()
|
|
{
|
|
kill (getpid (), SIGTSTP);
|
|
gui_window_ask_refresh (2);
|
|
}
|
|
|
|
/*
|
|
* Initializes signal.
|
|
*/
|
|
|
|
void
|
|
signal_init ()
|
|
{
|
|
/* ignore some signals */
|
|
signal_catch (SIGINT, SIG_IGN);
|
|
signal_catch (SIGPIPE, SIG_IGN);
|
|
|
|
/* catch signals that can be customized */
|
|
signal_catch (SIGHUP, &signal_sighup_cb);
|
|
signal_catch (SIGQUIT, &signal_sigquit_cb);
|
|
signal_catch (SIGTERM, &signal_sigterm_cb);
|
|
signal_catch (SIGUSR1, &signal_sigusr1_cb);
|
|
signal_catch (SIGUSR2, &signal_sigusr2_cb);
|
|
|
|
/* in case of crash (oh no!) */
|
|
signal_catch (SIGSEGV, &debug_sigsegv_cb);
|
|
}
|