1 /*
2 * System.hpp
3 *
4 * Copyright (C) 2021 by RStudio, PBC
5 *
6 * Unless you have received this program directly from RStudio pursuant
7 * to the terms of a commercial license agreement with RStudio, then
8 * this program is licensed to you under the terms of version 3 of the
9 * GNU Affero General Public License. This program is distributed WITHOUT
10 * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
11 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
12 * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
13 *
14 */
15
16 #ifndef CORE_SYSTEM_SYSTEM_HPP
17 #define CORE_SYSTEM_SYSTEM_HPP
18
19
20 #if defined(_WIN32)
21 #include <windows.h>
22 typedef DWORD PidType;
23 #else // UNIX
24 #include <sys/types.h>
25 #include <sys/resource.h>
26
27 #include <shared_core/system/PosixSystem.hpp>
28
29 typedef pid_t PidType;
30 typedef uid_t UidType;
31 #endif
32
33 #include <string>
34 #include <vector>
35 #include <map>
36 #include <iosfwd>
37
38 #include <boost/utility.hpp>
39 #include <boost/shared_ptr.hpp>
40 #include <boost/function.hpp>
41 #include <boost/date_time.hpp>
42
43 #include <core/Log.hpp>
44 #include <shared_core/Error.hpp>
45 #include <shared_core/FilePath.hpp>
46
47 #include <core/system/Types.hpp>
48
49 namespace rstudio {
50 namespace core {
51
52 class FileInfo;
53 class FilePath;
54
55 namespace system {
56
57 // portable realPath
58 Error realPath(const FilePath& filePath, FilePath* pRealPath);
59 Error realPath(const std::string& path, FilePath* pRealPath);
60 bool realPathsEqual(const FilePath& a, const FilePath& b);
61
62 void addToSystemPath(const FilePath& path, bool prepend = false);
63
64 Error findProgramOnPath(const std::string& program,
65 core::FilePath* pProgramPath);
66
67 #ifndef _WIN32
68 Error closeAllFileDescriptors();
69 Error closeNonStdFileDescriptors();
70
71 // retrieves a list of file descriptors opened by the specified child process
72 // and sends each fd to the child via pipe so that the child can signal-safely
73 // close the fds
74 Error closeChildFileDescriptorsFrom(pid_t childPid, int pipeFd, uint32_t fdStart);
75
76 // gets the list of open fds for the current process
77 Error getOpenFds(std::vector<uint32_t>* pFds);
78
79 // gets the list of open fds for the specified process
80 Error getOpenFds(pid_t pid, std::vector<uint32_t>* pFds);
81
82 namespace signal_safe {
83
84 // thread and signal-safe version of closeNonStdFileDescriptors()
85 void closeNonStdFileDescriptors(rlim_t fdLimit);
86
87 // close file descriptors given to us by our parent process
88 // must be paired with a call to closeChildFileDescriptorsFrom in the parent
89 void closeFileDescriptorsFromParent(int pipeFd, uint32_t fdStart, rlim_t fdLimit);
90
91 int clearSignalMask();
92
93 } // namespace signal_safe
94
95 void closeStdFileDescriptors();
96 void attachStdFileDescriptorsToDevNull();
97 void setStandardStreamsToDevNull();
98
99
100 // Handles EINTR retrying and error logging. Only for use with functions
101 // that return -1 on error and set errno.
102 template <typename T>
safePosixCall(const boost::function<T ()> & func,const ErrorLocation & location)103 void safePosixCall(const boost::function<T()>& func,
104 const ErrorLocation& location)
105 {
106 Error error = posix::posixCall<T>(func, location, nullptr);
107 if (error)
108 LOG_ERROR(error);
109 }
110
111 #endif
112
113 #ifdef _WIN32
114
115 // Is 64-bit Windows?
116 bool isWin64();
117
118 // Is calling process 64-bit?
119 bool isCurrentProcessWin64();
120
121 bool isWin7OrLater();
122 Error makeFileHidden(const FilePath& path);
123 Error copyMetafileToClipboard(const FilePath& path);
124 void ensureLongPath(FilePath* pFilePath);
125 Error expandEnvironmentVariables(std::string value, std::string* pResult);
126 FilePath expandComSpec();
127
128 // close a handle then set it to NULL (so we can call this function
129 // repeatedly without failure or other side effects)
130 Error closeHandle(HANDLE* pHandle, const ErrorLocation& location);
131
132 class CloseHandleOnExitScope : boost::noncopyable
133 {
134 public:
CloseHandleOnExitScope(HANDLE * pHandle,const ErrorLocation & location)135 CloseHandleOnExitScope(HANDLE* pHandle, const ErrorLocation& location)
136 : pHandle_(pHandle), location_(location)
137 {
138 }
139
140 virtual ~CloseHandleOnExitScope();
detach()141 void detach() { pHandle_ = nullptr; }
142 private:
143 HANDLE* pHandle_;
144 ErrorLocation location_;
145 };
146
147 // set $HOME to $USERPROFILE
148 void setHomeToUserProfile(core::system::Options* pChildEnv);
149
150 // Folder for per-machine configuration data
151 FilePath systemSettingsPath(const std::string& appName, bool create);
152
153 #endif // WIN32
154
155 void initHook();
156
157 // initialization
158 Error initializeSystemLog(const std::string& programIdentity,
159 log::LogLevel logLevel,
160 bool enableConfigReload = true);
161
162 Error initializeStderrLog(const std::string& programIdentity,
163 log::LogLevel logLevel,
164 bool enableConfigReload = true);
165
166 Error initializeLog(const std::string& programIdentity,
167 log::LogLevel logLevel,
168 const FilePath& logDir,
169 bool enableConfigReload = true);
170
171 Error initializeLog(const std::string& programIdentity,
172 log::LogLevel logLevel,
173 bool enableConfigReload = true);
174
175 void initializeLogConfigReload();
176
177 // common initialization functions - do not invoke directly
178 Error initLog();
179 Error reinitLog();
180
181 void initFileLogDestination(const log::LogLevel level, const FilePath defaultLogDir);
182
183 // exit
184 int exitFailure(const Error& error, const ErrorLocation& loggedFromLocation);
185 int exitFailure(const std::string& errMsg,
186 const ErrorLocation& loggedFromLocation);
187
188 // signals
189
190 // ignore selected signals
191 Error ignoreTerminalSignals();
192 Error ignoreChildExits();
193
194 // reap children (better way to handle child exits than ignoreChildExits
195 // because it doesn't prevent system from determining exit codes)
196 Error reapChildren();
197
198
199 enum SignalType
200 {
201 SigInt,
202 SigHup,
203 SigAbrt,
204 SigSegv,
205 SigIll,
206 SigUsr1,
207 SigUsr2,
208 SigPipe,
209 SigChld,
210 SigTerm
211 };
212
213
214
215 // block all signals for a given scope
216 class SignalBlocker : boost::noncopyable
217 {
218 public:
219 SignalBlocker();
220 virtual ~SignalBlocker();
221 // COPYING: boost::noncopyable
222
223 Error block(SignalType signal);
224 Error blockAll();
225
226 private:
227 struct Impl;
228 boost::shared_ptr<Impl> pImpl_;
229 };
230
231 core::Error clearSignalMask();
232
233 core::Error handleSignal(SignalType signal, void (*handler)(int));
234 core::Error ignoreSignal(SignalType signal);
235 core::Error useDefaultSignalHandler(SignalType signal);
236
237 void sendSignalToSelf(SignalType signal);
238
239 // user info
240 std::string username();
241
242 FilePath userHomePath(std::string envOverride = std::string());
243 FilePath userSettingsPath(const FilePath& userHomeDirectory,
244 const std::string& appName,
245 bool ensureDirectory = true /* create directory */);
246 unsigned int effectiveUserId();
247 bool effectiveUserIsRoot();
248 bool currentUserIsPrivilleged(unsigned int minimumUserId);
249
250 // log
251 void log(log::LogLevel level,
252 const char* message,
253 const std::string&logSection = std::string());
254
255 void log(log::LogLevel level,
256 const std::string& message,
257 const std::string& logSection = std::string());
258
259 void log(log::LogLevel level,
260 const boost::function<std::string()>& action,
261 const std::string& logSection = std::string());
262
263 const char* logLevelToStr(log::LogLevel level);
264
265 log::LoggerType loggerType(const std::string& logSection = "");
266
267 log::LogLevel lowestLogLevel();
268
269 // filesystem
270 bool isHiddenFile(const FilePath& filePath);
271 bool isHiddenFile(const FileInfo& fileInfo);
272 bool isReadOnly(const FilePath& filePath);
273
274 // terminals
275 bool stderrIsTerminal();
276 bool stdoutIsTerminal();
277
278 // uuid
279 std::string generateUuid(bool includeDashes = true);
280 std::string generateShortenedUuid();
281
282 // process info
283
284 PidType currentProcessId();
285 std::string currentProcessPidStr();
286
287 Error executablePath(int argc, const char * argv[],
288 FilePath* pExecutablePath);
289
290 Error executablePath(const char * argv0,
291 FilePath* pExecutablePath);
292
293
294 Error installPath(const std::string& relativeToExecutable,
295 const char * argv0,
296 FilePath* pInstallationPath);
297
298 void fixupExecutablePath(FilePath* pExePath);
299
300 void abort();
301
302 Error terminateProcess(PidType pid);
303
304 struct SubprocInfo
305 {
306 PidType pid;
307 std::string exe;
308 };
309
310 // Return list of child processes, by executable filename and pid
311 std::vector<SubprocInfo> getSubprocesses(PidType pid);
312
313 // Get current-working directory of a process; returns empty FilePath
314 // if unable to determine cwd
315 FilePath currentWorkingDir(PidType pid);
316
317 struct ProcessInfo
318 {
ProcessInforstudio::core::system::ProcessInfo319 ProcessInfo() : pid(0), ppid(0), pgrp(0) {}
320 PidType pid;
321 PidType ppid;
322 PidType pgrp;
323 std::string username;
324 std::string exe;
325 std::string state;
326 std::vector<std::string> arguments;
327
328 #if !defined _WIN32 && !defined __APPLE__
329 core::Error creationTime(boost::posix_time::ptime* pCreationTime) const;
330 #endif
331 };
332
333 // simple encapsulation of parent-child relationship of processes
334 struct ProcessTreeNode
335 {
336 boost::shared_ptr<ProcessInfo> data;
337 std::vector<boost::shared_ptr<ProcessTreeNode> > children;
338 };
339
340 // process tree, indexed by pid
341 typedef std::map<PidType, boost::shared_ptr<ProcessTreeNode> > ProcessTreeT;
342
343 Error terminateChildProcesses();
344
345 void createProcessTree(const std::vector<ProcessInfo>& processes,
346 ProcessTreeT *pOutTree);
347
348 void getChildren(const boost::shared_ptr<ProcessTreeNode>& node,
349 std::vector<ProcessInfo>* pOutChildren,
350 int depth = 0);
351
352 } // namespace system
353 } // namespace core
354 } // namespace rstudio
355
356 #endif // CORE_SYSTEM_SYSTEM_HPP
357
358