Home | History | Annotate | Line # | Download | only in common
linux32_signal.c revision 1.1.10.2
      1 /*	$NetBSD: linux32_signal.c,v 1.1.10.2 2006/04/22 11:38:14 simonb Exp $ */
      2 
      3 /*-
      4  * Copyright (c) 2006 Emmanuel Dreyfus, all rights reserved.
      5  *
      6  * Redistribution and use in source and binary forms, with or without
      7  * modification, are permitted provided that the following conditions
      8  * are met:
      9  * 1. Redistributions of source code must retain the above copyright
     10  *    notice, this list of conditions and the following disclaimer.
     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. All advertising materials mentioning features or use of this software
     15  *    must display the following acknowledgement:
     16  *	This product includes software developed by Emmanuel Dreyfus
     17  * 4. The name of the author may not be used to endorse or promote
     18  *    products derived from this software without specific prior written
     19  *    permission.
     20  *
     21  * THIS SOFTWARE IS PROVIDED BY THE THE AUTHOR AND CONTRIBUTORS ``AS IS''
     22  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
     23  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     24  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS
     25  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     26  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     27  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     28  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     29  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     30  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     31  * POSSIBILITY OF SUCH DAMAGE.
     32  */
     33 #include <sys/param.h>
     34 #include <sys/ucred.h>
     35 #include <sys/signalvar.h>
     36 #include <sys/lwp.h>
     37 #include <sys/time.h>
     38 
     39 #include <compat/netbsd32/netbsd32.h>
     40 
     41 #include <compat/linux32/common/linux32_types.h>
     42 #include <compat/linux32/common/linux32_signal.h>
     43 #include <compat/linux32/linux32_syscallargs.h>
     44 
     45 #define linux32_sigemptyset(s)    memset((s), 0, sizeof(*(s)))
     46 #define linux32_sigismember(s, n) ((s)->sig[((n) - 1) / LINUX32__NSIG_BPW]  \
     47 				    & (1 << ((n) - 1) % LINUX32__NSIG_BPW))
     48 #define linux32_sigaddset(s, n)   ((s)->sig[((n) - 1) / LINUX32__NSIG_BPW]  \
     49 				    |= (1 << ((n) - 1) % LINUX32__NSIG_BPW))
     50 
     51 extern const int native_to_linux32_signo[];
     52 extern const int linux32_to_native_signo[];
     53 
     54 void
     55 linux32_to_native_sigset(bss, lss)
     56 	sigset_t *bss;
     57 	const linux32_sigset_t *lss;
     58 {
     59 	int i, newsig;
     60 
     61 	sigemptyset(bss);
     62 	for (i = 1; i < LINUX32__NSIG; i++) {
     63 		if (linux32_sigismember(lss, i)) {
     64 			newsig = linux32_to_native_signo[i];
     65 			if (newsig)
     66 				sigaddset(bss, newsig);
     67 		}
     68 	}
     69 }
     70 
     71 void
     72 native_to_linux32_sigset(lss, bss)
     73 	linux32_sigset_t *lss;
     74 	const sigset_t *bss;
     75 {
     76 	int i, newsig;
     77 
     78 	linux32_sigemptyset(lss);
     79 	for (i = 1; i < NSIG; i++) {
     80 		if (sigismember(bss, i)) {
     81 			newsig = native_to_linux32_signo[i];
     82 			if (newsig)
     83 				linux32_sigaddset(lss, newsig);
     84 		}
     85 	}
     86 }
     87 
     88 unsigned int
     89 native_to_linux32_sigflags(bsf)
     90 	const int bsf;
     91 {
     92 	unsigned int lsf = 0;
     93 	if ((bsf & SA_NOCLDSTOP) != 0)
     94 		lsf |= LINUX32_SA_NOCLDSTOP;
     95 	if ((bsf & SA_NOCLDWAIT) != 0)
     96 		lsf |= LINUX32_SA_NOCLDWAIT;
     97 	if ((bsf & SA_ONSTACK) != 0)
     98 		lsf |= LINUX32_SA_ONSTACK;
     99 	if ((bsf & SA_RESTART) != 0)
    100 		lsf |= LINUX32_SA_RESTART;
    101 	if ((bsf & SA_NODEFER) != 0)
    102 		lsf |= LINUX32_SA_NOMASK;
    103 	if ((bsf & SA_RESETHAND) != 0)
    104 		lsf |= LINUX32_SA_ONESHOT;
    105 	if ((bsf & SA_SIGINFO) != 0)
    106 		lsf |= LINUX32_SA_SIGINFO;
    107 	return lsf;
    108 }
    109 
    110 int
    111 linux32_to_native_sigflags(lsf)
    112 	const unsigned long lsf;
    113 {
    114 	int bsf = 0;
    115 	if ((lsf & LINUX32_SA_NOCLDSTOP) != 0)
    116 		bsf |= SA_NOCLDSTOP;
    117 	if ((lsf & LINUX32_SA_NOCLDWAIT) != 0)
    118 		bsf |= SA_NOCLDWAIT;
    119 	if ((lsf & LINUX32_SA_ONSTACK) != 0)
    120 		bsf |= SA_ONSTACK;
    121 	if ((lsf & LINUX32_SA_RESTART) != 0)
    122 		bsf |= SA_RESTART;
    123 	if ((lsf & LINUX32_SA_ONESHOT) != 0)
    124 		bsf |= SA_RESETHAND;
    125 	if ((lsf & LINUX32_SA_NOMASK) != 0)
    126 		bsf |= SA_NODEFER;
    127 	if ((lsf & LINUX32_SA_SIGINFO) != 0)
    128 		bsf |= SA_SIGINFO;
    129 	if ((lsf & ~LINUX32_SA_ALLBITS) != 0) {
    130 #ifdef DEBUG_LINUX
    131 		printf("linux32_old_to_native_sigflags: "
    132 		    "%lx extra bits ignored\n", lsf);
    133 #endif
    134 	}
    135 	return bsf;
    136 }
    137 
    138 void
    139 linux32_to_native_sigaction(bsa, lsa)
    140 	struct sigaction *bsa;
    141 	const struct linux32_sigaction *lsa;
    142 {
    143 	bsa->sa_handler = NETBSD32PTR64(lsa->linux_sa_handler);
    144 	linux32_to_native_sigset(&bsa->sa_mask, &lsa->linux_sa_mask);
    145 	bsa->sa_flags = linux32_to_native_sigflags(lsa->linux_sa_flags);
    146 }
    147 
    148 void
    149 native_to_linux32_sigaction(lsa, bsa)
    150 	struct linux32_sigaction *lsa;
    151 	const struct sigaction *bsa;
    152 {
    153 	lsa->linux_sa_handler = (linux32_handler_t)(long)bsa->sa_handler;
    154 	native_to_linux32_sigset(&lsa->linux_sa_mask, &bsa->sa_mask);
    155 	lsa->linux_sa_flags = native_to_linux32_sigflags(bsa->sa_flags);
    156 	lsa->linux_sa_restorer = (linux32_restorer_t)NULL;
    157 }
    158 
    159 void
    160 native_to_linux32_sigaltstack(lss, bss)
    161 	struct linux32_sigaltstack *lss;
    162 	const struct sigaltstack *bss;
    163 {
    164 	lss->ss_sp = (netbsd32_voidp)(long)bss->ss_sp;
    165 	lss->ss_size = bss->ss_size;
    166 	if (bss->ss_flags & SS_ONSTACK)
    167 	    lss->ss_flags = LINUX32_SS_ONSTACK;
    168 	else if (bss->ss_flags & SS_DISABLE)
    169 	    lss->ss_flags = LINUX32_SS_DISABLE;
    170 	else
    171 	    lss->ss_flags = 0;
    172 }
    173 
    174 
    175 void
    176 native_to_linux32_old_sigset(lss, bss)
    177 	linux32_old_sigset_t *lss;
    178 	const sigset_t *bss;
    179 {
    180 	linux32_sigset_t lsnew;
    181 
    182 	native_to_linux32_sigset(&lsnew, bss);
    183 
    184 	/* convert new sigset to old sigset */
    185 	*lss = lsnew.sig[0];
    186 }
    187 
    188 void
    189 linux32_old_to_native_sigset(bss, lss)
    190 	sigset_t *bss;
    191 	const linux32_old_sigset_t *lss;
    192 {
    193 	linux32_sigset_t ls;
    194 
    195 	bzero(&ls, sizeof(ls));
    196 	ls.sig[0] = *lss;
    197 
    198 	linux32_to_native_sigset(bss, &ls);
    199 }
    200 
    201 int
    202 linux32_sys_rt_sigaction(l, v, retval)
    203 	struct lwp *l;
    204 	void *v;
    205 	register_t *retval;
    206 {
    207 	struct linux32_sys_rt_sigaction_args /* {
    208 		syscallarg(int) signum;
    209 		syscallarg(const linux32_sigactionp_t) nsa;
    210 		syscallarg(linux32_sigactionp_t) osa;
    211 		syscallarg(netbsd32_size_t) sigsetsize;
    212 	} */ *uap = v;
    213 	struct linux32_sigaction nls32;
    214 	struct linux32_sigaction ols32;
    215 	struct sigaction ns;
    216 	struct sigaction os;
    217 	int error;
    218 	int sig;
    219 	int vers = 0;
    220 	void *tramp = NULL;
    221 
    222 	if (SCARG(uap, sigsetsize) != sizeof(linux32_sigset_t))
    223 		return EINVAL;
    224 
    225 	if (NETBSD32PTR64(SCARG(uap, nsa)) != NULL) {
    226 		if ((error = copyin(NETBSD32PTR64(SCARG(uap, nsa)),
    227 		    &nls32, sizeof(nls32))) != 0)
    228 			return error;
    229 		linux32_to_native_sigaction(&ns, &nls32);
    230 	}
    231 
    232 	sig = SCARG(uap, signum);
    233 	if (sig < 0 || sig >= LINUX32__NSIG)
    234 		return EINVAL;
    235 	if (sig > 0 && !linux32_to_native_signo[sig]) {
    236 		/* unknown signal... */
    237 		os.sa_handler = SIG_IGN;
    238 		sigemptyset(&os.sa_mask);
    239 		os.sa_flags = 0;
    240 	} else {
    241 		if ((error = sigaction1(l->l_proc,
    242 		    linux32_to_native_signo[sig],
    243 		    NETBSD32PTR64(SCARG(uap, nsa)) ? &ns : NULL,
    244 		    NETBSD32PTR64(SCARG(uap, osa)) ? &os : NULL,
    245 		    tramp, vers)) != 0)
    246 			return error;
    247 	}
    248 
    249 	if (NETBSD32PTR64(SCARG(uap, osa)) != NULL) {
    250 		native_to_linux32_sigaction(&ols32, &os);
    251 
    252 		if ((error = copyout(&ols32, NETBSD32PTR64(SCARG(uap, osa)),
    253 		    sizeof(ols32))) != 0)
    254 			return error;
    255 	}
    256 
    257 	return 0;
    258 }
    259 
    260 int
    261 linux32_sys_rt_sigprocmask(l, v, retval)
    262 	struct lwp *l;
    263 	void *v;
    264 	register_t *retval;
    265 {
    266 	struct linux32_sys_rt_sigprocmask_args /* {
    267 		syscallarg(int) how;
    268 		syscallarg(const linux32_sigsetp_t) set;
    269 		syscallarg(linux32_sigsetp_t) oset;
    270 		syscallarg(netbsd32_size_t) sigsetsize;
    271 	} */ *uap = v;
    272 	struct proc *p = l->l_proc;
    273 	linux32_sigset_t nls32, ols32;
    274 	sigset_t ns, os;
    275 	int error;
    276 	int how;
    277 
    278 	if (SCARG(uap, sigsetsize) != sizeof(linux32_sigset_t))
    279 		return EINVAL;
    280 
    281 	switch (SCARG(uap, how)) {
    282 	case LINUX32_SIG_BLOCK:
    283 		how = SIG_BLOCK;
    284 		break;
    285 	case LINUX32_SIG_UNBLOCK:
    286 		how = SIG_UNBLOCK;
    287 		break;
    288 	case LINUX32_SIG_SETMASK:
    289 		how = SIG_SETMASK;
    290 		break;
    291 	default:
    292 		return EINVAL;
    293 		break;
    294 	}
    295 
    296 	if (NETBSD32PTR64(SCARG(uap, set)) != NULL) {
    297 		if ((error = copyin(NETBSD32PTR64(SCARG(uap, set)),
    298 		    &nls32, sizeof(nls32))) != 0)
    299 			return error;
    300 		linux32_to_native_sigset(&ns, &nls32);
    301 	}
    302 
    303 	if ((error = sigprocmask1(p, how,
    304 	    NETBSD32PTR64(SCARG(uap, set)) ? &ns : NULL,
    305 	    NETBSD32PTR64(SCARG(uap, oset)) ? &os : NULL)) != 0)
    306 		return error;
    307 
    308 	if (NETBSD32PTR64(SCARG(uap, oset)) != NULL) {
    309 		native_to_linux32_sigset(&ols32, &os);
    310 		if ((error = copyout(&ols32,
    311 		    NETBSD32PTR64(SCARG(uap, oset)), sizeof(ols32))) != 0)
    312 			return error;
    313 	}
    314 
    315 	return 0;
    316 }
    317 
    318 int
    319 linux32_sys_kill(l, v, retval)
    320 	struct lwp *l;
    321 	void *v;
    322 	register_t *retval;
    323 {
    324 	struct linux32_sys_kill_args /* {
    325 		syscallarg(int) pid;
    326 		syscallarg(int) signum;
    327 	} */ *uap = v;
    328 
    329 	struct sys_kill_args ka;
    330 	int sig;
    331 
    332 	SCARG(&ka, pid) = SCARG(uap, pid);
    333 	sig = SCARG(uap, signum);
    334 	if (sig < 0 || sig >= LINUX32__NSIG)
    335 		return (EINVAL);
    336 	SCARG(&ka, signum) = linux32_to_native_signo[sig];
    337 	return sys_kill(l, &ka, retval);
    338 }
    339 
    340 int
    341 linux32_sys_rt_sigsuspend(l, v, retval)
    342 	struct lwp *l;
    343 	void *v;
    344 	register_t *retval;
    345 {
    346 	struct linux32_sys_rt_sigsuspend_args /* {
    347 		syscallarg(linux32_sigsetp_t) unewset;
    348                 syscallarg(netbsd32_size_t) sigsetsize;
    349 	} */ *uap = v;
    350 	linux32_sigset_t lss;
    351 	sigset_t bss;
    352 	int error;
    353 
    354 	if (SCARG(uap, sigsetsize) != sizeof(linux32_sigset_t))
    355 		return EINVAL;
    356 
    357 	if ((error = copyin(NETBSD32PTR64(SCARG(uap, unewset)),
    358 	    &lss, sizeof(linux32_sigset_t))) != 0)
    359 		return error;
    360 
    361 	linux32_to_native_sigset(&bss, &lss);
    362 
    363 	return sigsuspend1(l->l_proc, &bss);
    364 }
    365 
    366 int
    367 linux32_sys_signal(l, v, retval)
    368 	struct lwp *l;
    369 	void *v;
    370 	register_t *retval;
    371 {
    372 	struct linux32_sys_signal_args /* {
    373 		syscallarg(int) signum;
    374 		syscallarg(linux32_handler_t) handler;
    375 	} */ *uap = v;
    376         struct proc *p = l->l_proc;
    377         struct sigaction nbsa, obsa;
    378         int error, sig;
    379 
    380         *retval = -1;
    381 
    382         sig = SCARG(uap, signum);
    383         if (sig < 0 || sig >= LINUX32__NSIG)
    384                 return EINVAL;
    385 
    386         nbsa.sa_handler = NETBSD32PTR64(SCARG(uap, handler));
    387         sigemptyset(&nbsa.sa_mask);
    388         nbsa.sa_flags = SA_RESETHAND | SA_NODEFER;
    389 
    390         if ((error = sigaction1(p, linux32_to_native_signo[sig],
    391             &nbsa, &obsa, NULL, 0)) != 0)
    392 		return error;
    393 
    394         *retval = (int)(long)obsa.sa_handler;
    395         return 0;
    396 }
    397