summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTodd C. Miller <millert@cvs.openbsd.org>2003-06-07 03:35:20 +0000
committerTodd C. Miller <millert@cvs.openbsd.org>2003-06-07 03:35:20 +0000
commit912020678b6f45f900b66e637e5848d9fa3b92b7 (patch)
treefed315ea71f42adc5b7f91b77e54ce06be52220c
parentca740922f63b8d6806ffacd67092fc0f20e90976 (diff)
Use interruptible syscalls instead of setjmp/longjmp. This makes
less's signal handlers safe. No one has reported problems so far...
-rw-r--r--usr.bin/less/funcs.h2
-rw-r--r--usr.bin/less/less.h2
-rw-r--r--usr.bin/less/os.c58
-rw-r--r--usr.bin/less/signal.c33
4 files changed, 21 insertions, 74 deletions
diff --git a/usr.bin/less/funcs.h b/usr.bin/less/funcs.h
index 4ee00d493f6..5fab0efdf6a 100644
--- a/usr.bin/less/funcs.h
+++ b/usr.bin/less/funcs.h
@@ -195,7 +195,6 @@
public struct loption * findopt ();
public struct loption * findopt_name ();
public int iread ();
- public void intread ();
public long get_time ();
public char * errno_message ();
public int percentage ();
@@ -249,3 +248,4 @@
public void open_getchr ();
public void close_getchr ();
public int getchr ();
+ public void (*lsignal()) ();
diff --git a/usr.bin/less/less.h b/usr.bin/less/less.h
index 07911d5ce7d..abb60f323c5 100644
--- a/usr.bin/less/less.h
+++ b/usr.bin/less/less.h
@@ -374,7 +374,7 @@ struct textlist
#if _OSK_MWC32
#define LSIGNAL(sig,func) os9_signal(sig,func)
#else
-#define LSIGNAL(sig,func) signal(sig,func)
+#define LSIGNAL(sig,func) lsignal(sig,func)
#endif
#if HAVE_SIGPROCMASK
diff --git a/usr.bin/less/os.c b/usr.bin/less/os.c
index ac63960df95..c5343a043a8 100644
--- a/usr.bin/less/os.c
+++ b/usr.bin/less/os.c
@@ -23,7 +23,6 @@
#include "less.h"
#include <signal.h>
-#include <setjmp.h>
#if HAVE_TIME_H
#include <time.h>
#endif
@@ -40,31 +39,10 @@
#define time_type long
#endif
-/*
- * BSD setjmp() saves (and longjmp() restores) the signal mask.
- * This costs a system call or two per setjmp(), so if possible we clear the
- * signal mask with sigsetmask(), and use _setjmp()/_longjmp() instead.
- * On other systems, setjmp() doesn't affect the signal mask and so
- * _setjmp() does not exist; we just use setjmp().
- */
-#if HAVE__SETJMP && HAVE_SIGSETMASK
-#define SET_JUMP _setjmp
-#define LONG_JUMP _longjmp
-#else
-#define SET_JUMP setjmp
-#define LONG_JUMP longjmp
-#endif
-
-public int reading;
-
-static jmp_buf read_label;
-
extern int sigs;
/*
* Like read() system call, but is deliberately interruptible.
- * A call to intread() from a signal handler will interrupt
- * any pending iread().
*/
public int
iread(fd, buf, len)
@@ -90,32 +68,8 @@ iread(fd, buf, len)
}
#endif
#endif
- if (SET_JUMP(read_label))
- {
- /*
- * We jumped here from intread.
- */
- reading = 0;
-#if HAVE_SIGPROCMASK
- {
- sigset_t mask;
- sigemptyset(&mask);
- sigprocmask(SIG_SETMASK, &mask, NULL);
- }
-#else
-#if HAVE_SIGSETMASK
- sigsetmask(0);
-#else
-#ifdef _OSK
- sigmask(~0);
-#endif
-#endif
-#endif
- return (READ_INTR);
- }
flush();
- reading = 1;
#if MSDOS_COMPILER==DJGPPC
if (isatty(fd))
{
@@ -154,22 +108,12 @@ iread(fd, buf, len)
}
}
#endif
- reading = 0;
if (n < 0)
- return (-1);
+ return (errno == EINTR ? READ_INTR : -1);
return (n);
}
/*
- * Interrupt a pending iread().
- */
- public void
-intread()
-{
- LONG_JUMP(read_label, 1);
-}
-
-/*
* Return the current time.
*/
#if HAVE_TIME
diff --git a/usr.bin/less/signal.c b/usr.bin/less/signal.c
index a641d99ee9d..01b510f73e8 100644
--- a/usr.bin/less/signal.c
+++ b/usr.bin/less/signal.c
@@ -15,8 +15,6 @@
* A signal usually merely causes a bit to be set in the "signals" word.
* At some convenient time, the mainline code checks to see if any
* signals need processing by calling psignal().
- * If we happen to be reading from a file [in iread()] at the time
- * the signal is received, we call intread to interrupt the iread.
*/
#include "less.h"
@@ -32,7 +30,6 @@ extern int screen_trashed;
extern int lnloop;
extern int linenums;
extern int wscroll;
-extern int reading;
/*
* Interrupt signal handler.
@@ -45,7 +42,6 @@ u_interrupt(type)
#if OS2
LSIGNAL(SIGINT, SIG_ACK);
#endif
- LSIGNAL(SIGINT, u_interrupt);
sigs |= S_INTERRUPT;
#if MSDOS_COMPILER==DJGPPC
/*
@@ -56,8 +52,6 @@ u_interrupt(type)
if (kbhit())
getkey();
#endif
- if (reading)
- intread();
}
#ifdef SIGTSTP
@@ -69,10 +63,7 @@ u_interrupt(type)
stop(type)
int type;
{
- LSIGNAL(SIGTSTP, stop);
sigs |= S_STOP;
- if (reading)
- intread();
}
#endif
@@ -85,10 +76,7 @@ stop(type)
winch(type)
int type;
{
- LSIGNAL(SIGWINCH, winch);
sigs |= S_WINCH;
- if (reading)
- intread();
}
#else
#ifdef SIGWIND
@@ -100,10 +88,7 @@ winch(type)
winch(type)
int type;
{
- LSIGNAL(SIGWIND, winch);
sigs |= S_WINCH;
- if (reading)
- intread();
}
#endif
#endif
@@ -268,3 +253,21 @@ psignals()
}
}
+
+/*
+ * Custom version of signal() that causes syscalls to be interrupted.
+ */
+ public void
+(*lsignal(s, a))()
+ int s;
+ void (*a) ();
+{
+ struct sigaction sa, osa;
+
+ sa.sa_handler = a;
+ sigemptyset(&sa.sa_mask);
+ sa.sa_flags = 0; /* don't restart system calls */
+ if (sigaction(s, &sa, &osa) != 0)
+ return (SIG_ERR);
+ return (osa.sa_handler);
+}