Initial import from FreeBSD RELENG_4:
[games.git] / sys / emulation / ibcs2 / i386 / ibcs2_signal.c
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  * $FreeBSD: src/sys/i386/ibcs2/ibcs2_signal.c,v 1.16 1999/10/10 09:14:31 marcel Exp $
29  */
30
31 #include <sys/param.h>
32 #include <sys/systm.h>
33 #include <sys/signalvar.h>
34 #include <sys/sysproto.h>
35
36 #include <i386/ibcs2/ibcs2_types.h>
37 #include <i386/ibcs2/ibcs2_signal.h>
38 #include <i386/ibcs2/ibcs2_proto.h>
39 #include <i386/ibcs2/ibcs2_xenix.h>
40 #include <i386/ibcs2/ibcs2_util.h>
41
42 #define sigemptyset(s)          SIGEMPTYSET(*(s))
43 #define sigismember(s, n)       SIGISMEMBER(*(s), n)
44 #define sigaddset(s, n)         SIGADDSET(*(s), n)
45
46 #define ibcs2_sigmask(n)        (1 << ((n) - 1))
47 #define ibcs2_sigemptyset(s)    bzero((s), sizeof(*(s)))
48 #define ibcs2_sigismember(s, n) (*(s) & ibcs2_sigmask(n))
49 #define ibcs2_sigaddset(s, n)   (*(s) |= ibcs2_sigmask(n))
50
51 static void ibcs2_to_bsd_sigset    __P((const ibcs2_sigset_t *, sigset_t *));
52 static void bsd_to_ibcs2_sigset    __P((const sigset_t *, ibcs2_sigset_t *));
53 static void ibcs2_to_bsd_sigaction __P((struct ibcs2_sigaction *,
54                                         struct sigaction *));
55 static void bsd_to_ibcs2_sigaction __P((struct sigaction *,
56                                         struct ibcs2_sigaction *));
57
58 int bsd_to_ibcs2_sig[IBCS2_SIGTBLSZ] = {
59         IBCS2_SIGHUP,           /* 1 */
60         IBCS2_SIGINT,           /* 2 */
61         IBCS2_SIGQUIT,          /* 3 */
62         IBCS2_SIGILL,           /* 4 */
63         IBCS2_SIGTRAP,          /* 5 */
64         IBCS2_SIGABRT,          /* 6 */
65         IBCS2_SIGEMT,           /* 7 */
66         IBCS2_SIGFPE,           /* 8 */
67         IBCS2_SIGKILL,          /* 9 */
68         IBCS2_SIGBUS,           /* 10 */
69         IBCS2_SIGSEGV,          /* 11 */
70         IBCS2_SIGSYS,           /* 12 */
71         IBCS2_SIGPIPE,          /* 13 */
72         IBCS2_SIGALRM,          /* 14 */
73         IBCS2_SIGTERM,          /* 15 */
74         0,                      /* 16 - SIGURG */
75         IBCS2_SIGSTOP,          /* 17 */
76         IBCS2_SIGTSTP,          /* 18 */
77         IBCS2_SIGCONT,          /* 19 */
78         IBCS2_SIGCLD,           /* 20 */
79         IBCS2_SIGTTIN,          /* 21 */
80         IBCS2_SIGTTOU,          /* 22 */
81         IBCS2_SIGPOLL,          /* 23 */
82         0,                      /* 24 - SIGXCPU */
83         0,                      /* 25 - SIGXFSZ */
84         IBCS2_SIGVTALRM,        /* 26 */
85         IBCS2_SIGPROF,          /* 27 */
86         IBCS2_SIGWINCH,         /* 28 */
87         0,                      /* 29 */
88         IBCS2_SIGUSR1,          /* 30 */
89         IBCS2_SIGUSR2,          /* 31 */
90         0                       /* 32 */
91 };
92
93 static int ibcs2_to_bsd_sig[IBCS2_SIGTBLSZ] = {
94         SIGHUP,                 /* 1 */
95         SIGINT,                 /* 2 */
96         SIGQUIT,                /* 3 */
97         SIGILL,                 /* 4 */
98         SIGTRAP,                /* 5 */
99         SIGABRT,                /* 6 */
100         SIGEMT,                 /* 7 */
101         SIGFPE,                 /* 8 */
102         SIGKILL,                /* 9 */
103         SIGBUS,                 /* 10 */
104         SIGSEGV,                /* 11 */
105         SIGSYS,                 /* 12 */
106         SIGPIPE,                /* 13 */
107         SIGALRM,                /* 14 */
108         SIGTERM,                /* 15 */
109         SIGUSR1,                /* 16 */
110         SIGUSR2,                /* 17 */
111         SIGCHLD,                /* 18 */
112         0,                      /* 19 - SIGPWR */
113         SIGWINCH,               /* 20 */
114         0,                      /* 21 */
115         SIGIO,                  /* 22 */
116         SIGSTOP,                /* 23 */
117         SIGTSTP,                /* 24 */
118         SIGCONT,                /* 25 */
119         SIGTTIN,                /* 26 */
120         SIGTTOU,                /* 27 */
121         SIGVTALRM,              /* 28 */
122         SIGPROF,                /* 29 */
123         0,                      /* 30 */
124         0,                      /* 31 */
125         0                       /* 32 */
126 };
127
128 void
129 ibcs2_to_bsd_sigset(iss, bss)
130         const ibcs2_sigset_t *iss;
131         sigset_t *bss;
132 {
133         int i, newsig;
134
135         sigemptyset(bss);
136         for (i = 1; i <= IBCS2_SIGTBLSZ; i++) {
137                 if (ibcs2_sigismember(iss, i)) {
138                         newsig = ibcs2_to_bsd_sig[_SIG_IDX(i)];
139                         if (newsig)
140                                 sigaddset(bss, newsig);
141                 }
142         }
143 }
144
145 static void
146 bsd_to_ibcs2_sigset(bss, iss)
147         const sigset_t *bss;
148         ibcs2_sigset_t *iss;
149 {
150         int i, newsig;
151
152         ibcs2_sigemptyset(iss);
153         for (i = 1; i <= IBCS2_SIGTBLSZ; i++) {
154                 if (sigismember(bss, i)) {
155                         newsig = bsd_to_ibcs2_sig[_SIG_IDX(i)];
156                         if (newsig)
157                                 ibcs2_sigaddset(iss, newsig);
158                 }
159         }
160 }
161
162 static void
163 ibcs2_to_bsd_sigaction(isa, bsa)
164         struct ibcs2_sigaction *isa;
165         struct sigaction *bsa;
166 {
167
168         bsa->sa_handler = isa->isa_handler;
169         ibcs2_to_bsd_sigset(&isa->isa_mask, &bsa->sa_mask);
170         bsa->sa_flags = 0;      /* ??? SA_NODEFER */
171         if ((isa->isa_flags & IBCS2_SA_NOCLDSTOP) != 0)
172                 bsa->sa_flags |= SA_NOCLDSTOP;
173 }
174
175 static void
176 bsd_to_ibcs2_sigaction(bsa, isa)
177         struct sigaction *bsa;
178         struct ibcs2_sigaction *isa;
179 {
180
181         isa->isa_handler = bsa->sa_handler;
182         bsd_to_ibcs2_sigset(&bsa->sa_mask, &isa->isa_mask);
183         isa->isa_flags = 0;
184         if ((bsa->sa_flags & SA_NOCLDSTOP) != 0)
185                 isa->isa_flags |= IBCS2_SA_NOCLDSTOP;
186 }
187
188 int
189 ibcs2_sigaction(p, uap)
190         register struct proc *p;
191         struct ibcs2_sigaction_args *uap;
192 {
193         struct ibcs2_sigaction *nisa, *oisa, tmpisa;
194         struct sigaction *nbsa, *obsa, tmpbsa;
195         struct sigaction_args sa;
196         caddr_t sg;
197         int error;
198
199         sg = stackgap_init();
200         nisa = SCARG(uap, act);
201         oisa = SCARG(uap, oact);
202
203         if (oisa != NULL)
204                 obsa = stackgap_alloc(&sg, sizeof(struct sigaction));
205         else
206                 obsa = NULL;
207
208         if (nisa != NULL) {
209                 nbsa = stackgap_alloc(&sg, sizeof(struct sigaction));
210                 if ((error = copyin(nisa, &tmpisa, sizeof(tmpisa))) != 0)
211                         return error;
212                 ibcs2_to_bsd_sigaction(&tmpisa, &tmpbsa);
213                 if ((error = copyout(&tmpbsa, nbsa, sizeof(tmpbsa))) != 0)
214                         return error;
215         } else
216                 nbsa = NULL;
217
218         SCARG(&sa, sig) = ibcs2_to_bsd_sig[_SIG_IDX(SCARG(uap, sig))];
219         SCARG(&sa, act) = nbsa;
220         SCARG(&sa, oact) = obsa;
221
222         if ((error = sigaction(p, &sa)) != 0)
223                 return error;
224
225         if (oisa != NULL) {
226                 if ((error = copyin(obsa, &tmpbsa, sizeof(tmpbsa))) != 0)
227                         return error;
228                 bsd_to_ibcs2_sigaction(&tmpbsa, &tmpisa);
229                 if ((error = copyout(&tmpisa, oisa, sizeof(tmpisa))) != 0)
230                         return error;
231         }
232
233         return 0;
234 }
235
236 int
237 ibcs2_sigsys(p, uap)
238         register struct proc *p;
239         struct ibcs2_sigsys_args *uap;
240 {
241         struct sigaction sa;
242         int signum = ibcs2_to_bsd_sig[_SIG_IDX(IBCS2_SIGNO(SCARG(uap, sig)))];
243         int error;
244         caddr_t sg = stackgap_init();
245
246         if (signum <= 0 || signum >= IBCS2_NSIG) {
247                 if (IBCS2_SIGCALL(SCARG(uap, sig)) == IBCS2_SIGNAL_MASK ||
248                     IBCS2_SIGCALL(SCARG(uap, sig)) == IBCS2_SIGSET_MASK)
249                         p->p_retval[0] = (int)IBCS2_SIG_ERR;
250                 return EINVAL;
251         }
252         
253         switch (IBCS2_SIGCALL(SCARG(uap, sig))) {
254         case IBCS2_SIGSET_MASK:
255                 /*
256                  * Check for SIG_HOLD action.
257                  * Otherwise, perform signal() except with different sa_flags.
258                  */
259                 if (SCARG(uap, fp) != IBCS2_SIG_HOLD) {
260                         /* add sig to mask before exececuting signal handler */
261                         sa.sa_flags = 0;
262                         goto ibcs2_sigset;
263                 }
264                 /* else fallthrough to sighold */
265
266         case IBCS2_SIGHOLD_MASK:
267                 {
268                         sigset_t mask;
269                         struct sigprocmask_args sa;
270
271                         SIGEMPTYSET(mask);
272                         SIGADDSET(mask, signum);
273                         SCARG(&sa, how) = SIG_BLOCK;
274                         SCARG(&sa, set) = &mask;
275                         SCARG(&sa, oset) = NULL;
276                         return sigprocmask(p, &sa);
277                 }
278                 
279         case IBCS2_SIGNAL_MASK:
280                 {
281                         struct sigaction_args sa_args;
282                         struct sigaction *nbsa, *obsa;
283
284                         /* do not automatically block signal */
285                         sa.sa_flags = SA_NODEFER;
286 #ifdef SA_RESETHAND
287                         if((signum != IBCS2_SIGILL) &&
288                            (signum != IBCS2_SIGTRAP) &&
289                            (signum != IBCS2_SIGPWR))
290                                 /* set to SIG_DFL before executing handler */
291                                 sa.sa_flags |= SA_RESETHAND;
292 #endif
293                 ibcs2_sigset:
294                         nbsa = stackgap_alloc(&sg, sizeof(struct sigaction));
295                         obsa = stackgap_alloc(&sg, sizeof(struct sigaction));
296                         SCARG(&sa_args, sig) = signum;
297                         SCARG(&sa_args, act) = nbsa;
298                         SCARG(&sa_args, oact) = obsa;
299
300                         sa.sa_handler = SCARG(uap, fp);
301                         sigemptyset(&sa.sa_mask);
302 #if 0
303                         if (signum != SIGALRM)
304                                 sa.sa_flags |= SA_RESTART;
305 #endif
306                         p->p_retval[0] = (int)IBCS2_SIG_ERR; /* init error return */
307
308                         /* perform native sigaction() */
309                         if ((error = copyout(&sa, nbsa, sizeof(sa))) != 0)
310                                 return error;
311                         if ((error = sigaction(p, &sa_args)) != 0) {
312                                 DPRINTF(("signal: sigaction failed: %d\n",
313                                          error));
314                                 return error;
315                         }
316                         if ((error = copyin(obsa, &sa, sizeof(sa))) != 0)
317                                 return error;
318                         p->p_retval[0] = (int)sa.sa_handler;
319
320                         /* special sigset() check */
321                         if(IBCS2_SIGCALL(SCARG(uap, sig)) == IBCS2_SIGSET_MASK)
322                                 /* check to make sure signal is not blocked */
323                                 if(sigismember(&p->p_sigmask, signum)) {
324                                         /* return SIG_HOLD and unblock signal*/
325                                         p->p_retval[0] = (int)IBCS2_SIG_HOLD;
326                                         SIGDELSET(p->p_sigmask, signum);
327                                 }
328                                 
329                         return 0;
330                 }
331                 
332         case IBCS2_SIGRELSE_MASK:
333                 {
334                         sigset_t mask;
335                         struct sigprocmask_args sa;
336
337                         SIGEMPTYSET(mask);
338                         SIGADDSET(mask, signum);
339                         SCARG(&sa, how) = SIG_UNBLOCK;
340                         SCARG(&sa, set) = &mask;
341                         SCARG(&sa, oset) = NULL;
342                         return sigprocmask(p, &sa);
343                 }
344                 
345         case IBCS2_SIGIGNORE_MASK:
346                 {
347                         struct sigaction_args sa_args;
348                         struct sigaction *bsa;
349
350                         bsa = stackgap_alloc(&sg, sizeof(struct sigaction));
351                         SCARG(&sa_args, sig) = signum;
352                         SCARG(&sa_args, act) = bsa;
353                         SCARG(&sa_args, oact) = NULL;
354
355                         sa.sa_handler = SIG_IGN;
356                         sigemptyset(&sa.sa_mask);
357                         sa.sa_flags = 0;
358                         if ((error = copyout(&sa, bsa, sizeof(sa))) != 0)
359                                 return error;
360                         if ((error = sigaction(p, &sa_args)) != 0) {
361                                 DPRINTF(("sigignore: sigaction failed\n"));
362                                 return error;
363                         }
364                         return 0;
365                 }
366                 
367         case IBCS2_SIGPAUSE_MASK:
368                 {
369                         sigset_t mask;
370                         struct sigsuspend_args sa;
371
372                         mask = p->p_sigmask;
373                         SIGDELSET(mask, signum);
374                         SCARG(&sa, sigmask) = &mask;
375                         return sigsuspend(p, &sa);
376                 }
377                 
378         default:
379                 return ENOSYS;
380         }
381 }
382
383 int
384 ibcs2_sigprocmask(p, uap)
385         register struct proc *p;
386         struct ibcs2_sigprocmask_args *uap;
387 {
388         ibcs2_sigset_t iss;
389         sigset_t bss;
390         int error = 0;
391
392         if (SCARG(uap, oset) != NULL) {
393                 /* Fix the return value first if needed */
394                 bsd_to_ibcs2_sigset(&p->p_sigmask, &iss);
395                 if ((error = copyout(&iss, SCARG(uap, oset), sizeof(iss))) != 0)
396                         return error;
397         }
398                 
399         if (SCARG(uap, set) == NULL)
400                 /* Just examine */
401                 return 0;
402
403         if ((error = copyin(SCARG(uap, set), &iss, sizeof(iss))) != 0)
404                 return error;
405
406         ibcs2_to_bsd_sigset(&iss, &bss);
407
408         (void) splhigh();
409
410         switch (SCARG(uap, how)) {
411         case IBCS2_SIG_BLOCK:
412                 SIGSETOR(p->p_sigmask, bss);
413                 SIG_CANTMASK(p->p_sigmask);
414                 break;
415
416         case IBCS2_SIG_UNBLOCK:
417                 SIGSETNAND(p->p_sigmask, bss);
418                 break;
419
420         case IBCS2_SIG_SETMASK:
421                 p->p_sigmask = bss;
422                 SIG_CANTMASK(p->p_sigmask);
423                 break;
424
425         default:
426                 error = EINVAL;
427                 break;
428         }
429
430         (void) spl0();
431
432         return error;
433 }
434
435 int
436 ibcs2_sigpending(p, uap)
437         register struct proc *p;
438         struct ibcs2_sigpending_args *uap;
439 {
440         sigset_t bss;
441         ibcs2_sigset_t iss;
442
443         bss = p->p_siglist;
444         SIGSETAND(bss, p->p_sigmask);
445         bsd_to_ibcs2_sigset(&bss, &iss);
446
447         return copyout(&iss, SCARG(uap, mask), sizeof(iss));
448 }
449
450 int
451 ibcs2_sigsuspend(p, uap)
452         register struct proc *p;
453         struct ibcs2_sigsuspend_args *uap;
454 {
455         ibcs2_sigset_t sss;
456         sigset_t bss;
457         struct sigsuspend_args sa;
458         int error;
459
460         if ((error = copyin(SCARG(uap, mask), &sss, sizeof(sss))) != 0)
461                 return error;
462
463         ibcs2_to_bsd_sigset(&sss, &bss);
464         SCARG(&sa, sigmask) = &bss;
465         return sigsuspend(p, &sa);
466 }
467
468 int
469 ibcs2_pause(p, uap)
470         register struct proc *p;
471         struct ibcs2_pause_args *uap;
472 {
473         sigset_t mask;
474         struct sigsuspend_args sa;
475
476         mask = p->p_sigmask;
477         SCARG(&sa, sigmask) = &mask;
478         return sigsuspend(p, &sa);
479 }
480
481 int
482 ibcs2_kill(p, uap)
483         register struct proc *p;
484         struct ibcs2_kill_args *uap;
485 {
486         struct kill_args ka;
487
488         SCARG(&ka, pid) = SCARG(uap, pid);
489         SCARG(&ka, signum) = ibcs2_to_bsd_sig[_SIG_IDX(SCARG(uap, signo))];
490         return kill(p, &ka);
491 }