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