linux_sigaction.c revision 1.10
1/* $NetBSD: linux_sigaction.c,v 1.10 1996/04/04 23:51:36 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_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/* linux_signal.c */ 136void linux_to_bsd_sigset __P((const linux_sigset_t *, sigset_t *)); 137void bsd_to_linux_sigset __P((const sigset_t *, linux_sigset_t *)); 138void linux_to_bsd_sigaction __P((struct linux_sigaction *, struct sigaction *)); 139void bsd_to_linux_sigaction __P((struct sigaction *, struct linux_sigaction *)); 140 141/* 142 * Ok, we know that Linux and BSD signals both are just an unsigned int. 143 * Don't bother to use the sigismember() stuff for now. 144 */ 145void 146linux_to_bsd_sigset(lss, bss) 147 const linux_sigset_t *lss; 148 sigset_t *bss; 149{ 150 int i, newsig; 151 152 sigemptyset(bss); 153 for (i = 1; i < LINUX_NSIG; i++) { 154 if (linux_sigismember(lss, i)) { 155 newsig = linux_to_bsd_sig[i]; 156 if (newsig) 157 sigaddset(bss, newsig); 158 } 159 } 160} 161 162void 163bsd_to_linux_sigset(bss, lss) 164 const sigset_t *bss; 165 linux_sigset_t *lss; 166{ 167 int i, newsig; 168 169 linux_sigemptyset(lss); 170 for (i = 1; i < NSIG; i++) { 171 if (sigismember(bss, i)) { 172 newsig = bsd_to_linux_sig[i]; 173 if (newsig) 174 linux_sigaddset(lss, newsig); 175 } 176 } 177} 178 179/* 180 * Convert between Linux and BSD sigaction structures. Linux has 181 * one extra field (sa_restorer) which we don't support. 182 */ 183void 184linux_to_bsd_sigaction(lsa, bsa) 185 struct linux_sigaction *lsa; 186 struct sigaction *bsa; 187{ 188 189 bsa->sa_handler = lsa->sa_handler; 190 linux_to_bsd_sigset(&lsa->sa_mask, &bsa->sa_mask); 191 bsa->sa_flags = 0; 192 if ((lsa->sa_flags & LINUX_SA_ONSTACK) != 0) 193 bsa->sa_flags |= SA_ONSTACK; 194 if ((lsa->sa_flags & LINUX_SA_RESTART) != 0) 195 bsa->sa_flags |= SA_RESTART; 196 if ((lsa->sa_flags & LINUX_SA_ONESHOT) != 0) 197 bsa->sa_flags |= SA_RESETHAND; 198 if ((lsa->sa_flags & LINUX_SA_NOCLDSTOP) != 0) 199 bsa->sa_flags |= SA_NOCLDSTOP; 200 if ((lsa->sa_flags & LINUX_SA_NOMASK) != 0) 201 bsa->sa_flags |= SA_NODEFER; 202} 203 204void 205bsd_to_linux_sigaction(bsa, lsa) 206 struct sigaction *bsa; 207 struct linux_sigaction *lsa; 208{ 209 210 lsa->sa_handler = bsa->sa_handler; 211 bsd_to_linux_sigset(&bsa->sa_mask, &lsa->sa_mask); 212 lsa->sa_flags = 0; 213 if ((bsa->sa_flags & SA_NOCLDSTOP) != 0) 214 lsa->sa_flags |= LINUX_SA_NOCLDSTOP; 215 if ((bsa->sa_flags & SA_ONSTACK) != 0) 216 lsa->sa_flags |= LINUX_SA_ONSTACK; 217 if ((bsa->sa_flags & SA_RESTART) != 0) 218 lsa->sa_flags |= LINUX_SA_RESTART; 219 if ((bsa->sa_flags & SA_NODEFER) != 0) 220 lsa->sa_flags |= LINUX_SA_NOMASK; 221 if ((bsa->sa_flags & SA_RESETHAND) != 0) 222 lsa->sa_flags |= LINUX_SA_ONESHOT; 223 lsa->sa_restorer = NULL; 224} 225 226 227/* 228 * The Linux sigaction() system call. Do the usual conversions, 229 * and just call sigaction(). Some flags and values are silently 230 * ignored (see above). 231 */ 232int 233linux_sys_sigaction(p, v, retval) 234 register struct proc *p; 235 void *v; 236 register_t *retval; 237{ 238 struct linux_sys_sigaction_args /* { 239 syscallarg(int) signum; 240 syscallarg(struct linux_sigaction *) nsa; 241 syscallarg(struct linux_sigaction *) osa; 242 } */ *uap = v; 243 struct linux_sigaction *nlsa, *olsa, tmplsa; 244 struct sigaction *nbsa, *obsa, tmpbsa; 245 struct sys_sigaction_args sa; 246 caddr_t sg; 247 int error; 248 249 sg = stackgap_init(p->p_emul); 250 nlsa = SCARG(uap, nsa); 251 olsa = SCARG(uap, osa); 252 253 if (olsa != NULL) 254 obsa = stackgap_alloc(&sg, sizeof(struct sigaction)); 255 else 256 obsa = NULL; 257 258 if (nlsa != NULL) { 259 nbsa = stackgap_alloc(&sg, sizeof(struct sigaction)); 260 if ((error = copyin(nlsa, &tmplsa, sizeof(tmplsa))) != 0) 261 return error; 262 linux_to_bsd_sigaction(&tmplsa, &tmpbsa); 263 if ((error = copyout(&tmpbsa, nbsa, sizeof(tmpbsa))) != 0) 264 return error; 265 } else 266 nbsa = NULL; 267 268 SCARG(&sa, signum) = linux_to_bsd_sig[SCARG(uap, signum)]; 269 SCARG(&sa, nsa) = nbsa; 270 SCARG(&sa, osa) = obsa; 271 272 if ((error = sys_sigaction(p, &sa, retval)) != 0) 273 return error; 274 275 if (olsa != NULL) { 276 if ((error = copyin(obsa, &tmpbsa, sizeof(tmpbsa))) != 0) 277 return error; 278 bsd_to_linux_sigaction(&tmpbsa, &tmplsa); 279 if ((error = copyout(&tmplsa, olsa, sizeof(tmplsa))) != 0) 280 return error; 281 } 282 283 return 0; 284} 285 286/* 287 * The Linux signal() system call. I think that the signal() in the C 288 * library actually calls sigaction, so I doubt this one is ever used. 289 * But hey, it can't hurt having it here. The same restrictions as for 290 * sigaction() apply. 291 */ 292int 293linux_sys_signal(p, v, retval) 294 register struct proc *p; 295 void *v; 296 register_t *retval; 297{ 298 struct linux_sys_signal_args /* { 299 syscallarg(int) sig; 300 syscallarg(linux_handler_t) handler; 301 } */ *uap = v; 302 caddr_t sg; 303 struct sys_sigaction_args sa_args; 304 struct sigaction *osa, *nsa, tmpsa; 305 int error; 306 307 sg = stackgap_init(p->p_emul); 308 nsa = stackgap_alloc(&sg, sizeof *nsa); 309 osa = stackgap_alloc(&sg, sizeof *osa); 310 311 tmpsa.sa_handler = SCARG(uap, handler); 312 tmpsa.sa_mask = (sigset_t) 0; 313 tmpsa.sa_flags = SA_RESETHAND | SA_NODEFER; 314 if ((error = copyout(&tmpsa, nsa, sizeof tmpsa))) 315 return error; 316 317 SCARG(&sa_args, signum) = linux_to_bsd_sig[SCARG(uap, sig)]; 318 SCARG(&sa_args, osa) = osa; 319 SCARG(&sa_args, nsa) = nsa; 320 if ((error = sys_sigaction(p, &sa_args, retval))) 321 return error; 322 323 if ((error = copyin(osa, &tmpsa, sizeof *osa))) 324 return error; 325 retval[0] = (register_t) tmpsa.sa_handler; 326 327 return 0; 328} 329 330/* 331 * This is just a copy of the svr4 compat one. I feel so creative now. 332 */ 333int 334linux_sys_sigprocmask(p, v, retval) 335 register struct proc *p; 336 void *v; 337 register_t *retval; 338{ 339 struct linux_sys_sigprocmask_args /* { 340 syscallarg(int) how; 341 syscallarg(linux_sigset_t *) set; 342 syscallarg(linux_sigset_t *) oset; 343 } */ *uap = v; 344 linux_sigset_t ss; 345 sigset_t bs; 346 int error = 0; 347 348 *retval = 0; 349 350 if (SCARG(uap, oset) != NULL) { 351 /* Fix the return value first if needed */ 352 bsd_to_linux_sigset(&p->p_sigmask, &ss); 353 if ((error = copyout(&ss, SCARG(uap, oset), sizeof(ss))) != 0) 354 return error; 355 } 356 357 if (SCARG(uap, set) == NULL) 358 /* Just examine */ 359 return 0; 360 361 if ((error = copyin(SCARG(uap, set), &ss, sizeof(ss))) != 0) 362 return error; 363 364 linux_to_bsd_sigset(&ss, &bs); 365 366 (void) splhigh(); 367 368 switch (SCARG(uap, how)) { 369 case LINUX_SIG_BLOCK: 370 p->p_sigmask |= bs & ~sigcantmask; 371 break; 372 373 case LINUX_SIG_UNBLOCK: 374 p->p_sigmask &= ~bs; 375 break; 376 377 case LINUX_SIG_SETMASK: 378 p->p_sigmask = bs & ~sigcantmask; 379 break; 380 381 default: 382 error = EINVAL; 383 break; 384 } 385 386 (void) spl0(); 387 388 return error; 389} 390 391/* 392 * The functions below really make no distinction between an int 393 * and [linux_]sigset_t. This is ok for now, but it might break 394 * sometime. Then again, sigset_t is trusted to be an int everywhere 395 * else in the kernel too. 396 */ 397/* ARGSUSED */ 398int 399linux_sys_siggetmask(p, v, retval) 400 register struct proc *p; 401 void *v; 402 register_t *retval; 403{ 404 405 bsd_to_linux_sigset(&p->p_sigmask, (linux_sigset_t *)retval); 406 return 0; 407} 408 409/* 410 * The following three functions fiddle with a process' signal mask. 411 * Convert the signal masks because of the different signal 412 * values for Linux. The need for this is the reason why 413 * they are here, and have not been mapped directly. 414 */ 415int 416linux_sys_sigsetmask(p, v, retval) 417 register struct proc *p; 418 void *v; 419 register_t *retval; 420{ 421 struct linux_sys_sigsetmask_args /* { 422 syscallarg(linux_sigset_t) mask; 423 } */ *uap = v; 424 linux_sigset_t mask; 425 sigset_t bsdsig; 426 427 bsd_to_linux_sigset(&p->p_sigmask, (linux_sigset_t *)retval); 428 429 mask = SCARG(uap, mask); 430 bsd_to_linux_sigset(&bsdsig, &mask); 431 432 splhigh(); 433 p->p_sigmask = bsdsig & ~sigcantmask; 434 spl0(); 435 436 return 0; 437} 438 439int 440linux_sys_sigpending(p, v, retval) 441 register struct proc *p; 442 void *v; 443 register_t *retval; 444{ 445 struct linux_sys_sigpending_args /* { 446 syscallarg(linux_sigset_t *) mask; 447 } */ *uap = v; 448 sigset_t bs; 449 linux_sigset_t ls; 450 451 bs = p->p_siglist & p->p_sigmask; 452 bsd_to_linux_sigset(&bs, &ls); 453 454 return copyout(&ls, SCARG(uap, mask), sizeof(ls)); 455} 456 457int 458linux_sys_sigsuspend(p, v, retval) 459 register struct proc *p; 460 void *v; 461 register_t *retval; 462{ 463 struct linux_sys_sigsuspend_args /* { 464 syscallarg(caddr_t) restart; 465 syscallarg(int) oldmask; 466 syscallarg(int) mask; 467 } */ *uap = v; 468 struct sys_sigsuspend_args sa; 469 linux_sigset_t mask = SCARG(uap, mask); 470 471 linux_to_bsd_sigset(&mask, &SCARG(&sa, mask)); 472 return sys_sigsuspend(p, &sa, retval); 473} 474 475/* 476 * The deprecated pause(2), which is really just an instance 477 * of sigsuspend(2). 478 */ 479int 480linux_sys_pause(p, v, retval) 481 register struct proc *p; 482 void *v; 483 register_t *retval; 484{ 485 struct sys_sigsuspend_args bsa; 486 487 SCARG(&bsa, mask) = p->p_sigmask; 488 return sys_sigsuspend(p, &bsa, retval); 489} 490 491/* 492 * Once more: only a signal conversion is needed. 493 */ 494int 495linux_sys_kill(p, v, retval) 496 register struct proc *p; 497 void *v; 498 register_t *retval; 499{ 500 struct linux_sys_kill_args /* { 501 syscallarg(int) pid; 502 syscallarg(int) signum; 503 } */ *uap = v; 504 struct sys_kill_args ka; 505 506 SCARG(&ka, pid) = SCARG(uap, pid); 507 SCARG(&ka, signum) = linux_to_bsd_sig[SCARG(uap, signum)]; 508 return sys_kill(p, &ka, retval); 509} 510