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

wls@astrovax.UUCP (William L. Sebok) (01/25/85)

This is a revision of the previously posted diffs to the 4.2 distribution of
uucp and tip to make them able to use the same lines for both dialing in and
dialing out.  This dialin-dialout mechanism runs under a vanilla 4.2 BSD
kernel, in particular on a Vax.  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.

OOPS!  Of course when one is about to post a program, even if it has been
stable for a a long time one is tempted to fix some nits in it.  One such nit
fix I did to acucntrl right before posting it broke it.  Under some
circumstances it would no longer properly recognize that a line was in use by
someone dialed in and would proceed to kick that person off.  The fixed
acucntrl has now been running smoothly here for several weeks.

Also I have redone the diffs.  The diffs are/were "edited diffs" as there have
been other changes I have made to uucico and tip besides those given here.
The last posting contained some editing mistakes that hopefully have been
fixed.

Finally the interface in uucico to acucntrl has been "improved".  uucico now
catches error output from acucntrl and puts it into the LOGFILE in lines of the
form:	ACUCNTRL: (message).

Bill Sebok			Princeton University, Astrophysics
{allegra,akgua,burl,cbosgd,decvax,ihnp4,noao,princeton,vax135}!astrovax!wls

----- Cut here ----
: 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.  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.

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 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 can only reach akgua, burl, and
sjuvax with a Hayes.  When our 2400 baud modem arrives so I can make special
note of that --- and 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.

There have been other changes here to both tip and uucp so that the "after"
line numbers in the diffs will not match.  The "before" files are fresh off the
4.2 BSD distribution tape.  The most important other change here in uucp was
one to allow site names longer that 7 characters.


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 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.

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),
or if the process is 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.  The 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
 * 
 * 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 subroutine
 *	stolen from program written by Tsutomu Shimomura
 *	{astrovax,escher}!tsutomu
 *
 *	Worked over many times by W.Sebok (i.e. hacked to death)
 *
 * 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 <signal.h>
#ifdef SIGIO
#	define	BSD4_2		/* how else am I to know? */
#endif
#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;
int utmploc;
int 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;
	long 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,&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,TIOCCDTR,0) < 0)
			fprintf(stderr,"On TIOCCDTR ioctl: %s\n",
				sys_errlist[errno]);

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

		if (ioctl(devfile, TIOCHPCL,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;

		settys(ENABLE);

		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 */
		settys(DISABLE);
		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, TIOCSDTR, 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(&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;

	post(device, uname);

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

	if (enable)
		return;

	/* wait till init has responded, clearing the utmp entry */
	do {
		sleep(1);
		if (lseek(etcutmp,utmploc,0)<0)
			fprintf(stderr,"On lseek in /etc/utmp: %s",
				sys_errlist[errno]);
		if (read(etcutmp,&utmp,sizeof utmp)<0)
			fprintf(stderr,"On read from /etc/utmp: %s",
				sys_errlist[errno]);
	} while (utmp.ut_name[0] !='\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;
	int  lnbeg, foundit, ndevice; 
	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,(long)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,(long)ttyslnbeg,0);
	if(write(ittysfil,&out,1)<0) {
		fprintf(stderr,"On %s write: %s\n",
			Etcttys, sys_errlist[errno]);
		exit(1);
	}
	(void)close(ittysfil);
}

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;
	struct uba_device *ubinfo;
	struct stat statb;
	short flags,devtype=0;
	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,
		(int) &(((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,(int) 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,(int) 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,(int) 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,addr,0);
	(void)read(kmem,(char *) &ubinfo,sizeof ubinfo);
	(void)lseek(kmem,(int) &(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,(int) &(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);
			}
			(void)lseek(kmem,(int) &(((char *)addr)[unit]),0);
			(void)write(kmem,(char *) &flags, sizeof flags);
			break;
		case DH11:
			if((addr = NLVALUE(DHSCAR)) == 0) {
				fprintf(stderr,"No dhsoftCAR.\n");
				return(-1);
			}
			(void)lseek(kmem,(int) &(((short *)addr)[unit]),0);
			(void)write(kmem,(char *) &flags, sizeof flags);
			break;
		case DMF:
			if((addr = NLVALUE(DMFSCAR)) == 0) {
				fprintf(stderr,"No dmfsoftCAR.\n");
				return(-1);
			}
			(void)lseek(kmem,(int) &(((short *)addr)[unit]),0);
			(void)write(kmem,(char *) &flags,2);
			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 tip.DIFF'
sed 's/^X//' <<'//go.sysin dd *' >tip.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;
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,153 -----
  		DV = next;
  		next = cp;
  	}
+ 	if (nextat != NOSTR) {
+ 		AT = nextat;
+ 		if ((nextat = index(nextat,',')) != NOSTR)
+ 			*nextat++ = '\0';
+ 	}
  	return (DV);
  }
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());
  
  	/*
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.DIFF
	/bin/echo -n '	'; /bin/ls -ld tip.DIFF
fi
/bin/echo 'Extracting uucp.DIFF'
sed 's/^X//' <<'//go.sysin dd *' >uucp.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();
diff -rc uucp.OLD/condevs.c /usr/src/usr.bin/uucp/condevs.c
*** uucp.OLD/condevs.c	Sat Aug 13 13:23:31 1983
--- /usr/src/usr.bin/uucp/condevs.c	Mon Jan 21 20:59:11 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);
***************
*** 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)

--- 499,505 -----
  	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')

--- 499,505 -----
  	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;
  

--- 501,521 -----
  		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);

--- 517,523 -----
  		}
  
  		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) {

--- 519,538 -----
  		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);
  		}
  	    }
  	}

--- 536,546 -----
  		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);

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

--- 543,550 -----
  			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);

--- 881,855 -----
  	/* 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);
  		if (hayes_sync(dh) == FAIL) {
  			logent(dev->D_line,"Cannot sync Hayes");
***************
*** 978,983
  
  	alarm(0);
  	next_fd = -1;
  	fixline(dnf, dev->D_speed);
  	DEBUG(4, "Hayes port - %s, ", dcname);
  

--- 1016,1028 -----
  
  	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

--- 1089,1100 -----
  		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 */

--- 1141,1152 -----
  	}
  
  	/* 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 */
***************
*** 1265,1271
  	if (dh < 0) {
  		delock(dev->D_line);
  		return(CF_NODEV);
! 		}
  	fixline(dh, dev->D_speed);
  
  /* translate - to K for Vadic */

--- 1322,1344 -----
  	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 */

--- 1457,1468 -----
  		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 */
***************
*** 1528,1539
  			logent("dialup open", "FAILED");
  		goto failret;
  	}
  	fixline(i, dev->D_speed);
  	goto ret;
  failret:

--- 1528,1539 -----
  			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

--- 1555,1644 -----
  	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
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.DIFF
	/bin/echo -n '	'; /bin/ls -ld uucp.DIFF
fi
exit
---- End.  If this line is not present something is missing ----
-- 
Bill Sebok			Princeton University, Astrophysics
{allegra,akgua,burl,cbosgd,decvax,ihnp4,noao,princeton,vax135}!astrovax!wls