[comp.unix.questions] signals & stopping

dg@wrs.UUCP (David Goodenough) (07/22/87)

HELP!

	I wrote a version of more recently which works like a charm
EXCEPT under the following conditions:

	1. It is run via a system(3) call (as happens in man, or with
		a ':!more file' command to vi);

	2. While this is running I hit ^Z to stop it.

The symptoms are thus:

	1. The program stops OK, but the terminal mode is not reset, however
		if I fire it up directly from csh and stop with a ^Z, then
		the terminal mode is reset. All evidence points to the
		fact that xstop is not trapping the ^Z. 

	2. When I 'fg' it to get it going again, it THEN executes xstop (a
		little late) so that now a ^Z behaves correctly, however
		a third ^Z behaves just like the first.

I have included all the bits that I think are relevant, if you want
the entire source, drop me a line & I'll mail it.

#include <stdio.h>
#include <signal.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>

#define TRUE	1
#define	FALSE	0

#define RESET	2

int term;

main(n, a)
char **a;
 {

    rawmode(TRUE);		/* set screen to cbreak mode */
    setsig(TRUE);		/* trap signals */

/* program does it's bit */

    rawmode(FALSE);		/* reset screen */
    exit(0);
 }

restart()
 {
    signal(SIGCONT, SIG_DFL);	/* reset SIGCONT for now */
    setsig(TRUE);		/* trap other signals */
    rawmode(TRUE);		/* reset cbreak mode */

/* other stuff to do with a screen redraw */

 }

xstop()
 {
    rawmode(RESET);		/* force terminal mode to cooked */
    setsig(FALSE);		/* reset signal trapping for now */
    signal(SIGCONT, restart);	/* except CONT's fire restart above */
    moveto(sc_height - 1, 0);
    cleol();
    fflush(stdout);		/* do something sensible with the cursor */
    kill(getpid(), SIGTSTP);	/* finally stop ourselves */
 }

setsig(on)
 {
    if (isatty(1))		/* bypass this if writing to a pipe */
     {
	signal(SIGINT, on ? SIG_IGN : SIG_DFL);
	signal(SIGQUIT, on ? SIG_IGN : SIG_DFL);
				/* ignore ^C's and ^\'s */
	signal(SIGTSTP, on ? xstop : SIG_DFL);
				/* send ^Z's to xstop() */
     }
 }

rawmode(on)
 {
    struct sgttyb s;
    static struct sgttyb saveterm;
    static int saved = FALSE;

    if (isatty(1))		/* only if not outputting to a pipe */
     {
	switch (on)
	 {
	    case TRUE:		/* set raw mode */
	     {
		ioctl(term, TIOCGETP, &s);
		if (saved == FALSE)
		 {		/* save a copy of terminal settings */
		    saveterm = s;
		    saved = TRUE;
		 }
		ospeed = s.sg_ospeed;
#ifdef	BAUD9600
		bflg = 1;
#else
		bflg = (ospeed != B9600); /* change this line if you want it to
					   * work at speeds other than 9600 */
#endif
		s.sg_flags |= CBREAK;
		s.sg_flags &= ~(ECHO | XTABS);
					/* set bits for cbreak mode */
	     }
	    break;
	    case RESET:
	     {
		ioctl(term, TIOCGETP, &s);
		s.sg_flags = 216;	/* force cooked mode */
	     }
	    break;
	    case FALSE:
	      s = saveterm;		/* reset to original */
	    break;
	 }
	ioctl(term, TIOCSETN, &s);
     }
 }

I hope someone can come up with something - My own guess is that it's
somehow connected to the fact that it's being run with several other
processes in the process group, however BSD more gets it right, so there
has to be a way.
--
		dg@wrs.UUCP - David Goodenough

					+---+
					| +-+-+
					+-+-+ |
					  +---+