diff options
author | Matthias Schiffer <mschiffer@universe-factory.net> | 2021-02-05 20:15:11 +0100 |
---|---|---|
committer | Matthias Schiffer <mschiffer@universe-factory.net> | 2021-02-05 20:15:11 +0100 |
commit | e78e29eae4a0cf2e3f46c6a117e1fe86219efe96 (patch) | |
tree | 29b4b4c2bbd47329d2c11b5ca7fbc7629401d662 | |
parent | da9fa7d1ad81528c60607f488f84155a3ecc3ee6 (diff) | |
download | rebel-e78e29eae4a0cf2e3f46c6a117e1fe86219efe96.tar rebel-e78e29eae4a0cf2e3f46c6a117e1fe86219efe96.zip |
IPC setup
-rw-r--r-- | Cargo.lock | 360 | ||||
-rw-r--r-- | Cargo.toml | 1 | ||||
-rw-r--r-- | src/executor.rs | 7 | ||||
-rw-r--r-- | src/main.rs | 42 | ||||
-rw-r--r-- | src/prepared_command.rs | 100 | ||||
-rw-r--r-- | src/runner.rs | 2 | ||||
-rw-r--r-- | src/runner/runc.rs | 88 | ||||
-rw-r--r-- | src/runner/runc/init.rs | 47 | ||||
-rw-r--r-- | src/runner/runc/run.rs | 18 | ||||
-rw-r--r-- | src/types.rs | 4 | ||||
-rw-r--r-- | src/unshare.rs | 31 | ||||
-rw-r--r-- | src/util.rs | 20 |
12 files changed, 542 insertions, 178 deletions
@@ -1,12 +1,34 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. [[package]] +name = "autocfg" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" + +[[package]] +name = "bincode" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f30d3a39baa26f9651f17b375061f3233dde33424a8b72b0dbe93a68a0bc896d" +dependencies = [ + "byteorder", + "serde", +] + +[[package]] name = "bitflags" version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" [[package]] +name = "byteorder" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae44d1a3d5a19df61dd0c8beb138458ac2a53a7ac09eba97d55592540004306b" + +[[package]] name = "cc" version = "1.0.66" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -14,17 +36,130 @@ checksum = "4c0496836a84f8d0495758516b8621a622beb77c0fed418570e50764093ced48" [[package]] name = "cfg-if" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" + +[[package]] +name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] +name = "crossbeam-channel" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b153fe7cbef478c567df0f972e02e6d736db11affe43dfc9c56a9374d1adfb87" +dependencies = [ + "crossbeam-utils", + "maybe-uninit", +] + +[[package]] +name = "crossbeam-utils" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8" +dependencies = [ + "autocfg", + "cfg-if 0.1.10", + "lazy_static", +] + +[[package]] name = "dtoa" version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "88d7ed2934d741c6b37e33e3832298e8850b53fd2d2bea03873375596c7cea4e" [[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "fuchsia-zircon" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" +dependencies = [ + "bitflags", + "fuchsia-zircon-sys", +] + +[[package]] +name = "fuchsia-zircon-sys" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" + +[[package]] +name = "getrandom" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" +dependencies = [ + "cfg-if 1.0.0", + "libc", + "wasi 0.9.0+wasi-snapshot-preview1", +] + +[[package]] +name = "getrandom" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9495705279e7140bf035dde1f6e750c162df8b625267cd52cc44e0b156732c8" +dependencies = [ + "cfg-if 1.0.0", + "libc", + "wasi 0.10.2+wasi-snapshot-preview1", +] + +[[package]] +name = "iovec" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e" +dependencies = [ + "libc", +] + +[[package]] +name = "ipc-channel" +version = "0.14.1" +source = "git+https://github.com/NeoRaider/ipc-channel.git?branch=integration#5dc12c729c316574af2245447648632ddd50de63" +dependencies = [ + "bincode", + "crossbeam-channel", + "fnv", + "lazy_static", + "libc", + "mio", + "rand 0.7.3", + "serde", + "tempfile", + "uuid", +] + +[[package]] +name = "kernel32-sys" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" +dependencies = [ + "winapi 0.2.8", + "winapi-build", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] name = "libc" version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -42,7 +177,55 @@ version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", +] + +[[package]] +name = "maybe-uninit" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" + +[[package]] +name = "mio" +version = "0.6.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4afd66f5b91bf2a3bc13fad0e21caedac168ca4c707504e75585648ae80e4cc4" +dependencies = [ + "cfg-if 0.1.10", + "fuchsia-zircon", + "fuchsia-zircon-sys", + "iovec", + "kernel32-sys", + "libc", + "log", + "miow", + "net2", + "slab", + "winapi 0.2.8", +] + +[[package]] +name = "miow" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebd808424166322d4a38da87083bfddd3ac4c131334ed55856112eb06d46944d" +dependencies = [ + "kernel32-sys", + "net2", + "winapi 0.2.8", + "ws2_32-sys", +] + +[[package]] +name = "net2" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "391630d12b68002ae1e25e8f974306474966550ad82dac6886fb8910c19568ae" +dependencies = [ + "cfg-if 0.1.10", + "libc", + "winapi 0.3.9", ] [[package]] @@ -53,11 +236,17 @@ checksum = "b2ccba0cfe4fdf15982d1674c69b1fd80bad427d293849982668dfe454bd61f2" dependencies = [ "bitflags", "cc", - "cfg-if", + "cfg-if 1.0.0", "libc", ] [[package]] +name = "ppv-lite86" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" + +[[package]] name = "proc-macro2" version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -76,9 +265,91 @@ dependencies = [ ] [[package]] +name = "rand" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" +dependencies = [ + "getrandom 0.1.16", + "libc", + "rand_chacha 0.2.2", + "rand_core 0.5.1", + "rand_hc 0.2.0", +] + +[[package]] +name = "rand" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ef9e7e66b4468674bfcb0c81af8b7fa0bb154fa9f28eb840da5c447baeb8d7e" +dependencies = [ + "libc", + "rand_chacha 0.3.0", + "rand_core 0.6.1", + "rand_hc 0.3.0", +] + +[[package]] +name = "rand_chacha" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" +dependencies = [ + "ppv-lite86", + "rand_core 0.5.1", +] + +[[package]] +name = "rand_chacha" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e12735cf05c9e10bf21534da50a147b924d555dc7a547c42e6bb2d5b6017ae0d" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.1", +] + +[[package]] +name = "rand_core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" +dependencies = [ + "getrandom 0.1.16", +] + +[[package]] +name = "rand_core" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c026d7df8b298d90ccbbc5190bd04d85e159eaf5576caeacf8741da93ccbd2e5" +dependencies = [ + "getrandom 0.2.2", +] + +[[package]] +name = "rand_hc" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" +dependencies = [ + "rand_core 0.5.1", +] + +[[package]] +name = "rand_hc" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3190ef7066a446f2e7f42e239d161e905420ccab01eb967c9eb27d21b2322a73" +dependencies = [ + "rand_core 0.6.1", +] + +[[package]] name = "rebel" version = "0.1.0" dependencies = [ + "ipc-channel", "libc", "nix", "scopeguard", @@ -89,6 +360,24 @@ dependencies = [ ] [[package]] +name = "redox_syscall" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05ec8ca9416c5ea37062b502703cd7fcb207736bc294f6e0cf367ac6fc234570" +dependencies = [ + "bitflags", +] + +[[package]] +name = "remove_dir_all" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" +dependencies = [ + "winapi 0.3.9", +] + +[[package]] name = "same-file" version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -136,6 +425,12 @@ dependencies = [ ] [[package]] +name = "slab" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" + +[[package]] name = "syn" version = "1.0.59" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -147,6 +442,20 @@ dependencies = [ ] [[package]] +name = "tempfile" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22" +dependencies = [ + "cfg-if 1.0.0", + "libc", + "rand 0.8.3", + "redox_syscall", + "remove_dir_all", + "winapi 0.3.9", +] + +[[package]] name = "unicode-xid" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -163,17 +472,44 @@ dependencies = [ ] [[package]] +name = "uuid" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" +dependencies = [ + "getrandom 0.2.2", +] + +[[package]] name = "walkdir" version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "777182bc735b6424e1a57516d35ed72cb8019d85c8c9bf536dccb3445c1a2f7d" dependencies = [ "same-file", - "winapi", + "winapi 0.3.9", "winapi-util", ] [[package]] +name = "wasi" +version = "0.9.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" + +[[package]] +name = "wasi" +version = "0.10.2+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" + +[[package]] +name = "winapi" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" + +[[package]] name = "winapi" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -184,6 +520,12 @@ dependencies = [ ] [[package]] +name = "winapi-build" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" + +[[package]] name = "winapi-i686-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -195,7 +537,7 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" dependencies = [ - "winapi", + "winapi 0.3.9", ] [[package]] @@ -205,6 +547,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] +name = "ws2_32-sys" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" +dependencies = [ + "winapi 0.2.8", + "winapi-build", +] + +[[package]] name = "yaml-rust" version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -8,6 +8,7 @@ edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +ipc-channel = { git = "https://github.com/NeoRaider/ipc-channel.git", branch = "integration" } libc = "0.2.84" nix = "0.19.1" scopeguard = "1.1.0" diff --git a/src/executor.rs b/src/executor.rs index 814aa79..1340f83 100644 --- a/src/executor.rs +++ b/src/executor.rs @@ -50,7 +50,7 @@ impl<'a> Executor<'a> { fn run_one(&mut self, runner: &impl runner::Runner) -> runner::Result<()> { let task = self.tasks_runnable.pop().expect("No runnable tasks left"); - runner.run(&task)?; + runner.run(self.tasks, &task)?; let rdeps = self.rdeps.get(&task); @@ -69,10 +69,9 @@ impl<'a> Executor<'a> { Ok(()) } - pub fn run(&mut self) -> runner::Result<()> { - let runner = runner::runc::RuncRunner::new(self.tasks); + pub fn run(&mut self, runner: &impl runner::Runner) -> runner::Result<()> { while !self.tasks_runnable.is_empty() { - self.run_one(&runner)?; + self.run_one(runner)?; } assert!(self.tasks_blocked.is_empty(), "No runnable tasks left"); diff --git a/src/main.rs b/src/main.rs index 8d4787d..d3ac7c8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,4 @@ mod executor; -mod prepared_command; mod recipe; mod resolve; mod runner; @@ -7,43 +6,13 @@ mod types; mod unshare; mod util; -use nix::{ - mount::{self, MsFlags}, - unistd, -}; -use std::{io::Result, path::Path}; +use std::path::Path; use types::*; -use util::ToIOResult; - -fn mount_buildtmp() -> Result<()> { - mount::mount::<_, _, _, str>( - Some("buildtmp"), - "build/tmp", - Some("tmpfs"), - MsFlags::empty(), - None, - ) - .to_io_result() -} - -fn exec_shell() -> Result<std::convert::Infallible> { - let bin_sh = std::ffi::CString::new("/bin/sh").unwrap(); - unistd::execv(&bin_sh, &[&bin_sh]).to_io_result() -} - -fn execute(mut exc: executor::Executor) -> Result<()> { - unshare::unshare()?; - mount_buildtmp()?; - - exc.run()?; - - exec_shell()?; - - Ok(()) -} fn main() { + let runner = unsafe { runner::runc::RuncRunner::new() }.unwrap(); + let recipes = recipe::read_recipes(Path::new("examples")).unwrap(); let mut tasks: TaskMap = TaskMap::default(); @@ -64,9 +33,8 @@ fn main() { std::process::exit(1); } let taskset = rsv.to_taskset(); - let exc = executor::Executor::new(&tasks, taskset); - - if let Err(error) = execute(exc) { + let mut exc = executor::Executor::new(&tasks, taskset); + if let Err(error) = exc.run(&runner) { eprintln!("{}", error); std::process::exit(1); } diff --git a/src/prepared_command.rs b/src/prepared_command.rs deleted file mode 100644 index 8297095..0000000 --- a/src/prepared_command.rs +++ /dev/null @@ -1,100 +0,0 @@ -use std::{ - ffi::{CString, OsStr}, - io::{Error, ErrorKind, Result}, - iter, - os::unix::{ffi::*, io::RawFd}, - ptr, -}; - -use libc::{c_char, c_void}; -use nix::{fcntl::OFlag, sys::wait, unistd}; - -use crate::util::ToIOResult; - -#[derive(Clone, Debug)] -pub struct PreparedCommandBuilder { - program: CString, - args: Vec<CString>, -} - -#[derive(Debug)] -pub struct PreparedCommand { - child: unistd::Pid, - pipew: RawFd, -} - -impl Drop for PreparedCommand { - fn drop(&mut self) { - assert!(unistd::close(self.pipew).is_ok()); - } -} - -fn os2c<S: AsRef<OsStr>>(s: S) -> CString { - CString::new(s.as_ref().as_bytes()).unwrap() -} - -impl PreparedCommandBuilder { - pub fn arg<S: AsRef<OsStr>>(&mut self, arg: S) -> &mut Self { - self.args.push(os2c(arg)); - self - } - - pub fn prepare(&mut self) -> Result<PreparedCommand> { - let exe_p = self.program.as_ptr(); - - let argv: Vec<*const c_char> = iter::once(exe_p) - .chain(self.args.iter().map(|arg| arg.as_ptr())) - .chain(iter::once(ptr::null())) - .collect(); - - let argv_p = argv.as_ptr(); - - let (piper, pipew) = unistd::pipe2(OFlag::O_CLOEXEC).to_io_result()?; - - unsafe { - match unistd::fork().to_io_result()? { - unistd::ForkResult::Parent { child } => { - let cmd = PreparedCommand { child, pipew }; - assert!(unistd::close(piper).is_ok()); - return Ok(cmd); - } - unistd::ForkResult::Child => {} - } - - // Child process - only async-signal-safe calls allowed - - if libc::close(pipew) != 0 { - libc::_exit(126); - } - - // Wait for run trigger - let mut buf = [0u8; 1]; - if libc::read(piper, buf.as_mut_ptr() as *mut c_void, buf.len()) != 1 { - // PreparedCommand was dropped, or controlling process exited - libc::_exit(126); - } - - libc::execvp(exe_p, argv_p); - - // exec failed - libc::_exit(127); - } - } -} - -impl PreparedCommand { - pub fn new<S: AsRef<OsStr>>(program: S) -> PreparedCommandBuilder { - PreparedCommandBuilder { - program: os2c(program), - args: Vec::new(), - } - } - - pub fn run(self) -> Result<wait::WaitStatus> { - if unistd::write(self.pipew, &[0]).to_io_result()? != 1 { - return Err(Error::new(ErrorKind::Other, "command trigger write failed")); - } - - wait::waitpid(Some(self.child), None).to_io_result() - } -} diff --git a/src/runner.rs b/src/runner.rs index a290aeb..810586c 100644 --- a/src/runner.rs +++ b/src/runner.rs @@ -7,5 +7,5 @@ use crate::types::*; pub type Result<T> = io::Result<T>; pub trait Runner { - fn run(&self, task: &TaskRef) -> Result<()>; + fn run(&self, tasks: &TaskMap, task: &TaskRef) -> Result<()>; } diff --git a/src/runner/runc.rs b/src/runner/runc.rs index b323d5d..663dc7a 100644 --- a/src/runner/runc.rs +++ b/src/runner/runc.rs @@ -1,21 +1,87 @@ -use super::*; -use crate::types::TaskMap; +mod init; +mod run; -pub struct RuncRunner<'a> { - tasks: &'a TaskMap, +use std::{io, process}; + +use ipc_channel::ipc; +use nix::unistd; +use serde::{Deserialize, Serialize}; + +use crate::types::*; +use crate::unshare; +use crate::util::CheckDisconnect; + +#[derive(Debug, Deserialize, Serialize)] +struct Request(TaskRef, Task, ipc::IpcSender<run::Error>); + +fn runner(init_error_sender: ipc::IpcSender<init::Error>, channel: ipc::IpcReceiver<Request>) -> ! { + if let Err(error) = init::runc_initialize() { + init_error_sender.send(error).expect("IPC send() failed"); + process::exit(1); + } + + drop(init_error_sender); + + while let Ok(request) = channel.recv() { + let Request(task, task_def, reply_sender) = request; + if let Err(error) = run::handle_task(task, task_def) { + reply_sender.send(error).expect("IPC send() failed"); + } + } + + process::exit(0); +} + +pub struct RuncRunner { + channel: ipc::IpcSender<Request>, } -impl<'a> RuncRunner<'a> { - pub fn new(tasks: &'a TaskMap) -> Self { - RuncRunner { tasks } +impl RuncRunner { + /// Creates a new Runc runner + /// + /// Unsafe: Do not call in multithreaded processes + pub unsafe fn new() -> io::Result<Self> { + let (tx, rx) = ipc::channel().expect("IPC channel creation failed"); + let (init_error_tx, init_error_rx) = ipc::channel().expect("IPC channel creation failed"); + + let pid = match unistd::fork().expect("fork()") { + unistd::ForkResult::Parent { child } => { + drop(rx); + drop(init_error_tx); + child + } + unistd::ForkResult::Child => { + drop(tx); + drop(init_error_rx); + runner(init_error_tx, rx); + /* Not reached */ + } + }; + + init_error_rx + .recv() + .check_disconnect() + .expect("IPC recv() error")?; + + unshare::idmap(pid)?; + + Ok(RuncRunner { channel: tx }) } } -impl<'a> Runner for RuncRunner<'a> { - fn run(&self, task: &TaskRef) -> Result<()> { - let task_def = self.tasks.get(task).expect("Invalid TaskRef"); +impl super::Runner for RuncRunner { + fn run(&self, tasks: &TaskMap, task: &TaskRef) -> super::Result<()> { + let task_def = tasks.get(task).expect("Invalid TaskRef"); + let (reply_tx, reply_rx) = ipc::channel().expect("IPC channel creation failed"); + + self.channel + .send(Request(task.clone(), task_def.clone(), reply_tx)) + .expect("RuncRunner task submission failed"); - println!("{}:\n\t{:?}", task, task_def); + reply_rx + .recv() + .check_disconnect() + .expect("IPC recv() error")?; Ok(()) } diff --git a/src/runner/runc/init.rs b/src/runner/runc/init.rs new file mode 100644 index 0000000..02b89e4 --- /dev/null +++ b/src/runner/runc/init.rs @@ -0,0 +1,47 @@ +use std::io; + +use nix::{ + mount::{self, MsFlags}, + sched::{self, CloneFlags}, +}; +use serde::{Deserialize, Serialize}; + +fn mount_buildtmp() -> nix::Result<()> { + mount::mount::<_, _, _, str>( + Some("buildtmp"), + "build/tmp", + Some("tmpfs"), + MsFlags::empty(), + None, + ) +} + +#[derive(Debug, Deserialize, Serialize)] +pub enum Error { + Code(i32), + String(String), +} + +impl From<nix::Error> for Error { + fn from(error: nix::Error) -> Self { + match error { + nix::Error::Sys(code) => Error::Code(code as i32), + _ => Error::String(error.to_string()), + } + } +} + +impl From<Error> for io::Error { + fn from(error: Error) -> Self { + match error { + Error::Code(code) => io::Error::from_raw_os_error(code), + Error::String(string) => io::Error::new(io::ErrorKind::Other, string), + } + } +} + +pub fn runc_initialize() -> Result<(), Error> { + sched::unshare(CloneFlags::CLONE_NEWUSER | CloneFlags::CLONE_NEWNS)?; + mount_buildtmp()?; + Ok(()) +} diff --git a/src/runner/runc/run.rs b/src/runner/runc/run.rs new file mode 100644 index 0000000..2d13330 --- /dev/null +++ b/src/runner/runc/run.rs @@ -0,0 +1,18 @@ +use std::io; + +use serde::{Deserialize, Serialize}; + +use crate::types::*; +#[derive(Debug, Deserialize, Serialize)] +pub struct Error; + +impl From<Error> for io::Error { + fn from(_: Error) -> Self { + io::Error::new(io::ErrorKind::Other, "Failed to run task") + } +} + +pub fn handle_task(task: TaskRef, task_def: Task) -> Result<(), Error> { + println!("{}:\n\t{:?}", task, task_def); + Ok(()) +} diff --git a/src/types.rs b/src/types.rs index 1773504..331b49a 100644 --- a/src/types.rs +++ b/src/types.rs @@ -1,9 +1,9 @@ -use serde::Deserialize; +use serde::{Deserialize, Serialize}; use std::collections::HashMap; pub type TaskRef = String; -#[derive(Clone, Debug, Deserialize)] +#[derive(Clone, Debug, Deserialize, Serialize)] pub struct Task { #[serde(default)] pub depends: Vec<TaskRef>, diff --git a/src/unshare.rs b/src/unshare.rs index a8ec1c1..da16d24 100644 --- a/src/unshare.rs +++ b/src/unshare.rs @@ -4,15 +4,13 @@ use std::{ io::{self, BufRead, Result}, os::unix::ffi::*, path::Path, + process, }; -use nix::{ - sched::{self, CloneFlags}, - unistd, -}; +use nix::unistd; -use crate::prepared_command::PreparedCommand; -use crate::util::{Checkable, ToIOResult}; +// use crate::prepared_command::PreparedCommand; +use crate::util::Checkable; #[derive(Debug, Eq, Ord, PartialEq, PartialOrd)] struct SubIDRange { @@ -98,27 +96,22 @@ fn get_gid_map() -> Result<Vec<SubIDMap>> { Ok(generate_idmap(gid, gid_ranges)) } -fn prepare_idmap_cmd(cmd: &str, pid: &str, map: &Vec<SubIDMap>) -> Result<PreparedCommand> { - let mut builder = PreparedCommand::new(cmd); - builder.arg(&pid); +fn run_idmap_cmd(cmd: &str, pid: &str, map: &Vec<SubIDMap>) -> Result<()> { + let mut builder = process::Command::new(cmd); + builder.arg(pid); for uids in map { builder.arg(uids.lower.to_string()); builder.arg(uids.upper.to_string()); builder.arg(uids.count.to_string()); } - builder.prepare() + builder.status().and_then(|status| status.check()) } -pub fn unshare() -> Result<()> { - let pid = unistd::getpid().to_string(); - - let newuidmap = prepare_idmap_cmd("newuidmap", pid.as_str(), &get_uid_map()?)?; - let newgidmap = prepare_idmap_cmd("newgidmap", pid.as_str(), &get_gid_map()?)?; - - sched::unshare(CloneFlags::CLONE_NEWUSER | CloneFlags::CLONE_NEWNS).to_io_result()?; +pub fn idmap(pid: unistd::Pid) -> Result<()> { + let pid_string = pid.to_string(); - newuidmap.run()?.check()?; - newgidmap.run()?.check()?; + run_idmap_cmd("newuidmap", pid_string.as_str(), &get_uid_map()?)?; + run_idmap_cmd("newgidmap", pid_string.as_str(), &get_gid_map()?)?; Ok(()) } diff --git a/src/util.rs b/src/util.rs index 4e996e8..0418c51 100644 --- a/src/util.rs +++ b/src/util.rs @@ -1,8 +1,10 @@ use std::{ io::{Error, ErrorKind, Result}, process::ExitStatus, + result, }; +use ipc_channel::ipc; use nix::sys::wait; pub trait ToIOResult<T> { @@ -46,3 +48,21 @@ impl Checkable for wait::WaitStatus { } } } + +pub trait CheckDisconnect { + type Output; + + fn check_disconnect(self) -> Result<Self::Output>; +} + +impl<T> CheckDisconnect for result::Result<T, ipc::IpcError> { + type Output = result::Result<(), T>; + + fn check_disconnect(self) -> Result<Self::Output> { + match self { + Ok(v) => Ok(Err(v)), + Err(ipc::IpcError::Disconnected) => Ok(Ok(())), + Err(error) => Err(Error::new(ErrorKind::Other, format!("{:?}", error))), + } + } +} |