Home | History | Annotate | Line # | Download | only in common
linux32_signal.c revision 1.3
      1 /*	$NetBSD: linux32_signal.c,v 1.3 2007/03/16 22:21:40 dsl 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 #include <sys/proc.h>
     39 
     40 #include <compat/netbsd32/netbsd32.h>
     41 
     42 #include <compat/linux32/common/linux32_types.h>
     43 #include <compat/linux32/common/linux32_signal.h>
     44 #include <compat/linux32/linux32_syscallargs.h>
     45 
     46 #define linux32_sigemptyset(s)    memset((s), 0, sizeof(*(s)))
     47 #define linux32_sigismember(s, n) ((s)->sig[((n) - 1) / LINUX32__NSIG_BPW]  \
     48 				    & (1 << ((n) - 1) % LINUX32__NSIG_BPW))
     49 #define linux32_sigaddset(s, n)   ((s)->sig[((n) - 1) / LINUX32__NSIG_BPW]  \
     50 				    |= (1 << ((n) - 1) % LINUX32__NSIG_BPW))
     51 
     52 extern const int native_to_linux32_signo[];
     53 extern const int linux32_to_native_signo[];
     54 
     55 void
     56 linux32_to_native_sigset(bss, lss)
     57 	sigset_t *bss;
     58 	const linux32_sigset_t *lss;
     59 {
     60 	int i, newsig;
     61 
     62 	sigemptyset(bss);
     63 	for (i = 1; i < LINUX32__NSIG; i++) {
     64 		if (linux32_sigismember(lss, i)) {
     65 			newsig = linux32_to_native_signo[i];
     66 			if (newsig)
     67 				sigaddset(bss, newsig);
     68 		}
     69 	}
     70 }
     71 
     72 void
     73 native_to_linux32_sigset(lss, bss)
     74 	linux32_sigset_t *lss;
     75 	const sigset_t *bss;
     76 {
     77 	int i, newsig;
     78 
     79 	linux32_sigemptyset(lss);
     80 	for (i = 1; i < NSIG; i++) {
     81 		if (sigismember(bss, i)) {
     82 			newsig = native_to_linux32_signo[i];
     83 			if (newsig)
     84 				linux32_sigaddset(lss, newsig);
     85 		}
     86 	}
     87 }
     88 
     89 unsigned int
     90 native_to_linux32_sigflags(bsf)
     91 	const int bsf;
     92 {
     93 	unsigned int lsf = 0;
     94 	if ((bsf & SA_NOCLDSTOP) != 0)
     95 		lsf |= LINUX32_SA_NOCLDSTOP;
     96 	if ((bsf & SA_NOCLDWAIT) != 0)
     97 		lsf |= LINUX32_SA_NOCLDWAIT;
     98 	if ((bsf & SA_ONSTACK) != 0)
     99 		lsf |= LINUX32_SA_ONSTACK;
    100 	if ((bsf & SA_RESTART) != 0)
    101 		lsf |= LINUX32_SA_RESTART;
    102 	if ((bsf & SA_NODEFER) != 0)
    103 		lsf |= LINUX32_SA_NOMASK;
    104 	if ((bsf & SA_RESETHAND) != 0)
    105 		lsf |= LINUX32_SA_ONESHOT;
    106 	if ((bsf & SA_SIGINFO) != 0)
    107 		lsf |= LINUX32_SA_SIGINFO;
    108 	return lsf;
    109 }
    110 
    111 int
    112 linux32_to_native_sigflags(lsf)
    113 	const unsigned long lsf;
    114 {
    115 	int bsf = 0;
    116 	if ((lsf & LINUX32_SA_NOCLDSTOP) != 0)
    117 		bsf |= SA_NOCLDSTOP;
    118 	if ((lsf & LINUX32_SA_NOCLDWAIT) != 0)
    119 		bsf |= SA_NOCLDWAIT;
    120 	if ((lsf & LINUX32_SA_ONSTACK) != 0)
    121 		bsf |= SA_ONSTACK;
    122 	if ((lsf & LINUX32_SA_RESTART) != 0)
    123 		bsf |= SA_RESTART;
    124 	if ((lsf & LINUX32_SA_ONESHOT) != 0)
    125 		bsf |= SA_RESETHAND;
    126 	if ((lsf & LINUX32_SA_NOMASK) != 0)
    127 		bsf |= SA_NODEFER;
    128 	if ((lsf & LINUX32_SA_SIGINFO) != 0)
    129 		bsf |= SA_SIGINFO;
    130 	if ((lsf & ~LINUX32_SA_ALLBITS) != 0) {
    131 #ifdef DEBUG_LINUX
    132 		printf("linux32_old_to_native_sigflags: "
    133 		    "%lx extra bits ignored\n", lsf);
    134 #endif
    135 	}
    136 	return bsf;
    137 }
    138 
    139 void
    140 linux32_to_native_sigaction(bsa, lsa)
    141 	struct sigaction *bsa;
    142 	const struct linux32_sigaction *lsa;
    143 {
    144 	bsa->sa_handler = NETBSD32PTR64(lsa->linux_sa_handler);
    145 	linux32_to_native_sigset(&bsa->sa_mask, &lsa->linux_sa_mask);
    146 	bsa->sa_flags = linux32_to_native_sigflags(lsa->linux_sa_flags);
    147 }
    148 
    149 void
    150 native_to_linux32_sigaction(lsa, bsa)
    151 	struct linux32_sigaction *lsa;
    152 	const struct sigaction *bsa;
    153 {
    154 	NETBSD32PTR32(lsa->linux_sa_handler, bsa->sa_handler);
    155 	native_to_linux32_sigset(&lsa->linux_sa_mask, &bsa->sa_mask);
    156 	lsa->linux_sa_flags = native_to_linux32_sigflags(bsa->sa_flags);
    157 	NETBSD32PTR32(lsa->linux_sa_restorer, NULL);
    158 }
    159 
    160 void
    161 native_to_linux32_sigaltstack(lss, bss)
    162 	struct linux32_sigaltstack *lss;
    163 	const struct sigaltstack *bss;
    164 {
    165 	NETBSD32PTR32(lss->ss_sp, bss->ss_sp);
    166 	lss->ss_size = bss->ss_size;
    167 	if (bss->ss_flags & SS_ONSTACK)
    168 	    lss->ss_flags = LINUX32_SS_ONSTACK;
    169 	else if (bss->ss_flags & SS_DISABLE)
    170 	    lss->ss_flags = LINUX32_SS_DISABLE;
    171 	else
    172 	    lss->ss_flags = 0;
    173 }
    174 
    175 
    176 void
    177 native_to_linux32_old_sigset(lss, bss)
    178 	linux32_old_sigset_t *lss;
    179 	const sigset_t *bss;
    180 {
    181 	linux32_sigset_t lsnew;
    182 
    183 	native_to_linux32_sigset(&lsnew, bss);
    184 
    185 	/* convert new sigset to old sigset */
    186 	*lss = lsnew.sig[0];
    187 }
    188 
    189 void
    190 linux32_old_to_native_sigset(bss, lss)
    191 	sigset_t *bss;
    192 	const linux32_old_sigset_t *lss;
    193 {
    194 	linux32_sigset_t ls;
    195 
    196 	bzero(&ls, sizeof(ls));
    197 	ls.sig[0] = *lss;
    198 
    199 	linux32_to_native_sigset(bss, &ls);
    200 }
    201 
    202 int
    203 linux32_sys_rt_sigaction(l, v, retval)
    204 	struct lwp *l;
    205 	void *v;
    206 	register_t *retval;
    207 {
    208 	struct linux32_sys_rt_sigaction_args /* {
    209 		syscallarg(int) signum;
    210 		syscallarg(const linux32_sigactionp_t) nsa;
    211 		syscallarg(linux32_sigactionp_t) osa;
    212 		syscallarg(netbsd32_size_t) sigsetsize;
    213 	} */ *uap = v;
    214 	struct linux32_sigaction nls32;
    215 	struct linux32_sigaction ols32;
    216 	struct sigaction ns;
    217 	struct sigaction os;
    218 	int error;
    219 	int sig;
    220 	int vers = 0;
    221 	void *tramp = NULL;
    222 
    223 	if (SCARG(uap, sigsetsize) != sizeof(linux32_sigset_t))
    224 		return EINVAL;
    225 
    226 	if (NETBSD32PTR64(SCARG(uap, nsa)) != NULL) {
    227 		if ((error = copyin(NETBSD32PTR64(SCARG(uap, nsa)),
    228 		    &nls32, sizeof(nls32))) != 0)
    229 			return error;
    230 		linux32_to_native_sigaction(&ns, &nls32);
    231 	}
    232 
    233 	sig = SCARG(uap, signum);
    234 	if (sig < 0 || sig >= LINUX32__NSIG)
    235 		return EINVAL;
    236 	if (sig > 0 && !linux32_to_native_signo[sig]) {
    237 		/* unknown signal... */
    238 		os.sa_handler = SIG_IGN;
    239 		sigemptyset(&os.sa_mask);
    240 		os.sa_flags = 0;
    241 	} else {
    242 		if ((error = sigaction1(l,
    243 		    linux32_to_native_signo[sig],
    244 		    NETBSD32PTR64(SCARG(uap, nsa)) ? &ns : NULL,
    245 		    NETBSD32PTR64(SCARG(uap, osa)) ? &os : NULL,
    246 		    tramp, vers)) != 0)
    247 			return error;
    248 	}
    249 
    250 	if (NETBSD32PTR64(SCARG(uap, osa)) != NULL) {
    251 		native_to_linux32_sigaction(&ols32, &os);
    252 
    253 		if ((error = copyout(&ols32, NETBSD32PTR64(SCARG(uap, osa)),
    254 		    sizeof(ols32))) != 0)
    255 			return error;
    256 	}
    257 
    258 	return 0;
    259 }
    260 
    261 int
    262 linux32_sys_rt_sigprocmask(l, v, retval)
    263 	struct lwp *l;
    264 	void *v;
    265 	register_t *retval;
    266 {
    267 	struct linux32_sys_rt_sigprocmask_args /* {
    268 		syscallarg(int) how;
    269 		syscallarg(const linux32_sigsetp_t) set;
    270 		syscallarg(linux32_sigsetp_t) oset;
    271 		syscallarg(netbsd32_size_t) sigsetsize;
    272 	} */ *uap = v;
    273 	struct proc *p = l->l_proc;
    274 	linux32_sigset_t nls32, ols32;
    275 	sigset_t ns, os;
    276 	int error;
    277 	int how;
    278 
    279 	if (SCARG(uap, sigsetsize) != sizeof(linux32_sigset_t))
    280 		return EINVAL;
    281 
    282 	switch (SCARG(uap, how)) {
    283 	case LINUX32_SIG_BLOCK:
    284 		how = SIG_BLOCK;
    285 		break;
    286 	case LINUX32_SIG_UNBLOCK:
    287 		how = SIG_UNBLOCK;
    288 		break;
    289 	case LINUX32_SIG_SETMASK:
    290 		how = SIG_SETMASK;
    291 		break;
    292 	default:
    293 		return EINVAL;
    294 		break;
    295 	}
    296 
    297 	if (NETBSD32PTR64(SCARG(uap, set)) != NULL) {
    298 		if ((error = copyin(NETBSD32PTR64(SCARG(uap, set)),
    299 		    &nls32, sizeof(nls32))) != 0)
    300 			return error;
    301 		linux32_to_native_sigset(&ns, &nls32);
    302 	}
    303 
    304 	mutex_enter(&p->p_smutex);
    305 	error = sigprocmask1(l, how,
    306 	    NETBSD32PTR64(SCARG(uap, set)) ? &ns : NULL,
    307 	    NETBSD32PTR64(SCARG(uap, oset)) ? &os : NULL);
    308 	mutex_exit(&p->p_smutex);
    309 
    310         if (error != 0)
    311 		return error;
    312 
    313 	if (NETBSD32PTR64(SCARG(uap, oset)) != NULL) {
    314 		native_to_linux32_sigset(&ols32, &os);
    315 		if ((error = copyout(&ols32,
    316 		    NETBSD32PTR64(SCARG(uap, oset)), sizeof(ols32))) != 0)
    317 			return error;
    318 	}
    319 
    320 	return 0;
    321 }
    322 
    323 int
    324 linux32_sys_kill(l, v, retval)
    325 	struct lwp *l;
    326 	void *v;
    327 	register_t *retval;
    328 {
    329 	struct linux32_sys_kill_args /* {
    330 		syscallarg(int) pid;
    331 		syscallarg(int) signum;
    332 	} */ *uap = v;
    333 
    334 	struct sys_kill_args ka;
    335 	int sig;
    336 
    337 	SCARG(&ka, pid) = SCARG(uap, pid);
    338 	sig = SCARG(uap, signum);
    339 	if (sig < 0 || sig >= LINUX32__NSIG)
    340 		return (EINVAL);
    341 	SCARG(&ka, signum) = linux32_to_native_signo[sig];
    342 	return sys_kill(l, &ka, retval);
    343 }
    344 
    345 int
    346 linux32_sys_rt_sigsuspend(l, v, retval)
    347 	struct lwp *l;
    348 	void *v;
    349 	register_t *retval;
    350 {
    351 	struct linux32_sys_rt_sigsuspend_args /* {
    352 		syscallarg(linux32_sigsetp_t) unewset;
    353                 syscallarg(netbsd32_size_t) sigsetsize;
    354 	} */ *uap = v;
    355 	linux32_sigset_t lss;
    356 	sigset_t bss;
    357 	int error;
    358 
    359 	if (SCARG(uap, sigsetsize) != sizeof(linux32_sigset_t))
    360 		return EINVAL;
    361 
    362 	if ((error = copyin(NETBSD32PTR64(SCARG(uap, unewset)),
    363 	    &lss, sizeof(linux32_sigset_t))) != 0)
    364 		return error;
    365 
    366 	linux32_to_native_sigset(&bss, &lss);
    367 
    368 	return sigsuspend1(l, &bss);
    369 }
    370 
    371 int
    372 linux32_sys_signal(l, v, retval)
    373 	struct lwp *l;
    374 	void *v;
    375 	register_t *retval;
    376 {
    377 	struct linux32_sys_signal_args /* {
    378 		syscallarg(int) signum;
    379 		syscallarg(linux32_handler_t) handler;
    380 	} */ *uap = v;
    381         struct sigaction nbsa, obsa;
    382         int error, sig;
    383 
    384         *retval = -1;
    385 
    386         sig = SCARG(uap, signum);
    387         if (sig < 0 || sig >= LINUX32__NSIG)
    388                 return EINVAL;
    389 
    390         nbsa.sa_handler = NETBSD32PTR64(SCARG(uap, handler));
    391         sigemptyset(&nbsa.sa_mask);
    392         nbsa.sa_flags = SA_RESETHAND | SA_NODEFER;
    393 
    394         if ((error = sigaction1(l, linux32_to_native_signo[sig],
    395             &nbsa, &obsa, NULL, 0)) != 0)
    396 		return error;
    397 
    398         *retval = (int)(long)obsa.sa_handler;
    399         return 0;
    400 }
    401