changeset 12268:b537cb58d506

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 <ebb9@byu.net>
author Eric Blake <ebb9@byu.net>
date Wed, 11 Nov 2009 14:22:44 -0700
parents c400da5f66bb
children 4758cd4c9683
files ChangeLog lib/mkfifoat.c lib/mknodat.c m4/mkfifoat.m4 modules/mkfifoat modules/mkfifoat-tests tests/test-mkfifoat.c
diffstat 7 files changed, 129 insertions(+), 90 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,17 @@
 2009-11-11  Eric Blake  <ebb9@byu.net>
 
+	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.
--- 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 bug-gnulib@gnu.org.
-#endif
-
 #if !HAVE_MKFIFO
-/* Mingw lacks mkfifo and mknod, so this wrapper is trivial.  */
 
 # include <errno.h>
 
+/* Mingw lacks mkfifo, so this wrapper is trivial.  */
+
 int
 mkfifoat (int fd _UNUSED_PARAMETER_, char const *path _UNUSED_PARAMETER_,
-	  mode_t mode _UNUSED_PARAMETER_)
-{
-  errno = ENOSYS;
-  return -1;
-}
-
-int
-mknodat (int fd _UNUSED_PARAMETER_, char const *path _UNUSED_PARAMETER_,
-	 mode_t mode _UNUSED_PARAMETER_, dev_t dev _UNUSED_PARAMETER_)
+          mode_t mode _UNUSED_PARAMETER_)
 {
   errno = ENOSYS;
   return -1;
@@ -75,22 +52,4 @@
 # 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 */
new file mode 100644
--- /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 */
--- 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_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
 ])
--- a/modules/mkfifoat
+++ b/modules/mkfifoat
@@ -3,11 +3,14 @@
 
 Files:
 lib/mkfifoat.c
+lib/mknodat.c
 m4/mkfifoat.m4
 
 Depends-on:
 extensions
 fcntl-h
+mkfifo
+mknod
 openat
 sys_stat
 
--- 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:
 
--- 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 @@
   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);
+  /* Remove any leftovers from a previous partial run.  */
+  ASSERT (system ("rm -rf " BASE "*") == 0);
 
-#if !HAVE_MKFIFO
-  fputs ("skipping test: no support for named fifos\n", stderr);
-  return 77;
-#endif
+  /* 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);
 
-  /* Clean up anything from previous incomplete test.  */
-  remove (fifo);
-
-  /* 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);
+      /* Create fifo while cwd is '.', then stat it from '..'.  */
+      ASSERT (func (AT_FDCWD, BASE "fifo", 0600) == 0);
       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);
-      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);