*BSD News Article 7085


Return to BSD News archive

Newsgroups: comp.unix.bsd
Path: sserve!manuel.anu.edu.au!munnari.oz.au!uunet!kithrup!hoptoad!decwrl!elroy.jpl.nasa.gov!swrinde!zaphod.mps.ohio-state.edu!caen!hellgate.utah.edu!fcom.cc.utah.edu!cs.weber.edu!terry
From: terry@cs.weber.edu (A Wizard of Earth C)
Subject: Re: uugetty for 386bsd
Message-ID: <1992Oct26.220714.5667@fcom.cc.utah.edu>
Sender: news@fcom.cc.utah.edu
Organization: Weber State University  (Ogden, UT)
References: <1992Oct18.191610.1992@draco.bison.mb.ca> <1992Oct20.174948.742@fcom.cc.utah.edu> <Bwon4H.Lx8@flatlin.ka.sub.org>
Date: Mon, 26 Oct 92 22:07:14 GMT
Lines: 295

In article <Bwon4H.Lx8@flatlin.ka.sub.org> bad@flatlin.ka.sub.org (Christoph Badura) writes:
>In <1992Oct20.174948.742@fcom.cc.utah.edu> terry@cs.weber.edu (A Wizard of Earth C) writes:
>>The purpose of uugetty is twofold:
>
>>1)	It waits for a return before spitting anything back; thus an
>>	improperly configured modem will continue to operate.
>>2)	It allows bidirectional use of modems.
>
>You have it backwards.
>
>The primary purpose of uugetty in *HDB* UUCP is to allow the use of
>bidrectional modem lines *despite* the lack of properly interlocking
>tty drivers. This is the reason why the uucp device lock files are
>created.

I guess this is true, as long as you only use UUCP and relate programs (like
cu) to talk to serial pots.  Of cours, if anything useful is ever required,
like pcomm or tip, etc) which *isn't* part of the UUCP program suite, then
you are SOL.

It's clear from the HDB sources in SVR3.2 and SVR4.2 and SVR4.4 that the
authors had access to UNIX sources.  The tty driver interlock workarounds
are unnecessary on these systems, and were they necessary, source mods to
the tty drivers would have been preferrable.

>Further, uugetty *only* waits for a return before spitting anything
>back, iff it is called with the -r option. This is solely to prevent
>two uugettys locking up by spitting login:s at each other on direct
>lines.

The "-r" option is correct; however, the reasoning for direct lines is
somewhat of a misnomer.  According to the comments in the UUCP sources,
this was to avoid the "chatter" problem on modems with DCD forced high,
not on direct lines.  Sure, it will have this effect on direct lines,
but this isn't the purpose.  The hack can fail on direct lines when
garbage is output on a warm or cold boot of one of the two systems
involved.  Generally, a direct line connection has the caller disable
the getty/uugetty on it's side, and calls are one direction at set
intervals, with uucico from cron tab.

The additional failure here is that login sessions do not necessarily
result in or clean up UUCP lock files, so there can still be some
tromping on toes.  The evidence for this is the secondary hack of the
pid in the lock file being tested with a kill 0 to determine if the
process that created the lock file is still around.  The kill 0 hack
is more evidence that HDB UUCP could have mandated changes to the tty
behaviour if the O_EXCL behaviour was not obeyed.  The failure here
is the lack of a normalized take-over machanism.  Any locks older than
90 minutes (by default) act as if the creating process does not exist
-- yet another toe-tromping situation for long user/transfer sessions.

>>Additionally, I object to uugetty's creation of UUCP style lockfiles.
>
>Why? Because they are not needed with properly interlocking tty
>drivers? Or because HDB has to cope with all sorts of tty braindamage,
>like say not properly interlocking tty drivers, on the various
>platforms it runs on?

The first reason -- "they are not needed with properly interlocking tty
drivers".  The second reason is not a consideration, given the origins
and code access for the original HDB UUCP.  Tty" brain damage" was not
a stated consideration in the AT&T HDB code.

>>  HDB
>>UUCP and clones do not correctly use the exclusivity mechanism from
>>O_EXCL, which should be sufficient to this task.  The existance of these
>>lock files appears to be the result of a misunderstanding of what is
>>called "the partial open hack" in sys2.c in the original SVR3.2 kernel;
>>this is probably because "open order" was not understood with reference
>>to O_EXCL not being reset on an O_NDELAY open --
>
>What are you talking about. sys2.c knows zilch about O_NDELAY and
>O_EXCL.

There exists something called "the partial open hack".  It is implemented
as follows, to allow the openning and use of a modem control port without
carrier detect being present:


part_open( port)
char	*port;
{
	int	pfd;
	int	realfd;

	if( ( pfd = open( port, O_RDWR|O_NDELAY)) == -1)
		return( -1);

	if( ( realfd  = open( port, O_RDWR)) == -1) {
		close( pfd);
		return( -1);
	}

	close( pfd);

	return( realfd);
}

This, of course, doesn't show the alarm calls around the open()'s to insure
a reasonable timeout.  If part_open() returns a valid descriptor, it may be
written to and read without DCD being present.

Now lets take the SVR3.2 sys2.c, which is the release where HDB UUCP had
it's first source release.

The fact that sys2.c "knows zilch about O_NDELAY and O_EXCL" is precisely
the problem, if one looks at the base implementation of cu or other
packages which did not use O_NDELAY I/O to effect polling reads, but
instead used 2 (or more) processes to allow them to hang in multiple
simultaneous reads (SVR3.2 poll() only worked on network I/O, and select()
wasn't really there yet).  This was accomplished by cu using a fork(),
where the parent read from the user and the child read from the serial
port; other programs used a "reader" program to communicate data from
the user or from the serial port to a common control program (TERM from
Century Software was one such product).  The purpose in doing this is to
allow incoming and outgoing processing of the data stream (terminal emulation,
file transfer, etc.).

The problem is, if the uugetty() used O_EXCL, then the O_EXCL bit stayed
set in the tty struct for realfd because of the way  the O_NDELAY open of
pfd effected the partial open hack state information.  In particular, an
O_NDELAY open does not reset the O_EXCL bit if someone else (like uugetty) 
has set it part way through an open.

Is this a problem?  By itself, no.... but in combination with trying to make
cu work, yes.  The problem is the duplication of the parent's open fd's
for the child -- using the code in sys2.c -- during the fork.  There are
fourteen lines of code that need to be moved down about 30 lines to fix
the problem -- so that children may inherit O_EXCL opened fd's from the
parent that forked them.  THIS IS WHAT KEPT cu FROM OPERATING IF O_EXCL
WAS USED INSTEAD OF LOCK FILES FOR HDB uucico AND uugetty, EACH OF WHICH
USE A SINGLE FD, UNLIKE cu.  THe authors either didn't know about (or
didn't bother to research how O_EXCL could be unset in the reference to
the file.  the way to do this is the following:


new_part_open( port)
char	*port;
{
	int	pfd;
	int	realfd;
	int	uefd;

	alarm( 2);
	uefd = open( port, O_RDWR);
	alarm( 0);
	if( uefd != -1)
		close( uefd);

	if( ( pfd = open( port, O_RDWR|O_NDELAY)) == -1)
		return( -1);

	if( ( realfd  = open( port, O_RDWR)) == -1) {
		close( pfd);
		return( -1);
	}

	close( pfd);

	return( realfd);
}

The addition code, which tries a non-O_NDELAY open, resets the O_EXCL bit,
so that not only can the caller of new_part_open() used the returned fd,
but that children will correctly inherit the parent's open fd to the
serial port.

Thus if uugetty() has the port open, the open will fail because of O_EXCL;
otherwise, the alarm() will go off.  I am not showing the errno handling
code here, but it's pretty obvious.  For more rigorous checking, the
reference count on the fd should be bumped once per partial open in
progress, and the following code fragment:

	int	exfd;

	alarm( 2);
	exfd = open( port, O_RDWR)|O_EXCL;
	alarm( 0);
	if( exfd != -1)
		close( exfd);

added and the errno checked to see if the open was denied for exclusivity
reasons (this is necessary, since O_EXCL is unset on open by the uugetty
before it exec's login; we can't so this in our program because our
credentials aren't the correct ones to unset the O_EXCL).

>> in actuality, a SVR3.2
>>UNIX will not reset and of the tty struct contents in the case of O_NDELAY.
>>This was either intentional (unlikely), or the result of misplacing about
>>12 lines of code in the dup2() system call implementation code, which is
>>also used during a "partial open hack" operation.
>
>Again, what are you talking about?

The partial open hack and how it interacts with O_EXCL for "non-partial"
opens, as explained above.

>SVR3 never reset the tty struct contents. It has always been the tty
>drivers calling ttinit() to do so. And since the tty struct (and
>ttinit() for that matter) know zilch about interlocking drivers,
>O_EXCL, and O_NDELAY how could it possibly be done with the tty
>struct?

Precidely the problem, and precisely what new_part_open() does, which is
why HDB should have used this code instead of going to bizarre lengths
with the locking mechanism, which is, in reality, unnecessary.

>And the dup2() system call has nothing to do with that either, because
>SVR3 doesn't support dup2() anyway. dup2() doesn't deal with
>"half-open" file descriptors, it doesn't deal with copen()/copen1() in
>any way.

And with opening the child fd's as a result of a fork() so that they
can be inherited from the parent.  In reality, it's the shared code
part that's in error.

>>In any case, Berkeley style calling units obviate the problem.
>
>Indeed.

>>		One of the major problems in
>>		the SCO implementation is the confusion of having two
>>		devices, both of which may operate simultaneously.  Thus
>>		the call-out works, but on connection a local host "login:"
>>		is echoed down the line to the remote host.  This is an
>>		error.  Login should only be enabled on the "non calling
>>		unit" device.
>
>Huh? I have never seen that one and I run SCO.

1.	login as root
2.	enable tty1a
3.	disable tty1A
4.	call out on tty1A

-or-

1.	login as root
2.	enable tty1A
3.	disable tty1a
4.	call out on tty1a

-or-

1.	enable both tty1A and tty1a (or tty14 if your SCO is real old)
2.	call out.

The main problem here is not only are there two devices that refer to the
same port that aren't interlocked between them to prevent them from
tromping on each other, but the problem can't be worked around because the
device name isn't cannonized to one form or the other.  The first case is
the most obvious, where you enable a uugetty on the non-modem control
device, which makes a lockfile for it, and then call out on the modem control
device, and the lock file name doesn't match; thus even though there is
a lock on the device, it doesn't prevent access to it.  An interlock between
the two would fix the problem.

>>	d)	Flags information should not be shared between versions of
>>		the device ("calling unit" vs. "non calling unit"), but
>>		mode information should be.  Thus baud rate is common, but
>>		O_EXCL and O_NDELAY are not.
>
>Give me a good reason why I shouldn't be able to have a 19200,8,N,1
>getty hanging on the dialin device while dialing out with 9600,7,e,2.

Your getty is converted.  This is *precisely* why you don't want shared
flags.  The open instances should maintain their own flags settings so
the *can't* screw with each other.

>>		Note that this requires
>>		blocking O_NDELAY opens to the device when its counterpart
>>		is in use.  This is acceptable, as it allows proper fail
>>		out on multiple getty's on the same device.
>
>I don't see a need for blocking a non-blocking open. Maybe it's
>because I don't understand what you want this for. An example why a
>non-blocking open shouldn't return EBUSY when the device's couterpart
>is in use would be most helpfull.

"blocking" in the sense of "interfering with", not "blocking" in the sense
of "putting the caller to sleep until the operation can be completed".
Sorry, about this -- it was inappropriate word choice on my part.


					Terry Lambert
					terry@icarus.weber.edu
					terry_lambert@novell.com
---
Any opinions in this posting are my own and not those of my present
or previous employers.
-- 
-------------------------------------------------------------------------------
                                        "I have an 8 user poetic license" - me
 Get the 386bsd FAQ from agate.berkeley.edu:/pub/386BSD/386bsd-0.1/unofficial
-------------------------------------------------------------------------------