linux_sigaction.c revision 1.9
1/* $NetBSD: linux_sigaction.c,v 1.9 1995/10/07 06:27:12 mycroft Exp $ */ 2 3/* 4 * Copyright (c) 1995 Frank van der Linden 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed for the NetBSD Project 18 * by Frank van der Linden 19 * 4. The name of the author may not be used to endorse or promote products 20 * derived from this software without specific prior written permission 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 25 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 27 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 31 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 * 33 * heavily from: svr4_signal.c,v 1.7 1995/01/09 01:04:21 christos Exp 34 */ 35 36#include <sys/param.h> 37#include <sys/systm.h> 38#include <sys/namei.h> 39#include <sys/proc.h> 40#include <sys/filedesc.h> 41#include <sys/ioctl.h> 42#include <sys/mount.h> 43#include <sys/kernel.h> 44#include <sys/signal.h> 45#include <sys/signalvar.h> 46#include <sys/malloc.h> 47 48#include <sys/syscallargs.h> 49 50#include <compat/linux/linux_types.h> 51#include <compat/linux/linux_signal.h> 52#include <compat/linux/linux_syscallargs.h> 53#include <compat/linux/linux_util.h> 54 55#define sigemptyset(s) bzero((s), sizeof(*(s))) 56#define sigismember(s, n) (*(s) & sigmask(n)) 57#define sigaddset(s, n) (*(s) |= sigmask(n)) 58 59#define linux_sigmask(n) (1 << ((n) - 1)) 60#define linux_sigemptyset(s) bzero((s), sizeof(*(s))) 61#define linux_sigismember(s, n) (*(s) & linux_sigmask(n)) 62#define linux_sigaddset(s, n) (*(s) |= linux_sigmask(n)) 63 64int bsd_to_linux_sig[] = { 65 0, 66 LINUX_SIGHUP, 67 LINUX_SIGINT, 68 LINUX_SIGQUIT, 69 LINUX_SIGILL, 70 LINUX_SIGTRAP, 71 LINUX_SIGABRT, 72 0, 73 LINUX_SIGFPE, 74 LINUX_SIGKILL, 75 LINUX_SIGBUS, 76 LINUX_SIGSEGV, 77 0, 78 LINUX_SIGPIPE, 79 LINUX_SIGALRM, 80 LINUX_SIGTERM, 81 LINUX_SIGURG, 82 LINUX_SIGSTOP, 83 LINUX_SIGTSTP, 84 LINUX_SIGCONT, 85 LINUX_SIGCHLD, 86 LINUX_SIGTTIN, 87 LINUX_SIGTTOU, 88 LINUX_SIGIO, 89 LINUX_SIGXCPU, 90 LINUX_SIGXFSZ, 91 LINUX_SIGVTALRM, 92 LINUX_SIGPROF, 93 LINUX_SIGWINCH, 94 0, 95 LINUX_SIGUSR1, 96 LINUX_SIGUSR2, 97}; 98 99int linux_to_bsd_sig[] = { 100 0, 101 SIGHUP, 102 SIGINT, 103 SIGQUIT, 104 SIGILL, 105 SIGTRAP, 106 SIGABRT, 107 SIGBUS, 108 SIGFPE, 109 SIGKILL, 110 SIGUSR1, 111 SIGSEGV, 112 SIGUSR2, 113 SIGPIPE, 114 SIGALRM, 115 SIGTERM, 116 0, 117 SIGCHLD, 118 SIGCONT, 119 SIGSTOP, 120 SIGTSTP, 121 SIGTTIN, 122 SIGTTOU, 123 SIGURG, 124 SIGXCPU, 125 SIGXFSZ, 126 SIGVTALRM, 127 SIGPROF, 128 SIGWINCH, 129 SIGIO, 130 0, 131 0, 132}; 133 134/* 135 * Ok, we know that Linux and BSD signals both are just an unsigned int. 136 * Don't bother to use the sigismember() stuff for now. 137 */ 138void 139linux_to_bsd_sigset(lss, bss) 140 const linux_sigset_t *lss; 141 sigset_t *bss; 142{ 143 int i, newsig; 144 145 sigemptyset(bss); 146 for (i = 1; i < LINUX_NSIG; i++) { 147 if (linux_sigismember(lss, i)) { 148 newsig = linux_to_bsd_sig[i]; 149 if (newsig) 150 sigaddset(bss, newsig); 151 } 152 } 153} 154 155void 156bsd_to_linux_sigset(bss, lss) 157 const sigset_t *bss; 158 linux_sigset_t *lss; 159{ 160 int i, newsig; 161 162 linux_sigemptyset(lss); 163 for (i = 1; i < NSIG; i++) { 164 if (sigismember(bss, i)) { 165 newsig = bsd_to_linux_sig[i]; 166 if (newsig) 167 linux_sigaddset(lss, newsig); 168 } 169 } 170} 171 172/* 173 * Convert between Linux and BSD sigaction structures. Linux has 174 * one extra field (sa_restorer) which we don't support. 175 */ 176void 177linux_to_bsd_sigaction(lsa, bsa) 178 struct linux_sigaction *lsa; 179 struct sigaction *bsa; 180{ 181 182 bsa->sa_handler = lsa->sa_handler; 183 linux_to_bsd_sigset(&bsa->sa_mask, &lsa->sa_mask); 184 bsa->sa_flags = 0; 185 if ((lsa->sa_flags & LINUX_SA_ONSTACK) != 0) 186 bsa->sa_flags |= SA_ONSTACK; 187 if ((lsa->sa_flags & LINUX_SA_RESTART) != 0) 188 bsa->sa_flags |= SA_RESTART; 189 if ((lsa->sa_flags & LINUX_SA_ONESHOT) != 0) 190 bsa->sa_flags |= SA_RESETHAND; 191 if ((lsa->sa_flags & LINUX_SA_NOCLDSTOP) != 0) 192 bsa->sa_flags |= SA_NOCLDSTOP; 193 if ((lsa->sa_flags & LINUX_SA_NOMASK) != 0) 194 bsa->sa_flags |= SA_NODEFER; 195} 196 197void 198bsd_to_linux_sigaction(bsa, lsa) 199 struct sigaction *bsa; 200 struct linux_sigaction *lsa; 201{ 202 203 lsa->sa_handler = bsa->sa_handler; 204 bsd_to_linux_sigset(&lsa->sa_mask, &bsa->sa_mask); 205 lsa->sa_flags = 0; 206 if ((bsa->sa_flags & SA_NOCLDSTOP) != 0) 207 lsa->sa_flags |= LINUX_SA_NOCLDSTOP; 208 if ((bsa->sa_flags & SA_ONSTACK) != 0) 209 lsa->sa_flags |= LINUX_SA_ONSTACK; 210 if ((bsa->sa_flags & SA_RESTART) != 0) 211 lsa->sa_flags |= LINUX_SA_RESTART; 212 if ((bsa->sa_flags & SA_NODEFER) != 0) 213 lsa->sa_flags |= LINUX_SA_NOMASK; 214 if ((bsa->sa_flags & SA_RESETHAND) != 0) 215 lsa->sa_flags |= LINUX_SA_ONESHOT; 216 lsa->sa_restorer = NULL; 217} 218 219 220/* 221 * The Linux sigaction() system call. Do the usual conversions, 222 * and just call sigaction(). Some flags and values are silently 223 * ignored (see above). 224 */ 225int 226linux_sys_sigaction(p, v, retval) 227 register struct proc *p; 228 void *v; 229 register_t *retval; 230{ 231 struct linux_sys_sigaction_args /* { 232 syscallarg(int) signum; 233 syscallarg(struct linux_sigaction *) nsa; 234 syscallarg(struct linux_sigaction *) osa; 235 } */ *uap = v; 236 struct linux_sigaction *nlsa, *olsa, tmplsa; 237 struct sigaction *nbsa, *obsa, tmpbsa; 238 struct sys_sigaction_args sa; 239 caddr_t sg; 240 int error; 241 242 sg = stackgap_init(p->p_emul); 243 nlsa = SCARG(uap, nsa); 244 olsa = SCARG(uap, osa); 245 246 if (olsa != NULL) 247 obsa = stackgap_alloc(&sg, sizeof(struct sigaction)); 248 else 249 obsa = NULL; 250 251 if (nlsa != NULL) { 252 nbsa = stackgap_alloc(&sg, sizeof(struct sigaction)); 253 if ((error = copyin(nlsa, &tmplsa, sizeof(tmplsa))) != 0) 254 return error; 255 linux_to_bsd_sigaction(&tmplsa, &tmpbsa); 256 if ((error = copyout(&tmpbsa, nbsa, sizeof(tmpbsa))) != 0) 257 return error; 258 } else 259 nbsa = NULL; 260 261 SCARG(&sa, signum) = linux_to_bsd_sig[SCARG(uap, signum)]; 262 SCARG(&sa, nsa) = nbsa; 263 SCARG(&sa, osa) = obsa; 264 265 if ((error = sys_sigaction(p, &sa, retval)) != 0) 266 return error; 267 268 if (olsa != NULL) { 269 if ((error = copyin(obsa, &tmpbsa, sizeof(tmpbsa))) != 0) 270 return error; 271 bsd_to_linux_sigaction(&tmpbsa, &tmplsa); 272 if ((error = copyout(&tmplsa, olsa, sizeof(tmplsa))) != 0) 273 return error; 274 } 275 276 return 0; 277} 278 279/* 280 * The Linux signal() system call. I think that the signal() in the C 281 * library actually calls sigaction, so I doubt this one is ever used. 282 * But hey, it can't hurt having it here. The same restrictions as for 283 * sigaction() apply. 284 */ 285int 286linux_sys_signal(p, v, retval) 287 register struct proc *p; 288 void *v; 289 register_t *retval; 290{ 291 struct linux_sys_signal_args /* { 292 syscallarg(int) sig; 293 syscallarg(linux_handler_t) handler; 294 } */ *uap = v; 295 caddr_t sg; 296 struct sys_sigaction_args sa_args; 297 struct sigaction *osa, *nsa, tmpsa; 298 int error; 299 300 sg = stackgap_init(p->p_emul); 301 nsa = stackgap_alloc(&sg, sizeof *nsa); 302 osa = stackgap_alloc(&sg, sizeof *osa); 303 304 tmpsa.sa_handler = SCARG(uap, handler); 305 tmpsa.sa_mask = (sigset_t) 0; 306 tmpsa.sa_flags = SA_RESETHAND | SA_NODEFER; 307 if ((error = copyout(&tmpsa, nsa, sizeof tmpsa))) 308 return error; 309 310 SCARG(&sa_args, signum) = linux_to_bsd_sig[SCARG(uap, sig)]; 311 SCARG(&sa_args, osa) = osa; 312 SCARG(&sa_args, nsa) = nsa; 313 if ((error = sys_sigaction(p, &sa_args, retval))) 314 return error; 315 316 if ((error = copyin(osa, &tmpsa, sizeof *osa))) 317 return error; 318 retval[0] = (register_t) tmpsa.sa_handler; 319 320 return 0; 321} 322 323/* 324 * This is just a copy of the svr4 compat one. I feel so creative now. 325 */ 326int 327linux_sys_sigprocmask(p, v, retval) 328 register struct proc *p; 329 void *v; 330 register_t *retval; 331{ 332 struct linux_sys_sigprocmask_args /* { 333 syscallarg(int) how; 334 syscallarg(linux_sigset_t *) set; 335 syscallarg(linux_sigset_t *) oset; 336 } */ *uap = v; 337 linux_sigset_t ss; 338 sigset_t bs; 339 int error = 0; 340 341 *retval = 0; 342 343 if (SCARG(uap, oset) != NULL) { 344 /* Fix the return value first if needed */ 345 bsd_to_linux_sigset(&p->p_sigmask, &ss); 346 if ((error = copyout(&ss, SCARG(uap, oset), sizeof(ss))) != 0) 347 return error; 348 } 349 350 if (SCARG(uap, set) == NULL) 351 /* Just examine */ 352 return 0; 353 354 if ((error = copyin(SCARG(uap, set), &ss, sizeof(ss))) != 0) 355 return error; 356 357 linux_to_bsd_sigset(&ss, &bs); 358 359 (void) splhigh(); 360 361 switch (SCARG(uap, how)) { 362 case LINUX_SIG_BLOCK: 363 p->p_sigmask |= bs & ~sigcantmask; 364 break; 365 366 case LINUX_SIG_UNBLOCK: 367 p->p_sigmask &= ~bs; 368 break; 369 370 case LINUX_SIG_SETMASK: 371 p->p_sigmask = bs & ~sigcantmask; 372 break; 373 374 default: 375 error = EINVAL; 376 break; 377 } 378 379 (void) spl0(); 380 381 return error; 382} 383 384/* 385 * The functions below really make no distinction between an int 386 * and [linux_]sigset_t. This is ok for now, but it might break 387 * sometime. Then again, sigset_t is trusted to be an int everywhere 388 * else in the kernel too. 389 */ 390/* ARGSUSED */ 391int 392linux_sys_siggetmask(p, v, retval) 393 register struct proc *p; 394 void *v; 395 register_t *retval; 396{ 397 398 bsd_to_linux_sigset(&p->p_sigmask, (linux_sigset_t *)retval); 399 return 0; 400} 401 402/* 403 * The following three functions fiddle with a process' signal mask. 404 * Convert the signal masks because of the different signal 405 * values for Linux. The need for this is the reason why 406 * they are here, and have not been mapped directly. 407 */ 408int 409linux_sys_sigsetmask(p, v, retval) 410 register struct proc *p; 411 void *v; 412 register_t *retval; 413{ 414 struct linux_sys_sigsetmask_args /* { 415 syscallarg(linux_sigset_t) mask; 416 } */ *uap = v; 417 linux_sigset_t mask; 418 sigset_t bsdsig; 419 420 bsd_to_linux_sigset(&p->p_sigmask, (linux_sigset_t *)retval); 421 422 mask = SCARG(uap, mask); 423 bsd_to_linux_sigset(&mask, &bsdsig); 424 425 splhigh(); 426 p->p_sigmask = bsdsig & ~sigcantmask; 427 spl0(); 428 429 return 0; 430} 431 432int 433linux_sys_sigpending(p, v, retval) 434 register struct proc *p; 435 void *v; 436 register_t *retval; 437{ 438 struct linux_sys_sigpending_args /* { 439 syscallarg(linux_sigset_t *) mask; 440 } */ *uap = v; 441 sigset_t bs; 442 linux_sigset_t ls; 443 444 bs = p->p_siglist & p->p_sigmask; 445 bsd_to_linux_sigset(&bs, &ls); 446 447 return copyout(&ls, SCARG(uap, mask), sizeof(ls)); 448} 449 450int 451linux_sys_sigsuspend(p, v, retval) 452 register struct proc *p; 453 void *v; 454 register_t *retval; 455{ 456 struct linux_sys_sigsuspend_args /* { 457 syscallarg(caddr_t) restart; 458 syscallarg(int) oldmask; 459 syscallarg(int) mask; 460 } */ *uap = v; 461 struct sys_sigsuspend_args sa; 462 463 linux_to_bsd_sigset(&SCARG(uap, mask), &SCARG(&sa, mask)); 464 return sys_sigsuspend(p, &sa, retval); 465} 466 467/* 468 * The deprecated pause(2), which is really just an instance 469 * of sigsuspend(2). 470 */ 471int 472linux_sys_pause(p, v, retval) 473 register struct proc *p; 474 void *v; 475 register_t *retval; 476{ 477 struct sys_sigsuspend_args bsa; 478 479 SCARG(&bsa, mask) = p->p_sigmask; 480 return sys_sigsuspend(p, &bsa, retval); 481} 482 483/* 484 * Once more: only a signal conversion is needed. 485 */ 486int 487linux_sys_kill(p, v, retval) 488 register struct proc *p; 489 void *v; 490 register_t *retval; 491{ 492 struct linux_sys_kill_args /* { 493 syscallarg(int) pid; 494 syscallarg(int) signum; 495 } */ *uap = v; 496 struct sys_kill_args ka; 497 498 SCARG(&ka, pid) = SCARG(uap, pid); 499 SCARG(&ka, signum) = linux_to_bsd_sig[SCARG(uap, signum)]; 500 return sys_kill(p, &ka, retval); 501} 502