Blame external/opae-test/framework/mock/test_system.cpp

Packit 534379
// Copyright(c) 2017, Intel Corporation
Packit 534379
//
Packit 534379
// Redistribution  and  use  in source  and  binary  forms,  with  or  without
Packit 534379
// modification, are permitted provided that the following conditions are met:
Packit 534379
//
Packit 534379
// * Redistributions of  source code  must retain the  above copyright notice,
Packit 534379
//   this list of conditions and the following disclaimer.
Packit 534379
// * Redistributions in binary form must reproduce the above copyright notice,
Packit 534379
//   this list of conditions and the following disclaimer in the documentation
Packit 534379
//   and/or other materials provided with the distribution.
Packit 534379
// * Neither the name  of Intel Corporation  nor the names of its contributors
Packit 534379
//   may be used to  endorse or promote  products derived  from this  software
Packit 534379
//   without specific prior written permission.
Packit 534379
//
Packit 534379
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
Packit 534379
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,  BUT NOT LIMITED TO,  THE
Packit 534379
// IMPLIED WARRANTIES OF  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
Packit 534379
// ARE DISCLAIMED.  IN NO EVENT  SHALL THE COPYRIGHT OWNER  OR CONTRIBUTORS BE
Packit 534379
// LIABLE  FOR  ANY  DIRECT,  INDIRECT,  INCIDENTAL,  SPECIAL,  EXEMPLARY,  OR
Packit 534379
// CONSEQUENTIAL  DAMAGES  (INCLUDING,  BUT  NOT LIMITED  TO,  PROCUREMENT  OF
Packit 534379
// SUBSTITUTE GOODS OR SERVICES;  LOSS OF USE,  DATA, OR PROFITS;  OR BUSINESS
Packit 534379
// INTERRUPTION)  HOWEVER CAUSED  AND ON ANY THEORY  OF LIABILITY,  WHETHER IN
Packit 534379
// CONTRACT,  STRICT LIABILITY,  OR TORT  (INCLUDING NEGLIGENCE  OR OTHERWISE)
Packit 534379
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,  EVEN IF ADVISED OF THE
Packit 534379
// POSSIBILITY OF SUCH DAMAGE.
Packit 534379
/*
Packit 534379
 * test-system.cpp
Packit 534379
 */
Packit 534379
Packit 534379
#include "test_system.h"
Packit 534379
#include <glob.h>
Packit 534379
#include <stdarg.h>
Packit 534379
#include <unistd.h>
Packit 534379
#include <algorithm>
Packit 534379
#include <cstring>
Packit 534379
#include <fstream>
Packit 534379
#include <iostream>
Packit 534379
#include "c_test_system.h"
Packit 534379
#include "test_utils.h"
Packit 534379
#ifndef _GNU_SOURCE
Packit 534379
#define _GNU_SOURCE 1
Packit 534379
#endif
Packit 534379
#include <dlfcn.h>
Packit 534379
#include <fcntl.h>
Packit 534379
#include <sys/stat.h>
Packit 534379
#include <uuid/uuid.h>
Packit 534379
#include <ftw.h>
Packit 534379
Packit 534379
void *__builtin_return_address(unsigned level);
Packit 534379
Packit 534379
// hijack malloc
Packit 534379
static bool _invalidate_malloc = false;
Packit 534379
static uint32_t _invalidate_malloc_after = 0;
Packit 534379
static const char *_invalidate_malloc_when_called_from = nullptr;
Packit 534379
void *malloc(size_t size) {
Packit 534379
  if (_invalidate_malloc) {
Packit 534379
    if (!_invalidate_malloc_when_called_from) {
Packit 534379
      if (!_invalidate_malloc_after) {
Packit 534379
        _invalidate_malloc = false;
Packit 534379
        return nullptr;
Packit 534379
      }
Packit 534379
Packit 534379
      --_invalidate_malloc_after;
Packit 534379
Packit 534379
    } else {
Packit 534379
      void *caller = __builtin_return_address(0);
Packit 534379
      int res;
Packit 534379
      Dl_info info;
Packit 534379
Packit 534379
      dladdr(caller, &info;;
Packit 534379
      if (!info.dli_sname)
Packit 534379
        res = 1;
Packit 534379
      else
Packit 534379
        res = strcmp(info.dli_sname, _invalidate_malloc_when_called_from);
Packit 534379
Packit 534379
      if (!_invalidate_malloc_after && !res) {
Packit 534379
        _invalidate_malloc = false;
Packit 534379
        _invalidate_malloc_when_called_from = nullptr;
Packit 534379
        return nullptr;
Packit 534379
      } else if (!res)
Packit 534379
        --_invalidate_malloc_after;
Packit 534379
    }
Packit 534379
  }
Packit 534379
  return __libc_malloc(size);
Packit 534379
}
Packit 534379
Packit 534379
// hijack calloc
Packit 534379
static bool _invalidate_calloc = false;
Packit 534379
static uint32_t _invalidate_calloc_after = 0;
Packit 534379
static const char *_invalidate_calloc_when_called_from = nullptr;
Packit 534379
void *calloc(size_t nmemb, size_t size) {
Packit 534379
  if (_invalidate_calloc) {
Packit 534379
    if (!_invalidate_calloc_when_called_from) {
Packit 534379
      if (!_invalidate_calloc_after) {
Packit 534379
        _invalidate_calloc = false;
Packit 534379
        return nullptr;
Packit 534379
      }
Packit 534379
Packit 534379
      --_invalidate_calloc_after;
Packit 534379
Packit 534379
    } else {
Packit 534379
      void *caller = __builtin_return_address(0);
Packit 534379
      int res;
Packit 534379
      Dl_info info;
Packit 534379
Packit 534379
      dladdr(caller, &info;;
Packit 534379
      if (!info.dli_sname)
Packit 534379
        res = 1;
Packit 534379
      else
Packit 534379
        res = strcmp(info.dli_sname, _invalidate_calloc_when_called_from);
Packit 534379
Packit 534379
      if (!_invalidate_calloc_after && !res) {
Packit 534379
        _invalidate_calloc = false;
Packit 534379
        _invalidate_calloc_when_called_from = nullptr;
Packit 534379
        return nullptr;
Packit 534379
      } else if (!res)
Packit 534379
        --_invalidate_calloc_after;
Packit 534379
    }
Packit 534379
  }
Packit 534379
  return __libc_calloc(nmemb, size);
Packit 534379
}
Packit 534379
Packit 534379
namespace opae {
Packit 534379
namespace testing {
Packit 534379
Packit 534379
static const char *dev_pattern =
Packit 534379
    R"regex(/dev/(intel-fpga|dfl)-(fme|port)\.([0-9]+))regex";
Packit 534379
static const char *sysclass_pattern =
Packit 534379
    R"regex(/sys/class/fpga((?:_region)?/(region|intel-fpga-dev\.)([0-9]+))regex";
Packit 534379
Packit 534379
static std::map<std::string, std::string> fpga_sysfs_path_map = {
Packit 534379
    {"/dev/intel", "/sys/class/fpga/intel-fpga-dev."},
Packit 534379
    {"/dev/dfl", "/sys/class/fpga_region/region"}};
Packit 534379
Packit 534379
mock_object::mock_object(const std::string &devpath,
Packit 534379
                         const std::string &sysclass, uint32_t device_id,
Packit 534379
                         type_t type)
Packit 534379
    : devpath_(devpath),
Packit 534379
      sysclass_(sysclass),
Packit 534379
      device_id_(device_id),
Packit 534379
      type_(type) {}
Packit 534379
Packit 534379
int mock_fme::ioctl(int request, va_list argp) {
Packit 534379
  (void)request;
Packit 534379
  (void)argp;
Packit 534379
  return 0;
Packit 534379
}
Packit 534379
Packit 534379
int mock_port::ioctl(int request, va_list argp) {
Packit 534379
  (void)request;
Packit 534379
  (void)argp;
Packit 534379
  return 0;
Packit 534379
}
Packit 534379
Packit 534379
#define ASSERT_FN(fn)                              \
Packit 534379
  do {                                             \
Packit 534379
    if (fn == nullptr) {                           \
Packit 534379
      throw std::runtime_error(#fn " not loaded"); \
Packit 534379
    }                                              \
Packit 534379
  } while (false);
Packit 534379
Packit 534379
test_device test_device::unknown() {
Packit 534379
  return test_device{.fme_guid = "C544CE5C-F630-44E1-8551-59BD87AF432E",
Packit 534379
                     .afu_guid = "C544CE5C-F630-44E1-8551-59BD87AF432E",
Packit 534379
                     .segment = 0x1919,
Packit 534379
                     .bus = 0x0A,
Packit 534379
                     .device = 9,
Packit 534379
                     .function = 5,
Packit 534379
                     .num_vfs = 8,
Packit 534379
                     .socket_id = 9,
Packit 534379
                     .num_slots = 9,
Packit 534379
                     .bbs_id = 9,
Packit 534379
                     .bbs_version = {0xFF, 0xFF, 0xFF},
Packit 534379
                     .state = FPGA_ACCELERATOR_ASSIGNED,
Packit 534379
                     .num_mmio = 0,
Packit 534379
                     .num_interrupts = 0xf,
Packit 534379
                     .fme_object_id = 9,
Packit 534379
                     .port_object_id = 9,
Packit 534379
                     .vendor_id = 0x1234,
Packit 534379
                     .device_id = 0x1234,
Packit 534379
                     .fme_num_errors = 0x1234,
Packit 534379
                     .port_num_errors = 0x1234,
Packit 534379
                     .gbs_guid = "C544CE5C-F630-44E1-8551-59BD87AF432E",
Packit 534379
                     .mdata = ""};
Packit 534379
}
Packit 534379
Packit 534379
test_system *test_system::instance_ = nullptr;
Packit 534379
Packit 534379
test_system::test_system() : initialized_(false), root_("") {
Packit 534379
  open_ = (open_func)dlsym(RTLD_NEXT, "open");
Packit 534379
  open_create_ = open_;
Packit 534379
  read_ = (read_func)dlsym(RTLD_NEXT, "read");
Packit 534379
  fopen_ = (fopen_func)dlsym(RTLD_NEXT, "fopen");
Packit 534379
  popen_ = (popen_func)dlsym(RTLD_NEXT, "popen");
Packit 534379
  pclose_ = (pclose_func)dlsym(RTLD_NEXT, "pclose");
Packit 534379
  close_ = (close_func)dlsym(RTLD_NEXT, "close");
Packit 534379
  ioctl_ = (ioctl_func)dlsym(RTLD_NEXT, "ioctl");
Packit 534379
  opendir_ = (opendir_func)dlsym(RTLD_NEXT, "opendir");
Packit 534379
  readlink_ = (readlink_func)dlsym(RTLD_NEXT, "readlink");
Packit 534379
  xstat_ = (__xstat_func)dlsym(RTLD_NEXT, "__xstat");
Packit 534379
  lstat_ = (__xstat_func)dlsym(RTLD_NEXT, "__lxstat");
Packit 534379
  scandir_ = (scandir_func)dlsym(RTLD_NEXT, "scandir");
Packit 534379
  sched_setaffinity_ =
Packit 534379
      (sched_setaffinity_func)dlsym(RTLD_NEXT, "sched_setaffinity");
Packit 534379
Packit 534379
  glob_ = (glob_func)dlsym(RTLD_NEXT, "glob");
Packit 534379
  realpath_ = (realpath_func)dlsym(RTLD_NEXT, "realpath");
Packit 534379
Packit 534379
  hijack_sched_setaffinity_ = false;
Packit 534379
  hijack_sched_setaffinity_return_val_ = 0;
Packit 534379
  hijack_sched_setaffinity_after_ = 0;
Packit 534379
  hijack_sched_setaffinity_caller_ = nullptr;
Packit 534379
}
Packit 534379
Packit 534379
test_system *test_system::instance() {
Packit 534379
  if (test_system::instance_ == nullptr) {
Packit 534379
    test_system::instance_ = new test_system();
Packit 534379
  }
Packit 534379
  return test_system::instance_;
Packit 534379
}
Packit 534379
Packit 534379
void test_system::prepare_syfs(const test_platform &platform) {
Packit 534379
  int result = 0;
Packit 534379
  char tmpsysfs[]{"tmpsysfs-XXXXXX"};
Packit 534379
Packit 534379
  if (platform.mock_sysfs != nullptr) {
Packit 534379
    char *tmp = mkdtemp(tmpsysfs);
Packit 534379
    if (tmp == nullptr) {
Packit 534379
      throw std::runtime_error("error making tmpsysfs");
Packit 534379
    }
Packit 534379
    root_ = std::string(tmp);
Packit 534379
    std::string cmd = "tar xzf " + std::string(platform.mock_sysfs) + " -C " +
Packit 534379
                      root_ + " --strip 1";
Packit 534379
    result = std::system(cmd.c_str());
Packit 534379
  }
Packit 534379
  return (void)result;
Packit 534379
}
Packit 534379
Packit 534379
Packit 534379
extern "C" {
Packit 534379
int process_fpath(const char *fpath, const struct stat *sb, int typeflag, struct FTW *ftw) {
Packit 534379
  (void)sb;
Packit 534379
  (void)ftw;
Packit 534379
  if (typeflag & FTW_DP) {
Packit 534379
    if (rmdir(fpath)) {
Packit 534379
      if (errno == ENOTDIR) {
Packit 534379
        goto do_unlink;
Packit 534379
      }
Packit 534379
      std::cerr << "error removing directory: " << fpath << " - " << strerror(errno) << "\n";
Packit 534379
      return -1;
Packit 534379
    }
Packit 534379
  }
Packit 534379
do_unlink:
Packit 534379
  if (unlink(fpath) && errno != ENOENT) {
Packit 534379
      std::cerr << "error removing node: " << fpath << " - " << strerror(errno) << "\n";
Packit 534379
      return -1;
Packit 534379
  }
Packit 534379
  return 0;
Packit 534379
}
Packit 534379
}
Packit 534379
Packit 534379
int test_system::remove_sysfs_dir(const char *path) {
Packit 534379
  if (root_.find("tmpsysfs") != std::string::npos) {
Packit 534379
    auto real_path = path == nullptr ? root_ : get_sysfs_path(path);
Packit 534379
    return nftw(real_path.c_str(), process_fpath, 100, FTW_DEPTH | FTW_PHYS);
Packit 534379
  }
Packit 534379
  return 0;
Packit 534379
}
Packit 534379
Packit 534379
int test_system::remove_sysfs() {
Packit 534379
  return remove_sysfs_dir();
Packit 534379
}
Packit 534379
Packit 534379
Packit 534379
void test_system::set_root(const char *root) { root_ = root; }
Packit 534379
std::string test_system::get_root() { return root_; }
Packit 534379
Packit 534379
std::string test_system::get_sysfs_path(const std::string &src) {
Packit 534379
  auto it = registered_files_.find(src);
Packit 534379
  if (it != registered_files_.end()) {
Packit 534379
    return it->second;
Packit 534379
  }
Packit 534379
  if (src.find("/sys") == 0 || src.find("/dev/intel-fpga") == 0 ||
Packit 534379
      src.find("/dev/dfl-") == 0) {
Packit 534379
    if (!root_.empty() && root_.size() > 1) {
Packit 534379
      return root_ + src;
Packit 534379
    }
Packit 534379
  }
Packit 534379
  return src;
Packit 534379
}
Packit 534379
Packit 534379
std::vector<uint8_t> test_system::assemble_gbs_header(const test_device &td) {
Packit 534379
  std::vector<uint8_t> gbs_header(20, 0);
Packit 534379
  if (uuid_parse(td.gbs_guid, gbs_header.data())) {
Packit 534379
    std::string msg = "unable to parse UUID: ";
Packit 534379
    msg.append(td.gbs_guid);
Packit 534379
    throw std::runtime_error(msg);
Packit 534379
  }
Packit 534379
  uint32_t len = strlen(td.mdata);
Packit 534379
  *reinterpret_cast<uint32_t *>(gbs_header.data() + 16) = len;
Packit 534379
  std::copy(&td.mdata[0], &td.mdata[len], std::back_inserter(gbs_header));
Packit 534379
  return gbs_header;
Packit 534379
}
Packit 534379
Packit 534379
std::vector<uint8_t> test_system::assemble_gbs_header(const test_device &td,
Packit 534379
                                                      const char *mdata) {
Packit 534379
  if (mdata) {
Packit 534379
    test_device copy = td;
Packit 534379
    copy.mdata = mdata;
Packit 534379
    return assemble_gbs_header(copy);
Packit 534379
  }
Packit 534379
  return std::vector<uint8_t>(0);
Packit 534379
}
Packit 534379
Packit 534379
void test_system::initialize() {
Packit 534379
  ASSERT_FN(open_);
Packit 534379
  ASSERT_FN(open_create_);
Packit 534379
  ASSERT_FN(read_);
Packit 534379
  ASSERT_FN(fopen_);
Packit 534379
  ASSERT_FN(popen_);
Packit 534379
  ASSERT_FN(pclose_);
Packit 534379
  ASSERT_FN(close_);
Packit 534379
  ASSERT_FN(ioctl_);
Packit 534379
  ASSERT_FN(readlink_);
Packit 534379
  ASSERT_FN(xstat_);
Packit 534379
  ASSERT_FN(lstat_);
Packit 534379
  ASSERT_FN(scandir_);
Packit 534379
  ASSERT_FN(sched_setaffinity_);
Packit 534379
  ASSERT_FN(glob_);
Packit 534379
  ASSERT_FN(realpath_);
Packit 534379
  for (const auto &kv : default_ioctl_handlers_) {
Packit 534379
    register_ioctl_handler(kv.first, kv.second);
Packit 534379
  }
Packit 534379
  initialized_ = true;
Packit 534379
}
Packit 534379
Packit 534379
void test_system::finalize() {
Packit 534379
  if (!initialized_) {
Packit 534379
    return;
Packit 534379
  }
Packit 534379
  initialized_ = false;
Packit 534379
  std::lock_guard<std::mutex> guard(fds_mutex_);
Packit 534379
  for (auto kv : fds_) {
Packit 534379
    if (kv.second) {
Packit 534379
      delete kv.second;
Packit 534379
      kv.second = nullptr;
Packit 534379
    }
Packit 534379
  }
Packit 534379
  remove_sysfs();
Packit 534379
  root_ = "";
Packit 534379
  fds_.clear();
Packit 534379
  for (auto kv : registered_files_) {
Packit 534379
    unlink(kv.second.c_str());
Packit 534379
  }
Packit 534379
  registered_files_.clear();
Packit 534379
  ioctl_handlers_.clear();
Packit 534379
}
Packit 534379
Packit 534379
bool test_system::default_ioctl_handler(int request, ioctl_handler_t h) {
Packit 534379
  bool already_registered =
Packit 534379
      default_ioctl_handlers_.find(request) != default_ioctl_handlers_.end();
Packit 534379
  default_ioctl_handlers_[request] = h;
Packit 534379
  return already_registered;
Packit 534379
}
Packit 534379
Packit 534379
bool test_system::register_ioctl_handler(int request, ioctl_handler_t h) {
Packit 534379
  bool already_registered =
Packit 534379
      ioctl_handlers_.find(request) != ioctl_handlers_.end();
Packit 534379
  ioctl_handlers_[request] = h;
Packit 534379
  return already_registered;
Packit 534379
}
Packit 534379
Packit 534379
FILE *test_system::register_file(const std::string &path) {
Packit 534379
  auto it = registered_files_.find(path);
Packit 534379
  if (it == registered_files_.end()) {
Packit 534379
    registered_files_[path] =
Packit 534379
        "/tmp/testfile" + std::to_string(registered_files_.size());
Packit 534379
  }
Packit 534379
Packit 534379
  auto fptr = fopen(path.c_str(), "w+");
Packit 534379
  return fptr;
Packit 534379
}
Packit 534379
Packit 534379
void test_system::normalize_guid(std::string &guid_str, bool with_hyphens) {
Packit 534379
  // normalizing a guid string can make it easier to compare guid strings
Packit 534379
  // and can also put the string in a format that can be parsed into actual
Packit 534379
  // guid bytes (uuid_parse expects the string to include hyphens).
Packit 534379
  const size_t std_guid_str_size = 36;
Packit 534379
  const size_t char_guid_str_size = 32;
Packit 534379
  if (guid_str.back() == '\n') {
Packit 534379
    guid_str.erase(guid_str.end() - 1);
Packit 534379
  }
Packit 534379
  std::locale lc;
Packit 534379
  auto c_idx = guid_str.find('-');
Packit 534379
  if (with_hyphens && c_idx == std::string::npos) {
Packit 534379
    // if we want the standard UUID format with hyphens (8-4-4-4-12)
Packit 534379
    if (guid_str.size() == char_guid_str_size) {
Packit 534379
      int idx = 20;
Packit 534379
      while (c_idx != 8) {
Packit 534379
        guid_str.insert(idx, 1, '-');
Packit 534379
        idx -= 4;
Packit 534379
        c_idx = guid_str.find('-');
Packit 534379
      }
Packit 534379
    } else {
Packit 534379
      throw std::invalid_argument("invalid guid string");
Packit 534379
    }
Packit 534379
  } else if (!with_hyphens && c_idx == 8) {
Packit 534379
    // we want the hex characters only, no other extra chars
Packit 534379
    if (guid_str.size() == std_guid_str_size) {
Packit 534379
      while (c_idx != std::string::npos) {
Packit 534379
        guid_str.erase(c_idx, 1);
Packit 534379
        c_idx = guid_str.find('-');
Packit 534379
      }
Packit 534379
    } else {
Packit 534379
      throw std::invalid_argument("invalid guid string");
Packit 534379
    }
Packit 534379
  }
Packit 534379
Packit 534379
  for (auto &c : guid_str) {
Packit 534379
    c = std::tolower(c, lc);
Packit 534379
  }
Packit 534379
}
Packit 534379
Packit 534379
uint32_t get_device_id(const std::string &sysclass) {
Packit 534379
  uint32_t res(0);
Packit 534379
  std::ifstream fs;
Packit 534379
  fs.open(sysclass + "/device/device");
Packit 534379
  if (fs.is_open()) {
Packit 534379
    std::string line;
Packit 534379
    std::getline(fs, line);
Packit 534379
    fs.close();
Packit 534379
    return std::stoul(line, 0, 16);
Packit 534379
  }
Packit 534379
  return res;
Packit 534379
}
Packit 534379
Packit 534379
std::string test_system::get_sysfs_claass_path(const std::string &path) {
Packit 534379
  for (auto it : fpga_sysfs_path_map) {
Packit 534379
    if (path.find(it.first) == 0) {
Packit 534379
      return it.second;
Packit 534379
    }
Packit 534379
  }
Packit 534379
  return "";
Packit 534379
}
Packit 534379
Packit 534379
int test_system::open(const std::string &path, int flags) {
Packit 534379
  if (!initialized_) {
Packit 534379
    return open_(path.c_str(), flags);
Packit 534379
  }
Packit 534379
  std::string syspath = get_sysfs_path(path);
Packit 534379
  int fd;
Packit 534379
  auto r1 = regex<>::create(sysclass_pattern);
Packit 534379
  auto r2 = regex<>::create(dev_pattern);
Packit 534379
  match_t::ptr_t m;
Packit 534379
Packit 534379
  // check if we are opening a driver attribute file
Packit 534379
  // or a device file to save the fd in an internal map
Packit 534379
  // this can be used later, (especially in ioctl)
Packit 534379
  if (r1 && (m = r1->match(path))) {
Packit 534379
    // path matches /sys/class/fpga/intel-fpga-dev\..*
Packit 534379
    // we are opening a driver attribute file
Packit 534379
Packit 534379
    if (flags == O_WRONLY) {
Packit 534379
      // truncate the file to zero to emulate the sysfs behavior.
Packit 534379
      flags |= O_TRUNC;
Packit 534379
    }
Packit 534379
Packit 534379
    fd = open_(syspath.c_str(), flags);
Packit 534379
    auto sysclass_path = m->group(0);
Packit 534379
    auto device_id = get_device_id(get_sysfs_path(sysclass_path));
Packit 534379
    std::lock_guard<std::mutex> guard(fds_mutex_);
Packit 534379
    fds_[fd] = new mock_object(path, sysclass_path, device_id);
Packit 534379
  } else if (r2 && (m = r2->match(path))) {
Packit 534379
    // path matches /dev/intel-fpga-(fme|port)\..*
Packit 534379
    // we are opening a device
Packit 534379
    fd = open_(syspath.c_str(), flags);
Packit 534379
    auto sysclass_path = get_sysfs_claass_path(path) + m->group(3);
Packit 534379
    auto device_id = get_device_id(get_sysfs_path(sysclass_path));
Packit 534379
    if (m->group(2) == "fme") {
Packit 534379
      std::lock_guard<std::mutex> guard(fds_mutex_);
Packit 534379
      fds_[fd] = new mock_fme(path, sysclass_path, device_id);
Packit 534379
    } else if (m->group(2) == "port") {
Packit 534379
      std::lock_guard<std::mutex> guard(fds_mutex_);
Packit 534379
      fds_[fd] = new mock_port(path, sysclass_path, device_id);
Packit 534379
    }
Packit 534379
  } else {
Packit 534379
    fd = open_(syspath.c_str(), flags);
Packit 534379
  }
Packit 534379
  return fd;
Packit 534379
}
Packit 534379
Packit 534379
int test_system::open(const std::string &path, int flags, mode_t mode) {
Packit 534379
  if (!initialized_) {
Packit 534379
    return open_create_(path.c_str(), flags, mode);
Packit 534379
  }
Packit 534379
Packit 534379
  std::string syspath = get_sysfs_path(path);
Packit 534379
  int fd = open_create_(syspath.c_str(), flags, mode);
Packit 534379
  if (syspath.find(root_) == 0) {
Packit 534379
    std::lock_guard<std::mutex> guard(fds_mutex_);
Packit 534379
    std::map<int, mock_object *>::iterator it = fds_.find(fd);
Packit 534379
    if (it != fds_.end()) {
Packit 534379
      delete it->second;
Packit 534379
    }
Packit 534379
    fds_[fd] = new mock_object(path, "", 0);
Packit 534379
  }
Packit 534379
  return fd;
Packit 534379
}
Packit 534379
Packit 534379
static bool _invalidate_read = false;
Packit 534379
static uint32_t _invalidate_read_after = 0;
Packit 534379
static const char *_invalidate_read_when_called_from = nullptr;
Packit 534379
void test_system::invalidate_read(uint32_t after,
Packit 534379
                                  const char *when_called_from) {
Packit 534379
  _invalidate_read = true;
Packit 534379
  _invalidate_read_after = after;
Packit 534379
  _invalidate_read_when_called_from = when_called_from;
Packit 534379
}
Packit 534379
Packit 534379
ssize_t test_system::read(int fd, void *buf, size_t count) {
Packit 534379
  if (_invalidate_read) {
Packit 534379
    if (!_invalidate_read_when_called_from) {
Packit 534379
      if (!_invalidate_read_after) {
Packit 534379
        _invalidate_read = false;
Packit 534379
        return -1;
Packit 534379
      }
Packit 534379
Packit 534379
      --_invalidate_read_after;
Packit 534379
Packit 534379
    } else {
Packit 534379
      // 2 here, because we were called through..
Packit 534379
      // 0 test_system.cpp:opae_test_read()
Packit 534379
      // 1 mock.c:read()
Packit 534379
      // 2 <caller>
Packit 534379
      void *caller = __builtin_return_address(2);
Packit 534379
      int res;
Packit 534379
      Dl_info info;
Packit 534379
Packit 534379
      dladdr(caller, &info;;
Packit 534379
      if (!info.dli_sname)
Packit 534379
        res = 1;
Packit 534379
      else
Packit 534379
        res = strcmp(info.dli_sname, _invalidate_read_when_called_from);
Packit 534379
Packit 534379
      if (!_invalidate_read_after && !res) {
Packit 534379
        _invalidate_read = false;
Packit 534379
        _invalidate_read_when_called_from = nullptr;
Packit 534379
        return -1;
Packit 534379
      } else if (!res)
Packit 534379
        --_invalidate_read_after;
Packit 534379
    }
Packit 534379
  }
Packit 534379
  return read_(fd, buf, count);
Packit 534379
}
Packit 534379
Packit 534379
FILE *test_system::fopen(const std::string &path, const std::string &mode) {
Packit 534379
  std::string syspath = get_sysfs_path(path);
Packit 534379
  return fopen_(syspath.c_str(), mode.c_str());
Packit 534379
}
Packit 534379
Packit 534379
FILE *test_system::popen(const std::string &cmd, const std::string &type) {
Packit 534379
  // Is this something we're interested in?
Packit 534379
  if (0 == cmd.compare(0, 5, "rdmsr")) {
Packit 534379
    char tmpfile[20];
Packit 534379
    strcpy(tmpfile, "popen-XXXXXX.tmp");
Packit 534379
    close(mkstemps(tmpfile, 4));
Packit 534379
Packit 534379
    FILE *fp = fopen(tmpfile, "w+");
Packit 534379
Packit 534379
    size_t last_spc = cmd.find_last_of(' ');
Packit 534379
    std::string msr(cmd.substr(last_spc + 1));
Packit 534379
Packit 534379
    if (0 == msr.compare("0x35")) {
Packit 534379
      fprintf(fp, "0x0000000000180030");
Packit 534379
    } else if (0 == msr.compare("0x610")) {
Packit 534379
      fprintf(fp, "0x000388d000148758");
Packit 534379
    } else if (0 == msr.compare("0x606")) {
Packit 534379
      fprintf(fp, "0x00000000000a0e03");
Packit 534379
    }
Packit 534379
Packit 534379
    fseek(fp, 0, SEEK_SET);
Packit 534379
    popen_requests_.insert(std::make_pair(fp, tmpfile));
Packit 534379
Packit 534379
    return fp;
Packit 534379
  } else {
Packit 534379
    return popen_(cmd.c_str(), type.c_str());
Packit 534379
  }
Packit 534379
}
Packit 534379
Packit 534379
int test_system::pclose(FILE *stream) {
Packit 534379
  // Is this something we intercepted?
Packit 534379
  std::map<FILE *, std::string>::iterator it = popen_requests_.find(stream);
Packit 534379
  if (it != popen_requests_.end()) {
Packit 534379
    unlink(it->second.c_str());
Packit 534379
    popen_requests_.erase(it);
Packit 534379
    fclose(stream);
Packit 534379
    return 0;  // process exit status
Packit 534379
  }
Packit 534379
  return pclose_(stream);
Packit 534379
}
Packit 534379
Packit 534379
int test_system::close(int fd) {
Packit 534379
  if (initialized_) {
Packit 534379
    std::lock_guard<std::mutex> guard(fds_mutex_);
Packit 534379
    std::map<int, mock_object *>::iterator it = fds_.find(fd);
Packit 534379
    if (it != fds_.end()) {
Packit 534379
      delete it->second;
Packit 534379
      fds_.erase(it);
Packit 534379
    }
Packit 534379
  }
Packit 534379
  return close_(fd);
Packit 534379
}
Packit 534379
Packit 534379
int test_system::ioctl(int fd, unsigned long request, va_list argp) {
Packit 534379
  mock_object *mo = nullptr;
Packit 534379
  {
Packit 534379
    std::lock_guard<std::mutex> guard(fds_mutex_);
Packit 534379
    auto mi = fds_.find(fd);
Packit 534379
    if (mi != fds_.end()) {
Packit 534379
      mo = mi->second;
Packit 534379
    }
Packit 534379
  }
Packit 534379
Packit 534379
  if (mo == nullptr) {
Packit 534379
    char *arg = va_arg(argp, char *);
Packit 534379
    return ioctl_(fd, request, arg);
Packit 534379
  }
Packit 534379
Packit 534379
  // replace mock_it->second with mo
Packit 534379
  auto handler_it = ioctl_handlers_.find(request);
Packit 534379
  if (handler_it != ioctl_handlers_.end()) {
Packit 534379
    return handler_it->second(mo, request, argp);
Packit 534379
  }
Packit 534379
  return mo->ioctl(request, argp);
Packit 534379
}
Packit 534379
Packit 534379
DIR *test_system::opendir(const char *path) {
Packit 534379
  std::string syspath = get_sysfs_path(path);
Packit 534379
  return opendir_(syspath.c_str());
Packit 534379
}
Packit 534379
Packit 534379
ssize_t test_system::readlink(const char *path, char *buf, size_t bufsize) {
Packit 534379
  std::string syspath = get_sysfs_path(path);
Packit 534379
  return readlink_(syspath.c_str(), buf, bufsize);
Packit 534379
}
Packit 534379
Packit 534379
int test_system::xstat(int ver, const char *path, struct stat *buf) {
Packit 534379
  std::string syspath = get_sysfs_path(path);
Packit 534379
  int res = xstat_(ver, syspath.c_str(), buf);
Packit 534379
Packit 534379
  if (!res && strlen(path) > 5) {
Packit 534379
    // If path is rooted at /dev, assume it is a char device.
Packit 534379
    std::string p(path, 5);
Packit 534379
    if (p == std::string("/dev/")) {
Packit 534379
            buf->st_mode &= ~S_IFMT;
Packit 534379
            buf->st_mode |= S_IFCHR;
Packit 534379
    }
Packit 534379
  }
Packit 534379
Packit 534379
  return res;
Packit 534379
}
Packit 534379
Packit 534379
int test_system::lstat(int ver, const char *path, struct stat *buf) {
Packit 534379
  std::string syspath = get_sysfs_path(path);
Packit 534379
  int res = lstat_(ver, syspath.c_str(), buf);
Packit 534379
Packit 534379
  if (!res && strlen(path) > 5) {
Packit 534379
    // If path is rooted at /dev, assume it is a char device.
Packit 534379
    std::string p(path, 5);
Packit 534379
    if (p == std::string("/dev/")) {
Packit 534379
            buf->st_mode &= ~S_IFMT;
Packit 534379
            buf->st_mode |= S_IFCHR;
Packit 534379
    }
Packit 534379
  }
Packit 534379
Packit 534379
  return res;
Packit 534379
}
Packit 534379
Packit 534379
int test_system::scandir(const char *dirp, struct dirent ***namelist,
Packit 534379
                         filter_func filter, compare_func cmp) {
Packit 534379
  std::string syspath = get_sysfs_path(dirp);
Packit 534379
  return scandir_(syspath.c_str(), namelist, filter, cmp);
Packit 534379
}
Packit 534379
Packit 534379
int test_system::sched_setaffinity(pid_t pid, size_t cpusetsize,
Packit 534379
                                   const cpu_set_t *mask) {
Packit 534379
  UNUSED_PARAM(pid);
Packit 534379
  UNUSED_PARAM(cpusetsize);
Packit 534379
  UNUSED_PARAM(mask);
Packit 534379
  if (hijack_sched_setaffinity_) {
Packit 534379
    if (!hijack_sched_setaffinity_caller_) {
Packit 534379
      if (!hijack_sched_setaffinity_after_) {
Packit 534379
        hijack_sched_setaffinity_ = false;
Packit 534379
        int res = hijack_sched_setaffinity_return_val_;
Packit 534379
        hijack_sched_setaffinity_return_val_ = 0;
Packit 534379
        return res;
Packit 534379
      }
Packit 534379
Packit 534379
      --hijack_sched_setaffinity_after_;
Packit 534379
Packit 534379
    } else {
Packit 534379
      // 2 here, because we were called through..
Packit 534379
      // 0 test_system.cpp:opae_test_sched_setaffinity()
Packit 534379
      // 1 mock.c:sched_setaffinity()
Packit 534379
      // 2 <caller>
Packit 534379
      void *caller = __builtin_return_address(2);
Packit 534379
      int res;
Packit 534379
      Dl_info info;
Packit 534379
Packit 534379
      dladdr(caller, &info;;
Packit 534379
      if (!info.dli_sname)
Packit 534379
        res = 1;
Packit 534379
      else
Packit 534379
        res = strcmp(info.dli_sname, hijack_sched_setaffinity_caller_);
Packit 534379
Packit 534379
      if (!hijack_sched_setaffinity_after_ && !res) {
Packit 534379
        hijack_sched_setaffinity_ = false;
Packit 534379
        hijack_sched_setaffinity_caller_ = nullptr;
Packit 534379
        res = hijack_sched_setaffinity_return_val_;
Packit 534379
        hijack_sched_setaffinity_return_val_ = 0;
Packit 534379
        return res;
Packit 534379
      } else if (!res)
Packit 534379
        --hijack_sched_setaffinity_after_;
Packit 534379
    }
Packit 534379
  }
Packit 534379
  return 0;  // return success - we don't actually
Packit 534379
             // want to change the affinity.
Packit 534379
}
Packit 534379
Packit 534379
void test_system::hijack_sched_setaffinity(int return_val, uint32_t after,
Packit 534379
                                           const char *when_called_from) {
Packit 534379
  hijack_sched_setaffinity_ = true;
Packit 534379
  hijack_sched_setaffinity_return_val_ = return_val;
Packit 534379
  hijack_sched_setaffinity_after_ = after;
Packit 534379
  hijack_sched_setaffinity_caller_ = when_called_from;
Packit 534379
}
Packit 534379
Packit 534379
int test_system::glob(const char *pattern, int flags,
Packit 534379
                      int (*errfunc)(const char *epath, int eerrno),
Packit 534379
                      glob_t *pglob) {
Packit 534379
  if (pattern == nullptr) {
Packit 534379
    return glob_(pattern, flags, errfunc, pglob);
Packit 534379
  }
Packit 534379
Packit 534379
  auto path = get_sysfs_path(pattern);
Packit 534379
Packit 534379
  auto res = glob_(path.c_str(), flags, errfunc, pglob);
Packit 534379
  if (!res) {
Packit 534379
    for (unsigned int i = 0; i < pglob->gl_pathc; ++i) {
Packit 534379
      std::string tmppath(pglob->gl_pathv[i]);
Packit 534379
      if (tmppath.find(get_root()) == 0) {
Packit 534379
        auto p = pglob->gl_pathv[i];
Packit 534379
        auto root_len = get_root().size();
Packit 534379
        auto new_len = tmppath.size() - root_len;
Packit 534379
        std::copy(tmppath.begin() + root_len, tmppath.end(), p);
Packit 534379
        p[new_len] = '\0';
Packit 534379
      }
Packit 534379
    }
Packit 534379
  }
Packit 534379
Packit 534379
  return res;
Packit 534379
}
Packit 534379
Packit 534379
char *test_system::realpath(const char *inp, char *dst)
Packit 534379
{
Packit 534379
  if (!initialized_ || root_.empty()) {
Packit 534379
    return realpath_(inp, dst);
Packit 534379
  }
Packit 534379
  bool current_inv_state = _invalidate_malloc;
Packit 534379
  _invalidate_malloc = false;
Packit 534379
  char *retvalue = realpath_(get_sysfs_path(inp).c_str(), dst);
Packit 534379
  if (retvalue) {
Packit 534379
    std::string dst_str(dst);
Packit 534379
    char prefix[PATH_MAX] = {0};
Packit 534379
    char *prefix_ptr = realpath_(root_.c_str(), prefix);
Packit 534379
    std::string prefix_str(prefix_ptr ? prefix_ptr : "");
Packit 534379
    if (prefix_str.size() && dst_str.find(prefix_str) == 0) {
Packit 534379
      auto cleaned_str = dst_str.substr(prefix_str.size());
Packit 534379
      std::copy(cleaned_str.begin(), cleaned_str.end(), &dst[0]);
Packit 534379
      dst[cleaned_str.size()] = '\0';
Packit 534379
      retvalue = &dst[0];
Packit 534379
    }
Packit 534379
  }
Packit 534379
  _invalidate_malloc = current_inv_state;
Packit 534379
  return retvalue;
Packit 534379
}
Packit 534379
Packit 534379
void test_system::invalidate_malloc(uint32_t after,
Packit 534379
                                    const char *when_called_from) {
Packit 534379
  _invalidate_malloc = true;
Packit 534379
  _invalidate_malloc_after = after;
Packit 534379
  _invalidate_malloc_when_called_from = when_called_from;
Packit 534379
}
Packit 534379
Packit 534379
void test_system::invalidate_calloc(uint32_t after,
Packit 534379
                                    const char *when_called_from) {
Packit 534379
  _invalidate_calloc = true;
Packit 534379
  _invalidate_calloc_after = after;
Packit 534379
  _invalidate_calloc_when_called_from = when_called_from;
Packit 534379
}
Packit 534379
Packit 534379
}  // end of namespace testing
Packit 534379
}  // end of namespace opae
Packit 534379
Packit 534379
// C functions
Packit 534379
Packit 534379
int opae_test_open(const char *path, int flags) {
Packit 534379
  return opae::testing::test_system::instance()->open(path, flags);
Packit 534379
}
Packit 534379
Packit 534379
int opae_test_open_create(const char *path, int flags, mode_t mode) {
Packit 534379
  return opae::testing::test_system::instance()->open(path, flags, mode);
Packit 534379
}
Packit 534379
Packit 534379
ssize_t opae_test_read(int fd, void *buf, size_t count) {
Packit 534379
  return opae::testing::test_system::instance()->read(fd, buf, count);
Packit 534379
}
Packit 534379
Packit 534379
FILE *opae_test_fopen(const char *path, const char *mode) {
Packit 534379
  return opae::testing::test_system::instance()->fopen(path, mode);
Packit 534379
}
Packit 534379
Packit 534379
FILE *opae_test_popen(const char *cmd, const char *type) {
Packit 534379
  return opae::testing::test_system::instance()->popen(cmd, type);
Packit 534379
}
Packit 534379
Packit 534379
int opae_test_pclose(FILE *stream) {
Packit 534379
  return opae::testing::test_system::instance()->pclose(stream);
Packit 534379
}
Packit 534379
Packit 534379
int opae_test_close(int fd) {
Packit 534379
  return opae::testing::test_system::instance()->close(fd);
Packit 534379
}
Packit 534379
Packit 534379
int opae_test_ioctl(int fd, unsigned long request, va_list argp) {
Packit 534379
  return opae::testing::test_system::instance()->ioctl(fd, request, argp);
Packit 534379
}
Packit 534379
Packit 534379
DIR *opae_test_opendir(const char *name) {
Packit 534379
  return opae::testing::test_system::instance()->opendir(name);
Packit 534379
}
Packit 534379
Packit 534379
ssize_t opae_test_readlink(const char *path, char *buf, size_t bufsize) {
Packit 534379
  return opae::testing::test_system::instance()->readlink(path, buf, bufsize);
Packit 534379
}
Packit 534379
Packit 534379
int opae_test_xstat(int ver, const char *path, struct stat *buf) {
Packit 534379
  return opae::testing::test_system::instance()->xstat(ver, path, buf);
Packit 534379
}
Packit 534379
Packit 534379
int opae_test_lstat(int ver, const char *path, struct stat *buf) {
Packit 534379
  return opae::testing::test_system::instance()->lstat(ver, path, buf);
Packit 534379
}
Packit 534379
Packit 534379
int opae_test_scandir(const char *dirp, struct dirent ***namelist,
Packit 534379
                      filter_func filter, compare_func cmp) {
Packit 534379
  return opae::testing::test_system::instance()->scandir(dirp, namelist, filter,
Packit 534379
                                                         cmp);
Packit 534379
}
Packit 534379
Packit 534379
int opae_test_sched_setaffinity(pid_t pid, size_t cpusetsize,
Packit 534379
                                const cpu_set_t *mask) {
Packit 534379
  return opae::testing::test_system::instance()->sched_setaffinity(
Packit 534379
      pid, cpusetsize, mask);
Packit 534379
}
Packit 534379
Packit 534379
int opae_test_glob(const char *pattern, int flags,
Packit 534379
                   int (*errfunc)(const char *epath, int eerrno),
Packit 534379
                   glob_t *pglob) {
Packit 534379
  return opae::testing::test_system::instance()->glob(pattern, flags, errfunc,
Packit 534379
                                                      pglob);
Packit 534379
}
Packit 534379
Packit 534379
char *opae_test_realpath(const char *inp, char *dst) {
Packit 534379
  return opae::testing::test_system::instance()->realpath(inp, dst);
Packit 534379
}