From 5ca4b90d06ed5871ed0bf7bd59dbbf23b69a00ea Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Wed, 11 Nov 2009 14:22:44 -0700 Subject: [PATCH] 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 --- 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 b9f5689a1..17ccdb44e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,17 @@ 2009-11-11 Eric Blake + 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 29fc070c6..89002f2bf 100644 --- a/lib/mkfifoat.c +++ b/lib/mkfifoat.c @@ -20,38 +20,15 @@ #include -#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 -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 000000000..b5126bf8b --- /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 . */ + +/* written by Eric Blake */ + +#include + +#include + +#if !HAVE_MKNOD + +# include + +/* 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 99e2336f7..3cf041687 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 db2f0da84..2bc7e6557 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 9ff5091e4..730ac8546 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 2992ba2ef..fca3411b3 100644 --- a/tests/test-mkfifoat.c +++ b/tests/test-mkfifoat.c @@ -22,6 +22,7 @@ #include #include +#include #include #include #include @@ -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); -- 2.11.0