[net.sources] UUCP and line turn around code

dan (08/19/82)

	I have received requests for the code to implement the scheme of
line turn around mentioned in a previous article under net.unix-wizards.
One should refer to that article for the reasons for each piece of code.
Since there are so many tty drivers around it seemed reasonable to present
the code in a commentary fashion rather than any diff listing or our driver
in its entirety. In the v7 tty.c, there is an XCLUDE bit; this code might be
thought of as an extension of that facilty.

*** In ttyopen(),
	A news process group is being started by a fork of init. These should
block if the line is locked. One can, of course, sleep on some other address
than tp->t_state.
***

	pp = u.u_procp;
	if (pp->p_pgrp == 0 && pp->p_pid != 1) {
		pp->p_pgrp = pp->p_pid;
		u.u_ttyp = tp;
		/* u.u_ttyd set up by openi in fio.c */
#ifdef	EXCLUDE
		if (tp->t_state&EXCLUDE) {
			spl5();
			while (tp->t_state&EXCLUDE)
				sleep(&tp->t_state, TTIPRI);
			spl0();
			u.u_error = EBUSY;
			return;
		}
#endif
		if (tp->t_pgrp) {
			signal(tp->t_pgrp, SIGHUP);
			flushtty(tp);
		}
		tp->t_pgrp = pp->p_pid;
	}

*** Also in ttyopen(),
	If the inode of the device entry has its x-bit set, call ttlock() to
lock the line. In our application, /dev/cul0 has its x-bit set and is a
different inode than its /dev/tty?.
***

#ifdef	EXCLUDE
	if ((fp = getf(u.u_ar0[R0])) == NULL)
		return;
	if (fp->f_inode->i_mode&IEXEC)
		ttlock(tp);
#endif

	tp->t_state =& ~WOPEN;
	tp->t_state =| ISOPEN;
}

ttyclose(tp)
register struct tty *tp;
{

*** In ttyclose(),
	The basic issue is to see if we should really close the device. If the
line is locked, then only the process group which set the lock is allowed to
close it. The line is also unlocked if it is closed.
	A bit of a kluge is used here and in ttlock(). The process group t_pgrp
is stored by ttlock() as the negative of pp->p_pgrp, if the process is not a
fork of init. The point is to try to avoid getting SIGHUP upon reopening and
carrier drops, while still knowing which p_pgrp set the lock.
***

#ifdef	EXCLUDE
	if ((tp->t_state&EXCLUDE) == 0
		|| abs(tp->t_pgrp) == u.u_procp->p_pgrp) {
#endif
		if (tp->t_state&CARR_ON)
			wflushtty(tp);
		else
			flushtty(tp);
#ifdef	EXCLUDE
	}
	spl5();
	if (tp->t_state&EXCLUDE)
		if (abs(tp->t_pgrp) == u.u_procp->p_pgrp)
			ttunlock(tp);
		else {	
			spl0();
			return(1);
		}
#endif
	tp->t_state &= (CARR_ON|SSTART|EXCLUDE);
#ifdef	EXCLUDE
	spl0();
#endif
	return(0);
}

*** Then in ttysgtty()/ttioctl(),
	One needs a way of calling ttlock() and ttunlock() from user programs.
***

#ifdef	EXCLUDE
	case(TTLOCK):
		ttlock(tp);
		break;
	case(TTUNLOCK):
		ttunlock(tp);
		break;
#endif
	default:
		u.u_error = EINVAL;
	}
}

*** Finally the short routines ttlock() and ttunlock()
***

#ifdef	EXCLUDE
ttlock(tp)
register struct tty *tp;
{
	register struct proc *pp;

	pp = u.u_procp;
	spl5();
*** Slight subtlety, members of the locking p_pgrp should be able to do reopens.
	while ((tp->t_state&EXCLUDE) && abs(tp->t_pgrp) != pp->p_pgrp)
		sleep(&tp->t_state, TTIPRI);
	tp->t_state |= EXCLUDE;
*** If not fork of init
	if (tp->t_pgrp != pp->p_pgrp) {
		if (tp->t_pgrp > 0)
			signal(tp->t_pgrp, SIGHUP);
		tp->t_pgrp = - pp->p_pgrp;
	}
	spl0();
}

ttunlock(tp)
register struct tty *tp;
{

	tp->t_state &= ~EXCLUDE;
	wakeup(&tp->t_state);
	if (tp->t_pgrp < 0)
		tp->t_pgrp = 0;
}

#endif

***
				Have fun,
				Dan Ts'o

				...decvax!cca!ima!n44a!dan