diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1997-01-07 02:33:00 +0000 |
---|---|---|
committer | <ralf@linux-mips.org> | 1997-01-07 02:33:00 +0000 |
commit | beb116954b9b7f3bb56412b2494b562f02b864b1 (patch) | |
tree | 120e997879884e1b9d93b265221b939d2ef1ade1 /kernel/signal.c | |
parent | 908d4681a1dc3792ecafbe64265783a86c4cccb6 (diff) |
Import of Linux/MIPS 2.1.14
Diffstat (limited to 'kernel/signal.c')
-rw-r--r-- | kernel/signal.c | 97 |
1 files changed, 57 insertions, 40 deletions
diff --git a/kernel/signal.c b/kernel/signal.c index f21d7a2c9..325663bed 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -13,22 +13,29 @@ #include <linux/unistd.h> #include <linux/mm.h> -#include <asm/segment.h> +#include <asm/uaccess.h> #define _S(nr) (1<<((nr)-1)) #define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP))) +#if !defined(__alpha__) && !defined(__mips__) + +/* + * This call isn't used by all ports, in particular, the Alpha + * uses osf_sigprocmask instead. Maybe it should be moved into + * arch-dependent dir? + */ asmlinkage int sys_sigprocmask(int how, sigset_t *set, sigset_t *oset) { sigset_t new_set, old_set = current->blocked; int error; if (set) { - error = verify_area(VERIFY_READ, set, sizeof(sigset_t)); + error = get_user(new_set, set); if (error) - return error; - new_set = get_fs_long((unsigned long *) set) & _BLOCKABLE; + return error; + new_set &= _BLOCKABLE; switch (how) { case SIG_BLOCK: current->blocked |= new_set; @@ -44,14 +51,19 @@ asmlinkage int sys_sigprocmask(int how, sigset_t *set, sigset_t *oset) } } if (oset) { - error = verify_area(VERIFY_WRITE, oset, sizeof(sigset_t)); + error = put_user(old_set, oset); if (error) - return error; - put_fs_long(old_set, (unsigned long *) oset); + return error; } return 0; } +#endif +#ifndef __alpha__ + +/* + * For backwards compatibility? Functionality superseded by sigprocmask. + */ asmlinkage int sys_sgetmask(void) { return current->blocked; @@ -65,21 +77,19 @@ asmlinkage int sys_ssetmask(int newmask) return old; } +#endif + asmlinkage int sys_sigpending(sigset_t *set) { - int error; - /* fill in "set" with signals pending but blocked. */ - error = verify_area(VERIFY_WRITE, set, 4); - if (!error) - put_fs_long(current->blocked & current->signal, (unsigned long *)set); - return error; + return put_user(current->blocked & current->signal, + /* Hack */(unsigned long *)set); } /* * POSIX 3.3.1.3: * "Setting a signal action to SIG_IGN for a signal that is pending * shall cause the pending signal to be discarded, whether or not - * it is blocked" (but SIGCHLD is unspecified: linux leaves it alone). + * it is blocked." * * "Setting a signal action to SIG_DFL for a signal that is pending * and whose default action is to ignore the signal (for example, @@ -90,31 +100,39 @@ asmlinkage int sys_sigpending(sigset_t *set) * isn't actually ignored, but does automatic child reaping, while * SIG_DFL is explicitly said by POSIX to force the signal to be ignored.. */ -static void check_pending(int signum) +static inline void check_pending(int signum) { struct sigaction *p; - p = signum - 1 + current->sigaction; + p = signum - 1 + current->sig->action; if (p->sa_handler == SIG_IGN) { - if (signum == SIGCHLD) - return; - current->signal &= ~_S(signum); + k_sigdelset(¤t->signal, signum); return; } if (p->sa_handler == SIG_DFL) { if (signum != SIGCONT && signum != SIGCHLD && signum != SIGWINCH) return; - current->signal &= ~_S(signum); + k_sigdelset(¤t->signal, signum); return; } } -asmlinkage unsigned long sys_signal(int signum, void (*handler)(int)) +#if !defined(__alpha__) && !defined(__mips__) +/* + * For backwards compatibility? Functionality superseded by sigaction. + */ +asmlinkage unsigned long sys_signal(int signum, __sighandler_t handler) { int err; struct sigaction tmp; - if (signum<1 || signum>32) + /* + * HACK: We still cannot handle signals > 32 due to the limited + * size of ksigset_t (which will go away). + */ + if (signum > 32) + return -EINVAL; + if (signum<1 || signum>_NSIG) return -EINVAL; if (signum==SIGKILL || signum==SIGSTOP) return -EINVAL; @@ -123,37 +141,38 @@ asmlinkage unsigned long sys_signal(int signum, void (*handler)(int)) if (err) return err; } + memset(&tmp, 0, sizeof(tmp)); tmp.sa_handler = handler; - tmp.sa_mask = 0; tmp.sa_flags = SA_ONESHOT | SA_NOMASK; - tmp.sa_restorer = NULL; - handler = current->sigaction[signum-1].sa_handler; - current->sigaction[signum-1] = tmp; + handler = current->sig->action[signum-1].sa_handler; + current->sig->action[signum-1] = tmp; check_pending(signum); return (unsigned long) handler; } +#endif /* !defined(__alpha__) && !defined(__mips__) */ asmlinkage int sys_sigaction(int signum, const struct sigaction * action, struct sigaction * oldaction) { struct sigaction new_sa, *p; - if (signum<1 || signum>32) + /* + * HACK: We still cannot handle signals > 32 due to the limited + * size of ksigset_t (which will go away). + */ + if (signum > 32) return -EINVAL; - if (signum==SIGKILL || signum==SIGSTOP) + if (signum<1 || signum>_NSIG) return -EINVAL; - p = signum - 1 + current->sigaction; + p = signum - 1 + current->sig->action; if (action) { int err = verify_area(VERIFY_READ, action, sizeof(*action)); if (err) return err; - memcpy_fromfs(&new_sa, action, sizeof(struct sigaction)); - if (new_sa.sa_flags & SA_NOMASK) - new_sa.sa_mask = 0; - else { - new_sa.sa_mask |= _S(signum); - new_sa.sa_mask &= _BLOCKABLE; - } + if (signum==SIGKILL || signum==SIGSTOP) + return -EINVAL; + if (copy_from_user(&new_sa, action, sizeof(struct sigaction))) + return -EFAULT; if (new_sa.sa_handler != SIG_DFL && new_sa.sa_handler != SIG_IGN) { err = verify_area(VERIFY_READ, new_sa.sa_handler, 1); if (err) @@ -161,10 +180,8 @@ asmlinkage int sys_sigaction(int signum, const struct sigaction * action, } } if (oldaction) { - int err = verify_area(VERIFY_WRITE, oldaction, sizeof(*oldaction)); - if (err) - return err; - memcpy_tofs(oldaction, p, sizeof(struct sigaction)); + if (copy_to_user(oldaction, p, sizeof(struct sigaction))) + return -EFAULT; } if (action) { *p = new_sa; |