linux_sigaction.c revision 1.7
1/* $NetBSD: linux_sigaction.c,v 1.7 1995/08/14 01:12:15 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_sigaction(p, uap, retval) 227 register struct proc *p; 228 struct linux_sigaction_args /* { 229 syscallarg(int) signum; 230 syscallarg(struct linux_sigaction *) nsa; 231 syscallarg(struct linux_sigaction *) osa; 232 } */ *uap; 233 register_t *retval; 234{ 235 struct linux_sigaction *nlsa, *olsa, tmplsa; 236 struct sigaction *nbsa, *obsa, tmpbsa; 237 struct sigaction_args sa; 238 caddr_t sg; 239 int error; 240 241 sg = stackgap_init(p->p_emul); 242 nlsa = SCARG(uap, nsa); 243 olsa = SCARG(uap, osa); 244 245 if (olsa != NULL) 246 obsa = stackgap_alloc(&sg, sizeof(struct sigaction)); 247 else 248 obsa = NULL; 249 250 if (nlsa != NULL) { 251 nbsa = stackgap_alloc(&sg, sizeof(struct sigaction)); 252 if ((error = copyin(nlsa, &tmplsa, sizeof(tmplsa))) != 0) 253 return error; 254 linux_to_bsd_sigaction(&tmplsa, &tmpbsa); 255 if ((error = copyout(&tmpbsa, nbsa, sizeof(tmpbsa))) != 0) 256 return error; 257 } else 258 nbsa = NULL; 259 260 SCARG(&sa, signum) = linux_to_bsd_sig[SCARG(uap, signum)]; 261 SCARG(&sa, nsa) = nbsa; 262 SCARG(&sa, osa) = obsa; 263 264 if ((error = sigaction(p, &sa, retval)) != 0) 265 return error; 266 267 if (olsa != NULL) { 268 if ((error = copyin(obsa, &tmpbsa, sizeof(tmpbsa))) != 0) 269 return error; 270 bsd_to_linux_sigaction(&tmpbsa, &tmplsa); 271 if ((error = copyout(&tmplsa, olsa, sizeof(tmplsa))) != 0) 272 return error; 273 } 274 275 return 0; 276} 277 278/* 279 * The Linux signal() system call. I think that the signal() in the C 280 * library actually calls sigaction, so I doubt this one is ever used. 281 * But hey, it can't hurt having it here. The same restrictions as for 282 * sigaction() apply. 283 */ 284int 285linux_signal(p, uap, retval) 286 register struct proc *p; 287 struct linux_signal_args /* { 288 syscallarg(int) sig; 289 syscallarg(linux_handler_t) handler; 290 } */ *uap; 291 register_t *retval; 292{ 293 caddr_t sg; 294 struct sigaction_args sa_args; 295 struct sigaction *osa, *nsa, tmpsa; 296 int error; 297 298 sg = stackgap_init(p->p_emul); 299 nsa = stackgap_alloc(&sg, sizeof *nsa); 300 osa = stackgap_alloc(&sg, sizeof *osa); 301 302 tmpsa.sa_handler = SCARG(uap, handler); 303 tmpsa.sa_mask = (sigset_t) 0; 304 tmpsa.sa_flags = SA_RESETHAND | SA_NODEFER; 305 if ((error = copyout(&tmpsa, nsa, sizeof tmpsa))) 306 return error; 307 308 SCARG(&sa_args, signum) = linux_to_bsd_sig[SCARG(uap, sig)]; 309 SCARG(&sa_args, osa) = osa; 310 SCARG(&sa_args, nsa) = nsa; 311 if ((error = sigaction(p, &sa_args, retval))) 312 return error; 313 314 if ((error = copyin(osa, &tmpsa, sizeof *osa))) 315 return error; 316 retval[0] = (register_t) tmpsa.sa_handler; 317 318 return 0; 319} 320 321/* 322 * This is just a copy of the svr4 compat one. I feel so creative now. 323 */ 324int 325linux_sigprocmask(p, uap, retval) 326 register struct proc *p; 327 struct linux_sigprocmask_args /* { 328 syscallarg(int) how; 329 syscallarg(linux_sigset_t *) set; 330 syscallarg(linux_sigset_t *) oset; 331 } */ *uap; 332 register_t *retval; 333{ 334 linux_sigset_t ss; 335 sigset_t bs; 336 int error = 0; 337 338 *retval = 0; 339 340 if (SCARG(uap, oset) != NULL) { 341 /* Fix the return value first if needed */ 342 bsd_to_linux_sigset(&p->p_sigmask, &ss); 343 if ((error = copyout(&ss, SCARG(uap, oset), sizeof(ss))) != 0) 344 return error; 345 } 346 347 if (SCARG(uap, set) == NULL) 348 /* Just examine */ 349 return 0; 350 351 if ((error = copyin(SCARG(uap, set), &ss, sizeof(ss))) != 0) 352 return error; 353 354 linux_to_bsd_sigset(&ss, &bs); 355 356 (void) splhigh(); 357 358 switch (SCARG(uap, how)) { 359 case LINUX_SIG_BLOCK: 360 p->p_sigmask |= bs & ~sigcantmask; 361 break; 362 363 case LINUX_SIG_UNBLOCK: 364 p->p_sigmask &= ~bs; 365 break; 366 367 case LINUX_SIG_SETMASK: 368 p->p_sigmask = bs & ~sigcantmask; 369 break; 370 371 default: 372 error = EINVAL; 373 break; 374 } 375 376 (void) spl0(); 377 378 return error; 379} 380 381/* 382 * The functions below really make no distinction between an int 383 * and [linux_]sigset_t. This is ok for now, but it might break 384 * sometime. Then again, sigset_t is trusted to be an int everywhere 385 * else in the kernel too. 386 */ 387/* ARGSUSED */ 388int 389linux_siggetmask(p, uap, retval) 390 register struct proc *p; 391 void *uap; 392 register_t *retval; 393{ 394 395 bsd_to_linux_sigset(&p->p_sigmask, (linux_sigset_t *)retval); 396 return 0; 397} 398 399/* 400 * The following three functions fiddle with a process' signal mask. 401 * Convert the signal masks because of the different signal 402 * values for Linux. The need for this is the reason why 403 * they are here, and have not been mapped directly. 404 */ 405int 406linux_sigsetmask(p, uap, retval) 407 register struct proc *p; 408 struct linux_sigsetmask_args /* { 409 syscallarg(linux_sigset_t) mask; 410 } */ *uap; 411 register_t *retval; 412{ 413 linux_sigset_t mask; 414 sigset_t bsdsig; 415 416 bsd_to_linux_sigset(&p->p_sigmask, (linux_sigset_t *)retval); 417 418 mask = SCARG(uap, mask); 419 bsd_to_linux_sigset(&mask, &bsdsig); 420 421 splhigh(); 422 p->p_sigmask = bsdsig & ~sigcantmask; 423 spl0(); 424 425 return 0; 426} 427 428int 429linux_sigpending(p, uap, retval) 430 register struct proc *p; 431 struct linux_sigpending_args /* { 432 syscallarg(linux_sigset_t *) mask; 433 } */ *uap; 434 register_t *retval; 435{ 436 sigset_t bs; 437 linux_sigset_t ls; 438 439 bs = p->p_siglist & p->p_sigmask; 440 bsd_to_linux_sigset(&bs, &ls); 441 442 return copyout(&ls, SCARG(uap, mask), sizeof(ls)); 443} 444 445int 446linux_sigsuspend(p, uap, retval) 447 register struct proc *p; 448 struct linux_sigsuspend_args /* { 449 syscallarg(caddr_t) restart; 450 syscallarg(int) oldmask; 451 syscallarg(int) mask; 452 } */ *uap; 453 register_t *retval; 454{ 455 struct sigsuspend_args sa; 456 457 linux_to_bsd_sigset(&SCARG(uap, mask), &SCARG(&sa, mask)); 458 return sigsuspend(p, &sa, retval); 459} 460 461/* 462 * The deprecated pause(2), which is really just an instance 463 * of sigsuspend(2). 464 */ 465int 466linux_pause(p, uap, retval) 467 register struct proc *p; 468 void *uap; 469 register_t *retval; 470{ 471 struct sigsuspend_args bsa; 472 473 SCARG(&bsa, mask) = p->p_sigmask; 474 return sigsuspend(p, &bsa, retval); 475} 476 477/* 478 * Once more: only a signal conversion is needed. 479 */ 480int 481linux_kill(p, uap, retval) 482 register struct proc *p; 483 struct linux_kill_args /* { 484 syscallarg(int) pid; 485 syscallarg(int) signum; 486 } */ *uap; 487 register_t *retval; 488{ 489 struct kill_args ka; 490 491 SCARG(&ka, pid) = SCARG(uap, pid); 492 SCARG(&ka, signum) = linux_to_bsd_sig[SCARG(uap, signum)]; 493 return kill(p, &ka, retval); 494} 495