diff --git a/programs/contain/src/main.rs b/programs/contain/src/main.rs
index 8e22e23439d33fc9227170d0213b6b30eaccf87a..2e600620c54aa6373523d80493cb312b04366950 100644
--- a/programs/contain/src/main.rs
+++ b/programs/contain/src/main.rs
@@ -2,31 +2,66 @@ extern crate syscall;
 
 use syscall::scheme::Scheme;
 
-use std::{env, fs, thread};
+use std::{env, fs,thread};
+use std::io::{stderr, Write};
 use std::os::unix::process::CommandExt;
-use std::process::Command;
+use std::path::Path;
+use std::process::{self, Command};
 
 use self::chroot::ChrootScheme;
 
 mod chroot;
 
-pub fn main() {
-    let mut args = env::args().skip(1);
+fn usage() -> ! {
+    write!(stderr(), "contain [create|enter] root cmd args..\n").unwrap();
+    process::exit(1);
+}
+
+fn create(root: &Path) {
+    let root = Path::new(root);
 
-    let root_opt = args.next();
+    println!("{}", root.display());
+    fs::create_dir(root).unwrap();
 
-    let cmd = args.next().unwrap_or("sh".to_string());
+    let mut bin = root.to_path_buf();
+    bin.push("bin");
+    println!("{}", bin.display());
+    fs::create_dir(&bin).unwrap();
 
-    let mut names = vec![
+    for entry in fs::read_dir("/bin").unwrap() {
+        let entry = entry.unwrap();
+        let mut dest = bin.clone();
+        dest.push(entry.file_name());
+        println!("{} -> {}", entry.path().display(), dest.display());
+        fs::copy(entry.path(), dest).unwrap();
+    }
+
+    let mut etc = root.to_path_buf();
+    etc.push("etc");
+    println!("{}", etc.display());
+    fs::create_dir(&etc).unwrap();
+
+    let mut net = etc.clone();
+    net.push("net");
+    println!("{}", net.display());
+    fs::create_dir(&net).unwrap();
+
+    for entry in fs::read_dir("/etc/net").unwrap() {
+        let entry = entry.unwrap();
+        let mut dest = net.clone();
+        dest.push(entry.file_name());
+        println!("{} -> {}", entry.path().display(), dest.display());
+        fs::copy(entry.path(), dest).unwrap();
+    }
+}
+
+fn enter(root: &Path, cmd: &str, args: &[String]) {
+    let names = [
         "rand",
         "tcp",
         "udp"
     ];
 
-    if root_opt.is_none() {
-        names.push("file");
-    }
-
     let mut name_ptrs = Vec::new();
     for name in names.iter() {
         name_ptrs.push([name.as_ptr() as usize, name.len()]);
@@ -34,27 +69,24 @@ pub fn main() {
 
     let new_ns = syscall::mkns(&name_ptrs).unwrap();
 
-    let root_thread = if let Some(root) = root_opt {
-        Some(thread::spawn(move || {
-            syscall::setrens(-1isize as usize, new_ns).unwrap();
-            let scheme_fd = syscall::open(":file", syscall::O_CREAT | syscall::O_RDWR | syscall::O_CLOEXEC).unwrap();
-            syscall::setrens(-1isize as usize, syscall::getns().unwrap()).unwrap();
-
-            let chroot_scheme = ChrootScheme::new(fs::canonicalize(root).unwrap());
-            loop {
-                let mut packet = syscall::Packet::default();
-                if syscall::read(scheme_fd, &mut packet).unwrap() == 0 {
-                    break;
-                }
-                chroot_scheme.handle(&mut packet);
-                syscall::write(scheme_fd, &packet).unwrap();
+    let root_canon = fs::canonicalize(root).unwrap();
+    let root_thread = thread::spawn(move || {
+        syscall::setrens(-1isize as usize, new_ns).unwrap();
+        let scheme_fd = syscall::open(":file", syscall::O_CREAT | syscall::O_RDWR | syscall::O_CLOEXEC).unwrap();
+        syscall::setrens(-1isize as usize, syscall::getns().unwrap()).unwrap();
+
+        let chroot_scheme = ChrootScheme::new(root_canon);
+        loop {
+            let mut packet = syscall::Packet::default();
+            if syscall::read(scheme_fd, &mut packet).unwrap() == 0 {
+                break;
             }
+            chroot_scheme.handle(&mut packet);
+            syscall::write(scheme_fd, &packet).unwrap();
+        }
 
-            let _ = syscall::close(scheme_fd);
-        }))
-    } else {
-        None
-    };
+        let _ = syscall::close(scheme_fd);
+    });
 
     let pid = unsafe { syscall::clone(0).unwrap() };
     if pid == 0 {
@@ -88,3 +120,27 @@ pub fn main() {
         println!("Container {}: exit: {:X}", new_ns, status);
     }
 }
+
+pub fn main() {
+    let mut args = env::args().skip(1);
+
+    if let Some(op) = args.next() {
+        match op.as_str() {
+            "create" => if let Some(root) = args.next() {
+                create(Path::new(&root));
+            } else {
+                usage();
+            },
+            "enter" => if let Some(root) = args.next() {
+                let cmd = args.next().unwrap_or("sh".to_string());
+                let args: Vec<String> = args.collect();
+                enter(Path::new(&root), &cmd, &args);
+            } else {
+                usage();
+            },
+            _ => usage()
+        }
+    } else {
+        usage();
+    }
+}
diff --git a/programs/coreutils b/programs/coreutils
index 3308c4507cfe7c3922e41ad472d792dac864e83f..c043ba9089b81e805a0c98e8e9caf4a54a9603f7 160000
--- a/programs/coreutils
+++ b/programs/coreutils
@@ -1 +1 @@
-Subproject commit 3308c4507cfe7c3922e41ad472d792dac864e83f
+Subproject commit c043ba9089b81e805a0c98e8e9caf4a54a9603f7