root/maint/gnulib/lib/getumask.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. getumask

   1 /* Retrieve the umask of the process (multithread-safe).
   2    Copyright (C) 2020-2021 Free Software Foundation, Inc.
   3 
   4    This program is free software: you can redistribute it and/or modify
   5    it under the terms of the GNU General Public License as published by
   6    the Free Software Foundation; either version 3 of the License, or
   7    (at your option) any later version.
   8 
   9    This program is distributed in the hope that it will be useful,
  10    but WITHOUT ANY WARRANTY; without even the implied warranty of
  11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12    GNU General Public License for more details.
  13 
  14    You should have received a copy of the GNU General Public License
  15    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
  16 
  17 /* Written by Bruno Haible <bruno@clisp.org>, 2020.  */
  18 
  19 /* There are three ways to implement a getumask() function on systems that
  20    don't have it:
  21      (a) Through system calls on the file system.
  22      (b) Through a global variable that the main() function has to set,
  23          together with an override of the umask() function.
  24      (c) Through { mode_t mask = umask (0); umask (mask); }.
  25 
  26    Each has its drawbacks:
  27      (a) Causes additional system calls. May fail in some rare cases.
  28      (b) Causes globally visible code complexity / maintainer effort.
  29      (c) Is not multithread-safe: open() calls in other threads may
  30          create files with wrong access permissions.
  31 
  32    Here we implement (a), as the least evil.  */
  33 
  34 #include <config.h>
  35 /* The package may define ASSUME_UMASK_CONSTANT to 1, to indicate that the
  36    program does not call umask().  */
  37 /* #define ASSUME_UMASK_CONSTANT 1 */
  38 
  39 /* Specification.  */
  40 #include <sys/stat.h>
  41 
  42 #include <fcntl.h>
  43 #include <stdlib.h>
  44 #include <string.h>
  45 #include <unistd.h>
  46 
  47 #include "clean-temp.h"
  48 #include "tempname.h"
  49 
  50 mode_t
  51 getumask (void)
     /* [previous][next][first][last][top][bottom][index][help] */
  52 {
  53 #if 0
  54   /* This is not multithread-safe!  */
  55   mode_t mask = umask (0);
  56   umask (mask);
  57   return mask;
  58 #else
  59 # if ASSUME_UMASK_CONSTANT
  60   static int cached_umask = -1;
  61   if (cached_umask >= 0)
  62     return cached_umask;
  63 # endif
  64 
  65   int mask = -1;
  66 # if defined __linux__
  67   {
  68     /* In Linux >= 4.7, the umask can be retrieved from an "Umask:" line in the
  69        /proc/self/status file.  */
  70     char buf[4096];
  71     int fd = open ("/proc/self/status", O_RDONLY);
  72     if (fd >= 0)
  73       {
  74         ssize_t n = read (fd, buf, sizeof (buf));
  75         if (n > 0)
  76           {
  77             const char *p_end = buf + n;
  78             const char *p = buf;
  79 
  80             for (;;)
  81               {
  82                 /* Here we're at the beginning of a line.  */
  83                 if (p_end - p > 8 && memcmp (p, "Umask:\t0", 8) == 0)
  84                   {
  85                     unsigned int value = 0;
  86                     p += 8;
  87                     for (; p < p_end && *p >= '0' && *p <= '7'; p++)
  88                       value = 8 * value + (*p - '0');
  89                     if (p < p_end && *p == '\n')
  90                       mask = value;
  91                     break;
  92                   }
  93                 /* Search the start of the next line.  */
  94                 for (; p < p_end && *p != '\n'; p++)
  95                   ;
  96                 if (p == p_end)
  97                   break;
  98                 p++;
  99               }
 100           }
 101         close (fd);
 102       }
 103   }
 104 # endif
 105   if (mask < 0)
 106     {
 107       /* Create a temporary file and inspect its access permissions.  */
 108       const char *tmpdir = getenv ("TMPDIR");
 109       if (tmpdir == NULL || *tmpdir == '\0')
 110         tmpdir = "/tmp";
 111       size_t tmpdir_length = strlen (tmpdir);
 112       char *temp_filename = (char *) malloc (tmpdir_length + 15 + 1);
 113       if (temp_filename != NULL)
 114         {
 115           memcpy (temp_filename, tmpdir, tmpdir_length);
 116           strcpy (temp_filename + tmpdir_length, "/gtumask.XXXXXX");
 117           int fd = gen_register_open_temp (temp_filename, 0, O_RDWR,
 118                                            S_IRWXU|S_IRWXG|S_IRWXO);
 119           if (fd >= 0)
 120             {
 121               struct stat statbuf;
 122               if (fstat (fd, &statbuf) >= 0)
 123                 mask = (S_IRWXU|S_IRWXG|S_IRWXO) & ~statbuf.st_mode;
 124               close_temp (fd);
 125               cleanup_temporary_file (temp_filename, false);
 126             }
 127           free (temp_filename);
 128         }
 129     }
 130   if (mask < 0)
 131     {
 132       /* We still don't know!  Assume a paranoid user.  */
 133       mask = 077;
 134     }
 135 # if ASSUME_UMASK_CONSTANT
 136   cached_umask = mask;
 137 # endif
 138   return mask;
 139 #endif
 140 }

/* [previous][next][first][last][top][bottom][index][help] */