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