diff options
author | marcel <marcel@FreeBSD.org> | 1999-08-14 17:28:46 +0000 |
---|---|---|
committer | marcel <marcel@FreeBSD.org> | 1999-08-14 17:28:46 +0000 |
commit | 195c2867a7981b012681e6b20ea15c73c451b503 (patch) | |
tree | accd80df8d7633ca8b19237e620cdd355e233dcc /sys/i386/linux | |
parent | ac3a4d6b97e4fdfa5ef88b63c02630ab97d7e175 (diff) | |
download | FreeBSD-src-195c2867a7981b012681e6b20ea15c73c451b503.zip FreeBSD-src-195c2867a7981b012681e6b20ea15c73c451b503.tar.gz |
Implementation of linux_rt_sigaction and linux_rt_sigprocmask syscalls. Both
functions use the new sigset_t and sigaction_t which allows support for more
than 32 signals. Only the lower 32 signals are supported for now.
linux_rt_sigaction, linux_sigaction and linux_signal use linux_do_sigaction
to do the actual work. That way unnecessary redundancy is avoided. The same
has been done for linux_rt_sigprocmask and linux_sigprocmask. They call
linux_do_sigprocmask to do the actual work.
Diffstat (limited to 'sys/i386/linux')
-rw-r--r-- | sys/i386/linux/linux.h | 16 | ||||
-rw-r--r-- | sys/i386/linux/linux_proto.h | 16 | ||||
-rw-r--r-- | sys/i386/linux/linux_signal.c | 291 | ||||
-rw-r--r-- | sys/i386/linux/linux_syscall.h | 4 | ||||
-rw-r--r-- | sys/i386/linux/linux_sysent.c | 6 |
5 files changed, 252 insertions, 81 deletions
diff --git a/sys/i386/linux/linux.h b/sys/i386/linux/linux.h index 03f9e16..d4cf410 100644 --- a/sys/i386/linux/linux.h +++ b/sys/i386/linux/linux.h @@ -25,7 +25,7 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * $Id: linux.h,v 1.31 1999/08/11 13:34:29 marcel Exp $ + * $Id: linux.h,v 1.32 1999/08/13 14:44:13 marcel Exp $ */ #ifndef _I386_LINUX_LINUX_H_ @@ -57,6 +57,17 @@ typedef struct { } linux_sigaction_t; typedef int linux_key_t; +typedef struct { + unsigned long sig[2]; +} linux_new_sigset_t; +typedef struct { + void (*lsa_handler)(int); + unsigned long lsa_flags; + void (*lsa_restorer)(void); + linux_new_sigset_t lsa_mask; +} linux_new_sigaction_t; + + /* * The Linux sigcontext, pretty much a standard 386 trapframe. */ @@ -154,6 +165,9 @@ struct trapframe; /* sigaction flags */ #define LINUX_SA_NOCLDSTOP 0x00000001 +#define LINUX_SA_NOCLDWAIT 0x00000002 +#define LINUX_SA_SIGINFO 0x00000004 +#define LINUX_SA_RESTORER 0x04000000 #define LINUX_SA_ONSTACK 0x08000000 #define LINUX_SA_RESTART 0x10000000 #define LINUX_SA_INTERRUPT 0x20000000 diff --git a/sys/i386/linux/linux_proto.h b/sys/i386/linux/linux_proto.h index 0729eee..78b66e8 100644 --- a/sys/i386/linux/linux_proto.h +++ b/sys/i386/linux/linux_proto.h @@ -2,7 +2,7 @@ * System call prototypes. * * DO NOT EDIT-- this file is automatically generated. - * created from Id: syscalls.master,v 1.18 1999/08/12 19:51:03 marcel Exp + * created from Id: syscalls.master,v 1.19 1999/08/14 17:14:13 marcel Exp */ #ifndef _LINUX_SYSPROTO_H_ @@ -394,6 +394,18 @@ struct linux_mremap_args { int new_len; char new_len_[PAD_(int)]; int flags; char flags_[PAD_(int)]; }; +struct linux_rt_sigaction_args { + int sig; char sig_[PAD_(int)]; + struct linux_new_sigaction * act; char act_[PAD_(struct linux_new_sigaction *)]; + struct linux_new_sigaction * oact; char oact_[PAD_(struct linux_new_sigaction *)]; + size_t sigsetsize; char sigsetsize_[PAD_(size_t)]; +}; +struct linux_rt_sigprocmask_args { + int how; char how_[PAD_(int)]; + struct linux_new_sigset * mask; char mask_[PAD_(struct linux_new_sigset *)]; + struct linux_new_sigset * omask; char omask_[PAD_(struct linux_new_sigset *)]; + size_t sigsetsize; char sigsetsize_[PAD_(size_t)]; +}; struct linux_chown_args { char * path; char path_[PAD_(char *)]; int uid; char uid_[PAD_(int)]; @@ -499,6 +511,8 @@ int linux_getdents __P((struct proc *, struct linux_getdents_args *)); int linux_newselect __P((struct proc *, struct linux_newselect_args *)); int linux_msync __P((struct proc *, struct linux_msync_args *)); int linux_mremap __P((struct proc *, struct linux_mremap_args *)); +int linux_rt_sigaction __P((struct proc *, struct linux_rt_sigaction_args *)); +int linux_rt_sigprocmask __P((struct proc *, struct linux_rt_sigprocmask_args *)); int linux_chown __P((struct proc *, struct linux_chown_args *)); #ifdef COMPAT_43 diff --git a/sys/i386/linux/linux_signal.c b/sys/i386/linux/linux_signal.c index 191c13c..29b5c4c 100644 --- a/sys/i386/linux/linux_signal.c +++ b/sys/i386/linux/linux_signal.c @@ -25,7 +25,7 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * $Id: linux_signal.c,v 1.15 1999/05/06 18:44:26 peter Exp $ + * $Id: linux_signal.c,v 1.16 1999/07/06 06:54:00 cracauer Exp $ */ #include <sys/param.h> @@ -74,6 +74,10 @@ linux_to_bsd_sigaction(linux_sigaction_t *lsa, struct sigaction *bsa) bsa->sa_flags = 0; if (lsa->lsa_flags & LINUX_SA_NOCLDSTOP) bsa->sa_flags |= SA_NOCLDSTOP; + if (lsa->lsa_flags & LINUX_SA_NOCLDWAIT) + bsa->sa_flags |= SA_NOCLDWAIT; + if (lsa->lsa_flags & LINUX_SA_SIGINFO) + bsa->sa_flags |= SA_SIGINFO; if (lsa->lsa_flags & LINUX_SA_ONSTACK) bsa->sa_flags |= SA_ONSTACK; if (lsa->lsa_flags & LINUX_SA_RESTART) @@ -93,6 +97,10 @@ bsd_to_linux_sigaction(struct sigaction *bsa, linux_sigaction_t *lsa) lsa->lsa_flags = 0; if (bsa->sa_flags & SA_NOCLDSTOP) lsa->lsa_flags |= LINUX_SA_NOCLDSTOP; + if (bsa->sa_flags & SA_NOCLDWAIT) + lsa->lsa_flags |= LINUX_SA_NOCLDWAIT; + if (bsa->sa_flags & SA_SIGINFO) + lsa->lsa_flags |= LINUX_SA_SIGINFO; if (bsa->sa_flags & SA_ONSTACK) lsa->lsa_flags |= LINUX_SA_ONSTACK; if (bsa->sa_flags & SA_RESTART) @@ -103,134 +111,267 @@ bsd_to_linux_sigaction(struct sigaction *bsa, linux_sigaction_t *lsa) lsa->lsa_flags |= LINUX_SA_NOMASK; } +static int +linux_do_sigaction(struct proc *p, int linux_sig, linux_sigaction_t *linux_nsa, + linux_sigaction_t *linux_osa) +{ + struct sigaction *nsa, *osa, sa; + struct sigaction_args sa_args; + int error; + caddr_t sg = stackgap_init(); + + if (linux_sig <= 0 || linux_sig >= LINUX_NSIG) + return EINVAL; + + if (linux_osa) + osa = stackgap_alloc(&sg, sizeof(struct sigaction)); + else + osa = NULL; + + if (linux_nsa) { + nsa = stackgap_alloc(&sg, sizeof(struct sigaction)); + linux_to_bsd_sigaction(linux_nsa, &sa); + error = copyout(&sa, nsa, sizeof(struct sigaction)); + if (error) + return error; + } + else + nsa = NULL; + + sa_args.signum = linux_to_bsd_signal[linux_sig]; + sa_args.nsa = nsa; + sa_args.osa = osa; + error = sigaction(p, &sa_args); + if (error) + return error; + + if (linux_osa) { + error = copyin(osa, &sa, sizeof(struct sigaction)); + if (error) + return error; + bsd_to_linux_sigaction(&sa, linux_osa); + } + + return 0; +} + int linux_sigaction(struct proc *p, struct linux_sigaction_args *args) { - linux_sigaction_t linux_sa; - struct sigaction *nsa = NULL, *osa = NULL, bsd_sa; - struct sigaction_args sa; + linux_sigaction_t nsa, osa; int error; - caddr_t sg = stackgap_init(); - + #ifdef DEBUG printf("Linux-emul(%ld): sigaction(%d, %p, %p)\n", - (long)p->p_pid, args->sig, (void *)args->nsa, (void *)args->osa); + (long)p->p_pid, args->sig, (void *)args->nsa, (void *)args->osa); #endif - if (args->sig <= 0 || args->sig >= LINUX_NSIG) - return EINVAL; - if (args->osa) - osa = (struct sigaction *)stackgap_alloc(&sg, sizeof(struct sigaction)); if (args->nsa) { - nsa = (struct sigaction *)stackgap_alloc(&sg, sizeof(struct sigaction)); - error = copyin(args->nsa, &linux_sa, sizeof(linux_sigaction_t)); - if (error) - return error; - linux_to_bsd_sigaction(&linux_sa, &bsd_sa); - error = copyout(&bsd_sa, nsa, sizeof(struct sigaction)); + error = copyin(args->nsa, &nsa, sizeof(linux_sigaction_t)); if (error) return error; } - sa.signum = linux_to_bsd_signal[args->sig]; - sa.nsa = nsa; - sa.osa = osa; - error = sigaction(p, &sa); + + error = linux_do_sigaction(p, args->sig, + args->nsa ? &nsa : NULL, + args->osa ? &osa : NULL); if (error) return error; if (args->osa) { - error = copyin(osa, &bsd_sa, sizeof(struct sigaction)); - if (error) - return error; - bsd_to_linux_sigaction(&bsd_sa, &linux_sa); - error = copyout(&linux_sa, args->osa, sizeof(linux_sigaction_t)); + error = copyout(&osa, args->osa, sizeof(linux_sigaction_t)); if (error) return error; } + return 0; } int linux_signal(struct proc *p, struct linux_signal_args *args) { - caddr_t sg; - struct sigaction_args sa_args; - struct sigaction *osa, *nsa, tmpsa; + linux_sigaction_t nsa, osa; int error; #ifdef DEBUG printf("Linux-emul(%ld): signal(%d, %p)\n", - (long)p->p_pid, args->sig, (void *)args->handler); + (long)p->p_pid, args->sig, (void *)args->handler); #endif - if (args->sig <= 0 || args->sig >= LINUX_NSIG) + + nsa.lsa_handler = args->handler; + nsa.lsa_flags = LINUX_SA_ONESHOT | LINUX_SA_NOMASK; + nsa.lsa_mask = NULL; + + error = linux_do_sigaction(p, args->sig, &nsa, &osa); + + p->p_retval[0] = (int)osa.lsa_handler; + + return 0; +} + +int +linux_rt_sigaction(struct proc *p, struct linux_rt_sigaction_args *args) +{ + linux_sigaction_t nsa, osa; + linux_new_sigaction_t new_sa; + int error; + +#ifdef DEBUG + printf("Linux-emul(%ld): rt_sigaction(%d, %p, %p, %d)\n", + (long)p->p_pid, args->sig, (void *)args->act, + (void *)args->oact, args->sigsetsize); +#endif + + if (args->sigsetsize != sizeof(linux_new_sigset_t)) return EINVAL; - sg = stackgap_init(); - nsa = stackgap_alloc(&sg, sizeof *nsa); - osa = stackgap_alloc(&sg, sizeof *osa); - - tmpsa.sa_handler = args->handler; - tmpsa.sa_mask = (sigset_t) 0; - tmpsa.sa_flags = SA_RESETHAND | SA_NODEFER; - if ((error = copyout(&tmpsa, nsa, sizeof tmpsa))) - return error; - sa_args.signum = linux_to_bsd_signal[args->sig]; - sa_args.osa = osa; - sa_args.nsa = nsa; - if ((error = sigaction(p, &sa_args))) - return error; +#ifdef DEBUG + if (args->sig >= LINUX_NSIG) { + printf("LINUX(%ld): rt_sigaction: 64-bit signal (%d)\n", + (long)p->p_pid, args->sig); + } +#endif + + if (args->act) { + error = copyin(args->act, &new_sa, sizeof(linux_new_sigaction_t)); + if (error) + return error; + + nsa.lsa_handler = new_sa.lsa_handler; + nsa.lsa_mask = new_sa.lsa_mask.sig[0]; + nsa.lsa_flags = new_sa.lsa_flags; + nsa.lsa_restorer = new_sa.lsa_restorer; + +#ifdef DEBUG + if (new_sa.lsa_mask.sig[1] != 0) + printf("LINUX(%ld): rt_sigaction: sig[1] = 0x%08lx\n", + (long)p->p_pid, new_sa.lsa_mask.sig[1]); +#endif + } - if ((error = copyin(osa, &tmpsa, sizeof *osa))) + error = linux_do_sigaction(p, args->sig, + args->act ? &nsa : NULL, + args->oact ? &osa : NULL); + if (error) return error; - p->p_retval[0] = (int)tmpsa.sa_handler; + if (args->oact) { + new_sa.lsa_handler = osa.lsa_handler; + new_sa.lsa_flags = osa.lsa_flags; + new_sa.lsa_restorer = osa.lsa_restorer; + new_sa.lsa_mask.sig[0] = osa.lsa_mask; + new_sa.lsa_mask.sig[1] = 0; + error = copyout(&osa, args->oact, sizeof(linux_new_sigaction_t)); + if (error) + return error; + } return 0; } +static int +linux_do_sigprocmask(struct proc *p, int how, linux_sigset_t *new, + linux_sigset_t *old) +{ + int error = 0, s; + sigset_t mask; + + p->p_retval[0] = 0; + + if (old != NULL) + *old = bsd_to_linux_sigset(p->p_sigmask); + + if (new != NULL) { + mask = linux_to_bsd_sigset(*new); + + s = splhigh(); + + switch (how) { + case LINUX_SIG_BLOCK: + p->p_sigmask |= (mask & ~sigcantmask); + break; + case LINUX_SIG_UNBLOCK: + p->p_sigmask &= ~mask; + break; + case LINUX_SIG_SETMASK: + p->p_sigmask = (mask & ~sigcantmask); + break; + default: + error = EINVAL; + break; + } + + splx(s); + } + + return error; +} int linux_sigprocmask(struct proc *p, struct linux_sigprocmask_args *args) { - int error, s; - sigset_t mask; - sigset_t omask; + linux_sigset_t mask; + linux_sigset_t omask; + int error; #ifdef DEBUG printf("Linux-emul(%d): sigprocmask(%d, *, *)\n", p->p_pid, args->how); #endif - p->p_retval[0] = 0; + if (args->mask != NULL) { + error = copyin(args->mask, &mask, sizeof(linux_sigset_t)); + if (error) + return error; + } + + error = linux_do_sigprocmask(p, args->how, + args->mask ? &mask : NULL, + args->omask ? &omask : NULL); + + if (!error && args->omask != NULL) { + error = copyout(&omask, args->omask, sizeof(linux_sigset_t)); + } + + return error; +} - if (args->omask != NULL) { - omask = bsd_to_linux_sigset(p->p_sigmask); - error = copyout(&omask, args->omask, sizeof(sigset_t)); +int +linux_rt_sigprocmask(struct proc *p, struct linux_rt_sigprocmask_args *args) +{ + linux_new_sigset_t new_mask; + linux_sigset_t old_mask; + int error; + +#ifdef DEBUG + printf("Linux-emul(%ld): rt_sigprocmask(%d, %p, %p, %d)\n", + (long)p->p_pid, args->how, (void *)args->mask, + (void *)args->omask, args->sigsetsize); +#endif + + if (args->sigsetsize != sizeof(linux_new_sigset_t)) + return EINVAL; + + if (args->mask != NULL) { + error = copyin(args->mask, &new_mask, sizeof(linux_new_sigset_t)); if (error) return error; + +#ifdef DEBUG + if (new_mask.sig[1] != 0) + printf("LINUX(%ld): rt_sigprocmask: sig[1] = 0x%08lx\n", + (long)p->p_pid, new_mask.sig[1]); +#endif } - if (!(args->mask)) - return 0; - error = copyin(args->mask, &mask, sizeof(linux_sigset_t)); - if (error) - return error; - mask = linux_to_bsd_sigset(mask); - s = splhigh(); - switch (args->how) { - case LINUX_SIG_BLOCK: - p->p_sigmask |= (mask & ~sigcantmask); - break; - case LINUX_SIG_UNBLOCK: - p->p_sigmask &= ~mask; - break; - case LINUX_SIG_SETMASK: - p->p_sigmask = (mask & ~sigcantmask); - break; - default: - error = EINVAL; - break; + error = linux_do_sigprocmask(p, args->how, + args->mask ? new_mask.sig : NULL, + args->omask ? &old_mask : NULL); + + if (!error && args->omask != NULL) { + new_mask.sig[0] = old_mask; + error = copyout(&new_mask, args->omask, sizeof(linux_new_sigset_t)); } - splx(s); + return error; } diff --git a/sys/i386/linux/linux_syscall.h b/sys/i386/linux/linux_syscall.h index eb1326a..a893f91 100644 --- a/sys/i386/linux/linux_syscall.h +++ b/sys/i386/linux/linux_syscall.h @@ -2,7 +2,7 @@ * System call numbers. * * DO NOT EDIT-- this file is automatically generated. - * created from Id: syscalls.master,v 1.18 1999/08/12 19:51:03 marcel Exp + * created from Id: syscalls.master,v 1.19 1999/08/14 17:14:13 marcel Exp */ #define LINUX_SYS_linux_setup 0 @@ -163,5 +163,7 @@ #define LINUX_SYS_nanosleep 162 #define LINUX_SYS_linux_mremap 163 #define LINUX_SYS_poll 168 +#define LINUX_SYS_linux_rt_sigaction 174 +#define LINUX_SYS_linux_rt_sigprocmask 175 #define LINUX_SYS_linux_chown 182 #define LINUX_SYS_MAXSYSCALL 183 diff --git a/sys/i386/linux/linux_sysent.c b/sys/i386/linux/linux_sysent.c index a03bd95..f8f2b7e 100644 --- a/sys/i386/linux/linux_sysent.c +++ b/sys/i386/linux/linux_sysent.c @@ -2,7 +2,7 @@ * System call switch table. * * DO NOT EDIT-- this file is automatically generated. - * created from Id: syscalls.master,v 1.18 1999/08/12 19:51:03 marcel Exp + * created from Id: syscalls.master,v 1.19 1999/08/14 17:14:13 marcel Exp */ #include "opt_compat.h" @@ -188,8 +188,8 @@ struct sysent linux_sysent[] = { { 0, (sy_call_t *)nosys }, /* 171 = getresgid */ { 0, (sy_call_t *)nosys }, /* 172 = prctl */ { 0, (sy_call_t *)nosys }, /* 173 = rt_sigreturn */ - { 0, (sy_call_t *)nosys }, /* 174 = rt_sigaction */ - { 0, (sy_call_t *)nosys }, /* 175 = rt_sigprocmask */ + { 4, (sy_call_t *)linux_rt_sigaction }, /* 174 = linux_rt_sigaction */ + { 4, (sy_call_t *)linux_rt_sigprocmask }, /* 175 = linux_rt_sigprocmask */ { 0, (sy_call_t *)nosys }, /* 176 = rt_sigpending */ { 0, (sy_call_t *)nosys }, /* 177 = rt_sigtimedwait */ { 0, (sy_call_t *)nosys }, /* 178 = rt_sigqueueinfo */ |