chiark / gitweb /
Merge gregkh@ehlo.org:/home/kay/public_html/pub/scm/linux/hotplug/udev-kay
[elogind.git] / klibc / klibc / sigaction.c
index ebd34710f18ec0f7db8090a60cbbc38eeb4fa351..85f42a244cc65ff7d65f6bde9a21a8c1e146aadb 100644 (file)
@@ -5,15 +5,40 @@
 #include <signal.h>
 #include <sys/syscall.h>
 
-#ifdef __NR_sigaction
+__extern void __sigreturn(void);
+__extern int __sigaction(int, const struct sigaction *, struct sigaction *);
+__extern int __rt_sigaction(int, const struct sigaction *, struct sigaction *, size_t);
+
+int sigaction(int sig, const struct sigaction *act, struct sigaction *oact)
+{
+  int rv;
 
-_syscall3(int,sigaction,int,sig,const struct sigaction *,act,struct sigaction *,oact);
+#if defined(__i386__) || defined(__x86_64__)
+  /* x86-64, and the Fedora i386 kernel, are broken without SA_RESTORER */
+  struct sigaction sa;
+
+  if ( act && !(act->sa_flags & SA_RESTORER) ) {
+    sa = *act;
+    act = &sa;
+
+    /* The kernel can't be trusted to have a valid default restorer */
+    sa.sa_flags |= SA_RESTORER;
+    sa.sa_restorer = &__sigreturn;
+  }
+#endif
 
+#ifdef __NR_sigaction
+  rv = __sigaction(sig, act, oact);
 #else
+  rv = __rt_sigaction(sig, act, oact, sizeof(sigset_t));
+#endif
 
-int sigaction(int sig, const struct sigaction *act, struct sigaction *oact)
-{
-  return rt_sigaction(sig, act, oact, sizeof(sigset_t));
-}
 
+#if defined(__i386__) || defined(__x86_64__)
+  if ( oact && (oact->sa_restorer == &__sigreturn) ) {
+    oact->sa_flags &= ~SA_RESTORER;
+  }
 #endif
+
+  return rv;
+}