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/sysproto.h> 34 #include <sys/proc.h> 35 #include <sys/signalvar.h> 36 37 #include <machine/../linux/linux.h> 38 #include <machine/../linux/linux_proto.h> 39 #include <compat/linux/linux_signal.h> 40 #include <compat/linux/linux_util.h> 41 42 void 43 linux_to_bsd_sigset(linux_sigset_t *lss, sigset_t *bss) 44 { 45 int b, l; 46 47 SIGEMPTYSET(*bss); 48 bss->__bits[0] = lss->__bits[0] & ~((1U << LINUX_SIGTBLSZ) - 1); 49 bss->__bits[1] = lss->__bits[1]; 50 for (l = 1; l <= LINUX_SIGTBLSZ; l++) { 51 if (LINUX_SIGISMEMBER(*lss, l)) { 52 #ifdef __alpha__ 53 b = _SIG_IDX(l); 54 #else 55 b = linux_to_bsd_signal[_SIG_IDX(l)]; 56 #endif 57 if (b) 58 SIGADDSET(*bss, b); 59 } 60 } 61 } 62 63 void 64 bsd_to_linux_sigset(sigset_t *bss, linux_sigset_t *lss) 65 { 66 int b, l; 67 68 LINUX_SIGEMPTYSET(*lss); 69 lss->__bits[0] = bss->__bits[0] & ~((1U << LINUX_SIGTBLSZ) - 1); 70 lss->__bits[1] = bss->__bits[1]; 71 for (b = 1; b <= LINUX_SIGTBLSZ; b++) { 72 if (SIGISMEMBER(*bss, b)) { 73 #if __alpha__ 74 l = _SIG_IDX(b); 75 #else 76 l = bsd_to_linux_signal[_SIG_IDX(b)]; 77 #endif 78 if (l) 79 LINUX_SIGADDSET(*lss, l); 80 } 81 } 82 } 83 84 static void 85 linux_to_bsd_sigaction(linux_sigaction_t *lsa, struct sigaction *bsa) 86 { 87 88 linux_to_bsd_sigset(&lsa->lsa_mask, &bsa->sa_mask); 89 bsa->sa_handler = lsa->lsa_handler; 90 bsa->sa_flags = 0; 91 if (lsa->lsa_flags & LINUX_SA_NOCLDSTOP) 92 bsa->sa_flags |= SA_NOCLDSTOP; 93 if (lsa->lsa_flags & LINUX_SA_NOCLDWAIT) 94 bsa->sa_flags |= SA_NOCLDWAIT; 95 if (lsa->lsa_flags & LINUX_SA_SIGINFO) 96 bsa->sa_flags |= SA_SIGINFO; 97 if (lsa->lsa_flags & LINUX_SA_ONSTACK) 98 bsa->sa_flags |= SA_ONSTACK; 99 if (lsa->lsa_flags & LINUX_SA_RESTART) 100 bsa->sa_flags |= SA_RESTART; 101 if (lsa->lsa_flags & LINUX_SA_ONESHOT) 102 bsa->sa_flags |= SA_RESETHAND; 103 if (lsa->lsa_flags & LINUX_SA_NOMASK) 104 bsa->sa_flags |= SA_NODEFER; 105 } 106 107 static void 108 bsd_to_linux_sigaction(struct sigaction *bsa, linux_sigaction_t *lsa) 109 { 110 111 bsd_to_linux_sigset(&bsa->sa_mask, &lsa->lsa_mask); 112 lsa->lsa_handler = bsa->sa_handler; 113 lsa->lsa_restorer = NULL; /* unsupported */ 114 lsa->lsa_flags = 0; 115 if (bsa->sa_flags & SA_NOCLDSTOP) 116 lsa->lsa_flags |= LINUX_SA_NOCLDSTOP; 117 if (bsa->sa_flags & SA_NOCLDWAIT) 118 lsa->lsa_flags |= LINUX_SA_NOCLDWAIT; 119 if (bsa->sa_flags & SA_SIGINFO) 120 lsa->lsa_flags |= LINUX_SA_SIGINFO; 121 if (bsa->sa_flags & SA_ONSTACK) 122 lsa->lsa_flags |= LINUX_SA_ONSTACK; 123 if (bsa->sa_flags & SA_RESTART) 124 lsa->lsa_flags |= LINUX_SA_RESTART; 125 if (bsa->sa_flags & SA_RESETHAND) 126 lsa->lsa_flags |= LINUX_SA_ONESHOT; 127 if (bsa->sa_flags & SA_NODEFER) 128 lsa->lsa_flags |= LINUX_SA_NOMASK; 129 } 130 131 int 132 linux_do_sigaction(struct proc *p, int linux_sig, linux_sigaction_t *linux_nsa, 133 linux_sigaction_t *linux_osa) 134 { 135 struct sigaction *nsa, *osa; 136 struct sigaction_args sa_args; 137 int error; 138 caddr_t sg = stackgap_init(); 139 140 if (linux_sig <= 0 || linux_sig > LINUX_NSIG) 141 return (EINVAL); 142 143 if (linux_osa != NULL) 144 osa = stackgap_alloc(&sg, sizeof(struct sigaction)); 145 else 146 osa = NULL; 147 148 if (linux_nsa != NULL) { 149 nsa = stackgap_alloc(&sg, sizeof(struct sigaction)); 150 linux_to_bsd_sigaction(linux_nsa, nsa); 151 } 152 else 153 nsa = NULL; 154 155 #ifndef __alpha__ 156 if (linux_sig <= LINUX_SIGTBLSZ) 157 sa_args.sig = linux_to_bsd_signal[_SIG_IDX(linux_sig)]; 158 else 159 #endif 160 sa_args.sig = linux_sig; 161 162 sa_args.act = nsa; 163 sa_args.oact = osa; 164 error = sigaction(p, &sa_args); 165 if (error) 166 return (error); 167 168 if (linux_osa != NULL) 169 bsd_to_linux_sigaction(osa, linux_osa); 170 171 return (0); 172 } 173 174 175 #ifndef __alpha__ 176 int 177 linux_signal(struct proc *p, struct linux_signal_args *args) 178 { 179 linux_sigaction_t nsa, osa; 180 int error; 181 182 #ifdef DEBUG 183 printf("Linux-emul(%ld): signal(%d, %p)\n", 184 (long)p->p_pid, args->sig, (void *)args->handler); 185 #endif 186 187 nsa.lsa_handler = args->handler; 188 nsa.lsa_flags = LINUX_SA_ONESHOT | LINUX_SA_NOMASK; 189 LINUX_SIGEMPTYSET(nsa.lsa_mask); 190 191 error = linux_do_sigaction(p, args->sig, &nsa, &osa); 192 p->p_retval[0] = (int)osa.lsa_handler; 193 194 return (error); 195 } 196 #endif /*!__alpha__*/ 197 198 int 199 linux_rt_sigaction(struct proc *p, struct linux_rt_sigaction_args *args) 200 { 201 linux_sigaction_t nsa, osa; 202 int error; 203 204 #ifdef DEBUG 205 printf("Linux-emul(%ld): rt_sigaction(%ld, %p, %p, %ld)\n", 206 (long)p->p_pid, (long)args->sig, (void *)args->act, 207 (void *)args->oact, (long)args->sigsetsize); 208 #endif 209 210 if (args->sigsetsize != sizeof(linux_sigset_t)) 211 return (EINVAL); 212 213 if (args->act != NULL) { 214 error = copyin(args->act, &nsa, sizeof(linux_sigaction_t)); 215 if (error) 216 return (error); 217 } 218 219 error = linux_do_sigaction(p, args->sig, 220 args->act ? &nsa : NULL, 221 args->oact ? &osa : NULL); 222 223 if (args->oact != NULL && !error) { 224 error = copyout(&osa, args->oact, sizeof(linux_sigaction_t)); 225 } 226 227 return (error); 228 } 229 230 static int 231 linux_do_sigprocmask(struct proc *p, int how, linux_sigset_t *new, 232 linux_sigset_t *old) 233 { 234 int error, s; 235 sigset_t mask; 236 237 error = 0; 238 p->p_retval[0] = 0; 239 240 if (old != NULL) 241 bsd_to_linux_sigset(&p->p_sigmask, old); 242 243 if (new != NULL) { 244 linux_to_bsd_sigset(new, &mask); 245 246 s = splhigh(); 247 248 switch (how) { 249 case LINUX_SIG_BLOCK: 250 SIGSETOR(p->p_sigmask, mask); 251 SIG_CANTMASK(p->p_sigmask); 252 break; 253 case LINUX_SIG_UNBLOCK: 254 SIGSETNAND(p->p_sigmask, mask); 255 break; 256 case LINUX_SIG_SETMASK: 257 p->p_sigmask = mask; 258 SIG_CANTMASK(p->p_sigmask); 259 break; 260 default: 261 error = EINVAL; 262 break; 263 } 264 265 splx(s); 266 } 267 268 return (error); 269 } 270 271 #ifndef __alpha__ 272 int 273 linux_sigprocmask(struct proc *p, struct linux_sigprocmask_args *args) 274 { 275 linux_osigset_t mask; 276 linux_sigset_t set, oset; 277 int error; 278 279 #ifdef DEBUG 280 printf("Linux-emul(%d): sigprocmask(%d, *, *)\n", p->p_pid, args->how); 281 #endif 282 283 if (args->mask != NULL) { 284 error = copyin(args->mask, &mask, sizeof(linux_osigset_t)); 285 if (error) 286 return (error); 287 LINUX_SIGEMPTYSET(set); 288 set.__bits[0] = mask; 289 } 290 291 error = linux_do_sigprocmask(p, args->how, 292 args->mask ? &set : NULL, 293 args->omask ? &oset : NULL); 294 295 if (args->omask != NULL && !error) { 296 mask = oset.__bits[0]; 297 error = copyout(&mask, args->omask, sizeof(linux_osigset_t)); 298 } 299 300 return (error); 301 } 302 #endif /*!__alpha__*/ 303 304 int 305 linux_rt_sigprocmask(struct proc *p, struct linux_rt_sigprocmask_args *args) 306 { 307 linux_sigset_t set, oset; 308 int error; 309 310 #ifdef DEBUG 311 printf("Linux-emul(%ld): rt_sigprocmask(%d, %p, %p, %ld)\n", 312 (long)p->p_pid, args->how, (void *)args->mask, 313 (void *)args->omask, (long)args->sigsetsize); 314 #endif 315 316 if (args->sigsetsize != sizeof(linux_sigset_t)) 317 return EINVAL; 318 319 if (args->mask != NULL) { 320 error = copyin(args->mask, &set, sizeof(linux_sigset_t)); 321 if (error) 322 return (error); 323 } 324 325 error = linux_do_sigprocmask(p, args->how, 326 args->mask ? &set : NULL, 327 args->omask ? &oset : NULL); 328 329 if (args->omask != NULL && !error) { 330 error = copyout(&oset, args->omask, sizeof(linux_sigset_t)); 331 } 332 333 return (error); 334 } 335 336 #ifndef __alpha__ 337 int 338 linux_siggetmask(struct proc *p, struct linux_siggetmask_args *args) 339 { 340 linux_sigset_t mask; 341 342 #ifdef DEBUG 343 printf("Linux-emul(%d): siggetmask()\n", p->p_pid); 344 #endif 345 346 bsd_to_linux_sigset(&p->p_sigmask, &mask); 347 p->p_retval[0] = mask.__bits[0]; 348 return (0); 349 } 350 351 int 352 linux_sigsetmask(struct proc *p, struct linux_sigsetmask_args *args) 353 { 354 linux_sigset_t lset; 355 sigset_t bset; 356 int s; 357 358 #ifdef DEBUG 359 printf("Linux-emul(%ld): sigsetmask(%08lx)\n", 360 (long)p->p_pid, (unsigned long)args->mask); 361 #endif 362 363 bsd_to_linux_sigset(&p->p_sigmask, &lset); 364 p->p_retval[0] = lset.__bits[0]; 365 LINUX_SIGEMPTYSET(lset); 366 lset.__bits[0] = args->mask; 367 linux_to_bsd_sigset(&lset, &bset); 368 s = splhigh(); 369 p->p_sigmask = bset; 370 SIG_CANTMASK(p->p_sigmask); 371 splx(s); 372 return (0); 373 } 374 375 int 376 linux_sigpending(struct proc *p, struct linux_sigpending_args *args) 377 { 378 sigset_t bset; 379 linux_sigset_t lset; 380 linux_osigset_t mask; 381 382 #ifdef DEBUG 383 printf("Linux-emul(%d): sigpending(*)\n", p->p_pid); 384 #endif 385 386 bset = p->p_siglist; 387 SIGSETAND(bset, p->p_sigmask); 388 bsd_to_linux_sigset(&bset, &lset); 389 mask = lset.__bits[0]; 390 return (copyout(&mask, args->mask, sizeof(mask))); 391 } 392 #endif /*!__alpha__*/ 393 394 int 395 linux_kill(struct proc *p, struct linux_kill_args *args) 396 { 397 struct kill_args /* { 398 int pid; 399 int signum; 400 } */ tmp; 401 402 #ifdef DEBUG 403 printf("Linux-emul(%d): kill(%d, %d)\n", 404 p->p_pid, args->pid, args->signum); 405 #endif 406 407 /* 408 * Allow signal 0 as a means to check for privileges 409 */ 410 if (args->signum < 0 || args->signum > LINUX_NSIG) 411 return EINVAL; 412 413 #ifndef __alpha__ 414 if (args->signum > 0 && args->signum <= LINUX_SIGTBLSZ) 415 tmp.signum = linux_to_bsd_signal[_SIG_IDX(args->signum)]; 416 else 417 #endif 418 tmp.signum = args->signum; 419 420 tmp.pid = args->pid; 421 return (kill(p, &tmp)); 422 } 423