lib/util: Standardize use of st_[acm]time ns
[samba.git] / source3 / lib / per_thread_cwd.c
1 /*
2    Unix SMB/Netbios implementation.
3
4    Copyright (C) Ralph Boehme 2019
5    Copyright (C) Stefan Metzmacher 2019
6
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 3 of the License, or
10    (at your option) any later version.
11
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with this program.  If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include "includes.h"
22 #include "system/filesys.h"
23 #include "system/threads.h"
24 #ifdef HAVE_UNSHARE_CLONE_FS
25 #include <sched.h>
26 #endif /* HAVE_UNSHARE_CLONE_FS */
27
28 static bool _per_thread_cwd_checked;
29 static bool _per_thread_cwd_supported;
30 #ifdef HAVE_UNSHARE_CLONE_FS
31 static __thread bool _per_thread_cwd_disabled;
32 static __thread bool _per_thread_cwd_activated;
33 #endif /* HAVE_UNSHARE_CLONE_FS */
34
35 /*
36  * This is the first function to be called!
37  * Typically in the main() function before
38  * any threads are created.
39  *
40  * This can be called multiple times
41  * as the result is cached the first time.
42  */
43 void per_thread_cwd_check(void)
44 {
45         if (_per_thread_cwd_checked) {
46                 return;
47         }
48
49 #ifdef HAVE_UNSHARE_CLONE_FS
50         /*
51          * While unshare(CLONE_FS) is available on
52          * Linux for ages, unshare() is also
53          * used to implement containers with various
54          * per container namespaces.
55          *
56          * It's possible that the whole unshare()
57          * is blocked in order to disallow neested
58          * containers.
59          *
60          * That's why we sadly need a runtime check
61          * for this.
62          */
63         {
64                 int res;
65
66                 res = unshare(CLONE_FS);
67                 if (res == 0) {
68                         _per_thread_cwd_supported = true;
69                 }
70         }
71
72         /*
73          * We're in the main thread, so we should disallow
74          * per_thread_cwd_activate() here.
75          */
76         _per_thread_cwd_disabled = true;
77 #endif /* HAVE_UNSHARE_CLONE_FS */
78
79         _per_thread_cwd_checked = true;
80 }
81
82 /*
83  * In order to use per_thread_cwd_supported()
84  * per_thread_cwd_check() needs to be called first!
85  * Otherwise an assert will be triggered!
86  */
87 bool per_thread_cwd_supported(void)
88 {
89         SMB_ASSERT(_per_thread_cwd_checked);
90         return _per_thread_cwd_supported;
91 }
92
93 /*
94  * In order to use per_thread_cwd_disable()
95  * should be called after any fork() in order
96  * to mark the main thread of the process,
97  * which should disallow per_thread_cwd_activate().
98  *
99  * This can be called without calling
100  * per_thread_cwd_check() first.
101  *
102  * And it can't be called after calling
103  * per_thread_cwd_activate()!
104  * Otherwise an assert will be triggered!
105  *
106  * This can be called multiple times
107  * as the result is cached the first time.
108  */
109 void per_thread_cwd_disable(void)
110 {
111 #ifdef HAVE_UNSHARE_CLONE_FS
112         SMB_ASSERT(!_per_thread_cwd_activated);
113         if (_per_thread_cwd_disabled) {
114                 return;
115         }
116         _per_thread_cwd_disabled = true;
117 #endif /* HAVE_UNSHARE_CLONE_FS */
118 }
119
120 /*
121  * In order to use per_thread_cwd_activate()
122  * per_thread_cwd_supported() needs to be checked first!
123  * Otherwise an assert will be triggered!
124  *
125  * This MUST only be called within helper threads!
126  *
127  * That means it can't be called after calling
128  * per_thread_cwd_disable()!
129  * Otherwise an assert will be triggered!
130  *
131  * This can be called multiple times
132  * as the result is cached the first time.
133  */
134 void per_thread_cwd_activate(void)
135 {
136         SMB_ASSERT(_per_thread_cwd_checked);
137         SMB_ASSERT(_per_thread_cwd_supported);
138
139 #ifdef HAVE_UNSHARE_CLONE_FS
140         if (_per_thread_cwd_activated) {
141                 return;
142         }
143
144         SMB_ASSERT(!_per_thread_cwd_disabled);
145
146         {
147                 int ret;
148                 ret = unshare(CLONE_FS);
149                 SMB_ASSERT(ret == 0);
150         }
151
152         _per_thread_cwd_activated = true;
153 #else /* not HAVE_UNSHARE_CLONE_FS */
154         smb_panic(__location__);
155 #endif /* not HAVE_UNSHARE_CLONE_FS */
156 }