1 /* $NetBSD: linux_signal.c,v 1.21 1998/12/19 16:27:10 drochner Exp $ */ 2 /*- 3 * Copyright (c) 1995, 1998 The NetBSD Foundation, Inc. 4 * All rights reserved. 5 * 6 * This code is derived from software contributed to The NetBSD Foundation 7 * by Frank van der Linden and Eric Haszlakiewicz. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. All advertising materials mentioning features or use of this software 18 * must display the following acknowledgement: 19 * This product includes software developed by the NetBSD 20 * Foundation, Inc. and its contributors. 21 * 4. Neither the name of The NetBSD Foundation nor the names of its 22 * contributors may be used to endorse or promote products derived 23 * from this software without specific prior written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 26 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 27 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 28 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 29 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35 * POSSIBILITY OF SUCH DAMAGE. 36 */ 37 /* 38 * heavily from: svr4_signal.c,v 1.7 1995/01/09 01:04:21 christos Exp 39 */ 40 41 /* 42 * Functions in multiarch: 43 * linux_sys_signal : linux_sig_notalpha.c 44 * linux_sys_siggetmask : linux_sig_notalpha.c 45 * linux_sys_sigsetmask : linux_sig_notalpha.c 46 * linux_sys_pause : linux_sig_notalpha.c 47 * linux_sys_sigaction : linux_sigaction.c 48 * 49 */ 50 51 /* 52 * Unimplemented: 53 * linux_sys_rt_sigtimedwait : sigsuspend w/timeout. 54 */ 55 56 #define COMPAT_LINUX 1 57 58 #include <sys/param.h> 59 #include <sys/systm.h> 60 #include <sys/namei.h> 61 #include <sys/proc.h> 62 #include <sys/filedesc.h> 63 #include <sys/ioctl.h> 64 #include <sys/mount.h> 65 #include <sys/kernel.h> 66 #include <sys/signal.h> 67 #include <sys/signalvar.h> 68 #include <sys/malloc.h> 69 70 #include <sys/syscallargs.h> 71 72 #include <compat/linux/common/linux_types.h> 73 #include <compat/linux/common/linux_signal.h> 74 #include <compat/linux/common/linux_siginfo.h> 75 #include <compat/linux/common/linux_util.h> 76 77 #include <compat/linux/linux_syscallargs.h> 78 79 /* Locally used defines (in bsd<->linux conversion functions): */ 80 #define linux_sigemptyset(s) memset((s), 0, sizeof(*(s))) 81 #define linux_sigismember(s, n) ((s)->sig[((n) - 1) / LINUX__NSIG_BPW] \ 82 & (1 << ((n) - 1) % LINUX__NSIG_BPW)) 83 #define linux_sigaddset(s, n) ((s)->sig[((n) - 1) / LINUX__NSIG_BPW] \ 84 |= (1 << ((n) - 1) % LINUX__NSIG_BPW)) 85 86 /* Note: linux_to_native_sig[] is in <arch>/linux_sigarray.c */ 87 int native_to_linux_sig[NSIG] = { 88 0, 89 LINUX_SIGHUP, 90 LINUX_SIGINT, 91 LINUX_SIGQUIT, 92 LINUX_SIGILL, 93 LINUX_SIGTRAP, 94 LINUX_SIGABRT, 95 0, /* SIGEMT */ 96 LINUX_SIGFPE, 97 LINUX_SIGKILL, 98 LINUX_SIGBUS, 99 LINUX_SIGSEGV, 100 0, /* SIGSEGV */ 101 LINUX_SIGPIPE, 102 LINUX_SIGALRM, 103 LINUX_SIGTERM, 104 LINUX_SIGURG, 105 LINUX_SIGSTOP, 106 LINUX_SIGTSTP, 107 LINUX_SIGCONT, 108 LINUX_SIGCHLD, 109 LINUX_SIGTTIN, 110 LINUX_SIGTTOU, 111 LINUX_SIGIO, 112 LINUX_SIGXCPU, 113 LINUX_SIGXFSZ, 114 LINUX_SIGVTALRM, 115 LINUX_SIGPROF, 116 LINUX_SIGWINCH, 117 0, /* SIGINFO */ 118 LINUX_SIGUSR1, 119 LINUX_SIGUSR2, 120 LINUX_SIGPWR, 121 }; 122 123 /* 124 * Convert between Linux and BSD signal sets. 125 */ 126 #if LINUX__NSIG_WORDS > 1 127 void 128 linux_old_extra_to_native_sigset(lss, extra, bss) 129 const linux_old_sigset_t *lss; 130 const unsigned long *extra; 131 sigset_t *bss; 132 { 133 linux_sigset_t lsnew; 134 135 /* convert old sigset to new sigset */ 136 linux_sigemptyset(&lsnew); 137 lsnew.sig[0] = *lss; 138 if (extra) 139 bcopy(extra, &lsnew.sig[1], 140 sizeof(linux_sigset_t) - sizeof(linux_old_sigset_t)); 141 142 linux_to_native_sigset(&lsnew, bss); 143 } 144 145 void 146 native_to_linux_old_extra_sigset(bss, lss, extra) 147 const sigset_t *bss; 148 linux_old_sigset_t *lss; 149 unsigned long *extra; 150 { 151 linux_sigset_t lsnew; 152 153 native_to_linux_sigset(bss, &lsnew); 154 155 /* convert new sigset to old sigset */ 156 *lss = lsnew.sig[0]; 157 if (extra) 158 bcopy(&lsnew.sig[1], extra, 159 sizeof(linux_sigset_t) - sizeof(linux_old_sigset_t)); 160 } 161 #endif 162 163 void 164 linux_to_native_sigset(lss, bss) 165 const linux_sigset_t *lss; 166 sigset_t *bss; 167 { 168 int i, newsig; 169 170 sigemptyset(bss); 171 for (i = 1; i < LINUX__NSIG; i++) { 172 if (linux_sigismember(lss, i)) { 173 newsig = linux_to_native_sig[i]; 174 if (newsig) 175 sigaddset(bss, newsig); 176 } 177 } 178 } 179 180 void 181 native_to_linux_sigset(bss, lss) 182 const sigset_t *bss; 183 linux_sigset_t *lss; 184 { 185 int i, newsig; 186 187 linux_sigemptyset(lss); 188 for (i = 1; i < NSIG; i++) { 189 if (sigismember(bss, i)) { 190 newsig = native_to_linux_sig[i]; 191 if (newsig) 192 linux_sigaddset(lss, newsig); 193 } 194 } 195 } 196 197 /* 198 * Convert between Linux and BSD sigaction structures. Linux sometimes 199 * has one extra field (sa_restorer) which we don't support. 200 */ 201 void 202 linux_old_to_native_sigaction(lsa, bsa) 203 struct linux_old_sigaction *lsa; 204 struct sigaction *bsa; 205 { 206 207 bsa->sa_handler = lsa->sa_handler; 208 linux_old_to_native_sigset(&lsa->sa_mask, &bsa->sa_mask); 209 bsa->sa_flags = 0; 210 if ((lsa->sa_flags & LINUX_SA_NOCLDSTOP) != 0) 211 bsa->sa_flags |= SA_NOCLDSTOP; 212 if ((lsa->sa_flags & LINUX_SA_ONSTACK) != 0) 213 bsa->sa_flags |= SA_ONSTACK; 214 if ((lsa->sa_flags & LINUX_SA_RESTART) != 0) 215 bsa->sa_flags |= SA_RESTART; 216 if ((lsa->sa_flags & LINUX_SA_ONESHOT) != 0) 217 bsa->sa_flags |= SA_RESETHAND; 218 if ((lsa->sa_flags & LINUX_SA_NOMASK) != 0) 219 bsa->sa_flags |= SA_NODEFER; 220 if ((lsa->sa_flags & LINUX_SA_SIGINFO) != 0) 221 bsa->sa_flags |= SA_SIGINFO; 222 #ifdef DEBUG 223 if ((lsa->sa_flags & ~LINUX_SA_ALLBITS) != 0) 224 /*XXX*/ printf("linux_old_to_native_sigaction: extra bits ignored\n"); 225 if (lsa->sa_restorer != 0) 226 /*XXX*/ printf("linux_old_to_native_sigaction: sa_restorer ignored\n"); 227 #endif 228 } 229 230 void 231 native_to_linux_old_sigaction(bsa, lsa) 232 struct sigaction *bsa; 233 struct linux_old_sigaction *lsa; 234 { 235 236 /* Clear sa_flags and sa_restorer (if it exists) */ 237 bzero(lsa, sizeof(struct linux_old_sigaction)); 238 239 /* ...and fill in the mask and flags */ 240 native_to_linux_old_sigset(&bsa->sa_mask, &lsa->sa_mask); 241 if ((bsa->sa_flags & SA_NOCLDSTOP) != 0) 242 lsa->sa_flags |= LINUX_SA_NOCLDSTOP; 243 if ((bsa->sa_flags & SA_ONSTACK) != 0) 244 lsa->sa_flags |= LINUX_SA_ONSTACK; 245 if ((bsa->sa_flags & SA_RESTART) != 0) 246 lsa->sa_flags |= LINUX_SA_RESTART; 247 if ((bsa->sa_flags & SA_NODEFER) != 0) 248 lsa->sa_flags |= LINUX_SA_NOMASK; 249 if ((bsa->sa_flags & SA_RESETHAND) != 0) 250 lsa->sa_flags |= LINUX_SA_ONESHOT; 251 if ((bsa->sa_flags & SA_SIGINFO) != 0) 252 lsa->sa_flags |= LINUX_SA_SIGINFO; 253 lsa->sa_handler = bsa->sa_handler; 254 } 255 256 /* ...and the new sigaction conversion funcs. */ 257 void 258 linux_to_native_sigaction(lsa, bsa) 259 struct linux_sigaction *lsa; 260 struct sigaction *bsa; 261 { 262 263 bsa->sa_handler = lsa->sa_handler; 264 linux_to_native_sigset(&lsa->sa_mask, &bsa->sa_mask); 265 bsa->sa_flags = 0; 266 if ((lsa->sa_flags & LINUX_SA_NOCLDSTOP) != 0) 267 bsa->sa_flags |= SA_NOCLDSTOP; 268 if ((lsa->sa_flags & LINUX_SA_ONSTACK) != 0) 269 bsa->sa_flags |= SA_ONSTACK; 270 if ((lsa->sa_flags & LINUX_SA_RESTART) != 0) 271 bsa->sa_flags |= SA_RESTART; 272 if ((lsa->sa_flags & LINUX_SA_ONESHOT) != 0) 273 bsa->sa_flags |= SA_RESETHAND; 274 if ((lsa->sa_flags & LINUX_SA_NOMASK) != 0) 275 bsa->sa_flags |= SA_NODEFER; 276 if ((lsa->sa_flags & LINUX_SA_SIGINFO) != 0) 277 bsa->sa_flags |= SA_SIGINFO; 278 #ifdef DEBUG 279 if ((lsa->sa_flags & ~LINUX_SA_ALLBITS) != 0) 280 /*XXX*/ printf("linux_to_native_sigaction: extra bits ignored\n"); 281 if (lsa->sa_restorer != 0) 282 /*XXX*/ printf("linux_to_native_sigaction: sa_restorer ignored\n"); 283 #endif 284 } 285 286 void 287 native_to_linux_sigaction(bsa, lsa) 288 struct sigaction *bsa; 289 struct linux_sigaction *lsa; 290 { 291 292 /* Clear sa_flags and sa_restorer (if it exists) */ 293 bzero(lsa, sizeof(struct linux_sigaction)); 294 295 /* ...and fill in the mask and flags */ 296 native_to_linux_sigset(&bsa->sa_mask, &lsa->sa_mask); 297 if ((bsa->sa_flags & SA_NOCLDSTOP) != 0) 298 lsa->sa_flags |= LINUX_SA_NOCLDSTOP; 299 if ((bsa->sa_flags & SA_ONSTACK) != 0) 300 lsa->sa_flags |= LINUX_SA_ONSTACK; 301 if ((bsa->sa_flags & SA_RESTART) != 0) 302 lsa->sa_flags |= LINUX_SA_RESTART; 303 if ((bsa->sa_flags & SA_NODEFER) != 0) 304 lsa->sa_flags |= LINUX_SA_NOMASK; 305 if ((bsa->sa_flags & SA_RESETHAND) != 0) 306 lsa->sa_flags |= LINUX_SA_ONESHOT; 307 if ((bsa->sa_flags & SA_SIGINFO) != 0) 308 lsa->sa_flags |= LINUX_SA_SIGINFO; 309 lsa->sa_handler = bsa->sa_handler; 310 } 311 312 /* ----------------------------------------------------------------------- */ 313 314 /* 315 * The Linux sigaction() system call. Do the usual conversions, 316 * and just call sigaction(). Some flags and values are silently 317 * ignored (see above). 318 */ 319 int 320 linux_sys_rt_sigaction(p, v, retval) 321 register struct proc *p; 322 void *v; 323 register_t *retval; 324 { 325 struct linux_sys_rt_sigaction_args /* { 326 syscallarg(int) signum; 327 syscallarg(const struct linux_sigaction *) nsa; 328 syscallarg(struct linux_sigaction *) osa; 329 syscallarg(size_t) sigsetsize; 330 } */ *uap = v; 331 struct linux_sigaction nlsa, olsa; 332 struct sigaction nbsa, obsa; 333 int error; 334 335 /* XXX XAX linux_sigset_t or struct linux_sigaction here? */ 336 if (SCARG(uap, sigsetsize) != sizeof(linux_sigset_t)) 337 return (EINVAL); 338 339 if (SCARG(uap, nsa)) { 340 error = copyin(SCARG(uap, nsa), &nlsa, sizeof(nlsa)); 341 if (error) 342 return (error); 343 linux_to_native_sigaction(&nlsa, &nbsa); 344 } 345 error = sigaction1(p, linux_to_native_sig[SCARG(uap, signum)], 346 SCARG(uap, nsa) ? &nbsa : 0, SCARG(uap, osa) ? &obsa : 0); 347 if (error) 348 return (error); 349 if (SCARG(uap, osa)) { 350 native_to_linux_sigaction(&obsa, &olsa); 351 error = copyout(&olsa, SCARG(uap, osa), sizeof(olsa)); 352 if (error) 353 return (error); 354 } 355 return (0); 356 } 357 358 int 359 linux_sigprocmask1(p, how, set, oset) 360 register struct proc *p; 361 int how; 362 const linux_old_sigset_t *set; 363 linux_old_sigset_t *oset; 364 { 365 linux_old_sigset_t nlss, olss; 366 sigset_t nbss, obss; 367 int error; 368 369 switch (how) { 370 case LINUX_SIG_BLOCK: 371 how = SIG_BLOCK; 372 break; 373 case LINUX_SIG_UNBLOCK: 374 how = SIG_UNBLOCK; 375 break; 376 case LINUX_SIG_SETMASK: 377 how = SIG_SETMASK; 378 break; 379 default: 380 return (EINVAL); 381 } 382 383 if (set) { 384 error = copyin(set, &nlss, sizeof(nlss)); 385 if (error) 386 return (error); 387 linux_old_to_native_sigset(&nlss, &nbss); 388 } 389 error = sigprocmask1(p, how, 390 set ? &nbss : 0, oset ? &obss : 0); 391 if (error) 392 return (error); 393 if (oset) { 394 native_to_linux_old_sigset(&obss, &olss); 395 error = copyout(&olss, oset, sizeof(olss)); 396 if (error) 397 return (error); 398 } 399 return (error); 400 } 401 402 int 403 linux_sys_rt_sigprocmask(p, v, retval) 404 register struct proc *p; 405 void *v; 406 register_t *retval; 407 { 408 struct linux_sys_rt_sigprocmask_args /* { 409 syscallarg(int) how; 410 syscallarg(const linux_sigset_t *) set; 411 syscallarg(linux_sigset_t *) oset; 412 syscallarg(size_t) sigsetsize; 413 } */ *uap = v; 414 415 /* Use non-rt function: sigsetsize is ignored. */ 416 /* Assume sizeof(linux_sigset_t) == sizeof(linux_old_sigset_t) */ 417 if (SCARG(uap, sigsetsize) != sizeof(linux_old_sigset_t)) { 418 #ifdef LINUX_DEBUG 419 printf("linux_sys_rt_sigprocmask: sigsetsize != sizeof(old_sigset_t)"); 420 #endif 421 return(ENOSYS); 422 } 423 424 return(linux_sigprocmask1(p, SCARG(uap, how), 425 (const linux_old_sigset_t *)SCARG(uap, set), 426 (linux_old_sigset_t *)SCARG(uap, oset))); 427 } 428 429 int 430 linux_sys_rt_sigpending(p, v, retval) 431 register struct proc *p; 432 void *v; 433 register_t *retval; 434 { 435 struct linux_sys_rt_sigpending_args /* { 436 syscallarg(linux_sigset_t *) set; 437 syscallarg(size_t) sigsetsize; 438 } */ *uap = v; 439 sigset_t bss; 440 linux_sigset_t lss; 441 442 if (SCARG(uap, sigsetsize) != sizeof(linux_sigset_t)) 443 return (EINVAL); 444 445 sigpending1(p, &bss); 446 native_to_linux_sigset(&bss, &lss); 447 return copyout(&lss, SCARG(uap, set), sizeof(lss)); 448 } 449 int 450 linux_sys_sigpending(p, v, retval) 451 register struct proc *p; 452 void *v; 453 register_t *retval; 454 { 455 struct linux_sys_sigpending_args /* { 456 syscallarg(linux_old_sigset_t *) mask; 457 } */ *uap = v; 458 sigset_t bss; 459 linux_old_sigset_t lss; 460 461 sigpending1(p, &bss); 462 native_to_linux_old_sigset(&bss, &lss); 463 return copyout(&lss, SCARG(uap, set), sizeof(lss)); 464 } 465 466 int 467 linux_sys_sigsuspend(p, v, retval) 468 register struct proc *p; 469 void *v; 470 register_t *retval; 471 { 472 struct linux_sys_sigsuspend_args /* { 473 syscallarg(caddr_t) restart; 474 syscallarg(int) oldmask; 475 syscallarg(int) mask; 476 } */ *uap = v; 477 linux_old_sigset_t lss; 478 sigset_t bss; 479 480 lss = SCARG(uap, mask); 481 linux_old_to_native_sigset(&lss, &bss); 482 return (sigsuspend1(p, &bss)); 483 } 484 int 485 linux_sys_rt_sigsuspend(p, v, retval) 486 register struct proc *p; 487 void *v; 488 register_t *retval; 489 { 490 struct linux_sys_rt_sigsuspend_args /* { 491 syscallarg(linux_sigset_t *) unewset; 492 syscallarg(size_t) sigsetsize; 493 } */ *uap = v; 494 linux_sigset_t lss; 495 sigset_t bss; 496 int error; 497 498 if (SCARG(uap, sigsetsize) != sizeof(linux_sigset_t)) 499 return (EINVAL); 500 501 error = copyin(SCARG(uap, unewset), &lss, sizeof(linux_sigset_t)); 502 if (error) 503 return (error); 504 505 linux_to_native_sigset(&lss, &bss); 506 507 return (sigsuspend1(p, &bss)); 508 } 509 510 /* 511 * Once more: only a signal conversion is needed. 512 * Note: also used as sys_rt_queueinfo. The info field is ignored. 513 */ 514 int 515 linux_sys_rt_queueinfo(p, v, retval) 516 register struct proc *p; 517 void *v; 518 register_t *retval; 519 { 520 /* XXX XAX This isn't this really int, int, siginfo_t *, is it? */ 521 #if 0 522 struct linux_sys_rt_queueinfo_args /* { 523 syscallarg(int) pid; 524 syscallarg(int) signum; 525 syscallarg(siginfo_t *) uinfo; 526 } */ *uap = v; 527 #endif 528 529 /* XXX To really implement this we need to */ 530 /* XXX keep a list of queued signals somewhere. */ 531 return (linux_sys_kill(p, v, retval)); 532 } 533 534 int 535 linux_sys_kill(p, v, retval) 536 register struct proc *p; 537 void *v; 538 register_t *retval; 539 { 540 struct linux_sys_kill_args /* { 541 syscallarg(int) pid; 542 syscallarg(int) signum; 543 } */ *uap = v; 544 struct sys_kill_args ka; 545 546 SCARG(&ka, pid) = SCARG(uap, pid); 547 SCARG(&ka, signum) = linux_to_native_sig[SCARG(uap, signum)]; 548 return sys_kill(p, &ka, retval); 549 } 550