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