mirror of
https://github.com/hermitcore/libhermit.git
synced 2025-03-09 00:00:03 +01:00
Added connect command and redirect output.
This commit is contained in:
parent
9f8357f564
commit
c3b21897e1
10 changed files with 263 additions and 120 deletions
|
@ -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<u32>),
|
||||
List,
|
||||
KillDaemon
|
||||
|
@ -116,10 +141,13 @@ pub enum ActionResult {
|
|||
CreateIsle(Result<u32>),
|
||||
StopIsle(Result<i32>),
|
||||
RemoveIsle(Result<i32>),
|
||||
Connect(Result<()>),
|
||||
Log(Vec<Log>),
|
||||
IsleLog(Result<String>),
|
||||
List(Vec<(Result<bool>, 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<Mutex<UnixStream>>) -> 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<u8> = 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<u8> = 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); }
|
||||
}}
|
||||
}
|
||||
|
|
|
@ -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<bool>;
|
||||
|
||||
fn add_endpoint(&mut self, stream: Arc<Mutex<UnixStream>>) -> Result<()>;
|
||||
|
||||
fn is_available(&self) -> Result<bool> {
|
||||
let log = match self.log_file() {
|
||||
Some(f) => f,
|
||||
|
|
|
@ -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<Socket>
|
||||
}
|
||||
|
||||
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<bool> {
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
fn add_endpoint(&mut self, stream: Arc<Mutex<UnixStream>>) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<Command> {
|
||||
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<String> {
|
||||
/*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<i32> {
|
||||
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<bool> {
|
||||
let state = self.send_cmd("info status")?;
|
||||
|
||||
Ok(state == "running")
|
||||
Ok(state == "VM status: running")
|
||||
}
|
||||
|
||||
fn add_endpoint(&mut self, stream: Arc<Mutex<UnixStream>>) -> Result<()> {
|
||||
self.console.lock().unwrap().push(stream);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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<Mutex<Vec<Arc<Mutex<UnixStream>>>>>;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Socket {
|
||||
QEmu,
|
||||
Multi(u8),
|
||||
Connected { stream: TcpStream, stdout: String, stderr: String }
|
||||
pub struct Socket {
|
||||
stream: Option<TcpStream>,
|
||||
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::<usize>()+ 4 + env::vars().map(|(x,y)| 5 + x.len()+ y.len()).sum::<usize>();
|
||||
let length: usize = 4 + env::args().skip(2).map(|x| 4+x.len()).sum::<usize>() +
|
||||
4 + env::vars().map(|(x,y)| 5 + x.len()+ y.len()).sum::<usize>();
|
||||
|
||||
let mut buf = Cursor::new(vec![0u8;length]);
|
||||
|
||||
// initialize the connection with the magic number
|
||||
buf.write_u32::<LittleEndian>(HERMIT_MAGIC);
|
||||
// send all arguments (skip first)
|
||||
buf.write_u32::<LittleEndian>(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<u8> = 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<u8> = 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(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<Return> {
|
||||
pub unsafe fn run(&self, guest_mem: *mut u8, console: Console) -> Result<Return> {
|
||||
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<u8> = 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);
|
||||
|
|
|
@ -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<Uhyve> {
|
||||
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<bool> {
|
||||
self.vm.is_running()
|
||||
}
|
||||
|
||||
fn add_endpoint(&mut self, stream: Arc<Mutex<UnixStream>>) -> Result<()> {
|
||||
self.console.lock().unwrap().push(stream);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<AtomicBool>
|
||||
running_state: Arc<AtomicBool>,
|
||||
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<AtomicBool>) -> Result<VirtualCPU> {
|
||||
pub fn new(kvm_fd: RawFd, vm_fd: RawFd, id: u32, entry: u64, mem: &mut Mmap, mboot: *mut u8, running_state: Arc<AtomicBool>, console: Console) -> Result<VirtualCPU> {
|
||||
|
||||
// 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
|
||||
}
|
||||
|
|
|
@ -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<AtomicBool>,
|
||||
thread_handles: Vec<JoinHandle<ExitCode>>
|
||||
thread_handles: Vec<JoinHandle<ExitCode>>,
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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::<u32>() {
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue