-
Notifications
You must be signed in to change notification settings - Fork 96
/
Copy pathrun.rs
104 lines (95 loc) · 3.57 KB
/
run.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
use std::env;
use std::fs::{read_link};
use std::io::{stdout, stderr};
use std::path::{Path, PathBuf};
use std::str::FromStr;
use libc::pid_t;
use argparse::{ArgumentParser, Store, List, StoreTrue};
use unshare::{Command};
use crate::process_util::DEFAULT_PATH;
use crate::process_util::{copy_env_vars, run_and_wait, convert_status};
use super::setup;
use super::Wrapper;
use super::util::warn_if_data_container;
pub fn run_command_cmd(wrapper: &Wrapper, cmdline: Vec<String>)
-> Result<i32, String>
{
let mut container: String = "".to_string();
let mut command: String = "".to_string();
let mut args = Vec::<String>::new();
let mut copy = false;
{
let mut ap = ArgumentParser::new();
ap.set_description("
Runs arbitrary command inside the container
");
ap.refer(&mut copy)
.add_option(&["-W", "--writeable"], StoreTrue,
"Create translient writeable container for running the command.
Currently we use hard-linked copy of the container, so it's
dangerous for some operations. Still it's ok for installing
packages or similar tasks");
ap.refer(&mut container)
.add_argument("container_name", Store,
"Container name to build");
ap.refer(&mut command)
.add_argument("command", Store,
"Command to run inside the container");
ap.refer(&mut args)
.add_argument("args", List,
"Arguments for the command");
ap.stop_on_first_argument(true);
match ap.parse(cmdline, &mut stdout(), &mut stderr()) {
Ok(()) => {}
Err(0) => return Ok(0),
Err(_) => {
return Ok(122);
}
}
}
let pid: pid_t = read_link(&Path::new("/proc/self"))
.map_err(|e| format!("Can't read /proc/self: {}", e))
.and_then(|v| v.to_str().and_then(|x| FromStr::from_str(x).ok())
.ok_or(format!("Can't parse pid: {:?}", v)))?;
setup::setup_base_filesystem(
wrapper.project_root, wrapper.ext_settings)?;
let cconfig = wrapper.config.containers.get(&container)
.ok_or(format!("Container {} not found", container))?;
let write_mode = match copy {
false => setup::WriteMode::ReadOnly,
true => setup::WriteMode::TransientHardlinkCopy(pid),
};
let container_ver = wrapper.root.as_ref().unwrap();
let mut setup_info = setup::SetupInfo::from_container(&cconfig);
setup_info.write_mode(write_mode);
warn_if_data_container(&cconfig);
setup::setup_filesystem(&setup_info, container_ver)?;
let env = setup::get_environment(&wrapper.settings, cconfig, None)?;
let mut cpath = PathBuf::from(&command);
let args = args.clone().to_vec();
if !command.contains("/") {
for path in DEFAULT_PATH.split(':') {
let path = Path::new(path).join(&cpath);
if path.exists() {
cpath = path;
break;
}
}
if !cpath.is_absolute() {
return Err(format!("Command {:?} not found in {:?}",
cpath, DEFAULT_PATH));
}
}
let mut cmd = Command::new(cpath);
cmd.args(&args);
cmd.current_dir(&env::var("_VAGGA_WORKDIR")
.unwrap_or("/work".to_string()));
cmd.gid(0);
cmd.groups(Vec::new());
cmd.env_clear();
copy_env_vars(&mut cmd, &wrapper.settings);
for (ref k, ref v) in env.iter() {
cmd.env(k.to_string(), v.to_string());
}
run_and_wait(&mut cmd).map(convert_status)
}