1: /*
2: * $Id: sighnd.c,v 1.12 2026/01/07 19:51:33 snw Exp $
3: * FreeM signal handlers
4: *
5: *
6: * Author: Serena Willis <snw@coherent-logic.com>
7: * Copyright (C) 1998 MUG Deutschland
8: * Copyright (C) 2020, 2025 Coherent Logic Development LLC
9: *
10: *
11: * This file is part of FreeM.
12: *
13: * FreeM is free software: you can redistribute it and/or modify
14: * it under the terms of the GNU Affero Public License as published by
15: * the Free Software Foundation, either version 3 of the License, or
16: * (at your option) any later version.
17: *
18: * FreeM is distributed in the hope that it will be useful,
19: * but WITHOUT ANY WARRANTY; without even the implied warranty of
20: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21: * GNU Affero Public License for more details.
22: *
23: * You should have received a copy of the GNU Affero Public License
24: * along with FreeM. If not, see <https://www.gnu.org/licenses/>.
25: *
26: * $Log: sighnd.c,v $
27: * Revision 1.12 2026/01/07 19:51:33 snw
28: * Fix segfault in reverse $QUERY
29: *
30: * Revision 1.11 2025/05/01 21:02:31 snw
31: * Documentation updates
32: *
33: * Revision 1.10 2025/04/30 20:03:09 snw
34: * Work on entryref parser
35: *
36: * Revision 1.9 2025/04/15 18:39:20 snw
37: * Remove extraneous CRLFs in logprintf calls
38: *
39: * Revision 1.8 2025/04/15 16:49:36 snw
40: * Make use of logprintf throughout codebase
41: *
42: * Revision 1.7 2025/04/10 01:24:38 snw
43: * Remove C++ style comments
44: *
45: * Revision 1.6 2025/03/24 04:15:25 snw
46: * Create dummy onwinch signal handler for OS/2
47: *
48: * Revision 1.5 2025/03/24 00:38:40 snw
49: * Fix termios junk in sighnd.c
50: *
51: * Revision 1.4 2025/03/24 00:34:30 snw
52: * Fix termios junk in sighnd.c
53: *
54: * Revision 1.3 2025/03/09 19:50:47 snw
55: * Second phase of REUSE compliance and header reformat
56: *
57: *
58: * SPDX-FileCopyrightText: (C) 2025 Coherent Logic Development LLC
59: * SPDX-License-Identifier: AGPL-3.0-or-later
60: **/
61:
62: #include <stddef.h>
63: #include <stdlib.h>
64: #include <setjmp.h>
65: #include <signal.h>
66: #include <unistd.h>
67: #include <stdio.h>
68:
69: #include <sys/types.h>
70: #include <sys/wait.h>
71:
72: #if !defined(__APPLE__) && !defined(__gnu_hurd__) && !defined(EMSCRIPTEN)
73: # if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__AMIGA)
74: # include <termios.h>
75: # if !defined(__AMIGA)
76: # define TCGETA TIOCGETA
77: # define TCSETA TIOCSETA
78: # endif
79: # define termio termios
80: # else
81: # if !defined(MSDOS) && !defined(__linux__)
82: # include <termio.h>
83: # else
84: # include <termios.h>
85: # endif
86: # endif
87: #else
88: # include <termios.h>
89: #endif
90:
91: #include <sys/ioctl.h>
92:
93: #include "mpsdef.h"
94: #include "transact.h"
95: #include "init.h"
96: #include "events.h"
97: #include "jobtab.h"
98: #include "shmmgr.h"
99: #include "log.h"
100:
101:
102: int pending_signal_type = -1;
103:
104: void sig_attach(int sig, void *handler)
105: {
106: struct sigaction act;
107:
108: act.sa_handler = handler;
109: #if !defined(__AMIGA)
110: sigaction (sig, &act, NULL);
111: #else
112: /* TODO: fill in for m68k-amigaos */
113: #endif
114: }
115:
116:
117: void sig_init(void)
118: {
119: /* signals stuff */
120: sig_attach (SIGINT, &onintr); /* set_up INTERRUPT */
121: sig_attach (SIGQUIT, &onquit); /* set_up ZBREAK */
122: sig_attach (SIGTERM, &onkill); /* catch kill signal */
123:
124: #if !defined(__CYGWIN__) && !defined(MSDOS)
125: sig_attach (SIGIOT, &onbus); /* catch IOT error */
126: #endif/*__CYGWIN__*/
127:
128: #ifndef LINUX
129: sig_attach (SIGEMT, &onbus); /* catch EMT error */
130: #endif/*LINUX*/
131:
132: #if !defined(MSDOS)
133: sig_attach (SIGWINCH, &onwinch);
134: #endif
135:
136: sig_attach (SIGUSR1, &oncld); /* catch son dies signal */
137: sig_attach (SIGHUP, &onhup); /* catch hangup */
138:
139: sig_attach (SIGUSR2, &onipc); /* catch IPC signal */
140: sig_attach (SIGFPE, &onfpe); /* catch floating pt except */
141: }
142:
143:
144: #if !defined(MSDOS) && !defined(__OS2__)
145: void onwinch (void)
146: {
147: struct winsize ws;
148:
149: /* restore handler */
150: sig_attach (SIGWINCH, &onwinch);
151:
152: ioctl (STDIN_FILENO, TIOCGWINSZ, &ws);
153:
154: n_lines = ws.ws_row;
155: n_columns = ws.ws_col;
156:
157: if (evt_async_enabled) {
158: pending_signal_type = SIGWINCH;
159: merr_raise (ASYNC);
160: }
161:
162: return;
163: }
164: #else
165: void onwinch (void)
166: {
167: sig_attach (SIGWINCH, &onwinch);
168:
169: return;
170: }
171: #endif
172:
173: void onintr (void)
174: {
175: sig_attach (SIGINT, &onintr); /* restore handler */
176:
177: /* printf ("\r\nSIGINT codptr = '%s'\r\n", codptr); */
178:
179: if (first_process) {
180: job_request_stop (pid);
181: }
182: else {
183: if (shm_config->hdr->maintenance_mode == 1) {
184:
185: job_slot_t *s = job_get (pid);
186:
187:
188: if ((s->flags & JFLG_FMADM) != JFLG_FMADM) {
189:
190: fprintf (stderr, "\r\n***ENVIRONMENT IN MAINTENANCE MODE***\r\n");
191:
192: while (shm_config->hdr->maintenance_mode == 1) {
193: sleep (1);
194: }
195:
196: return;
197:
198: }
199:
200: }
201: }
202:
203: if (breakon) {
204: merr_raise (INRPT);
205: inrpt_after_async = TRUE;
206: if (forsw) sigint_in_for = TRUE;
207:
208: if (usermode == 1) {
209: debug_mode = TRUE;
210: }
211: }
212: else {
213: zcc = TRUE;
214: }
215:
216: if (evt_async_enabled) {
217: pending_signal_type = SIGINT;
218: }
219:
220: return;
221: } /* end of onintr */
222:
223: void onfpe (void)
224: {
225: sig_attach (SIGFPE, &onfpe); /* restore handler */
226:
227: if (evt_async_enabled) {
228: pending_signal_type = SIGFPE;
229: }
230:
231: merr_raise (MXNUM);
232: return;
233: } /* end of onfpe */
234:
235: void onquit (void)
236: {
237:
238: if (run_daemon == TRUE) {
239: job_request_stop (pid);
240: }
241:
242: sig_attach (SIGQUIT, &onquit); /* restore handler */
243:
244: if (zbreakon && (merr () == OK)) ierr = OK - CTRLB;
245:
246: if (evt_async_enabled) {
247: pending_signal_type = SIGQUIT;
248: }
249:
250: return;
251: } /* end of onquit */
252:
253: void onkill (void)
254: {
255: int n = 0;
256:
257: if (run_daemon == TRUE) {
258: job_request_stop (pid);
259: }
260:
261: #if !defined(AMIGA68K)
262: if (direct_mode == TRUE) {
263: set_io (UNIX);
264: fprintf (stderr, "\n\nFreeM process %d caught SIGTERM\n", pid);
265: set_io (MUMPS);
266: }
267: #endif
268:
269:
270: sig_attach (SIGTERM, &onkill); /* restore handler */
271:
272: if (killerflag == FALSE) return; /* ignore that signal */
273:
274: /* if there exists an error trap, process as an error */
275: /* otherwise terminate the job */
276:
277: if (DSM2err) { /* DSM V.2 error trapping */
278:
279:
280:
281: if (ztrap[NESTLEVLS + 1][0] != EOL) {
282: merr_raise (KILLER);
283: return;
284: }
285:
286:
287: }
288: else {
289:
290:
291: while (n >= 0) {
292: if (ztrap[n--][0] != EOL) {
293: merr_raise (KILLER);
294: return;
295: }
296: }
297:
298:
299: }
300:
301: cleanup ();
302: if (father) kill (father, SIGUSR1); /* advertise death to parent */
303:
304: exit (1); /* terminate mumps */
305: } /* end of onkill() */
306:
307: void onhup (void)
308: {
309:
310: int n = nstx;
311:
312:
313: if (run_daemon == TRUE) {
314: logprintf (FM_LOG_INFO, "environment: daemon received SIGHUP");
315:
316: sig_attach (SIGHUP, &onhup); /* restore handler */
317:
318: return;
319: }
320:
321: sig_attach (SIGHUP, &onhup); /* restore handler */
322:
323: if (huperflag == FALSE) return; /* ignore that signal */
324:
325: /* if there exists an error trap, process as an error */
326: /* otherwise terminate the job */
327:
328: if (DSM2err) { /* DSM V.2 error trapping */
329:
330: if (ztrap[NESTLEVLS + 1][0] != EOL) {
331: merr_raise (HUPER);
332: return;
333: }
334:
335:
336: }
337: else {
338:
339: while (n >= 0) {
340: if (ztrap[n--][0] != EOL) {
341: merr_raise (HUPER);
342: return;
343: }
344: }
345:
346: }
347:
348: cleanup ();
349:
350: if (father) kill (father, SIGUSR1); /* advertise death to parent */
351:
352: exit (1); /* terminate mumps */
353:
354: } /* end of onhup() */
355:
356: void onbus (void)
357: {
358: cleanup ();
359:
360: printf ("\012\015BUS ERROR, SEGMENTATION VIOLATION\012\015");
361:
362: if (father) kill (father, SIGUSR1); /* advertise death to parent */
363:
364: exit (1); /* terminate mumps */
365: } /* end of onbus() */
366:
367: /* under XENIX processes started with JOB hang around as zombies */
368: /* if they HALT before the parent process, unless the parent process */
369: /* waits for his child to terminate. to solve the problem, the child */
370: /* sends a signal to his parent to avoid an unattended funeral which */
371: /* inevitably would result in a living dead sucking up cpu time */
372: void oncld (void)
373: {
374: int status;
375:
376: /* ignore signal while as we're here */
377: sig_attach (SIGUSR1, SIG_IGN);
378:
379: wait (&status); /* wait for report from child */
380:
381: sig_attach (SIGUSR1, &oncld);/* restore handler */
382:
383: return;
384: } /* end of oncld() */
385:
386: void onipc (void)
387: {
388: /* restore handler */
389: sig_attach (SIGUSR2, &onipc);
390:
391: ipc_pending = 1;
392:
393: return;
394: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>