From 08166afd7322d40407cf62e3c98b97782d7d1af0 Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Wed, 11 Nov 2009 13:22:04 -0700 Subject: [PATCH] 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 --- 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 fbfa1e483..8965456c0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,21 @@ 2009-11-11 Eric Blake + 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 717e1ae0a..a1e3acea0 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 926f57d70..ea872b1b3 100644 --- a/doc/posix-functions/mkfifo.texi +++ b/doc/posix-functions/mkfifo.texi @@ -4,15 +4,19 @@ POSIX specification: @url{http://www.opengroup.org/onlinepubs/9699919799/functions/mkfifo.html} -Gnulib module: --- +Gnulib module: mkfifo Portability problems fixed by Gnulib: @itemize +@item +This function mishandles trailing slash on some platforms: +FreeBSD 7.2, Solaris 9. +@item +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. @end itemize diff --git a/lib/mkfifo.c b/lib/mkfifo.c new file mode 100644 index 000000000..3c29e8f6b --- /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 . */ + +/* written by Eric Blake */ + +#include + +#include + +#include +#include + +#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 1e46da82a..4ff2ff6cb 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 !@HAVE_MKFIFO@ || @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 !@HAVE_MKFIFOAT@ 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 000000000..fc8044ea3 --- /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 +]], [[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 1edf54834..e86486645 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 000000000..ce7af63c8 --- /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: + + +License: +LGPL + +Maintainer: +Eric Blake diff --git a/modules/mkfifo-tests b/modules/mkfifo-tests new file mode 100644 index 000000000..87d6ce204 --- /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 246011f31..d51078ebc 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 000000000..3a0336c33 --- /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 . */ + +/* Written by Eric Blake , 2009. */ + +#include + +#include + +#include +#include +#include +#include +#include +#include + +#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 000000000..7ced3ce8d --- /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 . */ + +/* Written by Eric Blake , 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; +} -- 2.11.0