From c3b21897e1abf947a8fe011fbe07013f10ff9ce8 Mon Sep 17 00:00:00 2001 From: bytesnake Date: Sat, 22 Jul 2017 23:39:12 +0200 Subject: [PATCH] Added connect command and redirect output. --- tools/hermit_proxy/src/daemon.rs | 91 ++++++++++++----- tools/hermit_proxy/src/hermit/mod.rs | 5 + tools/hermit_proxy/src/hermit/multi.rs | 21 +++- tools/hermit_proxy/src/hermit/qemu.rs | 56 ++++++---- tools/hermit_proxy/src/hermit/socket.rs | 102 +++++++++++-------- tools/hermit_proxy/src/hermit/uhyve/proto.rs | 17 +++- tools/hermit_proxy/src/hermit/uhyve/uhyve.rs | 18 +++- tools/hermit_proxy/src/hermit/uhyve/vcpu.rs | 11 +- tools/hermit_proxy/src/hermit/uhyve/vm.rs | 24 ++--- tools/hermit_proxy/src/main.rs | 38 +++++-- 10 files changed, 263 insertions(+), 120 deletions(-) diff --git a/tools/hermit_proxy/src/daemon.rs b/tools/hermit_proxy/src/daemon.rs index 27a75759e..8bc167149 100644 --- a/tools/hermit_proxy/src/daemon.rs +++ b/tools/hermit_proxy/src/daemon.rs @@ -3,11 +3,14 @@ use std::path::Path; use std::result; use std::thread; use std::process; +use std::sync::Mutex; +use std::net::Shutdown; use log; use log::{LogMetadata, LogRecord, SetLoggerError, LogLevel, LogLevelFilter}; use nix::unistd::{fork, ForkResult}; use hermit::Isle; use std::sync::RwLock; +use std::sync::Arc; use std::io::Write; use std::io::Read; use bincode::{serialize, deserialize, Infinite}; @@ -69,6 +72,8 @@ impl Connection { loop { if let Ok(socket) = UnixStream::connect("/tmp/hermit_daemon") { + socket.set_nonblocking(true).unwrap(); + return Connection { socket: socket }; } } @@ -79,26 +84,45 @@ impl Connection { self.socket.write(&encoded).unwrap(); + let mut tmp = vec![0; 1024]; let mut buf = Vec::new(); - if let Err(err) = self.socket.read_to_end(&mut buf) { - if let Action::KillDaemon = action { - return ActionResult::KillDaemon(Ok(())); + loop { + match self.socket.read(&mut tmp) { + Ok(nread) => buf.extend_from_slice(&tmp[0..nread]), + Err(err) => { + if buf.len() > 0 { + break; + } + } } - - panic!("The daemon seem to be crashed!"); } if buf.len() == 0 { if let Action::KillDaemon = action { return ActionResult::KillDaemon(Ok(())); } else { - panic!("he result was empty!"); + panic!("The result was empty!"); } } deserialize(&buf).unwrap() } + + pub fn output(&mut self) { + let mut buf = vec![0; 1024]; + loop { + if let Ok(nread) = self.socket.read(&mut buf) { + let obj = deserialize(&buf).unwrap(); + + if let ActionResult::Output(out) = obj { + print!("{}", out); + } else if let ActionResult::OutputErr(out) = obj { + print!("{}", out); + } + } + } + } } #[derive(Serialize, Deserialize, Debug, Clone)] @@ -106,6 +130,7 @@ pub enum Action { CreateIsle(String, IsleParameter), StopIsle(u32), RemoveIsle(u32), + Connect(u32), Log(Option), List, KillDaemon @@ -116,10 +141,13 @@ pub enum ActionResult { CreateIsle(Result), StopIsle(Result), RemoveIsle(Result), + Connect(Result<()>), Log(Vec), IsleLog(Result), List(Vec<(Result, IsleParameter)>), - KillDaemon(Result<()>) + KillDaemon(Result<()>), + Output(String), + OutputErr(String) } #[derive(Serialize, Deserialize, Debug, Clone)] @@ -215,6 +243,12 @@ impl State { Err(Error::WrongIsleNumber) } } + + fn add_endpoint(&mut self, id: u32, stream: Arc>) -> Result<()> { + self.exist_isle(id)?; + + self.isles[id as usize].add_endpoint(stream) + } } pub fn daemon_handler() { @@ -224,13 +258,16 @@ pub fn daemon_handler() { LocalLogger::init(); let listener = UnixListener::bind("/tmp/hermit_daemon").unwrap(); - //for stream in listener.incoming() { - // match stream { - // Ok(mut stream) => { - 'outer: loop { match listener.accept() { - Ok((mut stream, addr)) => { -// loop { - if let Ok(nread) = stream.read(&mut buf) { + for stream in listener.incoming() { + match stream { + Ok(mut stream) => { + let mut stream = Arc::new(Mutex::new(stream)); + + loop { + //println!("READ"); + let nread = stream.lock().unwrap().read(&mut buf); + println!("{:?}", nread); + if let Ok(nread) = nread { if nread > 0 { let action:Action = deserialize(&buf).unwrap(); @@ -239,10 +276,16 @@ pub fn daemon_handler() { let ret = match action { Action::KillDaemon => { fs::remove_file("/tmp/hermit_daemon").unwrap(); - break 'outer; + break; }, Action::CreateIsle(path, specs) => ActionResult::CreateIsle(state.create_isle(path,specs)), Action::List => ActionResult::List(state.list()), + Action::Connect(id) => { + let res = ActionResult::Connect(state.add_endpoint(id, stream.clone())); + let buf: Vec = serialize(&res, Infinite).unwrap(); + stream.lock().unwrap().write(&buf); + break; + }, Action::Log(id) => { match id { Some(id) => ActionResult::IsleLog(state.log_isle(id)), @@ -254,17 +297,17 @@ pub fn daemon_handler() { _ => { panic!(""); } }; + println!("WRITE"); let buf: Vec = serialize(&ret, Infinite).unwrap(); - stream.write(&buf); + stream.lock().unwrap().write(&buf); + } else { + break; } } else { - + break; } - // } - }, - Err(err) => { - println!("ERR: {:?}", err); - } - } - } + } + }, + Err(err) => { println!("ERR: {:?}", err); } + }} } diff --git a/tools/hermit_proxy/src/hermit/mod.rs b/tools/hermit_proxy/src/hermit/mod.rs index 3416502ba..5b8ca361e 100644 --- a/tools/hermit_proxy/src/hermit/mod.rs +++ b/tools/hermit_proxy/src/hermit/mod.rs @@ -11,6 +11,9 @@ use std::path::Path; use std::io::{Write, Read, BufReader, BufRead}; use inotify::{Inotify, watch_mask}; use std::env; +use std::os::unix::net::UnixStream; +use std::sync::Arc; +use std::sync::Mutex; use hermit::qemu::QEmu; use hermit::multi::Multi; @@ -106,6 +109,8 @@ pub trait Isle { fn is_running(&mut self) -> Result; + fn add_endpoint(&mut self, stream: Arc>) -> Result<()>; + fn is_available(&self) -> Result { let log = match self.log_file() { Some(f) => f, diff --git a/tools/hermit_proxy/src/hermit/multi.rs b/tools/hermit_proxy/src/hermit/multi.rs index f81f21850..9ca1599a9 100644 --- a/tools/hermit_proxy/src/hermit/multi.rs +++ b/tools/hermit_proxy/src/hermit/multi.rs @@ -1,14 +1,19 @@ use std::fs::File; use std::env; use std::io::{Write, Read}; +use std::sync::Arc; +use std::sync::Mutex; +use std::thread; use hermit::Isle; use hermit::error::*; use hermit::socket::Socket; +use std::os::unix::net::UnixStream; + pub struct Multi { num: u8, - socket: Socket + socket: Option } impl Multi { @@ -46,7 +51,7 @@ impl Multi { return Err(Error::MultiIsleFailed); } - Ok(Multi { num: num, socket: Socket::new_multi(num) }) + Ok(Multi { num: num, socket: Some(Socket::new()) }) } } @@ -68,7 +73,13 @@ impl Isle for Multi { } fn run(&mut self) -> Result<()> { - self.socket.connect().run(); + let mut socket = self.socket.take().ok_or(Error::InternalError)?; + socket.connect()?; + + thread::spawn(move || { + + socket.run(); + }); Ok(()) } @@ -96,4 +107,8 @@ impl Isle for Multi { fn is_running(&mut self) -> Result { Ok(true) } + + fn add_endpoint(&mut self, stream: Arc>) -> Result<()> { + Ok(()) + } } diff --git a/tools/hermit_proxy/src/hermit/qemu.rs b/tools/hermit_proxy/src/hermit/qemu.rs index 5f5a4c5cb..1a3b50a3a 100644 --- a/tools/hermit_proxy/src/hermit/qemu.rs +++ b/tools/hermit_proxy/src/hermit/qemu.rs @@ -7,11 +7,14 @@ use std::process::{ChildStdout, ChildStderr}; use std::thread; use std::os::unix::net::UnixStream; use std::io::Write; +use std::time::Duration; +use std::sync::Arc; +use std::sync::Mutex; use hermit::{Isle, IsleParameterQEmu}; use hermit::utils; use hermit::error::*; -use hermit::socket::Socket; +use hermit::socket::{Socket, Console}; const PIDNAME: &'static str = "/tmp/hpid-XXXXXX"; const TMPNAME: &'static str = "/tmp/hermit-XXXXXX"; @@ -24,6 +27,7 @@ pub struct QEmu { stderr: ChildStderr, tmp_file: String, pid_file: String, + console: Console } impl QEmu { @@ -35,20 +39,22 @@ impl QEmu { let stdout = child.stdout.take().unwrap(); let stderr = child.stderr.take().unwrap(); println!("{}", pidf); + let socket = Socket::new(); + let console = socket.console(); Ok(QEmu { - socket: Some(Socket::new_qemu()), + socket: Some(socket), child: child, stdout: stdout, stderr: stderr, tmp_file: tmpf, pid_file: pidf, + console: console }) } pub fn start_with(path: &str, mem_size: u64, num_cpus: u32, add: IsleParameterQEmu, tmp_file: &str, pid_file: &str) -> Result { let hostfwd = format!("user,hostfwd=tcp:127.0.0.1:{}-:{}", add.port, add.port); - //let monitor_str = format!("telnet:127.0.0.1:{},server,nowait", add.port+1); let monitor_str = format!("unix:{}_monitor,server,nowait", pid_file); let chardev = format!("file,id=gnc0,path={}",&tmp_file); let freq = format!("\"-freq{} -proxy\"",(utils::cpufreq().unwrap()/1000).to_string()); @@ -126,15 +132,29 @@ impl QEmu { let mut control = UnixStream::connect(&file) .map_err(|_| Error::InvalidFile(file.clone()))?; + + control.set_read_timeout(Some(Duration::new(0,500))).unwrap(); control.write_all(cmd.as_bytes()) + .map_err(|_| Error::InvalidFile(file.clone()))?; + + control.write_all("\n".as_bytes()) .map_err(|_| Error::InvalidFile(file))?; - let mut buf = String::new(); + let mut response = [0u8; 256]; + let mut buf = Vec::new(); + loop { + if let Ok(nread) = control.read(&mut response) { + buf.extend_from_slice(&response[..nread]); + } else { + break; + } + } + + let res = String::from_utf8(buf).unwrap(); + let res: String = res.lines().filter(|x| !x.starts_with("QEMU") && !x.starts_with("(qemu)")).collect(); - control.read_to_string(&mut buf); - - Ok(buf) + Ok(res) } } @@ -151,21 +171,17 @@ impl Isle for QEmu { } fn run(&mut self) -> Result<()> { - let socket = self.socket.take(); + let mut socket = self.socket.take().ok_or(Error::InternalError)?; + socket.connect()?; - thread::spawn(|| { - socket.unwrap().connect().run(); + thread::spawn(move || { + socket.run(); }); Ok(()) } fn output(&self) -> Result { - /*if let &Socket::Connected { ref stdout, ref stderr, .. } = &self.socket.unwrap() { - Ok(stdout.clone()) - } else { - Err(Error::InternalError) - }*/ let mut file = File::open(&self.tmp_file).unwrap(); let mut content = String::new(); @@ -175,7 +191,7 @@ impl Isle for QEmu { } fn stop(&mut self) -> Result { - self.send_cmd("system_powerdown")?; + self.send_cmd("stop")?; Ok(0) } @@ -183,7 +199,13 @@ impl Isle for QEmu { fn is_running(&mut self) -> Result { let state = self.send_cmd("info status")?; - Ok(state == "running") + Ok(state == "VM status: running") + } + + fn add_endpoint(&mut self, stream: Arc>) -> Result<()> { + self.console.lock().unwrap().push(stream); + + Ok(()) } } diff --git a/tools/hermit_proxy/src/hermit/socket.rs b/tools/hermit_proxy/src/hermit/socket.rs index dc0694d48..8a20166e0 100644 --- a/tools/hermit_proxy/src/hermit/socket.rs +++ b/tools/hermit_proxy/src/hermit/socket.rs @@ -6,34 +6,42 @@ use std::ffi::CString; use std::ffi::CStr; use std::process; use byteorder::{ReadBytesExt, WriteBytesExt, LittleEndian}; +use std::sync::Arc; +use std::sync::Mutex; +use std::os::unix::net::UnixStream; +use bincode::{serialize, Infinite}; use hermit::proto; use hermit::proto::Packet; +use hermit::error::{Error, Result}; + +use daemon::ActionResult; use libc; const HERMIT_MAGIC: u32 = 0x7E317; +pub type Console = Arc>>>>; + #[derive(Debug)] -pub enum Socket { - QEmu, - Multi(u8), - Connected { stream: TcpStream, stdout: String, stderr: String } +pub struct Socket { + stream: Option, + console: Console } impl Socket { - pub fn new_qemu() -> Socket { - Socket::QEmu + pub fn new() -> Socket { + Socket { stream: None, console: Arc::new(Mutex::new(Vec::new())) } } - pub fn new_multi(id: u8) -> Socket { - Socket::Multi(id) - } - - pub fn connect(&self) -> Socket { + pub fn connect(&mut self) -> Result<()> { // prepare the initializing struct - let length: usize = 4 + env::args().skip(2).map(|x| 4+x.len()).sum::()+ 4 + env::vars().map(|(x,y)| 5 + x.len()+ y.len()).sum::(); + let length: usize = 4 + env::args().skip(2).map(|x| 4+x.len()).sum::() + + 4 + env::vars().map(|(x,y)| 5 + x.len()+ y.len()).sum::(); + let mut buf = Cursor::new(vec![0u8;length]); + + // initialize the connection with the magic number buf.write_u32::(HERMIT_MAGIC); // send all arguments (skip first) buf.write_u32::(env::args().count() as u32 - 2); @@ -52,47 +60,38 @@ impl Socket { let mut stream; loop { - match *self { - Socket::QEmu => { - match TcpStream::connect(("127.0.0.1", 0x494E)) { - Ok(mut s) => { - match s.write(buf.get_ref()) { - Ok(_) => { stream = s; break; }, - Err(_) => {} - } - }, + match TcpStream::connect(("127.0.0.1", 0x494E)) { + Ok(mut s) => { + match s.write(buf.get_ref()) { + Ok(_) => { stream = s; break; }, + Err(_) => {} + } + }, - Err(_) => {} - } - }, - Socket::Multi(id) => { - match TcpStream::connect((format!("127.0.0.{}", id).as_ref(), 0x494E)) { - Ok(mut s) => { - match s.write(buf.get_ref()) { - Ok(_) => { stream = s; break; }, - Err(_) => {} - } - }, - Err(_) => {} - } - }, - _ => panic!("") + Err(_) => {} } } - debug!("Connected to {}", stream.peer_addr().unwrap()); + self.stream = Some(stream); + + debug!("Connected to {}", self.stream()?.peer_addr().unwrap()); debug!("Transmitted environment and arguments with length {}", length); - Socket::Connected { stream: stream, stdout: String::new(), stderr: String::new() } + Ok(()) } - pub fn run(&mut self) { + pub fn console(&self) -> Console { + self.console.clone() + } + + pub fn stream(&self) -> Result<&TcpStream> { + self.stream.as_ref().ok_or(Error::InternalError) + } + + pub fn run(&mut self) -> Result<()> { debug!("Initializing protocol state machine"); let mut state = proto::State::Id; - let (mut stream, mut stdout, mut stderr) = match self { - &mut Socket::Connected { ref mut stream, ref mut stdout, ref mut stderr } => (stream, stdout, stderr), - _ => return - }; + let mut stream = self.stream()?; let mut cur = Cursor::new(vec![]); let mut buf = [0u8; 4096]; @@ -122,9 +121,21 @@ impl Socket { let buf_ret: [u8;8] = transmute(libc::write(fd as i32, buf.as_ptr() as *const libc::c_void, buf.len()).to_le()); if fd == 1 { - stdout.push_str(&String::from_utf8_unchecked(buf)); + let ret = ActionResult::Output(String::from_utf8_unchecked(buf)); + let buf: Vec = serialize(&ret, Infinite).unwrap(); + + for stream in self.console.lock().unwrap().iter_mut() { + stream.lock().unwrap().write(&buf).unwrap(); + } + //stdout.push_str(&String::from_utf8_unchecked(buf)); } else if fd == 2 { - stderr.push_str(&String::from_utf8_unchecked(buf)); + let ret = ActionResult::OutputErr(String::from_utf8_unchecked(buf)); + let buf: Vec = serialize(&ret, Infinite).unwrap(); + + for stream in self.console.lock().unwrap().iter_mut() { + stream.lock().unwrap().write(&buf).unwrap(); + } + //stderr.push_str(&String::from_utf8_unchecked(buf)); } else { stream.write(&buf_ret); } @@ -171,5 +182,6 @@ impl Socket { } } } + Ok(()) } } diff --git a/tools/hermit_proxy/src/hermit/uhyve/proto.rs b/tools/hermit_proxy/src/hermit/uhyve/proto.rs index 523526760..b4243519a 100644 --- a/tools/hermit_proxy/src/hermit/uhyve/proto.rs +++ b/tools/hermit_proxy/src/hermit/uhyve/proto.rs @@ -1,8 +1,12 @@ -use libc::{write, read, lseek, exit, open, close, c_int, c_void}; +use libc::{write, read, lseek, exit, open, close, c_int, c_void, c_char}; use super::kvm_header::{kvm_run, KVM_EXIT_IO, KVM_EXIT_HLT, KVM_EXIT_MMIO,KVM_EXIT_FAIL_ENTRY, KVM_EXIT_INTERNAL_ERROR, KVM_EXIT_SHUTDOWN }; use std::ffi::CStr; +use std::ffi::CString; +use bincode::{serialize, Infinite}; use super::{Error, Result}; +use hermit::socket::Console; +use daemon::ActionResult; const PORT_WRITE: u16 = 0x499; const PORT_OPEN: u16 = 0x500; @@ -91,12 +95,21 @@ impl Syscall { } - pub unsafe fn run(&self, guest_mem: *mut u8) -> Result { + pub unsafe fn run(&self, guest_mem: *mut u8, console: Console) -> Result { debug!("{:?}", *self); match *self { Syscall::Write(obj) => { if (*obj).fd == 1 { + use std::io::Write; + + let cstr = CString::from_raw((*obj).buf as *mut c_char); + let ret = ActionResult::Output(cstr.into_string().unwrap_or("".into())); + let buf: Vec = serialize(&ret, Infinite).unwrap(); + + for stream in console.lock().unwrap().iter_mut() { + stream.lock().unwrap().write(&buf).unwrap(); + } } else if (*obj).fd == 2 { } (*obj).length = write((*obj).fd, guest_mem.offset((*obj).buf) as *const c_void, (*obj).length as usize); diff --git a/tools/hermit_proxy/src/hermit/uhyve/uhyve.rs b/tools/hermit_proxy/src/hermit/uhyve/uhyve.rs index 82ad6acc0..90b05c39d 100644 --- a/tools/hermit_proxy/src/hermit/uhyve/uhyve.rs +++ b/tools/hermit_proxy/src/hermit/uhyve/uhyve.rs @@ -5,11 +5,16 @@ use std::ptr; use std::fs::{File,OpenOptions}; use std::os::unix::fs::OpenOptionsExt; use std::os::unix::io::AsRawFd; +use std::sync::Arc; +use std::sync::Mutex; use libc; use hermit::Isle; use super::{Error, Result, NameIOCTL}; use super::vm::VirtualMachine; +use hermit::socket::Console; + +use std::os::unix::net::UnixStream; /// The normal way of defining a IOCTL interface is provided by C macros. In Rust we have our own /// flawed macro system. The module below wraps a bunch of functions which are generated by the @@ -106,19 +111,22 @@ impl KVM { pub struct Uhyve { kvm: KVM, - vm: VirtualMachine + vm: VirtualMachine, + console: Console } impl Uhyve { pub fn new(path: &str, mem_size: u64, num_cpus: u32) -> Result { let kvm = KVM::new(); let mut vm = kvm.create_vm(mem_size as usize, num_cpus)?; + let console = vm.console(); vm.load_kernel(path)?; vm.init()?; Ok(Uhyve { kvm: kvm, - vm: vm + vm: vm, + console: console }) } } @@ -155,4 +163,10 @@ impl Isle for Uhyve { fn is_running(&mut self) -> Result { self.vm.is_running() } + + fn add_endpoint(&mut self, stream: Arc>) -> Result<()> { + self.console.lock().unwrap().push(stream); + + Ok(()) + } } diff --git a/tools/hermit_proxy/src/hermit/uhyve/vcpu.rs b/tools/hermit_proxy/src/hermit/uhyve/vcpu.rs index 73da43975..836d4a30d 100644 --- a/tools/hermit_proxy/src/hermit/uhyve/vcpu.rs +++ b/tools/hermit_proxy/src/hermit/uhyve/vcpu.rs @@ -19,6 +19,7 @@ use super::kvm_header::{kvm_sregs, kvm_regs, kvm_segment, kvm_cpuid2,kvm_cpuid2_ use super::{Result, Error, NameIOCTL}; use super::gdt; use super::proto; +use hermit::socket::Console; pub const GUEST_OFFSET: usize = 0x0; pub const CPUID_FUNC_PERFMON: usize = 0x0A; @@ -54,7 +55,8 @@ pub struct SharedState { run_mem: Mmap, mboot:*mut u8, guest_mem: *mut u8, - running_state: Arc + running_state: Arc, + console: Console } pub struct VirtualCPU { @@ -66,7 +68,7 @@ pub struct VirtualCPU { } impl VirtualCPU { - pub fn new(kvm_fd: RawFd, vm_fd: RawFd, id: u32, entry: u64, mem: &mut Mmap, mboot: *mut u8, running_state: Arc) -> Result { + pub fn new(kvm_fd: RawFd, vm_fd: RawFd, id: u32, entry: u64, mem: &mut Mmap, mboot: *mut u8, running_state: Arc, console: Console) -> Result { // create a new VCPU and save the file descriptor let fd = VirtualCPU::create_vcpu(vm_fd, id as u32)?; @@ -87,7 +89,8 @@ impl VirtualCPU { run_mem: run_mem, mboot: mboot, guest_mem: mem.mut_ptr(), - running_state: running_state + running_state: running_state, + console: console }; let cpu = VirtualCPU { @@ -207,7 +210,7 @@ impl VirtualCPU { } unsafe { - let a = proto::Syscall::from_mem(state.run_mem.ptr(), state.guest_mem).run(state.guest_mem); + let a = proto::Syscall::from_mem(state.run_mem.ptr(), state.guest_mem).run(state.guest_mem, state.console.clone()); a } diff --git a/tools/hermit_proxy/src/hermit/uhyve/vm.rs b/tools/hermit_proxy/src/hermit/uhyve/vm.rs index dda68b353..c341d2035 100644 --- a/tools/hermit_proxy/src/hermit/uhyve/vm.rs +++ b/tools/hermit_proxy/src/hermit/uhyve/vm.rs @@ -10,7 +10,7 @@ use elf; use elf::types::{ELFCLASS64, OSABI, PT_LOAD}; use std::ffi::CStr; use std::sync::atomic::{AtomicBool, Ordering}; -use std::sync::Arc; +use std::sync::{Arc, Mutex}; use std::thread::JoinHandle; use hermit::utils; @@ -18,6 +18,7 @@ use hermit::uhyve; use super::kvm_header::{kvm_userspace_memory_region, KVM_CAP_SYNC_MMU, KVM_32BIT_GAP_START, KVM_32BIT_GAP_SIZE, kvm_sregs}; use super::{Result, Error, NameIOCTL}; use super::vcpu::{ExitCode, VirtualCPU}; +use hermit::socket::Console; //use byteorder::ByteOrder; // guest offset? @@ -34,7 +35,8 @@ pub struct VirtualMachine { num_cpus: u32, sregs: kvm_sregs, running_state: Arc, - thread_handles: Vec> + thread_handles: Vec>, + console: Console } impl VirtualMachine { @@ -53,7 +55,7 @@ impl VirtualMachine { unsafe { libc::mprotect((mem.mut_ptr() as *mut libc::c_void).offset(KVM_32BIT_GAP_START as isize), KVM_32BIT_GAP_START, libc::PROT_NONE); } } - Ok(VirtualMachine { kvm_fd: kvm_fd, vm_fd: fd, mem: mem, elf_header: None, klog: None, vcpus: Vec::new(), mboot: None, num_cpus: num_cpus, sregs: kvm_sregs::default(), running_state: Arc::new(AtomicBool::new(false)), thread_handles: Vec::new() }) + Ok(VirtualMachine { kvm_fd: kvm_fd, vm_fd: fd, mem: mem, elf_header: None, klog: None, vcpus: Vec::new(), mboot: None, num_cpus: num_cpus, sregs: kvm_sregs::default(), running_state: Arc::new(AtomicBool::new(false)), thread_handles: Vec::new(), console: Arc::new(Mutex::new(Vec::new())) }) } /// Loads a kernel from path and initialite mem and elf_entry @@ -200,7 +202,7 @@ impl VirtualMachine { pub fn create_vcpu(&mut self, id: u32) -> Result<()> { let entry = self.elf_header.ok_or(Error::KernelNotLoaded)?.entry; - let cpu = VirtualCPU::new(self.kvm_fd, self.vm_fd, id, entry, &mut self.mem,self.mboot.unwrap(), self.running_state.clone())?; + let cpu = VirtualCPU::new(self.kvm_fd, self.vm_fd, id, entry, &mut self.mem,self.mboot.unwrap(), self.running_state.clone(), self.console.clone())?; if id == 0 { self.sregs = cpu.init_sregs()?; @@ -221,6 +223,9 @@ impl VirtualMachine { Ok(c_str.into()) } + pub fn console(&self) -> Console { + self.console.clone() + } pub fn run(&mut self) -> Result<()> { let mut guest_mem = unsafe { self.mem.as_mut_slice() }; @@ -257,17 +262,6 @@ impl VirtualMachine { if self.running_state.load(Ordering::Relaxed) { return Ok(true); } else { - /*while let Some(handle) = self.thread_handles.pop() { - if let Ok(ret) = handle.join() { - match ret { - ExitCode::Innocent => continue, - ExitCode::Cause(cause) => { - cause?; - } - } - } - }*/ - return Ok(false); } } diff --git a/tools/hermit_proxy/src/main.rs b/tools/hermit_proxy/src/main.rs index a5227f671..e68c7b702 100644 --- a/tools/hermit_proxy/src/main.rs +++ b/tools/hermit_proxy/src/main.rs @@ -56,6 +56,9 @@ fn main() { (@subcommand list => (about: "Lists all Hermit isles") ) + (@subcommand start_daemon => + (about: "Starts the daemon in foreground") + ) (@subcommand kill_daemon => (about: "Stops the daemon and deletes the unix socket") ) @@ -63,6 +66,10 @@ fn main() { (about: "Stops an Hermit isle") (@arg name: +required "The corresponding name") ) + (@subcommand connect => + (about: "Connects to an hermit isle") + (@arg name: +required "The corresponding name") + ) (@subcommand log => (about: "Acquire logging information") (@arg name: "Focus on a single instance") @@ -73,6 +80,12 @@ fn main() { ) ).get_matches(); + if let Some(_) = matches.subcommand_matches("start_daemon") { + daemon::daemon_handler(); + + return; + } + let mut daemon = daemon::Connection::connect(); // list all isles @@ -160,6 +173,23 @@ fn main() { } } + if let Some(matches) = matches.subcommand_matches("connect") { + match matches.value_of("name").unwrap().parse::() { + Ok(id) => { + let res = daemon.send(Action::Connect(id)); + + if let ActionResult::Connect(Ok(_)) = res { + daemon.output(); + } else if let ActionResult::Connect(Err(err)) = res { + println!("Connect failed: {:?}", err); + } + }, + Err(_) => { + println!("Invalid number!"); + } + } + } + // create the isle, wait to be available and start it if let Some(matches) = matches.subcommand_matches("run") { if let Some(isle) = matches.value_of("isle") { @@ -197,13 +227,5 @@ fn main() { )); println!("Created Isle with number: {:?}", res); - -// hermit::new_isle(&matches.value_of("file").unwrap()) -// .and_then(|mut isle| { -// isle.wait_until_available()?; -// isle.run()?; -// -// Ok(()) -// }).unwrap(); } }