diff --git a/src/bin/installer_tui.rs b/src/bin/installer_tui.rs
index ce71a2f7233471c22154c5500efa1e503be6ea2f..b60de2c78a9ba204bd0b8139cd72171d37f056b7 100644
--- a/src/bin/installer_tui.rs
+++ b/src/bin/installer_tui.rs
@@ -4,8 +4,10 @@ extern crate redoxfs;
 extern crate serde;
 extern crate toml;
 
+use redox_installer::Config;
 use redoxfs::{DiskFile, FileSystem};
 use std::{fs, io, process, sync, thread, time};
+use std::ffi::OsStr;
 use std::ops::DerefMut;
 use std::path::Path;
 use std::process::Command;
@@ -130,13 +132,33 @@ fn with_redoxfs<P, T, F>(disk_path: &P, bootloader: &[u8], callback: F)
         join_handle.join().unwrap()
     };
 
-    fs::remove_file(disk_path).unwrap();
+    res
+}
 
-    if cfg!(not(target_os = "redox")) {
-        fs::remove_dir(mount_path).unwrap();
+fn package_files(config: &mut Config, files: &mut Vec<String>) -> io::Result<()> {
+    //TODO: Remove packages from config where all files are located (and have valid shasum?)
+    for entry_res in fs::read_dir("file:/pkg")? {
+        let entry = entry_res?;
+        let path = entry.path();
+        if path.extension() == Some(OsStr::new("sha256sums")) {
+            let sha256sums = fs::read_to_string(&path)?;
+            for line in sha256sums.lines() {
+                //TODO: Support binary format (second space turns into an asterisk)
+                let mut parts = line.splitn(2, "  ");
+                let _sha256sum = parts.next().ok_or(io::Error::new(
+                    io::ErrorKind::InvalidData,
+                    "Missing checksum in sha256sums"
+                ))?;
+                let name = parts.next().ok_or(io::Error::new(
+                    io::ErrorKind::InvalidData,
+                    "Missing filename in sha256sums"
+                ))?;
+                files.push(name.to_string());
+            }
+        }
     }
 
-    res
+    Ok(())
 }
 
 fn main() {
@@ -195,7 +217,7 @@ fn main() {
     };
 
     let res = with_redoxfs(&disk_path, &bootloader, |mount_path| -> Result<(), failure::Error> {
-        let config = {
+        let mut config = {
             let path = "file:/filesystem.toml";
             match fs::read_to_string(path) {
                 Ok(config_data) => {
@@ -220,11 +242,37 @@ fn main() {
             }
         };
 
-        for name in &["bootloader", "filesystem.toml", "kernel"] {
-            eprintln!("copy {}", name);
+        // Copy bootloader, filesystem.toml, and kernel
+        let mut files = vec![
+            "bootloader".to_string(),
+            "filesystem.toml".to_string(),
+            "kernel".to_string()
+        ];
+
+        // Copy files from locally installed packages
+        if let Err(err) = package_files(&mut config, &mut files) {
+            eprintln!("installer_tui: failed to read package files: {}", err);
+            return Err(failure::Error::from_boxed_compat(
+                Box::new(err))
+            );
+        }
+
+        for (i, name) in files.iter().enumerate() {
+            eprintln!("copy {} [{}/{}]", name, i, files.len());
 
             let src = format!("file:/{}", name);
             let dest = mount_path.join(name);
+            if let Some(parent) = dest.parent() {
+                match fs::create_dir_all(&parent) {
+                    Ok(()) => (),
+                    Err(err) => {
+                        eprintln!("installer_tui: failed to create directory {}: {}", parent.display(), err);
+                        return Err(failure::Error::from_boxed_compat(
+                            Box::new(err))
+                        );
+                    }
+                }
+            }
             match fs::copy(&src, &dest) {
                 Ok(_) => (),
                 Err(err) => {
@@ -236,8 +284,12 @@ fn main() {
             }
         };
 
-        let cookbook: Option<&'static str> = None;
+        eprintln!("finished copying {} files", files.len());
+
+        // Packages will be copied locally, not installed from package server
+        config.packages.clear();
 
+        let cookbook: Option<&'static str> = None;
         redox_installer::install(config, mount_path, cookbook)
     });