Subject: alarm() does not work with tty read???
To: None <current-users@sun-lamp.cs.berkeley.edu>
From: Simon J. Gerraty <sjg@zen.void.oz.au>
List: current-users
Date: 12/07/1993 17:01:25
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);

and even with root sending SIGALRM's at the process it does not return
from the read.... so I hacked up the trivial prog at the end of this
post to test in isolation.  I was going to check various reading
approaches, but the first one using alarm() as above, did not work so
I'm pretty sure we have a bug...

com.c just calls the line discipline's read entry, but I'm not too
sure the standard line discipline is implemented.  kern/tty.c does not
look enough (no mention of VMIN etc - indeed it only appears in
arch/i386/isa/cy.c) and speaks of line disciplines as though they are
implemented elsewhere...  any clues appreciated.

Anyway here is the test prog.  You can call it with

./chat -l /dev/tty01 send expect ...

It always adds a "\r" for you (I said this was trivial).

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

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

	if ((fd = open(name, O_RDWR)) >= 0)
	{
		/* hooks for later... */
	}
	return fd;
}

volatile int timeout = 0;

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

int
tty_read(int fd, char *buf, int nbytes, int secs)
{
	int c;
	
	signal(SIGALRM, alarm_catcher);

	alarm(secs);
#if 0
	/* check that alarm() does work... */
	strcpy(buf, "nothing");
	sleep(100);
	c = -1;
#else
	c = read(fd, buf, nbytes);
#endif
	alarm(0);

	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;
}

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