You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mesos.apache.org by ka...@apache.org on 2016/05/11 22:24:43 UTC

[21/50] [abbrv] mesos git commit: Moved stout from libprocess/3rdparty/ to 3rdparty/.

http://git-wip-us.apache.org/repos/asf/mesos/blob/c235f7c1/3rdparty/stout/include/stout/os/posix/close.hpp
----------------------------------------------------------------------
diff --git a/3rdparty/stout/include/stout/os/posix/close.hpp b/3rdparty/stout/include/stout/os/posix/close.hpp
new file mode 100644
index 0000000..695b232
--- /dev/null
+++ b/3rdparty/stout/include/stout/os/posix/close.hpp
@@ -0,0 +1,35 @@
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef __STOUT_OS_POSIX_CLOSE_HPP__
+#define __STOUT_OS_POSIX_CLOSE_HPP__
+
+#include <unistd.h>
+
+#include <stout/error.hpp>
+#include <stout/nothing.hpp>
+#include <stout/try.hpp>
+
+namespace os {
+
+inline Try<Nothing> close(int fd)
+{
+  if (::close(fd) != 0) {
+    return ErrnoError();
+  }
+
+  return Nothing();
+}
+
+} // namespace os {
+
+#endif // __STOUT_OS_POSIX_CLOSE_HPP__

http://git-wip-us.apache.org/repos/asf/mesos/blob/c235f7c1/3rdparty/stout/include/stout/os/posix/direntsize.hpp
----------------------------------------------------------------------
diff --git a/3rdparty/stout/include/stout/os/posix/direntsize.hpp b/3rdparty/stout/include/stout/os/posix/direntsize.hpp
new file mode 100644
index 0000000..9d8f72e
--- /dev/null
+++ b/3rdparty/stout/include/stout/os/posix/direntsize.hpp
@@ -0,0 +1,42 @@
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef __STOUT_OS_POSIX_DIRENTSIZE_HPP__
+#define __STOUT_OS_POSIX_DIRENTSIZE_HPP__
+
+#include <dirent.h>
+#include <unistd.h>
+
+
+namespace os {
+
+inline size_t dirent_size(DIR* dir)
+{
+  // Calculate the size for a "directory entry".
+  long name_max = fpathconf(dirfd(dir), _PC_NAME_MAX);
+
+  // If we don't get a valid size, check NAME_MAX, but fall back on
+  // 255 in the worst case ... Danger, Will Robinson!
+  if (name_max == -1) {
+    name_max = (NAME_MAX > 255) ? NAME_MAX : 255;
+  }
+
+  size_t name_end = (size_t) offsetof(dirent, d_name) + name_max + 1;
+
+  size_t size = (name_end > sizeof(dirent) ? name_end : sizeof(dirent));
+
+  return size;
+}
+
+} // namespace os {
+
+#endif // __STOUT_OS_POSIX_DIRENTSIZE_HPP__

http://git-wip-us.apache.org/repos/asf/mesos/blob/c235f7c1/3rdparty/stout/include/stout/os/posix/exists.hpp
----------------------------------------------------------------------
diff --git a/3rdparty/stout/include/stout/os/posix/exists.hpp b/3rdparty/stout/include/stout/os/posix/exists.hpp
new file mode 100644
index 0000000..59ece35
--- /dev/null
+++ b/3rdparty/stout/include/stout/os/posix/exists.hpp
@@ -0,0 +1,55 @@
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef __STOUT_OS_POSIX_EXISTS_HPP__
+#define __STOUT_OS_POSIX_EXISTS_HPP__
+
+#include <errno.h>
+#include <signal.h>
+
+#include <sys/stat.h>
+
+#include <string>
+
+namespace os {
+
+
+inline bool exists(const std::string& path)
+{
+  struct stat s;
+
+  if (::lstat(path.c_str(), &s) < 0) {
+    return false;
+  }
+  return true;
+}
+
+
+// Determine if the process identified by pid exists.
+// NOTE: Zombie processes have a pid and therefore exist. See os::process(pid)
+// to get details of a process.
+inline bool exists(pid_t pid)
+{
+  // The special signal 0 is used to check if the process exists; see kill(2).
+  // If the current user does not have permission to signal pid, but it does
+  // exist, then ::kill will return -1 and set errno == EPERM.
+  if (::kill(pid, 0) == 0 || errno == EPERM) {
+    return true;
+  }
+
+  return false;
+}
+
+
+} // namespace os {
+
+#endif // __STOUT_OS_POSIX_EXISTS_HPP__

http://git-wip-us.apache.org/repos/asf/mesos/blob/c235f7c1/3rdparty/stout/include/stout/os/posix/fcntl.hpp
----------------------------------------------------------------------
diff --git a/3rdparty/stout/include/stout/os/posix/fcntl.hpp b/3rdparty/stout/include/stout/os/posix/fcntl.hpp
new file mode 100644
index 0000000..daaca0d
--- /dev/null
+++ b/3rdparty/stout/include/stout/os/posix/fcntl.hpp
@@ -0,0 +1,84 @@
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef __STOUT_OS_POSIX_FCNTL_HPP__
+#define __STOUT_OS_POSIX_FCNTL_HPP__
+
+#include <fcntl.h>
+
+#include <stout/error.hpp>
+#include <stout/nothing.hpp>
+#include <stout/try.hpp>
+
+
+// TODO(jieyu): Consider introducing a general os::fcntl function
+// which allows us to get/set multiple flags in one call.
+namespace os {
+
+inline Try<Nothing> cloexec(int fd)
+{
+  int flags = ::fcntl(fd, F_GETFD);
+
+  if (flags == -1) {
+    return ErrnoError();
+  }
+
+  if (::fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1) {
+    return ErrnoError();
+  }
+
+  return Nothing();
+}
+
+
+inline Try<bool> isCloexec(int fd)
+{
+  int flags = ::fcntl(fd, F_GETFD);
+
+  if (flags == -1) {
+    return ErrnoError();
+  }
+
+  return (flags & FD_CLOEXEC) != 0;
+}
+
+
+inline Try<Nothing> nonblock(int fd)
+{
+  int flags = ::fcntl(fd, F_GETFL);
+
+  if (flags == -1) {
+    return ErrnoError();
+  }
+
+  if (::fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) {
+    return ErrnoError();
+  }
+
+  return Nothing();
+}
+
+
+inline Try<bool> isNonblock(int fd)
+{
+  int flags = ::fcntl(fd, F_GETFL);
+
+  if (flags == -1) {
+    return ErrnoError();
+  }
+
+  return (flags & O_NONBLOCK) != 0;
+}
+
+} // namespace os {
+
+#endif // __STOUT_OS_POSIX_FCNTL_HPP__

http://git-wip-us.apache.org/repos/asf/mesos/blob/c235f7c1/3rdparty/stout/include/stout/os/posix/fork.hpp
----------------------------------------------------------------------
diff --git a/3rdparty/stout/include/stout/os/posix/fork.hpp b/3rdparty/stout/include/stout/os/posix/fork.hpp
new file mode 100644
index 0000000..695fe66
--- /dev/null
+++ b/3rdparty/stout/include/stout/os/posix/fork.hpp
@@ -0,0 +1,451 @@
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef __STOUT_OS_POSIX_FORK_HPP__
+#define __STOUT_OS_POSIX_FORK_HPP__
+
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <sys/mman.h>
+#ifdef __FreeBSD__
+#include <sys/stat.h>
+#endif // __FreeBSD__
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include <atomic>
+#include <list>
+#include <memory>
+#include <set>
+#include <string>
+
+#include <stout/abort.hpp>
+#include <stout/error.hpp>
+#include <stout/exit.hpp>
+#include <stout/foreach.hpp>
+#include <stout/os/strerror.hpp>
+#include <stout/stringify.hpp>
+#include <stout/try.hpp>
+
+#include <stout/os/close.hpp>
+#include <stout/os/ftruncate.hpp>
+#include <stout/os/process.hpp>
+
+
+// Abstractions around forking process trees. You can declare a
+// process tree "template" using 'Fork', 'Exec', and 'Wait'. For
+// example, to describe a simple "fork/exec" you can do:
+//
+//   Fork f = Fork(Exec("sleep 10));
+//
+// The command passed to an 'Exec' is run via 'sh -c'. You can
+// construct more complicated templates via nesting, for example:
+//
+//   Fork f =
+//     Fork(None(),
+//          Fork(Exec("echo 'grandchild 1'")),
+//          Fork(None(),
+//               Fork(Exec("echo 'great-grandchild'")),
+//               Exec("echo 'grandchild 2'"))
+//          Exec("echo 'child'"));
+//
+// Note that the first argument to 'Fork' here is an optional function
+// that can be invoked before forking any more children or executing a
+// command. THIS FUNCTION SHOULD BE ASYNC SIGNAL SAFE.
+//
+// To wait for children, you can use 'Wait' instead of 'Exec', for
+// example:
+//
+//   Fork f =
+//     Fork(None(),
+//          Fork(Exec("echo 'grandchild 1'")),
+//          Fork(Exec("echo 'grandchild 2'")),
+//          Wait());
+//
+// You can also omit either an 'Exec' or a 'Wait' and the forked
+// process will just 'exit(0)'. For example, the following will cause
+// to processes to get reparented by 'init'.
+//
+//   Fork f =
+//     Fork(None(),
+//          Fork(Exec("echo 'grandchild 1'")),
+//          Fork(Exec("echo 'grandchild 2'")));
+//
+// A template can be instantiated by invoking the 'Fork' as a
+// functor. For example, using any of the templates above we can do:
+//
+//   Try<ProcessTree> tree = f();
+//
+// It's important to note that the process tree returned represents
+// the instant in time after the forking has completed but before
+// 'Exec', 'Wait' or 'exit(0)' has occurred (i.e., the process tree
+// will be complete).
+
+namespace os {
+
+// Forward declaration.
+inline Result<Process> process(pid_t);
+
+
+struct Exec
+{
+  Exec(const std::string& _command)
+    : command(_command) {}
+
+  const std::string command;
+};
+
+
+struct Wait {};
+
+
+struct Fork
+{
+  //  -+- parent.
+  Fork(const Option<void(*)()>& _function,
+       const Exec& _exec)
+    : function(_function),
+      exec(_exec) {}
+
+  Fork(const Exec& _exec) : exec(_exec) {}
+
+  //  -+- parent
+  //   \--- child.
+  Fork(const Option<void(*)()>& _function,
+       const Fork& fork1)
+    : function(_function)
+  {
+    children.push_back(fork1);
+  }
+
+  Fork(const Option<void(*)()>& _function,
+       const Fork& fork1,
+       const Exec& _exec)
+    : function(_function),
+      exec(_exec)
+  {
+    children.push_back(fork1);
+  }
+
+  Fork(const Option<void(*)()>& _function,
+       const Fork& fork1,
+       const Wait& _wait)
+    : function(_function),
+      wait(_wait)
+  {
+    children.push_back(fork1);
+  }
+
+
+  // -+- parent
+  //   |--- child
+  //   \--- child.
+  Fork(const Option<void(*)()>& _function,
+       const Fork& fork1,
+       const Fork& fork2)
+    : function(_function)
+  {
+    children.push_back(fork1);
+    children.push_back(fork2);
+  }
+
+  Fork(const Option<void(*)()>& _function,
+       const Fork& fork1,
+       const Fork& fork2,
+       const Exec& _exec)
+    : function(_function),
+      exec(_exec)
+  {
+    children.push_back(fork1);
+    children.push_back(fork2);
+  }
+
+  Fork(const Option<void(*)()>& _function,
+       const Fork& fork1,
+       const Fork& fork2,
+       const Wait& _wait)
+    : function(_function),
+      wait(_wait)
+  {
+    children.push_back(fork1);
+    children.push_back(fork2);
+  }
+
+
+  // -+- parent
+  //   |--- child
+  //   |--- child
+  //   \--- child.
+  Fork(const Option<void(*)()>& _function,
+       const Fork& fork1,
+       const Fork& fork2,
+       const Fork& fork3)
+    : function(_function)
+  {
+    children.push_back(fork1);
+    children.push_back(fork2);
+    children.push_back(fork3);
+  }
+
+  Fork(const Option<void(*)()>& _function,
+       const Fork& fork1,
+       const Fork& fork2,
+       const Fork& fork3,
+       const Exec& _exec)
+    : function(_function),
+      exec(_exec)
+  {
+    children.push_back(fork1);
+    children.push_back(fork2);
+    children.push_back(fork3);
+  }
+
+  Fork(const Option<void(*)()>& _function,
+       const Fork& fork1,
+       const Fork& fork2,
+       const Fork& fork3,
+       const Wait& _wait)
+    : function(_function),
+      wait(_wait)
+  {
+    children.push_back(fork1);
+    children.push_back(fork2);
+    children.push_back(fork3);
+  }
+
+private:
+  // Represents the "tree" of descendants where each node has a
+  // pointer (into shared memory) from which we can read the
+  // descendants process information as well as a vector of children.
+  struct Tree
+  {
+    // NOTE: This struct is stored in shared memory and thus cannot
+    // hold any pointers to heap allocated memory.
+    struct Memory {
+      pid_t pid;
+      pid_t parent;
+      pid_t group;
+      pid_t session;
+
+      std::atomic_bool set; // Has this been initialized?
+    };
+
+    std::shared_ptr<Memory> memory;
+    std::vector<Tree> children;
+  };
+
+  // We use shared memory to "share" the pids of forked descendants.
+  // The benefit of shared memory over pipes is that each forked
+  // process can read its descendants' pids leading to a simpler
+  // implementation (with pipes, only one reader can ever read the
+  // value from the pipe, forcing much more complicated coordination).
+  //
+  // Shared memory works like a file (in memory) that gets deleted by
+  // "unlinking" it, but it won't get completely deleted until all
+  // open file descriptors referencing it have been closed. Each
+  // forked process has the shared memory mapped into it as well as an
+  // open file descriptor, both of which should get cleaned up
+  // automagically when the process exits, but we use a special
+  // "deleter" (in combination with shared_ptr) in order to clean this
+  // stuff up when we are actually finished using the shared memory.
+  struct SharedMemoryDeleter
+  {
+    SharedMemoryDeleter(int _fd) : fd(_fd) {}
+
+    void operator()(Tree::Memory* process) const
+    {
+      if (munmap(process, sizeof(Tree::Memory)) == -1) {
+        ABORT(std::string("Failed to unmap memory: ") + os::strerror(errno));
+      }
+      if (::close(fd) == -1) {
+        ABORT(std::string("Failed to close shared memory file descriptor: ") +
+              os::strerror(errno));
+      }
+    }
+
+    const int fd;
+  };
+
+  // Constructs a Tree (see above) from this fork template.
+  Try<Tree> prepare() const
+  {
+    static std::atomic_int forks(0);
+
+    // Each "instance" of an instantiated Fork needs a unique name for
+    // creating shared memory.
+    int instance = forks.fetch_add(1);
+
+    std::string name =
+      "/stout-forks-" + stringify(getpid()) + stringify(instance);
+
+    int fd = shm_open(name.c_str(), O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
+
+    if (fd == -1) {
+      return ErrnoError("Failed to open a shared memory object");
+    }
+
+    Try<Nothing> truncated = ftruncate(fd, sizeof(Tree::Memory));
+    if (truncated.isError()) {
+      return Error(
+          "Failed to set size of shared memory object: " + truncated.error());
+    }
+
+    void* memory = mmap(
+        NULL,
+        sizeof(Tree::Memory),
+        PROT_READ | PROT_WRITE, MAP_SHARED,
+        fd,
+        0);
+
+    if (memory == MAP_FAILED) {
+      return ErrnoError("Failed to map shared memory object");
+    }
+
+    if (shm_unlink(name.c_str()) == -1) {
+      return ErrnoError("Failed to unlink shared memory object");
+    }
+
+    SharedMemoryDeleter deleter(fd);
+
+    Tree tree;
+    tree.memory = std::shared_ptr<Tree::Memory>((Tree::Memory*)memory, deleter);
+    tree.memory->set.store(false);
+
+    for (size_t i = 0; i < children.size(); i++) {
+      Try<Tree> tree_ = children[i].prepare();
+      if (tree_.isError()) {
+        return Error(tree_.error());
+      }
+      tree.children.push_back(tree_.get());
+    }
+
+    return tree;
+  }
+
+  // Performs the fork, executes the function, recursively
+  // instantiates any children, and then executes/waits/exits.
+  pid_t instantiate(const Tree& tree) const
+  {
+    pid_t pid = ::fork();
+    if (pid > 0) {
+      return pid;
+    }
+
+    // Set the basic process information.
+    Tree::Memory process;
+    process.pid = getpid();
+    process.parent = getppid();
+    process.group = getpgid(0);
+    process.session = getsid(0);
+    process.set.store(true);
+
+    // Copy it into shared memory.
+    memcpy(tree.memory.get(), &process, sizeof(Tree::Memory));
+
+    // Execute the function, if any.
+    if (function.isSome()) {
+      function.get()();
+    }
+
+    // Fork the children, if any.
+    CHECK(children.size() == tree.children.size());
+    std::set<pid_t> pids;
+    for (size_t i = 0; i < children.size(); i++) {
+      pids.insert(children[i].instantiate(tree.children[i]));
+    }
+
+    // Execute or wait.
+    if (exec.isSome()) {
+      // Execute the command (via '/bin/sh -c command').
+      const char* command = exec.get().command.c_str();
+      execlp("sh", "sh", "-c", command, (char*) NULL);
+      EXIT(EXIT_FAILURE)
+        << "Failed to execute '" << command << "': " << os::strerror(errno);
+    } else if (wait.isSome()) {
+      foreach (pid_t pid, pids) {
+        // TODO(benh): Check for signal interruption or other errors.
+        waitpid(pid, NULL, 0);
+      }
+    }
+
+    exit(0);
+    return -1;
+  }
+
+  // Waits for all of the descendant processes in the tree to update
+  // their pids and constructs a ProcessTree using the Tree::Memory
+  // information from shared memory.
+  static Try<ProcessTree> coordinate(const Tree& tree)
+  {
+    // Wait for the forked process.
+    // TODO(benh): Don't wait forever?
+    while (!tree.memory->set.load());
+
+    // All processes in the returned ProcessTree will have the
+    // command-line of the top level process, since we construct the
+    // tree using post-fork pre-exec information. So, we'll grab the
+    // command of the current process here.
+    Result<Process> self = os::process(getpid());
+
+    Process process = Process(
+        tree.memory->pid,
+        tree.memory->parent,
+        tree.memory->group,
+        tree.memory->session,
+        None(),
+        None(),
+        None(),
+        self.isSome() ? self.get().command : "",
+        false);
+
+    std::list<ProcessTree> children;
+    for (size_t i = 0; i < tree.children.size(); i++) {
+      Try<ProcessTree> child = coordinate(tree.children[i]);
+      if (child.isError()) {
+        return Error(child.error());
+      }
+      children.push_back(child.get());
+    }
+
+    return ProcessTree(process, children);
+  }
+
+public:
+  // Prepares and instantiates the process tree.
+  Try<ProcessTree> operator()() const
+  {
+    Try<Tree> tree = prepare();
+
+    if (tree.isError()) {
+      return Error(tree.error());
+    }
+
+    Try<pid_t> pid = instantiate(tree.get());
+
+    if (pid.isError()) {
+      return Error(pid.error());
+    }
+
+    return coordinate(tree.get());
+  }
+
+private:
+  Option<void(*)()> function;
+  Option<const Exec> exec;
+  Option<const Wait> wait;
+  std::vector<Fork> children;
+};
+
+} // namespace os {
+
+#endif // __STOUT_OS_POSIX_FORK_HPP__

http://git-wip-us.apache.org/repos/asf/mesos/blob/c235f7c1/3rdparty/stout/include/stout/os/posix/ftruncate.hpp
----------------------------------------------------------------------
diff --git a/3rdparty/stout/include/stout/os/posix/ftruncate.hpp b/3rdparty/stout/include/stout/os/posix/ftruncate.hpp
new file mode 100644
index 0000000..98c4467
--- /dev/null
+++ b/3rdparty/stout/include/stout/os/posix/ftruncate.hpp
@@ -0,0 +1,39 @@
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef __STOUT_OS_POSIX_FTRUNCATE_HPP__
+#define __STOUT_OS_POSIX_FTRUNCATE_HPP__
+
+#include <sys/types.h>
+
+#include <stout/error.hpp>
+#include <stout/nothing.hpp>
+#include <stout/stringify.hpp>
+#include <stout/try.hpp>
+
+
+namespace os {
+
+inline Try<Nothing> ftruncate(int fd, off_t length)
+{
+  if (::ftruncate(fd, length) != 0) {
+    return ErrnoError(
+      "Failed to truncate file at file descriptor '" + stringify(fd) + "' to " +
+      stringify(length) + " bytes.");
+  }
+
+  return Nothing();
+}
+
+} // namespace os {
+
+#endif // __STOUT_OS_POSIX_FTRUNCATE_HPP__

http://git-wip-us.apache.org/repos/asf/mesos/blob/c235f7c1/3rdparty/stout/include/stout/os/posix/killtree.hpp
----------------------------------------------------------------------
diff --git a/3rdparty/stout/include/stout/os/posix/killtree.hpp b/3rdparty/stout/include/stout/os/posix/killtree.hpp
new file mode 100644
index 0000000..8ba21de
--- /dev/null
+++ b/3rdparty/stout/include/stout/os/posix/killtree.hpp
@@ -0,0 +1,226 @@
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef __STOUT_OS_POSIX_KILLTREE_HPP__
+#define __STOUT_OS_POSIX_KILLTREE_HPP__
+
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <list>
+#include <queue>
+#include <set>
+
+#include <stout/check.hpp>
+#include <stout/os.hpp>
+
+#include <stout/os/pstree.hpp>
+
+
+namespace os {
+
+// Forward declarations from os.hpp.
+inline std::set<pid_t> children(pid_t, const std::list<Process>&, bool);
+inline Result<Process> process(pid_t);
+inline Option<Process> process(pid_t, const std::list<Process>&);
+inline Try<std::list<Process>> processes();
+inline Try<std::list<ProcessTree>> pstrees(
+    const std::set<pid_t>&,
+    const std::list<Process>&);
+
+
+// Sends a signal to a process tree rooted at the specified pid.
+// If groups is true, this also sends the signal to all encountered
+// process groups.
+// If sessions is true, this also sends the signal to all encountered
+// process sessions.
+// Note that processes of the group and session of the parent of the
+// root process is not included unless they are part of the root
+// process tree.
+// Note that if the process 'pid' has exited we'll signal the process
+// tree(s) rooted at pids in the group or session led by the process
+// if groups = true or sessions = true, respectively.
+// Returns the process trees that were succesfully or unsuccessfully
+// signaled. Note that the process trees can be stringified.
+// TODO(benh): Allow excluding the root pid from stopping, killing,
+// and continuing so as to provide a means for expressing "kill all of
+// my children". This is non-trivial because of the current
+// implementation.
+inline Try<std::list<ProcessTree>> killtree(
+    pid_t pid,
+    int signal,
+    bool groups = false,
+    bool sessions = false)
+{
+  Try<std::list<Process>> processes = os::processes();
+
+  if (processes.isError()) {
+    return Error(processes.error());
+  }
+
+  Result<Process> process = os::process(pid, processes.get());
+
+  std::queue<pid_t> queue;
+
+  // If the root process has already terminated we'll add in any pids
+  // that are in the process group originally led by pid or in the
+  // session originally led by pid, if instructed.
+  if (process.isNone()) {
+    foreach (const Process& _process, processes.get()) {
+      if (groups && _process.group == pid) {
+        queue.push(_process.pid);
+      } else if (sessions &&
+                 _process.session.isSome() &&
+                 _process.session.get() == pid) {
+        queue.push(_process.pid);
+      }
+    }
+
+    // Root process is not running and no processes found in the
+    // process group or session so nothing we can do.
+    if (queue.empty()) {
+      return std::list<ProcessTree>();
+    }
+  } else {
+    // Start the traversal from pid as the root.
+    queue.push(pid);
+  }
+
+  struct {
+    std::set<pid_t> pids;
+    std::set<pid_t> groups;
+    std::set<pid_t> sessions;
+    std::list<Process> processes;
+  } visited;
+
+  // If we are following groups and/or sessions then we try and make
+  // the group and session of the parent process "already visited" so
+  // that we don't kill "up the tree". This can only be done if the
+  // process is present.
+  if (process.isSome() && (groups || sessions)) {
+    Option<Process> parent =
+      os::process(process.get().parent, processes.get());
+
+    if (parent.isSome()) {
+      if (groups) {
+        visited.groups.insert(parent.get().group);
+      }
+      if (sessions && parent.get().session.isSome()) {
+        visited.sessions.insert(parent.get().session.get());
+      }
+    }
+  }
+
+  while (!queue.empty()) {
+    pid_t pid = queue.front();
+    queue.pop();
+
+    if (visited.pids.count(pid) != 0) {
+      continue;
+    }
+
+    // Make sure this process still exists.
+    process = os::process(pid);
+
+    if (process.isError()) {
+      return Error(process.error());
+    } else if (process.isNone()) {
+      continue;
+    }
+
+    // Stop the process to keep it from forking while we are killing
+    // it since a forked child might get re-parented by init and
+    // become impossible to find.
+    kill(pid, SIGSTOP);
+
+    visited.pids.insert(pid);
+    visited.processes.push_back(process.get());
+
+    // Now refresh the process list knowing that the current process
+    // can't fork any more children (since it's stopped).
+    processes = os::processes();
+
+    if (processes.isError()) {
+      return Error(processes.error());
+    }
+
+    // Enqueue the children for visiting.
+    foreach (pid_t child, os::children(pid, processes.get(), false)) {
+      queue.push(child);
+    }
+
+    // Now "visit" the group and/or session of the current process.
+    if (groups) {
+      pid_t group = process.get().group;
+      if (visited.groups.count(group) == 0) {
+        foreach (const Process& process, processes.get()) {
+          if (process.group == group) {
+            queue.push(process.pid);
+          }
+        }
+        visited.groups.insert(group);
+      }
+    }
+
+    // If we do not have a session for the process, it's likely
+    // because the process is a zombie on OS X. This implies it has
+    // not been reaped and thus is located somewhere in the tree we
+    // are trying to kill. Therefore, we should discover it from our
+    // tree traversal, or through its group (which is always present).
+    if (sessions && process.get().session.isSome()) {
+      pid_t session = process.get().session.get();
+      if (visited.sessions.count(session) == 0) {
+        foreach (const Process& process, processes.get()) {
+          if (process.session.isSome() && process.session.get() == session) {
+            queue.push(process.pid);
+          }
+        }
+        visited.sessions.insert(session);
+      }
+    }
+  }
+
+  // Now that all processes are stopped, we send the signal.
+  foreach (pid_t pid, visited.pids) {
+    kill(pid, signal);
+  }
+
+  // There is a concern that even though some process is stopped,
+  // sending a signal to any of it's children may cause a SIGCLD to
+  // be delivered to it which wakes it up (or any other signal maybe
+  // delivered). However, from the Open Group standards on "Signal
+  // Concepts":
+  //
+  //   "While a process is stopped, any additional signals that are
+  //    sent to the process shall not be delivered until the process
+  //    is continued, except SIGKILL which always terminates the
+  //    receiving process."
+  //
+  // In practice, this is not what has been witnessed. Rather, a
+  // process that has been stopped will respond to SIGTERM, SIGINT,
+  // etc. That being said, we still continue the process below in the
+  // event that it doesn't terminate from the sending signal but it
+  // also doesn't get continued (as per the specifications above).
+
+  // Try and continue the processes in case the signal is
+  // non-terminating but doesn't continue the process.
+  foreach (pid_t pid, visited.pids) {
+    kill(pid, SIGCONT);
+  }
+
+  // Return the process trees representing the visited pids.
+  return pstrees(visited.pids, visited.processes);
+}
+
+} // namespace os {
+
+#endif // __STOUT_OS_POSIX_KILLTREE_HPP__

http://git-wip-us.apache.org/repos/asf/mesos/blob/c235f7c1/3rdparty/stout/include/stout/os/posix/mkdtemp.hpp
----------------------------------------------------------------------
diff --git a/3rdparty/stout/include/stout/os/posix/mkdtemp.hpp b/3rdparty/stout/include/stout/os/posix/mkdtemp.hpp
new file mode 100644
index 0000000..bbfbb8a
--- /dev/null
+++ b/3rdparty/stout/include/stout/os/posix/mkdtemp.hpp
@@ -0,0 +1,45 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef __STOUT_OS_POSIX_MKDTEMP_HPP__
+#define __STOUT_OS_POSIX_MKDTEMP_HPP__
+
+#include <stout/try.hpp>
+
+
+namespace os {
+
+// Creates a temporary directory using the specified path
+// template. The template may be any path with _6_ `Xs' appended to
+// it, for example /tmp/temp.XXXXXX. The trailing `Xs' are replaced
+// with a unique alphanumeric combination.
+inline Try<std::string> mkdtemp(const std::string& path = "/tmp/XXXXXX")
+{
+  char* temp = new char[path.size() + 1];
+  if (::mkdtemp(::strcpy(temp, path.c_str())) != NULL) {
+    std::string result(temp);
+    delete[] temp;
+    return result;
+  } else {
+    delete[] temp;
+    return ErrnoError();
+  }
+}
+
+} // namespace os {
+
+
+#endif // __STOUT_OS_POSIX_MKDTEMP_HPP__

http://git-wip-us.apache.org/repos/asf/mesos/blob/c235f7c1/3rdparty/stout/include/stout/os/posix/pagesize.hpp
----------------------------------------------------------------------
diff --git a/3rdparty/stout/include/stout/os/posix/pagesize.hpp b/3rdparty/stout/include/stout/os/posix/pagesize.hpp
new file mode 100644
index 0000000..f3ae69a
--- /dev/null
+++ b/3rdparty/stout/include/stout/os/posix/pagesize.hpp
@@ -0,0 +1,30 @@
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef __STOUT_OS_POSIX_PAGESIZE_HPP__
+#define __STOUT_OS_POSIX_PAGESIZE_HPP__
+
+#include <unistd.h>
+
+
+namespace os {
+
+// The alternative `getpagesize()` does not exist when enforcing
+// strict POSIX compliance.
+inline int pagesize()
+{
+  return sysconf(_SC_PAGESIZE);
+}
+
+} // namespace os {
+
+#endif // __STOUT_OS_POSIX_PAGESIZE_HPP__

http://git-wip-us.apache.org/repos/asf/mesos/blob/c235f7c1/3rdparty/stout/include/stout/os/posix/read.hpp
----------------------------------------------------------------------
diff --git a/3rdparty/stout/include/stout/os/posix/read.hpp b/3rdparty/stout/include/stout/os/posix/read.hpp
new file mode 100644
index 0000000..b6185de
--- /dev/null
+++ b/3rdparty/stout/include/stout/os/posix/read.hpp
@@ -0,0 +1,29 @@
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef __STOUT_OS_POSIX_READ_HPP__
+#define __STOUT_OS_POSIX_READ_HPP__
+
+#include <errno.h>
+#include <unistd.h>
+
+
+namespace os {
+
+// Compatibility function. On POSIX, this function is trivial, but on Windows,
+// we have to check whether the file descriptor is a socket or a file to read
+// from it.
+using ::read;
+
+} // namespace os {
+
+#endif // __STOUT_OS_POSIX_READ_HPP__

http://git-wip-us.apache.org/repos/asf/mesos/blob/c235f7c1/3rdparty/stout/include/stout/os/posix/rename.hpp
----------------------------------------------------------------------
diff --git a/3rdparty/stout/include/stout/os/posix/rename.hpp b/3rdparty/stout/include/stout/os/posix/rename.hpp
new file mode 100644
index 0000000..9cff6db
--- /dev/null
+++ b/3rdparty/stout/include/stout/os/posix/rename.hpp
@@ -0,0 +1,38 @@
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef __STOUT_OS_POSIX_RENAME_HPP__
+#define __STOUT_OS_POSIX_RENAME_HPP__
+
+#include <stdio.h>
+
+#include <string>
+
+#include <stout/error.hpp>
+#include <stout/nothing.hpp>
+#include <stout/try.hpp>
+
+
+namespace os {
+
+inline Try<Nothing> rename(const std::string& from, const std::string& to)
+{
+  if (::rename(from.c_str(), to.c_str()) != 0) {
+    return ErrnoError();
+  }
+
+  return Nothing();
+}
+
+} // namespace os {
+
+#endif // __STOUT_OS_POSIX_RENAME_HPP__

http://git-wip-us.apache.org/repos/asf/mesos/blob/c235f7c1/3rdparty/stout/include/stout/os/posix/rm.hpp
----------------------------------------------------------------------
diff --git a/3rdparty/stout/include/stout/os/posix/rm.hpp b/3rdparty/stout/include/stout/os/posix/rm.hpp
new file mode 100644
index 0000000..b1ec881
--- /dev/null
+++ b/3rdparty/stout/include/stout/os/posix/rm.hpp
@@ -0,0 +1,37 @@
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+#ifndef __STOUT_OS_POSIX_RM_HPP__
+#define __STOUT_OS_POSIX_RM_HPP__
+
+#include <stdio.h>
+
+#include <string>
+
+#include <stout/error.hpp>
+#include <stout/nothing.hpp>
+#include <stout/try.hpp>
+
+
+namespace os {
+
+inline Try<Nothing> rm(const std::string& path)
+{
+  if (::remove(path.c_str()) != 0) {
+    return ErrnoError();
+  }
+
+  return Nothing();
+}
+
+} // namespace os {
+
+#endif // __STOUT_OS_POSIX_RM_HPP__

http://git-wip-us.apache.org/repos/asf/mesos/blob/c235f7c1/3rdparty/stout/include/stout/os/posix/rmdir.hpp
----------------------------------------------------------------------
diff --git a/3rdparty/stout/include/stout/os/posix/rmdir.hpp b/3rdparty/stout/include/stout/os/posix/rmdir.hpp
new file mode 100644
index 0000000..a6d3b57
--- /dev/null
+++ b/3rdparty/stout/include/stout/os/posix/rmdir.hpp
@@ -0,0 +1,116 @@
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef __STOUT_OS_POSIX_RMDIR_HPP__
+#define __STOUT_OS_POSIX_RMDIR_HPP__
+
+#include <fts.h>
+#include <unistd.h>
+#include <string>
+
+#include <stout/error.hpp>
+#include <stout/nothing.hpp>
+#include <stout/try.hpp>
+
+#include <stout/os/exists.hpp>
+
+
+namespace os {
+
+// By default, recursively deletes a directory akin to: 'rm -r'. If
+// `recursive` is false, it deletes a directory akin to: 'rmdir'. In
+// recursive mode, `removeRoot` can be set to false to enable removing
+// all the files and directories beneath the given root directory, but
+// not the root directory itself.
+// Note that this function expects an absolute path.
+#ifndef __sun // FTS is not available on Solaris.
+inline Try<Nothing> rmdir(
+    const std::string& directory,
+    bool recursive = true,
+    bool removeRoot = true)
+{
+  if (!recursive) {
+    if (::rmdir(directory.c_str()) < 0) {
+      return ErrnoError();
+    }
+  } else {
+    // NOTE: `fts_open` will not always return `NULL` if the path does not
+    // exist. We manually induce an error here to indicate that we can't remove
+    // a directory that does not exist.
+    if (!os::exists(directory)) {
+      errno = ENOENT;
+      return ErrnoError();
+    }
+
+    char* paths[] = {const_cast<char*>(directory.c_str()), NULL};
+
+    // Using `FTS_PHYSICAL` here because we need `FTSENT` for the
+    // symbolic link in the directory and not the target it links to.
+    FTS* tree = fts_open(paths, (FTS_NOCHDIR | FTS_PHYSICAL), NULL);
+    if (tree == NULL) {
+      return ErrnoError();
+    }
+
+    FTSENT* node;
+    while ((node = fts_read(tree)) != NULL) {
+      switch (node->fts_info) {
+        case FTS_DP:
+          // Don't remove the root of the traversal of `removeRoot`
+          // is false.
+          if (!removeRoot && node->fts_level == FTS_ROOTLEVEL) {
+            continue;
+          }
+
+          if (::rmdir(node->fts_path) < 0 && errno != ENOENT) {
+            Error error = ErrnoError();
+            fts_close(tree);
+            return error;
+          }
+          break;
+        // `FTS_DEFAULT` would include any file type which is not
+        // explicitly described by any of the other `fts_info` values.
+        case FTS_DEFAULT:
+        case FTS_F:
+        case FTS_SL:
+        // `FTS_SLNONE` should never be the case as we don't set
+        // `FTS_COMFOLLOW` or `FTS_LOGICAL`. Adding here for completion.
+        case FTS_SLNONE:
+          if (::unlink(node->fts_path) < 0 && errno != ENOENT) {
+            Error error = ErrnoError();
+            fts_close(tree);
+            return error;
+          }
+          break;
+        default:
+          break;
+      }
+    }
+
+    if (errno != 0) {
+      Error error = ErrnoError();
+      fts_close(tree);
+      return error;
+    }
+
+    if (fts_close(tree) < 0) {
+      return ErrnoError();
+    }
+  }
+
+  return Nothing();
+}
+#endif // __sun
+
+} // namespace os {
+
+
+#endif // __STOUT_OS_POSIX_RMDIR_HPP__

http://git-wip-us.apache.org/repos/asf/mesos/blob/c235f7c1/3rdparty/stout/include/stout/os/posix/sendfile.hpp
----------------------------------------------------------------------
diff --git a/3rdparty/stout/include/stout/os/posix/sendfile.hpp b/3rdparty/stout/include/stout/os/posix/sendfile.hpp
new file mode 100644
index 0000000..c2806fa
--- /dev/null
+++ b/3rdparty/stout/include/stout/os/posix/sendfile.hpp
@@ -0,0 +1,86 @@
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef __STOUT_OS_POSIX_SENDFILE_HPP__
+#define __STOUT_OS_POSIX_SENDFILE_HPP__
+
+#include <errno.h>
+
+#if defined(__linux__) || defined(__sun)
+#include <sys/sendfile.h>
+#endif
+#if defined(__APPLE__) || defined(__FreeBSD__)
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+#endif // __APPLE__ || __FreeBSD__
+
+#include <stout/os/signals.hpp>
+#include <stout/unreachable.hpp>
+
+#include <stout/error.hpp>
+#include <stout/try.hpp>
+
+namespace os {
+
+// Returns the amount of bytes written from the input file
+// descriptor to the output socket. On error,
+// `Try<ssize_t, SocketError>` contains the error.
+// NOTE: The following limitations exist because of the OS X
+// implementation of sendfile:
+//   1. s must be a stream oriented socket descriptor.
+//   2. fd must be a regular file descriptor.
+inline Try<ssize_t, SocketError> sendfile(
+    int s, int fd, off_t offset, size_t length)
+{
+#if defined(__linux__) || defined(__sun)
+  SUPPRESS (SIGPIPE) {
+    // This will set errno to EPIPE if a SIGPIPE occurs.
+    ssize_t sent = ::sendfile(s, fd, &offset, length);
+    if (sent < 0) {
+      return SocketError();
+    }
+
+    return sent;
+  }
+  UNREACHABLE();
+#elif defined __APPLE__
+  // On OS X, sendfile does not need to have SIGPIPE suppressed.
+  off_t _length = static_cast<off_t>(length);
+
+  if (::sendfile(fd, s, offset, &_length, NULL, 0) < 0) {
+    if (errno == EAGAIN && _length > 0) {
+      return _length;
+    }
+    return SocketError();
+  }
+
+  return _length;
+#elif defined __FreeBSD__
+  off_t _length = 0;
+
+  SUPPRESS (SIGPIPE) {
+      if (::sendfile(fd, s, offset, length, NULL, &_length, 0) < 0) {
+        if (errno == EAGAIN && length > 0) {
+          return _length;
+        }
+        return SocketError();
+      }
+  }
+
+  return _length;
+#endif
+}
+
+} // namespace os {
+
+#endif // __STOUT_OS_POSIX_SENDFILE_HPP__

http://git-wip-us.apache.org/repos/asf/mesos/blob/c235f7c1/3rdparty/stout/include/stout/os/posix/shell.hpp
----------------------------------------------------------------------
diff --git a/3rdparty/stout/include/stout/os/posix/shell.hpp b/3rdparty/stout/include/stout/os/posix/shell.hpp
new file mode 100644
index 0000000..b786d47
--- /dev/null
+++ b/3rdparty/stout/include/stout/os/posix/shell.hpp
@@ -0,0 +1,156 @@
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef __STOUT_OS_POSIX_SHELL_HPP__
+#define __STOUT_OS_POSIX_SHELL_HPP__
+
+#include <stdarg.h> // For va_list, va_start, etc.
+#include <stdio.h> // For ferror, fgets, FILE, pclose, popen.
+
+#include <sys/wait.h> // For waitpid.
+
+#include <ostream>
+#include <string>
+
+#include <glog/logging.h>
+
+#include <stout/error.hpp>
+#include <stout/format.hpp>
+#include <stout/try.hpp>
+
+
+namespace os {
+
+namespace Shell {
+
+  // Canonical constants used as platform-dependent args to `exec` calls.
+  // `name` is the command name, `arg0` is the first argument received
+  // by the callee, usually the command name and `arg1` is the second
+  // command argument received by the callee.
+
+  constexpr const char* name = "sh";
+  constexpr const char* arg0 = "sh";
+  constexpr const char* arg1 = "-c";
+
+} // namespace Shell {
+
+/**
+ * Runs a shell command with optional arguments.
+ *
+ * This assumes that a successful execution will result in the exit code
+ * for the command to be `EXIT_SUCCESS`; in this case, the contents
+ * of the `Try` will be the contents of `stdout`.
+ *
+ * If the exit code is non-zero or the process was signaled, we will
+ * return an appropriate error message; but *not* `stderr`.
+ *
+ * If the caller needs to examine the contents of `stderr` it should
+ * be redirected to `stdout` (using, e.g., "2>&1 || true" in the command
+ * string).  The `|| true` is required to obtain a success exit
+ * code in case of errors, and still obtain `stderr`, as piped to
+ * `stdout`.
+ *
+ * @param fmt the formatting string that contains the command to execute
+ *   in the underlying shell.
+ * @param t optional arguments for `fmt`.
+ *
+ * @return the output from running the specified command with the shell; or
+ *   an error message if the command's exit code is non-zero.
+ */
+template <typename... T>
+Try<std::string> shell(const std::string& fmt, const T&... t)
+{
+  const Try<std::string> command = strings::internal::format(fmt, t...);
+  if (command.isError()) {
+    return Error(command.error());
+  }
+
+  FILE* file;
+  std::ostringstream stdout;
+
+  if ((file = popen(command.get().c_str(), "r")) == NULL) {
+    return Error("Failed to run '" + command.get() + "'");
+  }
+
+  char line[1024];
+  // NOTE(vinod): Ideally the if and while loops should be interchanged. But
+  // we get a broken pipe error if we don't read the output and simply close.
+  while (fgets(line, sizeof(line), file) != NULL) {
+    stdout << line;
+  }
+
+  if (ferror(file) != 0) {
+    pclose(file); // Ignoring result since we already have an error.
+    return Error("Error reading output of '" + command.get() + "'");
+  }
+
+  int status;
+  if ((status = pclose(file)) == -1) {
+    return Error("Failed to get status of '" + command.get() + "'");
+  }
+
+  if (WIFSIGNALED(status)) {
+    return Error(
+        "Running '" + command.get() + "' was interrupted by signal '" +
+        strsignal(WTERMSIG(status)) + "'");
+  } else if ((WEXITSTATUS(status) != EXIT_SUCCESS)) {
+    LOG(ERROR) << "Command '" << command.get()
+               << "' failed; this is the output:\n" << stdout.str();
+    return Error(
+        "Failed to execute '" + command.get() + "'; the command was either "
+        "not found or exited with a non-zero exit status: " +
+        stringify(WEXITSTATUS(status)));
+  }
+
+  return stdout.str();
+}
+
+
+// Executes a command by calling "/bin/sh -c <command>", and returns
+// after the command has been completed. Returns 0 if succeeds, and
+// return -1 on error (e.g., fork/exec/waitpid failed). This function
+// is async signal safe. We return int instead of returning a Try
+// because Try involves 'new', which is not async signal safe.
+inline int system(const std::string& command)
+{
+  pid_t pid = ::fork();
+
+  if (pid == -1) {
+    return -1;
+  } else if (pid == 0) {
+    // In child process.
+    ::execlp(
+        Shell::name, Shell::arg0, Shell::arg1, command.c_str(), (char*)NULL);
+    ::exit(127);
+  } else {
+    // In parent process.
+    int status;
+    while (::waitpid(pid, &status, 0) == -1) {
+      if (errno != EINTR) {
+        return -1;
+      }
+    }
+
+    return status;
+  }
+}
+
+
+template<typename... T>
+inline int execlp(const char* file, T... t)
+{
+  return ::execlp(file, t...);
+}
+
+} // namespace os {
+
+#endif // __STOUT_OS_POSIX_SHELL_HPP__

http://git-wip-us.apache.org/repos/asf/mesos/blob/c235f7c1/3rdparty/stout/include/stout/os/posix/signals.hpp
----------------------------------------------------------------------
diff --git a/3rdparty/stout/include/stout/os/posix/signals.hpp b/3rdparty/stout/include/stout/os/posix/signals.hpp
new file mode 100644
index 0000000..f46f591
--- /dev/null
+++ b/3rdparty/stout/include/stout/os/posix/signals.hpp
@@ -0,0 +1,188 @@
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef __STOUT_OS_POSIX_SIGNALS_HPP__
+#define __STOUT_OS_POSIX_SIGNALS_HPP__
+
+#include <errno.h>
+#include <pthread.h>
+#include <signal.h>
+#include <string.h>
+#include <unistd.h>
+
+
+namespace os {
+
+namespace signals {
+
+// Installs the given signal handler.
+inline int install(int signal, void(*handler)(int))
+{
+  struct sigaction action;
+  memset(&action, 0, sizeof(action));
+  sigemptyset(&action.sa_mask);
+  action.sa_handler = handler;
+  return sigaction(signal, &action, NULL);
+}
+
+
+// Resets the signal handler to the default handler of the signal.
+inline int reset(int signal)
+{
+  struct sigaction action;
+  memset(&action, 0, sizeof(action));
+  sigemptyset(&action.sa_mask);
+  action.sa_handler = SIG_DFL;
+  return sigaction(signal, &action, NULL);
+}
+
+
+// Returns true iff the signal is pending.
+inline bool pending(int signal)
+{
+  sigset_t set;
+  sigemptyset(&set);
+  sigpending(&set);
+  return sigismember(&set, signal);
+}
+
+
+// Returns true if the signal has been blocked, or false if the
+// signal was already blocked.
+inline bool block(int signal)
+{
+  sigset_t set;
+  sigemptyset(&set);
+  sigaddset(&set, signal);
+
+  sigset_t oldset;
+  sigemptyset(&oldset);
+
+  // We ignore errors here as the only documented one is
+  // EINVAL due to a bad value of the SIG_* argument.
+  pthread_sigmask(SIG_BLOCK, &set, &oldset);
+
+  return !sigismember(&oldset, signal);
+}
+
+
+// Returns true if the signal has been unblocked, or false if the
+// signal was not previously blocked.
+inline bool unblock(int signal)
+{
+  sigset_t set;
+  sigemptyset(&set);
+  sigaddset(&set, signal);
+
+  sigset_t oldset;
+  sigemptyset(&oldset);
+
+  pthread_sigmask(SIG_UNBLOCK, &set, &oldset);
+
+  return sigismember(&oldset, signal);
+}
+
+namespace internal {
+
+// Suppresses a signal on the current thread for the lifetime of
+// the Suppressor. The signal *must* be synchronous and delivered
+// per-thread. The suppression occurs only on the thread of
+// execution of the Suppressor.
+struct Suppressor
+{
+  Suppressor(int _signal)
+    : signal(_signal), pending(false), unblock(false)
+  {
+    // Check to see if the signal is already reported as pending.
+    // If pending, it means the thread already blocks the signal!
+    // Therefore, any new instances of the signal will also be
+    // blocked and merged with the pending one since there is no
+    // queuing for signals.
+    pending = signals::pending(signal);
+
+    if (!pending) {
+      // Block the signal for this thread only. If already blocked,
+      // there's no need to unblock it.
+      unblock = signals::block(signal);
+    }
+  }
+
+  ~Suppressor()
+  {
+    // We want to preserve errno when the Suppressor drops out of
+    // scope. Otherwise, one needs to potentially store errno when
+    // using the suppress() macro.
+    int _errno = errno;
+
+    // If the signal has become pending after we blocked it, we
+    // need to clear it before unblocking it.
+    if (!pending && signals::pending(signal)) {
+      // It is possible that in between having observed the pending
+      // signal with sigpending() and clearing it with sigwait(),
+      // the signal was delivered to another thread before we were
+      // able to clear it here. This can happen if the signal was
+      // generated for the whole process (e.g. a kill was issued).
+      // See 2.4.1 here:
+      // http://pubs.opengroup.org/onlinepubs/009695399/functions/xsh_chap02_04.html
+      // To handle the above scenario, one can either:
+      //   1. Use sigtimedwait() with a timeout of 0, to ensure we
+      //      don't block forever. However, this only works on Linux
+      //      and we may still swallow the signal intended for the
+      //      process.
+      //   2. After seeing the pending signal, signal ourselves with
+      //      pthread_kill prior to calling sigwait(). This can still
+      //      swallow the signal intended for the process.
+      // We chose to use the latter technique as it works on all
+      // POSIX systems and is less likely to swallow process signals,
+      // provided the thread signal and process signal are not merged.
+
+      // Delivering on this thread an extra time will require an extra sigwait
+      // call on FreeBSD, so we skip it.
+#ifndef __FreeBSD__
+      pthread_kill(pthread_self(), signal);
+#endif
+
+      sigset_t mask;
+      sigemptyset(&mask);
+      sigaddset(&mask, signal);
+
+      int result;
+      do {
+        int _ignored;
+        result = sigwait(&mask, &_ignored);
+      } while (result == -1 && errno == EINTR);
+    }
+
+    // Unblock the signal (only if we were the ones to block it).
+    if (unblock) {
+      signals::unblock(signal);
+    }
+
+    // Restore errno.
+    errno = _errno;
+  }
+
+  // Needed for the suppress() macro.
+  operator bool() { return true; }
+private:
+  const int signal;
+  bool pending; // Whether the signal is already pending.
+  bool unblock; // Whether to unblock the signal on destruction.
+};
+
+} // namespace internal {
+
+} // namespace signals {
+
+} // namespace os {
+
+#endif // __STOUT_OS_POSIX_SIGNALS_HPP__

http://git-wip-us.apache.org/repos/asf/mesos/blob/c235f7c1/3rdparty/stout/include/stout/os/posix/socket.hpp
----------------------------------------------------------------------
diff --git a/3rdparty/stout/include/stout/os/posix/socket.hpp b/3rdparty/stout/include/stout/os/posix/socket.hpp
new file mode 100644
index 0000000..ab5f62a
--- /dev/null
+++ b/3rdparty/stout/include/stout/os/posix/socket.hpp
@@ -0,0 +1,58 @@
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef __STOUT_OS_POSIX_SOCKET_HPP__
+#define __STOUT_OS_POSIX_SOCKET_HPP__
+
+#include <unistd.h>
+
+#include <sys/socket.h>
+#include <sys/stat.h>
+
+namespace net {
+
+// The error indicates the last socket operation has been
+// interupted, the operation can be restarted imediately.
+inline bool is_restartable_error(int error)
+{
+  return (error == EINTR);
+}
+
+
+// The error indicates the last socket function on a non-blocking socket
+// cannot be completed. This is a temporary condition and the caller can
+// retry the operation later.
+inline bool is_retryable_error(int error)
+{
+  return (error ==  EWOULDBLOCK || error == EAGAIN);
+}
+
+
+inline bool is_inprogress_error(int error)
+{
+  return (error == EINPROGRESS);
+}
+
+
+inline bool is_socket(int fd)
+{
+  struct stat statbuf;
+  if (fstat(fd, &statbuf) < 0) {
+    return false;
+  }
+
+  return S_ISSOCK(statbuf.st_mode) != 0;
+}
+
+} // namespace net {
+
+#endif // __STOUT_OS_POSIX_SOCKET_HPP__

http://git-wip-us.apache.org/repos/asf/mesos/blob/c235f7c1/3rdparty/stout/include/stout/os/posix/stat.hpp
----------------------------------------------------------------------
diff --git a/3rdparty/stout/include/stout/os/posix/stat.hpp b/3rdparty/stout/include/stout/os/posix/stat.hpp
new file mode 100644
index 0000000..32fa426
--- /dev/null
+++ b/3rdparty/stout/include/stout/os/posix/stat.hpp
@@ -0,0 +1,175 @@
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef __STOUT_OS_POSIX_STAT_HPP__
+#define __STOUT_OS_POSIX_STAT_HPP__
+
+#include <sys/stat.h>
+#include <sys/statvfs.h>
+
+#include <string>
+
+#include <stout/bytes.hpp>
+#include <stout/try.hpp>
+#include <stout/unreachable.hpp>
+
+
+namespace os {
+
+namespace stat {
+
+inline bool isdir(const std::string& path)
+{
+  struct stat s;
+
+  if (::stat(path.c_str(), &s) < 0) {
+    return false;
+  }
+
+  return S_ISDIR(s.st_mode);
+}
+
+
+inline bool isfile(const std::string& path)
+{
+  struct stat s;
+
+  if (::stat(path.c_str(), &s) < 0) {
+    return false;
+  }
+
+  return S_ISREG(s.st_mode);
+}
+
+
+inline bool islink(const std::string& path)
+{
+  struct stat s;
+
+  if (::lstat(path.c_str(), &s) < 0) {
+    return false;
+  }
+
+  return S_ISLNK(s.st_mode);
+}
+
+
+// Describes the different semantics supported for the implementation
+// of `size` defined below.
+enum FollowSymlink
+{
+  DO_NOT_FOLLOW_SYMLINK,
+  FOLLOW_SYMLINK
+};
+
+
+// Returns the size in Bytes of a given file system entry. When
+// applied to a symbolic link with `follow` set to
+// `DO_NOT_FOLLOW_SYMLINK`, this will return the length of the entry
+// name (strlen).
+inline Try<Bytes> size(
+    const std::string& path,
+    const FollowSymlink follow = FOLLOW_SYMLINK)
+{
+  struct stat s;
+
+  switch (follow) {
+    case DO_NOT_FOLLOW_SYMLINK: {
+      if (::lstat(path.c_str(), &s) < 0) {
+        return ErrnoError("Error invoking lstat for '" + path + "'");
+      } else {
+        return Bytes(s.st_size);
+      }
+      break;
+    }
+    case FOLLOW_SYMLINK: {
+      if (::stat(path.c_str(), &s) < 0) {
+        return ErrnoError("Error invoking stat for '" + path + "'");
+      } else {
+        return Bytes(s.st_size);
+      }
+      break;
+    }
+  }
+
+  UNREACHABLE();
+}
+
+
+inline Try<long> mtime(const std::string& path)
+{
+  struct stat s;
+
+  if (::lstat(path.c_str(), &s) < 0) {
+    return ErrnoError("Error invoking stat for '" + path + "'");
+  }
+
+  return s.st_mtime;
+}
+
+
+inline Try<mode_t> mode(const std::string& path)
+{
+  struct stat s;
+
+  if (::stat(path.c_str(), &s) < 0) {
+    return ErrnoError("Error invoking stat for '" + path + "'");
+  }
+
+  return s.st_mode;
+}
+
+
+inline Try<dev_t> dev(const std::string& path)
+{
+  struct stat s;
+
+  if (::stat(path.c_str(), &s) < 0) {
+    return ErrnoError("Error invoking stat for '" + path + "'");
+  }
+
+  return s.st_dev;
+}
+
+
+inline Try<dev_t> rdev(const std::string& path)
+{
+  struct stat s;
+
+  if (::stat(path.c_str(), &s) < 0) {
+    return ErrnoError("Error invoking stat for '" + path + "'");
+  }
+
+  if (!S_ISCHR(s.st_mode) && !S_ISBLK(s.st_mode)) {
+    return Error("Not a special file: " + path);
+  }
+
+  return s.st_rdev;
+}
+
+
+inline Try<ino_t> inode(const std::string& path)
+{
+  struct stat s;
+
+  if (::stat(path.c_str(), &s) < 0) {
+    return ErrnoError("Error invoking stat for '" + path + "'");
+  }
+
+  return s.st_ino;
+}
+
+} // namespace stat {
+
+} // namespace os {
+
+#endif // __STOUT_OS_STAT_HPP__

http://git-wip-us.apache.org/repos/asf/mesos/blob/c235f7c1/3rdparty/stout/include/stout/os/posix/su.hpp
----------------------------------------------------------------------
diff --git a/3rdparty/stout/include/stout/os/posix/su.hpp b/3rdparty/stout/include/stout/os/posix/su.hpp
new file mode 100644
index 0000000..43e91d6
--- /dev/null
+++ b/3rdparty/stout/include/stout/os/posix/su.hpp
@@ -0,0 +1,216 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef __STOUT_OS_POSIX_SU_HPP__
+#define __STOUT_OS_POSIX_SU_HPP__
+
+#include <string>
+
+#include <grp.h>
+#include <pwd.h>
+
+#include <stout/error.hpp>
+#include <stout/nothing.hpp>
+#include <stout/try.hpp>
+#include <stout/unreachable.hpp>
+
+namespace os {
+
+inline Result<uid_t> getuid(const Option<std::string>& user = None())
+{
+  if (user.isNone()) {
+    return ::getuid();
+  }
+
+  struct passwd passwd;
+  struct passwd* result = NULL;
+
+  int size = sysconf(_SC_GETPW_R_SIZE_MAX);
+  if (size == -1) {
+    // Initial value for buffer size.
+    size = 1024;
+  }
+
+  while (true) {
+    char* buffer = new char[size];
+
+    if (getpwnam_r(user.get().c_str(), &passwd, buffer, size, &result) == 0) {
+      // The usual interpretation of POSIX is that getpwnam_r will
+      // return 0 but set result == NULL if the user is not found.
+      if (result == NULL) {
+        delete[] buffer;
+        return None();
+      }
+
+      uid_t uid = passwd.pw_uid;
+      delete[] buffer;
+      return uid;
+    } else {
+      // RHEL7 (and possibly other systems) will return non-zero and
+      // set one of the following errors for "The given name or uid
+      // was not found." See 'man getpwnam_r'. We only check for the
+      // errors explicitly listed, and do not consider the ellipsis.
+      if (errno == ENOENT ||
+          errno == ESRCH ||
+          errno == EBADF ||
+          errno == EPERM) {
+        delete[] buffer;
+        return None();
+      }
+
+      if (errno != ERANGE) {
+        delete[] buffer;
+        return ErrnoError("Failed to get username information");
+      }
+      // getpwnam_r set ERANGE so try again with a larger buffer.
+      size *= 2;
+      delete[] buffer;
+    }
+  }
+
+  UNREACHABLE();
+}
+
+
+inline Result<gid_t> getgid(const Option<std::string>& user = None())
+{
+  if (user.isNone()) {
+    return ::getgid();
+  }
+
+  struct passwd passwd;
+  struct passwd* result = NULL;
+
+  int size = sysconf(_SC_GETPW_R_SIZE_MAX);
+  if (size == -1) {
+    // Initial value for buffer size.
+    size = 1024;
+  }
+
+  while (true) {
+    char* buffer = new char[size];
+
+    if (getpwnam_r(user.get().c_str(), &passwd, buffer, size, &result) == 0) {
+      // The usual interpretation of POSIX is that getpwnam_r will
+      // return 0 but set result == NULL if the group is not found.
+      if (result == NULL) {
+        delete[] buffer;
+        return None();
+      }
+
+      gid_t gid = passwd.pw_gid;
+      delete[] buffer;
+      return gid;
+    } else {
+      // RHEL7 (and possibly other systems) will return non-zero and
+      // set one of the following errors for "The given name or uid
+      // was not found." See 'man getpwnam_r'. We only check for the
+      // errors explicitly listed, and do not consider the ellipsis.
+      if (errno == ENOENT ||
+          errno == ESRCH ||
+          errno == EBADF ||
+          errno == EPERM) {
+        delete[] buffer;
+        return None();
+      }
+
+      if (errno != ERANGE) {
+        delete[] buffer;
+        return ErrnoError("Failed to get username information");
+      }
+      // getpwnam_r set ERANGE so try again with a larger buffer.
+      size *= 2;
+      delete[] buffer;
+    }
+  }
+
+  UNREACHABLE();
+}
+
+
+inline Result<std::string> user(Option<uid_t> uid = None())
+{
+  if (uid.isNone()) {
+    uid = ::getuid();
+  }
+
+  int size = sysconf(_SC_GETPW_R_SIZE_MAX);
+  if (size == -1) {
+    // Initial value for buffer size.
+    size = 1024;
+  }
+
+  struct passwd passwd;
+  struct passwd* result = NULL;
+
+  while (true) {
+    char* buffer = new char[size];
+
+    if (getpwuid_r(uid.get(), &passwd, buffer, size, &result) == 0) {
+      // getpwuid_r will return 0 but set result == NULL if the uid is
+      // not found.
+      if (result == NULL) {
+        delete[] buffer;
+        return None();
+      }
+
+      std::string user(passwd.pw_name);
+      delete[] buffer;
+      return user;
+    } else {
+      if (errno != ERANGE) {
+        delete[] buffer;
+        return ErrnoError();
+      }
+
+      // getpwuid_r set ERANGE so try again with a larger buffer.
+      size *= 2;
+      delete[] buffer;
+    }
+  }
+}
+
+inline Try<Nothing> su(const std::string& user)
+{
+  Result<gid_t> gid = os::getgid(user);
+  if (gid.isError() || gid.isNone()) {
+    return Error("Failed to getgid: " +
+        (gid.isError() ? gid.error() : "unknown user"));
+  } else if (::setgid(gid.get())) {
+    return ErrnoError("Failed to set gid");
+  }
+
+  // Set the supplementary group list. We ignore EPERM because
+  // performing a no-op call (switching to same group) still
+  // requires being privileged, unlike 'setgid' and 'setuid'.
+  if (::initgroups(user.c_str(), gid.get()) == -1 && errno != EPERM) {
+    return ErrnoError("Failed to set supplementary groups");
+  }
+
+  Result<uid_t> uid = os::getuid(user);
+  if (uid.isError() || uid.isNone()) {
+    return Error("Failed to getuid: " +
+        (uid.isError() ? uid.error() : "unknown user"));
+  } else if (::setuid(uid.get())) {
+    return ErrnoError("Failed to setuid");
+  }
+
+  return Nothing();
+}
+
+} // namespace os {
+
+#endif // __STOUT_OS_POSIX_SU_HPP__

http://git-wip-us.apache.org/repos/asf/mesos/blob/c235f7c1/3rdparty/stout/include/stout/os/posix/write.hpp
----------------------------------------------------------------------
diff --git a/3rdparty/stout/include/stout/os/posix/write.hpp b/3rdparty/stout/include/stout/os/posix/write.hpp
new file mode 100644
index 0000000..fcc9bb6
--- /dev/null
+++ b/3rdparty/stout/include/stout/os/posix/write.hpp
@@ -0,0 +1,30 @@
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef __STOUT_OS_POSIX_WRITE_HPP__
+#define __STOUT_OS_POSIX_WRITE_HPP__
+
+#include <errno.h>
+#include <unistd.h>
+
+
+namespace os {
+
+// Compatibility function. On POSIX, this function is trivial, but on Windows,
+// we have to check whether the file descriptor is a socket or a file to write
+// to it.
+using ::write;
+
+} // namespace os {
+
+
+#endif // __STOUT_OS_POSIX_READ_HPP__

http://git-wip-us.apache.org/repos/asf/mesos/blob/c235f7c1/3rdparty/stout/include/stout/os/process.hpp
----------------------------------------------------------------------
diff --git a/3rdparty/stout/include/stout/os/process.hpp b/3rdparty/stout/include/stout/os/process.hpp
new file mode 100644
index 0000000..a91a9d4
--- /dev/null
+++ b/3rdparty/stout/include/stout/os/process.hpp
@@ -0,0 +1,177 @@
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef __STOUT_OS_PROCESS_HPP__
+#define __STOUT_OS_PROCESS_HPP__
+
+#include <sys/types.h> // For pid_t.
+
+#include <list>
+#include <ostream>
+#include <sstream>
+#include <string>
+
+#include <stout/bytes.hpp>
+#include <stout/duration.hpp>
+#include <stout/none.hpp>
+#include <stout/option.hpp>
+#include <stout/strings.hpp>
+
+
+namespace os {
+
+struct Process
+{
+  Process(pid_t _pid,
+          pid_t _parent,
+          pid_t _group,
+          const Option<pid_t>& _session,
+          const Option<Bytes>& _rss,
+          const Option<Duration>& _utime,
+          const Option<Duration>& _stime,
+          const std::string& _command,
+          bool _zombie)
+    : pid(_pid),
+      parent(_parent),
+      group(_group),
+      session(_session),
+      rss(_rss),
+      utime(_utime),
+      stime(_stime),
+      command(_command),
+      zombie(_zombie) {}
+
+  const pid_t pid;
+  const pid_t parent;
+  const pid_t group;
+  const Option<pid_t> session;
+  const Option<Bytes> rss;
+  const Option<Duration> utime;
+  const Option<Duration> stime;
+  const std::string command;
+  const bool zombie;
+
+  // TODO(bmahler): Add additional data as needed.
+
+  bool operator<(const Process& p) const { return pid < p.pid; }
+  bool operator<=(const Process& p) const { return pid <= p.pid; }
+  bool operator>(const Process& p) const { return pid > p.pid; }
+  bool operator>=(const Process& p) const { return pid >= p.pid; }
+  bool operator==(const Process& p) const { return pid == p.pid; }
+  bool operator!=(const Process& p) const { return pid != p.pid; }
+};
+
+
+class ProcessTree
+{
+public:
+  // Returns a process subtree rooted at the specified PID, or none if
+  // the specified pid could not be found in this process tree.
+  Option<ProcessTree> find(pid_t pid) const
+  {
+    if (process.pid == pid) {
+      return *this;
+    }
+
+    foreach (const ProcessTree& tree, children) {
+      Option<ProcessTree> option = tree.find(pid);
+      if (option.isSome()) {
+        return option;
+      }
+    }
+
+    return None();
+  }
+
+  // Checks if the specified pid is contained in this process tree.
+  bool contains(pid_t pid) const
+  {
+    return find(pid).isSome();
+  }
+
+  operator Process() const
+  {
+    return process;
+  }
+
+  operator pid_t() const
+  {
+    return process.pid;
+  }
+
+  const Process process;
+  const std::list<ProcessTree> children;
+
+private:
+  friend struct Fork;
+  friend Try<ProcessTree> pstree(pid_t, const std::list<Process>&);
+
+  ProcessTree(
+      const Process& _process,
+      const std::list<ProcessTree>& _children)
+    : process(_process),
+      children(_children) {}
+};
+
+
+inline std::ostream& operator<<(std::ostream& stream, const ProcessTree& tree)
+{
+  if (tree.children.empty()) {
+    stream << "--- " << tree.process.pid << " ";
+    if (tree.process.zombie) {
+      stream << "(" << tree.process.command << ")";
+    } else {
+      stream << tree.process.command;
+    }
+  } else {
+    stream << "-+- " << tree.process.pid << " ";
+    if (tree.process.zombie) {
+      stream << "(" << tree.process.command << ")";
+    } else {
+      stream << tree.process.command;
+    }
+    size_t size = tree.children.size();
+    foreach (const ProcessTree& child, tree.children) {
+      std::ostringstream out;
+      out << child;
+      stream << "\n";
+      if (--size != 0) {
+        stream << " |" << strings::replace(out.str(), "\n", "\n |");
+      } else {
+        stream << " \\" << strings::replace(out.str(), "\n", "\n  ");
+      }
+    }
+  }
+  return stream;
+}
+
+} // namespace os {
+
+
+// An overload of stringify for printing a list of process trees
+// (since printing a process tree is rather particular).
+inline std::string stringify(const std::list<os::ProcessTree>& list)
+{
+  std::ostringstream out;
+  out << "[ " << std::endl;
+  std::list<os::ProcessTree>::const_iterator iterator = list.begin();
+  while (iterator != list.end()) {
+    out << stringify(*iterator);
+    if (++iterator != list.end()) {
+      out << std::endl << std::endl;
+    }
+  }
+  out << std::endl << "]";
+  return out.str();
+}
+
+#endif // __STOUT_OS_PROCESS_HPP__

http://git-wip-us.apache.org/repos/asf/mesos/blob/c235f7c1/3rdparty/stout/include/stout/os/pstree.hpp
----------------------------------------------------------------------
diff --git a/3rdparty/stout/include/stout/os/pstree.hpp b/3rdparty/stout/include/stout/os/pstree.hpp
new file mode 100644
index 0000000..fe382a1
--- /dev/null
+++ b/3rdparty/stout/include/stout/os/pstree.hpp
@@ -0,0 +1,131 @@
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef __STOUT_OS_PSTREE_HPP__
+#define __STOUT_OS_PSTREE_HPP__
+
+#include <list>
+#include <set>
+
+#include <stout/error.hpp>
+#include <stout/foreach.hpp>
+#include <stout/none.hpp>
+#include <stout/option.hpp>
+#include <stout/stringify.hpp>
+#include <stout/try.hpp>
+
+#include <stout/os/process.hpp>
+
+
+namespace os {
+
+// Forward declaration.
+inline Try<std::list<Process>> processes();
+
+
+// Returns a process tree rooted at the specified pid using the
+// specified list of processes (or an error if one occurs).
+inline Try<ProcessTree> pstree(
+    pid_t pid,
+    const std::list<Process>& processes)
+{
+  std::list<ProcessTree> children;
+  foreach (const Process& process, processes) {
+    if (process.parent == pid) {
+      Try<ProcessTree> tree = pstree(process.pid, processes);
+      if (tree.isError()) {
+        return Error(tree.error());
+      }
+      children.push_back(tree.get());
+    }
+  }
+
+  foreach (const Process& process, processes) {
+    if (process.pid == pid) {
+      return ProcessTree(process, children);
+    }
+  }
+
+  return Error("No process found at " + stringify(pid));
+}
+
+
+// Returns a process tree for the specified pid (or all processes if
+// pid is none or the current process if pid is 0).
+inline Try<ProcessTree> pstree(Option<pid_t> pid = None())
+{
+  if (pid.isNone()) {
+    pid = 1;
+  } else if (pid.get() == 0) {
+    pid = getpid();
+  }
+
+  const Try<std::list<Process>> processes = os::processes();
+
+  if (processes.isError()) {
+    return Error(processes.error());
+  }
+
+  return pstree(pid.get(), processes.get());
+}
+
+
+// Returns the minimum list of process trees that include all of the
+// specified pids using the specified list of processes.
+inline Try<std::list<ProcessTree>> pstrees(
+    const std::set<pid_t>& pids,
+    const std::list<Process>& processes)
+{
+  std::list<ProcessTree> trees;
+
+  foreach (pid_t pid, pids) {
+    // First, check if the pid is already connected to one of the
+    // process trees we've constructed.
+    bool disconnected = true;
+    foreach (const ProcessTree& tree, trees) {
+      if (tree.contains(pid)) {
+        disconnected = false;
+        break;
+      }
+    }
+
+    if (disconnected) {
+      Try<ProcessTree> tree = pstree(pid, processes);
+      if (tree.isError()) {
+        return Error(tree.error());
+      }
+
+      // Now see if any of the existing process trees are actually
+      // contained within the process tree we just created and only
+      // include the disjoint process trees.
+      // C++11:
+      // trees = trees.filter([](const ProcessTree& t) {
+      //   return tree.get().contains(t);
+      // });
+      std::list<ProcessTree> trees_ = trees;
+      trees.clear();
+      foreach (const ProcessTree& t, trees_) {
+        if (tree.get().contains(t.process.pid)) {
+          continue;
+        }
+        trees.push_back(t);
+      }
+      trees.push_back(tree.get());
+    }
+  }
+
+  return trees;
+}
+
+} // namespace os {
+
+#endif // __STOUT_OS_PSTREE_HPP__

http://git-wip-us.apache.org/repos/asf/mesos/blob/c235f7c1/3rdparty/stout/include/stout/os/raw/environment.hpp
----------------------------------------------------------------------
diff --git a/3rdparty/stout/include/stout/os/raw/environment.hpp b/3rdparty/stout/include/stout/os/raw/environment.hpp
new file mode 100644
index 0000000..80cc45b
--- /dev/null
+++ b/3rdparty/stout/include/stout/os/raw/environment.hpp
@@ -0,0 +1,79 @@
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef __STOUT_OS_RAW_ENVIRONMENT_HPP__
+#define __STOUT_OS_RAW_ENVIRONMENT_HPP__
+
+#ifdef __APPLE__
+#include <crt_externs.h> // For _NSGetEnviron().
+#elif !defined(__WINDOWS__)
+// Need to declare 'environ' pointer for platforms that are not OS X or Windows.
+extern char** environ;
+#endif
+
+
+// NOTE: the `os::raw` namespace contains a family of simple wrapper functions
+// for getting environment data from either Windows or Unix machines. For
+// example, `os::raw::environment` returns an "unstructured" `char**` that
+// contains the raw environment variables of the executing process. Accessing
+// "structured" version of this function, `os::environment`, returns a
+// `map<string, string>` instead. This family of functions exists in the
+// `os::raw` namespace because of the unstructured nature of their return
+// values.
+//
+// WARNING: these functions are called `environment` and not `environ` because
+// on Windows, `environ` is a macro, and not an `extern char**` as it is in the
+// POSIX standard. The existance of this macro on Windows makes it impossible
+// to use a function called `os::environ`.
+namespace os {
+namespace raw {
+
+inline char** environment()
+{
+  // Accessing the list of environment variables is platform-specific.
+  // On OS X, the 'environ' symbol isn't visible to shared libraries,
+  // so we must use the _NSGetEnviron() function (see 'man environ' on
+  // OS X). On other platforms, it's fine to access 'environ' from
+  // shared libraries.
+#ifdef __APPLE__
+  return *_NSGetEnviron();
+#else
+  // NOTE: the correct style for this expression would be `::environ`, but we
+  // leave it out because `environ` is a macro on Windows, and the `::` will
+  // break the build.
+  return environ;
+#endif
+}
+
+
+// Returns the address of os::environment().
+inline char*** environmentp()
+{
+  // Accessing the list of environment variables is platform-specific.
+  // On OS X, the 'environ' symbol isn't visible to shared libraries,
+  // so we must use the _NSGetEnviron() function (see 'man environ' on
+  // OS X). On other platforms, it's fine to access 'environ' from
+  // shared libraries.
+#ifdef __APPLE__
+  return _NSGetEnviron();
+#else
+  // NOTE: the correct style for this expression would be `environ`, but we
+  // leave it out because `environ` is a macro on Windows, and the `::` will
+  // break the build.
+  return &environ;
+#endif
+}
+
+} // namespace raw {
+} // namespace os {
+
+#endif // __STOUT_OS_RAW_ENVIRONMENT_HPP__

http://git-wip-us.apache.org/repos/asf/mesos/blob/c235f7c1/3rdparty/stout/include/stout/os/read.hpp
----------------------------------------------------------------------
diff --git a/3rdparty/stout/include/stout/os/read.hpp b/3rdparty/stout/include/stout/os/read.hpp
new file mode 100644
index 0000000..e1e97c1
--- /dev/null
+++ b/3rdparty/stout/include/stout/os/read.hpp
@@ -0,0 +1,147 @@
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef __STOUT_OS_READ_HPP__
+#define __STOUT_OS_READ_HPP__
+
+#include <stdio.h>
+#ifndef __WINDOWS__
+#include <unistd.h>
+#endif // __WINDOWS__
+
+#include <string>
+
+#if defined(__sun) || defined(__WINDOWS__)
+#include <fstream>
+#endif // __sun || __WINDOWS__
+
+#include <stout/error.hpp>
+#include <stout/result.hpp>
+#include <stout/try.hpp>
+#ifdef __WINDOWS__
+#include <stout/windows.hpp>
+#endif // __WINDOWS__
+
+#include <stout/os/socket.hpp>
+#ifdef __WINDOWS__
+#include <stout/os/windows/read.hpp>
+#else
+#include <stout/os/posix/read.hpp>
+#endif // __WINDOWS__
+
+
+namespace os {
+
+// Reads 'size' bytes from a file from its current offset.
+// If EOF is encountered before reading 'size' bytes then the result
+// will contain the bytes read and a subsequent read will return None.
+inline Result<std::string> read(int fd, size_t size)
+{
+  char* buffer = new char[size];
+  size_t offset = 0;
+
+  while (offset < size) {
+    ssize_t length = os::read(fd, buffer + offset, size - offset);
+
+#ifdef __WINDOWS__
+      int error = WSAGetLastError();
+#else
+      int error = errno;
+#endif // __WINDOWS__
+
+    if (length < 0) {
+      // TODO(bmahler): Handle a non-blocking fd? (EAGAIN, EWOULDBLOCK)
+      if (net::is_restartable_error(error)) {
+        continue;
+      }
+      ErrnoError error; // Constructed before 'delete' to capture errno.
+      delete[] buffer;
+      return error;
+    } else if (length == 0) {
+      // Reached EOF before expected! Only return as much data as
+      // available or None if we haven't read anything yet.
+      if (offset > 0) {
+        std::string result(buffer, offset);
+        delete[] buffer;
+        return result;
+      }
+      delete[] buffer;
+      return None();
+    }
+
+    offset += length;
+  }
+
+  std::string result(buffer, size);
+  delete[] buffer;
+  return result;
+}
+
+
+// Returns the contents of the file. NOTE: getline is not available on Solaris
+// or Windows, so we use STL.
+#if defined(__sun) || defined(__WINDOWS__)
+inline Try<std::string> read(const std::string& path)
+{
+  std::ifstream file(path.c_str());
+  if (!file.is_open()) {
+    // Does ifstream actually set errno?
+    return ErrnoError("Failed to open file '" + path + "'");
+  }
+  return std::string((std::istreambuf_iterator<char>(file)),
+                     (std::istreambuf_iterator<char>()));
+}
+#else
+inline Try<std::string> read(const std::string& path)
+{
+  FILE* file = fopen(path.c_str(), "r");
+  if (file == NULL) {
+    return ErrnoError("Failed to open file '" + path + "'");
+  }
+
+  // Initially the 'line' is NULL and length 0, getline() allocates
+  // ('malloc') a buffer for reading the line.
+  // In subsequent iterations, if the buffer is not large enough to
+  // hold the line, getline() resizes it with 'realloc' and updates
+  // 'line' and 'length' as necessary. See:
+  // - http://pubs.opengroup.org/onlinepubs/9699919799/functions/getline.html
+  // - http://man7.org/linux/man-pages/man3/getline.3.html
+  std::string result;
+  char* line = NULL;
+  size_t length = 0;
+  ssize_t read;
+
+  while ((read = getline(&line, &length, file)) != -1) {
+    result.append(line, read);
+  }
+
+  // getline() requires the line buffer to be freed by the caller.
+  free(line);
+
+  if (ferror(file)) {
+    ErrnoError error;
+    // NOTE: We ignore the error from fclose(). This is because
+    // users calling this function are interested in the return value
+    // of read(). Also an unsuccessful fclose() does not affect the
+    // read.
+    fclose(file);
+    return error;
+  }
+
+  fclose(file);
+  return result;
+}
+#endif // __sun || __WINDOWS__
+
+} // namespace os {
+
+#endif // __STOUT_OS_READ_HPP__

http://git-wip-us.apache.org/repos/asf/mesos/blob/c235f7c1/3rdparty/stout/include/stout/os/realpath.hpp
----------------------------------------------------------------------
diff --git a/3rdparty/stout/include/stout/os/realpath.hpp b/3rdparty/stout/include/stout/os/realpath.hpp
new file mode 100644
index 0000000..c368309
--- /dev/null
+++ b/3rdparty/stout/include/stout/os/realpath.hpp
@@ -0,0 +1,40 @@
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef __STOUT_OS_REALPATH_HPP__
+#define __STOUT_OS_REALPATH_HPP__
+
+
+#include <stout/result.hpp>
+
+#ifdef __WINDOWS__
+#include <stout/windows.hpp>
+#endif
+
+
+namespace os {
+
+inline Result<std::string> realpath(const std::string& path)
+{
+  char temp[PATH_MAX];
+  if (::realpath(path.c_str(), temp) == NULL) {
+    if (errno == ENOENT || errno == ENOTDIR) {
+      return None();
+    }
+    return ErrnoError();
+  }
+  return std::string(temp);
+}
+
+} // namespace os {
+
+#endif // __STOUT_OS_REALPATH_HPP__

http://git-wip-us.apache.org/repos/asf/mesos/blob/c235f7c1/3rdparty/stout/include/stout/os/rename.hpp
----------------------------------------------------------------------
diff --git a/3rdparty/stout/include/stout/os/rename.hpp b/3rdparty/stout/include/stout/os/rename.hpp
new file mode 100644
index 0000000..8a4e084
--- /dev/null
+++ b/3rdparty/stout/include/stout/os/rename.hpp
@@ -0,0 +1,22 @@
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//  http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef __STOUT_OS_RENAME_HPP__
+#define __STOUT_OS_RENAME_HPP__
+
+#ifdef __WINDOWS__
+#include <stout/os/windows/rename.hpp>
+#else
+#include <stout/os/posix/rename.hpp>
+#endif // __WINDOWS__
+
+#endif // __STOUT_OS_RENAME_HPP__