1 | //===- Unix/Process.cpp - Unix Process Implementation --------- -*- C++ -*-===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | // |
9 | // This file provides the generic Unix implementation of the Process class. |
10 | // |
11 | //===----------------------------------------------------------------------===// |
12 | |
13 | #include "Unix.h" |
14 | #include "llvm/ADT/Hashing.h" |
15 | #include "llvm/ADT/StringRef.h" |
16 | #include "llvm/Config/config.h" |
17 | #include <mutex> |
18 | #include <optional> |
19 | #if HAVE_FCNTL_H |
20 | #include <fcntl.h> |
21 | #endif |
22 | #ifdef HAVE_SYS_TIME_H |
23 | #include <sys/time.h> |
24 | #endif |
25 | #ifdef HAVE_SYS_RESOURCE_H |
26 | #include <sys/resource.h> |
27 | #endif |
28 | #ifdef HAVE_SYS_STAT_H |
29 | #include <sys/stat.h> |
30 | #endif |
31 | #if HAVE_SIGNAL_H |
32 | #include <signal.h> |
33 | #endif |
34 | #if defined(HAVE_MALLINFO) || defined(HAVE_MALLINFO2) |
35 | #include <malloc.h> |
36 | #endif |
37 | #if defined(HAVE_MALLCTL) |
38 | #include <malloc_np.h> |
39 | #endif |
40 | #ifdef HAVE_MALLOC_MALLOC_H |
41 | #include <malloc/malloc.h> |
42 | #endif |
43 | #ifdef HAVE_SYS_IOCTL_H |
44 | #include <sys/ioctl.h> |
45 | #endif |
46 | #ifdef HAVE_TERMIOS_H |
47 | #include <termios.h> |
48 | #endif |
49 | |
50 | //===----------------------------------------------------------------------===// |
51 | //=== WARNING: Implementation here must contain only generic UNIX code that |
52 | //=== is guaranteed to work on *all* UNIX variants. |
53 | //===----------------------------------------------------------------------===// |
54 | |
55 | using namespace llvm; |
56 | using namespace sys; |
57 | |
58 | static std::pair<std::chrono::microseconds, std::chrono::microseconds> |
59 | getRUsageTimes() { |
60 | #if defined(HAVE_GETRUSAGE) |
61 | struct rusage RU; |
62 | ::getrusage(RUSAGE_SELF, usage: &RU); |
63 | return {toDuration(TV: RU.ru_utime), toDuration(TV: RU.ru_stime)}; |
64 | #else |
65 | #ifndef __MVS__ // Exclude for MVS in case -pedantic is used |
66 | #warning Cannot get usage times on this platform |
67 | #endif |
68 | return {std::chrono::microseconds::zero(), std::chrono::microseconds::zero()}; |
69 | #endif |
70 | } |
71 | |
72 | Process::Pid Process::getProcessId() { |
73 | static_assert(sizeof(Pid) >= sizeof(pid_t), |
74 | "Process::Pid should be big enough to store pid_t" ); |
75 | return Pid(::getpid()); |
76 | } |
77 | |
78 | // On Cygwin, getpagesize() returns 64k(AllocationGranularity) and |
79 | // offset in mmap(3) should be aligned to the AllocationGranularity. |
80 | Expected<unsigned> Process::getPageSize() { |
81 | #if defined(HAVE_GETPAGESIZE) |
82 | static const int page_size = ::getpagesize(); |
83 | #elif defined(HAVE_SYSCONF) |
84 | static long page_size = ::sysconf(_SC_PAGE_SIZE); |
85 | #else |
86 | #error Cannot get the page size on this machine |
87 | #endif |
88 | if (page_size == -1) |
89 | return errorCodeToError(EC: errnoAsErrorCode()); |
90 | |
91 | return static_cast<unsigned>(page_size); |
92 | } |
93 | |
94 | size_t Process::GetMallocUsage() { |
95 | #if defined(HAVE_MALLINFO2) |
96 | struct mallinfo2 mi; |
97 | mi = ::mallinfo2(); |
98 | return mi.uordblks; |
99 | #elif defined(HAVE_MALLINFO) |
100 | struct mallinfo mi; |
101 | mi = ::mallinfo(); |
102 | return mi.uordblks; |
103 | #elif defined(HAVE_MALLOC_ZONE_STATISTICS) && defined(HAVE_MALLOC_MALLOC_H) |
104 | malloc_statistics_t Stats; |
105 | malloc_zone_statistics(malloc_default_zone(), &Stats); |
106 | return Stats.size_in_use; // darwin |
107 | #elif defined(HAVE_MALLCTL) |
108 | size_t alloc, sz; |
109 | sz = sizeof(size_t); |
110 | if (mallctl("stats.allocated" , &alloc, &sz, NULL, 0) == 0) |
111 | return alloc; |
112 | return 0; |
113 | #elif defined(HAVE_SBRK) |
114 | // Note this is only an approximation and more closely resembles |
115 | // the value returned by mallinfo in the arena field. |
116 | static char *StartOfMemory = reinterpret_cast<char *>(::sbrk(0)); |
117 | char *EndOfMemory = (char *)sbrk(0); |
118 | if (EndOfMemory != ((char *)-1) && StartOfMemory != ((char *)-1)) |
119 | return EndOfMemory - StartOfMemory; |
120 | return 0; |
121 | #else |
122 | #ifndef __MVS__ // Exclude for MVS in case -pedantic is used |
123 | #warning Cannot get malloc info on this platform |
124 | #endif |
125 | return 0; |
126 | #endif |
127 | } |
128 | |
129 | void Process::GetTimeUsage(TimePoint<> &elapsed, |
130 | std::chrono::nanoseconds &user_time, |
131 | std::chrono::nanoseconds &sys_time) { |
132 | elapsed = std::chrono::system_clock::now(); |
133 | std::tie(args&: user_time, args&: sys_time) = getRUsageTimes(); |
134 | } |
135 | |
136 | #if defined(HAVE_MACH_MACH_H) && !defined(__GNU__) |
137 | #include <mach/mach.h> |
138 | #endif |
139 | |
140 | // Some LLVM programs such as bugpoint produce core files as a normal part of |
141 | // their operation. To prevent the disk from filling up, this function |
142 | // does what's necessary to prevent their generation. |
143 | void Process::PreventCoreFiles() { |
144 | #if HAVE_SETRLIMIT |
145 | struct rlimit rlim; |
146 | getrlimit(RLIMIT_CORE, rlimits: &rlim); |
147 | #ifdef __linux__ |
148 | // On Linux, if the kernel.core_pattern sysctl starts with a '|' (i.e. it |
149 | // is being piped to a coredump handler such as systemd-coredumpd), the |
150 | // kernel ignores RLIMIT_CORE (since we aren't creating a file in the file |
151 | // system) except for the magic value of 1, which disables coredumps when |
152 | // piping. 1 byte is too small for any kind of valid core dump, so it |
153 | // also disables coredumps if kernel.core_pattern creates files directly. |
154 | // While most piped coredump handlers do respect the crashing processes' |
155 | // RLIMIT_CORE, this is notable not the case for Debian's systemd-coredump |
156 | // due to a local patch that changes sysctl.d/50-coredump.conf to ignore |
157 | // the specified limit and instead use RLIM_INFINITY. |
158 | // |
159 | // The alternative to using RLIMIT_CORE=1 would be to use prctl() with the |
160 | // PR_SET_DUMPABLE flag, however that also prevents ptrace(), so makes it |
161 | // impossible to attach a debugger. |
162 | rlim.rlim_cur = std::min<rlim_t>(a: 1, b: rlim.rlim_max); |
163 | #else |
164 | rlim.rlim_cur = 0; |
165 | #endif |
166 | setrlimit(RLIMIT_CORE, rlimits: &rlim); |
167 | #endif |
168 | |
169 | #if defined(HAVE_MACH_MACH_H) && !defined(__GNU__) |
170 | // Disable crash reporting on Mac OS X 10.0-10.4 |
171 | |
172 | // get information about the original set of exception ports for the task |
173 | mach_msg_type_number_t Count = 0; |
174 | exception_mask_t OriginalMasks[EXC_TYPES_COUNT]; |
175 | exception_port_t OriginalPorts[EXC_TYPES_COUNT]; |
176 | exception_behavior_t OriginalBehaviors[EXC_TYPES_COUNT]; |
177 | thread_state_flavor_t OriginalFlavors[EXC_TYPES_COUNT]; |
178 | kern_return_t err = task_get_exception_ports( |
179 | mach_task_self(), EXC_MASK_ALL, OriginalMasks, &Count, OriginalPorts, |
180 | OriginalBehaviors, OriginalFlavors); |
181 | if (err == KERN_SUCCESS) { |
182 | // replace each with MACH_PORT_NULL. |
183 | for (unsigned i = 0; i != Count; ++i) |
184 | task_set_exception_ports(mach_task_self(), OriginalMasks[i], |
185 | MACH_PORT_NULL, OriginalBehaviors[i], |
186 | OriginalFlavors[i]); |
187 | } |
188 | |
189 | // Disable crash reporting on Mac OS X 10.5 |
190 | signal(SIGABRT, _exit); |
191 | signal(SIGILL, _exit); |
192 | signal(SIGFPE, _exit); |
193 | signal(SIGSEGV, _exit); |
194 | signal(SIGBUS, _exit); |
195 | #endif |
196 | |
197 | coreFilesPrevented = true; |
198 | } |
199 | |
200 | std::optional<std::string> Process::GetEnv(StringRef Name) { |
201 | std::string NameStr = Name.str(); |
202 | const char *Val = ::getenv(name: NameStr.c_str()); |
203 | if (!Val) |
204 | return std::nullopt; |
205 | return std::string(Val); |
206 | } |
207 | |
208 | namespace { |
209 | class FDCloser { |
210 | public: |
211 | FDCloser(int &FD) : FD(FD), KeepOpen(false) {} |
212 | void keepOpen() { KeepOpen = true; } |
213 | ~FDCloser() { |
214 | if (!KeepOpen && FD >= 0) |
215 | ::close(fd: FD); |
216 | } |
217 | |
218 | private: |
219 | FDCloser(const FDCloser &) = delete; |
220 | void operator=(const FDCloser &) = delete; |
221 | |
222 | int &FD; |
223 | bool KeepOpen; |
224 | }; |
225 | } // namespace |
226 | |
227 | std::error_code Process::FixupStandardFileDescriptors() { |
228 | int NullFD = -1; |
229 | FDCloser FDC(NullFD); |
230 | const int StandardFDs[] = {STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO}; |
231 | for (int StandardFD : StandardFDs) { |
232 | struct stat st; |
233 | errno = 0; |
234 | if (RetryAfterSignal(Fail: -1, F&: ::fstat, As: StandardFD, As: &st) < 0) { |
235 | assert(errno && "expected errno to be set if fstat failed!" ); |
236 | // fstat should return EBADF if the file descriptor is closed. |
237 | if (errno != EBADF) |
238 | return errnoAsErrorCode(); |
239 | } |
240 | // if fstat succeeds, move on to the next FD. |
241 | if (!errno) |
242 | continue; |
243 | assert(errno == EBADF && "expected errno to have EBADF at this point!" ); |
244 | |
245 | if (NullFD < 0) { |
246 | // Call ::open in a lambda to avoid overload resolution in |
247 | // RetryAfterSignal when open is overloaded, such as in Bionic. |
248 | auto Open = [&]() { return ::open(file: "/dev/null" , O_RDWR); }; |
249 | if ((NullFD = RetryAfterSignal(Fail: -1, F: Open)) < 0) |
250 | return errnoAsErrorCode(); |
251 | } |
252 | |
253 | if (NullFD == StandardFD) |
254 | FDC.keepOpen(); |
255 | else if (dup2(fd: NullFD, fd2: StandardFD) < 0) |
256 | return errnoAsErrorCode(); |
257 | } |
258 | return std::error_code(); |
259 | } |
260 | |
261 | std::error_code Process::SafelyCloseFileDescriptor(int FD) { |
262 | // Create a signal set filled with *all* signals. |
263 | sigset_t FullSet, SavedSet; |
264 | if (sigfillset(set: &FullSet) < 0 || sigfillset(set: &SavedSet) < 0) |
265 | return errnoAsErrorCode(); |
266 | |
267 | // Atomically swap our current signal mask with a full mask. |
268 | #if LLVM_ENABLE_THREADS |
269 | if (int EC = pthread_sigmask(SIG_SETMASK, newmask: &FullSet, oldmask: &SavedSet)) |
270 | return std::error_code(EC, std::generic_category()); |
271 | #else |
272 | if (sigprocmask(SIG_SETMASK, &FullSet, &SavedSet) < 0) |
273 | return errnoAsErrorCode(); |
274 | #endif |
275 | // Attempt to close the file descriptor. |
276 | // We need to save the error, if one occurs, because our subsequent call to |
277 | // pthread_sigmask might tamper with errno. |
278 | int ErrnoFromClose = 0; |
279 | if (::close(fd: FD) < 0) |
280 | ErrnoFromClose = errno; |
281 | // Restore the signal mask back to what we saved earlier. |
282 | int EC = 0; |
283 | #if LLVM_ENABLE_THREADS |
284 | EC = pthread_sigmask(SIG_SETMASK, newmask: &SavedSet, oldmask: nullptr); |
285 | #else |
286 | if (sigprocmask(SIG_SETMASK, &SavedSet, nullptr) < 0) |
287 | EC = errno; |
288 | #endif |
289 | // The error code from close takes precedence over the one from |
290 | // pthread_sigmask. |
291 | if (ErrnoFromClose) |
292 | return std::error_code(ErrnoFromClose, std::generic_category()); |
293 | return std::error_code(EC, std::generic_category()); |
294 | } |
295 | |
296 | bool Process::StandardInIsUserInput() { |
297 | return FileDescriptorIsDisplayed(STDIN_FILENO); |
298 | } |
299 | |
300 | bool Process::StandardOutIsDisplayed() { |
301 | return FileDescriptorIsDisplayed(STDOUT_FILENO); |
302 | } |
303 | |
304 | bool Process::StandardErrIsDisplayed() { |
305 | return FileDescriptorIsDisplayed(STDERR_FILENO); |
306 | } |
307 | |
308 | bool Process::FileDescriptorIsDisplayed(int fd) { |
309 | #if HAVE_ISATTY |
310 | return isatty(fd: fd); |
311 | #else |
312 | // If we don't have isatty, just return false. |
313 | return false; |
314 | #endif |
315 | } |
316 | |
317 | static unsigned getColumns() { |
318 | // If COLUMNS is defined in the environment, wrap to that many columns. |
319 | if (const char *ColumnsStr = std::getenv(name: "COLUMNS" )) { |
320 | int Columns = std::atoi(nptr: ColumnsStr); |
321 | if (Columns > 0) |
322 | return Columns; |
323 | } |
324 | |
325 | // We used to call ioctl TIOCGWINSZ to determine the width. It is considered |
326 | // unuseful. |
327 | return 0; |
328 | } |
329 | |
330 | unsigned Process::StandardOutColumns() { |
331 | if (!StandardOutIsDisplayed()) |
332 | return 0; |
333 | |
334 | return getColumns(); |
335 | } |
336 | |
337 | unsigned Process::StandardErrColumns() { |
338 | if (!StandardErrIsDisplayed()) |
339 | return 0; |
340 | |
341 | return getColumns(); |
342 | } |
343 | |
344 | #ifdef LLVM_ENABLE_TERMINFO |
345 | // We manually declare these extern functions because finding the correct |
346 | // headers from various terminfo, curses, or other sources is harder than |
347 | // writing their specs down. |
348 | extern "C" int setupterm(char *term, int filedes, int *errret); |
349 | extern "C" struct term *set_curterm(struct term *termp); |
350 | extern "C" int del_curterm(struct term *termp); |
351 | extern "C" int tigetnum(char *capname); |
352 | #endif |
353 | |
354 | bool checkTerminalEnvironmentForColors() { |
355 | if (const char *TermStr = std::getenv(name: "TERM" )) { |
356 | return StringSwitch<bool>(TermStr) |
357 | .Case(S: "ansi" , Value: true) |
358 | .Case(S: "cygwin" , Value: true) |
359 | .Case(S: "linux" , Value: true) |
360 | .StartsWith(S: "screen" , Value: true) |
361 | .StartsWith(S: "xterm" , Value: true) |
362 | .StartsWith(S: "vt100" , Value: true) |
363 | .StartsWith(S: "rxvt" , Value: true) |
364 | .EndsWith(S: "color" , Value: true) |
365 | .Default(Value: false); |
366 | } |
367 | |
368 | return false; |
369 | } |
370 | |
371 | static bool terminalHasColors(int fd) { |
372 | #ifdef LLVM_ENABLE_TERMINFO |
373 | // First, acquire a global lock because these C routines are thread hostile. |
374 | static std::mutex TermColorMutex; |
375 | std::lock_guard<std::mutex> G(TermColorMutex); |
376 | |
377 | struct term *previous_term = set_curterm(nullptr); |
378 | int errret = 0; |
379 | if (setupterm(term: nullptr, filedes: fd, errret: &errret) != 0) |
380 | // Regardless of why, if we can't get terminfo, we shouldn't try to print |
381 | // colors. |
382 | return false; |
383 | |
384 | // Test whether the terminal as set up supports color output. How to do this |
385 | // isn't entirely obvious. We can use the curses routine 'has_colors' but it |
386 | // would be nice to avoid a dependency on curses proper when we can make do |
387 | // with a minimal terminfo parsing library. Also, we don't really care whether |
388 | // the terminal supports the curses-specific color changing routines, merely |
389 | // if it will interpret ANSI color escape codes in a reasonable way. Thus, the |
390 | // strategy here is just to query the baseline colors capability and if it |
391 | // supports colors at all to assume it will translate the escape codes into |
392 | // whatever range of colors it does support. We can add more detailed tests |
393 | // here if users report them as necessary. |
394 | // |
395 | // The 'tigetnum' routine returns -2 or -1 on errors, and might return 0 if |
396 | // the terminfo says that no colors are supported. |
397 | int colors_ti = tigetnum(capname: const_cast<char *>("colors" )); |
398 | bool HasColors = |
399 | colors_ti >= 0 ? colors_ti : checkTerminalEnvironmentForColors(); |
400 | |
401 | // Now extract the structure allocated by setupterm and free its memory |
402 | // through a really silly dance. |
403 | struct term *termp = set_curterm(previous_term); |
404 | (void)del_curterm(termp); // Drop any errors here. |
405 | |
406 | // Return true if we found a color capabilities for the current terminal. |
407 | return HasColors; |
408 | #else |
409 | // When the terminfo database is not available, check if the current terminal |
410 | // is one of terminals that are known to support ANSI color escape codes. |
411 | return checkTerminalEnvironmentForColors(); |
412 | #endif |
413 | } |
414 | |
415 | bool Process::FileDescriptorHasColors(int fd) { |
416 | // A file descriptor has colors if it is displayed and the terminal has |
417 | // colors. |
418 | return FileDescriptorIsDisplayed(fd) && terminalHasColors(fd); |
419 | } |
420 | |
421 | bool Process::StandardOutHasColors() { |
422 | return FileDescriptorHasColors(STDOUT_FILENO); |
423 | } |
424 | |
425 | bool Process::StandardErrHasColors() { |
426 | return FileDescriptorHasColors(STDERR_FILENO); |
427 | } |
428 | |
429 | void Process::UseANSIEscapeCodes(bool /*enable*/) { |
430 | // No effect. |
431 | } |
432 | |
433 | bool Process::ColorNeedsFlush() { |
434 | // No, we use ANSI escape sequences. |
435 | return false; |
436 | } |
437 | |
438 | const char *Process::OutputColor(char code, bool bold, bool bg) { |
439 | return colorcodes[bg ? 1 : 0][bold ? 1 : 0][code & 15]; |
440 | } |
441 | |
442 | const char *Process::OutputBold(bool bg) { return "\033[1m" ; } |
443 | |
444 | const char *Process::OutputReverse() { return "\033[7m" ; } |
445 | |
446 | const char *Process::ResetColor() { return "\033[0m" ; } |
447 | |
448 | #if !HAVE_DECL_ARC4RANDOM |
449 | static unsigned GetRandomNumberSeed() { |
450 | // Attempt to get the initial seed from /dev/urandom, if possible. |
451 | int urandomFD = open(file: "/dev/urandom" , O_RDONLY); |
452 | |
453 | if (urandomFD != -1) { |
454 | unsigned seed; |
455 | // Don't use a buffered read to avoid reading more data |
456 | // from /dev/urandom than we need. |
457 | int count = read(fd: urandomFD, buf: (void *)&seed, nbytes: sizeof(seed)); |
458 | |
459 | close(fd: urandomFD); |
460 | |
461 | // Return the seed if the read was successful. |
462 | if (count == sizeof(seed)) |
463 | return seed; |
464 | } |
465 | |
466 | // Otherwise, swizzle the current time and the process ID to form a reasonable |
467 | // seed. |
468 | const auto Now = std::chrono::high_resolution_clock::now(); |
469 | return hash_combine(args: Now.time_since_epoch().count(), args: ::getpid()); |
470 | } |
471 | #endif |
472 | |
473 | unsigned llvm::sys::Process::GetRandomNumber() { |
474 | #if HAVE_DECL_ARC4RANDOM |
475 | return arc4random(); |
476 | #else |
477 | static int x = (static_cast<void>(::srand(seed: GetRandomNumberSeed())), 0); |
478 | (void)x; |
479 | return ::rand(); |
480 | #endif |
481 | } |
482 | |
483 | [[noreturn]] void Process::ExitNoCleanup(int RetCode) { _Exit(status: RetCode); } |
484 | |