[net.bugs.4bsd] Definite portability bug in 4.2 getty

smk@axiom.UUCP (Steven M. Kramer) (02/26/84)

The variable allflags in main.c of the 4.2 getty (which is excellent
in most respects and quite an improvement over the older
non-tabularized getty's) assumes the bits for te TIOCLSET and the bits
for the st_flags word of TIOCSETP word are distinct.  They never were
before but now they are.  Porting getty to older version of UNIX will
cause a mess because of this.  My solution is to separate setflags()
in subr.c into two routines: setflags() and setlocalmode().  The
diffs below show the solution.  Note that I'm passing a short to
the TIOCLSET ioctl in main.c and this may not work on your UNIX (like
4.xBSD).  To fix that, make allflags a long and the result will work
much more portabally than before.

	Hey, am I right on the delay code?  It seems 0 is supposed
to give the ??0 setting.  Any other changes along those lines?

	--steve kramer

--------------------------
*** /usr/src/etc/getty/main.c	Mon Aug  1 19:07:07 1983
--- main.c	Sat Feb 25 17:51:39 1984
***************
*** 91,96
  	char *argv[];
  {
  	char *tname;
  	long allflags;
  
  	signal(SIGINT, SIG_IGN);

--- 99,119 -----
  	char *argv[];
  {
  	char *tname;
+ #ifdef AXIOM
+ 	/*
+ 	 * On our port, the kernel does a sizeof to find out the
+ 	 * size of the buffer.  Since it is a short, specifying a
+ 	 * long essentially always zeroes the setting (for the
+ 	 * TIOCL[GS]ET cases.  We make it unsigned because the top
+ 	 * bit can be set which may hurt at some point.  We also
+ 	 * declare setflags() and setlocalmode() to be unsigned
+ 	 * short to properly reflect what's going on here.
+ 	 * Steve Kramer 2/24/84
+ 	 */
+ 	unsigned short allflags;
+ 	extern unsigned short setflags();
+ 	extern unsigned short setlocalmode();
+ #else
  	long allflags;
  #endif
  
***************
*** 92,97
  {
  	char *tname;
  	long allflags;
  
  	signal(SIGINT, SIG_IGN);
  /*

--- 115,121 -----
  	extern unsigned short setlocalmode();
  #else
  	long allflags;
+ #endif
  
  	signal(SIGINT, SIG_IGN);
  /*
***************
*** 153,158
  				continue;
  			allflags = setflags(2);
  			tmode.sg_flags = allflags & 0xffff;
  			allflags >>= 16;
  			if (crmod || NL)
  				tmode.sg_flags |= CRMOD;

--- 177,195 -----
  				continue;
  			allflags = setflags(2);
  			tmode.sg_flags = allflags & 0xffff;
+ #ifdef AXIOM
+ 			/*
+ 			 * The original code here was bit dependent and
+ 			 * assumed that the bits for two separate functions
+ 			 * (the mode and local mode setting) did not
+ 			 * collide.  This is only true on 4.2BSD.  We
+ 			 * solve the problem on other systems (like our 68000
+ 			 * one) by making two separate routines deal with
+ 			 * the bits.
+ 			 * Steve Kramer 2/24/84
+ 			 */
+ 			allflags = setlocalmode();
+ #else
  			allflags >>= 16;
  #endif
  			if (crmod || NL)
***************
*** 154,159
  			allflags = setflags(2);
  			tmode.sg_flags = allflags & 0xffff;
  			allflags >>= 16;
  			if (crmod || NL)
  				tmode.sg_flags |= CRMOD;
  			if (upper || UC)

--- 191,197 -----
  			allflags = setlocalmode();
  #else
  			allflags >>= 16;
+ #endif
  			if (crmod || NL)
  				tmode.sg_flags |= CRMOD;
  			if (upper || UC)
*** /usr/src/etc/getty/subr.c	Thu Jul  7 06:32:55 1983
--- subr.c	Sat Feb 25 18:04:26 1984
***************
*** 114,119
  	}
  }
  
  long
  setflags(n)
  {

--- 122,139 -----
  	}
  }
  
+ #ifdef AXIOM
+ /*
+  * We define the routine here and local variables to be what they
+  * REALLy are, not any more or less.  In dealing with bit positions
+  * and arguments to ioctl()'s, this is crucial.
+  * Steve Kramer 2/24/84
+  */
+ unsigned short
+ setflags(n)
+ {
+ 	register unsigned short f;
+ #else
  long
  setflags(n)
  {
***************
*** 118,123
  setflags(n)
  {
  	register long f;
  
  	switch (n) {
  	case 0:

--- 138,144 -----
  setflags(n)
  {
  	register long f;
+ #endif
  
  	switch (n) {
  	case 0:
***************
*** 162,167
  	if (!HT)
  		f |= XTABS;
  
  	if (n == 0)
  		return (f);
  

--- 183,215 -----
  	if (!HT)
  		f |= XTABS;
  
+ #ifdef AXIOM
+ 	/*
+ 	 * NERTZ!  They changed the way 4.2BSD does mode setting but
+ 	 * forgot to say so in the documentation.  They changed the definition
+ 	 * of the local mode bits so they wouldn't collide with those
+ 	 * of the sg_flags bits.  Then, they used the same routine to
+ 	 * set all the bits at once.  The problem is that this is very
+ 	 * inplementation dependent and it stinks.  It should be, and is,
+ 	 * two routines in our implementation.  Note that the ECHO mode
+ 	 * setting belongs here.
+ 	 * Steve Kramer 2/25/84
+ 	 */
+ 
+ 	if (EC)
+ 		f |= ECHO;
+ 
+ 	return (f);
+ }
+ 
+ 
+ unsigned short
+ setlocalmode()
+ {
+ 	register unsigned short f;
+ 
+ 	f = 0L;
+ #else
  	if (n == 0)
  		return (f);
  
***************
*** 165,170
  	if (n == 0)
  		return (f);
  
  	if (CB)
  		f |= CRTBS;
  

--- 213,219 -----
  	if (n == 0)
  		return (f);
  
+ #endif
  	if (CB)
  		f |= CRTBS;
  
***************
*** 174,179
  	if (PE)
  		f |= PRTERA;
  
  	if (EC)
  		f |= ECHO;
  

--- 223,235 -----
  	if (PE)
  		f |= PRTERA;
  
+ #ifdef AXIOM
+ 	/*
+ 	 * Move this to the setflags() routine.  It conceptually and
+ 	 * now definitely belongs there.
+ 	 * Steve Kramer 2/25/84
+ 	 */
+ #else
  	if (EC)
  		f |= ECHO;
  
***************
*** 177,182
  	if (EC)
  		f |= ECHO;
  
  	if (XC)
  		f |= CTLECH;
  

--- 233,239 -----
  	if (EC)
  		f |= ECHO;
  
+ #endif
  	if (XC)
  		f |= CTLECH;
  
***************
*** 198,203
  	3,		CR3,
  	83,		CR1,
  	166,		CR2,
  	0,		CR3,
  };
  

--- 255,267 -----
  	3,		CR3,
  	83,		CR1,
  	166,		CR2,
+ #ifdef AXIOM
+ 	/*
+ 	 * 0 SHOULD mean CR0 obviously.
+ 	 * Steve Kramer 2/22/84
+ 	 */
+ 	0,		CR0,
+ #else
  	0,		CR3,
  #endif
  };
***************
*** 199,204
  	83,		CR1,
  	166,		CR2,
  	0,		CR3,
  };
  
  struct delayval nldelay[] = {

--- 263,269 -----
  	0,		CR0,
  #else
  	0,		CR3,
+ #endif
  };
  
  struct delayval nldelay[] = {
***************
*** 206,211
  	2,		NL2,
  	3,		NL3,
  	100,		NL2,
  	0,		NL3,
  };
  

--- 271,283 -----
  	2,		NL2,
  	3,		NL3,
  	100,		NL2,
+ #ifdef AXIOM
+ 	/*
+ 	 * 0 SHOULD mean NL0 obviously.
+ 	 * Steve Kramer 2/22/84
+ 	 */
+ 	0,		NL0,
+ #else
  	0,		NL3,
  #endif
  };
***************
*** 207,212
  	3,		NL3,
  	100,		NL2,
  	0,		NL3,
  };
  
  struct delayval	bsdelay[] = {

--- 279,285 -----
  	0,		NL0,
  #else
  	0,		NL3,
+ #endif
  };
  
  struct delayval	bsdelay[] = {
***************
*** 217,222
  struct delayval	ffdelay[] = {
  	1,		FF1,
  	1750,		FF1,
  	0,		FF1,
  };
  

--- 290,302 -----
  struct delayval	ffdelay[] = {
  	1,		FF1,
  	1750,		FF1,
+ #ifdef AXIOM
+ 	/*
+ 	 * 0 SHOULD mean FF0 obviously.
+ 	 * Steve Kramer 2/22/84
+ 	 */
+ 	0,		FF0,
+ #else
  	0,		FF1,
  #endif
  };
***************
*** 218,223
  	1,		FF1,
  	1750,		FF1,
  	0,		FF1,
  };
  
  struct delayval	tbdelay[] = {

--- 298,304 -----
  	0,		FF0,
  #else
  	0,		FF1,
+ #endif
  };
  
  struct delayval	tbdelay[] = {
-- 
	--steve kramer
	{allegra,genrad,ihnp4,utzoo,philabs,uw-beaver}!linus!axiom!smk	(UUCP)
	linus!axiom!smk@mitre-bedford					(MIL)

kre@mulga.SUN (Robert Elz) (02/27/84)

To: Steven M Kramer @ Axiom  (posted as a correction of earlier news)

I'm glad that you approve of the 4.2bsd getty (which is one
of my small contributions), however, your bug fixes really just aren't ...

Easiest is your "fix" to the delay setting tables.  There you simply
have not read the code.  If you look in adelay() in subr.c, you
will see that the delay tables are searched in ascending order
of delay values, stopping when a delay greater than, or equal to,
the requested delay is encountered.  To stop such a search, I
have used a '0' as a sentinal value, a fairly common technique
I think.  An alternative would be to use a value bigger than
anything anyone would ever request - but how big is that?
The '0' means "anything bigger than the previous value", and
should obviously result in the longest possible delay, not none!
Adelay() has a special case for a requested delay of 0.

The "portability" bug in the handling of the flag bits is
really just an implementation technique, perhaps not the
best possible, but not really a bug either.

Getty uses the new, 4.2bsd, #defines of CRTBS, CTLECH, etc,
which aren't available on previous systems (really they're
not intended for use outside the kernel on 4.2, but getty
is a pretty special program).  These names are defined
to be (LCRTBS<<16) (etc) - they must have 16 low order zero
bits, and cannot conflict with any of the sg_flags bits
used with TIOCSETP.

If you are going to port getty from 4.2 to some other
system, you should port the #defines as well, I guess
that you have assumed that CRTBS is just a new name
for LCRTBS;  such is not the case, LCRTBS is still
there, and has the same value that it always had.
It hasn't been "moved".

It is true, as you suggest, that the code would be a little
cleaner if the "standard" flags and the "local" flags were
handled by distinct routines - that is while the distinction
between them remains, which it didn't on 4.1c bsd, where the
4.2 getty was developed.  Its quite likely that sometime the
distinction will vanish again, after all, they're all just flags ...


Robert Elz
decvax!mulga!kre

ps: just in case anyone hasn't guessed, I'm suggesting that
you ignore the suggested fixes to getty, and leave it as it is.