/*
* $Id: sighnd.c,v 1.6 2025/03/24 04:15:25 snw Exp $
* FreeM signal handlers
*
*
* Author: Serena Willis <snw@coherent-logic.com>
* Copyright (C) 1998 MUG Deutschland
* Copyright (C) 2020, 2025 Coherent Logic Development LLC
*
*
* This file is part of FreeM.
*
* FreeM is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* FreeM 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 Affero Public License for more details.
*
* You should have received a copy of the GNU Affero Public License
* along with FreeM. If not, see <https://www.gnu.org/licenses/>.
*
* $Log: sighnd.c,v $
* Revision 1.6 2025/03/24 04:15:25 snw
* Create dummy onwinch signal handler for OS/2
*
* Revision 1.5 2025/03/24 00:38:40 snw
* Fix termios junk in sighnd.c
*
* Revision 1.4 2025/03/24 00:34:30 snw
* Fix termios junk in sighnd.c
*
* Revision 1.3 2025/03/09 19:50:47 snw
* Second phase of REUSE compliance and header reformat
*
*
* SPDX-FileCopyrightText: (C) 2025 Coherent Logic Development LLC
* SPDX-License-Identifier: AGPL-3.0-or-later
**/
#include <stddef.h>
#include <stdlib.h>
#include <setjmp.h>
#include <signal.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#if !defined(__APPLE__) && !defined(__gnu_hurd__) && !defined(EMSCRIPTEN)
# if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__AMIGA)
# include <termios.h>
# if !defined(__AMIGA)
# define TCGETA TIOCGETA
# define TCSETA TIOCSETA
# endif
# define termio termios
# else
# if !defined(MSDOS)
# include <termio.h>
# endif
# endif
#else
# include <termios.h>
#endif
#include <sys/ioctl.h>
#include "mpsdef.h"
#include "transact.h"
#include "init.h"
#include "events.h"
#include "jobtab.h"
#include "shmmgr.h"
void m_log (int, const char *);
int pending_signal_type = -1;
void sig_attach(int sig, void *handler)
{
struct sigaction act;
act.sa_handler = handler;
#if !defined(__AMIGA)
sigaction (sig, &act, NULL);
#else
//TODO: fill in for m68k-amigaos
#endif
}
void sig_init(void)
{
/* signals stuff */
sig_attach (SIGINT, &onintr); /* set_up INTERRUPT */
sig_attach (SIGQUIT, &onquit); /* set_up ZBREAK */
sig_attach (SIGTERM, &onkill); /* catch kill signal */
#if !defined(__CYGWIN__) && !defined(MSDOS)
sig_attach (SIGIOT, &onbus); /* catch IOT error */
#endif/*__CYGWIN__*/
#ifndef LINUX
sig_attach (SIGEMT, &onbus); /* catch EMT error */
#endif/*LINUX*/
#if !defined(MSDOS)
sig_attach (SIGWINCH, &onwinch);
#endif
sig_attach (SIGUSR1, &oncld); /* catch son dies signal */
sig_attach (SIGHUP, &onhup); /* catch hangup */
sig_attach (SIGUSR2, &onipc); /* catch IPC signal */
sig_attach (SIGFPE, &onfpe); /* catch floating pt except */
}
#if !defined(MSDOS) && !defined(__OS2__)
void onwinch (void)
{
struct winsize ws;
/* restore handler */
sig_attach (SIGWINCH, &onwinch);
ioctl (STDIN_FILENO, TIOCGWINSZ, &ws);
n_lines = ws.ws_row;
n_columns = ws.ws_col;
if (evt_async_enabled) {
pending_signal_type = SIGWINCH;
merr_raise (ASYNC);
}
return;
}
#else
void onwinch (void)
{
sig_attach (SIGWINCH, &onwinch);
return;
}
#endif
void onintr (void)
{
sig_attach (SIGINT, &onintr); /* restore handler */
//printf ("\r\nSIGINT codptr = '%s'\r\n", codptr);
if (first_process) {
job_request_stop (pid);
}
else {
if (shm_config->hdr->maintenance_mode == 1) {
job_slot_t *s = job_get (pid);
if ((s->flags & JFLG_FMADM) != JFLG_FMADM) {
fprintf (stderr, "\r\n***ENVIRONMENT IN MAINTENANCE MODE***\r\n");
while (shm_config->hdr->maintenance_mode == 1) {
sleep (1);
}
return;
}
}
}
if (breakon) {
merr_raise (INRPT);
inrpt_after_async = TRUE;
if (forsw) sigint_in_for = TRUE;
}
else {
zcc = TRUE;
}
if (evt_async_enabled) {
pending_signal_type = SIGINT;
}
return;
} /* end of onintr */
void onfpe (void)
{
sig_attach (SIGFPE, &onfpe); /* restore handler */
if (evt_async_enabled) {
pending_signal_type = SIGFPE;
}
merr_raise (MXNUM);
return;
} /* end of onfpe */
void onquit (void)
{
if (run_daemon == TRUE) {
job_request_stop (pid);
}
sig_attach (SIGQUIT, &onquit); /* restore handler */
if (zbreakon && (merr () == OK)) ierr = OK - CTRLB;
if (evt_async_enabled) {
pending_signal_type = SIGQUIT;
}
return;
} /* end of onquit */
void onkill (void)
{
int n = 0;
if (run_daemon == TRUE) {
job_request_stop (pid);
}
#if !defined(AMIGA68K)
if (direct_mode == TRUE) {
set_io (UNIX);
fprintf (stderr, "\n\nFreeM process %d caught SIGTERM\n", pid);
set_io (MUMPS);
}
#endif
sig_attach (SIGTERM, &onkill); /* restore handler */
if (killerflag == FALSE) return; /* ignore that signal */
/* if there exists an error trap, process as an error */
/* otherwise terminate the job */
if (DSM2err) { /* DSM V.2 error trapping */
if (ztrap[NESTLEVLS + 1][0] != EOL) {
merr_raise (KILLER);
return;
}
}
else {
while (n >= 0) {
if (ztrap[n--][0] != EOL) {
merr_raise (KILLER);
return;
}
}
}
cleanup ();
if (father) kill (father, SIGUSR1); /* advertise death to parent */
exit (1); /* terminate mumps */
} /* end of onkill() */
void onhup (void)
{
int n = nstx;
if (run_daemon == TRUE) {
fprintf (stderr, "freem: daemon received SIGHUP\r\n");
m_log (1, "freem: daemon received SIGHUP");
sig_attach (SIGHUP, &onhup); /* restore handler */
return;
}
sig_attach (SIGHUP, &onhup); /* restore handler */
if (huperflag == FALSE) return; /* ignore that signal */
/* if there exists an error trap, process as an error */
/* otherwise terminate the job */
if (DSM2err) { /* DSM V.2 error trapping */
if (ztrap[NESTLEVLS + 1][0] != EOL) {
merr_raise (HUPER);
return;
}
}
else {
while (n >= 0) {
if (ztrap[n--][0] != EOL) {
merr_raise (HUPER);
return;
}
}
}
cleanup ();
if (father) kill (father, SIGUSR1); /* advertise death to parent */
exit (1); /* terminate mumps */
} /* end of onhup() */
void onbus (void)
{
cleanup ();
printf ("\012\015BUS ERROR, SEGMENTATION VIOLATION\012\015");
if (father) kill (father, SIGUSR1); /* advertise death to parent */
exit (1); /* terminate mumps */
} /* end of onbus() */
/* under XENIX processes started with JOB hang around as zombies */
/* if they HALT before the parent process, unless the parent process */
/* waits for his child to terminate. to solve the problem, the child */
/* sends a signal to his parent to avoid an unattended funeral which */
/* inevitably would result in a living dead sucking up cpu time */
void oncld (void)
{
int status;
/* ignore signal while as we're here */
sig_attach (SIGUSR1, SIG_IGN);
wait (&status); /* wait for report from child */
sig_attach (SIGUSR1, &oncld);/* restore handler */
return;
} /* end of oncld() */
void onipc (void)
{
/* restore handler */
sig_attach (SIGUSR2, &onipc);
ipc_pending = 1;
return;
}
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>