1/*-
2 * Copyright (c) 1995 Scott Bartram
3 * Copyright (c) 1995 Steven Wallace
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 * 3. The name of the author may not be used to endorse or promote products
15 *    derived from this software without specific prior written permission
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#include <sys/cdefs.h>
30__FBSDID("$FreeBSD$");
31
32#include <sys/param.h>
33#include <sys/systm.h>
34#include <sys/lock.h>
35#include <sys/mutex.h>
36#include <sys/signalvar.h>
37#include <sys/syscallsubr.h>
38#include <sys/sysproto.h>
39
40#include <i386/ibcs2/ibcs2_types.h>
41#include <i386/ibcs2/ibcs2_signal.h>
42#include <i386/ibcs2/ibcs2_proto.h>
43#include <i386/ibcs2/ibcs2_xenix.h>
44#include <i386/ibcs2/ibcs2_util.h>
45
46#define sigemptyset(s)		SIGEMPTYSET(*(s))
47#define sigismember(s, n)	SIGISMEMBER(*(s), n)
48#define sigaddset(s, n)		SIGADDSET(*(s), n)
49
50#define	ibcs2_sigmask(n)	(1 << ((n) - 1))
51#define ibcs2_sigemptyset(s)	bzero((s), sizeof(*(s)))
52#define ibcs2_sigismember(s, n)	(*(s) & ibcs2_sigmask(n))
53#define ibcs2_sigaddset(s, n)	(*(s) |= ibcs2_sigmask(n))
54
55static void ibcs2_to_bsd_sigset(const ibcs2_sigset_t *, sigset_t *);
56static void bsd_to_ibcs2_sigset(const sigset_t *, ibcs2_sigset_t *);
57static void ibcs2_to_bsd_sigaction(struct ibcs2_sigaction *,
58					struct sigaction *);
59static void bsd_to_ibcs2_sigaction(struct sigaction *,
60					struct ibcs2_sigaction *);
61
62int bsd_to_ibcs2_sig[IBCS2_SIGTBLSZ] = {
63	IBCS2_SIGHUP,		/* 1 */
64	IBCS2_SIGINT,		/* 2 */
65	IBCS2_SIGQUIT,		/* 3 */
66	IBCS2_SIGILL,		/* 4 */
67	IBCS2_SIGTRAP,		/* 5 */
68	IBCS2_SIGABRT,		/* 6 */
69	IBCS2_SIGEMT,		/* 7 */
70	IBCS2_SIGFPE,		/* 8 */
71	IBCS2_SIGKILL,		/* 9 */
72	IBCS2_SIGBUS,		/* 10 */
73	IBCS2_SIGSEGV,		/* 11 */
74	IBCS2_SIGSYS,		/* 12 */
75	IBCS2_SIGPIPE,		/* 13 */
76	IBCS2_SIGALRM,		/* 14 */
77	IBCS2_SIGTERM,		/* 15 */
78	0,			/* 16 - SIGURG */
79	IBCS2_SIGSTOP,		/* 17 */
80	IBCS2_SIGTSTP,		/* 18 */
81	IBCS2_SIGCONT,		/* 19 */
82	IBCS2_SIGCLD,		/* 20 */
83	IBCS2_SIGTTIN,		/* 21 */
84	IBCS2_SIGTTOU,		/* 22 */
85	IBCS2_SIGPOLL,		/* 23 */
86	0,			/* 24 - SIGXCPU */
87	0,			/* 25 - SIGXFSZ */
88	IBCS2_SIGVTALRM,	/* 26 */
89	IBCS2_SIGPROF,		/* 27 */
90	IBCS2_SIGWINCH,		/* 28 */
91	0,			/* 29 */
92	IBCS2_SIGUSR1,		/* 30 */
93	IBCS2_SIGUSR2,		/* 31 */
94	0			/* 32 */
95};
96
97static int ibcs2_to_bsd_sig[IBCS2_SIGTBLSZ] = {
98	SIGHUP,			/* 1 */
99	SIGINT,			/* 2 */
100	SIGQUIT,		/* 3 */
101	SIGILL,			/* 4 */
102	SIGTRAP,		/* 5 */
103	SIGABRT,		/* 6 */
104	SIGEMT,			/* 7 */
105	SIGFPE,			/* 8 */
106	SIGKILL,		/* 9 */
107	SIGBUS,			/* 10 */
108	SIGSEGV,		/* 11 */
109	SIGSYS,			/* 12 */
110	SIGPIPE,		/* 13 */
111	SIGALRM,		/* 14 */
112	SIGTERM,		/* 15 */
113	SIGUSR1,		/* 16 */
114	SIGUSR2,		/* 17 */
115	SIGCHLD,		/* 18 */
116	0,			/* 19 - SIGPWR */
117	SIGWINCH,		/* 20 */
118	0,			/* 21 */
119	SIGIO,			/* 22 */
120	SIGSTOP,		/* 23 */
121	SIGTSTP,		/* 24 */
122	SIGCONT,		/* 25 */
123	SIGTTIN,		/* 26 */
124	SIGTTOU,		/* 27 */
125	SIGVTALRM,		/* 28 */
126	SIGPROF,		/* 29 */
127	0,			/* 30 */
128	0,			/* 31 */
129	0			/* 32 */
130};
131
132void
133ibcs2_to_bsd_sigset(iss, bss)
134	const ibcs2_sigset_t *iss;
135	sigset_t *bss;
136{
137	int i, newsig;
138
139	sigemptyset(bss);
140	for (i = 1; i <= IBCS2_SIGTBLSZ; i++) {
141		if (ibcs2_sigismember(iss, i)) {
142			newsig = ibcs2_to_bsd_sig[_SIG_IDX(i)];
143			if (newsig)
144				sigaddset(bss, newsig);
145		}
146	}
147}
148
149static void
150bsd_to_ibcs2_sigset(bss, iss)
151	const sigset_t *bss;
152	ibcs2_sigset_t *iss;
153{
154	int i, newsig;
155
156	ibcs2_sigemptyset(iss);
157	for (i = 1; i <= IBCS2_SIGTBLSZ; i++) {
158		if (sigismember(bss, i)) {
159			newsig = bsd_to_ibcs2_sig[_SIG_IDX(i)];
160			if (newsig)
161				ibcs2_sigaddset(iss, newsig);
162		}
163	}
164}
165
166static void
167ibcs2_to_bsd_sigaction(isa, bsa)
168	struct ibcs2_sigaction *isa;
169	struct sigaction *bsa;
170{
171
172	bsa->sa_handler = isa->isa_handler;
173	ibcs2_to_bsd_sigset(&isa->isa_mask, &bsa->sa_mask);
174	bsa->sa_flags = 0;	/* ??? SA_NODEFER */
175	if ((isa->isa_flags & IBCS2_SA_NOCLDSTOP) != 0)
176		bsa->sa_flags |= SA_NOCLDSTOP;
177}
178
179static void
180bsd_to_ibcs2_sigaction(bsa, isa)
181	struct sigaction *bsa;
182	struct ibcs2_sigaction *isa;
183{
184
185	isa->isa_handler = bsa->sa_handler;
186	bsd_to_ibcs2_sigset(&bsa->sa_mask, &isa->isa_mask);
187	isa->isa_flags = 0;
188	if ((bsa->sa_flags & SA_NOCLDSTOP) != 0)
189		isa->isa_flags |= IBCS2_SA_NOCLDSTOP;
190}
191
192int
193ibcs2_sigaction(td, uap)
194	register struct thread *td;
195	struct ibcs2_sigaction_args *uap;
196{
197	struct ibcs2_sigaction isa;
198	struct sigaction nbsa, obsa;
199	struct sigaction *nbsap;
200 	int error;
201
202	if (uap->act != NULL) {
203		if ((error = copyin(uap->act, &isa, sizeof(isa))) != 0)
204			return (error);
205		ibcs2_to_bsd_sigaction(&isa, &nbsa);
206		nbsap = &nbsa;
207	} else
208		nbsap = NULL;
209	if (uap->sig <= 0 || uap->sig > IBCS2_NSIG)
210		return (EINVAL);
211	error = kern_sigaction(td, ibcs2_to_bsd_sig[_SIG_IDX(uap->sig)], &nbsa,
212	    &obsa, 0);
213	if (error == 0 && uap->oact != NULL) {
214		bsd_to_ibcs2_sigaction(&obsa, &isa);
215		error = copyout(&isa, uap->oact, sizeof(isa));
216	}
217	return (error);
218}
219
220int
221ibcs2_sigsys(td, uap)
222	register struct thread *td;
223	struct ibcs2_sigsys_args *uap;
224{
225	struct proc *p = td->td_proc;
226	struct sigaction sa;
227	int signum = IBCS2_SIGNO(uap->sig);
228	int error;
229
230	if (signum <= 0 || signum > IBCS2_NSIG) {
231		if (IBCS2_SIGCALL(uap->sig) == IBCS2_SIGNAL_MASK ||
232		    IBCS2_SIGCALL(uap->sig) == IBCS2_SIGSET_MASK)
233			td->td_retval[0] = (int)IBCS2_SIG_ERR;
234		return EINVAL;
235	}
236	signum = ibcs2_to_bsd_sig[_SIG_IDX(signum)];
237
238	switch (IBCS2_SIGCALL(uap->sig)) {
239	case IBCS2_SIGSET_MASK:
240		/*
241		 * Check for SIG_HOLD action.
242		 * Otherwise, perform signal() except with different sa_flags.
243		 */
244		if (uap->fp != IBCS2_SIG_HOLD) {
245			/* add sig to mask before exececuting signal handler */
246			sa.sa_flags = 0;
247			goto ibcs2_sigset;
248		}
249		/* else FALLTHROUGH to sighold */
250
251	case IBCS2_SIGHOLD_MASK:
252		{
253			sigset_t mask;
254
255			SIGEMPTYSET(mask);
256			SIGADDSET(mask, signum);
257			return (kern_sigprocmask(td, SIG_BLOCK, &mask, NULL,
258				    0));
259		}
260
261	case IBCS2_SIGNAL_MASK:
262		{
263			struct sigaction osa;
264
265			/* do not automatically block signal */
266			sa.sa_flags = SA_NODEFER;
267#ifdef SA_RESETHAND
268			if((signum != IBCS2_SIGILL) &&
269			   (signum != IBCS2_SIGTRAP) &&
270			   (signum != IBCS2_SIGPWR))
271				/* set to SIG_DFL before executing handler */
272				sa.sa_flags |= SA_RESETHAND;
273#endif
274		ibcs2_sigset:
275			sa.sa_handler = uap->fp;
276			sigemptyset(&sa.sa_mask);
277#if 0
278			if (signum != SIGALRM)
279				sa.sa_flags |= SA_RESTART;
280#endif
281			error = kern_sigaction(td, signum, &sa, &osa, 0);
282			if (error != 0) {
283				DPRINTF(("signal: sigaction failed: %d\n",
284					 error));
285				td->td_retval[0] = (int)IBCS2_SIG_ERR;
286				return (error);
287			}
288			td->td_retval[0] = (int)osa.sa_handler;
289
290			/* special sigset() check */
291                        if(IBCS2_SIGCALL(uap->sig) == IBCS2_SIGSET_MASK) {
292				PROC_LOCK(p);
293			        /* check to make sure signal is not blocked */
294                                if(sigismember(&td->td_sigmask, signum)) {
295				        /* return SIG_HOLD and unblock signal*/
296                                        td->td_retval[0] = (int)IBCS2_SIG_HOLD;
297					SIGDELSET(td->td_sigmask, signum);
298					signotify(td);
299				}
300				PROC_UNLOCK(p);
301			}
302
303			return 0;
304		}
305
306	case IBCS2_SIGRELSE_MASK:
307		{
308			sigset_t mask;
309
310			SIGEMPTYSET(mask);
311			SIGADDSET(mask, signum);
312			return (kern_sigprocmask(td, SIG_UNBLOCK, &mask, NULL,
313				    0));
314		}
315
316	case IBCS2_SIGIGNORE_MASK:
317		{
318			sa.sa_handler = SIG_IGN;
319			sigemptyset(&sa.sa_mask);
320			sa.sa_flags = 0;
321			error = kern_sigaction(td, signum, &sa, NULL, 0);
322			if (error != 0)
323				DPRINTF(("sigignore: sigaction failed\n"));
324			return (error);
325		}
326
327	case IBCS2_SIGPAUSE_MASK:
328		{
329			sigset_t mask;
330
331			PROC_LOCK(p);
332			mask = td->td_sigmask;
333			PROC_UNLOCK(p);
334			SIGDELSET(mask, signum);
335			return kern_sigsuspend(td, mask);
336		}
337
338	default:
339		return ENOSYS;
340	}
341}
342
343int
344ibcs2_sigprocmask(td, uap)
345	register struct thread *td;
346	struct ibcs2_sigprocmask_args *uap;
347{
348	ibcs2_sigset_t iss;
349	sigset_t oss, nss;
350	sigset_t *nssp;
351	int error, how;
352
353	switch (uap->how) {
354	case IBCS2_SIG_BLOCK:
355		how = SIG_BLOCK;
356		break;
357	case IBCS2_SIG_UNBLOCK:
358		how = SIG_UNBLOCK;
359		break;
360	case IBCS2_SIG_SETMASK:
361		how = SIG_SETMASK;
362		break;
363	default:
364		return (EINVAL);
365	}
366	if (uap->set != NULL) {
367		if ((error = copyin(uap->set, &iss, sizeof(iss))) != 0)
368			return error;
369		ibcs2_to_bsd_sigset(&iss, &nss);
370		nssp = &nss;
371	} else
372		nssp = NULL;
373	error = kern_sigprocmask(td, how, nssp, &oss, 0);
374	if (error == 0 && uap->oset != NULL) {
375		bsd_to_ibcs2_sigset(&oss, &iss);
376		error = copyout(&iss, uap->oset, sizeof(iss));
377	}
378	return (error);
379}
380
381int
382ibcs2_sigpending(td, uap)
383	register struct thread *td;
384	struct ibcs2_sigpending_args *uap;
385{
386	struct proc *p = td->td_proc;
387	sigset_t bss;
388	ibcs2_sigset_t iss;
389
390	PROC_LOCK(p);
391	bss = td->td_siglist;
392	SIGSETOR(bss, p->p_siglist);
393	SIGSETAND(bss, td->td_sigmask);
394	PROC_UNLOCK(p);
395	bsd_to_ibcs2_sigset(&bss, &iss);
396
397	return copyout(&iss, uap->mask, sizeof(iss));
398}
399
400int
401ibcs2_sigsuspend(td, uap)
402	register struct thread *td;
403	struct ibcs2_sigsuspend_args *uap;
404{
405	ibcs2_sigset_t sss;
406	sigset_t bss;
407	int error;
408
409	if ((error = copyin(uap->mask, &sss, sizeof(sss))) != 0)
410		return error;
411
412	ibcs2_to_bsd_sigset(&sss, &bss);
413	return kern_sigsuspend(td, bss);
414}
415
416int
417ibcs2_pause(td, uap)
418	register struct thread *td;
419	struct ibcs2_pause_args *uap;
420{
421	sigset_t mask;
422
423	PROC_LOCK(td->td_proc);
424	mask = td->td_sigmask;
425	PROC_UNLOCK(td->td_proc);
426	return kern_sigsuspend(td, mask);
427}
428
429int
430ibcs2_kill(td, uap)
431	register struct thread *td;
432	struct ibcs2_kill_args *uap;
433{
434	struct kill_args ka;
435
436	if (uap->signo <= 0 || uap->signo > IBCS2_NSIG)
437		return (EINVAL);
438	ka.pid = uap->pid;
439	ka.signum = ibcs2_to_bsd_sig[_SIG_IDX(uap->signo)];
440	return sys_kill(td, &ka);
441}
442