[comp.unix.sysv386] PD uugetty for Interactives 386/ix?

johnl@esegue.segue.boston.ma.us (John R. Levine) (09/01/90)

In article <90243.123640RREED@ucf1vm.cc.ucf.edu> you write:
>A friend of mine without net access (now, but if you can help, that will
>change!) asked me to see if I could find a PD uugetty replacement for his
>386/ix system.

Rather than using uugetty, use either the async driver on the X5 or X6
update disks, or else the public FAS driver posted here.  Both of them
provide separate /dev entries for dialin and dialout, so you can run a
modem both ways without uugetty.  I have used both, and they both work.

FAS is somewhat faster, X5/X6 supports VP/ix.  Both take advantage of
the extra buffering in a 16550 ASYNC chip.

Regards,
John Levine, johnl@esegue.segue.boston.ma.us, {spdcc|ima|world}!esegue!johnl

karl@ddsw1.MCS.COM (Karl Denninger) (09/03/90)

In article <9009011253.AA13674@esegue.segue.boston.ma.us> johnl@esegue.segue.boston.ma.us (John R. Levine) writes:
>In article <90243.123640RREED@ucf1vm.cc.ucf.edu> you write:
>>A friend of mine without net access (now, but if you can help, that will
>>change!) asked me to see if I could find a PD uugetty replacement for his
>>386/ix system.
>
>Rather than using uugetty, use either the async driver on the X5 or X6
>update disks, or else the public FAS driver posted here.  Both of them
>provide separate /dev entries for dialin and dialout, so you can run a
>modem both ways without uugetty.  I have used both, and they both work.
>
>FAS is somewhat faster, X5/X6 supports VP/ix.  Both take advantage of
>the extra buffering in a 16550 ASYNC chip.

That does NOT solve one problem:

o You dial out on the non-modem control port.  The call completes, then
  drops.  How do you detect it?  The answer?  You don't!

The fix?  Below is a shar archive.  Unpack, read the comments, compile and
go.  This will work on ISC 2.2, 2.0.2, and should work on SCO Unix V/386
(but it has NOT been tested there).  There is one hack in the code right now:

	ISC does not correctly support CLOCAL on modem control lines.  If
	you open a port with O_NDELAY, then set CLOCAL and clear O_NDELAY
	with fcntl, you should get BLOCKING reads with the CD signal
	ignored.  Instead you get non-blocking reads if CD is low, and
	blocking reads if CD is high (idiots!).  Thus, there's a timer-read
	routine in here; it'll work if and when ISC fixes their driver, and
	works ok as is now (but does consume a couple seconds of runtime per 
	hour when the port is idle).

	Unfortunately, Equinox and a few other board makers have mimiced the
	broken code instead of fixing it (double idiots!)  Thus this hack.


Note:  This code is NOT PD; it's Copyrighted.  It can be used
  	non-commercially, but if you want to sell it or enhance the value of
	a commercial poduct you have to get a distribution license.  Flame
	if you must, use the code if it helps you.

	This program is still a little messy, but it certainly functions.
	We run all our modems at "ddsw1" with this and have no trouble with
	it at all.


#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of shell archive."
# Contents:  autonew.c
# Wrapped by karl@ddsw1 on Mon Sep  3 01:03:03 1990
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'autonew.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'autonew.c'\"
else
echo shar: Extracting \"'autonew.c'\" \(18668 characters\)
sed "s/^X//" >'autonew.c' <<'END_OF_FILE'
X/*
X *	Copyright 1990 MCS & Karl Denninger.  All rights reserved.
X *
X *	Public use is permitted under the following conditions:
X *
X *	1) You do not remove my name from the package, or claim you wrote it.
X *	2) You distribute ORIGINAL source code with all distributions made,
X *	   modified or not, binary or source.
X *	3) You do not attempt to sell the package, or use it to enhance the
X *	   commercial value of any product or service.  
X *	4) This package is distributed with ABSOLUTELY NO WARRANTY OF ANY
X *	   KIND.  If it melts your system to slag YOU are responsible, not
X *	   MCS or myself.  The burden rests with you to perform adaquate
X *	   testing before turning this loose on unsuspecting users.
X *
X *	Commercial distribution rights reserved; contact MCS at (708) 808-7200
X *	for details on commercial distribution licensing.
X *
X *	Compile with:  cc -s -o autonew autonew.c -lc_s -lx
X *
X */
X/*	Autobaud program 
X
X	Run in place of 'getty', this will prompt for a name
X	and call login just like the old one used to do... Only
X	difference is that it is rather interesting in it's interpretation
X	of what a 'gettydefs' file is; that is, there isn't one.
X	
X	We use modem return messages to determine the baud rate.  Locks are
X	respected as well, allowing the uucp system to share the ports.
X
X	The issue file is in /etc/issue.new.  The first line of this file
X	contains the login prompt.  The remainder is the banner message.
X
X	You invoke this with:
X		/etc/autonew ttyA2 [code]
X	
X	from /etc/inittab.  "[code]" is the numeric code for the baud rate
X	to send the initialization string at -- most of the time  you want
X	this to be the highest baud rate your modem will support.
X
X	Notes:
X		1) The device name does not have a prefix.  It is prepended
X		   automatically (/dev/ is added).
X		2) For ISC, use the MODEM CONTROL PORTS.  This program can
X		   interlock with UUCP; see their DEVICES file for the
X		   proper flags to set in the DEVICES and DIALERS files.
X		   Use the "new" definitions which have ",M" added (see your
X		   documentation for details).
X		3) While a port is being used for dialout, it will show
X		   up in a "who" command as "_Dialout".
X		4) Modes will be changed on ports to prevent random users
X		   from using the ports for "cu"s and other communications
X		   uses.  This can be easily changed if desired (look for
X		   the "chmod" call in the source).
X		5) The file /etc/autobaud.parm must be present.  The format
X		   is as follows:
X			First line -- initialization string for ports
X			Second line -- response to initialization string
X			Rest of lines -- baud codes, rates (text), and
X					 response strings expected.
X
X			Baud codes are the speed codes from termio.h; 
X			11, for example, is 2400 baud.
X
X		An example /etc/autobaud.parm file:
X			
X		AAAAATE0Q0V1
X		OK
X		7 300 CONNECT
X		9 1200 CONNECT 1200
X		11 2400 CONNECT 2400
X		14 19200 CONNECT FAST
X	
X		
X		6) Your I/O board and/or drivers MUST correctly support the
X		   notion of O_NDELAY.  In addition, you have to be able to
X		   turn on and off the NDELAY flag with fcntl.  LOTS of
X		   intelligent boards broke this; if it's broken this
X		   program will NOT work.  ONE HACK:  If your NDELAY
X		   interpretation returns non-blocking if CD is down (with
X		   CLOCAL set and NDELAY cleared) this program will function
X		   correctly, although it will eat a small portion of CPU
X		   time to do so.
X		
X		7) Autobaud will wait for a carriage return and use it 
X		   to determine the parity of the caller's terminal (either
X		   8/N/1 or 7/E/1 only).  If the user doesn't press anything
X		   within a reasonable time frame, 8/N/1 is assumed.  The
X		   message "CONNECTED" is output to the user terminal
X		   immediately after autobaud senses the user's baud rate.
X
X		8) All modems served by this have must use the same response
X		   sequences, although subsets are permitted (ie: the
X		   example file above would work for a USR Courier 2400 and
X		   a Telebit Trailblazer Plus equally well).
X
X	CHECK THE FUNCTIONS "checklock()" and "makelock()" -- they may need 
X	to be modified for your system!  In particular, some systems use 
X	binary PIDs and/or store the lock file in a different place.  We 
X	currently are set up for HDB UUCP on ISC 2.0.2/2.2.
X
X	Note that this program can share a port with a modem dialing out on
X	the same line!  It will perform with uucp on the same port without
X	trouble, so long as the locking is done correctly by uucp and other
X	programs which expect lock files.
X
X	Autobaud removes any stale lock files it finds automatically.
X
X*/
X
X#define		MAXSECONDS	60			/* Timeout at start */
X#define		LOGSECONDS	90			/* Timeout at login */
X#define		UUCICO		"/usr/lib/uucp/uucico"	/* Where's uucico? */
X#define		BELL		7			/* Makes a "beep" */
X
X#include	<stdio.h>
X#include	<fcntl.h>
X#include	<sys/types.h>
X#include	<sys/tty.h>
X#include	<utmp.h>
X#include	<signal.h>
X#include	<errno.h>
X#include	<termio.h>
X#include	<sys/stat.h>
X
X/*	Globals		*/
X
int	maschan = -1;		/* Nothing initially; master channel */
int	timeout = 0;		/* Timer value for keeping track of time */
XFILE	*ferr;			/* Error channel */
X
slowwrite(chan, str, len)	/* Write a string slowly to the port */
int	chan, len;
char	*str;
X{	
X	int 	x;
X	char	*ptr;
X	char	ch[2];
X
X	ptr = str;
X	for (x = 0; x < len; x++) {
X		ch[0] = *ptr;
X		write(chan, ch, 1);
X		nap(10);
X		ptr++;
X	}
X	return;
X}
X
checkmatch(matches, mcount, bfr, speed)		/* Any matches in array? */
struct	{
X	char	string[40];
X	int	baud;
X	char	speed[20];
X} matches[];
int	mcount;
char	bfr[];
char	speed[];
X{
X	int	x = 0;
X
X	for (x = 0; x < mcount; x++) {
X		if (!strcmp(bfr, matches[x].string)) {
X			strcpy(speed, matches[x].speed);
X			return(matches[x].baud);
X		}
X	}
X	return(0);
X}
X
X/* 	External declarations	*/
extern	struct	utmp	*getutent(), *pututline();
X
X
X/*	Makelock / Checklock - makes / checks for lock files
X	line		- the line to check for a lock
X	lockflag	- if non-zero, checklock will sleep until it sees the
X			  lock is gone, otherwise it returns status
X			  (checklock only)
X
Returns not zero (-1) if line is locked
X
X*/
X
int	makelock(line)
char	*line;
X{
X
char	tmp[80];
char	tmp2[80];
char	tbfr[20];
int	id;
XFILE	*id2;
int	pid;
struct	stat	st;
X
X	sprintf(tmp, "/usr/spool/locks/LTMP..%d", getpid());
X	sprintf(tmp2, "/usr/spool/locks/LCK..%s", line);
X	if ((id = open(tmp, O_WRONLY|O_CREAT, 0660)) < 0) {
X		exit(1);
X	}
X	sprintf(tbfr, "%10d\n", getpid());
X	tbfr[11] = 0;
X	write(id, tbfr, 11);
X	close(id);
X	if (!stat(UUCICO, &st)) {			/* Find ownership */
X		chown(tmp, st.st_uid, st.st_gid);	/* Set owner/group */
X	}
X	while (link(tmp, tmp2)) {
X		if ((id2 = fopen(tmp2, "r")) == (FILE *) NULL) {
X			sleep(1);			/* Slow down.. */
X			continue;
X		}
X		fscanf(id2, "%d", &pid);		/* Read PID from file */
X		fclose(id2);				/* Be nice.. */
X		if (!kill(pid, 0)) {			/* Oh oh, a process! */
X			return(-1);
X		}
X		unlink(tmp2);
X	}
X	unlink(tmp);
X	return(0);
X}
X
int	checklock(line, lockflag)
char	*line;
int	lockflag;		/* If non-zero, wait for open line */
X{
X
char	ltmp[10];
char	tmp[80];
int	pid;
XFILE	*id;
X	
X	strcpy(ltmp, line);
X	sprintf(tmp, "/usr/spool/locks/LCK..%s", ltmp);	/* Where are locks? */
X	while (!access(tmp, 0)) {			/* If file is there */
X		if ((id = fopen(tmp, "r")) != (FILE *) NULL) {	/* opened? */
X			fscanf(id, " %d", &pid);	/* Get pid from bfr */
X			fclose(id);			/* Clean up */
X			if (kill(pid, 0)) {	/* See if process is alive */
X				if (errno == ESRCH) {	/* Nope; it died */
X					unlink(tmp);	/* Clear lock */
X					continue;	/* Look again */
X				}
X			}
X			if (lockflag) {			/* IF waiting */
X				sleep(1);		/* Wait/keep going */
X			} else {
X				return(-1);		/* Else return locked */
X			}
X		}
X	}
X	if (ltmp[4] <= 'Z')		/* Did idiot use lowercase port name? */
X		ltmp[4] = ltmp[4] + 32;	/* Oh yeah, check it too... */
X	sprintf(tmp, "/usr/spool/locks/LCK..%s", ltmp);	/* Where are locks? */
X	while (!access(tmp, 0)) {			/* If file is there */
X		if ((id = fopen(tmp, "r")) != (FILE *) NULL) {	/* opened? */
X			fscanf(id, " %d", &pid);	/* Get pid from bfr */
X			fclose(id);			/* Clean up */
X			if (kill(pid, 0)) {	/* See if process is alive */
X				if (errno == ESRCH) {	/* Nope; it died */
X					unlink(tmp);	/* Clear lock */
X					continue;	/* Look again */
X				}
X			}
X			if (lockflag) {			/* IF waiting */
X				sleep(1);		/* Wait/keep going */
X			} else {
X				return(-1);		/* Else return locked */
X			}
X		}
X	}
X	return(0);					/* Line is clear */
X}
X
settogetty(line)			/* Mark process in Getty */
char	*line;
X{
X	int	pid;
X	struct	utmp	*u;
X	FILE	*fid;
X
X	pid = getpid();		/* Get our pid */
X	while ((u = getutent()) != NULL) {	/* While there are more lines */
X		if (((u->ut_type == INIT_PROCESS) || (u->ut_type == USER_PROCESS)) && (u->ut_pid == pid)) {
X			strcpy(u->ut_line, line);	/* Set line name */
X			strcpy(u->ut_user, "_Idle");	/* And name */
X			u->ut_pid = getpid();		/* And pid */
X			u->ut_type = LOGIN_PROCESS;	/* And type */
X			pututline(u);			/* Do it */
X			if ((fid = fopen(WTMP_FILE, "a+")) != NULL) {
X				fseek(fid, 0L, 2);	/* Seek end */
X				fwrite((char *) u, sizeof(*u), 1, fid);
X				fclose(fid);		/* Wrote wtmp */
X			}
X			break;
X		}
X	}
X	endutent();
X	return;
X}
X
settologin(line)		/* Tell the system we're at login state */
char	*line;
X{
X	int	pid;
X	struct	utmp	*u;
X
X	pid = getpid();		/* Get our pid */
X	while ((u = getutent()) != NULL) {	/* While there are more lines */
X		if ((u->ut_type == LOGIN_PROCESS) && (u->ut_pid == pid)) {
X			strcpy(u->ut_line, line);
X			strcpy(u->ut_user, "LOGIN");	/* Change name.. */
X			pututline(u);
X		}
X	}
X	endutent();
X	return;
X}
X
setlocked(line)		/* Fake a utmp entry for dialout lines (flagging) */
char	*line;
X{
X	int	pid;
X	struct	utmp	*u;
X
X	pid = getpid();		/* Get our pid */
X	while ((u = getutent()) != NULL) {	/* While there are more lines */
X		if ((u->ut_type == INIT_PROCESS) && (u->ut_pid == pid)) {
X			strcpy(u->ut_line, line);	/* Set line name */
X			strncpy(u->ut_user, "_Dialout", 8);	/* "User" */
X/*			u->ut_type = LOGIN_PROCESS;	*//* If invisible */
X			u->ut_type = USER_PROCESS;	/* It's visible */
X			pututline(u);
X		}
X	}
X	endutent();
X	return;
X}
X
X/*	Catch alarm signals	
X	Does two things -- catches the alarms, and also adds one to the
X	seconds counter.  If the user takes too long call 'hangup()' before
X	returning		*/
X
catch()
X{
X	signal(SIGALRM, catch);		/* Re-enable signal catcher */
X	if (timeout++ >= MAXSECONDS)
X		hangup();		/* Kill the user if he just sat */
X	return;				/* Do nothing else, just exit */
X}
X
X/*	Make upper case into lower case	*/
X
tlc(ptr)
char	*ptr;
X{
X	char	*pt;
X	int 	qm = 0;
X
X	pt = ptr;
X	while (*pt != 0) {
X		if ((*pt >= 'A') && (*pt <= 'Z')) {
X			*pt = *pt + 32;
X			qm++;
X		}
X		pt++;
X	}
X	if (qm) 
X		printf("%c\nWarning: Please use *lower* case on this system%c\n", BELL, BELL);
X	return;
X}
X
X
hangup()	 /*	Make sure the phone gets hung up when we exit	*/
X{
X	struct	termio	tt_array;
X	
X	if (maschan < 0)
X		exit(1);				/* Just exit */
X	if (ioctl(maschan, TCGETA, &tt_array)) {	/* No delay */
X		perror("Get parameter error");
X		exit(1);
X	}
X	tt_array.c_cflag &= ~(CBAUD|CLOCAL);		/* Set baud to 0 */
X	tt_array.c_cflag |= HUPCL|CREAD|CS8;		/* Set hangup */
X
X	if (ioctl(maschan, TCSETA, &tt_array)) {	/* No delay */
X		perror("Hang up error");
X		exit(1);
X	}
X	exit(0);
X}
X
X/*	Here is where all the fun begins; the main program 	*/
X
main(argc, argv)
int	argc;
char	*argv[];
X{
X	int	debug = 0;
X	int	x, ch, sw, status;
X	struct	termio	tt_array;
X	FILE	*fid, *fid2;
X	static	char	tmp[80], loginp[80];
X	extern	struct utmp *getutent(), *pututline();
X	char	baud[132];
X	int	fbaud = 0;
X	int	sbaud = 0;
X	char	line[80];
X	struct	stat	st;
X	char	init[80];
X	char	iresp[80];
X	int	initbaud;
X	char	speed[20];
X	struct	{
X		char	string[40];
X		int	baud;
X		char	speed[20];
X	} matches[20];
X	int	mcount = 0;
X	int	bcount = 0;
X	char	bc[2];
X	char	bfr[20];
X	int	satisfied = 0;
X	int	hoseline;
X	int	quit = 0;
X
X	signal(SIGALRM, catch);			/* Catch alarms */
X	signal(SIGINT, SIG_IGN);		/* Ignore interrupts */
X	if (argc > 3)
X		debug++;
X	initbaud = atoi(argv[2]);		/* Initial baud rate */
X	strcpy(init, "ATZ\r");			/* Send this to init */
X	fid = fopen("/etc/autobaud.parm", "r");	/* Try to open it */
X	if (fid != (FILE *) NULL) {
X		fgets(init, 80, fid);		/* Init string */
X		fscanf(fid, " %s", iresp);
X		while (fgets(tmp, 80, fid) != (char *) NULL) {
X			sscanf(tmp, "%d %[!-z] %[!-z ]", &matches[mcount].baud, matches[mcount].speed, matches[mcount].string);
X			mcount++;
X		}
X		fclose(fid);
X		init[strlen(init) - 1] = '\r';	/* Make last a return */
X	}
X	strcpy(line, argv[1]);			/* Look on this line */
X	setlocked(argv[1]);			/* Set port id to locked */
X	sprintf(tmp, "/dev/%s", line);		/* Check the line */
X	if (!stat(UUCICO, &st)) {		/* Who owns uucp? */
X		chown(tmp, st.st_uid, st.st_gid);/* Set line owner & group */
X		chmod(tmp, 0660);
X	}
X	checklock(line, 1);			/* Wait for no locks */
X	settogetty(argv[1]);			/* Mark us as in 'getty' */
X#ifndef	DEBUG
X	close(0);				/* Close stdin,stdout,stderr */
X	close(1);
X	close(2);
X	(void) setpgrp();			/* Make sure we have our own
X					   	   control terminal */
X#endif
X	sprintf(tmp, "/dev/%s", argv[1]);
X	if ((x = open(tmp, O_RDWR|O_NDELAY)) < 0) {/* BECOMES CONTROL TERM */
X		exit(1);			/* Exit; error! */
X	}					/* End of line.. */
X	maschan = x;				/* Master I/O channel */
X	tt_array.c_cflag = (HUPCL|CLOCAL|CS8|CREAD);
X	tt_array.c_cc[VMIN] = 1;
X	tt_array.c_cc[VTIME] = 1;		/* Set parameters */
X	if (ioctl(maschan, TCSETAW, &tt_array) == -1) {/* Set DTR down */
X		exit(1);
X	}
X	sleep(1);
X	tt_array.c_cflag |= initbaud;		/* Set initial baud rate */
X	checklock(line, 0);			/* Exit if locked */
X	if (ioctl(maschan, TCSETAW, &tt_array) == -1) {/* Set parameters */
X		exit(1);
X	}
X	sleep(1);
X	if ((status = fcntl(x, F_GETFL, 0)) != -1) {
X		status &= (~O_NDELAY);
X		if (fcntl(x, F_SETFL, status)) {	/* Clear O_NDELAY */
X			exit(0);
X		}
X	}
X	status = fcntl(maschan, F_GETFL, 0);	/* Read it again to be sure */
X	sleep(1);				/* Allow modem to settle */
X	checklock(line, 0);			/* Exit if locked */
X	timeout = 0;				/* No timeout yet */
X	slowwrite(maschan, init, strlen(init));/* Write initialization */
X	if (debug)
X		fprintf(ferr, "%x\n", status);
X	signal(SIGALRM, hangup);		/* Quit on timeout */
X	bcount = 0;
X	alarm(5);				/* Wait 5 seconds tops */
X	while (!quit) {				/* Check return from init */
X		if (!read(maschan, bc, 1)) {	/* Look for a character */
X			sleep(1);
X			continue;
X		}
X		if (debug)
X			fprintf(ferr, " %d\n", bc[0]);
X		if ((bc[0] == 10) || (bc[0] == 13)) {
X			if (strcmp(bfr, iresp)) {/* If not correct response */
X				bcount = 0;	/* Then drop it */
X				continue;	/* Keep looking */
X			} else {
X				quit++;		/* Else done */
X			}
X		} else {
X			bfr[bcount++] = bc[0];	/* Save character */
X			bfr[bcount] = 0;	/* Null terminate */
X		}
X	}
X	dup(maschan);
X	dup(maschan);	
X	ferr = fopen("/dev/console", "w");	/* Write to console for errs */
X	alarm(0);				/* Turn off timeout */
X	strcpy(line, argv[1]);			/* Look on this line */
X	if (checklock(line, 0))			/* Check lock status again */
X		exit(0);			/* Exit if line is locked */
X	satisfied = 0;
X	bcount = 0;				/* Nothing in buffer */
X	while (!satisfied) {			/* Read result codes */
X		if (!read(maschan, bc, 1)) {	/* Look for a character */
X			sleep(2);
X			continue;
X		}
X		if (checklock(line, 0))		/* Locked by someone else? */
X			exit(0);		/* Quit if so */
X		if ((bc[0] == 10) || (bc[0] == 13)) {	/* New line? */
X			satisfied = checkmatch(matches, mcount, bfr, speed);
X			if (!satisfied) {
X				bcount = 0;
X			}
X		} else {
X			bfr[bcount++] = bc[0];		/* Store character */
X			bfr[bcount] = 0;		/* Null terminate */
X		}
X	}
X	if (makelock(line)) {			/* This is VERY bad! */
X		exit(0);			/* Quit right now! */
X	}
X	sprintf(baud, "%s @ %s bps", line, speed);
X	fid2 = fdopen(maschan, "a+");	/* Give us a stream channel please */
X	ioctl(maschan, TCFLSH, 2);	/* Flush input & output */
X	sleep(1);			/* Wait a second for settling... */
X	fprintf(fid2, "CONNECTED\r\n");
X	fflush(fid2);
X	signal(SIGALRM, catch);
X	timeout = 0;
X	alarm(10);
X	if (read(maschan, bc, 1) > 0) {
X		switch(bc[0]) {
X			case 13:
X			case 10:
X				strcat(baud, ", 8/N/1");
X				goto aexit;		/* Do nothing */
X				break;
X			case -115:		/* If signed... */
X			case 141:		/* 7/E/1, but otherwise ok */
X				tt_array.c_cflag &= (~CS8);
X				tt_array.c_cflag |= (CS7|PARENB);
X				ioctl(maschan, TCSETAW, &tt_array);
X				ioctl((maschan + 1), TCSETAW, &tt_array);
X				ioctl((maschan + 2), TCSETAW, &tt_array);
X				strcat(baud, ", 7/E/1");
X				goto aexit;
X				break;
X		}
X	}
aexit:;
X	tt_array.c_cflag &= (~(CBAUD|CLOCAL));
X	tt_array.c_cflag |= (satisfied|HUPCL);	/* New baud rate */
X	tt_array.c_oflag |= OPOST|ONLCR;
X
X/*	If available, enable CTS flow control.  This is necessary for
X	Telebit Trailblazers and others of the general type.  Unfortunately,
X	only SCO has these things... (grr)  
X*/
X
X#ifdef	HARDWARE_FLOW
X	tt_array.c_iflag |= BRKINT|IGNPAR|INPCK|ICRNL;
X	tt_array.c_cflag |= HUPCL|CTSFLOW|RTSFLOW;
X#else
X	tt_array.c_iflag |= BRKINT|IGNPAR|INPCK|ICRNL|IXON|IXANY;
X	tt_array.c_cflag |= HUPCL;
X#endif
X	tt_array.c_lflag |= ISIG|ICANON|ECHO|ECHOE|ECHOK;
X	tt_array.c_cc[VINTR] = 177;
X	tt_array.c_cc[VQUIT] = 0;
X	tt_array.c_cc[VERASE] = 8;
X	tt_array.c_cc[VKILL] = 21;
X	tt_array.c_cc[VEOF] = 4;
X	tt_array.c_cc[VEOL] = 0;
X	ioctl(maschan, TCSETAW, &tt_array);	/* Set parameters */
X	ioctl((maschan + 1), TCSETAW, &tt_array);
X	ioctl((maschan + 2), TCSETAW, &tt_array);
X	signal(SIGALRM, hangup);	/* If we time out, hang up the line */
X	alarm(LOGSECONDS);		/* LOGSECONDS to read/reply, then out */
X	fprintf(fid2, "\n[%s]\n", baud);/* Display parameters we found */
X	if ((fid = fopen("/etc/issue.new", "r")) != NULL) {
X		fgets(loginp, 80, fid);	/* Get login prompt */
X		loginp[strlen(loginp)-1] = 0;
X		while (fgets(tmp, 80, fid) != NULL) {	/* Display issue file */
X			fputs(tmp, fid2);
X		}
X		fclose(fid);
X	}
X	fputs("\r\n", fid2);		/* End with another <return> */
bg1:;
X	fputs(loginp, fid2);		/* Prompt for login name */
X	fgets(tmp, 80, fid2);		/* Read it, but don't allow overrun */
X	if (*tmp == 10)			/* If nothing, ask again */
X		goto bg1;
X	tmp[strlen(tmp)-1] = 0;		/* Make sure null terminated */
X	tlc(tmp);			/* Lower case the name */
X	signal(SIGINT, SIG_DFL);	/* Reset signal handling */
X	signal(SIGALRM, SIG_DFL);
X	alarm(0);			/* Clear alarm */
X	fclose(ferr);			/* Close error channel */
X/*
X * Take two shots at where login is.  If we can't find it in either of these
X * places you're screwed; dump the caller.  Try to tell the user if this
X * happens, but no guarantees....
X */
X
X	execlp("/etc/login", "login", tmp, (char *) NULL);
X	execlp("/bin/login", "login", tmp, (char *) NULL);
X	fputs("Login not executable; contact administrator\n", fid2);
X	fflush(fid2);			/* Make sure it's printed */
X	sleep(3);			/* Wait for output to drain */
X	exit(1);			/* And quit with error (ignored) */
X}
X
END_OF_FILE
if test 18668 -ne `wc -c <'autonew.c'`; then
    echo shar: \"'autonew.c'\" unpacked with wrong size!
fi
# end of 'autonew.c'
fi
echo shar: End of shell archive.
exit 0

gemini@geminix.mbx.sub.org (Uwe Doering) (09/06/90)

karl@ddsw1.MCS.COM (Karl Denninger) writes:

>In article <9009011253.AA13674@esegue.segue.boston.ma.us> johnl@esegue.segue.boston.ma.us (John R. Levine) writes:
>>
>>Rather than using uugetty, use either the async driver on the X5 or X6
>>update disks, or else the public FAS driver posted here.  Both of them
>>provide separate /dev entries for dialin and dialout, so you can run a
>>modem both ways without uugetty.  I have used both, and they both work.
>>
>>FAS is somewhat faster, X5/X6 supports VP/ix.  Both take advantage of
>>the extra buffering in a 16550 ASYNC chip.
>
>That does NOT solve one problem:
>
>o You dial out on the non-modem control port.  The call completes, then
>  drops.  How do you detect it?  The answer?  You don't!

This isn't true for FAS. Even on the dialout port you have (by default)
modem control, that is, the processes on the port get the SIGHUP signal
if the carrier drops, and from thereon the port is unusable until it
is again set up by an ioctl call or it is closed. Therefor you don't
need to change anything on your system to do proper dialin/dialout on
the same port. But on the other hand, having `getty' sources isn't
a bad thing anyway.

BTW, FAS 2.07 (not yet released) _will_ have VP/ix support. You won't
need the X5/X6 drivers any more. :-)

>	ISC does not correctly support CLOCAL on modem control lines.  If
>	you open a port with O_NDELAY, then set CLOCAL and clear O_NDELAY
>	with fcntl, you should get BLOCKING reads with the CD signal
>	ignored.  Instead you get non-blocking reads if CD is low, and
>	blocking reads if CD is high (idiots!).
> [stuff deleted]
>	Unfortunately, Equinox and a few other board makers have mimiced the
>	broken code instead of fixing it (double idiots!).

Just to be complete, FAS doesn't have this bug.

     Uwe
-- 
Uwe Doering  |  USA      : gemini@geminix.mbx.sub.org
Berlin       |  World    : gemini%geminix@tmpmbx.UUCP
Germany      |  Bangpath : ...!{backbone}!tmpmbx!geminix!gemini

karl@ddsw1.MCS.COM (Karl Denninger) (09/09/90)

In article <NB7IOGG@geminix.mbx.sub.org> gemini@geminix.mbx.sub.org (Uwe Doering) writes:
>karl@ddsw1.MCS.COM (Karl Denninger) writes:
>
>>In article <9009011253.AA13674@esegue.segue.boston.ma.us> johnl@esegue.segue.boston.ma.us (John R. Levine) writes:
>>>
>>>FAS is somewhat faster, X5/X6 supports VP/ix.  Both take advantage of
>>>the extra buffering in a 16550 ASYNC chip.

>>That does NOT solve one problem:

>>o You dial out on the non-modem control port.  The call completes, then
>>  drops.  How do you detect it?  The answer?  You don't!
>
>This isn't true for FAS. Even on the dialout port you have (by default)
>modem control, that is, the processes on the port get the SIGHUP signal
>if the carrier drops, and from thereon the port is unusable until it
>is again set up by an ioctl call or it is closed. Therefor you don't
>need to change anything on your system to do proper dialin/dialout on
>the same port. But on the other hand, having `getty' sources isn't
>a bad thing anyway.

Uh, I don't like that idea.  The port should NOT be unusable, nor should it
be automatically closed.  That's not the idea; to send SIGHUP certainly is.

The former "idea" can leave you with a hung line if something doesn't
release itself when it gets SIGHUP (ie: a hung process, etc).  Unless you've
also fixed the ISC line discipline, this kind of pathological behavior is
easy to produce, and damnable when it happens.  Writing line disciplines is
often harder than doing drivers, especially since it's difficult to locate
ANY documentation on what it's supposed to really do!

>BTW, FAS 2.07 (not yet released) _will_ have VP/ix support. You won't
>need the X5/X6 drivers any more. :-)

For outgoing connections AND terminal use?  Half the solution doesn't do
much; if I can run a mouse off it (ie: COM1MOUSE works) then you've got
something.

>>	ISC does not correctly support CLOCAL on modem control lines.  If
>>	you open a port with O_NDELAY, then set CLOCAL and clear O_NDELAY
>>	with fcntl, you should get BLOCKING reads with the CD signal
>>	ignored.  Instead you get non-blocking reads if CD is low, and
>>	blocking reads if CD is high (idiots!).
>> [stuff deleted]
>>	Unfortunately, Equinox and a few other board makers have mimiced the
>>	broken code instead of fixing it (double idiots!).
>
>Just to be complete, FAS doesn't have this bug.

Equinox finally listened.  Maybe people took my advice literally and beat
them over the head to fix this problem; I don't know, we solved in two weeks
with a Usenet posting what 6 months of asking nicely didn't accomplish.  I
don't have the "fixed" drivers yet, but should within a week.

Much as I hate to say it, most manufacturers work best when you hit them
over the head with a ton of bricks rather than ask nicely.  Too bad, but
'tis life. 

--
Karl Denninger (karl@ddsw1.MCS.COM, <well-connected>!ddsw1!karl)
Public Access Data Line: [+1 708 808-7300], Voice: [+1 708 808-7200]
Macro Computer Solutions, Inc.   "Quality Solutions at a Fair Price"

gemini@geminix.mbx.sub.org (Uwe Doering) (09/10/90)

karl@ddsw1.MCS.COM (Karl Denninger) writes:

>In article <NB7IOGG@geminix.mbx.sub.org> gemini@geminix.mbx.sub.org (Uwe Doering) writes:
>>karl@ddsw1.MCS.COM (Karl Denninger) writes:
>
>>>That does NOT solve one problem:
>
>>>o You dial out on the non-modem control port.  The call completes, then
>>>  drops.  How do you detect it?  The answer?  You don't!
>>
>>This isn't true for FAS. Even on the dialout port you have (by default)
>>modem control, that is, the processes on the port get the SIGHUP signal
>>if the carrier drops, and from thereon the port is unusable until it
>>is again set up by an ioctl call or it is closed. Therefor you don't
>>need to change anything on your system to do proper dialin/dialout on
>>the same port. But on the other hand, having `getty' sources isn't
>>a bad thing anyway.
>
>Uh, I don't like that idea.  The port should NOT be unusable, nor should it
>be automatically closed.  That's not the idea; to send SIGHUP certainly is.
>
>The former "idea" can leave you with a hung line if something doesn't
>release itself when it gets SIGHUP (ie: a hung process, etc).  Unless you've
>also fixed the ISC line discipline, this kind of pathological behavior is
>easy to produce, and damnable when it happens.  Writing line disciplines is
>often harder than doing drivers, especially since it's difficult to locate
>ANY documentation on what it's supposed to really do!

I haven't fixed the line discipline. First, the design goal for the
dialout ports with modem control was that their behaviour is the same
as with getty ports, with the only difference that they ignore the
DCD line until this line goes to high. After that it will behave
exactly like the getty ports.

When I sayed that the port is unusable after a DCD drop I meant that it
does the same as a getty port after a DCD drop: Read and write system
calls return immediately with a result of 0 which should be detected
as an error by any well-written program (`uucico' does this, and other
programs as well). Therefor you won't have hung processes.

The worst thing that could happen is that a program is brain-dead enough
to go into an infinite loop if it ignores the SIGHUP signal and doesn't
check the read/write return values. But that's not a problem with the
serial driver. It's a problem with the application programmer not knowing
what he's doing.

If I would leave the port enabled after the DCD drop a program that ignores
SIGHUP would continue to receive and send data, and this could easily
lead to a nice chat between the modem and the program because the modem
is in the command mode after a DCD drop. This is definately not what
should happen! This could even destroy your EEPROM modem setup as all
these things usually follow Murphy's Law. :-(

I can assure you that there are only few (if any) problems with real-
world applications and FAS. This DCD behaviour was the same with all
previous releases of FAS, and I yet have to find a program that refuses
to work on the dialout port. I haven't got any reports about this issue,
either.

Therefor, I still think it's much worse to let a program read/write
from/to the port when it isn't supposed to, than to disable the port
until the program explicitely sets it up again either by closing and
reopening the port or by an ioctl call with the TCSETA{W|F} command.
As I said this works with all the programs I've used so far. And
if a program wants to ignore DCD completely it can do so by setting
the CLOCAL termio(7) flag.

>>BTW, FAS 2.07 (not yet released) _will_ have VP/ix support. You won't
>>need the X5/X6 drivers any more. :-)
>
>For outgoing connections AND terminal use?  Half the solution doesn't do
>much; if I can run a mouse off it (ie: COM1MOUSE works) then you've got
>something.

Yes, COM1MOUSE works as well as COM1, and you can use COM2 at the same
time. I've used the telecommunication program Telemate 2.10 to talk
to a modem on COM2 while I could move the mouse cursor with a mouse
on COM1.

And if you dial in via a modem (or have a dos mode terminal connected
to the computer) you can start VP/ix directly on this serial line.
I tried this with a VT100 terminal emulation and to my surprise I
could use several fullscreen DOS applications. :-) Even if the modem
carrier drops while you are in VP/ix the DOS emulator won't hang the
line but instead will exit due to a SIGHUP signal.

Karl, is this what you had in mind?

        Uwe
-- 
Uwe Doering  |  USA      : gemini@geminix.mbx.sub.org
Berlin       |  World    : gemini%geminix@tmpmbx.UUCP
Germany      |  Bangpath : ...!{backbone}!tmpmbx!geminix!gemini

karl@naitc.uucp (Karl Denninger) (09/13/90)

In article <3QBJ5BI@geminix.mbx.sub.org> gemini@geminix.mbx.sub.org (Uwe Doering) writes:
>I haven't fixed the line discipline. First, the design goal for the
>dialout ports with modem control was that their behaviour is the same
>as with getty ports, with the only difference that they ignore the
>DCD line until this line goes to high. After that it will behave
>exactly like the getty ports......

Ok, I guess that's ok.  It's not quite what I had in mind, but it should
work ok for most purposes.

>I can assure you that there are only few (if any) problems with real-
>world applications and FAS. This DCD behaviour was the same with all
>previous releases of FAS, and I yet have to find a program that refuses
>to work on the dialout port. I haven't got any reports about this issue,
>either.
>
>Therefor, I still think it's much worse to let a program read/write
>from/to the port when it isn't supposed to, than to disable the port
>until the program explicitely sets it up again either by closing and
>reopening the port or by an ioctl call with the TCSETA{W|F} command.
>As I said this works with all the programs I've used so far. And
>if a program wants to ignore DCD completely it can do so by setting
>the CLOCAL termio(7) flag.

That is ok, providing that O_NDELAY toggling and control is properly
implemented.  You've said that it is; this is good.

>>>BTW, FAS 2.07 (not yet released) _will_ have VP/ix support. You won't
>>>need the X5/X6 drivers any more. :-)
>>
>>For outgoing connections AND terminal use?  Half the solution doesn't do
>>much; if I can run a mouse off it (ie: COM1MOUSE works) then you've got
>>something.
>
>Yes, COM1MOUSE works as well as COM1, and you can use COM2 at the same
>time. I've used the telecommunication program Telemate 2.10 to talk
>to a modem on COM2 while I could move the mouse cursor with a mouse
>on COM1.

That's necesasry in order to be able to say you have VP/ix support.  More
than one vendor doesn't do the second half of the job...

>And if you dial in via a modem (or have a dos mode terminal connected
>to the computer) you can start VP/ix directly on this serial line.
>I tried this with a VT100 terminal emulation and to my surprise I
>could use several fullscreen DOS applications. :-) Even if the modem
>carrier drops while you are in VP/ix the DOS emulator won't hang the
>line but instead will exit due to a SIGHUP signal.
>
>Karl, is this what you had in mind?

Yes, it is.  Unfortunately, it only handles dumb ports.  Too bad; you can't
get enough of them in with a reasonable impact on the system, even with
16550's.


--
Karl Denninger	AC Nielsen
kdenning@ksun.naitc.com
(708) 317-3285
Disclaimer:  Contents represent opinions of the author; I do not speak for
	     AC Nielsen on Usenet.