You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mesos.apache.org by bm...@apache.org on 2016/05/19 06:28:53 UTC

[1/6] mesos git commit: Rewrote os::read() to be friendlier to reading binary data.

Repository: mesos
Updated Branches:
  refs/heads/master 4248b3c3a -> fc4507da5


Rewrote os::read() to be friendlier to reading binary data.

The previous read() implementation was based on calling getline() to
read in chunks of data from a file. This is fine for text-based files,
but is a little strange for binary files.

The new implementation reads in chunks of raw bytes into a buffer
before copying them into their final location.

Review: https://reviews.apache.org/r/47481/


Project: http://git-wip-us.apache.org/repos/asf/mesos/repo
Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/d9d65089
Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/d9d65089
Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/d9d65089

Branch: refs/heads/master
Commit: d9d65089134c0849b362a78e7cb071c0b26dd616
Parents: 9b4949f
Author: Kevin Klues <kl...@gmail.com>
Authored: Wed May 18 15:55:37 2016 -0700
Committer: Benjamin Mahler <bm...@apache.org>
Committed: Wed May 18 16:25:27 2016 -0700

----------------------------------------------------------------------
 3rdparty/stout/include/stout/os/read.hpp | 56 ++++++++++++++-------------
 1 file changed, 29 insertions(+), 27 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/d9d65089/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
index 002b13b..c39140f 100644
--- a/3rdparty/stout/include/stout/os/read.hpp
+++ b/3rdparty/stout/include/stout/os/read.hpp
@@ -13,6 +13,7 @@
 #ifndef __STOUT_OS_READ_HPP__
 #define __STOUT_OS_READ_HPP__
 
+#include <assert.h>
 #include <stdio.h>
 #ifndef __WINDOWS__
 #include <unistd.h>
@@ -103,41 +104,42 @@ inline Try<std::string> read(const std::string& path)
 #else
 inline Try<std::string> read(const std::string& path)
 {
-  FILE* file = fopen(path.c_str(), "r");
+  FILE* file = ::fopen(path.c_str(), "r");
   if (file == NULL) {
     return ErrnoError("Failed to open file");
   }
 
-  // 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
+  // Use a buffer to read the file in BUFSIZ
+  // chunks and append it to the string we return.
+  //
+  // NOTE: We aren't able to use fseek() / ftell() here
+  // to find the file size because these functions don't
+  // work properly for in-memory files like /proc/*/stat.
+  char* buffer = new char[BUFSIZ];
   std::string result;
-  char* line = NULL;
-  size_t length = 0;
-  ssize_t read;
 
-  while ((read = getline(&line, &length, file)) != -1) {
-    result.append(line, read);
-  }
+  while (true) {
+    size_t read = ::fread(buffer, 1, BUFSIZ, file);
 
-  // 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;
-  }
+    if (::ferror(file)) {
+      // NOTE: ferror() will not modify errno if the stream
+      // is valid, which is the case here since it is open.
+      ErrnoError error;
+      delete buffer;
+      ::fclose(file);
+      return error;
+    }
+
+    result.append(buffer, read);
+
+    if (read != BUFSIZ) {
+      assert(feof(file));
+      break;
+    }
+  };
 
-  fclose(file);
+  ::fclose(file);
+  delete buffer;
   return result;
 }
 #endif // __sun || __WINDOWS__


[3/6] mesos git commit: Added preliminary support for parsing ELF files in stout.

Posted by bm...@apache.org.
Added preliminary support for parsing ELF files in stout.

Right now we are able to parse ELF formatted shared libraries and
extract their canonical SONAME and external library dependencies. In
the future, we should add support for fully parsing an ELf file for
easy access to all of its contents.

The current implementation relies on libelf. We should probably remove
this dependency in future versions (mostly since the headers for
libelf are not installed on a standard Linux distribution by default).

Review: https://reviews.apache.org/r/47482/


Project: http://git-wip-us.apache.org/repos/asf/mesos/repo
Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/12a9c4eb
Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/12a9c4eb
Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/12a9c4eb

Branch: refs/heads/master
Commit: 12a9c4ebf7c7894e0847eb2eec4bf0a101a82168
Parents: d9d6508
Author: Kevin Klues <kl...@gmail.com>
Authored: Wed May 18 16:32:14 2016 -0700
Committer: Benjamin Mahler <bm...@apache.org>
Committed: Wed May 18 21:17:29 2016 -0700

----------------------------------------------------------------------
 3rdparty/stout/configure.ac          |   1 +
 3rdparty/stout/include/stout/elf.hpp | 236 ++++++++++++++++++++++++++++++
 2 files changed, 237 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/12a9c4eb/3rdparty/stout/configure.ac
----------------------------------------------------------------------
diff --git a/3rdparty/stout/configure.ac b/3rdparty/stout/configure.ac
index ada1e22..52b4a05 100644
--- a/3rdparty/stout/configure.ac
+++ b/3rdparty/stout/configure.ac
@@ -151,6 +151,7 @@ fi
 case "${target_os}" in
   linux*)
     LIBS="$LIBS -lrt" # For clock_gettime() in stout/stopwatch.hpp.
+    LIBS="$LIBS -lelf" # For stout/elf.hpp.
     OS_NAME=linux # Used below for OS_LINUX.
     ;;
   darwin*)

http://git-wip-us.apache.org/repos/asf/mesos/blob/12a9c4eb/3rdparty/stout/include/stout/elf.hpp
----------------------------------------------------------------------
diff --git a/3rdparty/stout/include/stout/elf.hpp b/3rdparty/stout/include/stout/elf.hpp
new file mode 100644
index 0000000..e1f0b61
--- /dev/null
+++ b/3rdparty/stout/include/stout/elf.hpp
@@ -0,0 +1,236 @@
+// 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_ELF_HPP__
+#define __STOUT_ELF_HPP__
+
+#include <fcntl.h>
+#include <gelf.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include <stout/error.hpp>
+#include <stout/foreach.hpp>
+#include <stout/nothing.hpp>
+#include <stout/option.hpp>
+#include <stout/stringify.hpp>
+#include <stout/try.hpp>
+
+namespace elf {
+
+enum Class {
+  CLASSNONE = ELFCLASSNONE,
+  CLASS32 = ELFCLASS32,
+  CLASS64 = ELFCLASS64,
+};
+
+enum class SectionType {
+  DYNAMIC = SHT_DYNAMIC,
+};
+
+enum class DynamicTag {
+  STRTAB = DT_STRTAB,
+  SONAME = DT_SONAME,
+  NEEDED = DT_NEEDED,
+};
+
+// This class is used to represent the contents of a standard ELF
+// binary. The current implementation is incomplete.
+//
+// TODO(klueska): For now, we only include functionality to extract
+// the SONAME from shared libraries and read their external library
+// dependencies. In the future, we will expand this class to include
+// helpers for full access to an ELF file's contents.
+class File {
+public:
+  // Open an ELF binary. We do some preliminary parsing as part of
+  // opening the ELF to get quick references to all of its internal
+  // sections for all future calls.
+  //
+  // TODO(klueska): Consider adding a 'stout::Owned' type to avoid
+  // returning a raw pointer here.
+  static Try<File*> open(const std::string& path)
+  {
+    // Set the elf library operating version.
+    if (elf_version(EV_CURRENT) == EV_NONE) {
+      return Error("Failed to set ELF library version: " +
+                   stringify(elf_errmsg(-1)));
+    }
+
+    File* file = new File();
+
+    file->fd = ::open(path.c_str(), O_RDONLY);
+    if (file->fd < 0) {
+      delete file;
+      return ErrnoError("Failed to open file");
+    }
+
+    file->elf = elf_begin(file->fd, ELF_C_READ, NULL);
+    if (file->elf == NULL) {
+      delete file;
+      return Error("elf_begin() failed: " + stringify(elf_errmsg(-1)));
+    }
+
+    if (elf_kind(file->elf) != ELF_K_ELF) {
+      delete file;
+      return Error("File is not an ELF binary");
+    }
+
+    // Create the mapping from section type to section locations.
+    Elf_Scn* section = NULL;
+    while ((section = elf_nextscn(file->elf, section)) != NULL) {
+      GElf_Shdr section_header;
+      if (gelf_getshdr(section, &section_header) == NULL) {
+        delete file;
+        return Error("gelf_getshdr() failed: " + stringify(elf_errmsg(-1)));
+      }
+
+      SectionType section_type = (SectionType) section_header.sh_type;
+      switch (section_type) {
+        case SectionType::DYNAMIC:
+          file->sections[section_type].push_back(section);
+      }
+    }
+
+    return file;
+  }
+
+  void close()
+  {
+    if (elf != NULL) {
+      elf_end(elf);
+      elf = NULL;
+    }
+
+    if (fd >= 0) {
+      ::close(fd);
+      fd = -1;
+    }
+  }
+
+  ~File()
+  {
+    close();
+  };
+
+
+  // Returns the ELF class of an
+  // ELF file (CLASS32, or CLASS64).
+  Try<Class> GetClass() const
+  {
+    Class c = (Class)gelf_getclass(elf);
+    if (c == CLASSNONE) {
+      return Error("gelf_getclass() failed: " + stringify(elf_errmsg(-1)));
+    }
+    return c;
+  }
+
+
+  // Extract the strings associated with the provided `DynamicTag`
+  // from the DYNAMIC section of the ELF binary.
+  Try<std::vector<std::string>> GetDynamicStrings(DynamicTag tag) const
+  {
+    if (sections.count(SectionType::DYNAMIC) == 0) {
+      return Error("No DYNAMIC sections found in ELF");
+    }
+
+    if (sections.count(SectionType::DYNAMIC) != 1) {
+      return Error("Multiple DYNAMIC sections found in ELF");
+    }
+
+    Elf_Scn* dynamic_section = sections.at(SectionType::DYNAMIC)[0];
+
+    // Walk through the entries in the dynamic section and look for
+    // entries with the provided tag. These entries contain offsets to
+    // strings in the dynamic section's string table. Consequently, we
+    // also have to look for an entry containing a pointer to the
+    // dynamic section's string table so we can resolve the strings
+    // associated with the provided tag later on.
+    Elf_Data* dynamic_data = elf_getdata(dynamic_section, NULL);
+    if (dynamic_data == NULL) {
+      return Error("elf_getdata() failed: " + stringify(elf_errmsg(-1)));
+    }
+
+    Option<uintptr_t> strtab_pointer = None();
+    std::vector<uintptr_t> strtab_offsets;
+
+    for (size_t i = 0; i < dynamic_data->d_size / sizeof(GElf_Dyn); i++) {
+      GElf_Dyn entry;
+      if (gelf_getdyn(dynamic_data, i, &entry) == NULL) {
+          return Error("gelf_getdyn() failed: " + stringify(elf_errmsg(-1)));
+      }
+
+      if ((DynamicTag)entry.d_tag == DynamicTag::STRTAB) {
+        strtab_pointer = entry.d_un.d_ptr;
+      }
+
+      if ((DynamicTag)entry.d_tag == tag) {
+        strtab_offsets.push_back(entry.d_un.d_ptr);
+      }
+    }
+
+    if (strtab_offsets.empty()) {
+      return std::vector<std::string>();
+    }
+
+    if (strtab_pointer.isNone()) {
+      return Error("Failed to find string table");
+    }
+
+    // Get a reference to the actual string table so we can index into it.
+    Elf_Scn* string_table_section = gelf_offscn(elf, strtab_pointer.get());
+    if (string_table_section == NULL) {
+      return Error("gelf_offscn() failed: " + stringify(elf_errmsg(-1)));
+    }
+
+    size_t strtab_index = elf_ndxscn(string_table_section);
+    if (strtab_index == SHN_UNDEF) {
+      return Error("elf_ndxscn() failed: " + stringify(elf_errmsg(-1)));
+    }
+
+    // Find the strings in the string table from their offsets and return them.
+    std::vector<std::string> strings;
+    foreach (uintptr_t offset, strtab_offsets) {
+      char* string = elf_strptr(elf, strtab_index, offset);
+      if (string == NULL) {
+        return Error("elf_strptr() failed: " + stringify(elf_errmsg(-1)));
+      }
+
+      strings.push_back(string);
+    }
+
+    return strings;
+  }
+
+private:
+  explicit File()
+    : fd(-1),
+      elf(NULL) {}
+
+  int fd;
+  Elf* elf;
+  std::map<SectionType, std::vector<Elf_Scn*>> sections;
+};
+
+} // namespace elf {
+
+#endif // __STOUT_ELF_HPP__


[2/6] mesos git commit: Updated os::read error messages to exclude caller-available information.

Posted by bm...@apache.org.
Updated os::read error messages to exclude caller-available information.

Previously os::read was returning the path provided by the caller
in the error messages when the file cannot be opened. Our error
composition pattern is to exclude caller-available information
in the callee to avoid redundant error logging.


Project: http://git-wip-us.apache.org/repos/asf/mesos/repo
Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/9b4949f2
Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/9b4949f2
Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/9b4949f2

Branch: refs/heads/master
Commit: 9b4949f255ea7a3d59e73dccc1943ed2f17e7087
Parents: 4248b3c
Author: Benjamin Mahler <bm...@apache.org>
Authored: Wed May 18 16:18:51 2016 -0700
Committer: Benjamin Mahler <bm...@apache.org>
Committed: Wed May 18 16:25:27 2016 -0700

----------------------------------------------------------------------
 3rdparty/stout/include/stout/os/read.hpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/9b4949f2/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
index e1e97c1..002b13b 100644
--- a/3rdparty/stout/include/stout/os/read.hpp
+++ b/3rdparty/stout/include/stout/os/read.hpp
@@ -95,7 +95,7 @@ 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 ErrnoError("Failed to open file");
   }
   return std::string((std::istreambuf_iterator<char>(file)),
                      (std::istreambuf_iterator<char>()));
@@ -105,7 +105,7 @@ 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 + "'");
+    return ErrnoError("Failed to open file");
   }
 
   // Initially the 'line' is NULL and length 0, getline() allocates


[6/6] mesos git commit: Added utility for parsing ld.so.cache on linux.

Posted by bm...@apache.org.
Added utility for parsing ld.so.cache on linux.

Review: https://reviews.apache.org/r/47485/


Project: http://git-wip-us.apache.org/repos/asf/mesos/repo
Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/fc4507da
Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/fc4507da
Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/fc4507da

Branch: refs/heads/master
Commit: fc4507da5570ce0049258b725d0a7220ca05182f
Parents: aa81845
Author: Kevin Klues <kl...@gmail.com>
Authored: Wed May 18 21:08:29 2016 -0700
Committer: Benjamin Mahler <bm...@apache.org>
Committed: Wed May 18 23:26:21 2016 -0700

----------------------------------------------------------------------
 configure.ac                |   8 ++
 src/Makefile.am             |   4 +
 src/linux/ldcache.cpp       | 244 +++++++++++++++++++++++++++++++++++++++
 src/linux/ldcache.hpp       |  38 ++++++
 src/tests/ldcache_tests.cpp |  72 ++++++++++++
 5 files changed, 366 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/fc4507da/configure.ac
----------------------------------------------------------------------
diff --git a/configure.ac b/configure.ac
index 0bae999..f61ff77 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1285,6 +1285,14 @@ if test x"$enable_nvidia_gpu_support" = "xyes"; then
     LDFLAGS="-L${with_nvml_lib} $LDFLAGS"
   fi
 
+  AC_CHECK_HEADERS([elf.h], [],
+                   [AC_MSG_ERROR([Cannot find the libelf headers
+-------------------------------------------------------------------
+The libelf headers are required to build Mesos with Nvidia
+GPU support. Make sure these headers are installed on the system.
+-------------------------------------------------------------------
+  ])])
+
   AC_CHECK_HEADERS([nvidia/gdk/nvml.h], [],
                    [AC_MSG_ERROR([Cannot find the Nvidia NVML headers
 -------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/mesos/blob/fc4507da/src/Makefile.am
----------------------------------------------------------------------
diff --git a/src/Makefile.am b/src/Makefile.am
index 571d2a5..705f132 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -941,6 +941,7 @@ libmesos_no_3rdparty_la_SOURCES +=					\
 MESOS_LINUX_FILES =							\
   linux/cgroups.cpp							\
   linux/fs.cpp								\
+  linux/ldcache.cpp							\
   linux/perf.cpp							\
   linux/systemd.cpp							\
   slave/containerizer/mesos/linux_launcher.cpp				\
@@ -960,6 +961,7 @@ MESOS_LINUX_FILES =							\
 MESOS_LINUX_FILES +=							\
   linux/cgroups.hpp							\
   linux/fs.hpp								\
+  linux/ldcache.hpp							\
   linux/ns.hpp								\
   linux/perf.hpp							\
   linux/sched.hpp							\
@@ -2047,6 +2049,7 @@ mesos_tests_DEPENDENCIES =					\
 
 if OS_LINUX
 mesos_tests_SOURCES +=						\
+  tests/ldcache_tests.cpp				 	\
   tests/containerizer/cgroups_isolator_tests.cpp		\
   tests/containerizer/cgroups_tests.cpp				\
   tests/containerizer/docker_volume_isolator_tests.cpp		\
@@ -2069,6 +2072,7 @@ endif
 
 if ENABLE_NVIDIA_GPU_SUPPORT
 mesos_tests_SOURCES +=						\
+  tests/ldcache_tests.cpp					\
   tests/containerizer/nvidia_gpu_isolator_tests.cpp
 endif
 

http://git-wip-us.apache.org/repos/asf/mesos/blob/fc4507da/src/linux/ldcache.cpp
----------------------------------------------------------------------
diff --git a/src/linux/ldcache.cpp b/src/linux/ldcache.cpp
new file mode 100644
index 0000000..6260496
--- /dev/null
+++ b/src/linux/ldcache.cpp
@@ -0,0 +1,244 @@
+// 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.
+
+#include <fcntl.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdint.h>
+
+#include <string>
+#include <vector>
+
+#include <stout/os.hpp>
+#include <stout/try.hpp>
+
+#include "linux/ldcache.hpp"
+
+using std::string;
+using std::vector;
+
+// There are two formats for ld.so.cache. The pre-glibc format 2.2
+// listed the number of library entries, followed by the entries
+// themselves, followed by a string table holding strings pointed
+// to by the library entries. This format is summarized below:
+//
+//      HEADER_MAGIC_OLD
+//      nlibs
+//      libs[0]
+//      ...
+//      libs[nlibs-1]
+//      first string\0second string\0...last string\0
+//      ^                                           ^
+//      start of string table     end of string table
+//
+// For glibc 2.2 and beyond, a new format was created so that each
+// library entry could hold more meta-data about the libraries they
+// reference. To preserve backwards compatibility, the new format was
+// embedded in the old format inside its string table (simply moving
+// all existing strings further down in the string table). This makes
+// sense for backwards compatibility because code that could parse the
+// old format still works (the offsets for strings pointed to by
+// the library entries are just larger now).
+//
+// However, it adds complications when parsing for the new format
+// because the new format header needs to be aligned on an 8 byte
+// boundary (potentially pushing the start address of the string table
+// down a few bytes). A summary of the new format embedded in the old
+// format with annotations on the start address of the string table
+// can be seen below:
+//
+//      HEADER_MAGIC_OLD
+//      nlibs
+//      libs[0]
+//      ...
+//      libs[nlibs-1]
+//      pad (align for new format)
+//      HEADER_MAGIC_NEW    <-- start of string table
+//      nlibs
+//      len_strings
+//      unused    // 20 bytes reserved for extensions
+//      libs[0]
+//      ...
+//      libs[nlibs-1]
+//      first string\0second string\0...last string\0
+//                                                  ^
+//                                end of string table
+//
+// We currently only support the new format, since glibc 2.2
+// was released in late 2000.
+
+namespace ldcache {
+
+constexpr char HEADER_MAGIC_OLD[] = "ld.so-1.7.0";
+constexpr char HEADER_MAGIC_NEW[] = "glibc-ld.so.cache1.1";
+
+#define IS_ELF  0x00000001
+
+
+struct HeaderOld
+{
+  char magic[sizeof(HEADER_MAGIC_OLD) - 1];
+  uint32_t libraryCount; // Number of library entries.
+};
+
+
+struct EntryOld
+{
+  int32_t flags;  // 0x01 indicates ELF library.
+  uint32_t key;   // String table index.
+  uint32_t value; // String table index.
+};
+
+
+struct HeaderNew
+{
+  char magic[sizeof(HEADER_MAGIC_NEW) - 1];
+  uint32_t libraryCount;  // Number of library entries.
+  uint32_t stringsLength; // Length of "actual" string table.
+  uint32_t unused[5];     // Leave space for future extensions
+                          // and align to 8 byte boundary.
+};
+
+
+struct EntryNew
+{
+  int16_t flags;        // Flags bits determine arch and library type.
+  uint32_t key;         // String table index.
+  uint32_t value;       // String table index.
+  uint32_t osVersion;   // Required OS version.
+  uint64_t hwcap;       // Hwcap entry.
+};
+
+
+// Returns a 'boundary' aligned pointer by rounding up to
+// the nearest multiple of 'boundary'.
+static inline const char* align(const char* address, size_t boundary)
+{
+  if ((size_t)address % boundary == 0) {
+    return address;
+  }
+  return (address + boundary) - ((size_t)address % boundary);
+}
+
+
+Try<vector<Entry>> parse(const string& path)
+{
+  // Read the complete file into a buffer
+  Try<string> buffer = os::read(path);
+  if (buffer.isError()) {
+    return Error(buffer.error());
+  }
+
+  const char* data = buffer->data();
+
+  // Grab a pointer to the old format header (for verification of
+  // HEADER_MAGIC_OLD later on). Then jump forward to the location of
+  // the new format header (it is the only format we support).
+  HeaderOld* headerOld = (HeaderOld*)data;
+  data += sizeof(HeaderOld);
+  if (data >= buffer->data() + buffer->size()) {
+    return Error("Invalid format");
+  }
+
+  data += headerOld->libraryCount * sizeof(EntryOld);
+  if (data >= buffer->data() + buffer->size()) {
+    return Error("Invalid format");
+  }
+
+  // The new format header and all of its library entries are embedded
+  // in the old format's string table (the current location of data).
+  // However, the header is aligned on an 8 byte boundary, so we
+  // need to align 'data' to get it to point to the new header.
+  data = align(data, alignof(HeaderNew));
+  if (data >= buffer->data() + buffer->size()) {
+    return Error("Invalid format");
+  }
+
+  // Construct pointers to all of the important regions in the new
+  // format: the header, the libentry array, and the new string table
+  // (which starts at the same address as the aligned headerNew pointer).
+  HeaderNew* headerNew = (HeaderNew*)data;
+  data += sizeof(HeaderNew);
+  if (data >= buffer->data() + buffer->size()) {
+    return Error("Invalid format");
+  }
+
+  EntryNew* entriesNew = (EntryNew*)data;
+  data += headerNew->libraryCount * sizeof(EntryNew);
+  if (data >= buffer->data() + buffer->size()) {
+    return Error("Invalid format");
+  }
+
+  // The start of the strings table is at the beginning of
+  // the new header, per the above format description.
+  char* strings = (char*)headerNew;
+
+  // Adjust the pointer to add on the additional size of the strings
+  // contained in the string table. At this point, 'data' should
+  // point to an address just beyond the end of the file.
+  data += headerNew->stringsLength;
+  if ((size_t)(data - buffer->data()) != buffer->size()) {
+    return Error("Invalid format");
+  }
+
+  // Validate our header magic.
+  if (strncmp(headerOld->magic,
+        HEADER_MAGIC_OLD,
+        sizeof(HEADER_MAGIC_OLD) - 1) != 0) {
+    return Error("Invalid format");
+  }
+
+  if (strncmp(headerNew->magic,
+        HEADER_MAGIC_NEW,
+        sizeof(HEADER_MAGIC_NEW) - 1) != 0) {
+    return Error("Invalid format");
+  }
+
+  // Make sure the very last character in the buffer is a '\0'.
+  // This way, no matter what strings we index in the string
+  // table, we know they will never run beyond the end of the
+  // file buffer when extracting them.
+  if (*(data - 1) != '\0') {
+    return Error("Invalid format");
+  }
+
+  // Build our vector of ldcache entries.
+  vector<Entry> ldcache;
+  for (uint32_t i = 0; i < headerNew->libraryCount; i++) {
+    if (!(entriesNew[i].flags & IS_ELF)) {
+      continue;
+    }
+
+    if (strings + entriesNew[i].key >= data) {
+      return Error("Invalid format");
+    }
+
+    if (strings + entriesNew[i].value >= data) {
+      return Error("Invalid format");
+    }
+
+    Entry entry;
+    entry.name = &strings[entriesNew[i].key];
+    entry.path = &strings[entriesNew[i].value];
+    ldcache.push_back(entry);
+  }
+
+  return ldcache;
+}
+
+} // namespace ldcache {

http://git-wip-us.apache.org/repos/asf/mesos/blob/fc4507da/src/linux/ldcache.hpp
----------------------------------------------------------------------
diff --git a/src/linux/ldcache.hpp b/src/linux/ldcache.hpp
new file mode 100644
index 0000000..a004d3d
--- /dev/null
+++ b/src/linux/ldcache.hpp
@@ -0,0 +1,38 @@
+// 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 __LDCACHE_HPP__
+#define __LDCACHE_HPP__
+
+#include <string>
+#include <vector>
+
+#include <stout/try.hpp>
+
+namespace ldcache {
+
+struct Entry
+{
+  std::string name;
+  std::string path;
+};
+
+// Parse an ld.so.cache file into a vector of ELF library entries.
+Try<std::vector<Entry>> parse(const std::string& path = "/etc/ld.so.cache");
+
+} // namespace ldcache {
+
+#endif // __LDCACHE_HPP__

http://git-wip-us.apache.org/repos/asf/mesos/blob/fc4507da/src/tests/ldcache_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/ldcache_tests.cpp b/src/tests/ldcache_tests.cpp
new file mode 100644
index 0000000..b387a8b
--- /dev/null
+++ b/src/tests/ldcache_tests.cpp
@@ -0,0 +1,72 @@
+// 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.
+
+#include <string>
+#include <vector>
+
+#include <process/owned.hpp>
+
+#include <stout/elf.hpp>
+#include <stout/try.hpp>
+
+#include "linux/ldcache.hpp"
+
+#include "tests/mesos.hpp"
+
+using process::Owned;
+
+using std::string;
+using std::vector;
+
+namespace mesos {
+namespace internal {
+namespace tests {
+
+// Test to make sure we are able to read in and parse the ld.so.cache
+// file on a Linux machine.
+TEST(LdcacheTest, Parse)
+{
+  Try<vector<ldcache::Entry>> cache = ldcache::parse();
+  ASSERT_SOME(cache);
+  ASSERT_GT(cache->size(), 1u);
+
+  foreach (const ldcache::Entry& entry, cache.get()) {
+    Try<elf::File*> open = elf::File::open(entry.path);
+    ASSERT_SOME(open);
+
+    Owned<elf::File> file(open.get());
+
+    Try<elf::Class> c = file->GetClass();
+    ASSERT_SOME(c);
+    ASSERT_TRUE(c.get() == elf::CLASS32 || c.get() == elf::CLASS64);
+
+    Try<vector<string>> soname =
+      file->GetDynamicStrings(elf::DynamicTag::SONAME);
+    ASSERT_SOME(soname);
+    ASSERT_LE(soname->size(), 1u);
+
+    Try<vector<string>> needed =
+      file->GetDynamicStrings(elf::DynamicTag::NEEDED);
+    ASSERT_SOME(needed);
+    ASSERT_LE(needed->size(), cache->size());
+
+    file->close();
+  }
+}
+
+} // namespace tests {
+} // namespace internal {
+} // namespace mesos {


[4/6] mesos git commit: Added -lelf to default dynamic libraries for libprocess on Linux.

Posted by bm...@apache.org.
Added -lelf to default dynamic libraries for libprocess on Linux.

Review: https://reviews.apache.org/r/47483/


Project: http://git-wip-us.apache.org/repos/asf/mesos/repo
Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/7ae4c3f5
Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/7ae4c3f5
Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/7ae4c3f5

Branch: refs/heads/master
Commit: 7ae4c3f52394f689139abe622395f49f0372a530
Parents: 12a9c4e
Author: Kevin Klues <kl...@gmail.com>
Authored: Wed May 18 21:04:28 2016 -0700
Committer: Benjamin Mahler <bm...@apache.org>
Committed: Wed May 18 21:17:30 2016 -0700

----------------------------------------------------------------------
 3rdparty/libprocess/configure.ac | 1 +
 1 file changed, 1 insertion(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/7ae4c3f5/3rdparty/libprocess/configure.ac
----------------------------------------------------------------------
diff --git a/3rdparty/libprocess/configure.ac b/3rdparty/libprocess/configure.ac
index c8fcd35..2daded5 100644
--- a/3rdparty/libprocess/configure.ac
+++ b/3rdparty/libprocess/configure.ac
@@ -339,6 +339,7 @@ AM_CONDITIONAL([ENABLE_STATIC_LIBPROCESS], [false])
 case "${target_os}" in
   linux*)
     LIBS="$LIBS -lrt" # For clock_gettime() in stout/stopwatch.hpp.
+    LIBS="$LIBS -lelf" # For stout/elf.hpp.
     OS_NAME=linux # Used below for OS_LINUX.
     ;;
   darwin*)


[5/6] mesos git commit: Added -lelf to default dynamic libraries on Linux.

Posted by bm...@apache.org.
Added -lelf to default dynamic libraries on Linux.

Review: https://reviews.apache.org/r/47484/


Project: http://git-wip-us.apache.org/repos/asf/mesos/repo
Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/aa818454
Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/aa818454
Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/aa818454

Branch: refs/heads/master
Commit: aa818454b1fb799fc6658cd13c1093aeb0b5de80
Parents: 7ae4c3f
Author: Kevin Klues <kl...@gmail.com>
Authored: Wed May 18 21:06:53 2016 -0700
Committer: Benjamin Mahler <bm...@apache.org>
Committed: Wed May 18 21:17:30 2016 -0700

----------------------------------------------------------------------
 configure.ac | 1 +
 1 file changed, 1 insertion(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/aa818454/configure.ac
----------------------------------------------------------------------
diff --git a/configure.ac b/configure.ac
index 63ea028..0bae999 100644
--- a/configure.ac
+++ b/configure.ac
@@ -577,6 +577,7 @@ case "${target_os}" in
   linux*)
     OS_NAME=linux
     LIBS="$LIBS -lrt"
+    LIBS="$LIBS -lelf" # For stout/elf.hpp.
     ;;
   darwin*)
     OS_NAME=darwin