[comp.sources.misc] prelog.c, a getty like front end for UNOS, mostly UNIX compatable

crds@t.UUCP (Who Am I) (10/15/87)

#!/bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #!/bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
#	prelog.c
# This archive created: Sun Oct 11 06:12:11 1987
export PATH; PATH=/bin:$PATH
if test -f 'prelog.c'
then
	echo shar: over-writing existing file "'prelog.c'"
fi
cat << \SHAR_EOF > 'prelog.c'
/*
 * 	prelog.c	Version 1.0	Glenn A. Emelko		10/10/87
 *
 *	First of all, I do hereby declare this code as a completely original
 *	program, inspired by many but written by one (me).  I hereby grant
 *	anyone permission to use this code as public domain, for the sole
 *	purpose of understanding, learning, or simply implementation of any
 *	or all of the concepts herein.  I hereby restrict the usage of this
 *	code to NON-PROFIT purposes; no portions of this code should be used
 *	by anyone in any way, shape, or form, in order to promote gain to
 *	either self or others (except me, but I'll never do that).  This
 *	restriction also stipulates that any of the above words, as well
 *	these, shall be proliferated with this code until doomsday (or after).
 *
 *	Thank you.
 *
 *	This program was written and developed on a Charles River Data Systems
 *	Universe 68/35 running UNOS 5.1.  The purpose was to provide a login
 *	preprocessor similar to getty, which would automatically detect baud
 *	rate, set the entry in the /etc/ttys file for the proper baud setting,
 *	and then execute the original login processor to log in a user.  No
 *	attempt has been made at this point to test this code with signals,
 *	but it is my belief that it should work properly.
 *
 *
 *	The file /etc/ttys must be maintained properly for the original UNOS
 *	login procedure to set the baud rate during the login procedeure.  I
 *	have added a field in /etc/ttys which will determine which baud table
 *	is used for rotary baud selection.  Baud selection is accomplished by
 *	sensing for two carriage returns, and if they are not found adjacent
 *	to each other, waiting for no data, and then rotoring to the next baud
 *	selection, and repeating.  During this time, either nothing, or a
 *	message (see rotormsg) may be sent to the terminal as each rate is
 *	rotored through.
 *
 *	Support in the code exists to start up and drive a "ATxx" compatable
 *	modem, and it may be desirable to take advantage of the carrier
 *	message to determine baud selection directly, rather than rotoring.
 *
 *	The /etc/ttys file has single line items for each tty device, with
 *	the information fields delimited by colons.  I did not put in the
 *	necessary support for continuation lines; it can be safely left as
 *	an exercise to the guru [smile].  The format of the /etc/ttys file
 *	is as follows:
 *
 *	state:lineno:devpath:devid:terminal:ttymodes:comments:extra
 *
 *	where [in brackets is the maximum field with allowed by prelog]:
 *
 *		state [12] -- either "on" or something else; on indicating an
 *			active login port, and anything else indicating an
 *			i/o port for other usage.
 *
 *		lineno [4] -- logical tty number, on the CRDS, it corresponds
 *			to last number in the device path, whichhas a range
 *			from 0 to 11.
 *
 *		dpath [12] -- the full path of the tty device.  Something like
 *			"/dev/tty4" is valid.
 *
 *		devnum [6] -- The system major and minor device number.  On
 *			the CRDS, this is 1/nn, where nn is the tty number.
 *
 *		ttyid [12] -- this is the terminal id assumed to be connected
 *			to the line; it is looked up in the termcap entries
 *			to set terminal parameters.  Something like "vt100"
 *			is valid.
 *
 *		tbaud [20] -- this is the entry read to set terminal modes on
 *			the tty device.  This entry is passed by the original
 *			login program to an internal UNOS specific system call
 *			called _ttymodes.  The standard /etc/ttys file only
 *			sets the baud rate by this field, and this is where
 *			prelog puts its speed setting after it has detected
 *			the speed.  A standard UNOS entry in this field is
 *			something like "speed=9600".
 *			NOTE: THIS FIELD IS MODIFIED BY prelog.
 *
 *		tsetb [30] -- this field was the comment field associated with
 *			the tty device.  I commandeered this field, and have
 *			given it new meaning; the FIRST character of this
 *			field shall be a '0' thru '9', identifying which table
 *			prelog shall use to select its baud rates by, as well
 *			as control a modem by.  The DEFAULT setting is 0 or
 *			a non-numeric character, which are treated the same.
 *			In this default mode, the baud rate will NOT be auto
 *			selected, instead, the ttymodes field will be used
 *			as is, without changing it.  See the tables for the
 *			other possible values.  The REST of this field may
 *			still be used for comments of any sort.
 *			NOTE: THIS FIELD IS CHECKED BY prelog.
 *
 *		extra [30] -- Well, your guess is as good as mine.  This
 *			field may or may not even exist on some of the
 *			entries; in fact there are some extra colons at the
 *			end of some lines in my own ttys file.  Anything
 *			after the comments field is captured verbatim, so it
 *			will be put back exactly the same way it came out.
 *
 *	One last thing, before we get on with the program....
 *
 *	INSTALLATION
 *
 *	To install this program on a CRDS under UNOS 5.1, compile it with cc,
 *	move /sys/login to /sys/post_login, and move the compiled code to
 *	/sys/login.  This is all that is needed, it will take over once you
 *	log off.  For other versions of UNOS or other UNIX machines, I will
 *	say that YOU ARE AT YOUR OWN RISK -- playing with /sys/login is a
 *	very dangerous thing to do, and I do not recomment it for those who
 *	are weak at heart.  I crashed my CRDS completely several times; even
 *	though I had multiple ttys logged in to try to have recoverable
 *	system problems, occasionally the WHOLE SYSTEM came to it's knees --
 *	I get the feeling it really didn't like what I was doing.  Please
 *	note that this was an experimental time, and NOW it works fine, I
 *	have been running my new login procedure for several weeks.  You may
 *	also wish to run "strip" on the new /sys/login file, to cut down its
 *	storage requirements on the disk (strip removes symbolic information).
 */

#include <fcntl.h>				/* For file i/o		*/
#include <sgtty.h>				/* For tty modes	*/
#include <signal.h>				/* for sigquit/sighup	*/
#include <stdio.h>				/* for fprintf		*/
#include <sys/utsname.h>			/* for uname call	*/
#include <termio.h>				/* for terminal setting	*/

int at_init();

int no_init(){};

struct ttyentry {
    char state[12];				/* state "on" or other	*/
    char lineno[4];				/* lineno (range 0-11)	*/
    char dpath[12];				/* device path /dev/tty	*/
    char devnum[6];				/* major/minor, 1/nn	*/
    char ttyid[12];				/* tty type, i.e. vt100	*/
    char tbaud[20];				/* baud, speed=9600	*/
    char tsetb[30];				/* table (0-9), remark	*/
    char extra[30];				/* anything else ?	*/
} ttys[20];					/* NOTE max 20 entries	*/

int ttys_count;					/* count of entries	*/
int myttyentry;					/* which entry am I?	*/

FILE *ttysfile;					/* fildes for /etc/ttys */

int tty_lun;					/* login terminal unit	*/
FILE *indev;					/* stdin/stdout		*/
FILE *outdev;

struct sgttyb tty_mode;				/* tty settings struct	*/

char post_login[] = "/sys/post_login";		/* orig. login program	*/

char s110[]	= "speed=110";			/* Text for ttymodes	*/
char s300[]	= "speed=300";
char s1200[]	= "speed=1200";
char s9600[]	= "speed=9600";
char s38400[]	= "speed=38400";

char ttymatch[] = "/dev/tty?? ";		/* reserve space	*/

char rotormsg[] = "\007";

struct tset {
	char	tableid;			/* table name ('0'-'9')	*/
	int	(*Line_init)();			/* anything to do first	*/
	char	rotori;				/* rotor name ('A'-'Z')	*/
} tsets[] = {

	'0',no_init,\0,		/* tset 0, no init, use /etc/ttys	*/

	'1',no_init,'A',	/* tset 1, no init, use rotor A		*/

	'2',at_init,'B',	/* tset 2, "ATxx" init, use rotor B	*/

	\0,no_init,\0		/* End of table, no init, use /etc/ttys */
};

#define NUMTSETS sizeof tsets/sizeof tsets[0]

struct rotor {
	char	rotorid;			/* rotor name ('A'-'Z')	*/
	int	flags;				/* Sense setup flags	*/
	int	speed;				/* Baud flags		*/
	char	*tbaudset;			/* ttys tbaud setting	*/
} rotors[] = {

	'A',CR1+NL1+CRMOD+RAW,B9600,s9600,	/*A, flags, ibaud, text	*/
	'A',CR1+NL1+CRMOD+RAW,B38400,s38400,	/*A, flags, ibaud, text	*/
	'A',CR1+NL1+CRMOD+RAW,B1200,s1200,	/*A, flags, ibaud, text	*/
	'A',CR1+NL1+CRMOD+RAW,B1200,s1200,	/*A, flags, ibaud, text	*/

	'B',CR1+NL1+CRMOD+RAW,B300,s300,	/*A, flags, ibaud, text	*/
	'B',CR1+NL1+CRMOD+RAW,B1200,s1200,	/*A, flags, ibaud, text	*/

	\0,0,0,(char *)\0		/* End of table */
};

main(argc,argv)
int argc;
char **argv;
{
    struct utsname sysname;			/* utsname definition	*/
    char tsetgo;				/* default use table 0	*/
    char rotorgo;				/* search character	*/
    int i,j;					/* general purpose	*/
    int tsetnum, rotornum;			/* pointer counts	*/
    char chr;					/* general purpuse	*/

    uname(&sysname);				/* Get system name	*/

    if (argc==1) {
	tty_lun = fdown(outdev=stdout);		/* get tty logical unit	*/
	indev = stdin;				/* get i/o devices	*/
    } else {
	tty_lun = fdown(outdev=fileopen(argv[1],"w"));
						/* get tty logical unit */
	indev = fileopen(argv[1],"r");		/* and get i/o devices	*/
    }

    setbuf(indev,NULL);				/* no i/o buffering	*/
    setbuf(outdev,NULL);
    
    strcpy(ttymatch,ttyname(tty_lun));		/* save device path	*/
    setctlterm(tty_lun);			/* set controlling term	*/
    tty_lun=open(ttymatch,O_RDWR);		/* reopen device for us	*/

    ttys_count = 0;
    ttysfile = fopen("/etc/ttys","r");		/* get /etc/ttys info	*/
    while (fread(&chr,1,1,ttysfile)>0)		/* if chr, get entry	*/
	getentry(chr);
    fclose(ttysfile);				/* have ttys information*/

    for(i=0;i<ttys_count;i++) {			/* scan ttys entries	*/
	if (0==strcmp(ttymatch,ttys[i].dpath)) {/* if it matches...	*/
	    tsetgo = *ttys[i].tsetb;		/* get character	*/
	    if ((tsetgo<'0') || (tsetgo>'9'))	/* resort to default?	*/
		tsetgo='0';
	}
    }

    for(tsetnum=0;tsetnum<(NUMTSETS);tsetnum++)	/* find tsetgo in tsets*/
	if (tsets[tsetnum].tableid==tsetgo) break;

    (*tsets[tsetnum].Line_init)();		/* Initialize the line	*/

    rotorgo = tsets[tsetnum].rotori;		/* get the rotor ident	*/

    while (rotorgo!=\0) {			/* do until cr detect	*/
						/* unless rotorgo is 0	*/
	rotornum=0;				/* start at first rotor	*/
	while (rotors[rotornum].rotorid!=rotorgo) {/* scan list for match*/
	    rotornum++;				/* go to next if not	*/
	    if (rotors[rotornum].rotorid==\0)	/* did we not find it?	*/
		rotorgo = \0;			/* Not found, GET OUT!	*/
	}
	if (rotorgo!=\0) {			/* now scan good ones	*/
	    while (rotors[rotornum].rotorid==rotorgo) {
						/* for each valid entry	*/
		tty_mode.sg_erase = CERASE;	/* prepare parameters	*/
		tty_mode.sg_kill = CKILL;
		tty_mode.sg_flags = rotors[rotornum].flags;
		tty_mode.sg_ispeed = rotors[rotornum].speed;
		tty_mode.sg_ospeed = rotors[rotornum].speed;
		stty(tty_lun,&tty_mode);	/* set tty parameters	*/
		delay(1);
		j=0;				/* count of cr's	*/
		while ((j<2) && (read(tty_lun,&chr,1)>0)) {
		/* go until 2 cr's, eof, or we get a bad chr		*/
		    if ((chr=='\n') || (chr=='\r')) {
			fprintf(outdev,rotormsg);
			j++;			/* count them		*/
		    }
		    else
			break;
		}

		if (j==2) {			/* we got 2 cr's, GO!	*/

		    ttys_count = 0;
		    ttysfile = fopen("/etc/ttys","r");	/* do it again	*/
		    while (fread(&chr,1,1,ttysfile)>0)	/* get entry	*/
			getentry(chr);
		    fclose(ttysfile);		/* have ttys information*/

		    ttysfile = fopen("/etc/ttys","w");	/* now update	*/
		    for(i=0;i<ttys_count;i++) {
			if (0==strcmp(ttymatch,ttys[i].dpath))
			    strcpy(ttys[i].tbaud,rotors[rotornum].tbaudset);
						/* match entry & change	*/
			fprintf(ttysfile,"%s:%s:%s:%s:%s:%s:%s:%s\n",
			    ttys[i].state,
			    ttys[i].lineno,
			    ttys[i].dpath,
			    ttys[i].devnum,
			    ttys[i].ttyid,
			    ttys[i].tbaud,
			    ttys[i].tsetb,
			    ttys[i].extra
			);			/* put back in file	*/
		    };
		    fclose(ttysfile);
		    rotorgo = \0;		/* done, exit		*/
		} else {
		    rotornum++;			/* otherwise next entry	*/
		}
	    } /* end while matching rotorgo */
	} /* end if (rotorgo) */
    } /* end while (rotorgo) */

    fprintf(outdev,"\n\nCharles River Data Systems 68/35");
    if (*sysname.nodename)			/* if nodename, print it*/
	fprintf(outdev," (%s)",sysname.nodename);
    fprintf(outdev,"\n\015");

    fexecl(post_login, indev, outdev, outdev, "login", ttymatch, 0);
    exit(1);					/* Never get here???	*/
}

getentry(a) /* parse entry from /etc/ttys file, increment ttys_count */
char a;
{
    char *ptr;				/* field pointer in record	*/
    char *tbl[8];			/* ttys record field pointers	*/
    int i;				/* field number, general purpose*/

    tbl[0]=ttys[ttys_count].state;		/* point to fields 	*/
    tbl[1]=ttys[ttys_count].lineno;
    tbl[2]=ttys[ttys_count].dpath;
    tbl[3]=ttys[ttys_count].devnum;
    tbl[4]=ttys[ttys_count].ttyid;
    tbl[5]=ttys[ttys_count].tbaud;
    tbl[6]=ttys[ttys_count].tsetb;
    tbl[7]=ttys[ttys_count].extra;

    for(i=0;i<8;i++) *tbl[i]=0;			/* init fields to null	*/

    i = 0;					/* start at first field	*/
    while (a!=10) {				/* watch for EOL	*/
	ptr=tbl[i];				/* point at field	*/
	while ((a!=10) && ((i==7) || (a!=58))) {
	    *ptr++=a;				/* save chr if valid	*/
	    if (fread(&a,1,1,ttysfile)==0) a=10;/* EOF, terminate	*/
	}
	if (a!=10)
	    if (fread(&a,1,1,ttysfile)==0) a=10;/* is there next field?	*/
	*ptr=0;					/* mark end of string	*/
	if (i<7) i++;				/* next field ptr	*/
    }
    ttys_count++;				/* count line-item	*/
}

at_init()
{
    int awake = 0;
    char junk;

    tty_mode.sg_erase = CERASE;			/* prepare parameters	*/
    tty_mode.sg_kill = CKILL;
    tty_mode.sg_flags = CR1+NL1+CRMOD+RAW;
    tty_mode.sg_ispeed = B1200;
    tty_mode.sg_ospeed = B1200;
    stty(tty_lun,&tty_mode);			/* set tty parameters	*/

    sleep(4);
    fprintf(outdev,"+++");			/* get modems attention	*/
    sleep(4);
    fprintf(outdev,"\r");
    sleep(1);
    fprintf(outdev,"ATZ\r");			/* reset modem		*/
    sleep(1);
    fprintf(outdev,"ATS0=1\r");			/* auto answer		*/
    sleep(1);
    junk=' ';
    while(junk!='1') read(tty_lun,&junk,1);	/* flush input buffer	*/
    while(junk!='\r') read(tty_lun,&junk,1);
}
SHAR_EOF
chmod +x 'prelog.c'
#	End of shell archive
exit 0