diff --git a/README.md b/README.md
index 82e393021e6bf56ec096ed3ec5b9ae0dcd5e0131..4eedf34aef7b383b3df84150cd57c8502832b3cb 100644
--- a/README.md
+++ b/README.md
@@ -99,9 +99,34 @@ the internal built-in cd command with that path as the argument.
 examples/   # cd examples/
 ```
 
-### Exiting the Shell
+### Job Control
 
-The `exit` command will exit the shell, but unlike Bash, this will send a `SIGTERM` to any background tasks that are still active.
+#### Disowning Processes
+
+Ion features a `disown` command which supports the following flags:
+
+- **-r**: Remove all running jobs from the background process list.
+- **-h**: Specifies that each job supplied will not receive the `SIGHUP` signal when the shell receives a `SIGHUP`.
+- **-a**: If no job IDs were supplied, remove all jobs from the background process list.
+
+Unlike Bash, job arguments are their specified job IDs.
+
+#### Foreground & Background Tasks
+
+This area is still a work in progress. When a foreground task is stopped with the **Ctrl+Z** signal, that process will
+be added to the background process list as a stopped job. When a supplied command ends with the **&** operator, this
+will specify to run the task the background as a running job. To resume a stopped job, executing the `bg <job_id>`
+command will send a `SIGCONT` to the specified job ID, hence resuming the job. The `fg` command doesn't work at the
+moment though (coming soon).
+
+#### Exiting the Shell
+
+The `exit` command will exit the shell, sending a `SIGTERM` to any background tasks that are still active.
+
+#### Suspending the Shell
+
+While the shell ignores `SIGTSTP` signals, you can forcefully suspend the shell by executing the `suspend` command,
+which forcefully stops the shell via a `SIGSTOP` signal.
 
 ### Defining Variables
 
diff --git a/src/builtins/job_control.rs b/src/builtins/job_control.rs
index e0a0396edbcf38a2429b01406b06e03676096dc1..b53b10f0645a18031d3492ba68a517ff860b7f5f 100644
--- a/src/builtins/job_control.rs
+++ b/src/builtins/job_control.rs
@@ -21,8 +21,8 @@ pub fn set_foreground(pid: u32) {
 
 #[cfg(all(unix, not(target_os = "redox")))]
 /// Suspends a given process by it's process ID.
-fn suspend(pid: u32) {
-    let _ = signal::kill(-(pid as pid_t), Some(Signal::SIGTSTP));
+pub fn suspend(pid: u32) {
+    let _ = signal::kill(-(pid as pid_t), Some(Signal::SIGSTOP));
 }
 
 #[cfg(all(unix, not(target_os = "redox")))]
@@ -31,8 +31,72 @@ fn resume(pid: u32) {
     let _ = signal::kill(-(pid as pid_t), Some(Signal::SIGCONT));
 }
 
+pub fn disown(shell: &mut Shell, args: &[&str]) -> i32 {
+    let stderr = stderr();
+    let mut stderr = stderr.lock();
+    const NO_SIGHUP: u8 = 1;
+    const ALL_JOBS:  u8 = 2;
+    const RUN_JOBS:  u8 = 4;
+
+    let mut jobspecs = Vec::new();
+    let mut flags = 0u8;
+    for &arg in args {
+        match arg {
+            "-a" => flags |= ALL_JOBS,
+            "-h" => flags |= NO_SIGHUP,
+            "-r" => flags |= RUN_JOBS,
+            _    => match arg.parse::<u32>() {
+                Ok(jobspec) => jobspecs.push(jobspec),
+                Err(_) => {
+                    let _ = writeln!(stderr, "ion: disown: invalid jobspec: '{}'", arg);
+                    return FAILURE
+                },
+            }
+        }
+    }
+
+    let mut processes = shell.background.lock().unwrap();
+    if jobspecs.is_empty() && flags & ALL_JOBS != 0 {
+        if flags & NO_SIGHUP != 0 {
+            for process in processes.iter_mut() {
+                process.ignore_sighup = true;
+            }
+        } else {
+            for process in processes.iter_mut() {
+                process.state = ProcessState::Empty;
+            }
+        }
+    } else {
+        jobspecs.sort();
+
+        let mut jobspecs = jobspecs.into_iter();
+        let mut current_jobspec = jobspecs.next().unwrap();
+        for (id, process) in processes.iter_mut().enumerate() {
+            if id == current_jobspec as usize {
+                if flags & NO_SIGHUP != 0 { process.ignore_sighup = true; }
+                process.state = ProcessState::Empty;
+                match jobspecs.next() {
+                    Some(jobspec) => current_jobspec = jobspec,
+                    None          => break
+                }
+            }
+        }
+
+        if flags & RUN_JOBS != 0 {
+            for process in processes.iter_mut() {
+                if process.state == ProcessState::Running {
+                    process.state = ProcessState::Empty;
+                }
+            }
+        }
+    }
+
+    SUCCESS
+}
+
+
 #[cfg(target_os = "redox")]
-fn suspend(pid: u32) {
+pub fn suspend(pid: u32) {
     use syscall;
     let _ = syscall::kill(pid as usize, syscall::SIGSTOP);
 }
diff --git a/src/builtins/mod.rs b/src/builtins/mod.rs
index 264f3ffd9807dc642a7e5a5c9423007b0a564a5f..75076252530b2c8562ec749ef14128692eb1b558 100644
--- a/src/builtins/mod.rs
+++ b/src/builtins/mod.rs
@@ -21,7 +21,7 @@ use std::process;
 use std::error::Error;
 
 use parser::QuoteTerminator;
-use shell::job_control::JobControl;
+use shell::job_control::{JobControl, ProcessState};
 use shell::{Shell, FlowLogic, ShellHistory};
 use shell::status::*;
 
@@ -46,9 +46,11 @@ fn exit_builtin() -> Builtin {
             use nix::sys::signal::{self, Signal as NixSignal};
             use libc::pid_t;
 
-            // Kill all background tasks before exiting the shell.
+            // Kill all active background tasks before exiting the shell.
             for process in shell.background.lock().unwrap().iter() {
-                let _ = signal::kill(process.pid as pid_t, Some(NixSignal::SIGTERM));
+                if process.state != ProcessState::Empty {
+                    let _ = signal::kill(process.pid as pid_t, Some(NixSignal::SIGTERM));
+                }
             }
 
             process::exit(args.get(1).and_then(|status| status.parse::<i32>().ok())
@@ -256,6 +258,23 @@ impl Builtin {
             })
         });
 
+        commands.insert("suspend", Builtin {
+            name: "suspend",
+            help: "Suspends the shell with a SIGTSTOP signal",
+            main: Box::new(|args: &[&str], shell: &mut Shell| -> i32 {
+                job_control::suspend(0);
+                SUCCESS
+            })
+        });
+
+        commands.insert("disown", Builtin {
+            name: "disown",
+            help: "Disowning a process removes that process from the shell's background process table.",
+            main: Box::new(|args: &[&str], shell: &mut Shell| -> i32 {
+                job_control::disown(shell, &args[1..])
+            })
+        });
+
         commands.insert("history",
                         Builtin {
                             name: "history",
diff --git a/src/main.rs b/src/main.rs
index 7bf6860a8e58d66b04c9c1b0f7e6ad3c36cb4f6b..6b604effbf7171a5ca30a656475bcf040dd6005d 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -81,13 +81,14 @@ fn main() {
     let mut core = Core::new().unwrap();
     let handle = core.handle();
 
-    // Mask the SIGTSTP signal -- prevents the shell from being stopped
+    // Block the SIGTSTP signal -- prevents the shell from being stopped
     // when the foreground group is changed during command execution.
-    mask_sigstp();
+    block_signals();
 
-    // Create a stream that will select over SIGINT and SIGTERM signals.
+    // Create a stream that will select over SIGINT, SIGTERM, and SIGHUP signals.
     let signals = Signal::new(unix_signal::SIGINT, &handle).flatten_stream()
-        .select(Signal::new(unix_signal::SIGTERM, &handle).flatten_stream());
+        .select(Signal::new(unix_signal::SIGTERM, &handle).flatten_stream())
+        .select(Signal::new(unix_signal::SIGHUP, &handle).flatten_stream());
 
     // Execute the event loop that will listen for and transmit received
     // signals to the shell.
@@ -104,19 +105,22 @@ fn main() {
 }
 
 #[cfg(all(unix, not(target_os = "redox")))]
-fn mask_sigstp() {
+fn block_signals() {
     unsafe {
-        use libc::{sigset_t, SIGTSTP, SIG_BLOCK, sigemptyset, sigaddset, sigprocmask};
+        use libc::*;
         use std::mem;
         use std::ptr;
         let mut sigset = mem::uninitialized::<sigset_t>();
         sigemptyset(&mut sigset as *mut sigset_t);
         sigaddset(&mut sigset as *mut sigset_t, SIGTSTP);
+        sigaddset(&mut sigset as *mut sigset_t, SIGTTOU);
+        sigaddset(&mut sigset as *mut sigset_t, SIGTTIN);
+        sigaddset(&mut sigset as *mut sigset_t, SIGCHLD);
         sigprocmask(SIG_BLOCK, &sigset as *const sigset_t, ptr::null_mut() as *mut sigset_t);
     }
 }
 
 #[cfg(target_os = "redox")]
-fn mask_sigstp() {
+fn block_signals() {
     // TODO
 }
diff --git a/src/shell/job_control.rs b/src/shell/job_control.rs
index 1dfa4df15f793b6b52938c4e8ce46d43eb6c8326..6ea857756a7b11ba0189d52bb1df5738bfaee1fe 100644
--- a/src/shell/job_control.rs
+++ b/src/shell/job_control.rs
@@ -17,7 +17,7 @@ pub trait JobControl {
     fn send_to_background(&mut self, child: u32, state: ProcessState);
 }
 
-#[derive(Clone)]
+#[derive(Clone, Copy, Debug, PartialEq)]
 /// Defines whether the background process is running or stopped.
 pub enum ProcessState {
     Running,
@@ -46,9 +46,9 @@ pub fn watch_background_pid (
     pid: u32,
     njob: usize)
 {
-    use nix::sys::wait::{waitpid, WaitStatus, WUNTRACED, WNOHANG};
+    use nix::sys::wait::*;
     loop {
-        match waitpid(-(pid as pid_t), Some(WUNTRACED | WNOHANG)) {
+        match waitpid(-(pid as pid_t), Some(WUNTRACED)) {
             Ok(WaitStatus::Exited(_, status)) => {
                 eprintln!("ion: ([{}] {}) exited with {}", njob, pid, status);
                 let mut processes = processes.lock().unwrap();
@@ -77,7 +77,6 @@ pub fn watch_background_pid (
                 break
             }
         }
-        sleep(Duration::from_millis(100));
     }
 }
 
@@ -93,6 +92,7 @@ pub fn add_to_background (
         Some(id) => {
             (*processes)[id] = BackgroundProcess {
                 pid: pid,
+                ignore_sighup: false,
                 state: state
             };
             id
@@ -101,6 +101,7 @@ pub fn add_to_background (
             let njobs = (*processes).len();
             (*processes).push(BackgroundProcess {
                 pid: pid,
+                ignore_sighup: false,
                 state: state
             });
             njobs
@@ -115,6 +116,7 @@ pub fn add_to_background (
 /// process is executing.
 pub struct BackgroundProcess {
     pub pid: u32,
+    pub ignore_sighup: bool,
     pub state: ProcessState
     // TODO: Each process should have the command registered to it
     // pub command: String
@@ -160,6 +162,8 @@ impl<'a> JobControl for Shell<'a> {
                     eprintln!("ion: process ended by signal");
                     if signal == Signal::SIGTERM {
                         self.handle_signal(libc::SIGTERM);
+                    } else if signal == Signal::SIGHUP {
+                        self.handle_signal(libc::SIGHUP);
                     } else if signal == Signal::SIGINT {
                         self.foreground_send(libc::SIGINT as i32);
                     }
@@ -230,9 +234,17 @@ impl<'a> JobControl for Shell<'a> {
     #[cfg(all(unix, not(target_os = "redox")))]
     /// Send a kill signal to all running background tasks.
     fn background_send(&self, signal: i32) {
-        for process in self.background.lock().unwrap().iter() {
-            if let ProcessState::Running = process.state {
-                let _ = signal::kill(-(process.pid as pid_t), NixSignal::from_c_int(signal as c_int).ok());
+        if signal == libc::SIGHUP {
+            for process in self.background.lock().unwrap().iter() {
+                if !process.ignore_sighup {
+                    let _ = signal::kill(-(process.pid as pid_t), NixSignal::from_c_int(signal as c_int).ok());
+                }
+            }
+        } else {
+            for process in self.background.lock().unwrap().iter() {
+                if let ProcessState::Running = process.state {
+                    let _ = signal::kill(-(process.pid as pid_t), NixSignal::from_c_int(signal as c_int).ok());
+                }
             }
         }
     }
@@ -255,8 +267,8 @@ impl<'a> JobControl for Shell<'a> {
     /// before the shell terminates itself.
     #[cfg(all(unix, not(target_os = "redox")))]
     fn handle_signal(&self, signal: i32) {
-        if signal == libc::SIGTERM {
-            self.background_send(libc::SIGTERM);
+        if signal == libc::SIGTERM || signal == libc::SIGHUP {
+            self.background_send(signal);
             process::exit(TERMINATED);
         }
     }
diff --git a/src/shell/pipe.rs b/src/shell/pipe.rs
index b741f6a38607f5c55ed85b9a66ce347c734e5304..7dee66a671df9a121be9878d6db55cfa4b253d34 100644
--- a/src/shell/pipe.rs
+++ b/src/shell/pipe.rs
@@ -44,14 +44,17 @@ mod crossplat {
         }
     }
 
-    pub fn unmask_sigtstp() {
+    pub fn unblock_signals() {
         unsafe {
-            use libc::{sigset_t, SIG_UNBLOCK, SIGTSTP, sigemptyset, sigaddset, sigprocmask};
+            use libc::*;
             use std::mem;
             use std::ptr;
             let mut sigset = mem::uninitialized::<sigset_t>();
             sigemptyset(&mut sigset as *mut sigset_t);
             sigaddset(&mut sigset as *mut sigset_t, SIGTSTP);
+            sigaddset(&mut sigset as *mut sigset_t, SIGTTOU);
+            sigaddset(&mut sigset as *mut sigset_t, SIGTTIN);
+            sigaddset(&mut sigset as *mut sigset_t, SIGCHLD);
             sigprocmask(SIG_UNBLOCK, &sigset as *const sigset_t, ptr::null_mut() as *mut sigset_t);
         }
     }
@@ -127,7 +130,7 @@ mod crossplat {
         }
     }
 
-    pub fn unmask_sigtstp() {
+    pub fn unblock_signals() {
         // TODO
     }
 
@@ -293,7 +296,7 @@ fn fork_pipe(shell: &mut Shell, commands: Vec<(Command, JobKind)>) -> i32 {
             SUCCESS
         },
         Ok(Fork::Child) => {
-            unmask_sigtstp();
+            unblock_signals();
             create_process_group();
             exit(pipe(shell, commands, false));
         },
@@ -332,7 +335,6 @@ fn pipe (
 
             match kind {
                 JobKind::Pipe(mut mode) => {
-
                     // We need to remember the commands as they own the file descriptors that are
                     // created by crossplat::create_pipe. We purposfully drop the pipes that are
                     // owned by a given command in `wait` in order to close those pipes, sending
@@ -343,7 +345,7 @@ fn pipe (
                     macro_rules! spawn_proc {
                         ($cmd:expr) => {{
                             let child = $cmd.before_exec(move || {
-                                unmask_sigtstp();
+                                unblock_signals();
                                 create_process_group();
                                 Ok(())
                             }).spawn();
@@ -412,12 +414,12 @@ fn terminate_fg(shell: &mut Shell) {
 
 #[cfg(target_os = "redox")]
 fn terminate_fg(shell: &mut Shell) {
-    shell.foreground_send(syscall::SIGTERM as i32);
+        shell.foreground_send(syscall::SIGTERM as i32);
 }
 
 fn execute_command(shell: &mut Shell, command: &mut Command, foreground: bool) -> i32 {
     match command.before_exec(move || {
-        unmask_sigtstp();
+        unblock_signals();
         create_process_group();
         Ok(())
     }).spawn() {