S_ISCHR, S_ISFIFO, O_NONBLOCK, O_NOCTTY

Zack Weinberg zack@rabi.columbia.edu
Sun Feb 7 10:29:00 GMT 1999


On Sat, 6 Feb 1999 13:16:18 -0800, "Melissa O'Neill" wrote:
>Zack wrote:
>> Well, even if NEXTSTEP has S_IFIFO, we can't rely on all 4.x (x<4)
>> derivatives to have it.  So we do need to detect sockets some other
>> way.
>
>Right...
>
>> I've appended a partial patch to do the detection.  It has portability
>> problems.  One is easy: we need an S_ISSOCK() default definition in
>> system.h now.  Could you please add that to your patch?  If there is no
>> S_IFSOCK, don't define it at all (note the conditionals in my patch).
>> Also, I've assumed that if S_ISSOCK or S_IFSOCK is available in
>> <sys/stat.h> then fstat() on a socket will use those values.
>
>I don't think that is a correct assumption.  I think in a BSD 4.2 system,
>stat on a Unix domain socket in the filesystem will set S_ISSOCK, but
>fstat on a file descriptor will fail. Remember that `BUGS' line I quoted
>from my NEXTSTEP system. While it doesn't appear to apply any more, I'd
>guess that it used to apply in BSD 4.2 (and earlier?).  The quote was:
>
>    BUGS
>	  Applying fstat to a socket (and thus to a pipe) returns a
>	  zeroed buffer, except for the blocksize field, and a unique
>	  device and inode number.

I misunderstood this to meean that the problem affected stat() also,
and that there was no S_IFSOCK.

>I'd probably just use something like:
>
>      else if (S_ISFIFO (st.st_mode)
>    #ifdef S_ISSOCK
>		|| S_ISSOCK (st.st_mode)
>    #endif
>    #ifdef SOCKET_FSTAT_BUG
>    		|| (st.st_mode == 0 && st.st_size == 0 && st.st_nlink == 0)
>		  /* socket/pipe in BSD 4.x (x < 4) */
>    #endif
>		|| (S_ISCHR (st.st_mode) && isatty (fd)))
[...]
>I think either of the above is probably a better solution than trying
>to use shutdown, given what you said about shutdown's not being in some
>early BSDs.  (Of course, how you'd get to set SOCKET_FSTAT_BUG is an
>exercise for the reader.)

Mmm.  Yes, shutdown is more trouble than it's worth.  SOCKET_FSTAT_BUG
could only be detected with an AC_TRY_RUN autoconf test which causes
problems when cross-compiling, so we don't want to do that.  I don't
see any harm in putting the test in all the time, this isn't
performance critical and st.st_mode will never be zero on non-buggy
systems.

We still have a problem with detecting pipes on systems that are so
old that we have neither sockets nor named pipes.  This is not worth
worrying about until someone complains.  It's possible that the BSD
bug is because V7 derivatives put zero in st.st_mode for fstat() of a
pipe, and therefore we won't have a problem at all.

Your definition of S_ISSOCK is fine.  Appended is my cppfiles.c patch,
modified as discussed above and with more comments, since this is
confusing.

Dave, have you committed her patch?  I'm starting to get confused as
to what's in and what's not.

zw

===================================================================
Index: cppfiles.c
--- cppfiles.c	1999/02/06 07:38:49	1.13
+++ cppfiles.c	1999/02/07 18:27:48
@@ -683,11 +683,27 @@
 
   fp = CPP_BUFFER (pfile);
 
+  /* If fd points to a plain file, we know how big it is, so we can
+     allocate the buffer all at once.  If fd is a pipe or terminal, we
+     can't.  Most C source files are 4k or less, so we guess that.  If
+     fd is something weird, like a block device or a directory, we
+     don't want to read it at all.
+
+     Unfortunately, different systems use different st.st_mode values
+     for pipes: some have S_ISFIFO, some S_ISSOCK, some are buggy and
+     zero the entire struct stat except a couple fields.  Hence the
+     mess below.
+
+     In all cases, read_and_prescan will resize the buffer if it
+     turns out there's more data than we thought.  */
+
   if (S_ISREG (st.st_mode))
     {
       /* off_t might have a wider range than size_t - in other words,
 	 the max size of a file might be bigger than the address
-	 space, and we need to detect that now. */
+	 space.  We can't handle a file that large.  (Anyone with
+         a single source file bigger than 4GB needs to rethink
+	 their coding style.)  */
       st_size = (size_t) st.st_size;
       if ((unsigned HOST_WIDE_INT) st_size
 	  != (unsigned HOST_WIDE_INT) st.st_size)
@@ -696,7 +712,11 @@
 	  goto fail;
 	}
     }
-  else if (S_ISFIFO (st.st_mode) || (S_ISCHR (st.st_mode) && isatty (fd)))
+  else if (S_ISFIFO (st.st_mode) || S_ISSOCK (st.st_mode)
+	   /* Some 4.x (x<4) derivatives have a bug that makes fstat()
+	      of a socket or pipe return an all-zero stat struct. */
+	   || (st.st_mode == 0 && st.st_nlink == 0 && st.st_size == 0)
+	   || (S_ISCHR (st.st_mode) && isatty (fd)))
     {
       /* Cannot get its file size before reading.  4k is a decent
          first guess. */


More information about the Gcc-patches mailing list