Subject: Re: alarm() does not work with tty read???
To: <>
From: Simon J. Gerraty <sjg@zen.void.oz.au>
List: current-users
Date: 12/07/1993 18:37:55
I wrote:
> I'm "porting" mgetty+sendfax.  sendfax works more or less ok.
> mgetty gets stuck...  it gets stuck because it tries to do a read from
> a tty device with and 
> 
>     t->c_lflag &= ~ICANON;
>     t->c_cc[VMIN] = 0;
>     t->c_cc[VTIME]= 1;
> 
> it should work, but the time out never happens.
> I modified mgetty to simply use
> 
> 	alarm(1);
> 	read()
> 	alarm(0);

Ok so like an idiot, I keep forgetting I'm using BSD :-)
Simply using signal() is no good as the read is automagically restarted. 
Modifying things to use sigaction and to specify no-retry works ok.

My initial question remains though... does NetBSD actually support
termios timed reads using c_cc[VTIME] as above.  The modified test
prog below suggests not.

Compile it with just

	cc -g -O -o chat.sigaction -static chat.c

and it works

	cc -g -O -o chat.signal -DUSE_SIGNAL -static chat.c

does not (as expected) and nor does

	cc -g -O -o chat.vtime -DUSE_VTIME -static chat.c

#include <stdio.h>
#include <termios.h>
#include <sys/types.h>
#include <sys/time.h>
#include <unistd.h>
#include <fcntl.h>
#include <signal.h>

volatile int timeout = 0;

void
alarm_catcher(int sig)
{
	timeout++;
}

int
tty_open(char *name)
{
	int fd = -1;
	struct termios tio;

	if ((fd = open(name, O_RDWR)) >= 0)
	{
#ifdef USE_SIGNAL
		signal(SIGALRM, alarm_catcher);
#else
		struct sigaction sa;

		sa.sa_handler = alarm_catcher;
		sa.sa_flags = 0;			/* no restart */
		sigaction(SIGALRM, &sa, NULL);
#endif
	}
	return fd;
}

int
tty_read(int fd, char *buf, int nbytes, int secs)
{
	int c;
#ifdef USE_VTIME
	static struct termios t, old;
	static int once = 0;

	if (!once) {
		once++;
		tcgetattr(fd, &old);
	}
	t = old;
	t.c_lflag &= ~( ICANON );
	t.c_cc[VMIN] = 0;
	t.c_cc[VTIME]= secs * 10;
	tcsetattr(fd, TCSANOW, &t);
	c = read(fd, buf, nbytes);
	tcsetattr(fd, TCSANOW, &old);
#else
	alarm(secs);
	c = read(fd, buf, nbytes);
	alarm(0);
#endif

	return c;
}

int
wait_for(int fd, char *str)
{
	char buf[128];
	int c;

	printf("looking for '%s', got: ", str);
	fflush(stdout);
	while ((c = tty_read(fd, buf, sizeof (buf) - 1, 5)) > 0)
	{
		buf[c] = '\0';
		printf("%s", buf);
		fflush(stdout);
		if (strstr(buf, str))
			return 1;
	}
	return 0;
}

void
do_chat(int fd, char **args)
{
	int i = 0;

	for (i = 0; args[i]; i += 2)
	{
		printf("send: '%s'\n", args[i]);
		write(fd, args[i], strlen(args[i]));
		write(fd, "\r", 1);
		wait_for(fd, args[i + 1]);
		printf("\n");
	}
}


int
main(int argc, char **argv)
{
	char *tty_dev = NULL;
	int c, fd = -1;
	
	while ((c = getopt(argc, argv, "l:")) != EOF)
	{
		switch (c)
		{
		case 'l':
			tty_dev = optarg;
			break;
		}
	}
	if (tty_dev)
		if ((fd = tty_open(tty_dev)) >= 0)
			do_chat(fd, &argv[optind]);
	return 0;
}

------------------------------------------------------------------------------