1/*	$NetBSD: sig.c,v 1.27 2023/02/03 19:47:38 christos Exp $	*/
2
3/*-
4 * Copyright (c) 1992, 1993
5 *	The Regents of the University of California.  All rights reserved.
6 *
7 * This code is derived from software contributed to Berkeley by
8 * Christos Zoulas of Cornell University.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the University nor the names of its contributors
19 *    may be used to endorse or promote products derived from this software
20 *    without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 */
34
35#include "config.h"
36#if !defined(lint) && !defined(SCCSID)
37#if 0
38static char sccsid[] = "@(#)sig.c	8.1 (Berkeley) 6/4/93";
39#else
40__RCSID("$NetBSD: sig.c,v 1.27 2023/02/03 19:47:38 christos Exp $");
41#endif
42#endif /* not lint && not SCCSID */
43
44/*
45 * sig.c: Signal handling stuff.
46 *	  our policy is to trap all signals, set a good state
47 *	  and pass the ball to our caller.
48 */
49#include <errno.h>
50#include <stdlib.h>
51
52#include "el.h"
53#include "common.h"
54
55static EditLine *sel = NULL;
56
57static const int sighdl[] = {
58#define	_DO(a)	(a),
59	ALLSIGS
60#undef	_DO
61	- 1
62};
63
64static void sig_handler(int);
65
66/* sig_handler():
67 *	This is the handler called for all signals
68 *	XXX: we cannot pass any data so we just store the old editline
69 *	state in a private variable
70 */
71static void
72sig_handler(int signo)
73{
74	int i, save_errno;
75	sigset_t nset, oset;
76
77	save_errno = errno;
78	(void) sigemptyset(&nset);
79	(void) sigaddset(&nset, signo);
80	(void) sigprocmask(SIG_BLOCK, &nset, &oset);
81
82	sel->el_signal->sig_no = signo;
83
84	switch (signo) {
85	case SIGCONT:
86		tty_rawmode(sel);
87		if (ed_redisplay(sel, 0) == CC_REFRESH)
88			re_refresh(sel);
89		terminal__flush(sel);
90		break;
91
92	case SIGWINCH:
93		el_resize(sel);
94		break;
95
96	default:
97		tty_cookedmode(sel);
98		break;
99	}
100
101	for (i = 0; sighdl[i] != -1; i++)
102		if (signo == sighdl[i])
103			break;
104
105	(void) sigaction(signo, &sel->el_signal->sig_action[i], NULL);
106	sel->el_signal->sig_action[i].sa_handler = SIG_ERR;
107	sel->el_signal->sig_action[i].sa_flags = 0;
108	sigemptyset(&sel->el_signal->sig_action[i].sa_mask);
109	(void) sigprocmask(SIG_SETMASK, &oset, NULL);
110	(void) kill(0, signo);
111	errno = save_errno;
112}
113
114
115/* sig_init():
116 *	Initialize all signal stuff
117 */
118libedit_private int
119sig_init(EditLine *el)
120{
121	size_t i;
122	sigset_t *nset, oset;
123
124	el->el_signal = el_malloc(sizeof(*el->el_signal));
125	if (el->el_signal == NULL)
126		return -1;
127
128	nset = &el->el_signal->sig_set;
129	(void) sigemptyset(nset);
130#define	_DO(a) (void) sigaddset(nset, a);
131	ALLSIGS
132#undef	_DO
133	(void) sigprocmask(SIG_BLOCK, nset, &oset);
134
135	for (i = 0; sighdl[i] != -1; i++) {
136		el->el_signal->sig_action[i].sa_handler = SIG_ERR;
137		el->el_signal->sig_action[i].sa_flags = 0;
138		sigemptyset(&el->el_signal->sig_action[i].sa_mask);
139	}
140
141	(void) sigprocmask(SIG_SETMASK, &oset, NULL);
142
143	return 0;
144}
145
146
147/* sig_end():
148 *	Clear all signal stuff
149 */
150libedit_private void
151sig_end(EditLine *el)
152{
153
154	el_free(el->el_signal);
155	el->el_signal = NULL;
156}
157
158
159/* sig_set():
160 *	set all the signal handlers
161 */
162libedit_private void
163sig_set(EditLine *el)
164{
165	size_t i;
166	sigset_t oset;
167	struct sigaction osa, nsa;
168
169	nsa.sa_handler = sig_handler;
170	nsa.sa_flags = 0;
171	sigemptyset(&nsa.sa_mask);
172
173	sel = el;
174	(void) sigprocmask(SIG_BLOCK, &el->el_signal->sig_set, &oset);
175
176	for (i = 0; sighdl[i] != -1; i++) {
177		/* This could happen if we get interrupted */
178		if (sigaction(sighdl[i], &nsa, &osa) != -1 &&
179		    osa.sa_handler != sig_handler)
180			el->el_signal->sig_action[i] = osa;
181	}
182	(void) sigprocmask(SIG_SETMASK, &oset, NULL);
183}
184
185
186/* sig_clr():
187 *	clear all the signal handlers
188 */
189libedit_private void
190sig_clr(EditLine *el)
191{
192	size_t i;
193	sigset_t oset;
194
195	(void) sigprocmask(SIG_BLOCK, &el->el_signal->sig_set, &oset);
196
197	for (i = 0; sighdl[i] != -1; i++)
198		if (el->el_signal->sig_action[i].sa_handler != SIG_ERR)
199			(void)sigaction(sighdl[i],
200			    &el->el_signal->sig_action[i], NULL);
201
202	(void)sigprocmask(SIG_SETMASK, &oset, NULL);
203}
204