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