Fork me on GitHub

plash runb


Usage

plash runb IMAGE_ID CHANGESDIR CMD1 [ CMD2 ... ] ]

Description

Run an image in the build environment. Filesystem changes are saved to
CHANGESDIR. This program might be merged together with `plash create` in the
future.

The following host file systems are mapped to the container:
- /etc/resolv.conf
- /sys
- /dev
- /proc
- /home
- /root

Source Code


#define USAGE "usage: plash runb IMAGE_ID CHANGESDIR CMD1 [ CMD2 ... ] ]\n"

#define _GNU_SOURCE
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <pwd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mount.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>

#include <plash.h>

int runb_main(int argc, char *argv[]) {

  if (argc < 4) {
    fputs(USAGE, stderr);
    return EXIT_FAILURE;
  }
  char *container_id = argv[1];
  char *changesdir = argv[2];
  char *origpwd = get_current_dir_name();
  char *plash_data = pl_call("data");
  //
  // get "userspace root"
  //
  pl_unshare_user();
  pl_unshare_mount();

  //
  // prepare an empty mountpoint
  //
  if (chdir(plash_data) == -1)
    pl_fatal("chdir");
  if (mount("tmpfs", "mnt", "tmpfs", MS_MGC_VAL, NULL) == -1)
    pl_fatal("mount");

  //
  // mount root filesystem at the empty mountpoint
  //
  pl_call("mount", container_id, "mnt", changesdir);

  //
  // mount
  //
  if (chdir("mnt") == -1)
    pl_fatal("chdir");
  pl_bind_mount("/sys", "sys");
  pl_bind_mount("/dev", "dev");
  pl_bind_mount("/proc", "proc");
  pl_bind_mount("/home", "home");
  pl_bind_mount("/root", "root");

  // ensure /etc/resolv.conf is a normal file. Because if it where a symlink,
  // mounting over it would not work as expected
  unlink("etc/resolv.conf");
  int fd;
  if ((fd = open("etc/resolv.conf", O_CREAT | O_WRONLY, 0775)) < 0)
    pl_fatal("open");
  close(fd);
  pl_bind_mount("/etc/resolv.conf", "etc/resolv.conf");

  //
  // Import envs
  //
  pl_whitelist_env("TERM");
  pl_whitelist_env("HOME");
  pl_whitelist_env("DISPLAY");
  pl_whitelist_env("PLASH_DATA");
  pl_whitelist_env(NULL);

  //
  // chroot, then reconstruct working directory
  //
  chroot(".") != -1 || pl_fatal("chroot");
  pl_chdir(origpwd);

  //
  // exec!
  //
  char **run_args = argv + 3;
  execvp(*run_args, run_args);
  pl_fatal("execvp");
  return EXIT_FAILURE;
}