linux_sigaction.c revision 1.5
1/* $NetBSD: linux_sigaction.c,v 1.5 1995/06/24 20:20:30 christos 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_syscallargs.h> 52#include <compat/linux/linux_util.h> 53#include <compat/linux/linux_signal.h> 54 55/* 56 * Most of ths stuff in this file is taken from Christos' SVR4 emul 57 * code. The things that need to be done are largely the same, so 58 * re-inventing the wheel doesn't make much sense. 59 */ 60 61/* 62 * Some boring signal conversion functions. Just a switch() for all signals; 63 * return the converted signal number, 0 if not supported. 64 */ 65 66int 67bsd_to_linux_sig(sig) 68 int sig; 69{ 70 switch(sig) { 71 case SIGHUP: 72 return LINUX_SIGHUP; 73 case SIGINT: 74 return LINUX_SIGINT; 75 case SIGQUIT: 76 return LINUX_SIGQUIT; 77 case SIGILL: 78 return LINUX_SIGILL; 79 case SIGTRAP: 80 return LINUX_SIGTRAP; 81 case SIGABRT: 82 return LINUX_SIGABRT; 83 case SIGFPE: 84 return LINUX_SIGFPE; 85 case SIGKILL: 86 return LINUX_SIGKILL; 87 case SIGBUS: 88 return LINUX_SIGBUS; 89 case SIGSEGV: 90 return LINUX_SIGSEGV; 91 case SIGPIPE: 92 return LINUX_SIGPIPE; 93 case SIGALRM: 94 return LINUX_SIGALRM; 95 case SIGTERM: 96 return LINUX_SIGTERM; 97 case SIGURG: 98 return LINUX_SIGURG; 99 case SIGSTOP: 100 return LINUX_SIGSTOP; 101 case SIGTSTP: 102 return LINUX_SIGTSTP; 103 case SIGCONT: 104 return LINUX_SIGCONT; 105 case SIGCHLD: 106 return LINUX_SIGCHLD; 107 case SIGTTIN: 108 return LINUX_SIGTTIN; 109 case SIGTTOU: 110 return LINUX_SIGTTOU; 111 case SIGIO: 112 return LINUX_SIGIO; 113 case SIGXCPU: 114 return LINUX_SIGXCPU; 115 case SIGXFSZ: 116 return LINUX_SIGXFSZ; 117 case SIGVTALRM: 118 return LINUX_SIGVTALRM; 119 case SIGPROF: 120 return LINUX_SIGPROF; 121 case SIGWINCH: 122 return LINUX_SIGWINCH; 123 case SIGUSR1: 124 return LINUX_SIGUSR1; 125 case SIGUSR2: 126 return LINUX_SIGUSR2; 127 /* Not supported: EMT, SYS, INFO */ 128 } 129 return 0; 130} 131 132int 133linux_to_bsd_sig(sig) 134 int sig; 135{ 136 switch(sig) { 137 case LINUX_SIGHUP: 138 return SIGHUP; 139 case LINUX_SIGINT: 140 return SIGINT; 141 case LINUX_SIGQUIT: 142 return SIGQUIT; 143 case LINUX_SIGILL: 144 return SIGILL; 145 case LINUX_SIGTRAP: 146 return SIGTRAP; 147 case LINUX_SIGABRT: 148 return SIGABRT; 149 case LINUX_SIGBUS: 150 return SIGBUS; 151 case LINUX_SIGFPE: 152 return SIGFPE; 153 case LINUX_SIGKILL: 154 return SIGKILL; 155 case LINUX_SIGUSR1: 156 return SIGUSR1; 157 case LINUX_SIGSEGV: 158 return SIGSEGV; 159 case LINUX_SIGUSR2: 160 return SIGUSR2; 161 case LINUX_SIGPIPE: 162 return SIGPIPE; 163 case LINUX_SIGALRM: 164 return SIGALRM; 165 case LINUX_SIGTERM: 166 return SIGTERM; 167 case LINUX_SIGCHLD: 168 return SIGCHLD; 169 case LINUX_SIGCONT: 170 return SIGCONT; 171 case LINUX_SIGSTOP: 172 return SIGSTOP; 173 case LINUX_SIGTSTP: 174 return SIGTSTP; 175 case LINUX_SIGTTIN: 176 return SIGTTIN; 177 case LINUX_SIGTTOU: 178 return SIGTTOU; 179 case LINUX_SIGURG: 180 return SIGURG; 181 case LINUX_SIGXCPU: 182 return SIGXCPU; 183 case LINUX_SIGXFSZ: 184 return SIGXFSZ; 185 case LINUX_SIGVTALRM: 186 return SIGVTALRM; 187 case LINUX_SIGPROF: 188 return SIGPROF; 189 case LINUX_SIGWINCH: 190 return SIGWINCH; 191 case LINUX_SIGIO: 192 return SIGIO; 193 /* Not supported: STKFLT, PWR */ 194 } 195 return 0; 196} 197 198/* 199 * Ok, we know that Linux and BSD signals both are just an unsigned int. 200 * Don't bother to use the sigismember() stuff for now. 201 */ 202static void 203linux_to_bsd_sigset(lss, bss) 204 const linux_sigset_t *lss; 205 sigset_t *bss; 206{ 207 int i, newsig; 208 209 *bss = (sigset_t) 0; 210 for (i = 1; i <= LINUX_NSIG; i++) { 211 if (*lss & sigmask(i)) { 212 newsig = linux_to_bsd_sig(i); 213 if (newsig) 214 *bss |= sigmask(newsig); 215 } 216 } 217} 218 219void 220bsd_to_linux_sigset(bss, lss) 221 const sigset_t *bss; 222 linux_sigset_t *lss; 223{ 224 int i, newsig; 225 226 *lss = (linux_sigset_t) 0; 227 for (i = 1; i <= NSIG; i++) { 228 if (*bss & sigmask(i)) { 229 newsig = bsd_to_linux_sig(i); 230 if (newsig) 231 *lss |= sigmask(newsig); 232 } 233 } 234} 235 236/* 237 * Convert between Linux and BSD sigaction structures. Linux has 238 * one extra field (sa_restorer) which we don't support. The Linux 239 * SA_ONESHOT and SA_NOMASK flags (which together form the old 240 * SysV signal behavior) are silently ignored. XXX 241 */ 242void 243linux_to_bsd_sigaction(lsa, bsa) 244 struct linux_sigaction *lsa; 245 struct sigaction *bsa; 246{ 247 bsa->sa_handler = lsa->sa_handler; 248 linux_to_bsd_sigset(&bsa->sa_mask, &lsa->sa_mask); 249 bsa->sa_flags = 0; 250 bsa->sa_flags |= cvtto_bsd_mask(lsa->sa_flags, LINUX_SA_NOCLDSTOP, 251 SA_NOCLDSTOP); 252 bsa->sa_flags |= cvtto_bsd_mask(lsa->sa_flags, LINUX_SA_ONSTACK, 253 SA_ONSTACK); 254 bsa->sa_flags |= cvtto_bsd_mask(lsa->sa_flags, LINUX_SA_RESTART, 255 SA_RESTART); 256} 257 258void 259bsd_to_linux_sigaction(bsa, lsa) 260 struct sigaction *bsa; 261 struct linux_sigaction *lsa; 262{ 263 lsa->sa_handler = bsa->sa_handler; 264 bsd_to_linux_sigset(&lsa->sa_mask, &bsa->sa_mask); 265 lsa->sa_flags = 0; 266 lsa->sa_flags |= cvtto_linux_mask(bsa->sa_flags, SA_NOCLDSTOP, 267 LINUX_SA_NOCLDSTOP); 268 lsa->sa_flags |= cvtto_linux_mask(bsa->sa_flags, SA_ONSTACK, 269 LINUX_SA_ONSTACK); 270 lsa->sa_flags |= cvtto_linux_mask(bsa->sa_flags, SA_RESTART, 271 LINUX_SA_RESTART); 272 lsa->sa_restorer = NULL; 273} 274 275 276/* 277 * The Linux sigaction() system call. Do the usual conversions, 278 * and just call sigaction(). Some flags and values are silently 279 * ignored (see above). 280 */ 281int 282linux_sigaction(p, uap, retval) 283 register struct proc *p; 284 struct linux_sigaction_args /* { 285 syscallarg(int) signum; 286 syscallarg(struct linux_sigaction *) nsa; 287 syscallarg(struct linux_sigaction *) osa; 288 } */ *uap; 289 register_t *retval; 290{ 291 struct sigaction *nbsda = NULL, *obsda = NULL, tmpbsda; 292 struct linux_sigaction *nlsa, *olsa, tmplsa; 293 struct sigaction_args sa; 294 caddr_t sg; 295 int error; 296 297 sg = stackgap_init(p->p_emul); 298 olsa = SCARG(uap, osa); 299 nlsa = SCARG(uap, nsa); 300 301 if (olsa != NULL) 302 obsda = stackgap_alloc(&sg, sizeof (struct sigaction)); 303 304 if (nlsa != NULL) { 305 nbsda = stackgap_alloc(&sg, sizeof (struct sigaction)); 306 if ((error = copyin(nlsa, &tmplsa, sizeof tmplsa))) 307 return error; 308 linux_to_bsd_sigaction(&tmplsa, &tmpbsda); 309 if ((error = copyout(&tmpbsda, nbsda, sizeof tmpbsda))) 310 return error; 311 } 312 313 SCARG(&sa, signum) = linux_to_bsd_sig(SCARG(uap, signum)); 314 SCARG(&sa, nsa) = nbsda; 315 SCARG(&sa, osa) = obsda; 316 317 if ((error = sigaction(p, &sa, retval))) 318 return error; 319 320 if (olsa != NULL) { 321 if ((error = copyin(obsda, &tmpbsda, sizeof tmpbsda))) 322 return error; 323 bsd_to_linux_sigaction(&tmpbsda, &tmplsa); 324 if ((error = copyout(&tmplsa, olsa, sizeof tmplsa))) 325 return error; 326 } 327 return 0; 328} 329 330/* 331 * The Linux signal() system call. I think that the signal() in the C 332 * library actually calls sigaction, so I doubt this one is ever used. 333 * But hey, it can't hurt having it here. The same restrictions as for 334 * sigaction() apply. 335 */ 336int 337linux_signal(p, uap, retval) 338 register struct proc *p; 339 struct linux_signal_args /* { 340 syscallarg(int) sig; 341 syscallarg(linux_handler_t) handler; 342 } */ *uap; 343 register_t *retval; 344{ 345 caddr_t sg; 346 struct sigaction_args sa_args; 347 struct sigaction *osa, *nsa, tmpsa; 348 int error; 349 350 sg = stackgap_init(p->p_emul); 351 nsa = stackgap_alloc(&sg, sizeof *nsa); 352 osa = stackgap_alloc(&sg, sizeof *osa); 353 354 tmpsa.sa_handler = SCARG(uap, handler); 355 tmpsa.sa_mask = (sigset_t) 0; 356 tmpsa.sa_flags = 0; 357 if ((error = copyout(&tmpsa, nsa, sizeof tmpsa))) 358 return error; 359 360 SCARG(&sa_args, signum) = linux_to_bsd_sig(SCARG(uap, sig)); 361 SCARG(&sa_args, osa) = osa; 362 SCARG(&sa_args, nsa) = nsa; 363 if ((error = sigaction(p, &sa_args, retval))) 364 return error; 365 366 if ((error = copyin(osa, &tmpsa, sizeof *osa))) 367 return error; 368 retval[0] = (register_t) tmpsa.sa_handler; 369 370 return 0; 371} 372 373/* 374 * This is just a copy of the svr4 compat one. I feel so creative now. 375 */ 376int 377linux_sigprocmask(p, uap, retval) 378 register struct proc *p; 379 register struct linux_sigprocmask_args /* { 380 syscallarg(int) how; 381 syscallarg(linux_sigset_t *) set; 382 syscallarg(linux_sigset_t * oset; 383 } */ *uap; 384 register_t *retval; 385{ 386 linux_sigset_t ss; 387 sigset_t bs; 388 int error = 0; 389 390 *retval = 0; 391 392 if (SCARG(uap, oset) != NULL) { 393 /* Fix the return value first if needed */ 394 bsd_to_linux_sigset(&p->p_sigmask, &ss); 395 if ((error = copyout(&ss, SCARG(uap, oset), sizeof(ss))) != 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), &ss, sizeof(ss))) != 0) 404 return error; 405 406 linux_to_bsd_sigset(&ss, &bs); 407 408 (void) splhigh(); 409 410 switch (SCARG(uap, how)) { 411 case LINUX_SIG_BLOCK: 412 p->p_sigmask |= bs & ~sigcantmask; 413 break; 414 415 case LINUX_SIG_UNBLOCK: 416 p->p_sigmask &= ~bs; 417 break; 418 419 case LINUX_SIG_SETMASK: 420 p->p_sigmask = bs & ~sigcantmask; 421 break; 422 423 default: 424 error = EINVAL; 425 break; 426 } 427 428 (void) spl0(); 429 430 return error; 431} 432 433/* 434 * The functions below really make no distinction between an int 435 * and [linux_]sigset_t. This is ok for now, but it might break 436 * sometime. Then again, sigset_t is trusted to be an int everywhere 437 * else in the kernel too. 438 */ 439/* ARGSUSED */ 440int 441linux_siggetmask(p, uap, retval) 442 struct proc *p; 443 void *uap; 444 register_t *retval; 445{ 446 bsd_to_linux_sigset(&p->p_sigmask, (linux_sigset_t *) retval); 447 return 0; 448} 449 450/* 451 * The following three functions fiddle with a process' signal mask. 452 * Convert the signal masks because of the different signal 453 * values for Linux. The need for this is the reason why 454 * they are here, and have not been mapped directly. 455 */ 456int 457linux_sigsetmask(p, uap, retval) 458 struct proc *p; 459 struct linux_sigsetmask_args /* { 460 syscallarg(linux_sigset_t) mask; 461 } */ *uap; 462 register_t *retval; 463{ 464 linux_sigset_t mask; 465 sigset_t bsdsig; 466 467 bsd_to_linux_sigset(&p->p_sigmask, (linux_sigset_t *) retval); 468 469 mask = SCARG(uap, mask); 470 bsd_to_linux_sigset(&mask, &bsdsig); 471 472 splhigh(); 473 p->p_sigmask = bsdsig & ~sigcantmask; 474 spl0(); 475 476 return 0; 477} 478 479int 480linux_sigpending(p, uap, retval) 481 struct proc *p; 482 struct linux_sigpending_args /* { 483 syscallarg(linux_sigset_t *) mask; 484 } */ *uap; 485 register_t *retval; 486{ 487 sigset_t bsdsig; 488 linux_sigset_t linuxsig; 489 490 bsdsig = p->p_siglist & p->p_sigmask; 491 492 bsd_to_linux_sigset(&bsdsig, &linuxsig); 493 return copyout(&linuxsig, SCARG(uap, mask), sizeof linuxsig); 494} 495 496int 497linux_sigsuspend(p, uap, retval) 498 struct proc *p; 499 struct linux_sigsuspend_args /* { 500 syscallarg(caddr_t) restart; 501 syscallarg(int) oldmask; 502 syscallarg(int) mask; 503 } */ *uap; 504 register_t *retval; 505{ 506 struct sigsuspend_args ssa; 507 508 linux_to_bsd_sigset(&SCARG(uap, mask), &SCARG(&ssa, mask)); 509 return sigsuspend(p, &ssa, retval); 510} 511 512/* 513 * The deprecated pause(2), which is really just an instance 514 * of sigsuspend(2). 515 */ 516int 517linux_pause(p, uap, retval) 518 struct proc *p; 519 void *uap; 520 register_t *retval; 521{ 522 struct sigsuspend_args bsa; 523 524 SCARG(&bsa, mask) = p->p_sigmask; 525 return sigsuspend(p, &bsa, retval); 526} 527 528/* 529 * Once more: only a signal conversion is needed. 530 */ 531int 532linux_kill(p, uap, retval) 533 struct proc *p; 534 struct linux_kill_args /* { 535 syscallarg(int) pid; 536 syscallarg(int) signum; 537 } */ *uap; 538 register_t *retval; 539{ 540 SCARG(uap, signum) = linux_to_bsd_sig(SCARG(uap, signum)); 541 return kill(p, (struct kill_args *) uap, retval); 542} 543