From 599bbd22717fdd0f8d6b8a6f54b99b2a9fa7b410 Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Wed, 11 Nov 2009 13:23:04 -0700 Subject: [PATCH] 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 --- 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 8965456c0..b9f5689a1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,19 @@ 2009-11-11 Eric Blake + 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 a1e3acea0..5738ea4b4 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 2853416cf..99105eab0 100644 --- a/doc/posix-functions/mknod.texi +++ b/doc/posix-functions/mknod.texi @@ -4,15 +4,26 @@ 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 000000000..662f5f88e --- /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 . */ + +/* written by Eric Blake */ + +#include + +#include + +#include +#include + +#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 4ff2ff6cb..4c6644890 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 000000000..c2496dcd9 --- /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 + #include +]], [[/* 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 e86486645..838cf484e 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 000000000..62ddeca7d --- /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: + + +License: +LGPL + +Maintainer: +Eric Blake diff --git a/modules/mknod-tests b/modules/mknod-tests new file mode 100644 index 000000000..9ee444537 --- /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 d51078ebc..20a8c83bf 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 000000000..2e308833f --- /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 . */ + +/* 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-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); +} -- 2.11.0