Skip to content

Commit

Permalink
tailhook#152 Make vagga_wrapper and user commands group leaders, mana…
Browse files Browse the repository at this point in the history
…ge controlling terminal
  • Loading branch information
anti-social committed Jan 8, 2016
1 parent 86d79a8 commit b35c8aa
Show file tree
Hide file tree
Showing 6 changed files with 126 additions and 14 deletions.
1 change: 1 addition & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ mod container;
mod file_util;
mod path_util;
mod process_util;
mod tty_util;
mod options;

// Commands
Expand Down
43 changes: 41 additions & 2 deletions src/process_util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,18 @@ use std::env;
use std::io::{Read};
use std::path::{Path, PathBuf};

use libc::getuid;
use nix::sys::signal::{SIGINT, SIGTERM, SIGCHLD};
use libc::{getuid, getpgrp};
use nix;
use nix::errno::EINTR;
use nix::sys::signal::{SIGINT, SIGTERM, SIGCHLD, SIGCONT, SIGTTIN, SIGTTOU};
use nix::sys::wait::{waitpid, WaitStatus, WUNTRACED};
use unshare::{Command, Stdio, Fd, ExitStatus, UidMap, GidMap, reap_zombies};
use signal::trap::Trap;

use config::Settings;
use container::uidmap::{Uidmap};
use path_util::PathExt;
use tty_util::give_tty_to;


pub static DEFAULT_PATH: &'static str =
Expand Down Expand Up @@ -97,6 +101,41 @@ pub fn run_and_wait(cmd: &mut Command)
unreachable!();
}

pub fn run_with_tty_and_wait(cmd: &mut Command)
-> Result<i32, String>
{
let pgid = unsafe { getpgrp() };
let child = match cmd.spawn() {
Ok(child) => child,
Err(e) => return Err(format!("Error running {:?}: {}", cmd, e)),
};
loop {
match waitpid(child.pid(), Some(WUNTRACED)) {
Ok(WaitStatus::Stopped(_, signum)) => {
if signum == SIGTTOU || signum == SIGTTIN {
try!(give_tty_to(0, child.pid()));
match child.signal(SIGCONT) {
Ok(_) => continue,
Err(e) => return Err(format!("Error when sending SIGCONT signal to {:?}: {}", cmd, e)),
}
}
// TODO: process SIGTSTP & SIGSTOP
// we should stop current process
},
Ok(WaitStatus::Exited(_, st)) => {
try!(give_tty_to(0, pgid));
return Ok(st as i32);
},
Ok(_) => continue,
Err(nix::Error::Sys(EINTR)) => continue,
Err(e) => {
try!(give_tty_to(0, pgid));
return Err(format!("Error when waiting {:?}: {}", cmd, e));
},
}
}
}

pub fn convert_status(st: ExitStatus) -> i32 {
match st {
ExitStatus::Exited(c) => c as i32,
Expand Down
30 changes: 30 additions & 0 deletions src/tty_util.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
use libc::{c_int, c_ulong, pid_t, sighandler_t};
use libc::funcs::posix01::signal::signal;
use nix::sys::ioctl::ioctl;
use nix::sys::signal::{SIGTTIN, SIGTTOU};


static SIG_IGN: sighandler_t = 1;
static SIG_ERR: sighandler_t = !0;

static TIOCSPGRP: c_ulong = 21520;


pub fn give_tty_to(fd: c_int, pid: pid_t) -> Result<(), String> {
let res = unsafe { ioctl(fd, TIOCSPGRP, &pid) };
match res {
res if res < 0 => Err(format!("Error when giving tty with fd {} to process {}", fd, pid)),
_ => Ok(()),
}
}

pub fn ignore_tty_signals() -> Result<(), String> {
let tty_signals = vec![SIGTTIN, SIGTTOU];
for signum in tty_signals {
let res = unsafe { signal(signum, SIG_IGN) };
if res == SIG_ERR {
return Err(format!("Error when setting signal handler for signum: {}", signum));
}
}
Ok(())
}
14 changes: 10 additions & 4 deletions src/wrapper/commandline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@ use container::uidmap::{map_users};
use super::setup;
use super::Wrapper;
use super::util::find_cmd;
use process_util::{run_and_wait, set_uidmap};
use process_util::{run_and_wait, run_with_tty_and_wait, set_uidmap};


pub fn commandline_cmd(command: &CommandInfo,
wrapper: &Wrapper, mut cmdline: Vec<String>)
wrapper: &Wrapper, mut cmdline: Vec<String>, foreground: bool)
-> Result<i32, String>
{
if command.run.len() == 0 {
Expand Down Expand Up @@ -98,7 +98,13 @@ pub fn commandline_cmd(command: &CommandInfo,
for (ref k, ref v) in env.iter() {
cmd.env(k, v);
}
if foreground {
cmd.make_group_leader(true);
}

run_and_wait(&mut cmd)
.map_err(|e| format!("Error running {:?}: {}", cmd, e))
if foreground {
run_with_tty_and_wait(&mut cmd)
} else {
run_and_wait(&mut cmd)
}
}
36 changes: 33 additions & 3 deletions src/wrapper/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,12 @@ use std::path::Path;
use std::process::exit;

use argparse::{ArgumentParser, Store, StoreOption, List};
use libc::STDIN_FILENO;
use nix::unistd::{isatty, getpid, setpgid};

use super::config::{find_config, Config, Settings};
use super::config::command::MainCommand::{Command, Supervise};
use super::tty_util::{ignore_tty_signals, give_tty_to};
use config::read_settings::{read_settings, MergedSettings};


Expand Down Expand Up @@ -80,6 +83,33 @@ pub fn run() -> i32 {
}
};

match ignore_tty_signals() {
Ok(_) => {},
Err(e) => {
writeln!(&mut err, "{}", e).ok();
return 123;
},
}
let tty_fd = STDIN_FILENO;
let is_foreground = isatty(tty_fd).unwrap_or(false);
if is_foreground {
let pid = getpid();
match setpgid(pid, pid) {
Ok(_) => {},
Err(e) => {
writeln!(&mut err, "{}", e).ok();
return 124;
},
}
match give_tty_to(tty_fd, pid) {
Ok(_) => {},
Err(e) => {
writeln!(&mut err, "{}", e).ok();
return 125;
},
}
}

let wrapper = Wrapper {
root: root,
config: &config,
Expand All @@ -94,14 +124,14 @@ pub fn run() -> i32 {
"_build_shell" => Ok(debug::run_interactive_build_shell(&wrapper)),
"_build" => build::build_container_cmd(&wrapper, args),
"_version_hash" => build::print_version_hash_cmd(&wrapper, args),
"_run" => run::run_command_cmd(&wrapper, args, true),
"_run_in_netns" => run::run_command_cmd(&wrapper, args, false),
"_run" => run::run_command_cmd(&wrapper, args, true, is_foreground),
"_run_in_netns" => run::run_command_cmd(&wrapper, args, false, is_foreground),
"_clean" => clean::clean_cmd(&wrapper, args),
"_pack_image" => pack::pack_image_cmd(&wrapper, args),
_ => {
match config.commands.get(&cmd) {
Some(&Command(ref cmd_info)) => {
commandline::commandline_cmd(cmd_info, &wrapper, args)
commandline::commandline_cmd(cmd_info, &wrapper, args, is_foreground)
}
Some(&Supervise(ref svc_info)) => {
supervise::supervise_cmd(&cmd, svc_info, &wrapper, args)
Expand Down
16 changes: 11 additions & 5 deletions src/wrapper/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,12 @@ use container::uidmap::{map_users};
use super::setup;
use super::Wrapper;
use path_util::PathExt;
use process_util::{convert_status, set_uidmap, copy_env_vars};
use process_util::{run_and_wait, run_with_tty_and_wait};
use process_util::{set_uidmap, copy_env_vars};


pub fn run_command_cmd(wrapper: &Wrapper, cmdline: Vec<String>, user_ns: bool)
pub fn run_command_cmd(wrapper: &Wrapper,
cmdline: Vec<String>, user_ns: bool, foreground: bool)
-> Result<i32, String>
{
let mut container: String = "".to_string();
Expand Down Expand Up @@ -109,9 +111,13 @@ pub fn run_command_cmd(wrapper: &Wrapper, cmdline: Vec<String>, user_ns: bool)
for (ref k, ref v) in env.iter() {
cmd.env(k.to_string(), v.to_string());
}
if foreground {
cmd.make_group_leader(true);
}

match cmd.status() {
Ok(s) => Ok(convert_status(s)),
Err(e) => Err(format!("Error running {:?}: {}", cmd, e)),
if foreground {
run_with_tty_and_wait(&mut cmd)
} else {
run_and_wait(&mut cmd)
}
}

0 comments on commit b35c8aa

Please sign in to comment.