[net.sources] 3rd rev. - 4.2 BSD uucp and tip dialin/dialout on same line

wls@astrovax.UUCP (William L. Sebok) (04/23/85)

: Run this shell script with "sh" not "csh"
PATH=:/bin:/usr/bin:/usr/ucb
export PATH
all=FALSE
if [ $1x = -ax ]; then
	all=TRUE
fi
/bin/echo 'Extracting README'
sed 's/^X//' <<'//go.sysin dd *' >README
The following are diffs to the 4.2 distribution of uucp and tip to make them
able to use the same lines for both dialin in and dialing out.  A program to
do the line-turnaround (acucntrl) is included.  This dialin-dialout mechanism
runs under a vanilla 4.2 BSD kernel.  Similar changes to uucp and tip ran here
when we were running 4.1 BSD. The Vax specificity is in the auxiliary program
acucntrl which enables/disables modem control by poking into /dev/kmem to
change flags in the tty drivers.  Similar things could be done for the tty
drivers of other machines (ideally the kernel would provide an ioctl() to
achieve this function).

This is the third revision of this posting. There were problems in the 
interaction between the diffs and patch.  The diffs are "edited" diffs
because there were many other changes made here to both programs.  Making
edited diffs work for patch involves extremely tedious and error-prone editing
of line numbers.  This time the diffs have been verified to work with patch when
applied to source directly off a 4.2 BSD distribution tape (vintage Nov. 1983).
The patched sources have then been verified to compile correctly.

The version of acucntrl included here is also the latest version of that
program.

We started to use uucp after the dialin lines had been in place for a while.
It would have been very unpopular here to remove one of lines from public use
to let uucp dial out.  The first version of these changes ran here early in
1983.

Having this ability is a very useful way to make full use of your modems. For
one thing, I can smile when a neighoring site complains that their one dialer
is tied up from news backed up to one of their neighbors which has been down
for a while and has just come back up. For another thing some of our neighbors
seem to be reachable better by some modems than by others.  For example, I can
only reach rocky2 with a Racal Vadic.  I have been able to only reach akgua,
burl, and sjuvax with a Hayes.  With our 2400 baud modem I don't have to buy
two 2400 baud modems to have two-way 2400 baud capability.

The key to this is a program is provided in the file acucntrl.c .  This should
be installed suid to root in the file /usr/local/lib/acucntrl . A set of diffs
for tip and uucp are also provided.

uucp notes:
The 3rd field of the L-devices file should contain "inout"  for all devices
intended for dialin/out use.  Devices without the "inout" specification will
be used like before: for dialout only. Changes are included to only disable
dialins on the line once per dialing session (rather than enabling it and
disabling it whenever another site is called).  Also included is the fix to
the nasty TIOCSPGP bug which caused all dialing attempts after the first
unsuccessful one to fail.

tip notes:
tip runs here setgid to uucp.  It assumes that /usr/local/lib/acucntrl is
executable by group uucp (in case you want to restrict general execute
permission on this program).  A change has been included to allow comma
separated entries in the "va" field of the remote file.  This is the field
that specifies the dialer type.  With more dialers available it is more likely
that they will be of different types.  If the number of "va" subfields is less
than the number of "dv" (i.e. device name) fields the device type that of
the last previously specified device.

Example from a past version of our own /etc/remote:
	:dv=/dev/ttyd2,/dev/ttyd1,/dev/ttyd0:at=hayes,vadic:

The first modem /dev/ttyd2 is a hayes.  The second two modems /dev/ttyd1 and
X/dev/ttyd0 are vadics.

It is assumed in tip that the dialin/dialout devices have names /dev/ttyd?.
Other names will require modifications in acucntrl and in uucplock.c.

Hopefully, I or someone else will be able to do the equivalent for 4.3 BSD.
I will do it if I can get my hands on a 4.3 BSD system.  Hopefully 4.3 BSD
will provide better hooks to provide these functions than the hooks that
the version of acucntrl used here had to use.

Good luck.  I want to never go back to reserving modems for dialout.

Bill Sebok			Princeton University, Astrophysics
{allegra,akgua,burl,cbosgd,decvax,ihnp4,noao,princeton,vax135}!astrovax!wls
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
	/bin/chmod 644 README
	/bin/echo -n '	'; /bin/ls -ld README
fi
/bin/echo 'Extracting acucntrl.8l'
sed 's/^X//' <<'//go.sysin dd *' >acucntrl.8l
X.TH acucntrl 8 local
X.SH NAME
X.B acucntrl \- turn around tty line between dialin and dialout
X.SH SYNOPSIS
X.B /usr/lib/local/acucntrl
keyword ttyline
X.SH DESCRIPTION
X.PP
X.I Acucntrl
turns around terminal line, enabling it to be used for both dialin and dialout.
On dialin a terminal line is assumed to have  modem control enabled and a getty
process in existence waiting for logins.  On dialout modem control is disabled
and there is no getty process.
X.PP
This program must be run setuid to root.
X.PP
X.I keyword
is chosen from the list:
X.I disable
or
X.IR dialout ,
to condition a line for dialout;
and
X.I enable
or
X.IR dialin ,
to condition a line for dialin.
X.PP
When the line is conditioned for dialing out, the login name of the real uid
of the process is placed in /etc/utmp in capitals.
This declares that the line is in use and acts as an additional locking
mechanism.
X.I Acucntrl
will refuse to act if the /etc/utmp entry for the line is not null,
is not the the user's login name (capitalized or not),
and if the process is not running as the superuser.
The last condition is to allow the superuser to clear the state of the line.
X.PP
Turning modem control on or off is handled by poking into /dev/kmem.
It is currently implemented for dz, dh, and dmf lines.
X.PP
Under 4.2 BSD the program will also refuse to disable a line if carrier is
sensed on it.  This is to avoid the dead period where someone has just dialed
in and made the connection but has not yet logged in.
X.PP
X.I Ttyline
can be either of the form tty* or /dev/tty*.
Enabling/disabling a line whose name does not begin with ttyd? is prohibited
unless the real uid of the process is 0 or if the login name corresponding to
the real uid is uucp.  This is a security precaution.
X.PP 
Steps taken when disabling
X.RI ( i . e .
setup for dialing out)
X.IP 1)
check input arguments
X.IP 2)
look in /etc/utmp to check that the line is not in use by another user
X.IP 3)
disable modem control on line
X.IP 4)
check for carrier on device
X.IP 5)
change owner of device to real uid
X.IP 6)
edit /etc/ttys,  changing the first character of the appropriate line to 0
X.IP 7)
send a hangup to process 1 to poke init to disable getty
X.IP 8)
post uid name in capitals in /etc/utmp to let world know device has been grabbed
X.IP 9)
make sure that DTR is on
X.PP
Steps taken when enabling
X.RI ( i . e .
setup for dialin)
X.IP 1)
check input arguments
X.IP 2)
look in /etc/utmp to check that the line is not in use by another user
X.IP 3)
make sure modem control on line is disabled
X.IP 4)
turn off DTR to make sure line is hung up
X.IP 5)
condition line: clear exclusive use and set hangup on close modes
X.IP 6)
turn on modem control
X.IP 7)
edit /etc/ttys,  changing the first character of the appropriate line to 1
X.IP 8)
send a hangup to process 1 to poke init to enable getty
X.IP 9)
clear uid name for /etc/utmp
X.SH HISTORY
X.PP
First written by Allan Wilkes (fisher!allan)
X.PP
Modified June 8,1983 by W.Sebok (astrovax!wls) to poke the kernel rather
than use a kernel hack to turn on/off modem control, using a subroutine
stolen from a program written by Tsutomu Shimomura {astrovax,escher}!tsutomu
X.PP
Worked over many times by W.Sebok
X.RI ( i . e .
hacked to death)
X.SH FILES
X/dev/kmem, /vmunix, /etc/ttys, /etc/utmp, /dev/tty*
X.SH BUGS
X.PP
Sensing carrier requires the 4.2 BSD TIOCMGET ioctl call.  Unfortunately this
ioctl is not implemented in the vanilla 4.2 BSD dh driver even though the
dz and dmf drivers use an emulation of the DH11's modem control bits. This
has been fixed here.
X.PP
Some time (currently 2 seconds) is required between disabling modem control
and opening the device.  This is probably because of a race with getty whose
open is finally being allowed to complete.  This time interval may not be
enough on a loaded system.  Because of this problem and the above problem with
the dh driver there is deliberately no error message given when the TIOCMGET
ioctl fails.
X.PP
Previously there was similar synchronization problem with the init process.
When dialins are disabled the capitalized name of the process cannot be posted
into /etc/utmp until init has finished clearing /etc/utmp.  However one does
not know how long that will take, and, on a loaded system,  it can take quite
a while.  This was solved by the strategy of 1) posting the name, 2) poking
init, 3) going into a loop where the process repeatedly waits a second and
checks whether the entry has been cleared from /etc/utmp, and 4) posting the
name again.
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
	/bin/chmod 644 acucntrl.8l
	/bin/echo -n '	'; /bin/ls -ld acucntrl.8l
fi
/bin/echo 'Extracting acucntrl.c'
sed 's/^X//' <<'//go.sysin dd *' >acucntrl.c
X/*  acucntrl - turn around tty line between dialin and dialout
 * 
 * $Header: acucntrl.c,v 1.4 85/04/23 11:33:09 root Exp $
 *
 * Usage:	acucntrl {enable,disable} /dev/ttydX
 *
 * History:
 *
 * First written by Allan Wilkes (fisher!allan)
 *
 * Modified June 8,1983 by W.Sebok (astrovax!wls) to poke kernel rather
 * than use kernel hack to turn on/off modem control, using a subroutine
 * stolen from program written by Tsutomu Shimomura {astrovax,escher}!tsutomu
 *
 * Worked over many times by W.Sebok (i.e. hacked to death)
 *
 * $Log:	acucntrl.c,v $
 * Revision 1.4  85/04/23  11:33:09  root
 * moved BSD4_2 definition to makefile and took out include of signal.h
 * 
 * Revision 1.3  85/03/29  13:21:59  root
 * added parentheses to test for /dev/ttydX.  The operator prececence was
 * not what I thought it was
 * 
 * Revision 1.2  85/03/17  13:49:44  root
 * 1) fixed infinite loop when a line already disabled was disabled again.
 * 2) fixed data types of modem control flags.  In particular the in the
 * dz driver it was writing out a short when it should have been writing out
 * an int.  Also, it was addressing dmfsoftCAR as a short array when it
 * should have been addressing it as a char array.
 * 3) did various cleanups to enable it to pass lint.
 * 
 * Revision 1.1  85/02/18  13:50:03  root
 * Initial revision
 * 
 * Operation:
 *   disable (i.e. setup for dialing out)
 *	(1) check input arguments
 *	(2) look in /etc/utmp to check that the line is not in use by another
 *	(3) disable modem control on terminal
 *	(4) check for carrier on device
 *	(5) change owner of device to real id
 *	(6) edit /etc/ttys,  changing the first character of the appropriate
 *	    line to 0
 *	(7) send a hangup to process 1 to poke init to disable getty
 *	(8) post uid name in capitals in /etc/utmp to let world know device has
 *	    been grabbed
 *	(9) make sure that DTR is on
 *
 *   enable (i.e.) restore for dialin
 *	(1) check input arguments
 *	(2) look in /etc/utmp to check that the line is not in use by another
 *	(3) make sure modem control on terminal is disabled
 *	(4) turn off DTR to make sure line is hung up
 *	(5) condition line: clear exclusive use and set hangup on close modes
 *	(6) turn on modem control
 *	(7) edit /etc/ttys,  changing the first character of the appropriate
 *	    line to 1
 *	(8) send a hangup to process 1 to poke init to enable getty
 *	(9) clear uid name for /etc/utmp
 */

X/* #define SENSECARRIER */

#include <sys/param.h>
#include <sys/buf.h>
#include <sys/conf.h>
#ifdef BSD4_2
#include "/sys/vaxuba/ubavar.h"
#else
#include <sys/ubavar.h>
#endif
#include <sys/stat.h>
#include <nlist.h>
#include <sgtty.h>
#include <utmp.h>
#include <pwd.h>
#include <stdio.h>

#define NDZLINE	8	/* lines/dz */
#define NDHLINE	16	/* lines/dh */
#define NDMFLINE 8	/* lines/dmf */

#define DZ11	1
#define DH11	2
#define DMF	3

#define NLVALUE(val)	(nl[val].n_value)

struct nlist nl[] = {
#define CDEVSW	0
	{ "_cdevsw" },

#define DZOPEN	1
	{ "_dzopen" },
#define DZINFO	2
	{ "_dzinfo" },
#define NDZ11	3
	{ "_dz_cnt" },
#define DZSCAR	4
	{ "_dzsoftCAR" },

#define DHOPEN	5
	{ "_dhopen" },
#define DHINFO	6
	{ "_dhinfo" },
#define NDH11	7
	{ "_ndh11" },
#define DHSCAR	8
	{ "_dhsoftCAR" },

#define DMFOPEN	9
	{ "_dmfopen" },
#define DMFINFO	10
	{ "_dmfinfo" },
#define NDMF	11
	{ "_ndmf" },
#define DMFSCAR	12
	{ "_dmfsoftCAR" },

	{ "\0" }
};

#define ENABLE	1
#define DISABLE	0

char Etcutmp[] = "/etc/utmp";
char Etcttys[] = "/etc/ttys";
char Devhome[] = "/dev";

char usage[] = "Usage: acucntrl {dis|en}able ttydX\n";

struct utmp utmp;
char resettty, resetmodem;
int etcutmp;
off_t utmploc;
off_t ttyslnbeg;

#define NAMSIZ	sizeof(utmp.ut_name)
#define	LINSIZ	sizeof(utmp.ut_line)

main(argc, argv)
int argc; char *argv[];
{
	register char *p;
	register int i;
	char uname[NAMSIZ], Uname[NAMSIZ];
	int enable ;
	char *device;
	int devfile;
	int uid, gid;
	off_t lseek();
	struct passwd *getpwuid();
	char *rindex();
	extern int errno;
	extern char *sys_errlist[];

	/* check input arguments */
	if (argc!=3) {
		fprintf(stderr, usage);
		exit(1);
	}

	/* interpret command type */
	if (prefix(argv[1], "disable")  || strcmp(argv[1],"dialout")==0)
		enable = 0;
	else if (prefix(argv[1], "enable")  || strcmp(argv[1],"dialin")==0)
		enable = 1;
	else {
		fprintf(stderr, usage);
		exit(1);
	}

	device = rindex(argv[2],'/');
	device = (device == NULL) ? argv[2]: device+1;

	/* only recognize devices of the form ttydX */
	if (strncmp(device,"ttyd",4)!=0) {
		fprintf(stderr,"Bad Device Name %s",device);
		exit(1);
	}

	opnttys(device);

	/* Get nlist info */
	nlist("/vmunix",nl);

	/* Chdir to /dev */
	if(chdir(Devhome) < 0) {
		fprintf(stderr, "Cannot chdir to %s: %s\r\n",
			Devhome, sys_errlist[errno]);
		exit(1);
	}

	/* Get uid information */
	uid = getuid();
	gid = getgid();

	p = getpwuid(uid)->pw_name;
	if (p==NULL) {
		fprintf(stderr,"cannot get uid name\n");
		exit(1);
	}

	/*  to upper case */
	i = 0;
	do {
		uname[i] = *p;
		Uname[i] = (*p>='a' && *p<='z') ? (*p - ('a'-'A')) : *p;
		i++; p++;
	} while (*p && i<NAMSIZ);


	/* check to see if line is being used */
	if( (etcutmp = open(Etcutmp, 2)) < 0) {
		fprintf(stderr,"On open %s open: %s\n",
			Etcutmp,sys_errlist[errno]);
		exit(1);
	}

	(void)lseek(etcutmp,utmploc, 0);

	i = read(etcutmp,(char *)&utmp,sizeof(struct utmp));

	if(
		i == sizeof(struct utmp) &&
		utmp.ut_line[0] != '\0'  &&
		utmp.ut_name[0] != '\0'  &&
		(
			!upcase(utmp.ut_name,NAMSIZ) ||
			(
				uid != 0 &&
				strncmp(utmp.ut_name,Uname,NAMSIZ) != 0
			)
		)
	) {
		fprintf(stderr, "%s in use by %s\n", device, utmp.ut_name);
		exit(2);
	}

	/* Disable modem control */
	if (setmodem(device,DISABLE)<0) {
		fprintf(stderr,"Unable to disable modem control\n");
		exit(1);
	}

	if (enable) {
		if((devfile = open(device, 1)) < 0) {
			fprintf(stderr,"On open of %s: %s\n",
				device, sys_errlist[errno]);
			(void)setmodem(device,resetmodem);
			exit(1);
		}
		/* Try one last time to hang up */
		if (ioctl(devfile,(int)TIOCCDTR,(char *)0) < 0)
			fprintf(stderr,"On TIOCCDTR ioctl: %s\n",
				sys_errlist[errno]);

		if (ioctl(devfile, (int)TIOCNXCL,(char *)0) < 0)
			fprintf(stderr,
			    "Cannot clear Exclusive Use on %s: %s\n",
				device, sys_errlist[errno]);

		if (ioctl(devfile, (int)TIOCHPCL,(char *)0) < 0)
			fprintf(stderr,
			    "Cannot set hangup on close on %s: %s\n",
				device, sys_errlist[errno]);

		i = resetmodem;

		if (setmodem(device,ENABLE) < 0) {
			fprintf(stderr,"Cannot Enable modem control\n");
			(void)setmodem(device,i);
			exit(1);
		}
		resetmodem=i;

		if (settys(ENABLE)) {
			fprintf(stderr,"%s already enabled\n",device);
		} else {
			pokeinit(device,Uname,enable);
		}
		post(device,"");

	} else {
#if defined(TIOCMGET) && defined(SENSECARRIER)
		if (uid!=0) {
			int linestat = 0;

			/* check for presence of carrier */
			sleep(2); /* need time after modem control turnoff */

			if((devfile = open(device, 1)) < 0) {
				fprintf(stderr,"On open of %s: %s\n",
					device, sys_errlist[errno]);
				(void)setmodem(device,resetmodem);
				exit(1);
			}

			(void)ioctl(devfile,TIOCMGET,&linestat);

			if (linestat&TIOCM_CAR) {
				fprintf(stderr,"%s is in use (Carrier On)\n",
					device);
				(void)setmodem(device,resetmodem);
				exit(2);
			}
			(void)close(devfile);
		}
#endif TIOCMGET
		/* chown device */
		if(chown(device, uid, gid) < 0)
			fprintf(stderr, "Cannot chown %s: %s\n",
				device, sys_errlist[errno]);


		/* poke init */
		if(settys(DISABLE)) {
			fprintf(stderr,"%s already disabled\n",device);
		} else {
			pokeinit(device,Uname,enable);
		}
		post(device,Uname);
		if((devfile = open(device, 1)) < 0) {
			fprintf(stderr, "On %s open: %s\n",
				device, sys_errlist[errno]);
		} else {
			if(ioctl(devfile, (int)TIOCSDTR, (char *)0) < 0)
				fprintf(stderr,
				    "Cannot set DTR on %s: %s\n",
					device, sys_errlist[errno]);
		}
	}

	exit(0);
}

X/* return true if no lower case */
upcase(str,len)
register char *str;
register int len;
{
	for (; *str, --len >= 0 ; str++)
		if (*str>='a' && *str<='z')
			return(0);
	return(1);
}

X/* Post name to public */
post(device,name)
char *device, *name;
{
	(void)time((time_t *)&utmp.ut_time);
	strcpyn(utmp.ut_line, device, LINSIZ);
	strcpyn(utmp.ut_name, name,  NAMSIZ);
	if (lseek(etcutmp, utmploc, 0)<0)
		fprintf(stderr,"on lseek in /etc/utmp: %s",
			sys_errlist[errno]);
	if (write(etcutmp, (char *)&utmp, sizeof(utmp))<0)
		fprintf(stderr,"on write in /etc/utmp: %s",
			sys_errlist[errno]);
}
	
X/* poke process 1 and wait for it to do its thing */
pokeinit(device,uname,enable)
char *uname, *device; int enable;
{
	struct utmp utmp;
	register int i;

	post(device, uname);

	/* poke init */
	if (kill(1, SIGHUP)) {
		fprintf(stderr,
		    "Cannot send hangup to init process: %s\n",
			sys_errlist[errno]);
		(void)settys(resettty);
		(void)setmodem(device,resetmodem);
		exit(1);
	}

	if (enable)
		return;

	/* wait till init has responded, clearing the utmp entry */
	i=100;
	do {
		sleep(1);
		if (lseek(etcutmp,utmploc,0)<0)
			fprintf(stderr,"On lseek in /etc/utmp: %s",
				sys_errlist[errno]);
		if (read(etcutmp,(char *)&utmp,sizeof utmp)<0)
			fprintf(stderr,"On read from /etc/utmp: %s",
				sys_errlist[errno]);
	} while (utmp.ut_name[0] != '\0' && --i > 0);
}

X/* identify terminal line in ttys */
opnttys(device)
char *device;
{
	register FILE *ttysfile;
	register int  ndevice, lnsiz; 
	register char *p;
	char *index();
	char linebuf[100];

	ttysfile = fopen(Etcttys, "r");
	if(ttysfile == NULL) {
		fprintf(stderr, "Cannot open %s: %s\n", Etcttys,
			sys_errlist[errno]);
		exit(1);
	}

	ndevice = strlen(device);
	ttyslnbeg = 0;
	utmploc = 0;

	while(fgets(linebuf, sizeof(linebuf) - 1, ttysfile) != NULL) {
		utmploc += sizeof(utmp);
		lnsiz = strlen(linebuf);
		if ((p = index(linebuf,'\n')) != NULL)
			*p = '\0';
		if(strncmp(device, &linebuf[2], ndevice) == 0) {
			(void)fclose(ttysfile);
			return;
		}
		ttyslnbeg += lnsiz;
	}
	fprintf(stderr, "%s not found in %s\n", device, Etcttys);
	exit(1);
}

X/* modify appropriate line in /etc/ttys to turn on/off the device */
settys(enable)
int enable;
{
	int ittysfil;
	char out,in;

	ittysfil = open(Etcttys, 2);
	if(ittysfil == NULL) {
		fprintf(stderr, "Cannot open %s for output: %s\n",
			Etcttys, sys_errlist[errno]);
		exit(1);
	}
	(void)lseek(ittysfil,ttyslnbeg,0);
	if(read(ittysfil,&in,1)<0) {
		fprintf(stderr,"On %s write: %s\n",
			Etcttys, sys_errlist[errno]);
		exit(1);
	}
	resettty = (in == '1');
	out = enable ? '1' : '0';
	(void)lseek(ittysfil,ttyslnbeg,0);
	if(write(ittysfil,&out,1)<0) {
		fprintf(stderr,"On %s write: %s\n",
			Etcttys, sys_errlist[errno]);
		exit(1);
	}
	(void)close(ittysfil);
	return(in==out);
}

X/*
 * Excerpted from (June 8,1983 W.Sebok)
 * > ttymodem.c - enable/disable modem control for tty lines.
 * >
 * > Knows about DZ11s and DH11/DM11s.
 * > 23.3.83 - TS
 * > modified to know about DMF's  (hasn't been tested) Nov 8,1984 - WLS
 */


setmodem(ttyline,enable)
char *ttyline; int enable;
{
	dev_t dev;
	int kmem;
	int unit,line,nlines,addr,tflags;
	int devtype=0;
	char cflags; short sflags;
#ifdef BSD4_2
	int flags;
#else
	short flags;
#endif
	struct uba_device *ubinfo;
	struct stat statb;
	struct cdevsw cdevsw;

	if(nl[CDEVSW].n_type == 0) {
		fprintf(stderr,"No namelist.\n");
		return(-1);
	}

	if((kmem = open("/dev/kmem", 2)) < 0) {
		fprintf(stderr,"/dev/kmem open: %s\n", sys_errlist[errno]);
		return(-1);
	}

	if(stat(ttyline,&statb) < 0) {
		fprintf(stderr,"%s stat: %s\n", ttyline, sys_errlist[errno]);
		return(-1);
	}

	if((statb.st_mode&S_IFMT) != S_IFCHR) {
		fprintf(stderr,"%s is not a character device.\n",ttyline);
		return(-1);
	}

	dev = statb.st_rdev;
	(void)lseek(kmem,
		(off_t) &(((struct cdevsw *)NLVALUE(CDEVSW))[major(dev)]),0);
	(void)read(kmem,(char *) &cdevsw,sizeof cdevsw);

	if((int)(cdevsw.d_open) == NLVALUE(DZOPEN)) {
		devtype = DZ11;
		unit = minor(dev) / NDZLINE;
		line = minor(dev) % NDZLINE;
		addr = (int) &(((int *)NLVALUE(DZINFO))[unit]);
		(void)lseek(kmem,(off_t) NLVALUE(NDZ11),0);
	} else if((int)(cdevsw.d_open) == NLVALUE(DHOPEN)) {
		devtype = DH11;
		unit = minor(dev) / NDHLINE;
		line = minor(dev) % NDHLINE;
		addr = (int) &(((int *)NLVALUE(DHINFO))[unit]);
		(void)lseek(kmem,(off_t) NLVALUE(NDH11),0);
	} else if((int)(cdevsw.d_open) == NLVALUE(DMFOPEN)) {
		devtype = DMF;
		unit = minor(dev) / NDMFLINE;
		line = minor(dev) % NDMFLINE;
		addr = (int) &(((int *)NLVALUE(DMFINFO))[unit]);
		(void)lseek(kmem,(off_t) NLVALUE(NDMF),0);
	} else {
		fprintf(stderr,"Device %s (%d/%d) unknown.\n",ttyline,
		    major(dev),minor(dev));
		return(-1);
	}

	(void)read(kmem,(char *) &nlines,sizeof nlines);
	if(minor(dev) >= nlines) {
		fprintf(stderr,"Sub-device %d does not exist (only %d).\n",
		    minor(dev),nlines);
		return(-1);
	}

	(void)lseek(kmem,(off_t)addr,0);
	(void)read(kmem,(char *) &ubinfo,sizeof ubinfo);
	(void)lseek(kmem,(off_t) &(ubinfo->ui_flags),0);
	(void)read(kmem,(char *) &flags,sizeof flags);

	tflags = 1<<line;
	resetmodem = ((flags&tflags) == 0);
	flags = enable ? (flags & ~tflags) : (flags | tflags);
	(void)lseek(kmem,(off_t) &(ubinfo->ui_flags),0);
	(void)write(kmem,(char *) &flags, sizeof flags);
	switch(devtype) {
		case DZ11:
			if((addr = NLVALUE(DZSCAR)) == 0) {
				fprintf(stderr,"No dzsoftCAR.\n");
				return(-1);
			}
			cflags = flags;
			(void)lseek(kmem,(off_t) &(((char *)addr)[unit]),0);
			(void)write(kmem,(char *) &cflags, sizeof cflags);
			break;
		case DH11:
			if((addr = NLVALUE(DHSCAR)) == 0) {
				fprintf(stderr,"No dhsoftCAR.\n");
				return(-1);
			}
			sflags = flags;
			(void)lseek(kmem,(off_t) &(((short *)addr)[unit]),0);
			(void)write(kmem,(char *) &sflags, sizeof sflags);
			break;
		case DMF:
			if((addr = NLVALUE(DMFSCAR)) == 0) {
				fprintf(stderr,"No dmfsoftCAR.\n");
				return(-1);
			}
			cflags = flags;
			(void)lseek(kmem,(off_t) &(((char *)addr)[unit]),0);
			(void)write(kmem,(char *) &flags, sizeof cflags);
			break;
		default:
			fprintf(stderr,"Unknown device type\n");
			return(-1);
	}
	return(0);
}

prefix(s1, s2)
	register char *s1, *s2;
{
	register char c;

	while ((c = *s1++) == *s2++)
		if (c == '\0')
			return (1);
	return (c == '\0');
}
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
	/bin/chmod 644 acucntrl.c
	/bin/echo -n '	'; /bin/ls -ld acucntrl.c
fi
/bin/echo 'Extracting makefile'
sed 's/^X//' <<'//go.sysin dd *' >makefile
CFLAGS= -DBSD4_2 -O
LFLAGS= -s

acucntrl:	acucntrl.c
	${CC} ${CFLAGS} ${OFLAGS} -o acucntrl acucntrl.c
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
	/bin/chmod 644 makefile
	/bin/echo -n '	'; /bin/ls -ld makefile
fi
/bin/echo 'Extracting tip.cu.DIFF'
sed 's/^X//' <<'//go.sysin dd *' >tip.cu.DIFF
diff -c -r tip.OLD/cu.c /usr/src/usr.bin/tip/cu.c
*** tip.OLD/cu.c	Tue Jun 28 03:33:09 1983
--- /usr/src/usr.bin/tip/cu.c	Mon May 28 20:23:25 1984
***************
*** 82,88
  	setbuf(stdout, NULL);
  	loginit();
  	setuid(getuid());
! 	setgid(getgid());
  	vinit();
  	setparity("none");
  	boolean(value(VERBOSE)) = 0;

--- 82,88 -----
  	setbuf(stdout, NULL);
  	loginit();
  	setuid(getuid());
! /*	setgid(getgid());	*/
  	vinit();
  	setparity("none");
  	boolean(value(VERBOSE)) = 0;
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
	/bin/chmod 644 tip.cu.DIFF
	/bin/echo -n '	'; /bin/ls -ld tip.cu.DIFF
fi
/bin/echo 'Extracting tip.remote.DIFF'
sed 's/^X//' <<'//go.sysin dd *' >tip.remote.DIFF
diff -c -r tip.OLD/remote.c /usr/src/usr.bin/tip/remote.c
*** tip.OLD/remote.c	Sat Jun 25 04:19:16 1983
--- /usr/src/usr.bin/tip/remote.c	Sat Jun  2 00:40:49 1984
***************
*** 121,126
  {
  	register char *cp;
  	static char *next;
  	static int lookedup = 0;
  
  	if (!lookedup) {

--- 121,127 -----
  {
  	register char *cp;
  	static char *next;
+ 	static char *nextat;	/* next AT */
  	static int lookedup = 0;
  
  	if (!lookedup) {
***************
*** 130,135
  		}
  		getremcap(host);
  		next = DV;
  		lookedup++;
  	}
  	/*

--- 131,137 -----
  		}
  		getremcap(host);
  		next = DV;
+ 		nextat = AT;
  		lookedup++;
  	}
  	/*
***************
*** 146,150
  		DV = next;
  		next = cp;
  	}
  	return (DV);
  }

--- 148,157 -----
  		DV = next;
  		next = cp;
  	}
+ 	if (nextat != NOSTR) {
+ 		AT = nextat;
+ 		if ((nextat = index(nextat,',')) != NOSTR)
+ 			*nextat++ = '\0';
+ 	}
  	return (DV);
  }
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
	/bin/chmod 644 tip.remote.DIFF
	/bin/echo -n '	'; /bin/ls -ld tip.remote.DIFF
fi
/bin/echo 'Extracting tip.tip.DIFF'
sed 's/^X//' <<'//go.sysin dd *' >tip.tip.DIFF
diff -c -r tip.OLD/tip.c /usr/src/usr.bin/tip/tip.c
*** tip.OLD/tip.c	Tue Jun 28 03:33:11 1983
--- /usr/src/usr.bin/tip/tip.c	Mon May 28 21:14:01 1984
***************
*** 82,87
  	signal(SIGHUP, cleanup);
  	signal(SIGTERM, cleanup);
  
  	if ((i = hunt(system)) == 0) {
  		printf("all ports busy\n");
  		exit(3);

--- 82,90 -----
  	signal(SIGHUP, cleanup);
  	signal(SIGTERM, cleanup);
  
+ 	setbuf(stdout, NULL);
+ 	loginit();
+ 
  	if ((i = hunt(system)) == 0) {
  		printf("all ports busy\n");
  		exit(3);
***************
*** 91,98
  		delock(uucplock);
  		exit(3);
  	}
- 	setbuf(stdout, NULL);
- 	loginit();
  	/*
  	 * Now that we have the logfile and the ACU open
  	 *  return to the real uid and gid.  These things will

--- 94,99 -----
  		delock(uucplock);
  		exit(3);
  	}
  	/*
  	 * Now that we have the logfile and the ACU open
  	 *  return to the real uid and gid.  These things will
***************
*** 100,106
  	 *  because locking mechanism on the tty and the accounting
  	 *  will be bypassed.
  	 */
! 	setgid(getgid());
  	setuid(getuid());
  
  	/*

--- 101,107 -----
  	 *  because locking mechanism on the tty and the accounting
  	 *  will be bypassed.
  	 */
! /*	setgid(getgid()); */
  	setuid(getuid());
  
  	/*
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
	/bin/chmod 644 tip.tip.DIFF
	/bin/echo -n '	'; /bin/ls -ld tip.tip.DIFF
fi
/bin/echo 'Extracting tip.uucplock.DIFF'
sed 's/^X//' <<'//go.sysin dd *' >tip.uucplock.DIFF
diff -c -r tip.OLD/uucplock.c /usr/src/usr.bin/tip/uucplock.c
*** tip.OLD/uucplock.c	Sat Jun 25 04:19:18 1983
--- /usr/src/usr.bin/tip/uucplock.c	Sun Dec  2 23:37:34 1984
***************
*** 4,10
  /*
   * defs that come from uucp.h
   */
! #define NAMESIZE 15
  #define FAIL -1
  #define SAME 0
  #define SLCKTIME 28800	/* system/device timeout (LCK.. files) in seconds (8 hours) */

--- 4,12 -----
  /*
   * defs that come from uucp.h
   */
! /* program to enable/disable devices */
! #define ACUPROG "/usr/local/lib/acucntrl"
! #define NAMESIZE 40
  #define FAIL -1
  #define SAME 0
  #define SLCKTIME 28800	/* system/device timeout (LCK.. files) in seconds (8 hours) */
***************
*** 190,196
  	char *s;
  {
  	char ln[30];
! 
  	sprintf(ln, "%s.%s", LOCKPRE, s);
  	rmlock(ln);
  }

--- 192,199 -----
  	char *s;
  {
  	char ln[30];
! 	if (strncmp(s, "ttyd", 4) == 0)
! 		reenable(s);
  	sprintf(ln, "%s.%s", LOCKPRE, s);
  	rmlock(ln);
  }
***************
*** 207,211
  {
  	char lname[30];
  	sprintf(lname, "%s.%s", LOCKPRE, sys);
! 	return (ulockf(lname, (time_t) SLCKTIME ) < 0 ? FAIL : 0);
  }

--- 210,268 -----
  {
  	char lname[30];
  	sprintf(lname, "%s.%s", LOCKPRE, sys);
! 	if (ulockf(lname, (time_t) SLCKTIME ) < 0)
! 		return(FAIL);
! 	if (strncmp(sys, "ttyd", 4)!=0)
! 		return(0);
! 	if (disable(sys) == 0)
! 		return(0);
! 	return(FAIL);
! }
! 
! /***************************************************************************
!  * disable and reenable:  allow a single line to be use for dialin/dialout *
!  *  routines added by David Sebok 4/15/84 based on those created by        *
!  *  William Sebok							   *
!  ***************************************************************************/
! 
! static int disableflg=0;
! disable(dev)
! register char *dev;
! {
! 	printf("disabling %s...",dev);
! 	fflush(stdout);
! 	if (enbcall("disable", dev) == FAIL) {
! 		printf("could not disable %s\n",dev);
! 		return(FAIL);
! 	}
! 	disableflg=1;
! 	printf(" done\n");
! 	return(0);
! }
! 
! reenable(dev)
! register char *dev;
! {
! 	if (disableflg==0)
! 		return(FAIL);
! 	printf("reenabling %s...",dev);
! 	if (enbcall("enable", dev) == FAIL)
! 		return(FAIL);
! 	printf(" done\n\r");
! 	return(0);
! }
! 
! enbcall(type, dev)
! char *type, *dev;
! {
! 	register int pid;
! 	int status;
! 
! 	if ((pid = fork()) == 0) {
! 		setuid(getuid());	/* for chown(uid()) in acu program */
! 		execl(ACUPROG, "acu", type, dev, 0);
! 		exit(9);
! 	}
! 	while(wait(&status) != pid);
! 	return(status ? FAIL : 0);	/*FAIL if ACU exits other than 0 */
  }
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
	/bin/chmod 644 tip.uucplock.DIFF
	/bin/echo -n '	'; /bin/ls -ld tip.uucplock.DIFF
fi
/bin/echo 'Extracting uucp.cico.DIFF'
sed 's/^X//' <<'//go.sysin dd *' >uucp.cico.DIFF
diff -rc uucp.OLD/cico.c /usr/src/usr.bin/uucp/cico.c
*** uucp.OLD/cico.c	Wed Nov  2 18:51:44 1983
--- /usr/src/usr.bin/uucp/cico.c	Sat Dec  8 14:25:58 1984
***************
*** 444,449
  			ret = ioctl(0, TCSETA, &Savettyb);
  #endif
  #ifndef	SYSIII
  			/* rti!trt:  use more robust hang up sequence */
  			ret = ioctl(0, TIOCHPCL, STBNULL);
  			ret = ioctl(0, TIOCGETP, &Hupvec);

--- 457,468 -----
  			ret = ioctl(0, TCSETA, &Savettyb);
  #endif
  #ifndef	SYSIII
+ #ifdef TIOCSDTR		/* WLS 3/2/84 */
+ 			(void)ioctl(0, TIOCCDTR, STBNULL);
+ 			sleep(2);
+ 			(void)ioctl(0, TIOCSDTR, STBNULL);
+ 			(void)ioctl(0, TIOCHPCL, STBNULL);
+ #else  TIOCSDTR
  			/* rti!trt:  use more robust hang up sequence */
  			ret = ioctl(0, TIOCHPCL, STBNULL);
  			ret = ioctl(0, TIOCGETP, &Hupvec);
***************
*** 452,457
  			ret = ioctl(0, TIOCSETP, &Hupvec);
  			sleep(2);
  			ret = ioctl(0, TIOCSETP, &Savettyb);
  #endif
  			DEBUG(4, "ret ioctl - %d\n", ret);
  		}

--- 471,477 -----
  			ret = ioctl(0, TIOCSETP, &Hupvec);
  			sleep(2);
  			ret = ioctl(0, TIOCSETP, &Savettyb);
+ #endif TIOCSDTR
  #endif
  			DEBUG(4, "ret ioctl - %d\n", ret);
  		}
***************
*** 465,470
  		close(Ifn);
  		close(Ofn);
  	}
  	DEBUG(1, "exit code %d\n", code);
  	if (code == 0)
  		xuuxqt();

--- 485,494 -----
  		close(Ifn);
  		close(Ofn);
  	}
+ #ifdef DIALINOUT
+ 	/* reenable logins on dialout (WLS Mar 3, 1984) */
+ 	reenable();
+ #endif
  	DEBUG(1, "exit code %d\n", code);
  	if (code == 0)
  		xuuxqt();
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
	/bin/chmod 644 uucp.cico.DIFF
	/bin/echo -n '	'; /bin/ls -ld uucp.cico.DIFF
fi
/bin/echo 'Extracting uucp.condevs.DIFF'
sed 's/^X//' <<'//go.sysin dd *' >uucp.condevs.DIFF
*** condevs.c.orig	Fri Apr 19 16:25:08 1985
--- condevs.c	Fri Apr 19 16:31:16 1985
***************
*** 193,198
  		delock(dev.D_line);
  		return(FAIL);
  	}
  	fflush(stdout);
  	fixline(dcr, dev.D_speed);
  	strcpy(devSel, dev.D_line);	/* for latter unlock */

--- 193,204 -----
  		delock(dev.D_line);
  		return(FAIL);
  	}
+ #ifdef TIOCSPGRP
+ 	{	/* fix for mysterious "EIO" on read error */
+ 		int pgrp = getpgrp(0);
+ 		ioctl(dcr, TIOCSPGRP, &pgrp);
+ 	}
+ #endif
  	fflush(stdout);
  	fixline(dcr, dev.D_speed);
  	strcpy(devSel, dev.D_line);	/* for latter unlock */
***************
*** 406,411
  				}
  			}
  		}
  	fclose(dfp);
  	if (dh < 0)
  		return(CF_NODEV);

--- 412,423 -----
  				}
  			}
  		}
+ #ifdef TIOCSPGRP
+ 	{	/* fix for mysterious "EIO" on read error */
+ 		int pgrp = getpgrp(0);
+ 		ioctl(dh, TIOCSPGRP, &pgrp);
+ 	}
+ #endif
  	fclose(dfp);
  	if (dh < 0)
  		return(CF_NODEV);
***************
*** 472,482
  Acuopn(flds)
  register char *flds[];
  {
!     char phone[MAXPH+1];
!     register struct condev *cd;
!     register int fd;
!     register FILE *dfp;
!     struct Devices dev;
  
      exphone(flds[F_PHONE], phone);
      devSel[0] = '\0';

--- 484,495 -----
  Acuopn(flds)
  register char *flds[];
  {
! 	char phone[MAXPH+1];
! 	register struct condev *cd;
! 	register int fd;
! 	register FILE *dfp;
! 	struct Devices dev;
! 	int success = 0;
  
      exphone(flds[F_PHONE], phone);
      devSel[0] = '\0';
***************
*** 484,493
      dfp = fopen(DEVFILE, "r");
      ASSERT(dfp != NULL, "Can't open", DEVFILE, 0);
  
!     for(cd = condevs; cd->CU_meth != NULL; cd++) {
! 	if (snccmp(flds[F_LINE], cd->CU_meth) == SAME) {
! 	    fseek(dfp, (off_t)0, 0);
! 	    while(rddev(dfp, &dev) != FAIL) {
  		if (strcmp(flds[F_CLASS], dev.D_class) != SAME)
  		    continue;
  		if (snccmp(flds[F_LINE], dev.D_type) != SAME)

--- 497,504 -----
      dfp = fopen(DEVFILE, "r");
      ASSERT(dfp != NULL, "Can't open", DEVFILE, 0);
  
! 	fseek(dfp, (off_t)0, 0);
! 	while(rddev(dfp, &dev) != FAIL) {
  		if (strcmp(flds[F_CLASS], dev.D_class) != SAME)
  			continue;
  		if (snccmp(flds[F_LINE], dev.D_type) != SAME)
***************
*** 489,495
  	    fseek(dfp, (off_t)0, 0);
  	    while(rddev(dfp, &dev) != FAIL) {
  		if (strcmp(flds[F_CLASS], dev.D_class) != SAME)
! 		    continue;
  		if (snccmp(flds[F_LINE], dev.D_type) != SAME)
  		    continue;
  		if (dev.D_brand[0] == '\0')

--- 500,506 -----
  	fseek(dfp, (off_t)0, 0);
  	while(rddev(dfp, &dev) != FAIL) {
  		if (strcmp(flds[F_CLASS], dev.D_class) != SAME)
! 			continue;
  		if (snccmp(flds[F_LINE], dev.D_type) != SAME)
  			continue;
  		if (dev.D_brand[0] == '\0') {
***************
*** 491,501
  		if (strcmp(flds[F_CLASS], dev.D_class) != SAME)
  		    continue;
  		if (snccmp(flds[F_LINE], dev.D_type) != SAME)
! 		    continue;
! 		if (dev.D_brand[0] == '\0')
! 		    logent("Acuopn","No 'brand' name on ACU");
! 		else if (snccmp(dev.D_brand, cd->CU_brand) != SAME)
! 		    continue;
  		if (mlock(dev.D_line) == FAIL)
  		    continue;
  

--- 502,522 -----
  		if (strcmp(flds[F_CLASS], dev.D_class) != SAME)
  			continue;
  		if (snccmp(flds[F_LINE], dev.D_type) != SAME)
! 			continue;
! 		if (dev.D_brand[0] == '\0') {
! 			logent("Acuopn","No 'brand' name on ACU");
! 			continue;
! 		}
! 		for(cd = condevs; cd->CU_meth != NULL; cd++) {
! 			if (snccmp(flds[F_LINE], cd->CU_meth) == SAME
! 			    && snccmp(dev.D_brand, cd->CU_brand) == SAME)
! 				break;
! 		}
! 		if (cd->CU_meth == NULL) {
! 			logent(dev.D_brand,"unsupported ACU type");
! 			continue;
! 		}
! 
  		if (mlock(dev.D_line) == FAIL)
  			continue;
  
***************
*** 497,503
  		else if (snccmp(dev.D_brand, cd->CU_brand) != SAME)
  		    continue;
  		if (mlock(dev.D_line) == FAIL)
! 		    continue;
  
  		DEBUG(4, "Using %s\n", cd->CU_brand);
  		fd = (*(cd->CU_open))(phone, flds, &dev);

--- 518,524 -----
  		}
  
  		if (mlock(dev.D_line) == FAIL)
! 			continue;
  
  #ifdef DIALINOUT
  		if (snccmp("inout",dev.D_calldev) == 0
***************
*** 499,504
  		if (mlock(dev.D_line) == FAIL)
  		    continue;
  
  		DEBUG(4, "Using %s\n", cd->CU_brand);
  		fd = (*(cd->CU_open))(phone, flds, &dev);
  		if (fd > 0) {

--- 520,539 -----
  		if (mlock(dev.D_line) == FAIL)
  			continue;
  
+ #ifdef DIALINOUT
+ 		if (snccmp("inout",dev.D_calldev) == 0
+ 		    && disable(dev.D_line) == FAIL) {
+ 			delock(dev.D_line);
+ 			continue;
+ 		}
+ #endif
+ 		success++;
+ 		break;
+ 	}
+ 
+ 	fclose(dfp);
+ 
+ 	if (success) {
  		DEBUG(4, "Using %s\n", cd->CU_brand);
  		fd = (*(cd->CU_open))(phone, flds, &dev);
  		if (fd > 0) {
***************
*** 502,513
  		DEBUG(4, "Using %s\n", cd->CU_brand);
  		fd = (*(cd->CU_open))(phone, flds, &dev);
  		if (fd > 0) {
! 		    CU_end = cd->CU_clos;   /* point CU_end at close func */
! 		    fclose(dfp);
! 		    strcpy(devSel, dev.D_line);   /* save for later unlock() */
! 		    return(fd);
! 		    }
! 		delock(dev.D_line);
  		}
  	    }
  	}

--- 537,547 -----
  		DEBUG(4, "Using %s\n", cd->CU_brand);
  		fd = (*(cd->CU_open))(phone, flds, &dev);
  		if (fd > 0) {
! 			CU_end = cd->CU_clos;   /* point CU_end at close func */
! 			strcpy(devSel, dev.D_line); /* save for later unlock()*/
! 			return(fd);
! 		} else {
! 			delock(dev.D_line);
  		}
  	}
  	return(FAIL);
***************
*** 509,515
  		    }
  		delock(dev.D_line);
  		}
- 	    }
  	}
      fclose(dfp);
      return(FAIL);

--- 543,548 -----
  		} else {
  			delock(dev.D_line);
  		}
  	}
  	return(FAIL);
  }
***************
*** 511,519
  		}
  	    }
  	}
!     fclose(dfp);
!     return(FAIL);
!     }
  
  #ifdef DN11
  

--- 544,551 -----
  			delock(dev.D_line);
  		}
  	}
! 	return(FAIL);
! }
  
  #ifdef DN11
  
***************
*** 850,855
  	/* modem is open */
  	next_fd = -1;
  	if (dh >= 0) {
  		fixline(dh, dev->D_speed);
  #ifdef HAYSTONE
  		write(dh, "\rATDT", 5);

--- 882,892 -----
  	/* modem is open */
  	next_fd = -1;
  	if (dh >= 0) {
+ #ifdef TIOCSPGRP
+ 		/* fix for mysterious "EIO" on read error */
+ 		int pgrp = getpgrp(0);
+ 		ioctl(dh, TIOCSPGRP, &pgrp);
+ #endif
  		fixline(dh, dev->D_speed);
  #ifdef HAYSTONE
  		write(dh, "\rATDT", 5);
***************
*** 978,983
  
  	alarm(0);
  	next_fd = -1;
  	fixline(dnf, dev->D_speed);
  	DEBUG(4, "Hayes port - %s, ", dcname);
  

--- 1015,1027 -----
  
  	alarm(0);
  	next_fd = -1;
+ #ifdef TIOCSPGRP
+ 	{
+ 		/* fix for mysterious "EIO" on read error */
+ 		int pgrp = getpgrp(0);
+ 		ioctl(dnf, TIOCSPGRP, &pgrp);
+ 	}
+ #endif
  	fixline(dnf, dev->D_speed);
  	DEBUG(4, "Hayes port - %s, ", dcname);
  
***************
*** 1044,1049
  		close(fd);
  		sleep(2);
  		fd = open(dcname, 2);
  /*
   * Since we have a getty sleeping on this line, when it wakes up it sends
   * all kinds of garbage to the modem.  Unfortunatly, the modem likes to

--- 1088,1099 -----
  		close(fd);
  		sleep(2);
  		fd = open(dcname, 2);
+ #ifdef TIOCSPGRP
+ 		{	/* fix for mysterious "EIO" on read error */
+ 			int pgrp = getpgrp(0);
+ 			ioctl(fd, TIOCSPGRP, &pgrp);
+ 		}
+ #endif
  /*
   * Since we have a getty sleeping on this line, when it wakes up it sends
   * all kinds of garbage to the modem.  Unfortunatly, the modem likes to
***************
*** 1090,1095
  	}
  
  	/* modem is open */
  	fixline(dh, dev->D_speed);
  
  	/* translate - to % and = to & for VenTel */

--- 1140,1151 -----
  	}
  
  	/* modem is open */
+ #ifdef TIOCSPGRP
+ 	{	/* fix for mysterious "EIO" on read error */
+ 		int pgrp = getpgrp(0);
+ 		ioctl(dh, TIOCSPGRP, &pgrp);
+ 	}
+ #endif
  	fixline(dh, dev->D_speed);
  
  	/* translate - to % and = to & for VenTel */
***************
*** 1147,1182
   * uucpdelay:  delay execution for numerator/denominator seconds.
   */
  
- #ifdef INTERVALTIMER
- #define uucpdelay(num,denom) intervaldelay(1000000*num/denom)
- #include <sys/time.h>
- catch alarm sig
- SIGALRM
- struct itimerval itimerval;
- itimerval.itimer_reload =
- itimerval.rtime.itimer_interval =
- itimerval.rtime.itimer_value =
- settimer(ITIMER_REAL, &itimerval);
- pause();
- alarm comes in
- turn off timer.
- #endif INTERVALTIMER
- 
- #ifdef FASTTIMER
- #define uucpdelay(num,denom) nap(60*num/denom)
- /*	Sleep in increments of 60ths of second.	*/
- nap (time)
- 	register int time;
- {
- 	static int fd;
- 
- 	if (fd == 0)
- 		fd = open (FASTTIMER, 0);
- 
- 	read (fd, 0, time);
- }
- #endif FASTTIMER
- 
  #ifdef FTIME
  #define uucpdelay(num,denom) ftimedelay(1000*num/denom)
  #include <sys/timeb.h>

--- 1203,1208 -----
   * uucpdelay:  delay execution for numerator/denominator seconds.
   */
  
  #ifdef FTIME
  #define uucpdelay(num,denom) ftimedelay(1000*num/denom)
  #include <sys/timeb.h>
***************
*** 1265,1271
  	if (dh < 0) {
  		delock(dev->D_line);
  		return(CF_NODEV);
! 		}
  	fixline(dh, dev->D_speed);
  
  /* translate - to K for Vadic */

--- 1291,1303 -----
  	if (dh < 0) {
  		delock(dev->D_line);
  		return(CF_NODEV);
! 	}
! #ifdef TIOCSPGRP
! 	{	/* fix for mysterious "EIO" on read error */
! 		int pgrp = getpgrp(0);
! 		ioctl(dh, TIOCSPGRP, &pgrp);
! 	}
! #endif
  	fixline(dh, dev->D_speed);
  
  /* translate - to K for Vadic */
***************
*** 1394,1399
  		i = CF_NODEV;
  		goto ret;
  	}
  	fixline(va, dev->D_speed);
  
  	p_chwrite(va, STX);	/* access adaptor */

--- 1426,1437 -----
  		i = CF_NODEV;
  		goto ret;
  	}
+ #if TIOCSPGRP
+ 	{	/* fix for mysterious "EIO" on read error */
+ 		int pgrp = getpgrp(0);
+ 		ioctl(va, TIOCSPGRP, &pgrp);
+ 	}
+ #endif
  	fixline(va, dev->D_speed);
  
  	p_chwrite(va, STX);	/* access adaptor */
***************
*** 1459,1464
  			logent("dialup open", "FAILED");
  		goto failret;
  	}
  	fixline(i, dev->D_speed);
  	goto ret;
  failret:

--- 1497,1508 -----
  			logent("dialup open", "FAILED");
  		goto failret;
  	}
+ #ifdef TIOCSPGRP
+ 	{	/* fix for mysterious "EIO" on read error */
+ 		int pgrp = getpgrp(0);
+ 		ioctl(i, TIOCSPGRP, &pgrp);
+ 	}
+ #endif
  	fixline(i, dev->D_speed);
  	goto ret;
  failret:
***************
*** 1480,1482
  	close(fd);
  }
  #endif

--- 1524,1613 -----
  	close(fd);
  }
  #endif
+ 
+ #ifdef DIALINOUT
+ /* DIALIN/OUT CODE (WLS) */
+ /***************************************************************************
+  * disable and reenable:  allow a single line to be use for dialin/dialout *
+  ***************************************************************************/
+ 
+ char enbdev[16];
+ 
+ disable(dev)
+ register char *dev;
+ {
+ 	register char *rdev;
+ 
+ 	/* strip of directory prefixes */
+ 	rdev = dev;
+ 	while (*rdev) rdev++;
+ 	while (--rdev >= dev && *rdev != '/');
+ 	rdev++;
+ 
+ 
+ 	if (enbdev[0]) {
+ 		if (strcmp(enbdev,rdev) == 0)
+ 			return(SUCCESS);	/* already disabled */
+ 		delock(enbdev);
+ 		reenable();			/* else, reenable the old one */
+ 	}
+ 	DEBUG(4, "Disable %s\n", rdev);
+ 	if (enbcall("disable", rdev) == FAIL)
+ 		return(FAIL);
+ 	logent(rdev, "DISABLED LOGIN");
+ 	strcpy(enbdev,rdev);
+ 	return(SUCCESS);
+ }
+ 
+ reenable()
+ {
+ 	if (enbdev[0] == NULL) return;
+ 	DEBUG(4, "Reenable %s\n", enbdev);
+ 	(void)enbcall("enable", enbdev);
+ 	logent(enbdev, "REENABLED LOGIN");
+ 	enbdev[0] = '\0';
+ }
+ 
+ enbcall(type, dev)
+ char *type, *dev;
+ {
+ 	int pid;
+ 	register char *p;
+ 	int fildes[2];
+ 	int status;
+ 	FILE *fil;
+ 	char buf[80];
+ 	
+ 	fflush(stderr); fflush(stdout);
+ 	pipe(fildes);
+ 	if ((pid = fork()) == 0) {
+ 		DEBUG(4, ACUPROG, 0);
+ 		DEBUG(4, " %s", type);
+ 		DEBUG(4, " %s\n", dev);
+ 		close(fildes[0]);
+ 		close(0); close(1); close(2);
+ 		open("/dev/null",0);
+ 		dup(fildes[1]); dup(fildes[1]);
+ 		setuid(geteuid());	/* for chown(uid()) in acu program */
+ 		execl(ACUPROG, "acu", type, dev, 0);
+ 		exit(999);
+ 	}
+ 	if (pid<0)
+ 		return(FAIL);
+ 
+ 	close(fildes[1]);
+ 	fil = fdopen(fildes[0],"r");
+ 	if (fil!=NULL) {
+ 		setlinebuf(fil);
+ 		while (fgets(buf,sizeof buf, fil)!=NULL) {
+ 			p = buf + strlen(buf) - 1;
+ 			if (*p == '\n')
+ 				*p = '\0';
+ 			logent(buf,"ACUCNTRL:");
+ 		}
+ 	}
+ 	while(wait(&status) != pid);
+ 	fclose(fil);
+ 	return(status ? FAIL : SUCCESS);
+ }
+ #endif DIALINOUT
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
	/bin/chmod 644 uucp.condevs.DIFF
	/bin/echo -n '	'; /bin/ls -ld uucp.condevs.DIFF
fi
/bin/echo 'Extracting uucp.uucp.DIFF'
sed 's/^X//' <<'//go.sysin dd *' >uucp.uucp.DIFF
diff -rc uucp.OLD/uucp.h /usr/src/usr.bin/uucp/uucp.h
*** uucp.OLD/uucp.h	Tue Jul 26 23:58:08 1983
--- /usr/src/usr.bin/uucp/uucp.h	Tue Jan 15 16:18:01 1985
***************
*** 116,119
  #define	PRIV_UIDS	3
  
  #define XQTDIR		"/usr/spool/uucp/XTMP"
  #define SQFILE		"/usr/lib/uucp/SQFILE"

--- 116,125 -----
  #define	PRIV_UIDS	3
  
+ /* program to disable/reenable logins on dialout line  (Mar 3,1984 WLS) */
+ #define ACUPROG		"/usr/local/lib/acucntrl"
+ #ifdef  ACUPROG
+ #	define	DIALINOUT
+ #endif
+ 
  #define XQTDIR		"/usr/spool/uucp/XTMP"
  #define SQFILE		"/usr/lib/uucp/SQFILE"
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
	/bin/chmod 644 uucp.uucp.DIFF
	/bin/echo -n '	'; /bin/ls -ld uucp.uucp.DIFF
fi
exit 0
-- 
Bill Sebok			Princeton University, Astrophysics
{allegra,akgua,burl,cbosgd,decvax,ihnp4,noao,princeton,vax135}!astrovax!wls