-----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 [email protected] -----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 <[email protected]> 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 <[email protected]> --- 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 <[email protected]> + 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 +...@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 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 !...@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 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 <[email protected]>, 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 <[email protected]>, 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 <[email protected]> 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 <[email protected]> --- 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 <[email protected]> + 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 +...@item +This function requires super-user privileges to create a fifo: +FreeBSD 7.2, OpenBSD 3.8. +...@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. +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 !...@have_mknod@ || @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 !...@have_mknodat@ 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 <[email protected]>, 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 <[email protected]> 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 <[email protected]> --- 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 <[email protected]> + 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 [email protected]. -#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
