]> Savannah Git Hosting - gnulib.git/commitdiff
getumask: New module.
authorBruno Haible <bruno@clisp.org>
Sat, 4 Jul 2020 16:14:46 +0000 (18:14 +0200)
committerBruno Haible <bruno@clisp.org>
Sat, 4 Jul 2020 16:14:46 +0000 (18:14 +0200)
* 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
doc/glibc-functions/getumask.texi [new file with mode: 0644]
doc/gnulib.texi
lib/getumask.c [new file with mode: 0644]
lib/sys_stat.in.h
m4/getumask.m4 [new file with mode: 0644]
m4/sys_stat_h.m4
modules/getumask [new file with mode: 0644]
modules/sys_stat
tests/test-sys_stat-c++.cc

index 15f5dd0ff8a123a1876197e5303cff22e261fa2d..fb1b853cae677c1794fd43c5f882675dc9503a27 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,19 @@
+2020-07-04  Bruno Haible  <bruno@clisp.org>
+
+       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  <bruno@clisp.org>
 
        clean-temp: Add support for temporary files with given mode.
diff --git a/doc/glibc-functions/getumask.texi b/doc/glibc-functions/getumask.texi
new file mode 100644 (file)
index 0000000..2fbf9e3
--- /dev/null
@@ -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
index ec6e633290db616db55713e54775d09e6910c88e..812e7d063ff71270c05a64b9dc110df585f16da1 100644 (file)
@@ -6119,10 +6119,12 @@ This list of functions is sorted according to the header that declares them.
 @section Glibc Extensions to @code{<sys/stat.h>}
 
 @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 (file)
index 0000000..6168ef6
--- /dev/null
@@ -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 <https://www.gnu.org/licenses/>.  */
+
+/* Written by Bruno Haible <bruno@clisp.org>, 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 <config.h>
+/* 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 <sys/stat.h>
+
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#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
+}
index dc8881e6f67eeae35b4d459941c98cdb9c40fd0d..c1618a6597cb80b13e456731f376ed2839f0c706 100644 (file)
@@ -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 (file)
index 0000000..f8b526d
--- /dev/null
@@ -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 <sys/stat.h> 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],
+[
+  :
+])
index 3efba5a7b98632322343871b91e3bfddbe71a6ae..929144d155b10337345a6e05544a831db8d6802d 100644 (file)
@@ -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 <sys/stat.h>
-    ]], [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 (file)
index 0000000..9f19a0e
--- /dev/null
@@ -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:
+<sys/stat.h>
+
+License:
+GPL
+
+Maintainer:
+all
index 4783c7efb80d7d2aef1b99ddce81880d748b85ef..af276abb856f9e7bf7c619175ef4703a093b6fdb 100644 (file)
@@ -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' \
index 9b2e733fe826ad37325852002ad1339356416f0d..981199bf4c178d07b68da366205510208a23cfba 100644 (file)
@@ -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