Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Path: utzoo!mnetor!uunet!husc6!sri-unix!quintus!ok From: ok@quintus.UUCP (Richard A. O'Keefe) Newsgroups: comp.lang.c Subject: Re: stdio error detection Message-ID: <336@cresswell.quintus.UUCP> Date: Wed, 2-Dec-87 18:07:50 EST Article-I.D.: cresswel.336 Posted: Wed Dec 2 18:07:50 1987 Date-Received: Sun, 6-Dec-87 04:03:12 EST References: <289@cresswell.quintus.UUCP> <13100001@bucc2> Organization: Quintus Computer Systems, Mountain View, CA Lines: 165 Summary: ANSI C errno stdio If you're interested in fclose(), here is the conclusion so far from mail several people were kind enough to send me: - because of buffered output, anything that can go wrong with fputc() can go wrong with fclose(). - even if you have successfully fflush()ed just before fclose()ing, some sort of device control error might happen - when an error occurs, everyone thinks the stdio stream ought to be closed, but there is no guarantee that it is. - in EUUG V7 UNIX, fclose() called fflush(), close(), and free() in that order. An error might be signalled because of any of them, so errno could be anything, but at least in that version of UNIX fclose() always freed up the stdio stream. My conclusion is that I ought to check for an error return from fclose(), because there *might* be lost data. In fact, I ought to fclose() or fflush() stdout before exiting, to be sure I don't miss lost data. But there is nothing I can do to tell the difference between lost data and a device that won't close. At least with respect to UNIX, I'm not worrying about lost streams any more. I have definitely learned something from this: it had never occurred to me before that my programs ought to end with something like if (fflush(stdout)) error_exit("probable data loss from stdout"); Ouch. If you're interested in a rambling discussion of error codes, continue, otherwise stop now. In article <289@cresswell.quintus.UUCP> I said > It would be really nice if the stdio functions were defined to set > errno (any ANSI C people care to comment?). In article <13100001@bucc2>, markb@bucc2.UUCP replied: > Set errno to what? There is no way the C standards committee is going to > attempt to identify all OS-dependent low-level error causes and provide > standard encodings for all of them! This is a red herring: maybe the latest draft is radically different, but in the October '86 draft of the ANSI C standard *NO* values of errno are defined at all. The standard *does* say that certain specified functions set errno to indicate an error, but says nothing about what they might set it TO. All I was suggesting here was that ANSI C should do the same sort of thing for fclose() that it already does for signal(). Here is what the text says: Otherwise, a value of SIG_ERR is returned, and >> the integer expression errno is set to indicate the error. << The October 86 draft says of fclose: The fclose function returns zero if the stream was successfully closed or nonzero if any errors were detected or if the stream was already closed. All I'm asking for here is for something like If the stream was successfully closed, the fclose function returns zero. NEW If any errors were detected or if the stream was already NEW closed, the fclose function returns nonzero, and NEW the integer expression errno is set to indicate the error. Several people told me that all my problems could be solved by setting errno to 0 beforehand and checking it afterwards. This is not defined to work for ANYTHING, even a straight system call. A successful system call is entitled to set errno to anything it pleases. Even supposing an implementation of stdio uses straight V7 system calls and nothing else and that those system calls do not change errno when they are successful, there is no reason to expect the last unsuccessful system call done by an implementation of some stdio routine to be the one which is responsible for the failure. Suppose an implementation of fopen(3s), having found that open(2) failed, tried to call stat(2) in an attempt to diagnose the error for me, and that while executing stat(2) an I/O error occurred. Then errno would be set to reflect the incomplete status of some operation I neither know nor care about, AND THAT WOULD BE LEGAL. How difficult could it be for a C implementor to ensure that the value given to errno reflected the error responsible for the failure of the stdio operation? [Strictly speaking it is impossible, but that's true of everything, not just stdio. See signal().] Quite easy: just put errno in a safe place and move it back just before returning the failure code. Yes, the actual numbers would be implementation defined, but ALL errno numbers are implementation defined. That's a great deal better than not having any errno at all. To repeat markb's comment: > Set errno to what? There is no way the C standards committee is going to > attempt to identify all OS-dependent low-level error causes and provide > standard encodings for all of them! Why not? The COBOL committee made the attempt (:-). Seriously, provided that host-specific details are accessible some other way (which might as well be host-specific itself), there aren't all that many different cases. With a little bit of mental effort, it is easy to find error classes which are not just host-independent, but aren't even tied to files as such. Here are some, with UNIX examples. E_DEADLY_PARAMETERS The parameters are so scrambled we nearly died trying to read them EFAULT (typically means wild address, e.g. 0) E_INVALID_PARAMETERS We could find the parameters, but they didn't make sense EINVAL (file name syntax error) E_NO_SUCH_OBJECT We found the parameters and they made sense but there is no such object ENOENT (missing file or directory) E_OBJECT_ALREADY_EXISTS We found the parameters and they made sense but there already is an object of that sort so you can't create one EEXIST, EADDRINUSE E_WRONG_TYPE We found the object ok, but it is not the right type of object ENOTDIR, EISDIR, ENOTTY, ESPIPE, EPROTOTYPE, ENOTSOCK, E_NOT_ALLOWED We found the object ok, but you aren't allowed to do that operation ENOPERM (no write permission), EROFS, EACCES E_BUSY_TRY_LATER We found the object ok, and you can do that, but it's busy with another caller right now. Try again later. EBUSY, ETXTBSY, EALREADY, EWOULDBLOCK, EOPNOTSUPP E_WRONG_STATE We found the object ok, and you might be able to do that, but you have the object in the wrong state just now. EISCONN, ENOTCONN, E_RESOURCE_EXCEEDED We found the object and you can do that, but you ran out of X (processes: EAGAIN, memory: ENOMEM, per process file table: EMFILE, system file table: ENFILE, link count field: EMLINK, file size: EFBIG, socket buffers: ENOBUFFS, &c) E_OPERATION_FAILED We found the object and you can do that, but something went wrong EIO, (physical I/O error, RFS locks lost, &c) ETIMEDOUT, ECONNREFUSED, ... You want more information about various errors. For example, if you can't find a file: is the device off-line, which directory is missing, or is it the file proper? But you can't pack it all into one integer, and the availability of further details would be system-specific. That doesn't mean that a coarse classification such as I'm sketched above would be any less use, or that it would be system-specific. This was something of a digression. It was NOT the job of the ANSI C committee to redesign the errno mechanism. For ANSI C, specifying that errno is set, without saying what it is set to, is the right choice. Given that the description ofhas always been incredibly vague, ANSI C's leaving it undefined whether error is set to indicate a stdio error, or some other error, or the phase of the moon, is probably the right choice too: no VALID existing program, it appears, could have depended on the setting of errno after a stdio operation, so no valid existing program will be broken by leaving it undefined. But it would be a help to new code if the stdio operations were defined to set errno on error, and it would be interesting to know whether the ANSI C committee considered doing this, and what practical obstacles they found. I used to be rather fond of C, but this error stuff is quite incredibly bad. The problem isn't really the language; it's the libraries. For a really horrible example of an under-specified library package, look up "hsearch" in the SVID or a System V manual.