1 /*- 2 * Copyright (c) 1994-1995 S�ren Schmidt 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer 10 * in this position and unchanged. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. The name of the author may not be used to endorse or promote products 15 * derived from this software withough specific prior written permission 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 * 28 * $FreeBSD$ 29 */ 30 31 #include <sys/param.h> 32 #include <sys/systm.h> 33 #include <sys/lock.h> 34 #include <sys/mutex.h> 35 #include <sys/proc.h> 36 #include <sys/signalvar.h> 37 #include <sys/sysproto.h> 38 39 #include <machine/../linux/linux.h> 40 #include <machine/../linux/linux_proto.h> 41 #include <compat/linux/linux_signal.h> 42 #include <compat/linux/linux_util.h> 43 44 void 45 linux_to_bsd_sigset(l_sigset_t *lss, sigset_t *bss) 46 { 47 int b, l; 48 49 SIGEMPTYSET(*bss); 50 bss->__bits[0] = lss->__bits[0] & ~((1U << LINUX_SIGTBLSZ) - 1); 51 bss->__bits[1] = lss->__bits[1]; 52 for (l = 1; l <= LINUX_SIGTBLSZ; l++) { 53 if (LINUX_SIGISMEMBER(*lss, l)) { 54 #ifdef __alpha__ 55 b = _SIG_IDX(l); 56 #else 57 b = linux_to_bsd_signal[_SIG_IDX(l)]; 58 #endif 59 if (b) 60 SIGADDSET(*bss, b); 61 } 62 } 63 } 64 65 void 66 bsd_to_linux_sigset(sigset_t *bss, l_sigset_t *lss) 67 { 68 int b, l; 69 70 LINUX_SIGEMPTYSET(*lss); 71 lss->__bits[0] = bss->__bits[0] & ~((1U << LINUX_SIGTBLSZ) - 1); 72 lss->__bits[1] = bss->__bits[1]; 73 for (b = 1; b <= LINUX_SIGTBLSZ; b++) { 74 if (SIGISMEMBER(*bss, b)) { 75 #if __alpha__ 76 l = _SIG_IDX(b); 77 #else 78 l = bsd_to_linux_signal[_SIG_IDX(b)]; 79 #endif 80 if (l) 81 LINUX_SIGADDSET(*lss, l); 82 } 83 } 84 } 85 86 static void 87 linux_to_bsd_sigaction(l_sigaction_t *lsa, struct sigaction *bsa) 88 { 89 90 linux_to_bsd_sigset(&lsa->lsa_mask, &bsa->sa_mask); 91 bsa->sa_handler = lsa->lsa_handler; 92 bsa->sa_flags = 0; 93 if (lsa->lsa_flags & LINUX_SA_NOCLDSTOP) 94 bsa->sa_flags |= SA_NOCLDSTOP; 95 if (lsa->lsa_flags & LINUX_SA_NOCLDWAIT) 96 bsa->sa_flags |= SA_NOCLDWAIT; 97 if (lsa->lsa_flags & LINUX_SA_SIGINFO) 98 bsa->sa_flags |= SA_SIGINFO; 99 if (lsa->lsa_flags & LINUX_SA_ONSTACK) 100 bsa->sa_flags |= SA_ONSTACK; 101 if (lsa->lsa_flags & LINUX_SA_RESTART) 102 bsa->sa_flags |= SA_RESTART; 103 if (lsa->lsa_flags & LINUX_SA_ONESHOT) 104 bsa->sa_flags |= SA_RESETHAND; 105 if (lsa->lsa_flags & LINUX_SA_NOMASK) 106 bsa->sa_flags |= SA_NODEFER; 107 } 108 109 static void 110 bsd_to_linux_sigaction(struct sigaction *bsa, l_sigaction_t *lsa) 111 { 112 113 bsd_to_linux_sigset(&bsa->sa_mask, &lsa->lsa_mask); 114 lsa->lsa_handler = bsa->sa_handler; 115 lsa->lsa_restorer = NULL; /* unsupported */ 116 lsa->lsa_flags = 0; 117 if (bsa->sa_flags & SA_NOCLDSTOP) 118 lsa->lsa_flags |= LINUX_SA_NOCLDSTOP; 119 if (bsa->sa_flags & SA_NOCLDWAIT) 120 lsa->lsa_flags |= LINUX_SA_NOCLDWAIT; 121 if (bsa->sa_flags & SA_SIGINFO) 122 lsa->lsa_flags |= LINUX_SA_SIGINFO; 123 if (bsa->sa_flags & SA_ONSTACK) 124 lsa->lsa_flags |= LINUX_SA_ONSTACK; 125 if (bsa->sa_flags & SA_RESTART) 126 lsa->lsa_flags |= LINUX_SA_RESTART; 127 if (bsa->sa_flags & SA_RESETHAND) 128 lsa->lsa_flags |= LINUX_SA_ONESHOT; 129 if (bsa->sa_flags & SA_NODEFER) 130 lsa->lsa_flags |= LINUX_SA_NOMASK; 131 } 132 133 int 134 linux_do_sigaction(struct thread *td, int linux_sig, l_sigaction_t *linux_nsa, 135 l_sigaction_t *linux_osa) 136 { 137 struct sigaction *nsa, *osa; 138 struct sigaction_args sa_args; 139 int error; 140 caddr_t sg = stackgap_init(); 141 142 if (linux_sig <= 0 || linux_sig > LINUX_NSIG) 143 return (EINVAL); 144 145 if (linux_osa != NULL) 146 osa = stackgap_alloc(&sg, sizeof(struct sigaction)); 147 else 148 osa = NULL; 149 150 if (linux_nsa != NULL) { 151 nsa = stackgap_alloc(&sg, sizeof(struct sigaction)); 152 linux_to_bsd_sigaction(linux_nsa, nsa); 153 } 154 else 155 nsa = NULL; 156 157 #ifndef __alpha__ 158 if (linux_sig <= LINUX_SIGTBLSZ) 159 sa_args.sig = linux_to_bsd_signal[_SIG_IDX(linux_sig)]; 160 else 161 #endif 162 sa_args.sig = linux_sig; 163 164 sa_args.act = nsa; 165 sa_args.oact = osa; 166 error = sigaction(td, &sa_args); 167 if (error) 168 return (error); 169 170 if (linux_osa != NULL) 171 bsd_to_linux_sigaction(osa, linux_osa); 172 173 return (0); 174 } 175 176 177 #ifndef __alpha__ 178 int 179 linux_signal(struct thread *td, struct linux_signal_args *args) 180 { 181 l_sigaction_t nsa, osa; 182 int error; 183 184 #ifdef DEBUG 185 if (ldebug(signal)) 186 printf(ARGS(signal, "%d, %p"), 187 args->sig, (void *)args->handler); 188 #endif 189 190 nsa.lsa_handler = args->handler; 191 nsa.lsa_flags = LINUX_SA_ONESHOT | LINUX_SA_NOMASK; 192 LINUX_SIGEMPTYSET(nsa.lsa_mask); 193 194 error = linux_do_sigaction(td, args->sig, &nsa, &osa); 195 td->td_retval[0] = (int)osa.lsa_handler; 196 197 return (error); 198 } 199 #endif /*!__alpha__*/ 200 201 int 202 linux_rt_sigaction(struct thread *td, struct linux_rt_sigaction_args *args) 203 { 204 l_sigaction_t nsa, osa; 205 int error; 206 207 #ifdef DEBUG 208 if (ldebug(rt_sigaction)) 209 printf(ARGS(rt_sigaction, "%ld, %p, %p, %ld"), 210 (long)args->sig, (void *)args->act, 211 (void *)args->oact, (long)args->sigsetsize); 212 #endif 213 214 if (args->sigsetsize != sizeof(l_sigset_t)) 215 return (EINVAL); 216 217 if (args->act != NULL) { 218 error = copyin(args->act, &nsa, sizeof(l_sigaction_t)); 219 if (error) 220 return (error); 221 } 222 223 error = linux_do_sigaction(td, args->sig, 224 args->act ? &nsa : NULL, 225 args->oact ? &osa : NULL); 226 227 if (args->oact != NULL && !error) { 228 error = copyout(&osa, args->oact, sizeof(l_sigaction_t)); 229 } 230 231 return (error); 232 } 233 234 static int 235 linux_do_sigprocmask(struct thread *td, int how, l_sigset_t *new, 236 l_sigset_t *old) 237 { 238 int error; 239 sigset_t mask; 240 struct proc *p = td->td_proc; 241 242 error = 0; 243 td->td_retval[0] = 0; 244 245 PROC_LOCK(p); 246 if (old != NULL) 247 bsd_to_linux_sigset(&p->p_sigmask, old); 248 249 if (new != NULL) { 250 linux_to_bsd_sigset(new, &mask); 251 252 switch (how) { 253 case LINUX_SIG_BLOCK: 254 SIGSETOR(p->p_sigmask, mask); 255 SIG_CANTMASK(p->p_sigmask); 256 break; 257 case LINUX_SIG_UNBLOCK: 258 SIGSETNAND(p->p_sigmask, mask); 259 signotify(p); 260 break; 261 case LINUX_SIG_SETMASK: 262 p->p_sigmask = mask; 263 SIG_CANTMASK(p->p_sigmask); 264 signotify(p); 265 break; 266 default: 267 error = EINVAL; 268 break; 269 } 270 } 271 PROC_UNLOCK(p); 272 273 return (error); 274 } 275 276 #ifndef __alpha__ 277 int 278 linux_sigprocmask(struct thread *td, struct linux_sigprocmask_args *args) 279 { 280 l_osigset_t mask; 281 l_sigset_t set, oset; 282 int error; 283 284 #ifdef DEBUG 285 if (ldebug(sigprocmask)) 286 printf(ARGS(sigprocmask, "%d, *, *"), args->how); 287 #endif 288 289 if (args->mask != NULL) { 290 error = copyin(args->mask, &mask, sizeof(l_osigset_t)); 291 if (error) 292 return (error); 293 LINUX_SIGEMPTYSET(set); 294 set.__bits[0] = mask; 295 } 296 297 error = linux_do_sigprocmask(td, args->how, 298 args->mask ? &set : NULL, 299 args->omask ? &oset : NULL); 300 301 if (args->omask != NULL && !error) { 302 mask = oset.__bits[0]; 303 error = copyout(&mask, args->omask, sizeof(l_osigset_t)); 304 } 305 306 return (error); 307 } 308 #endif /*!__alpha__*/ 309 310 int 311 linux_rt_sigprocmask(struct thread *td, struct linux_rt_sigprocmask_args *args) 312 { 313 l_sigset_t set, oset; 314 int error; 315 316 #ifdef DEBUG 317 if (ldebug(rt_sigprocmask)) 318 printf(ARGS(rt_sigprocmask, "%d, %p, %p, %ld"), 319 args->how, (void *)args->mask, 320 (void *)args->omask, (long)args->sigsetsize); 321 #endif 322 323 if (args->sigsetsize != sizeof(l_sigset_t)) 324 return EINVAL; 325 326 if (args->mask != NULL) { 327 error = copyin(args->mask, &set, sizeof(l_sigset_t)); 328 if (error) 329 return (error); 330 } 331 332 error = linux_do_sigprocmask(td, args->how, 333 args->mask ? &set : NULL, 334 args->omask ? &oset : NULL); 335 336 if (args->omask != NULL && !error) { 337 error = copyout(&oset, args->omask, sizeof(l_sigset_t)); 338 } 339 340 return (error); 341 } 342 343 #ifndef __alpha__ 344 int 345 linux_sgetmask(struct thread *td, struct linux_sgetmask_args *args) 346 { 347 struct proc *p = td->td_proc; 348 l_sigset_t mask; 349 350 #ifdef DEBUG 351 if (ldebug(sgetmask)) 352 printf(ARGS(sgetmask, "")); 353 #endif 354 355 PROC_LOCK(p); 356 bsd_to_linux_sigset(&p->p_sigmask, &mask); 357 PROC_UNLOCK(p); 358 td->td_retval[0] = mask.__bits[0]; 359 return (0); 360 } 361 362 int 363 linux_ssetmask(struct thread *td, struct linux_ssetmask_args *args) 364 { 365 struct proc *p = td->td_proc; 366 l_sigset_t lset; 367 sigset_t bset; 368 369 #ifdef DEBUG 370 if (ldebug(ssetmask)) 371 printf(ARGS(ssetmask, "%08lx"), (unsigned long)args->mask); 372 #endif 373 374 PROC_LOCK(p); 375 bsd_to_linux_sigset(&p->p_sigmask, &lset); 376 td->td_retval[0] = lset.__bits[0]; 377 LINUX_SIGEMPTYSET(lset); 378 lset.__bits[0] = args->mask; 379 linux_to_bsd_sigset(&lset, &bset); 380 p->p_sigmask = bset; 381 SIG_CANTMASK(p->p_sigmask); 382 signotify(p); 383 PROC_UNLOCK(p); 384 return (0); 385 } 386 387 int 388 linux_sigpending(struct thread *td, struct linux_sigpending_args *args) 389 { 390 struct proc *p = td->td_proc; 391 sigset_t bset; 392 l_sigset_t lset; 393 l_osigset_t mask; 394 395 #ifdef DEBUG 396 if (ldebug(sigpending)) 397 printf(ARGS(sigpending, "*")); 398 #endif 399 400 PROC_LOCK(p); 401 bset = p->p_siglist; 402 SIGSETAND(bset, p->p_sigmask); 403 bsd_to_linux_sigset(&bset, &lset); 404 PROC_UNLOCK(p); 405 mask = lset.__bits[0]; 406 return (copyout(&mask, args->mask, sizeof(mask))); 407 } 408 #endif /*!__alpha__*/ 409 410 int 411 linux_kill(struct thread *td, struct linux_kill_args *args) 412 { 413 struct kill_args /* { 414 int pid; 415 int signum; 416 } */ tmp; 417 418 #ifdef DEBUG 419 if (ldebug(kill)) 420 printf(ARGS(kill, "%d, %d"), args->pid, args->signum); 421 #endif 422 423 /* 424 * Allow signal 0 as a means to check for privileges 425 */ 426 if (args->signum < 0 || args->signum > LINUX_NSIG) 427 return EINVAL; 428 429 #ifndef __alpha__ 430 if (args->signum > 0 && args->signum <= LINUX_SIGTBLSZ) 431 tmp.signum = linux_to_bsd_signal[_SIG_IDX(args->signum)]; 432 else 433 #endif 434 tmp.signum = args->signum; 435 436 tmp.pid = args->pid; 437 return (kill(td, &tmp)); 438 } 439