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