summaryrefslogtreecommitdiffstats
path: root/usr/klibc/sigaction.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/klibc/sigaction.c')
-rw-r--r--usr/klibc/sigaction.c61
1 files changed, 61 insertions, 0 deletions
diff --git a/usr/klibc/sigaction.c b/usr/klibc/sigaction.c
new file mode 100644
index 0000000..9481750
--- /dev/null
+++ b/usr/klibc/sigaction.c
@@ -0,0 +1,61 @@
+/*
+ * sigaction.c
+ */
+
+#include <signal.h>
+#include <stddef.h>
+#include <sys/syscall.h>
+#include <klibc/sysconfig.h>
+
+__extern void __sigreturn(void);
+
+#if _KLIBC_NEEDS_SIGACTION_FIXUP
+typedef struct sigaction *act_type;
+#else
+typedef const struct sigaction *act_type;
+#endif
+
+__extern int __rt_sigaction(int, act_type, struct sigaction *, size_t);
+
+int sigaction(int sig, const struct sigaction *act, struct sigaction *oact)
+{
+ unsigned int needed_flags = 0
+#if _KLIBC_NEEDS_SA_RESTORER
+ | SA_RESTORER
+#endif
+#if _KLIBC_NEEDS_SA_SIGINFO
+ | SA_SIGINFO
+#endif
+ ;
+ struct sigaction sa;
+ int rv;
+
+ if (act &&
+ ((act->sa_flags & needed_flags) != needed_flags ||
+ _KLIBC_NEEDS_SIGACTION_FIXUP)) {
+ sa = *act;
+ sa.sa_flags |= needed_flags;
+#if _KLIBC_NEEDS_SA_RESTORER
+ if (!(act->sa_flags & SA_RESTORER))
+ sa.sa_restorer = &__sigreturn;
+#endif
+ act = &sa;
+ }
+
+ /* Check that we have the right signal API definitions */
+ (void)sizeof(char[_NSIG >= 64 ? 1 : -1]);
+ (void)sizeof(char[sizeof(sigset_t) * 8 >= _NSIG ? 1 : -1]);
+ (void)sizeof(char[offsetof(struct sigaction, sa_mask)
+ + sizeof(sigset_t) == sizeof(struct sigaction)
+ ? 1 : -1]);
+
+ rv = __rt_sigaction(sig, (act_type)act, oact, sizeof(sigset_t));
+
+#if _KLIBC_NEEDS_SA_RESTORER
+ if (oact && (oact->sa_restorer == &__sigreturn)) {
+ oact->sa_flags &= ~SA_RESTORER;
+ }
+#endif
+
+ return rv;
+}