linux_sigaction.c revision 1.13
1/* $NetBSD: linux_sigaction.c,v 1.13 1998/09/29 14:15:49 tv 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 linux_sigmask(n) (1 << ((n) - 1)) 56#define linux_sigemptyset(s) memset((s), 0, sizeof(*(s))) 57#define linux_sigismember(s, n) (*(s) & linux_sigmask(n)) 58#define linux_sigaddset(s, n) (*(s) |= linux_sigmask(n)) 59 60int native_to_linux_sig[NSIG] = { 61 0, 62 LINUX_SIGHUP, 63 LINUX_SIGINT, 64 LINUX_SIGQUIT, 65 LINUX_SIGILL, 66 LINUX_SIGTRAP, 67 LINUX_SIGABRT, 68 0, /* SIGEMT */ 69 LINUX_SIGFPE, 70 LINUX_SIGKILL, 71 LINUX_SIGBUS, 72 LINUX_SIGSEGV, 73 0, /* SIGSEGV */ 74 LINUX_SIGPIPE, 75 LINUX_SIGALRM, 76 LINUX_SIGTERM, 77 LINUX_SIGURG, 78 LINUX_SIGSTOP, 79 LINUX_SIGTSTP, 80 LINUX_SIGCONT, 81 LINUX_SIGCHLD, 82 LINUX_SIGTTIN, 83 LINUX_SIGTTOU, 84 LINUX_SIGIO, 85 LINUX_SIGXCPU, 86 LINUX_SIGXFSZ, 87 LINUX_SIGVTALRM, 88 LINUX_SIGPROF, 89 LINUX_SIGWINCH, 90 0, /* SIGINFO */ 91 LINUX_SIGUSR1, 92 LINUX_SIGUSR2, 93 LINUX_SIGPWR, 94}; 95 96int linux_to_native_sig[LINUX_NSIG] = { 97 0, 98 SIGHUP, 99 SIGINT, 100 SIGQUIT, 101 SIGILL, 102 SIGTRAP, 103 SIGABRT, 104 SIGBUS, 105 SIGFPE, 106 SIGKILL, 107 SIGUSR1, 108 SIGSEGV, 109 SIGUSR2, 110 SIGPIPE, 111 SIGALRM, 112 SIGTERM, 113 0, /* SIGSTKFLT */ 114 SIGCHLD, 115 SIGCONT, 116 SIGSTOP, 117 SIGTSTP, 118 SIGTTIN, 119 SIGTTOU, 120 SIGURG, 121 SIGXCPU, 122 SIGXFSZ, 123 SIGVTALRM, 124 SIGPROF, 125 SIGWINCH, 126 SIGIO, 127 SIGPWR, 128 0, /* SIGUNUSED */ 129}; 130 131/* linux_signal.c */ 132void linux_to_native_sigaction __P((struct linux_sigaction *, struct sigaction *)); 133void native_to_linux_sigaction __P((struct sigaction *, struct linux_sigaction *)); 134 135void 136linux_to_native_sigset(lss, bss) 137 const linux_sigset_t *lss; 138 sigset_t *bss; 139{ 140 int i, newsig; 141 142 sigemptyset(bss); 143 for (i = 1; i < LINUX_NSIG; i++) { 144 if (linux_sigismember(lss, i)) { 145 newsig = linux_to_native_sig[i]; 146 if (newsig) 147 sigaddset(bss, newsig); 148 } 149 } 150} 151 152void 153native_to_linux_sigset(bss, lss) 154 const sigset_t *bss; 155 linux_sigset_t *lss; 156{ 157 int i, newsig; 158 159 linux_sigemptyset(lss); 160 for (i = 1; i < NSIG; i++) { 161 if (sigismember(bss, i)) { 162 newsig = native_to_linux_sig[i]; 163 if (newsig) 164 linux_sigaddset(lss, newsig); 165 } 166 } 167} 168 169/* 170 * Convert between Linux and BSD sigaction structures. Linux has 171 * one extra field (sa_restorer) which we don't support. 172 */ 173void 174linux_to_native_sigaction(lsa, bsa) 175 struct linux_sigaction *lsa; 176 struct sigaction *bsa; 177{ 178 179 bsa->sa_handler = lsa->sa_handler; 180 linux_to_native_sigset(&lsa->sa_mask, &bsa->sa_mask); 181 bsa->sa_flags = 0; 182 if ((lsa->sa_flags & LINUX_SA_NOCLDSTOP) != 0) 183 bsa->sa_flags |= SA_NOCLDSTOP; 184 if ((lsa->sa_flags & LINUX_SA_ONSTACK) != 0) 185 bsa->sa_flags |= SA_ONSTACK; 186 if ((lsa->sa_flags & LINUX_SA_RESTART) != 0) 187 bsa->sa_flags |= SA_RESTART; 188 if ((lsa->sa_flags & LINUX_SA_ONESHOT) != 0) 189 bsa->sa_flags |= SA_RESETHAND; 190 if ((lsa->sa_flags & LINUX_SA_NOMASK) != 0) 191 bsa->sa_flags |= SA_NODEFER; 192#ifdef DEBUG 193 if ((lsa->sa_flags & ~LINUX_SA_ALLBITS) != 0) 194/*XXX*/ printf("linux_to_native_sigaction: extra bits ignored\n"); 195 if (lsa->sa_restorer != 0) 196/*XXX*/ printf("linux_to_native_sigaction: sa_restorer ignored\n"); 197#endif 198} 199 200void 201native_to_linux_sigaction(bsa, lsa) 202 struct sigaction *bsa; 203 struct linux_sigaction *lsa; 204{ 205 206 lsa->sa_handler = bsa->sa_handler; 207 native_to_linux_sigset(&bsa->sa_mask, &lsa->sa_mask); 208 lsa->sa_flags = 0; 209 if ((bsa->sa_flags & SA_NOCLDSTOP) != 0) 210 lsa->sa_flags |= LINUX_SA_NOCLDSTOP; 211 if ((bsa->sa_flags & SA_ONSTACK) != 0) 212 lsa->sa_flags |= LINUX_SA_ONSTACK; 213 if ((bsa->sa_flags & SA_RESTART) != 0) 214 lsa->sa_flags |= LINUX_SA_RESTART; 215 if ((bsa->sa_flags & SA_NODEFER) != 0) 216 lsa->sa_flags |= LINUX_SA_NOMASK; 217 if ((bsa->sa_flags & SA_RESETHAND) != 0) 218 lsa->sa_flags |= LINUX_SA_ONESHOT; 219 lsa->sa_restorer = NULL; 220} 221 222 223/* 224 * The Linux sigaction() system call. Do the usual conversions, 225 * and just call sigaction(). Some flags and values are silently 226 * ignored (see above). 227 */ 228int 229linux_sys_sigaction(p, v, retval) 230 register struct proc *p; 231 void *v; 232 register_t *retval; 233{ 234 struct linux_sys_sigaction_args /* { 235 syscallarg(int) signum; 236 syscallarg(const struct linux_sigaction *) nsa; 237 syscallarg(struct linux_sigaction *) osa; 238 } */ *uap = v; 239 struct linux_sigaction nlsa, olsa; 240 struct sigaction nbsa, obsa; 241 int error; 242 243 if (SCARG(uap, nsa)) { 244 error = copyin(SCARG(uap, nsa), &nlsa, sizeof(nlsa)); 245 if (error) 246 return (error); 247 linux_to_native_sigaction(&nlsa, &nbsa); 248 } 249 error = sigaction1(p, linux_to_native_sig[SCARG(uap, signum)], 250 SCARG(uap, nsa) ? &nbsa : 0, SCARG(uap, osa) ? &obsa : 0); 251 if (error) 252 return (error); 253 if (SCARG(uap, osa)) { 254 native_to_linux_sigaction(&obsa, &olsa); 255 error = copyout(&olsa, SCARG(uap, osa), sizeof(olsa)); 256 if (error) 257 return (error); 258 } 259 return (0); 260} 261 262/* 263 * The Linux signal() system call. I think that the signal() in the C 264 * library actually calls sigaction, so I doubt this one is ever used. 265 * But hey, it can't hurt having it here. The same restrictions as for 266 * sigaction() apply. 267 */ 268int 269linux_sys_signal(p, v, retval) 270 register struct proc *p; 271 void *v; 272 register_t *retval; 273{ 274 struct linux_sys_signal_args /* { 275 syscallarg(int) sig; 276 syscallarg(linux_handler_t) handler; 277 } */ *uap = v; 278 struct sigaction nbsa, obsa; 279 int error; 280 281 nbsa.sa_handler = SCARG(uap, handler); 282 sigemptyset(&nbsa.sa_mask); 283 nbsa.sa_flags = SA_RESETHAND | SA_NODEFER; 284 error = sigaction1(p, linux_to_native_sig[SCARG(uap, sig)], 285 &nbsa, &obsa); 286 if (error) 287 return (error); 288 *retval = (int)obsa.sa_handler; 289 return (0); 290} 291 292int 293linux_sys_sigprocmask(p, v, retval) 294 register struct proc *p; 295 void *v; 296 register_t *retval; 297{ 298 struct linux_sys_sigprocmask_args /* { 299 syscallarg(int) how; 300 syscallarg(const linux_sigset_t *) set; 301 syscallarg(linux_sigset_t *) oset; 302 } */ *uap = v; 303 linux_sigset_t nlss, olss; 304 sigset_t nbss, obss; 305 int how; 306 int error; 307 308 switch (SCARG(uap, how)) { 309 case LINUX_SIG_BLOCK: 310 how = SIG_BLOCK; 311 break; 312 case LINUX_SIG_UNBLOCK: 313 how = SIG_UNBLOCK; 314 break; 315 case LINUX_SIG_SETMASK: 316 how = SIG_SETMASK; 317 break; 318 default: 319 return (EINVAL); 320 } 321 322 if (SCARG(uap, set)) { 323 error = copyin(SCARG(uap, set), &nlss, sizeof(nlss)); 324 if (error) 325 return (error); 326 linux_to_native_sigset(&nlss, &nbss); 327 } 328 error = sigprocmask1(p, how, 329 SCARG(uap, set) ? &nbss : 0, SCARG(uap, oset) ? &obss : 0); 330 if (error) 331 return (error); 332 if (SCARG(uap, oset)) { 333 native_to_linux_sigset(&obss, &olss); 334 error = copyout(&olss, SCARG(uap, oset), sizeof(olss)); 335 if (error) 336 return (error); 337 } 338 return (error); 339} 340 341/* ARGSUSED */ 342int 343linux_sys_siggetmask(p, v, retval) 344 register struct proc *p; 345 void *v; 346 register_t *retval; 347{ 348 sigset_t bss; 349 linux_sigset_t lss; 350 int error; 351 352 error = sigprocmask1(p, SIG_SETMASK, 0, &bss); 353 if (error) 354 return (error); 355 native_to_linux_sigset(&bss, &lss); 356 *retval = lss; 357 return (0); 358} 359 360/* 361 * The following three functions fiddle with a process' signal mask. 362 * Convert the signal masks because of the different signal 363 * values for Linux. The need for this is the reason why 364 * they are here, and have not been mapped directly. 365 */ 366int 367linux_sys_sigsetmask(p, v, retval) 368 register struct proc *p; 369 void *v; 370 register_t *retval; 371{ 372 struct linux_sys_sigsetmask_args /* { 373 syscallarg(linux_sigset_t) mask; 374 } */ *uap = v; 375 sigset_t nbss, obss; 376 linux_sigset_t nlss, olss; 377 int error; 378 379 nlss = SCARG(uap, mask); 380 linux_to_native_sigset(&nlss, &nbss); 381 error = sigprocmask1(p, SIG_SETMASK, &nbss, &obss); 382 if (error) 383 return (error); 384 native_to_linux_sigset(&obss, &olss); 385 *retval = olss; 386 return (0); 387} 388 389int 390linux_sys_sigpending(p, v, retval) 391 register struct proc *p; 392 void *v; 393 register_t *retval; 394{ 395 struct linux_sys_sigpending_args /* { 396 syscallarg(linux_sigset_t *) set; 397 } */ *uap = v; 398 sigset_t bss; 399 linux_sigset_t lss; 400 401 sigpending1(p, &bss); 402 native_to_linux_sigset(&bss, &lss); 403 return copyout(&lss, SCARG(uap, set), sizeof(lss)); 404} 405 406int 407linux_sys_sigsuspend(p, v, retval) 408 register struct proc *p; 409 void *v; 410 register_t *retval; 411{ 412 struct linux_sys_sigsuspend_args /* { 413 syscallarg(caddr_t) restart; 414 syscallarg(int) oldmask; 415 syscallarg(int) mask; 416 } */ *uap = v; 417 linux_sigset_t lss; 418 sigset_t bss; 419 420 lss = SCARG(uap, mask); 421 linux_to_native_sigset(&lss, &bss); 422 return (sigsuspend1(p, &bss)); 423} 424 425/* 426 * The deprecated pause(2), which is really just an instance 427 * of sigsuspend(2). 428 */ 429int 430linux_sys_pause(p, v, retval) 431 register struct proc *p; 432 void *v; 433 register_t *retval; 434{ 435 436 return (sigsuspend1(p, 0)); 437} 438 439/* 440 * Once more: only a signal conversion is needed. 441 */ 442int 443linux_sys_kill(p, v, retval) 444 register struct proc *p; 445 void *v; 446 register_t *retval; 447{ 448 struct linux_sys_kill_args /* { 449 syscallarg(int) pid; 450 syscallarg(int) signum; 451 } */ *uap = v; 452 struct sys_kill_args ka; 453 454 SCARG(&ka, pid) = SCARG(uap, pid); 455 SCARG(&ka, signum) = linux_to_native_sig[SCARG(uap, signum)]; 456 return sys_kill(p, &ka, retval); 457} 458