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__