title: Can I test if a file descriptor is of the right type for read()?
body: <p>There are plenty of fds that can't be read from (for example, a listening socket). How do I test whether a <code>read</code>(2) on the fd will return <code>EINVAL</code>, without risking taking data out?</p>
  
  <h3>Things that don't work:</h3>
  
  <ol>
  <li><p>We could do a <code>read()</code> with a zero-byte buffer passed. This is ruled out though:</p>
  
  <blockquote>
    <p>Implementations are allowed, but not required, to perform error checking for <code>read()</code> requests of zero bytes. [From POSIX 1003.1-2008]</p>
  </blockquote></li>
  <li><p>We might be tempted to call <code>select()</code> on the descriptor. Unfortunately, <code>select()</code> has very overloaded semantics for the readable set, so will tell that an fd is "readable" when in fact it's an error to call <code>read()</code> on it (for example, a listening socket will be marked "readable" but needs <code>accept()</code>, not <code>read()</code>, and there are other non-portable examples like event or kqueue fds).</p></li>
  <li><p>(Sort of works) Read manpages for every platform you compile on test the fd with specific system calls to produce a function that looks roughly like:</p>
  
  <pre><code>int isReadable(int fd)
  { return isActiveSocket(fd) || isFifo(fd) || isRegFile(fd) ||
             isEventFd(fd) || ... /* more pain */ }
  </code></pre></li>
  <li><p>(Sort of works) Note that <code>read()</code> itself doesn't necessarily give you a nice answer as to whether the fd was the right type for the system call! Surprisingly, <code>EINVAL</code> is unspecified in POSIX for <code>read()</code> (except on STREAMS), but is given to you on linux ("EINVAL: fd is attached to an object which is unsuitable for reading") and rather mysteriously on BSD ("EINVAL: The pointer associated with [the fd] was negative.").</p></li>
  </ol>
  
  <h3>Scenarios</h3>
  
  <p>Someone launches your application, and you want to know whether the fd with value 0 is bogus (eg a listening socket) or whether it's ever going to possible to read from it. You'd like to do without trying an actual <code>read()</code> a) because that blocks, b) because after taking the data out you can't stuff it back in.</p>