hoey@nrl-aic.arpa (Dan Hoey) (08/20/87)
From: der Mouse <mouse@mcgill-vision.uucp> Subject: Re: Accessing argc & argv from a functi Message-Id: <853@mcgill-vision.UUCP> Date: 5 Aug 87 07:33:09 GMT ... Well over half of all the calls to perror() I write look like perror((char *)0); because the prefix is more complicated than a single string, so I have fprintf(stderr,....); before the perror(). Then you had better save and restore errno around the call to fprintf, in case fprint makes a failing syscall. Wish perror() were printflike, perhaps like syslog() - syslog() accepts a printf format, except that %m means insert sys_errlst[errno]. Maybe that's why sendmail sometimes says ``Not a typewriter''? Dan Hoey HOEY@NRL-AIC.ARPA
chris@mimsy.UUCP (Chris Torek) (08/21/87)
In article <8913@brl-adm.ARPA> hoey@nrl-aic.arpa (Dan Hoey) writes: >you had better save and restore errno around the call to fprintf, >in case fprintf makes a failing syscall. This is something I had thought about; since my error() takes errno as a parameter, it does not have this problem. On the other hand, the only time fprintf(stderr, ...) currently fails is when stderr is not connected anywhere, in which case none of the perror() text will go anywhere. >Maybe that's why sendmail sometimes says ``Not a typewriter''? No, this is (almost?) always a result of the isatty() calls in _flsbuf(), followed by a syslog() with no intervening section 2 call errors. -- In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7690) Domain: chris@mimsy.umd.edu Path: seismo!mimsy!chris
rpw3@amdcad.AMD.COM (Rob Warnock) (08/22/87)
Sometimes when I get really frustrated by the fact that a successful system call does *not* clear errno, I use the following macro: #define ERRED(x) ((errno = 0), (x), errno != 0) So you can say things like: while (ERRED(pid = fork())) { /* handle fork() failure */ ...decide how many times to sleep + loop, or whether to exit() or longjmp() or what... } if (pid) { ...parent... } else { ...child... } This bypasses problems with syscalls that can return "-1" as a valid successful result, such as "nice()", and also avoids the "Not a typewriter" syndrome. The problem is I don't use it consistently (nor does anyone else) and therefore it can sometimes be a hindrance to maintenance rather than a help (the old "Bourne Shell ALGOL" problem). ;-} ;-} Rob Warnock Systems Architecture Consultant UUCP: {amdcad,fortune,sun,attmail}!redwood!rpw3 ATTmail: !rpw3 DDD: (415)572-2607 USPS: 627 26th Ave, San Mateo, CA 94403
brian@ncrcan.UUCP (Brian Onn) (08/24/87)
In article <18005@amdcad.AMD.COM> rpw3@amdcad.UUCP (Rob Warnock) writes: >This bypasses problems with syscalls that can return "-1" as a valid successful >result, such as "nice()", and also avoids the "Not a typewriter" syndrome. Sorry if this has been hashed here before. but what is this syndrome? I remember working with a guy who was writing some code, and he kept complaining that after his system calls, errno was being set to 25 (ENOTTY). I beleive this is what you are talking about, but what causes it?
rpw3@amdcad.AMD.COM (Rob Warnock) (08/26/87)
Tutorial time. All old-timers please "n" now... In article <301@ncrcan.UUCP> brian@ncrcan.UUCP () writes: +--------------- | In article <18005@amdcad.AMD.COM> rpw3@amdcad.UUCP (Rob Warnock) writes: | > ...and also avoids the "Not a typewriter" syndrome. | Sorry if this has been hashed here before. but what is this syndrome? I | remember working with a guy who was writing some code, and he kept complaining | that after his system calls, errno was being set to 25 (ENOTTY). I beleive | this is what you are talking about, but what causes it? +--------------- Chain of causes/events: 1. Unix does not clear errno on successful system calls, it only *sets* it on unsuccessful ones. (Why? Who knows/cares! It's there, and I'm sure some program somewhere would break if you changed it at this late date...) 2. Stdio packages which do "clever" line buffering of stdout on terminals (BSD 4.x and some System-V's) call "isatty()" to see if the file descriptor is a terminal. "Isatty()" does the system call "ioctl(fd, TIOCGETP, &tmp)" (Berkeley) or "ioctl(fd, TCGETA, &tmp)" (System-V), attempting to get the TTY characteristics. If the call succeeds, fine, set line buffering. If it fails (e.g., when your stdout is a pipe or a file), errno gets set to 25 (ENOTTY). 3. Many programs have a common routine [often called "panic()", "fatal()", or "die()"] they use to print error messages and exit, and some of those blindly call "perror()" (or private equivalent) to print an error message, and seeing errno set [due to #1 & #2 above], print the corresponding message from "sys_errlist[]". By the way, the usual string in "sys_errlist[25]" is "Not a typewriter". 4. The program detects an error of some kind which is *NOT* the immediate result of a unsuccessful system call, and because of #3, prints "Not a typewriter" instead of anything useful. Result? User is confused. How can #4 happen? At least three ways: a. An actually successful system call returns a value which the program mistakenly is in error. A typical example is a negative return value (including "-1") which the program wasn't expecting [such as from "nice()"]. b. The program detects an inconsistency in its input *data*, and "panic()"s. Errno is set even though no user-visible system call has failed. Per #3, "panic()" mistakenly assumes non-zero errno means use "perror()" (or equiv). This one is not quite so stupid as it looks. Many programs have an internal convention of "-1" or a negative value as an error return from lower-level routines. If an error occurs in a low-level routine, each level sees the "-1" return and backs out to the next higher. At the top level, some error handling occurs, using the value left in errno by the low-level routine that detected the error. Unfortunately, sloppy code may return "-1" as an error (due to bad input data, etc.) *without* explicitly setting errno, so the left-over "25" gets used. c. An actual system call error occurs, but while handling the error stdio is touched for the first time, and the errno value from the user's system call gets stomped on by the errno value from the failing "ioctl()" in "isatty()". Example: char *fname = "/No/such/file/exists"; if (open(fname, 0) < 0) { fprintf(stderr, "File '%s', ", fname); perror("open failed"); exit(1); } Between the failing "open()" and the "perror()", "fprintf()" opens stderr for the first time. If stderr has been redirected to a non-TTY, errno will be set to ENOTTY by the "isatty()". (While 4.3 BSD will not not call "isatty()" except on stdout, some programs are so broken as to do output to stdout between the failing system call and the "perror()"!) The solution is not fun, but starts with always clearing errno before a system call (which was what the "ERRED(x)" macro was about in the previous article). Then, *ALWAYS* make sure that you don't use errno when it's not germane. One way is to include an error-code argument in any "die()" routine; you can always say 'die(errno, "message...")' when errno's known to be valid. If an error is not due to a system call, either call "die(0,...)" or explicitly use some error value chosen to be "appropriate". For example, if the user has violated some protection boundary, say 'die(EACCESS, "That's not allowed")'. (Actually, please use a better message than that!) Finally, in any error- handling routine, save errno early so it's not lost, and *ALWAYS* print the numeric code in addition to any other messages. - Rob ("Help stamp out 'Not a typewriter'!") Warnock UUCP: {amdcad,fortune,sun,attmail}!redwood!rpw3 ATTmail: !rpw3 DDD: (415)572-2607 USPS: 627 26th Ave, San Mateo, CA 94403
karl@haddock.ISC.COM (Karl Heuer) (08/31/87)
In article <18082@amdcad.AMD.COM> rpw3@amdcad.UUCP (Rob Warnock) writes: [explanation of the "Not a typewriter" syndrome] I avoid this problem by using my own copy of isatty(); one which does not have the side effect of setting errno. Lately I've noticed some official versions of isatty() have also fixed this. If yours doesn't, help yourself to the PD implementation below. (Actually, the one I keep in my libhack.a is from an assembler version.) Karl W. Z. Heuer (ima!haddock!karl or karl@haddock.isc.com), The Walking Lint ---- cut here ---- #!/bin/sh cat <<\! >bool.h typedef int bool; #define YES 1 #define NO 0 ! cat <<\! >isatty.c /* Test whether a file descriptor is a terminal; preserve errno */ #include "bool.h" #ifdef USG #include <sys/termio.h> #define ioarg struct termio #define ISATTY TCGETA #else #include <sgtty.h> #define ioarg struct sgttyb #define ISATTY TIOCGETP #endif extern int ioctl(); bool isatty(f) int f; { extern int errno; ioarg dummy; register int saverrno = errno; if (ioctl(f, ISATTY, &dummy) < 0) { errno = saverrno; return (NO); } else { return (YES); } } ! exit 0