1 /* Retrieve the umask of the process (multithread-safe).
2 Copyright (C) 2020 Free Software Foundation, Inc.
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.
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.
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/>. */
17 /* Written by Bruno Haible <bruno@clisp.org>, 2020. */
19 /* There are three ways to implement a getumask() function on systems that
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); }.
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.
32 Here we implement (a), as the least evil. */
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 */
47 #include "clean-temp.h"
54 /* This is not multithread-safe! */
55 mode_t mask
= umask (0);
59 # if ASSUME_UMASK_CONSTANT
60 static int cached_umask
= -1;
61 if (cached_umask
>= 0)
66 # if defined __linux__
68 /* In Linux >= 4.7, the umask can be retrieved from an "Umask:" line in the
69 /proc/self/status file. */
71 int fd
= open ("/proc/self/status", O_RDONLY
);
74 ssize_t n
= read (fd
, buf
, sizeof (buf
));
77 const char *p_end
= buf
+ n
;
82 /* Here we're at the beginning of a line. */
83 if (p_end
- p
> 8 && memcmp (p
, "Umask:\t0", 8) == 0)
85 unsigned int value
= 0;
87 for (; p
< p_end
&& *p
>= '0' && *p
<= '7'; p
++)
88 value
= 8 * value
+ (*p
- '0');
89 if (p
< p_end
&& *p
== '\n')
93 /* Search the start of the next line. */
94 for (; p
< p_end
&& *p
!= '\n'; p
++)
107 /* Create a temporary file and inspect its access permissions. */
108 const char *tmpdir
= getenv ("TMPDIR");
109 if (tmpdir
== NULL
|| *tmpdir
== '\0')
111 size_t tmpdir_length
= strlen (tmpdir
);
112 char *temp_filename
= (char *) malloc (tmpdir_length
+ 15 + 1);
113 if (temp_filename
!= NULL
)
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
);
122 if (fstat (fd
, &statbuf
) >= 0)
123 mask
= (S_IRWXU
|S_IRWXG
|S_IRWXO
) & ~statbuf
.st_mode
;
125 cleanup_temporary_file (temp_filename
, false);
127 free (temp_filename
);
132 /* We still don't know! Assume a paranoid user. */
135 # if ASSUME_UMASK_CONSTANT