>From 6aa22a864222eb7199a71dabb85906088ee988cc Mon Sep 17 00:00:00 2001 From: Bruno Haible Date: Sat, 4 Jul 2020 18:14:46 +0200 Subject: [PATCH 1/2] getumask: New module. * lib/sys_stat.in.h (getumask): New declaration. * lib/getumask.c: New file. * m4/getumask.m4: New file. * m4/sys_stat_h.m4 (gl_HEADER_SYS_STAT_H): Test whether getumask is declared. (gl_SYS_STAT_H_DEFAULTS): Initialize GNULIB_GETUMASK, HAVE_GETUMASK. * modules/sys_stat (Makefile.am): Substitute GNULIB_GETUMASK, HAVE_GETUMASK. * modules/getumask: New file. * tests/test-sys_stat-c++.cc (getumask): Check signature. * doc/glibc-functions/getumask.texi: New file. * doc/gnulib.texi (Glibc sys/stat.h): Include it. --- ChangeLog | 16 +++++ doc/glibc-functions/getumask.texi | 30 ++++++++ doc/gnulib.texi | 2 + lib/getumask.c | 140 ++++++++++++++++++++++++++++++++++++++ lib/sys_stat.in.h | 17 +++++ m4/getumask.m4 | 24 +++++++ m4/sys_stat_h.m4 | 8 ++- modules/getumask | 32 +++++++++ modules/sys_stat | 2 + tests/test-sys_stat-c++.cc | 4 ++ 10 files changed, 272 insertions(+), 3 deletions(-) create mode 100644 doc/glibc-functions/getumask.texi create mode 100644 lib/getumask.c create mode 100644 m4/getumask.m4 create mode 100644 modules/getumask diff --git a/ChangeLog b/ChangeLog index 15f5dd0..fb1b853 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,21 @@ 2020-07-04 Bruno Haible + getumask: New module. + * lib/sys_stat.in.h (getumask): New declaration. + * lib/getumask.c: New file. + * m4/getumask.m4: New file. + * m4/sys_stat_h.m4 (gl_HEADER_SYS_STAT_H): Test whether getumask is + declared. + (gl_SYS_STAT_H_DEFAULTS): Initialize GNULIB_GETUMASK, HAVE_GETUMASK. + * modules/sys_stat (Makefile.am): Substitute GNULIB_GETUMASK, + HAVE_GETUMASK. + * modules/getumask: New file. + * tests/test-sys_stat-c++.cc (getumask): Check signature. + * doc/glibc-functions/getumask.texi: New file. + * doc/gnulib.texi (Glibc sys/stat.h): Include it. + +2020-07-04 Bruno Haible + clean-temp: Add support for temporary files with given mode. * lib/clean-temp.h (gen_register_open_temp): Add mode argument. * lib/clean-temp.c (struct try_create_file_params): New type. diff --git a/doc/glibc-functions/getumask.texi b/doc/glibc-functions/getumask.texi new file mode 100644 index 0000000..2fbf9e3 --- /dev/null +++ b/doc/glibc-functions/getumask.texi @@ -0,0 +1,30 @@ +@node getumask +@subsection @code{getumask} +@findex getumask + +Documentation: +@itemize +@item +@ifinfo +@ref{Setting Permissions,,Assigning File Permissions,libc}, +@end ifinfo +@ifnotinfo +@url{https://www.gnu.org/software/libc/manual/html_node/Setting-Permissions.html}, +@end ifnotinfo +@item +@uref{https://www.kernel.org/doc/man-pages/online/pages/man3/getumask.3.html,,man getumask}. +@end itemize + +Gnulib module: getumask + +Portability problems fixed by Gnulib: +@itemize +@item +This function exists only on Hurd and is therefore +missing on all non-glibc platforms: +glibc/Linux, glibc/kFreeBSD, Mac OS X 10.13, FreeBSD 12.0, NetBSD 9.0, OpenBSD 6.7, Minix 3.3, AIX 7.2, HP-UX 11, IRIX 6.5, Solaris 11.4, Cygwin, mingw, MSVC 14, Android 9.0. +@end itemize + +Portability problems not fixed by Gnulib: +@itemize +@end itemize diff --git a/doc/gnulib.texi b/doc/gnulib.texi index ec6e633..812e7d0 100644 --- a/doc/gnulib.texi +++ b/doc/gnulib.texi @@ -6119,10 +6119,12 @@ This list of functions is sorted according to the header that declares them. @section Glibc Extensions to @code{} @menu +* getumask:: * lchmod:: * statx:: @end menu +@include glibc-functions/getumask.texi @include glibc-functions/lchmod.texi @include glibc-functions/statx.texi diff --git a/lib/getumask.c b/lib/getumask.c new file mode 100644 index 0000000..6168ef6 --- /dev/null +++ b/lib/getumask.c @@ -0,0 +1,140 @@ +/* Retrieve the umask of the process (multithread-safe). + Copyright (C) 2020 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 Bruno Haible , 2020. */ + +/* There are three ways to implement a getumask() function on systems that + don't have it: + (a) Through system calls on the file system. + (b) Through a global variable that the main() function has to set, + together with an override of the umask() function. + (c) Through { mode_t mask = umask (0); umask (mask); }. + + Each has its drawbacks: + (a) Causes additional system calls. May fail in some rare cases. + (b) Causes globally visible code complexity / maintainer effort. + (c) Is not multithread-safe: open() calls in other threads may + create files with wrong access permissions. + + Here we implement (a), as the least evil. */ + +#include +/* The package may define ASSUME_UMASK_CONSTANT to 1, to indicate that the + program does not call umask(). */ +/* #define ASSUME_UMASK_CONSTANT 1 */ + +/* Specification. */ +#include + +#include +#include +#include +#include + +#include "clean-temp.h" +#include "tempname.h" + +mode_t +getumask (void) +{ +#if 0 + /* This is not multithread-safe! */ + mode_t mask = umask (0); + umask (mask); + return mask; +#else +# if ASSUME_UMASK_CONSTANT + static int cached_umask = -1; + if (cached_umask >= 0) + return cached_umask; +# endif + + int mask = -1; +# if defined __linux__ + { + /* In Linux >= 4.7, the umask can be retrieved from an "Umask:" line in the + /proc/self/status file. */ + char buf[4096]; + int fd = open ("/proc/self/status", O_RDONLY); + if (fd >= 0) + { + ssize_t n = read (fd, buf, sizeof (buf)); + if (n > 0) + { + const char *p_end = buf + n; + const char *p = buf; + + for (;;) + { + /* Here we're at the beginning of a line. */ + if (p_end - p > 8 && memcmp (p, "Umask:\t0", 8) == 0) + { + unsigned int value = 0; + p += 8; + for (; p < p_end && *p >= '0' && *p <= '7'; p++) + value = 8 * value + (*p - '0'); + if (p < p_end && *p == '\n') + mask = value; + break; + } + /* Search the start of the next line. */ + for (; p < p_end && *p != '\n'; p++) + ; + if (p == p_end) + break; + p++; + } + } + close (fd); + } + } +# endif + if (mask < 0) + { + /* Create a temporary file and inspect its access permissions. */ + const char *tmpdir = getenv ("TMPDIR"); + if (tmpdir == NULL || *tmpdir == '\0') + tmpdir = "/tmp"; + size_t tmpdir_length = strlen (tmpdir); + char *temp_filename = (char *) malloc (tmpdir_length + 15 + 1); + if (temp_filename != NULL) + { + memcpy (temp_filename, tmpdir, tmpdir_length); + strcpy (temp_filename + tmpdir_length, "/gtumask.XXXXXX"); + int fd = gen_register_open_temp (temp_filename, 0, O_RDWR, + S_IRWXU|S_IRWXG|S_IRWXO); + if (fd >= 0) + { + struct stat statbuf; + if (fstat (fd, &statbuf) >= 0) + mask = (S_IRWXU|S_IRWXG|S_IRWXO) & ~statbuf.st_mode; + close_temp (fd); + cleanup_temporary_file (temp_filename, false); + } + free (temp_filename); + } + } + if (mask < 0) + { + /* We still don't know! Assume a paranoid user. */ + mask = 077; + } +# if ASSUME_UMASK_CONSTANT + cached_umask = mask; +# endif + return mask; +#endif +} diff --git a/lib/sys_stat.in.h b/lib/sys_stat.in.h index dc8881e..c1618a6 100644 --- a/lib/sys_stat.in.h +++ b/lib/sys_stat.in.h @@ -515,6 +515,23 @@ _GL_WARN_ON_USE (futimens, "futimens is not portable - " #endif +#if @GNULIB_GETUMASK@ +# if !@HAVE_GETUMASK@ +_GL_FUNCDECL_SYS (getumask, mode_t, (void)); +# endif +_GL_CXXALIAS_SYS (getumask, mode_t, (void)); +# if @HAVE_GETUMASK@ +_GL_CXXALIASWARN (getumask); +# endif +#elif defined GNULIB_POSIXCHECK +# undef getumask +# if HAVE_RAW_DECL_GETUMASK +_GL_WARN_ON_USE (getumask, "getumask is not portable - " + "use gnulib module getumask for portability"); +# endif +#endif + + #if @GNULIB_LCHMOD@ /* Change the mode of FILENAME to MODE, without dereferencing it if FILENAME denotes a symbolic link. */ diff --git a/m4/getumask.m4 b/m4/getumask.m4 new file mode 100644 index 0000000..f8b526d --- /dev/null +++ b/m4/getumask.m4 @@ -0,0 +1,24 @@ +# getumask.m4 serial 1 +dnl Copyright 2020 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. + +AC_DEFUN([gl_FUNC_GETUMASK], +[ + AC_REQUIRE([gl_SYS_STAT_H_DEFAULTS]) + + dnl Persuade glibc to declare getumask(). + AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS]) + + AC_CHECK_FUNCS_ONCE([getumask]) + if test $ac_cv_func_getumask = no; then + HAVE_GETUMASK=0 + fi +]) + +# Prerequisites of lib/getumask.c. +AC_DEFUN([gl_PREREQ_GETUMASK], +[ + : +]) diff --git a/m4/sys_stat_h.m4 b/m4/sys_stat_h.m4 index 3efba5a..929144d 100644 --- a/m4/sys_stat_h.m4 +++ b/m4/sys_stat_h.m4 @@ -1,4 +1,4 @@ -# sys_stat_h.m4 serial 33 -*- Autoconf -*- +# sys_stat_h.m4 serial 34 -*- Autoconf -*- dnl Copyright (C) 2006-2020 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, @@ -46,8 +46,8 @@ AC_DEFUN([gl_HEADER_SYS_STAT_H], dnl Check for declarations of anything we want to poison if the dnl corresponding gnulib module is not in use. gl_WARN_ON_USE_PREPARE([[#include - ]], [fchmodat fstat fstatat futimens lchmod lstat mkdirat mkfifo mkfifoat - mknod mknodat stat utimensat]) + ]], [fchmodat fstat fstatat futimens getumask lchmod lstat + mkdirat mkfifo mkfifoat mknod mknodat stat utimensat]) AC_REQUIRE([AC_C_RESTRICT]) ]) @@ -68,6 +68,7 @@ AC_DEFUN([gl_SYS_STAT_H_DEFAULTS], GNULIB_FSTAT=0; AC_SUBST([GNULIB_FSTAT]) GNULIB_FSTATAT=0; AC_SUBST([GNULIB_FSTATAT]) GNULIB_FUTIMENS=0; AC_SUBST([GNULIB_FUTIMENS]) + GNULIB_GETUMASK=0; AC_SUBST([GNULIB_GETUMASK]) GNULIB_LCHMOD=0; AC_SUBST([GNULIB_LCHMOD]) GNULIB_LSTAT=0; AC_SUBST([GNULIB_LSTAT]) GNULIB_MKDIRAT=0; AC_SUBST([GNULIB_MKDIRAT]) @@ -82,6 +83,7 @@ AC_DEFUN([gl_SYS_STAT_H_DEFAULTS], HAVE_FCHMODAT=1; AC_SUBST([HAVE_FCHMODAT]) HAVE_FSTATAT=1; AC_SUBST([HAVE_FSTATAT]) HAVE_FUTIMENS=1; AC_SUBST([HAVE_FUTIMENS]) + HAVE_GETUMASK=1; AC_SUBST([HAVE_GETUMASK]) HAVE_LCHMOD=1; AC_SUBST([HAVE_LCHMOD]) HAVE_LSTAT=1; AC_SUBST([HAVE_LSTAT]) HAVE_MKDIRAT=1; AC_SUBST([HAVE_MKDIRAT]) diff --git a/modules/getumask b/modules/getumask new file mode 100644 index 0000000..9f19a0e --- /dev/null +++ b/modules/getumask @@ -0,0 +1,32 @@ +Description: +getumask() function: retrieve the umask of the process (multithread-safe) + +Files: +lib/getumask.c +m4/getumask.m4 + +Depends-on: +sys_stat +extensions +unistd [test $HAVE_GETUMASK = 0] +clean-temp [test $HAVE_GETUMASK = 0] +tempname [test $HAVE_GETUMASK = 0] + +configure.ac: +gl_FUNC_GETUMASK +if test $HAVE_GETUMASK = 0; then + AC_LIBOBJ([getumask]) + gl_PREREQ_GETUMASK +fi +gl_SYS_STAT_MODULE_INDICATOR([getumask]) + +Makefile.am: + +Include: + + +License: +GPL + +Maintainer: +all diff --git a/modules/sys_stat b/modules/sys_stat index 4783c7e..af276ab 100644 --- a/modules/sys_stat +++ b/modules/sys_stat @@ -38,6 +38,7 @@ sys/stat.h: sys_stat.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNU -e 's/@''GNULIB_FSTAT''@/$(GNULIB_FSTAT)/g' \ -e 's/@''GNULIB_FSTATAT''@/$(GNULIB_FSTATAT)/g' \ -e 's/@''GNULIB_FUTIMENS''@/$(GNULIB_FUTIMENS)/g' \ + -e 's/@''GNULIB_GETUMASK''@/$(GNULIB_GETUMASK)/g' \ -e 's/@''GNULIB_LCHMOD''@/$(GNULIB_LCHMOD)/g' \ -e 's/@''GNULIB_LSTAT''@/$(GNULIB_LSTAT)/g' \ -e 's/@''GNULIB_MKDIRAT''@/$(GNULIB_MKDIRAT)/g' \ @@ -51,6 +52,7 @@ sys/stat.h: sys_stat.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNU -e 's|@''HAVE_FCHMODAT''@|$(HAVE_FCHMODAT)|g' \ -e 's|@''HAVE_FSTATAT''@|$(HAVE_FSTATAT)|g' \ -e 's|@''HAVE_FUTIMENS''@|$(HAVE_FUTIMENS)|g' \ + -e 's|@''HAVE_GETUMASK''@|$(HAVE_GETUMASK)|g' \ -e 's|@''HAVE_LCHMOD''@|$(HAVE_LCHMOD)|g' \ -e 's|@''HAVE_LSTAT''@|$(HAVE_LSTAT)|g' \ -e 's|@''HAVE_MKDIRAT''@|$(HAVE_MKDIRAT)|g' \ diff --git a/tests/test-sys_stat-c++.cc b/tests/test-sys_stat-c++.cc index 9b2e733..981199b 100644 --- a/tests/test-sys_stat-c++.cc +++ b/tests/test-sys_stat-c++.cc @@ -43,6 +43,10 @@ SIGNATURE_CHECK (GNULIB_NAMESPACE::futimens, int, (int, struct timespec const[2])); #endif +#if GNULIB_TEST_GETUMASK +SIGNATURE_CHECK (GNULIB_NAMESPACE::getumask, mode_t, (void)); +#endif + #if GNULIB_TEST_LCHMOD SIGNATURE_CHECK (GNULIB_NAMESPACE::lchmod, int, (const char *, mode_t)); #endif -- 2.7.4