diff lib/isapipe.c @ 7233:ec85aace506a

* modules/isapipe: New file. * MODULES.html.sh (File descriptor based Input/Output): Add isapipe. * lib/isapipe.c, lib/isapipe.h, m4/isapipe.m4: New files.
author Paul Eggert <eggert@cs.ucla.edu>
date Tue, 29 Aug 2006 20:32:07 +0000
parents
children c05b41ab8e3b
line wrap: on
line diff
new file mode 100644
--- /dev/null
+++ b/lib/isapipe.c
@@ -0,0 +1,98 @@
+/* Test whether a file descriptor is a pipe.
+
+   Copyright (C) 2006 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software Foundation,
+   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
+
+/* Written by Paul Eggert.  */
+
+#include <config.h>
+
+#include "isapipe.h"
+
+#include <errno.h>
+#include <stdbool.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include "stat-macros.h"
+
+/* Whether pipes are FIFOs; -1 if not known.  */
+#ifndef HAVE_FIFO_PIPES
+# define HAVE_FIFO_PIPES (-1)
+#endif
+
+/* The maximum link count for pipes; (nlink_t) -1 if not known.  */
+#ifndef PIPE_LINK_COUNT_MAX
+# define PIPE_LINK_COUNT_MAX ((nlink_t) (-1))
+#endif
+
+/* Return 1 if FD is a pipe, 0 if not, -1 (setting errno) on error.
+
+   Test fairly strictly whether FD is a pipe.  lseek and checking for
+   ESPIPE does not suffice, since many non-pipe files cause lseek to
+   fail with errno == ESPIPE.  */
+
+int
+isapipe (int fd)
+{
+  nlink_t pipe_link_count_max = PIPE_LINK_COUNT_MAX;
+  bool check_for_fifo = (HAVE_FIFO_PIPES == 1);
+  struct stat st;
+  int fstat_result = fstat (fd, &st);
+
+  if (fstat_result != 0)
+    return fstat_result;
+
+  /* We want something that succeeds only for pipes, but on
+     POSIX-conforming hosts S_ISFIFO succeeds for both FIFOs and pipes
+     and we know of no portable, reliable way to distinguish them in
+     general.  However, in practice pipes always have a link count <=
+     PIPE_LINK_COUNT_MAX (unless someone attaches them to the file
+     system name space using fattach, in which case they're not really
+     pipes any more), so test for that as well.
+
+     On Darwin 7.7, pipes are sockets, so check for those instead.  */
+
+  if (! ((HAVE_FIFO_PIPES == 0 || HAVE_FIFO_PIPES == 1)
+	 && PIPE_LINK_COUNT_MAX != (nlink_t) -1)
+      && (S_ISFIFO (st.st_mode) | S_ISSOCK (st.st_mode)))
+    {
+      int fd[2];
+      int pipe_result = pipe (fd);
+      if (pipe_result != 0)
+	return pipe_result;
+      else
+	{
+	  struct stat pipe_st;
+	  int fstat_pipe_result = fstat (fd[0], &pipe_st);
+	  int fstat_pipe_errno = errno;
+	  close (fd[0]);
+	  close (fd[1]);
+	  if (fstat_pipe_result != 0)
+	    {
+	      errno = fstat_pipe_errno;
+	      return fstat_pipe_result;
+	    }
+	  check_for_fifo = (S_ISFIFO (pipe_st.st_mode) != 0);
+	  pipe_link_count_max = pipe_st.st_nlink;
+	}
+    }
+
+  return
+    (st.st_nlink <= pipe_link_count_max
+     && (check_for_fifo ? S_ISFIFO (st.st_mode) : S_ISSOCK (st.st_mode)));
+}