linux_sigaction.c revision 1.12
1/* $NetBSD: linux_sigaction.c,v 1.12 1998/09/11 12:50:09 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 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 if ((lsa->sa_flags & ~LINUX_SA_ALLBITS) != 0) 193/*XXX*/ printf("linux_to_native_sigaction: extra bits ignored\n"); 194 if (lsa->sa_restorer != 0) 195/*XXX*/ printf("linux_to_native_sigaction: sa_restorer ignored\n"); 196} 197 198void 199native_to_linux_sigaction(bsa, lsa) 200 struct sigaction *bsa; 201 struct linux_sigaction *lsa; 202{ 203 204 lsa->sa_handler = bsa->sa_handler; 205 native_to_linux_sigset(&bsa->sa_mask, &lsa->sa_mask); 206 lsa->sa_flags = 0; 207 if ((bsa->sa_flags & SA_NOCLDSTOP) != 0) 208 lsa->sa_flags |= LINUX_SA_NOCLDSTOP; 209 if ((bsa->sa_flags & SA_ONSTACK) != 0) 210 lsa->sa_flags |= LINUX_SA_ONSTACK; 211 if ((bsa->sa_flags & SA_RESTART) != 0) 212 lsa->sa_flags |= LINUX_SA_RESTART; 213 if ((bsa->sa_flags & SA_NODEFER) != 0) 214 lsa->sa_flags |= LINUX_SA_NOMASK; 215 if ((bsa->sa_flags & SA_RESETHAND) != 0) 216 lsa->sa_flags |= LINUX_SA_ONESHOT; 217 lsa->sa_restorer = NULL; 218} 219 220 221/* 222 * The Linux sigaction() system call. Do the usual conversions, 223 * and just call sigaction(). Some flags and values are silently 224 * ignored (see above). 225 */ 226int 227linux_sys_sigaction(p, v, retval) 228 register struct proc *p; 229 void *v; 230 register_t *retval; 231{ 232 struct linux_sys_sigaction_args /* { 233 syscallarg(int) signum; 234 syscallarg(const struct linux_sigaction *) nsa; 235 syscallarg(struct linux_sigaction *) osa; 236 } */ *uap = v; 237 struct linux_sigaction nlsa, olsa; 238 struct sigaction nbsa, obsa; 239 int error; 240 241 if (SCARG(uap, nsa)) { 242 error = copyin(SCARG(uap, nsa), &nlsa, sizeof(nlsa)); 243 if (error) 244 return (error); 245 linux_to_native_sigaction(&nlsa, &nbsa); 246 } 247 error = sigaction1(p, linux_to_native_sig[SCARG(uap, signum)], 248 SCARG(uap, nsa) ? &nbsa : 0, SCARG(uap, osa) ? &obsa : 0); 249 if (error) 250 return (error); 251 if (SCARG(uap, osa)) { 252 native_to_linux_sigaction(&obsa, &olsa); 253 error = copyout(&olsa, SCARG(uap, osa), sizeof(olsa)); 254 if (error) 255 return (error); 256 } 257 return (0); 258} 259 260/* 261 * The Linux signal() system call. I think that the signal() in the C 262 * library actually calls sigaction, so I doubt this one is ever used. 263 * But hey, it can't hurt having it here. The same restrictions as for 264 * sigaction() apply. 265 */ 266int 267linux_sys_signal(p, v, retval) 268 register struct proc *p; 269 void *v; 270 register_t *retval; 271{ 272 struct linux_sys_signal_args /* { 273 syscallarg(int) sig; 274 syscallarg(linux_handler_t) handler; 275 } */ *uap = v; 276 struct sigaction nbsa, obsa; 277 int error; 278 279 nbsa.sa_handler = SCARG(uap, handler); 280 sigemptyset(&nbsa.sa_mask); 281 nbsa.sa_flags = SA_RESETHAND | SA_NODEFER; 282 error = sigaction1(p, linux_to_native_sig[SCARG(uap, sig)], 283 &nbsa, &obsa); 284 if (error) 285 return (error); 286 *retval = (int)obsa.sa_handler; 287 return (0); 288} 289 290int 291linux_sys_sigprocmask(p, v, retval) 292 register struct proc *p; 293 void *v; 294 register_t *retval; 295{ 296 struct linux_sys_sigprocmask_args /* { 297 syscallarg(int) how; 298 syscallarg(const linux_sigset_t *) set; 299 syscallarg(linux_sigset_t *) oset; 300 } */ *uap = v; 301 linux_sigset_t nlss, olss; 302 sigset_t nbss, obss; 303 int how; 304 int error; 305 306 switch (SCARG(uap, how)) { 307 case LINUX_SIG_BLOCK: 308 how = SIG_BLOCK; 309 break; 310 case LINUX_SIG_UNBLOCK: 311 how = SIG_UNBLOCK; 312 break; 313 case LINUX_SIG_SETMASK: 314 how = SIG_SETMASK; 315 break; 316 default: 317 return (EINVAL); 318 } 319 320 if (SCARG(uap, set)) { 321 error = copyin(SCARG(uap, set), &nlss, sizeof(nlss)); 322 if (error) 323 return (error); 324 linux_to_native_sigset(&nlss, &nbss); 325 } 326 error = sigprocmask1(p, how, 327 SCARG(uap, set) ? &nbss : 0, SCARG(uap, oset) ? &obss : 0); 328 if (error) 329 return (error); 330 if (SCARG(uap, oset)) { 331 native_to_linux_sigset(&obss, &olss); 332 error = copyout(&olss, SCARG(uap, oset), sizeof(olss)); 333 if (error) 334 return (error); 335 } 336 return (error); 337} 338 339/* ARGSUSED */ 340int 341linux_sys_siggetmask(p, v, retval) 342 register struct proc *p; 343 void *v; 344 register_t *retval; 345{ 346 sigset_t bss; 347 linux_sigset_t lss; 348 int error; 349 350 error = sigprocmask1(p, SIG_SETMASK, 0, &bss); 351 if (error) 352 return (error); 353 native_to_linux_sigset(&bss, &lss); 354 *retval = lss; 355 return (0); 356} 357 358/* 359 * The following three functions fiddle with a process' signal mask. 360 * Convert the signal masks because of the different signal 361 * values for Linux. The need for this is the reason why 362 * they are here, and have not been mapped directly. 363 */ 364int 365linux_sys_sigsetmask(p, v, retval) 366 register struct proc *p; 367 void *v; 368 register_t *retval; 369{ 370 struct linux_sys_sigsetmask_args /* { 371 syscallarg(linux_sigset_t) mask; 372 } */ *uap = v; 373 sigset_t nbss, obss; 374 linux_sigset_t nlss, olss; 375 int error; 376 377 nlss = SCARG(uap, mask); 378 linux_to_native_sigset(&nlss, &nbss); 379 error = sigprocmask1(p, SIG_SETMASK, &nbss, &obss); 380 if (error) 381 return (error); 382 native_to_linux_sigset(&obss, &olss); 383 *retval = olss; 384 return (0); 385} 386 387int 388linux_sys_sigpending(p, v, retval) 389 register struct proc *p; 390 void *v; 391 register_t *retval; 392{ 393 struct linux_sys_sigpending_args /* { 394 syscallarg(linux_sigset_t *) set; 395 } */ *uap = v; 396 sigset_t bss; 397 linux_sigset_t lss; 398 399 sigpending1(p, &bss); 400 native_to_linux_sigset(&bss, &lss); 401 return copyout(&lss, SCARG(uap, set), sizeof(lss)); 402} 403 404int 405linux_sys_sigsuspend(p, v, retval) 406 register struct proc *p; 407 void *v; 408 register_t *retval; 409{ 410 struct linux_sys_sigsuspend_args /* { 411 syscallarg(caddr_t) restart; 412 syscallarg(int) oldmask; 413 syscallarg(int) mask; 414 } */ *uap = v; 415 linux_sigset_t lss; 416 sigset_t bss; 417 418 lss = SCARG(uap, mask); 419 linux_to_native_sigset(&lss, &bss); 420 return (sigsuspend1(p, &bss)); 421} 422 423/* 424 * The deprecated pause(2), which is really just an instance 425 * of sigsuspend(2). 426 */ 427int 428linux_sys_pause(p, v, retval) 429 register struct proc *p; 430 void *v; 431 register_t *retval; 432{ 433 434 return (sigsuspend1(p, 0)); 435} 436 437/* 438 * Once more: only a signal conversion is needed. 439 */ 440int 441linux_sys_kill(p, v, retval) 442 register struct proc *p; 443 void *v; 444 register_t *retval; 445{ 446 struct linux_sys_kill_args /* { 447 syscallarg(int) pid; 448 syscallarg(int) signum; 449 } */ *uap = v; 450 struct sys_kill_args ka; 451 452 SCARG(&ka, pid) = SCARG(uap, pid); 453 SCARG(&ka, signum) = linux_to_native_sig[SCARG(uap, signum)]; 454 return sys_kill(p, &ka, retval); 455} 456