Alien-cares

 view release on metacpan or  search on metacpan

libcares/test/ares-test-ns.cc  view on Meta::CPAN

#include "ares-test.h"

#ifdef HAVE_CONTAINER

#include <sys/mount.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#include <iostream>
#include <functional>
#include <string>
#include <sstream>
#include <vector>

namespace ares {
namespace test {

namespace {

struct ContainerInfo {
  ContainerFilesystem* fs_;
  std::string hostname_;
  std::string domainname_;
  VoidToIntFn fn_;
};

int EnterContainer(void *data) {
  ContainerInfo *container = (ContainerInfo*)data;

  if (verbose) {
    std::cerr << "Running function in container {chroot='"
              << container->fs_->root() << "', hostname='" << container->hostname_
              << "', domainname='" << container->domainname_ << "'}"
              << std::endl;
  }

  // Ensure we are apparently root before continuing.
  int count = 10;
  while (getuid() != 0 && count > 0) {
    usleep(100000);
    count--;
  }
  if (getuid() != 0) {
    std::cerr << "Child in user namespace has uid " << getuid() << std::endl;
    return -1;
  }
  if (!container->fs_->mountpt().empty()) {
    // We want to bind mount this inside the specified directory.
    std::string innerdir = container->fs_->root() + container->fs_->mountpt();
    if (verbose) std::cerr << " mount --bind " << container->fs_->mountpt()
                           << " " << innerdir << std::endl;
    int rc = mount(container->fs_->mountpt().c_str(), innerdir.c_str(),
                   "none", MS_BIND, 0);
    if (rc != 0) {
      std::cerr << "Warning: failed to bind mount " << container->fs_->mountpt() << " at "
                << innerdir << ", errno=" << errno << std::endl;
    }
  }

  // Move into the specified directory.
  if (chdir(container->fs_->root().c_str()) != 0) {
    std::cerr << "Failed to chdir('" << container->fs_->root()
              << "'), errno=" << errno << std::endl;
    return -1;
  }
  // And make it the new root directory;
  char buffer[PATH_MAX + 1];
  if (getcwd(buffer, PATH_MAX) == NULL) {
    std::cerr << "failed to retrieve cwd, errno=" << errno << std::endl;
    return -1;
  }
  buffer[PATH_MAX] = '\0';
  if (chroot(buffer) != 0) {
    std::cerr << "chroot('" << buffer << "') failed, errno=" << errno << std::endl;
    return -1;
  }

  // Set host/domainnames if specified
  if (!container->hostname_.empty()) {
    if (sethostname(container->hostname_.c_str(),
                    container->hostname_.size()) != 0) {
      std::cerr << "Failed to sethostname('" << container->hostname_
                << "'), errno=" << errno << std::endl;
      return -1;
    }
  }
  if (!container->domainname_.empty()) {
    if (setdomainname(container->domainname_.c_str(),
                      container->domainname_.size()) != 0) {
      std::cerr << "Failed to setdomainname('" << container->domainname_
                << "'), errno=" << errno << std::endl;
      return -1;
    }
  }

  return container->fn_();
}

}  // namespace

// Run a function while:
//  - chroot()ed into a particular directory
//  - having a specified hostname/domainname

int RunInContainer(ContainerFilesystem* fs, const std::string& hostname,
                   const std::string& domainname, VoidToIntFn fn) {
  const int stack_size = 1024 * 1024;
  std::vector<byte> stack(stack_size, 0);
  ContainerInfo container = {fs, hostname, domainname, fn};

  // Start a child process in a new user and UTS namespace
  pid_t child = clone(EnterContainer, stack.data() + stack_size,
                      CLONE_VM|CLONE_NEWNS|CLONE_NEWUSER|CLONE_NEWUTS|SIGCHLD,
                      (void *)&container);
  if (child < 0) {



( run in 1.422 second using v1.01-cache-2.11-cpan-2398b32b56e )