[comp.sources.bugs] Compress error message

john@basser.oz (John Mackin) (08/26/87)

In article <209@ho7cad.ATT.COM> nuucp@ho7cad.ATT.COM (UUCP) writes:

> In article <339@cbstr1.att.com> Karl.Kleinpaste@cbstr1.att.com writes:
> 
> >>	   Not a typewriter
> 
> Well, I agree.  This is pretty funny.  But don't blame compress.  A lot
> of programs give you this.  Seems to be what you get on some machines
> when you call "perror()" when there ain't been no error (of its genre)
> [or maybe when the error number is bigger than the secret message
> array]. 

Consider this example code:

main()
{
	perror("foo");
}

On many UNIX systems (I'm sure there are many exceptions, please don't
send me mail (or worse, post!) pointing out that yours is one of them)
this will indeed print ``foo: Not a typewriter'', if its output has
been redirected onto a file.  Why?  It certainly isn't because there
hasn't been an error.  The reason is that the standard I/O library
(on many, but by no means all, systems) makes the buffering of stdout
behave differently if it is attached to a terminal.  On some systems,
it then becomes unbuffered by default; others (e.g., 4.3BSD) have
line-buffering, which is used by default on stdout if it is a terminal.

Now, to determine if the standard output is a terminal or not, the
stdio initialization typically uses isatty().  And isatty() works by
applying a system call that only works on terminals (typically, gtty())
to the supplied file descriptor and seeing whether it fails or not.
Hence, any time isatty() is applied to a file descriptor that is not
a terminal, it has the side-effect of setting errno to ENOTTY, "Not
a typewriter".

Mr. Kleinpaste is indeed entitled to blame compress.  The real problem
here is that perror() is being used in an inappropriate manner.  Seventh
Edition intro(2) clearly states:

    Errno is not cleared on successful calls, so it should
    be tested only after an error has occurred.

The only time errno is valid is immediately after a system call (or
library routine whose manual states that it sets errno on error) has
returned an error indication.  In this case it would seem that that
is not the case.  Many programs are quite cavalier about their use of
errno, both directly and indirectly (e.g. via perror()), and this
can sometimes lead to very subtle bugs, as well as annoying and
confusing inappropriate error messages.

John Mackin, Basser Department of Computer Science,
	     University of Sydney, Sydney, Australia

john@basser.oz.AU (john%basser.oz@SEISMO.CSS.GOV)
{seismo,hplabs,mcvax,ukc,nttlab}!munnari!basser.oz!john

Copyright 1987 John J. Mackin.  Restricted redistribution prohibited.

domo@riddle.UUCP (Dominic Dunlop) (09/08/87)

Nobody seems to have posted anything quite like this (although some are
quite close), so stand back while I demonstrate my prowess (you might just
get bored to death)...

An unexpected ``Not a typewriter'' message is usually the result of
perror() being called after some standard I/O operation which the caller
deems to have failed, but which has not actually made a failing system
call.  The reason is that, any time standard I/O opens an output file,
it tries a terminal-specific ioctl().  If the call succeeds, stdio knows
that it should send the output to the file without (much) buffering.  If it
fails, buffering is desirable for efficiency.  A failed ioctl() leaves
ENOTTY in errno, the location used by perror() to index into the table of
error messages.  As the errno value hangs around until the programmer
explicitly clears it (and most programmers don't bother), it's liable to
get picked up if perror() is called much later following an operation which
the programmer considers to be a failure, but which the kernel doesn't.
If the programmer clears errno before such an operation, and calls perror()
afterwards, another helpful message such as ``(null)'' may well result.

The moral of this story is that the only time it's safe to use perror()
to report problems is when a failure's so obvious that even the kernel's
noticed.  Why compress fails in this way on encountering the ulimit (boo,
hiss), rather than primly reporting an EFBIG error is beyond me.  Can I be
bothered to look at the source?  No (the pubs are open).

Dominic Dunlop
domo@riddle.uucp  domo@sphinx.co.uk