summaryrefslogtreecommitdiff
path: root/src/signal/sigaction.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/signal/sigaction.c')
-rw-r--r--src/signal/sigaction.c48
1 files changed, 48 insertions, 0 deletions
diff --git a/src/signal/sigaction.c b/src/signal/sigaction.c
new file mode 100644
index 00000000..4acd1730
--- /dev/null
+++ b/src/signal/sigaction.c
@@ -0,0 +1,48 @@
+#include <stdlib.h>
+#include <signal.h>
+#include <errno.h>
+#include "syscall.h"
+#include "pthread_impl.h"
+
+static void restorer()
+{
+ syscall0(__NR_rt_sigreturn);
+}
+
+int __libc_sigaction(int sig, const struct sigaction *sa, struct sigaction *old)
+{
+ struct {
+ void *handler;
+ unsigned long flags;
+ void (*restorer)(void);
+ sigset_t mask;
+ } ksa, kold;
+ long pksa=0, pkold=0;
+ if (sa) {
+ ksa.handler = sa->sa_handler;
+ ksa.flags = sa->sa_flags;
+ ksa.restorer = restorer;
+ ksa.mask = sa->sa_mask;
+ pksa = (long)&ksa;
+ }
+ if (old) pkold = (long)&kold;
+ if (syscall4(__NR_rt_sigaction, sig, pksa, pkold, 8))
+ return -1;
+ if (old) {
+ old->sa_handler = kold.handler;
+ old->sa_flags = kold.flags;
+ old->sa_mask = kold.mask;
+ }
+ return 0;
+}
+
+int __sigaction(int sig, const struct sigaction *sa, struct sigaction *old)
+{
+ if (sig == SIGCANCEL || sig == SIGSYSCALL) {
+ errno = EINVAL;
+ return -1;
+ }
+ return __libc_sigaction(sig, sa, old);
+}
+
+weak_alias(__sigaction, sigaction);