bug-gnulib
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: 4 test failures on freebsd8-rc2


From: Eric Blake
Subject: Re: 4 test failures on freebsd8-rc2
Date: Wed, 11 Nov 2009 21:05:40 -0700
User-agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.23) Gecko/20090812 Thunderbird/2.0.0.23 Mnenhy/0.7.6.666

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

According to Eric Blake on 11/10/2009 6:51 AM:
> rm a
> mkfifo b/         => mistakenly creates a
> 
> So I've got a few more to go.  For that matter, Solaris 9 has the same
> bugs for chmod and chown, but we don't have a chmod replacement yet.

Here's what I'm applying for mkfifo/mknod; tested across OpenBSD, FreeBSD,
Solaris 9 and 10, Linux, and cygwin.

chown will be harder, since there is no test-chown already written to
start from.  I'm starting to think I will have to use getgroups to see
whether the current user has a supplementary group membership, since
that's about the only observable successful change that can be made to
pinpoint whether the right file was modified.  But that means the test
will be reduced, or even skipped, if the user only belongs to one group.
And then there's mingw to worry about, with neither getgroups nor chown.
Also, the gnulib implementation of getgroups can call exit(), so I'd like
to fix that first.

- --
Don't work too hard, make some time for fun as well!

Eric Blake             address@hidden
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.9 (Cygwin)
Comment: Public key at home.comcast.net/~ericblake/eblake.gpg
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/

iEYEARECAAYFAkr7iZMACgkQ84KuGfSFAYCtrACfezbrHTf+w6RHwcxIOyBmDdPW
gzsAn1FhTWTCaCPMNJs5YFfIOOs+m2Tv
=RUAd
-----END PGP SIGNATURE-----
>From 08166afd7322d40407cf62e3c98b97782d7d1af0 Mon Sep 17 00:00:00 2001
From: Eric Blake <address@hidden>
Date: Wed, 11 Nov 2009 13:22:04 -0700
Subject: [PATCH 1/3] mkfifo: new module

Solaris 9 mkfifo("name/",mode) mistakenly creates "name".
FreeBSD 7.2 mkfifo("dangling/",mode) mistakenly creates a fifo
at the target of "dangling".  Mingw lacks named pipes altogether,
but this at least avoids link failures.

* modules/mkfifo: New file.
* m4/mkfifo.m4 (gl_FUNC_MKFIFO): Likewise.
* lib/mkfifo.c (mkfifo): Likewise.
* m4/sys_stat_h.m4 (gl_SYS_STAT_H_DEFAULTS): Set witness
defaults.
* modules/sys_stat (Makefile.am): Substitute them.
* lib/sys_stat.in.h (mkfifo): Declare replacement.
* MODULES.html.sh (Support for systems lacking POSIX:2008):
Document it.
* doc/posix-functions/mkfifo.texi (mkfifo): Likewise.
* modules/mkfifo-tests: New test.
* tests/test-mkfifo.h (test_mkfifo): New file, borrowed in part
from test-mkfifoat.c.
* tests/test-mkfifo.c: New file.

Signed-off-by: Eric Blake <address@hidden>
---
 ChangeLog                       |   16 ++++++++
 MODULES.html.sh                 |    1 +
 doc/posix-functions/mkfifo.texi |   12 ++++--
 lib/mkfifo.c                    |   58 ++++++++++++++++++++++++++++++
 lib/sys_stat.in.h               |   17 +++++++++
 m4/mkfifo.m4                    |   45 +++++++++++++++++++++++
 m4/sys_stat_h.m4                |    5 ++-
 modules/mkfifo                  |   25 +++++++++++++
 modules/mkfifo-tests            |   13 +++++++
 modules/sys_stat                |    3 ++
 tests/test-mkfifo.c             |   53 ++++++++++++++++++++++++++++
 tests/test-mkfifo.h             |   74 +++++++++++++++++++++++++++++++++++++++
 12 files changed, 317 insertions(+), 5 deletions(-)
 create mode 100644 lib/mkfifo.c
 create mode 100644 m4/mkfifo.m4
 create mode 100644 modules/mkfifo
 create mode 100644 modules/mkfifo-tests
 create mode 100644 tests/test-mkfifo.c
 create mode 100644 tests/test-mkfifo.h

diff --git a/ChangeLog b/ChangeLog
index fbfa1e4..8965456 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,21 @@
 2009-11-11  Eric Blake  <address@hidden>

+       mkfifo: new module
+       * modules/mkfifo: New file.
+       * m4/mkfifo.m4 (gl_FUNC_MKFIFO): Likewise.
+       * lib/mkfifo.c (mkfifo): Likewise.
+       * m4/sys_stat_h.m4 (gl_SYS_STAT_H_DEFAULTS): Set witness
+       defaults.
+       * modules/sys_stat (Makefile.am): Substitute them.
+       * lib/sys_stat.in.h (mkfifo): Declare replacement.
+       * MODULES.html.sh (Support for systems lacking POSIX:2008):
+       Document it.
+       * doc/posix-functions/mkfifo.texi (mkfifo): Likewise.
+       * modules/mkfifo-tests: New test.
+       * tests/test-mkfifo.h (test_mkfifo): New file, borrowed in part
+       from test-mkfifoat.c.
+       * tests/test-mkfifo.c: New file.
+
        readlink: detect FreeBSD bug
        * m4/readlink.m4 (gl_FUNC_READLINK): Also detect FreeBSD bug with
        slash on symlink.
diff --git a/MODULES.html.sh b/MODULES.html.sh
index 717e1ae..a1e3ace 100755
--- a/MODULES.html.sh
+++ b/MODULES.html.sh
@@ -2287,6 +2287,7 @@ func_all_modules ()
   func_module mbsnrtowcs
   func_module mkdir
   func_module mkdtemp
+  func_module mkfifo
   func_module mkstemp
   func_module netdb
   func_module netinet_in
diff --git a/doc/posix-functions/mkfifo.texi b/doc/posix-functions/mkfifo.texi
index 926f57d..ea872b1 100644
--- a/doc/posix-functions/mkfifo.texi
+++ b/doc/posix-functions/mkfifo.texi
@@ -4,15 +4,19 @@ mkfifo

 POSIX specification: 
@url{http://www.opengroup.org/onlinepubs/9699919799/functions/mkfifo.html}

-Gnulib module: ---
+Gnulib module: mkfifo

 Portability problems fixed by Gnulib:
 @itemize
address@hidden
+This function mishandles trailing slash on some platforms:
+FreeBSD 7.2, Solaris 9.
address@hidden
+This function is missing on some platforms; however, the replacement
+always fails with @code{ENOSYS}:
+mingw.
 @end itemize

 Portability problems not fixed by Gnulib:
 @itemize
address@hidden
-This function is missing on some platforms:
-mingw.
 @end itemize
diff --git a/lib/mkfifo.c b/lib/mkfifo.c
new file mode 100644
index 0000000..3c29e8f
--- /dev/null
+++ b/lib/mkfifo.c
@@ -0,0 +1,58 @@
+/* Create a named fifo.
+   Copyright (C) 2009 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 3 of the License, 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, see <http://www.gnu.org/licenses/>.  */
+
+/* written by Eric Blake */
+
+#include <config.h>
+
+#include <sys/stat.h>
+
+#include <errno.h>
+#include <string.h>
+
+#if !HAVE_MKFIFO
+/* Mingw lacks mkfifo; always fail with ENOSYS.  */
+
+int
+mkfifo (char const *name _UNUSED_PARAMETER_, mode_t mode _UNUSED_PARAMETER_)
+{
+  errno = ENOSYS;
+  return -1;
+}
+
+#else /* HAVE_MKFIFO */
+
+# undef mkfifo
+
+/* Create a named fifo FILE, with access permissions in MODE.  Work
+around trailing slash bugs.  */
+
+int
+rpl_mkfifo (char const *name, mode_t mode)
+{
+# if MKFIFO_TRAILING_SLASH_BUG
+  size_t len = strlen (name);
+  if (len && name[len - 1] == '/')
+    {
+      struct stat st;
+      if (stat (name, &st) == 0)
+        errno = EEXIST;
+      return -1;
+    }
+# endif
+  return mkfifo (name, mode);
+}
+#endif /* HAVE_MKFIFO */
diff --git a/lib/sys_stat.in.h b/lib/sys_stat.in.h
index 1e46da8..4ff2ff6 100644
--- a/lib/sys_stat.in.h
+++ b/lib/sys_stat.in.h
@@ -424,6 +424,23 @@ extern int mkdirat (int fd, char const *file, mode_t mode);
 #endif


+#if @GNULIB_MKFIFO@
+# if @REPLACE_MKFIFO@
+#  undef mkfifo
+#  define mkfifo rpl_mkfifo
+# endif
+# if address@hidden@ || @REPLACE_MKFIFO@
+int mkfifo (char const *file, mode_t mode);
+# endif
+#elif defined GNULIB_POSIXCHECK
+# undef mkfifo
+# define mkfifo(n,m)                                                    \
+    (GL_LINK_WARNING ("mkfifo is not portable - "                       \
+                      "use gnulib module mkfifo for portability"),      \
+     mkfifo (n, m))
+#endif
+
+
 #if @GNULIB_MKFIFOAT@
 # if address@hidden@
 int mkfifoat (int fd, char const *file, mode_t mode);
diff --git a/m4/mkfifo.m4 b/m4/mkfifo.m4
new file mode 100644
index 0000000..fc8044e
--- /dev/null
+++ b/m4/mkfifo.m4
@@ -0,0 +1,45 @@
+# serial 1
+# See if we need to provide mkfifo replacement.
+
+dnl Copyright (C) 2009 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+# Written by Eric Blake.
+
+AC_DEFUN([gl_FUNC_MKFIFO],
+[
+  AC_REQUIRE([gl_SYS_STAT_H_DEFAULTS])
+  AC_CHECK_FUNCS_ONCE([mkfifo])
+  if test $ac_cv_func_mkfifo = no; then
+    HAVE_MKFIFO=0
+    AC_LIBOBJ([mkfifo])
+  else
+    dnl Check for Solaris 9 and FreeBSD bug with trailing slash.
+    AC_CHECK_FUNCS_ONCE([lstat])
+    AC_CACHE_CHECK([whether mkfifo rejects trailing slashes],
+      [gl_cv_func_mkfifo_works],
+      [# Assume that if we have lstat, we can also check symlinks.
+       if test $ac_cv_func_lstat = yes; then
+         ln -s conftest.tmp conftest.lnk
+       fi
+       AC_RUN_IFELSE(
+         [AC_LANG_PROGRAM(
+           [[#include <sys/stat.h>
+]], [[if (!mkfifo ("conftest.tmp/", 0600)) return 1;
+#if HAVE_LSTAT
+      if (!mkfifo ("conftest.lnk/", 0600)) return 2;
+#endif
+           ]])],
+         [gl_cv_func_mkfifo_works=yes], [gl_cv_func_mkfifo_works=no],
+         [gl_cv_func_mkfifo_works="guessing no"])
+       rm -f conftest.tmp conftest.lnk])
+    if test "$gl_cv_func_mkfifo_works" != yes; then
+      AC_DEFINE([MKFIFO_TRAILING_SLASH_BUG], [1], [Define to 1 if mkfifo
+        does not reject trailing slash])
+      REPLACE_MKFIFO=1
+      AC_LIBOBJ([mkfifo])
+    fi
+  fi
+])
diff --git a/m4/sys_stat_h.m4 b/m4/sys_stat_h.m4
index 1edf548..e864866 100644
--- a/m4/sys_stat_h.m4
+++ b/m4/sys_stat_h.m4
@@ -1,4 +1,4 @@
-# sys_stat_h.m4 serial 19   -*- Autoconf -*-
+# sys_stat_h.m4 serial 20   -*- Autoconf -*-
 dnl Copyright (C) 2006-2009 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -45,6 +45,7 @@ AC_DEFUN([gl_SYS_STAT_H_DEFAULTS],
   GNULIB_LCHMOD=0;      AC_SUBST([GNULIB_LCHMOD])
   GNULIB_LSTAT=0;       AC_SUBST([GNULIB_LSTAT])
   GNULIB_MKDIRAT=0;     AC_SUBST([GNULIB_MKDIRAT])
+  GNULIB_MKFIFO=0;      AC_SUBST([GNULIB_MKFIFO])
   GNULIB_MKFIFOAT=0;    AC_SUBST([GNULIB_MKFIFOAT])
   GNULIB_MKNODAT=0;     AC_SUBST([GNULIB_MKNODAT])
   GNULIB_STAT=0;        AC_SUBST([GNULIB_STAT])
@@ -56,6 +57,7 @@ AC_DEFUN([gl_SYS_STAT_H_DEFAULTS],
   HAVE_LCHMOD=1;        AC_SUBST([HAVE_LCHMOD])
   HAVE_LSTAT=1;         AC_SUBST([HAVE_LSTAT])
   HAVE_MKDIRAT=1;       AC_SUBST([HAVE_MKDIRAT])
+  HAVE_MKFIFO=1;        AC_SUBST([HAVE_MKFIFO])
   HAVE_MKFIFOAT=1;      AC_SUBST([HAVE_MKFIFOAT])
   HAVE_MKNODAT=1;       AC_SUBST([HAVE_MKNODAT])
   HAVE_UTIMENSAT=1;     AC_SUBST([HAVE_UTIMENSAT])
@@ -64,6 +66,7 @@ AC_DEFUN([gl_SYS_STAT_H_DEFAULTS],
   REPLACE_FUTIMENS=0;   AC_SUBST([REPLACE_FUTIMENS])
   REPLACE_LSTAT=0;      AC_SUBST([REPLACE_LSTAT])
   REPLACE_MKDIR=0;      AC_SUBST([REPLACE_MKDIR])
+  REPLACE_MKFIFO=0;     AC_SUBST([REPLACE_MKFIFO])
   REPLACE_STAT=0;       AC_SUBST([REPLACE_STAT])
   REPLACE_UTIMENSAT=0;  AC_SUBST([REPLACE_UTIMENSAT])
 ])
diff --git a/modules/mkfifo b/modules/mkfifo
new file mode 100644
index 0000000..ce7af63
--- /dev/null
+++ b/modules/mkfifo
@@ -0,0 +1,25 @@
+Description:
+mkfifo(): create named FIFO
+
+Files:
+lib/mkfifo.c
+m4/mkfifo.m4
+
+Depends-on:
+stat
+sys_stat
+
+configure.ac:
+gl_FUNC_MKFIFO
+gl_UNISTD_MODULE_INDICATOR([mkfifo])
+
+Makefile.am:
+
+Include:
+<sys/stat.h>
+
+License:
+LGPL
+
+Maintainer:
+Eric Blake
diff --git a/modules/mkfifo-tests b/modules/mkfifo-tests
new file mode 100644
index 0000000..87d6ce2
--- /dev/null
+++ b/modules/mkfifo-tests
@@ -0,0 +1,13 @@
+Files:
+tests/test-mkfifo.h
+tests/test-mkfifo.c
+
+Depends-on:
+stdbool
+symlink
+
+configure.ac:
+
+Makefile.am:
+TESTS += test-mkfifo
+check_PROGRAMS += test-mkfifo
diff --git a/modules/sys_stat b/modules/sys_stat
index 246011f..d51078e 100644
--- a/modules/sys_stat
+++ b/modules/sys_stat
@@ -33,6 +33,7 @@ sys/stat.h: sys_stat.in.h
              -e 's|@''GNULIB_LCHMOD''@|$(GNULIB_LCHMOD)|g' \
              -e 's|@''GNULIB_LSTAT''@|$(GNULIB_LSTAT)|g' \
              -e 's|@''GNULIB_MKDIRAT''@|$(GNULIB_MKDIRAT)|g' \
+             -e 's|@''GNULIB_MKFIFO''@|$(GNULIB_MKFIFO)|g' \
              -e 's|@''GNULIB_MKFIFOAT''@|$(GNULIB_MKFIFOAT)|g' \
              -e 's|@''GNULIB_MKNODAT''@|$(GNULIB_MKNODAT)|g' \
              -e 's|@''GNULIB_STAT''@|$(GNULIB_STAT)|g' \
@@ -43,6 +44,7 @@ sys/stat.h: sys_stat.in.h
              -e 's|@''HAVE_LCHMOD''@|$(HAVE_LCHMOD)|g' \
              -e 's|@''HAVE_LSTAT''@|$(HAVE_LSTAT)|g' \
              -e 's|@''HAVE_MKDIRAT''@|$(HAVE_MKDIRAT)|g' \
+             -e 's|@''HAVE_MKFIFO''@|$(HAVE_MKFIFO)|g' \
              -e 's|@''HAVE_MKFIFOAT''@|$(HAVE_MKFIFOAT)|g' \
              -e 's|@''HAVE_MKNODAT''@|$(HAVE_MKNODAT)|g' \
              -e 's|@''HAVE_UTIMENSAT''@|$(HAVE_UTIMENSAT)|g' \
@@ -51,6 +53,7 @@ sys/stat.h: sys_stat.in.h
              -e 's|@''REPLACE_FUTIMENS''@|$(REPLACE_FUTIMENS)|g' \
              -e 's|@''REPLACE_LSTAT''@|$(REPLACE_LSTAT)|g' \
              -e 's|@''REPLACE_MKDIR''@|$(REPLACE_MKDIR)|g' \
+             -e 's|@''REPLACE_MKFIFO''@|$(REPLACE_MKFIFO)|g' \
              -e 's|@''REPLACE_STAT''@|$(REPLACE_STAT)|g' \
              -e 's|@''REPLACE_UTIMENSAT''@|$(REPLACE_UTIMENSAT)|g' \
              -e '/definition of GL_LINK_WARNING/r $(LINK_WARNING_H)' \
diff --git a/tests/test-mkfifo.c b/tests/test-mkfifo.c
new file mode 100644
index 0000000..3a0336c
--- /dev/null
+++ b/tests/test-mkfifo.c
@@ -0,0 +1,53 @@
+/* Tests of mkfifo.
+   Copyright (C) 2009 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 3 of the License, 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, see <http://www.gnu.org/licenses/>.  */
+
+/* Written by Eric Blake <address@hidden>, 2009.  */
+
+#include <config.h>
+
+#include <sys/stat.h>
+
+#include <fcntl.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#define ASSERT(expr) \
+  do                                                                         \
+    {                                                                        \
+      if (!(expr))                                                           \
+        {                                                                    \
+          fprintf (stderr, "%s:%d: assertion failed\n", __FILE__, __LINE__);  \
+          fflush (stderr);                                                   \
+          abort ();                                                          \
+        }                                                                    \
+    }                                                                        \
+  while (0)
+
+#define BASE "test-mkfifo.t"
+
+#include "test-mkfifo.h"
+
+int
+main (void)
+{
+  /* Remove any leftovers from a previous partial run.  */
+  ASSERT (system ("rm -rf " BASE "*") == 0);
+
+  return test_mkfifo (mkfifo, true);
+}
diff --git a/tests/test-mkfifo.h b/tests/test-mkfifo.h
new file mode 100644
index 0000000..7ced3ce
--- /dev/null
+++ b/tests/test-mkfifo.h
@@ -0,0 +1,74 @@
+/* Tests of mkfifo and friends.
+   Copyright (C) 2009 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 3 of the License, 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, see <http://www.gnu.org/licenses/>.  */
+
+/* Written by Eric Blake <address@hidden>, 2009.  */
+
+/* This file is designed to test mkfifo(n,m), mknod(n,m|S_IFIFO,0),
+   mkfifoat(AT_FDCWD,n,m), and mknodat(AT_FDCWD,n,m|S_IFIFO,0).  FUNC
+   is the function to test.  Assumes that BASE and ASSERT are already
+   defined, and that appropriate headers are already included.  If
+   PRINT, warn before skipping symlink tests with status 77.  */
+
+static int
+test_mkfifo (int (*func) (char const *, mode_t), bool print)
+{
+  int result = func (BASE "fifo", 0600);
+  struct stat st;
+  if (result == -1 && errno == ENOSYS)
+    {
+      if (print)
+        fputs ("skipping test: no support for named fifos\n", stderr);
+      return 77;
+    }
+  ASSERT (result == 0);
+  ASSERT (stat (BASE "fifo", &st) == 0);
+  ASSERT (S_ISFIFO (st.st_mode));
+
+  /* Sanity checks of failures.  */
+  errno = 0;
+  ASSERT (func ("", S_IRUSR | S_IWUSR) == -1);
+  ASSERT (errno == ENOENT);
+  errno = 0;
+  ASSERT (func (".", 0600) == -1);
+  ASSERT (errno == EEXIST || errno == EINVAL);
+  errno = 0;
+  ASSERT (func (BASE "fifo", 0600) == -1);
+  ASSERT (errno == EEXIST);
+  ASSERT (unlink (BASE "fifo") == 0);
+  errno = 0;
+  ASSERT (func (BASE "fifo/", 0600) == -1);
+  ASSERT (errno == ENOENT || errno == ENOTDIR);
+
+  /* Test trailing slash behavior.  */
+  if (symlink (BASE "fifo", BASE "link"))
+    {
+      if (print)
+        fputs ("skipping test: symlinks not supported on this file system\n",
+               stderr);
+      return 77;
+    }
+  errno = 0;
+  ASSERT (func (BASE "link", 0600) == -1);
+  ASSERT (errno == EEXIST);
+  errno = 0;
+  ASSERT (func (BASE "link/", 0600) == -1);
+  ASSERT (errno == EEXIST || errno == ENOENT || errno == ENOTDIR);
+  errno = 0;
+  ASSERT (unlink (BASE "fifo") == -1);
+  ASSERT (errno == ENOENT);
+  ASSERT (unlink (BASE "link") == 0);
+  return 0;
+}
-- 
1.6.5.rc1


>From 599bbd22717fdd0f8d6b8a6f54b99b2a9fa7b410 Mon Sep 17 00:00:00 2001
From: Eric Blake <address@hidden>
Date: Wed, 11 Nov 2009 13:23:04 -0700
Subject: [PATCH 2/3] mknod: new module

Solaris 9 mknod("name/",mode,dev) mistakenly creates "name" for
non-directory mode.  FreeBSD 7.2 mknod("dangling/",mode,dev)
mistakenly creates the target of the symlink if run as root.
FreeBSD and OpenBSD mknod("fifo",S_IFIFO|mode,0) fails for non-root.
Use of mknod caused link failures on mingw.

* modules/mknod: New file.
* m4/mknod.m4 (gl_FUNC_MKNOD): Likewise.
* lib/mknod.c (mknod): Likewise.
* m4/sys_stat_h.m4 (gl_SYS_STAT_H_DEFAULTS): Set witness
defaults.
* modules/sys_stat (Makefile.am): Substitute them.
* lib/sys_stat.in.h (mknod): Declare replacement.
* MODULES.html.sh (Support for systems lacking POSIX:2008):
Document it.
* doc/posix-functions/mknod.texi (mknod): Likewise.
* modules/mknod-tests: New test.
* tests/test-mknod.c: Likewise.

Signed-off-by: Eric Blake <address@hidden>
---
 ChangeLog                      |   14 +++++++
 MODULES.html.sh                |    1 +
 doc/posix-functions/mknod.texi |   17 +++++++--
 lib/mknod.c                    |   74 ++++++++++++++++++++++++++++++++++++++++
 lib/sys_stat.in.h              |   17 +++++++++
 m4/mknod.m4                    |   45 ++++++++++++++++++++++++
 m4/sys_stat_h.m4               |    5 ++-
 modules/mknod                  |   26 ++++++++++++++
 modules/mknod-tests            |   13 +++++++
 modules/sys_stat               |    3 ++
 tests/test-mknod.c             |   62 +++++++++++++++++++++++++++++++++
 11 files changed, 273 insertions(+), 4 deletions(-)
 create mode 100644 lib/mknod.c
 create mode 100644 m4/mknod.m4
 create mode 100644 modules/mknod
 create mode 100644 modules/mknod-tests
 create mode 100644 tests/test-mknod.c

diff --git a/ChangeLog b/ChangeLog
index 8965456..b9f5689 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,19 @@
 2009-11-11  Eric Blake  <address@hidden>

+       mknod: new module
+       * modules/mknod: New file.
+       * m4/mknod.m4 (gl_FUNC_MKNOD): Likewise.
+       * lib/mknod.c (mknod): Likewise.
+       * m4/sys_stat_h.m4 (gl_SYS_STAT_H_DEFAULTS): Set witness
+       defaults.
+       * modules/sys_stat (Makefile.am): Substitute them.
+       * lib/sys_stat.in.h (mknod): Declare replacement.
+       * MODULES.html.sh (Support for systems lacking POSIX:2008):
+       Document it.
+       * doc/posix-functions/mknod.texi (mknod): Likewise.
+       * modules/mknod-tests: New test.
+       * tests/test-mknod.c: Likewise.
+
        mkfifo: new module
        * modules/mkfifo: New file.
        * m4/mkfifo.m4 (gl_FUNC_MKFIFO): Likewise.
diff --git a/MODULES.html.sh b/MODULES.html.sh
index a1e3ace..5738ea4 100755
--- a/MODULES.html.sh
+++ b/MODULES.html.sh
@@ -2288,6 +2288,7 @@ func_all_modules ()
   func_module mkdir
   func_module mkdtemp
   func_module mkfifo
+  func_module mknod
   func_module mkstemp
   func_module netdb
   func_module netinet_in
diff --git a/doc/posix-functions/mknod.texi b/doc/posix-functions/mknod.texi
index 2853416..99105ea 100644
--- a/doc/posix-functions/mknod.texi
+++ b/doc/posix-functions/mknod.texi
@@ -4,15 +4,26 @@ mknod

 POSIX specification: 
@url{http://www.opengroup.org/onlinepubs/9699919799/functions/mknod.html}

-Gnulib module: ---
+Gnulib module: mknod

 Portability problems fixed by Gnulib:
 @itemize
address@hidden
+This function requires super-user privileges to create a fifo:
+FreeBSD 7.2, OpenBSD 3.8.
address@hidden
+This function mishandles trailing slash on some platforms:
+FreeBSD 7.2, Solaris 9.
address@hidden
+This function is missing on some platforms; however, the replacement
+always fails with @code{ENOSYS}:
+mingw.
 @end itemize

 Portability problems not fixed by Gnulib:
 @itemize
 @item
-This function is missing on some platforms:
-mingw.
+Use of this function for anything except fifos is not portable,
+generally requiring super-user privileges and knowledge of supported
+device numbers.
 @end itemize
diff --git a/lib/mknod.c b/lib/mknod.c
new file mode 100644
index 0000000..662f5f8
--- /dev/null
+++ b/lib/mknod.c
@@ -0,0 +1,74 @@
+/* Create a device inode.
+   Copyright (C) 2009 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 3 of the License, 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, see <http://www.gnu.org/licenses/>.  */
+
+/* written by Eric Blake */
+
+#include <config.h>
+
+#include <sys/stat.h>
+
+#include <errno.h>
+#include <string.h>
+
+#if !HAVE_MKNOD
+/* Mingw lacks mknod; always fail with ENOSYS.  */
+
+int
+mknod (char const *name _UNUSED_PARAMETER_, mode_t mode _UNUSED_PARAMETER_,
+       dev_t dev _UNUSED_PARAMETER_)
+{
+  errno = ENOSYS;
+  return -1;
+}
+
+#else /* HAVE_MKNOD */
+
+# undef mknod
+
+/* Create a file system node FILE, with access permissions and file
+   type in MODE, and device type in DEV.  Usually, non-root
+   applications can only create named fifos (mode includes S_IFIFO),
+   with DEV set to 0.  Also work around trailing slash bugs.  */
+
+int
+rpl_mknod (char const *name, mode_t mode, dev_t dev)
+{
+# if MKFIFO_TRAILING_SLASH_BUG
+  /* Trailing slash only makes sense for directories.  Of course,
+     using mknod to create a directory is not very portable, so it may
+     still fail later on.  */
+  if (!S_ISDIR (mode))
+    {
+      size_t len = strlen (name);
+      if (len && name[len - 1] == '/')
+        {
+          struct stat st;
+          if (stat (name, &st) == 0)
+            errno = EEXIST;
+          return -1;
+        }
+    }
+# endif
+# if MKNOD_FIFO_BUG
+  /* POSIX requires mknod to create fifos for non-privileged
+     processes, but BSD implementations fail with EPERM.  */
+  if (S_ISFIFO (mode) && dev == 0)
+    return mkfifo (name, mode & ~S_IFIFO);
+# endif
+  return mknod (name, mode, dev);
+}
+
+#endif /* HAVE_MKNOD */
diff --git a/lib/sys_stat.in.h b/lib/sys_stat.in.h
index 4ff2ff6..4c66448 100644
--- a/lib/sys_stat.in.h
+++ b/lib/sys_stat.in.h
@@ -454,6 +454,23 @@ int mkfifoat (int fd, char const *file, mode_t mode);
 #endif


+#if @GNULIB_MKNOD@
+# if @REPLACE_MKNOD@
+#  undef mknod
+#  define mknod rpl_mknod
+# endif
+# if address@hidden@ || @REPLACE_MKNOD@
+int mknod (char const *file, mode_t mode, dev_t dev);
+# endif
+#elif defined GNULIB_POSIXCHECK
+# undef mknod
+# define mknod(n,m,d)                                                   \
+    (GL_LINK_WARNING ("mknod is not portable - "                        \
+                      "use gnulib module mknod for portability"),       \
+     mknod (n, m, d))
+#endif
+
+
 #if @GNULIB_MKNODAT@
 # if address@hidden@
 int mknodat (int fd, char const *file, mode_t mode, dev_t dev);
diff --git a/m4/mknod.m4 b/m4/mknod.m4
new file mode 100644
index 0000000..c2496dc
--- /dev/null
+++ b/m4/mknod.m4
@@ -0,0 +1,45 @@
+# serial 1
+# See if we need to provide mknod replacement.
+
+dnl Copyright (C) 2009 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+# Written by Eric Blake.
+
+AC_DEFUN([gl_FUNC_MKNOD],
+[
+  AC_REQUIRE([gl_SYS_STAT_H_DEFAULTS])
+  AC_REQUIRE([gl_FUNC_MKFIFO])
+  AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS])
+  AC_CHECK_FUNCS_ONCE([mknod])
+  if test $ac_cv_func_mknod = no; then
+    HAVE_MKNOD=0
+    AC_LIBOBJ([mknod])
+  else
+    dnl Detect BSD bug, where mknod requires root privileges to create fifo.
+    AC_CACHE_CHECK([whether mknod can create fifo without root privileges],
+      [gl_cv_func_mknod_works],
+      [AC_RUN_IFELSE(
+         [AC_LANG_PROGRAM(
+           [[#include <sys/stat.h>
+             #include <unistd.h>
+]], [[/* Indeterminate for super-user, assume no.  Why are you running
+         configure as root, anyway?  */
+      if (!geteuid ()) return 1;
+      if (mknod ("conftest.fifo", S_IFIFO | 0600, 0)) return 2;]])],
+         [gl_cv_func_mknod_works=yes], [gl_cv_func_mknod_works=no],
+         [gl_cv_func_mknod_works="guessing no"])
+       rm -f conftest.fifo])
+    if test "$gl_cv_func_mknod_works" != yes; then
+      AC_DEFINE([MKNOD_FIFO_BUG], [1], [Define to 1 if mknod cannot create
+        a fifo without super-user privileges])
+    fi
+    dnl Systems that mishandle trailing slash on mkfifo also goof on mknod.
+    if test $REPLACE_MKFIFO = 1 || test "$gl_cv_func_mknod_works" != yes; then
+      REPLACE_MKNOD=1
+      AC_LIBOBJ([mknod])
+    fi
+  fi
+])
diff --git a/m4/sys_stat_h.m4 b/m4/sys_stat_h.m4
index e864866..838cf48 100644
--- a/m4/sys_stat_h.m4
+++ b/m4/sys_stat_h.m4
@@ -1,4 +1,4 @@
-# sys_stat_h.m4 serial 20   -*- Autoconf -*-
+# sys_stat_h.m4 serial 21   -*- Autoconf -*-
 dnl Copyright (C) 2006-2009 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -47,6 +47,7 @@ AC_DEFUN([gl_SYS_STAT_H_DEFAULTS],
   GNULIB_MKDIRAT=0;     AC_SUBST([GNULIB_MKDIRAT])
   GNULIB_MKFIFO=0;      AC_SUBST([GNULIB_MKFIFO])
   GNULIB_MKFIFOAT=0;    AC_SUBST([GNULIB_MKFIFOAT])
+  GNULIB_MKNOD=0;       AC_SUBST([GNULIB_MKNOD])
   GNULIB_MKNODAT=0;     AC_SUBST([GNULIB_MKNODAT])
   GNULIB_STAT=0;        AC_SUBST([GNULIB_STAT])
   GNULIB_UTIMENSAT=0;   AC_SUBST([GNULIB_UTIMENSAT])
@@ -59,6 +60,7 @@ AC_DEFUN([gl_SYS_STAT_H_DEFAULTS],
   HAVE_MKDIRAT=1;       AC_SUBST([HAVE_MKDIRAT])
   HAVE_MKFIFO=1;        AC_SUBST([HAVE_MKFIFO])
   HAVE_MKFIFOAT=1;      AC_SUBST([HAVE_MKFIFOAT])
+  HAVE_MKNOD=1;         AC_SUBST([HAVE_MKNOD])
   HAVE_MKNODAT=1;       AC_SUBST([HAVE_MKNODAT])
   HAVE_UTIMENSAT=1;     AC_SUBST([HAVE_UTIMENSAT])
   REPLACE_FSTAT=0;      AC_SUBST([REPLACE_FSTAT])
@@ -67,6 +69,7 @@ AC_DEFUN([gl_SYS_STAT_H_DEFAULTS],
   REPLACE_LSTAT=0;      AC_SUBST([REPLACE_LSTAT])
   REPLACE_MKDIR=0;      AC_SUBST([REPLACE_MKDIR])
   REPLACE_MKFIFO=0;     AC_SUBST([REPLACE_MKFIFO])
+  REPLACE_MKNOD=0;      AC_SUBST([REPLACE_MKNOD])
   REPLACE_STAT=0;       AC_SUBST([REPLACE_STAT])
   REPLACE_UTIMENSAT=0;  AC_SUBST([REPLACE_UTIMENSAT])
 ])
diff --git a/modules/mknod b/modules/mknod
new file mode 100644
index 0000000..62ddeca
--- /dev/null
+++ b/modules/mknod
@@ -0,0 +1,26 @@
+Description:
+mknod(): create various special devices
+
+Files:
+lib/mknod.c
+m4/mknod.m4
+
+Depends-on:
+mkfifo
+stat
+sys_stat
+
+configure.ac:
+gl_FUNC_MKNOD
+gl_UNISTD_MODULE_INDICATOR([mknod])
+
+Makefile.am:
+
+Include:
+<sys/stat.h>
+
+License:
+LGPL
+
+Maintainer:
+Eric Blake
diff --git a/modules/mknod-tests b/modules/mknod-tests
new file mode 100644
index 0000000..9ee4445
--- /dev/null
+++ b/modules/mknod-tests
@@ -0,0 +1,13 @@
+Files:
+tests/test-mkfifo.h
+tests/test-mknod.c
+
+Depends-on:
+stdbool
+symlink
+
+configure.ac:
+
+Makefile.am:
+TESTS += test-mknod
+check_PROGRAMS += test-mknod
diff --git a/modules/sys_stat b/modules/sys_stat
index d51078e..20a8c83 100644
--- a/modules/sys_stat
+++ b/modules/sys_stat
@@ -35,6 +35,7 @@ sys/stat.h: sys_stat.in.h
              -e 's|@''GNULIB_MKDIRAT''@|$(GNULIB_MKDIRAT)|g' \
              -e 's|@''GNULIB_MKFIFO''@|$(GNULIB_MKFIFO)|g' \
              -e 's|@''GNULIB_MKFIFOAT''@|$(GNULIB_MKFIFOAT)|g' \
+             -e 's|@''GNULIB_MKNOD''@|$(GNULIB_MKNOD)|g' \
              -e 's|@''GNULIB_MKNODAT''@|$(GNULIB_MKNODAT)|g' \
              -e 's|@''GNULIB_STAT''@|$(GNULIB_STAT)|g' \
              -e 's|@''GNULIB_UTIMENSAT''@|$(GNULIB_UTIMENSAT)|g' \
@@ -46,6 +47,7 @@ sys/stat.h: sys_stat.in.h
              -e 's|@''HAVE_MKDIRAT''@|$(HAVE_MKDIRAT)|g' \
              -e 's|@''HAVE_MKFIFO''@|$(HAVE_MKFIFO)|g' \
              -e 's|@''HAVE_MKFIFOAT''@|$(HAVE_MKFIFOAT)|g' \
+             -e 's|@''HAVE_MKNOD''@|$(HAVE_MKNOD)|g' \
              -e 's|@''HAVE_MKNODAT''@|$(HAVE_MKNODAT)|g' \
              -e 's|@''HAVE_UTIMENSAT''@|$(HAVE_UTIMENSAT)|g' \
              -e 's|@''REPLACE_FSTAT''@|$(REPLACE_FSTAT)|g' \
@@ -54,6 +56,7 @@ sys/stat.h: sys_stat.in.h
              -e 's|@''REPLACE_LSTAT''@|$(REPLACE_LSTAT)|g' \
              -e 's|@''REPLACE_MKDIR''@|$(REPLACE_MKDIR)|g' \
              -e 's|@''REPLACE_MKFIFO''@|$(REPLACE_MKFIFO)|g' \
+             -e 's|@''REPLACE_MKNOD''@|$(REPLACE_MKNOD)|g' \
              -e 's|@''REPLACE_STAT''@|$(REPLACE_STAT)|g' \
              -e 's|@''REPLACE_UTIMENSAT''@|$(REPLACE_UTIMENSAT)|g' \
              -e '/definition of GL_LINK_WARNING/r $(LINK_WARNING_H)' \
diff --git a/tests/test-mknod.c b/tests/test-mknod.c
new file mode 100644
index 0000000..2e30883
--- /dev/null
+++ b/tests/test-mknod.c
@@ -0,0 +1,62 @@
+/* Tests of mknod.
+   Copyright (C) 2009 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 3 of the License, 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, see <http://www.gnu.org/licenses/>.  */
+
+/* Written by Eric Blake <address@hidden>, 2009.  */
+
+#include <config.h>
+
+#include <sys/stat.h>
+
+#include <fcntl.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#define ASSERT(expr) \
+  do                                                                         \
+    {                                                                        \
+      if (!(expr))                                                           \
+        {                                                                    \
+          fprintf (stderr, "%s:%d: assertion failed\n", __FILE__, __LINE__);  \
+          fflush (stderr);                                                   \
+          abort ();                                                          \
+        }                                                                    \
+    }                                                                        \
+  while (0)
+
+#define BASE "test-mknod.t"
+
+#include "test-mkfifo.h"
+
+/* Wrapper around mknod, to create fifos.  */
+static int
+do_mknod (char const *name, mode_t mode)
+{
+  return mknod (name, mode | S_IFIFO, 0);
+}
+
+int
+main (void)
+{
+  /* Remove any leftovers from a previous partial run.  */
+  ASSERT (system ("rm -rf " BASE "*") == 0);
+
+  /* We can only portably test creation of fifos.  Anything else
+     requires root privileges and knowledge of device numbers.  */
+  return test_mkfifo (do_mknod, true);
+}
-- 
1.6.5.rc1


>From 5ca4b90d06ed5871ed0bf7bd59dbbf23b69a00ea Mon Sep 17 00:00:00 2001
From: Eric Blake <address@hidden>
Date: Wed, 11 Nov 2009 14:22:44 -0700
Subject: [PATCH 3/3] mkfifoat: use new modules for Solaris and BSD bugs

Pick up Solaris 9 and BSD fixes to mkfifo and mknod.  No known
system has mknodat but broken mknod, so there is no need for
rpl_mkfifoat or rpl_mknodat.  Split mknodat into its own file.

* m4/mkfifoat.m4 (gl_FUNC_MKFIFOAT): Simplify.
* lib/mkfifoat.c (mknodat): Split...
* lib/mknodat.c (mknodat): ...into new file.
* modules/mkfifoat (Files): Ship new file.
(Depends-on): Add mkfifo, mknod.
* modules/mkfifoat-tests (Files): Reuse mkfifo tests.
(Depends-on): Add symlink.
* tests/test-mkfifoat.c (main): Enhance test.  Drop portions now
redundant with test_mkfifo.h.
(do_mkfifoat, do_mknodat): New helpers.

Signed-off-by: Eric Blake <address@hidden>
---
 ChangeLog              |   12 ++++++
 lib/mkfifoat.c         |   47 ++-----------------------
 lib/mknodat.c          |   57 ++++++++++++++++++++++++++++++
 m4/mkfifoat.m4         |    5 ++-
 modules/mkfifoat       |    3 ++
 modules/mkfifoat-tests |    2 +
 tests/test-mkfifoat.c  |   91 +++++++++++++++++++++++++----------------------
 7 files changed, 128 insertions(+), 89 deletions(-)
 create mode 100644 lib/mknodat.c

diff --git a/ChangeLog b/ChangeLog
index b9f5689..17ccdb4 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,17 @@
 2009-11-11  Eric Blake  <address@hidden>

+       mkfifoat: use new modules for Solaris and BSD bugs
+       * m4/mkfifoat.m4 (gl_FUNC_MKFIFOAT): Simplify.
+       * lib/mkfifoat.c (mknodat): Split...
+       * lib/mknodat.c (mknodat): ...into new file.
+       * modules/mkfifoat (Files): Ship new file.
+       (Depends-on): Add mkfifo, mknod.
+       * modules/mkfifoat-tests (Files): Reuse mkfifo tests.
+       (Depends-on): Add symlink.
+       * tests/test-mkfifoat.c (main): Enhance test.  Drop portions now
+       redundant with test_mkfifo.h.
+       (do_mkfifoat, do_mknodat): New helpers.
+
        mknod: new module
        * modules/mknod: New file.
        * m4/mknod.m4 (gl_FUNC_MKNOD): Likewise.
diff --git a/lib/mkfifoat.c b/lib/mkfifoat.c
index 29fc070..89002f2 100644
--- a/lib/mkfifoat.c
+++ b/lib/mkfifoat.c
@@ -20,38 +20,15 @@

 #include <sys/stat.h>

-#ifndef HAVE_MKFIFO
-# define HAVE_MKFIFO 0
-#endif
-#ifndef HAVE_MKNOD
-# define HAVE_MKNOD 0
-#endif
-
-/* For now, all known systems either have both mkfifo and mknod, or
-   neither.  If this is not true, we can implement the portable
-   aspects of one using the other (POSIX only requires mknod to create
-   fifos; all other uses of mknod are for root users and outside the
-   realm of POSIX).  */
-#if HAVE_MKNOD != HAVE_MKFIFO
-# error Please report this message and your system to address@hidden
-#endif
-
 #if !HAVE_MKFIFO
-/* Mingw lacks mkfifo and mknod, so this wrapper is trivial.  */

 # include <errno.h>

-int
-mkfifoat (int fd _UNUSED_PARAMETER_, char const *path _UNUSED_PARAMETER_,
-         mode_t mode _UNUSED_PARAMETER_)
-{
-  errno = ENOSYS;
-  return -1;
-}
+/* Mingw lacks mkfifo, so this wrapper is trivial.  */

 int
-mknodat (int fd _UNUSED_PARAMETER_, char const *path _UNUSED_PARAMETER_,
-        mode_t mode _UNUSED_PARAMETER_, dev_t dev _UNUSED_PARAMETER_)
+mkfifoat (int fd _UNUSED_PARAMETER_, char const *path _UNUSED_PARAMETER_,
+          mode_t mode _UNUSED_PARAMETER_)
 {
   errno = ENOSYS;
   return -1;
@@ -75,22 +52,4 @@ mknodat (int fd _UNUSED_PARAMETER_, char const *path 
_UNUSED_PARAMETER_,
 # undef AT_FUNC_POST_FILE_PARAM_DECLS
 # undef AT_FUNC_POST_FILE_ARGS

-/* Create a file system node FILE relative to directory FD, with
-   access permissions and file type in MODE, and device type in DEV.
-   Usually, non-root applications can only create named fifos, with
-   DEV set to 0.  If possible, create the node without changing the
-   working directory.  Otherwise, resort to using save_cwd/fchdir,
-   then mknod/restore_cwd.  If either the save_cwd or the restore_cwd
-   fails, then give a diagnostic and exit nonzero.  */
-
-# define AT_FUNC_NAME mknodat
-# define AT_FUNC_F1 mknod
-# define AT_FUNC_POST_FILE_PARAM_DECLS , mode_t mode, dev_t dev
-# define AT_FUNC_POST_FILE_ARGS        , mode, dev
-# include "at-func.c"
-# undef AT_FUNC_NAME
-# undef AT_FUNC_F1
-# undef AT_FUNC_POST_FILE_PARAM_DECLS
-# undef AT_FUNC_POST_FILE_ARGS
-
 #endif /* HAVE_MKFIFO */
diff --git a/lib/mknodat.c b/lib/mknodat.c
new file mode 100644
index 0000000..b5126bf
--- /dev/null
+++ b/lib/mknodat.c
@@ -0,0 +1,57 @@
+/* Create an inode relative to an open directory.
+   Copyright (C) 2009 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 3 of the License, 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, see <http://www.gnu.org/licenses/>.  */
+
+/* written by Eric Blake */
+
+#include <config.h>
+
+#include <sys/stat.h>
+
+#if !HAVE_MKNOD
+
+# include <errno.h>
+
+/* Mingw lacks mknod, so this wrapper is trivial.  */
+
+int
+mknodat (int fd _UNUSED_PARAMETER_, char const *path _UNUSED_PARAMETER_,
+         mode_t mode _UNUSED_PARAMETER_, dev_t dev _UNUSED_PARAMETER_)
+{
+  errno = ENOSYS;
+  return -1;
+}
+
+#else /* HAVE_MKFIFO */
+
+/* Create a file system node FILE relative to directory FD, with
+   access permissions and file type in MODE, and device type in DEV.
+   Usually, non-root applications can only create named fifos, with
+   DEV set to 0.  If possible, create the node without changing the
+   working directory.  Otherwise, resort to using save_cwd/fchdir,
+   then mknod/restore_cwd.  If either the save_cwd or the restore_cwd
+   fails, then give a diagnostic and exit nonzero.  */
+
+# define AT_FUNC_NAME mknodat
+# define AT_FUNC_F1 mknod
+# define AT_FUNC_POST_FILE_PARAM_DECLS , mode_t mode, dev_t dev
+# define AT_FUNC_POST_FILE_ARGS        , mode, dev
+# include "at-func.c"
+# undef AT_FUNC_NAME
+# undef AT_FUNC_F1
+# undef AT_FUNC_POST_FILE_PARAM_DECLS
+# undef AT_FUNC_POST_FILE_ARGS
+
+#endif /* HAVE_MKFIFO */
diff --git a/m4/mkfifoat.m4 b/m4/mkfifoat.m4
index 99e2336..3cf0416 100644
--- a/m4/mkfifoat.m4
+++ b/m4/mkfifoat.m4
@@ -1,4 +1,4 @@
-# serial 1
+# serial 2
 # See if we need to provide mkfifoat/mknodat replacement.

 dnl Copyright (C) 2009 Free Software Foundation, Inc.
@@ -13,11 +13,12 @@ AC_DEFUN([gl_FUNC_MKFIFOAT],
   AC_REQUIRE([gl_SYS_STAT_H_DEFAULTS])
   AC_REQUIRE([gl_FUNC_OPENAT])
   AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS])
-  AC_CHECK_FUNCS_ONCE([mkfifo mknod mkfifoat mknodat])
+  AC_CHECK_FUNCS_ONCE([mkfifoat mknodat])
   if test $ac_cv_func_mkfifoat = no; then
     # No known system has mkfifoat but not mknodat
     HAVE_MKFIFOAT=0
     HAVE_MKNODAT=0
     AC_LIBOBJ([mkfifoat])
+    AC_LIBOBJ([mknodat])
   fi
 ])
diff --git a/modules/mkfifoat b/modules/mkfifoat
index db2f0da..2bc7e65 100644
--- a/modules/mkfifoat
+++ b/modules/mkfifoat
@@ -3,11 +3,14 @@ mkfifoat() and mknodat(): create named FIFOs relative to a 
directory

 Files:
 lib/mkfifoat.c
+lib/mknodat.c
 m4/mkfifoat.m4

 Depends-on:
 extensions
 fcntl-h
+mkfifo
+mknod
 openat
 sys_stat

diff --git a/modules/mkfifoat-tests b/modules/mkfifoat-tests
index 9ff5091..730ac85 100644
--- a/modules/mkfifoat-tests
+++ b/modules/mkfifoat-tests
@@ -1,7 +1,9 @@
 Files:
+tests/test-mkfifo.h
 tests/test-mkfifoat.c

 Depends-on:
+symlink

 configure.ac:

diff --git a/tests/test-mkfifoat.c b/tests/test-mkfifoat.c
index 2992ba2..fca3411 100644
--- a/tests/test-mkfifoat.c
+++ b/tests/test-mkfifoat.c
@@ -22,6 +22,7 @@

 #include <fcntl.h>
 #include <errno.h>
+#include <stdbool.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -31,17 +32,23 @@
   do                                                                         \
     {                                                                        \
       if (!(expr))                                                           \
-       {                                                                    \
-         fprintf (stderr, "%s:%d: assertion failed\n", __FILE__, __LINE__);  \
-         fflush (stderr);                                                   \
-         abort ();                                                          \
-       }                                                                    \
+        {                                                                    \
+          fprintf (stderr, "%s:%d: assertion failed\n", __FILE__, __LINE__);  \
+          fflush (stderr);                                                   \
+          abort ();                                                          \
+        }                                                                    \
     }                                                                        \
   while (0)

+#define BASE "test-mkfifoat.t"
+
+#include "test-mkfifo.h"
+
 typedef int (*test_func) (int, char const *, mode_t);

-/* Wrapper to make testing mknodat easier.  */
+static int dfd = AT_FDCWD;
+
+/* Wrapper to test mknodat like mkfifoat.  */
 static int
 test_mknodat (int fd, char const *name, mode_t mode)
 {
@@ -49,73 +56,71 @@ test_mknodat (int fd, char const *name, mode_t mode)
   return mknodat (fd, name, mode | S_IFIFO, 0);
 }

+/* Wrapper to test mkfifoat like mkfifo.  */
+static int
+do_mkfifoat (char const *name, mode_t mode)
+{
+  return mkfifoat (dfd, name, mode);
+}
+
+/* Wrapper to test mknodat like mkfifo.  */
+static int
+do_mknodat (char const *name, mode_t mode)
+{
+  return mknodat (dfd, name, mode | S_IFIFO, 0);
+}
+
 int
 main (void)
 {
   int i;
   test_func funcs[2] = { mkfifoat, test_mknodat };
-  const char *fifo = "test-mkfifoat.fifo";
+  int result;

-  /* Create handle for future use.  */
-  int dfd = openat (AT_FDCWD, ".", O_RDONLY);
-  ASSERT (0 <= dfd);
-
-#if !HAVE_MKFIFO
-  fputs ("skipping test: no support for named fifos\n", stderr);
-  return 77;
-#endif
+  /* Remove any leftovers from a previous partial run.  */
+  ASSERT (system ("rm -rf " BASE "*") == 0);

-  /* Clean up anything from previous incomplete test.  */
-  remove (fifo);
+  /* Basic tests.  */
+  result = test_mkfifo (do_mkfifoat, true);
+  ASSERT (test_mkfifo (do_mknodat, false) == result);
+  dfd = open (".", O_RDONLY);
+  ASSERT (0 <= dfd);
+  ASSERT (test_mkfifo (do_mkfifoat, false) == result);
+  ASSERT (test_mkfifo (do_mknodat, false) == result);

-  /* Test both functions.  */
+  /* Test directory-relative handling of both functions.  */
   for (i = 0; i < 2; i++)
     {
       struct stat st;
       test_func func = funcs[i];

-      /* Sanity checks of failures.  */
-      errno = 0;
-      ASSERT (func (AT_FDCWD, "", 0600) == -1);
-      ASSERT (errno == ENOENT);
-      errno = 0;
-      ASSERT (func (dfd, "", S_IRUSR | S_IWUSR) == -1);
-      ASSERT (errno == ENOENT);
-      errno = 0;
-      ASSERT (func (AT_FDCWD, ".", 0600) == -1);
-      /* POSIX requires EEXIST, but Solaris gives EINVAL.  */
-      ASSERT (errno == EEXIST || errno == EINVAL);
-      errno = 0;
-      ASSERT (func (dfd, ".", 0600) == -1);
-      ASSERT (errno == EEXIST || errno == EINVAL);
-
       /* Create fifo while cwd is '.', then stat it from '..'.  */
-      ASSERT (func (AT_FDCWD, fifo, 0600) == 0);
+      ASSERT (func (AT_FDCWD, BASE "fifo", 0600) == 0);
       errno = 0;
-      ASSERT (func (dfd, fifo, 0600) == -1);
+      ASSERT (func (dfd, BASE "fifo", 0600) == -1);
       ASSERT (errno == EEXIST);
       ASSERT (chdir ("..") == 0);
       errno = 0;
-      ASSERT (fstatat (AT_FDCWD, fifo, &st, 0) == -1);
+      ASSERT (fstatat (AT_FDCWD, BASE "fifo", &st, 0) == -1);
       ASSERT (errno == ENOENT);
       memset (&st, 0, sizeof st);
-      ASSERT (fstatat (dfd, fifo, &st, 0) == 0);
+      ASSERT (fstatat (dfd, BASE "fifo", &st, 0) == 0);
       ASSERT (S_ISFIFO (st.st_mode));
-      ASSERT (unlinkat (dfd, fifo, 0) == 0);
+      ASSERT (unlinkat (dfd, BASE "fifo", 0) == 0);

       /* Create fifo while cwd is '..', then stat it from '.'.  */
-      ASSERT (func (dfd, fifo, 0600) == 0);
+      ASSERT (func (dfd, BASE "fifo", 0600) == 0);
       ASSERT (fchdir (dfd) == 0);
       errno = 0;
-      ASSERT (func (AT_FDCWD, fifo, 0600) == -1);
+      ASSERT (func (AT_FDCWD, BASE "fifo", 0600) == -1);
       ASSERT (errno == EEXIST);
       memset (&st, 0, sizeof st);
-      ASSERT (fstatat (AT_FDCWD, fifo, &st, AT_SYMLINK_NOFOLLOW) == 0);
+      ASSERT (fstatat (AT_FDCWD, BASE "fifo", &st, AT_SYMLINK_NOFOLLOW) == 0);
       ASSERT (S_ISFIFO (st.st_mode));
       memset (&st, 0, sizeof st);
-      ASSERT (fstatat (dfd, fifo, &st, AT_SYMLINK_NOFOLLOW) == 0);
+      ASSERT (fstatat (dfd, BASE "fifo", &st, AT_SYMLINK_NOFOLLOW) == 0);
       ASSERT (S_ISFIFO (st.st_mode));
-      ASSERT (unlink (fifo) == 0);
+      ASSERT (unlink (BASE "fifo") == 0);
     }

   ASSERT (close (dfd) == 0);
-- 
1.6.5.rc1


reply via email to

[Prev in Thread] Current Thread [Next in Thread]