Apache Mesos
os.hpp
Go to the documentation of this file.
1 // Licensed under the Apache License, Version 2.0 (the "License");
2 // you may not use this file except in compliance with the License.
3 // You may obtain a copy of the License at
4 //
5 // http://www.apache.org/licenses/LICENSE-2.0
6 //
7 // Unless required by applicable law or agreed to in writing, software
8 // distributed under the License is distributed on an "AS IS" BASIS,
9 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 // See the License for the specific language governing permissions and
11 // limitations under the License.
12 
13 #ifndef __STOUT_WINDOWS_OS_HPP__
14 #define __STOUT_WINDOWS_OS_HPP__
15 
16 #include <sys/utime.h>
17 
18 #include <algorithm>
19 #include <list>
20 #include <map>
21 #include <memory>
22 #include <numeric>
23 #include <set>
24 #include <string>
25 #include <vector>
26 
27 #include <stout/bytes.hpp>
28 #include <stout/duration.hpp>
29 #include <stout/none.hpp>
30 #include <stout/nothing.hpp>
31 #include <stout/option.hpp>
32 #include <stout/path.hpp>
33 #include <stout/stringify.hpp>
34 #include <stout/strings.hpp>
35 #include <stout/try.hpp>
36 #include <stout/version.hpp>
37 #include <stout/windows.hpp>
38 
39 #include <stout/os/os.hpp>
40 #include <stout/os/getenv.hpp>
41 #include <stout/os/process.hpp>
42 #include <stout/os/read.hpp>
43 
45 
46 // NOTE: These system headers must be included after `stout/windows.hpp`
47 // as they may include `Windows.h`. See comments in `stout/windows.hpp`
48 // for why this ordering is important.
49 #include <Psapi.h> // For `EnumProcesses` and `GetProcessMemoryInfo`.
50 #include <TlHelp32.h> // For `PROCESSENTRY32W` and `CreateToolhelp32Snapshot`.
51 #include <Userenv.h> // For `GetAllUsersProfileDirectoryW`.
52 
53 namespace os {
54 namespace internal {
55 
57 {
58  // MSDN documentation states "The names are established at system startup,
59  // when the system reads them from the registry." This is akin to the
60  // Linux `gethostname` which calls `uname`, thus avoiding a DNS lookup.
61  // The `net::getHostname` function can be used for an explicit DNS lookup.
62  //
63  // NOTE: This returns the hostname of the local computer, or the local
64  // node if this computer is part of a cluster.
65  COMPUTER_NAME_FORMAT format = ComputerNamePhysicalDnsHostname;
66  DWORD size = 0;
67  if (::GetComputerNameExW(format, nullptr, &size) == 0) {
68  if (::GetLastError() != ERROR_MORE_DATA) {
69  return WindowsError();
70  }
71  }
72 
73  std::vector<wchar_t> buffer;
74  buffer.reserve(size);
75 
76  if (::GetComputerNameExW(format, buffer.data(), &size) == 0) {
77  return WindowsError();
78  }
79 
80  return stringify(std::wstring(buffer.data()));
81 }
82 
83 
84 // Converts a `FILETIME` from an absoute Windows time, which is the number of
85 // 100-nanosecond intervals since 1601-01-01 00:00:00 +0000, to an UNIX
86 // absolute time, which is number of seconds from 1970-01-01 00:00:00 +0000.
87 inline double windows_to_unix_epoch(const FILETIME& filetime)
88 {
89  ULARGE_INTEGER time;
90 
91  // `FILETIME` isn't 8 byte aligned so they suggest not do cast to int64*.
92  time.HighPart = filetime.dwHighDateTime;
93  time.LowPart = filetime.dwLowDateTime;
94 
95  // Constant taken from here:
96  // https://msdn.microsoft.com/en-us/library/windows/desktop/ms724228(v=vs.85).aspx. // NOLINT(whitespace/line_length)
97  // It is the number of 100ns periods between the Windows and UNIX epochs.
98  constexpr uint64_t epoch_offset = 116444736000000000ULL;
99 
100  // Now the `QuadPart` field is the 64-bit representation due to the
101  // layout of the `ULARGE_INTEGER` struct.
102  static_assert(
103  std::is_same<decltype(time.QuadPart), uint64_t>::value,
104  "Expected `ULARGE_INTEGER.QuadPart` to be of type `uint64_t`");
105 
106  CHECK_GE(time.QuadPart, epoch_offset)
107  << "windows_to_unix_epoch: Given time was before UNIX epoch: "
108  << time.QuadPart;
109 
110  return static_cast<double>(time.QuadPart - epoch_offset) / 10000000;
111 }
112 
113 } // namespace internal {
114 
115 
116 // Overload of os::pids for filtering by groups and sessions. A group / session
117 // id of 0 will fitler on the group / session ID of the calling process.
118 // NOTE: Windows does not have the concept of a process group, so we need to
119 // enumerate all processes.
121 {
122  DWORD max_items = 4096;
123  DWORD bytes_returned;
124  std::vector<pid_t> processes;
125  size_t size_in_bytes;
126 
127  // Attempt to populate `processes` with PIDs. We repeatedly call
128  // `EnumProcesses` with increasingly large arrays until it "succeeds" at
129  // populating the array with PIDs. The criteria for determining when
130  // `EnumProcesses` has succeeded are:
131  // (1) the return value is nonzero.
132  // (2) the `bytes_returned` is less than the number of bytes in the array.
133  do {
134  // TODO(alexnaparu): Set a limit to the memory that can be used.
135  processes.resize(max_items);
136  size_in_bytes = processes.size() * sizeof(pid_t);
137  CHECK_LE(size_in_bytes, MAXDWORD);
138 
139  BOOL result = ::EnumProcesses(
140  processes.data(),
141  static_cast<DWORD>(size_in_bytes),
142  &bytes_returned);
143 
144  if (!result) {
145  return WindowsError("os::pids: Call to `EnumProcesses` failed");
146  }
147 
148  max_items *= 2;
149  } while (bytes_returned >= size_in_bytes);
150 
151  std::set<pid_t> pids_set(processes.begin(), processes.end());
152 
153  // NOTE: The PID `0` will always be returned by `EnumProcesses`; however, it
154  // is the PID of Windows' System Idle Process. While the PID is valid, using
155  // it for anything is almost always invalid. For instance, `OpenProcess` will
156  // fail with an invalid parameter error if the user tries to get a handle for
157  // PID `0`. In the interest of safety, we prevent the `pids` API from ever
158  // including the PID `0`.
159  pids_set.erase(0);
160  return pids_set;
161 }
162 
163 
164 inline Try<std::set<pid_t>> pids()
165 {
166  return pids(None(), None());
167 }
168 
169 
170 // Sets the value associated with the specified key in the set of
171 // environment variables.
172 inline void setenv(
173  const std::string& key,
174  const std::string& value,
175  bool overwrite = true)
176 {
177  // Do not set the variable if already set and `overwrite` was not specified.
178  //
179  // Per MSDN, `GetEnvironmentVariable` returns 0 on error and sets the
180  // error code to `ERROR_ENVVAR_NOT_FOUND` if the variable was not found.
181  //
182  // https://msdn.microsoft.com/en-us/library/windows/desktop/ms683188(v=vs.85).aspx // NOLINT(whitespace/line_length)
183  if (!overwrite &&
184  ::GetEnvironmentVariableW(wide_stringify(key).data(), nullptr, 0) != 0 &&
185  ::GetLastError() == ERROR_ENVVAR_NOT_FOUND) {
186  return;
187  }
188 
189  // `SetEnvironmentVariable` returns an error code, but we can't act on it.
190  ::SetEnvironmentVariableW(
191  wide_stringify(key).data(), wide_stringify(value).data());
192 }
193 
194 
195 // Unsets the value associated with the specified key in the set of
196 // environment variables.
197 inline void unsetenv(const std::string& key)
198 {
199  // Per MSDN documentation[1], passing `nullptr` as the value will cause
200  // `SetEnvironmentVariable` to delete the key from the process's environment.
201  ::SetEnvironmentVariableW(wide_stringify(key).data(), nullptr);
202 }
203 
204 
205 // NOTE: This exists for compatibility with the POSIX API. On Windows,
206 // either function is suitable for clearing a secret from the
207 // environment, as the pointers returned by `GetEnvironmentVariable`
208 // and `GetEnvironmentStrings` are to blocks allocated on invocation.
209 inline void eraseenv(const std::string& key)
210 {
211  unsetenv(key);
212 }
213 
214 
215 // Suspends execution of the calling process until a child specified by `pid`
216 // has changed state. Unlike the POSIX standard function `::waitpid`, this
217 // function does not use -1 and 0 to signify errors and nonblocking return.
218 // Instead, we return `Result<pid_t>`:
219 // * In case of error, we return `Error` rather than -1. For example, we
220 // would return an `Error` in case of `EINVAL`.
221 // * In case of nonblocking return, we return `None` rather than 0. For
222 // example, if we pass `WNOHANG` in the `options`, we would expect 0 to be
223 // returned in the case that children specified by `pid` exist, but have
224 // not changed state yet. In this case we return `None` instead.
225 //
226 // NOTE: There are important differences between the POSIX and Windows
227 // implementations of this function:
228 // * On POSIX, `pid_t` is a signed number, but on Windows, PIDs are `DWORD`,
229 // which is `unsigned long`. Thus, if we use `DWORD` to represent the `pid`
230 // argument, passing -1 as the `pid` would (on most modern servers)
231 // silently convert to a really large `pid`. This is undesirable.
232 // * Since it is important to be able to detect -1 has been passed to
233 // `os::waitpid`, as a matter of practicality, we choose to:
234 // (1) Use `long` to represent the `pid` argument.
235 // (2) Disable using any value <= 0 for `pid` on Windows.
236 // * This decision is pragmatic. The reasoning is:
237 // (1) The Windows code paths call `os::waitpid` in only a handful of
238 // places, and in none of these conditions do we need `-1` as a value.
239 // (2) Since PIDs virtually never take on values outside the range of
240 // vanilla signed `long` it is likely that an accidental conversion
241 // will never happen.
242 // (3) Even though it is not formalized in the C specification, the
243 // implementation of `long` on the vast majority of production servers
244 // is 2's complement, so we expect that when we accidentally do
245 // implicitly convert from `unsigned long` to `long`, we will "wrap
246 // around" to negative values. And since we've disabled the negative
247 // `pid` in the Windows implementation, we should error out.
248 // * Finally, on Windows, we currently do not check that the process we are
249 // attempting to await is a child process.
250 inline Result<pid_t> waitpid(long pid, int* status, int options)
251 {
252  const bool wait_for_child = (options & WNOHANG) == 0;
253 
254  // NOTE: Windows does not implement pids <= 0.
255  if (pid <= 0) {
256  errno = ENOSYS;
257  return ErrnoError(
258  "os::waitpid: Value of pid is '" + stringify(pid) +
259  "'; the Windows implementation currently does not allow values <= 0");
260  } else if (options != 0 && options != WNOHANG) {
261  // NOTE: We only support `options == 0` or `options == WNOHANG`. On Windows
262  // no flags other than `WNOHANG` are supported.
263  errno = ENOSYS;
264  return ErrnoError(
265  "os::waitpid: Only flag `WNOHANG` is implemented on Windows");
266  }
267 
268  // TODO(hausdorff): Check that `pid` is one of the child processes. If not,
269  // set `errno` to `ECHILD` and return -1.
270 
271  // Open the child process as a safe `SharedHandle`.
272  const HANDLE process = ::OpenProcess(
273  PROCESS_QUERY_INFORMATION | SYNCHRONIZE,
274  FALSE,
275  static_cast<DWORD>(pid));
276 
277  if (process == nullptr) {
278  return WindowsError("os::waitpid: Failed to open process for pid '" +
279  stringify(pid) + "'");
280  }
281 
282  SharedHandle scoped_process(process, ::CloseHandle);
283 
284  // If `WNOHANG` flag is set, don't wait. Otherwise, wait for child to
285  // terminate.
286  const DWORD wait_time = wait_for_child ? INFINITE : 0;
287  const DWORD wait_results = ::WaitForSingleObject(
288  scoped_process.get(),
289  wait_time);
290 
291  // Verify our wait exited correctly.
292  const bool state_signaled = wait_results == WAIT_OBJECT_0;
293  if (options == 0 && !state_signaled) {
294  // If `WNOHANG` is not set, then we should have stopped waiting only for a
295  // state change in `scoped_process`.
296  errno = ECHILD;
297  return WindowsError(
298  "os::waitpid: Failed to wait for pid '" + stringify(pid) +
299  "'. `::WaitForSingleObject` should have waited for child process to " +
300  "exit, but returned code '" + stringify(wait_results) +
301  "' instead");
302  } else if (wait_for_child && !state_signaled &&
303  wait_results != WAIT_TIMEOUT) {
304  // If `WNOHANG` is set, then a successful wait should report either a
305  // timeout (since we set the time to wait to `0`), or a successful state
306  // change of `scoped_process`. Anything else is an error.
307  errno = ECHILD;
308  return WindowsError(
309  "os::waitpid: Failed to wait for pid '" + stringify(pid) +
310  "'. `ENOHANG` flag was passed in, so `::WaitForSingleObject` should " +
311  "have either returned `WAIT_OBJECT_0` or `WAIT_TIMEOUT` (the " +
312  "timeout was set to 0, because we are not waiting for the child), " +
313  "but instead returned code '" + stringify(wait_results) + "'");
314  }
315 
316  if (!wait_for_child && wait_results == WAIT_TIMEOUT) {
317  // Success. `ENOHANG` was set and we got a timeout, so return `None` (POSIX
318  // `::waitpid` would return 0 here).
319  return None();
320  }
321 
322  // Attempt to retrieve exit code from child process. Store that exit code in
323  // the `status` variable if it's `nullptr`.
324  DWORD child_exit_code = 0;
325  if (!::GetExitCodeProcess(scoped_process.get(), &child_exit_code)) {
326  errno = ECHILD;
327  return WindowsError(
328  "os::waitpid: Successfully waited on child process with pid '" +
329  std::to_string(pid) + "', but could not retrieve exit code");
330  }
331 
332  if (status != nullptr) {
333  *status = child_exit_code;
334  }
335 
336  // Success. Return pid of the child process for which the status is reported.
337  return pid;
338 }
339 
340 
341 inline std::string hstrerror(int err) = delete;
342 
343 
344 inline Try<Nothing> chown(
345  uid_t uid,
346  gid_t gid,
347  const std::string& path,
348  bool recursive) = delete;
349 
350 
351 inline Try<Nothing> chmod(const std::string& path, int mode) = delete;
352 
353 
354 inline Try<Nothing> mknod(
355  const std::string& path,
356  mode_t mode,
357  dev_t dev) = delete;
358 
359 
360 // Suspends execution for the given duration.
361 // NOTE: This implementation features a millisecond-resolution sleep API, while
362 // the POSIX version uses a nanosecond-resolution sleep API. As of this writing,
363 // Mesos only requires millisecond resolution, so this is ok for now.
364 inline Try<Nothing> sleep(const Duration& duration)
365 {
366  if (duration.ms() < 0) {
367  return WindowsError(ERROR_INVALID_PARAMETER);
368  }
369 
370  ::Sleep(static_cast<DWORD>(duration.ms()));
371 
372  return Nothing();
373 }
374 
375 
376 // Returns the list of files that match the given (shell) pattern.
377 // NOTE: Deleted on Windows, as a POSIX-API-compliant `glob` is much more
378 // trouble than its worth, considering our relatively simple usage.
379 inline Try<std::list<std::string>> glob(const std::string& pattern) = delete;
380 
381 
382 // Returns the total number of cpus (cores).
383 inline Try<long> cpus()
384 {
385  SYSTEM_INFO sys_info;
386  ::GetSystemInfo(&sys_info);
387  return static_cast<long>(sys_info.dwNumberOfProcessors);
388 }
389 
390 // Returns load struct with average system loads for the last
391 // 1, 5 and 15 minutes respectively.
392 // Load values should be interpreted as usual average loads from
393 // uptime(1).
394 inline Try<Load> loadavg()
395 {
396  // No Windows equivalent, return an error until there is a need. We can
397  // construct an approximation of this function by periodically polling
398  // `GetSystemTimes` and using a sliding window of statistics.
399  return WindowsError(ERROR_NOT_SUPPORTED,
400  "Failed to determine system load averages");
401 }
402 
403 
404 // Returns the total size of main and free memory.
405 inline Try<Memory> memory()
406 {
407  Memory memory;
408 
409  MEMORYSTATUSEX memory_status;
410  memory_status.dwLength = sizeof(MEMORYSTATUSEX);
411  if (!::GlobalMemoryStatusEx(&memory_status)) {
412  return WindowsError("os::memory: Call to `GlobalMemoryStatusEx` failed");
413  }
414 
415  memory.total = Bytes(memory_status.ullTotalPhys);
416  memory.free = Bytes(memory_status.ullAvailPhys);
417  memory.totalSwap = Bytes(memory_status.ullTotalPageFile);
418  memory.freeSwap = Bytes(memory_status.ullAvailPageFile);
419 
420  return memory;
421 }
422 
423 
424 inline Try<Version> release() = delete;
425 
426 
427 // Return the system information.
428 inline Try<UTSInfo> uname() = delete;
429 
430 
431 inline tm* gmtime_r(const time_t* timep, tm* result)
432 {
433  return ::gmtime_s(result, timep) == ERROR_SUCCESS ? result : nullptr;
434 }
435 
436 
438 {
439  // Get a snapshot of the processes in the system. NOTE: We should not check
440  // whether the handle is `nullptr`, because this API will always return
441  // `INVALID_HANDLE_VALUE` on error.
442  HANDLE snapshot_handle = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, pid);
443  if (snapshot_handle == INVALID_HANDLE_VALUE) {
444  return WindowsError(
445  "os::process_entry: Call to `CreateToolhelp32Snapshot` failed");
446  }
447 
448  SharedHandle safe_snapshot_handle(snapshot_handle, ::CloseHandle);
449 
450  // Initialize process entry.
451  PROCESSENTRY32W process_entry;
452  memset(&process_entry, 0, sizeof(process_entry));
453  process_entry.dwSize = sizeof(process_entry);
454 
455  // Get first process so that we can loop through process entries until we
456  // find the one we care about.
457  SetLastError(ERROR_SUCCESS);
458  BOOL has_next = Process32First(safe_snapshot_handle.get(), &process_entry);
459  if (has_next == FALSE) {
460  // No first process was found. We should never be here; it is arguable we
461  // should return `None`, since we won't find the PID we're looking for, but
462  // we elect to return `Error` because something terrible has probably
463  // happened.
464  if (::GetLastError() != ERROR_SUCCESS) {
465  return WindowsError("os::process_entry: Call to `Process32First` failed");
466  } else {
467  return Error("os::process_entry: Call to `Process32First` failed");
468  }
469  }
470 
471  // Loop through processes until we find the one we're looking for.
472  while (has_next == TRUE) {
473  if (process_entry.th32ProcessID == pid) {
474  // Process found.
475  return process_entry;
476  }
477 
478  has_next = Process32Next(safe_snapshot_handle.get(), &process_entry);
479  if (has_next == FALSE) {
480  DWORD last_error = ::GetLastError();
481  if (last_error != ERROR_NO_MORE_FILES && last_error != ERROR_SUCCESS) {
482  return WindowsError(
483  "os::process_entry: Call to `Process32Next` failed");
484  }
485  }
486  }
487 
488  return None();
489 }
490 
491 
492 // Generate a `Process` object for the process associated with `pid`. If
493 // process is not found, we return `None`; error is reserved for the case where
494 // something went wrong.
495 inline Result<Process> process(pid_t pid)
496 {
497  if (pid == 0) {
498  // The 0th PID is that of the System Idle Process on Windows. However, it is
499  // invalid to attempt to get a proces handle or else perform any operation
500  // on this pseudo-process.
501  return Error("os::process: Invalid parameter: pid == 0");
502  }
503 
504  // Find process with pid.
506 
507  if (entry.isError()) {
508  return WindowsError(entry.error());
509  } else if (entry.isNone()) {
510  return None();
511  }
512 
513  HANDLE process_handle = ::OpenProcess(
514  PROCESS_QUERY_LIMITED_INFORMATION | PROCESS_VM_READ,
515  false,
516  pid);
517 
518  // ::OpenProcess returns `NULL`, not `INVALID_HANDLE_VALUE` on failure.
519  if (process_handle == nullptr) {
520  return WindowsError("os::process: Call to `OpenProcess` failed");
521  }
522 
523  SharedHandle safe_process_handle(process_handle, ::CloseHandle);
524 
525  // Get Windows Working set size (Resident set size in linux).
526  PROCESS_MEMORY_COUNTERS proc_mem_counters;
527  BOOL get_process_memory_info = ::GetProcessMemoryInfo(
528  safe_process_handle.get_handle(),
529  &proc_mem_counters,
530  sizeof(proc_mem_counters));
531 
532  if (!get_process_memory_info) {
533  return WindowsError("os::process: Call to `GetProcessMemoryInfo` failed");
534  }
535 
536  // Get session Id.
537  pid_t session_id;
538  BOOL process_id_to_session_id = ::ProcessIdToSessionId(pid, &session_id);
539 
540  if (!process_id_to_session_id) {
541  return WindowsError("os::process: Call to `ProcessIdToSessionId` failed");
542  }
543 
544  // Get Process CPU time.
545  FILETIME create_filetime, exit_filetime, kernel_filetime, user_filetime;
546  BOOL get_process_times = ::GetProcessTimes(
547  safe_process_handle.get_handle(),
548  &create_filetime,
549  &exit_filetime,
550  &kernel_filetime,
551  &user_filetime);
552 
553  if (!get_process_times) {
554  return WindowsError("os::process: Call to `GetProcessTimes` failed");
555  }
556 
557  // Get utime and stime.
558  ULARGE_INTEGER lKernelTime, lUserTime; // In 100 nanoseconds.
559  lKernelTime.HighPart = kernel_filetime.dwHighDateTime;
560  lKernelTime.LowPart = kernel_filetime.dwLowDateTime;
561  lUserTime.HighPart = user_filetime.dwHighDateTime;
562  lUserTime.LowPart = user_filetime.dwLowDateTime;
563 
564  Try<Duration> utime = Nanoseconds(lKernelTime.QuadPart * 100);
565  Try<Duration> stime = Nanoseconds(lUserTime.QuadPart * 100);
566 
567  return Process(
568  pid,
569  entry.get().th32ParentProcessID, // Parent process id.
570  0, // Group id.
571  session_id,
572  Bytes(proc_mem_counters.WorkingSetSize),
573  utime.isSome() ? utime.get() : Option<Duration>::none(),
574  stime.isSome() ? stime.get() : Option<Duration>::none(),
575  stringify(entry.get().szExeFile), // Executable filename.
576  false); // Is not zombie process.
577 }
578 
579 
580 inline int random()
581 {
582  return rand();
583 }
584 
585 
586 inline Try<std::string> var()
587 {
588  // Get the `ProgramData` path. First, find the size of the output buffer.
589  // This size includes the null-terminating character.
590  DWORD size = 0;
591  if (::GetAllUsersProfileDirectoryW(nullptr, &size)) {
592  // The expected behavior here is for the function to "fail"
593  // and return `false`, and `size` receives necessary buffer size.
594  return WindowsError(
595  "os::var: `GetAllUsersProfileDirectoryW` succeeded unexpectedly");
596  }
597 
598  std::vector<wchar_t> buffer;
599  buffer.reserve(static_cast<size_t>(size));
600  if (!::GetAllUsersProfileDirectoryW(buffer.data(), &size)) {
601  return WindowsError("os::var: `GetAllUsersProfileDirectoryW` failed");
602  }
603 
604  return stringify(std::wstring(buffer.data()));
605 }
606 
607 
608 // Returns a host-specific default for the `PATH` environment variable, based
609 // on the configuration of the host.
610 inline std::string host_default_path()
611 {
612  // NOTE: On Windows, this code must run on the host where we are
613  // expecting to `exec` the task, because the value of
614  // `%SystemRoot%` is not identical on all platforms.
615  const Option<std::string> system_root_env = os::getenv("SystemRoot");
616  const std::string system_root = system_root_env.isSome()
617  ? system_root_env.get()
618  : path::join("C:", "Windows");
619 
620  return strings::join(";",
621  path::join(system_root, "System32"),
622  system_root,
623  path::join(system_root, "System32", "Wbem"),
624  path::join(system_root, "System32", "WindowsPowerShell", "v1.0"));
625 }
626 
627 } // namespace os {
628 
629 #endif // __STOUT_WINDOWS_OS_HPP__
Definition: path.hpp:26
bool isNone() const
Definition: result.hpp:112
Try< uid_t > uid(const std::string &path, const FollowSymlink follow=FollowSymlink::FOLLOW_SYMLINK)
Definition: stat.hpp:215
Definition: nothing.hpp:16
Definition: errorbase.hpp:36
Try< Bytes > size(const std::string &path, const FollowSymlink follow=FollowSymlink::FOLLOW_SYMLINK)
Definition: stat.hpp:121
T & get()&
Definition: try.hpp:73
HANDLE get_handle() const
Definition: windows.hpp:90
Definition: windows.hpp:72
std::stringstream & join(std::stringstream &stream, const std::string &separator, T &&...args)
Definition: strings.hpp:307
Try< Nothing > chmod(const std::string &path, int mode)
Definition: os.hpp:216
Definition: check.hpp:33
Try< Nothing > sleep(const Duration &duration)
Definition: os.hpp:240
static Result< T > error(const std::string &message)
Definition: result.hpp:53
Try< std::list< Process > > processes()
Definition: os.hpp:182
Try< Nothing > mknod(const std::string &path, mode_t mode, dev_t dev)
Definition: os.hpp:226
Result< ProcessStatus > status(pid_t pid)
Definition: proc.hpp:166
Definition: error.hpp:108
#define WNOHANG
Definition: windows.hpp:382
double ms() const
Definition: duration.hpp:48
Definition: errorbase.hpp:50
Definition: posix_signalhandler.hpp:23
std::string join(const std::string &path1, const std::string &path2, const char _separator=os::PATH_SEPARATOR)
Definition: path.hpp:56
void setenv(const std::string &key, const std::string &value, bool overwrite=true)
Definition: os.hpp:157
void unsetenv(const std::string &key)
Definition: os.hpp:167
Definition: duration.hpp:32
Definition: check.hpp:30
Bytes freeSwap
Definition: os.hpp:39
std::string host_default_path()
Definition: os.hpp:495
bool isSome() const
Definition: option.hpp:115
Try< Load > loadavg()
Definition: os.hpp:301
Try< std::string > nodename()
Definition: os.hpp:56
DWORD pid_t
Definition: windows.hpp:181
Definition: process.hpp:32
int mode_t
Definition: windows.hpp:177
Bytes totalSwap
Definition: os.hpp:38
Try< dev_t > dev(const std::string &path, const FollowSymlink follow=FollowSymlink::FOLLOW_SYMLINK)
Definition: stat.hpp:172
double windows_to_unix_epoch(const FILETIME &filetime)
Definition: os.hpp:87
constexpr Handle HANDLE
Definition: ingress.hpp:37
Try< Nothing > utime(const std::string &path)
Definition: utime.hpp:32
Try< long > cpus()
Definition: os.hpp:286
std::string hstrerror(int err)=delete
int uid_t
Definition: windows.hpp:183
static Option< T > none()
Definition: option.hpp:31
bool isSome() const
Definition: try.hpp:70
const T & get() const &
Definition: option.hpp:118
Option< std::string > getenv(const std::string &key)
Definition: getenv.hpp:29
int random()
Definition: os.hpp:580
Try< Version > release()
Definition: os.hpp:399
const T & get() const
Definition: result.hpp:115
Result< pid_t > waitpid(pid_t pid, int *status, int options)
Definition: os.hpp:141
Try< UTSInfo > uname()
Definition: os.hpp:318
Result< Process > process(pid_t pid)
Definition: freebsd.hpp:30
Definition: grp.hpp:26
Definition: os.hpp:34
Definition: none.hpp:27
Definition: attributes.hpp:24
Bytes total
Definition: os.hpp:36
Definition: executor.hpp:48
void eraseenv(const std::string &key)
Definition: os.hpp:181
Try< Nothing > chown(uid_t uid, gid_t gid, const std::string &path, bool recursive)
Definition: chown.hpp:30
Try< mode_t > mode(const std::string &path, const FollowSymlink follow=FollowSymlink::FOLLOW_SYMLINK)
Definition: stat.hpp:159
bool isError() const
Definition: result.hpp:113
int gid_t
Definition: windows.hpp:184
Try< std::string > format(const std::string &fmt, va_list args)
Definition: format.hpp:68
Result< PROCESSENTRY32W > process_entry(pid_t pid)
Definition: os.hpp:437
Definition: duration.hpp:165
Definition: bytes.hpp:30
Try< std::string > var()
Definition: os.hpp:428
std::string stringify(int flags)
Try< Memory > memory()
Definition: freebsd.hpp:78
Try< std::list< std::string > > glob(const std::string &pattern)
Definition: os.hpp:260
Bytes free
Definition: os.hpp:37
Try< std::set< pid_t > > pids()
Definition: freebsd.hpp:62
Try< std::vector< Value > > time(const std::string &hierarchy, const std::string &cgroup)
tm * gmtime_r(const time_t *timep, tm *result)
Definition: os.hpp:431