[net.bugs.uucp] fix for "4.2 dialup bug" and "LOST LINE

shannon@sun.uucp (Bill Shannon) (06/20/84)

I believe I have the fixes to two recently described problems,
the first from Mark Callow and the second from Ken Turkowski
(see references).

The general problem is that uucico is able to poll a site just
fine if you run it by hand but sometimes (only sometimes) fails
when it is run by cron.  The key to the problem is process groups
and the kernel's idea of a "control terminal" for a process.  The
problem occurs when uucico (called from cron) opens the tty line to
dial the modem, the dial fails, it closes and reopens the line and
tries again.  The problem only occurs on systems with 4.1bsd-derivative
tty drivers.  Now, the details of the problem.

Each process has a "controlling terminal", whose identity is saved
u.u_ttyp.  It is a pointer to the tty struct for the FIRST tty ever
opened by the process (clue).  A process also has a process group,
set to be the same as the process group of its parent, by default.
Init has process group 0 so the process group of all process' is 0
until one changes its process group or opens a tty. So, the uucico
started by cron has process group 0.  When a tty is first opened,
(see ttyopen() in tty.c) if the process group of the opening process
is 0, the process group of the process (u.u_procp->p_pgrp) and the
tty (tp->t_pgrp) are set to the pid of the process.  When the tty is
closed, its process group is reset to 0.

Now, consider the following code extract from tty.c:

	/*
	 * Hang process if it's in the background.
	 */
#define bit(a) (1<<(a-1))
	while (tp == u.u_ttyp && u.u_procp->p_pgrp != tp->t_pgrp) {
		if ((u.u_procp->p_sigignore & bit(SIGTTIN)) ||
		   (u.u_procp->p_sigmask & bit(SIGTTIN)) ||
/*
		    (u.u_procp->p_flag&SDETACH) ||
*/
		    u.u_procp->p_flag&SVFORK) {
			return (EIO);
		}

The first time the tty is opened by uucico (which is started by
cron), the second part of the while condition will be false (the
process groups will be equal).  The second time the same tty is
opened (after having been closed) its process group will have been
reset to 0 so the second part of the while condition will be true
and it will return EIO.  (In both cases the first part is true.
In the case where uucico is started by hand, the first part is false.
In both cases SIGTTIN is ignored so the if is always taken.)

And now, the fix.  In conn.c, in dialup(), after

		if ((Dnf = open(dnname, 2)) < 0) {
			delock(dev.D_line);
			continue;
		}

or some similar place where it opens the tty line, add

#ifdef TIOCSPGRP
		{
		int pgrp = getpgrp(0);
		ioctl(Dnf, TIOCSPGRP, &pgrp);
		}
#endif

This resets the process group of the terminal to the process'
process group after each open of the tty.  Perhaps not the best
fix, but it does work.

				Bill Shannon
				Sun Microsystems, Inc.