use colored::*;
use failure::{err_msg, Error};
use libc;
use std::ffi::CString;
use std::fs::{self, File};
use std::io::{self, Read, Write};
use std::os::unix::ffi::OsStringExt;
use std::path::PathBuf;
use std::thread;
use std::time::Duration;
#[derive(Fail, Debug)]
#[fail(display = "ITM Overflow")]
pub struct Overflow;
pub fn create_pipe(name: &str) -> Result<(), Error> {
let pipe = PathBuf::from(name);
if pipe.exists() {
fs::remove_file(&pipe)?;
}
let pipe = pipe.clone().into_os_string().into_vec();
let result = unsafe { libc::mkfifo(CString::new(pipe)?.as_ptr(), 0o644) };
if result != 0 {
Err(err_msg("Failed to create a FIFO"))?;
}
Ok(())
}
pub fn run_loop(pipe: &str, port: u8, debug: bool) -> Result<(), Error> {
let mut stream = io::BufReader::new(File::open(pipe)?);
let mut buffer = [0; 4];
loop {
match read(&mut stream, &mut buffer, port, debug) {
Ok(Some(payload)) => {
if debug {
for byte in payload {
print!("{:?} ", *byte as char);
}
println!();
} else {
io::stdout().write_all(payload)?;
io::stdout().flush()?;
}
}
Ok(None) => {
if debug {
println!("{}", "[IGN]".yellow());
}
}
Err(err) => {
if err.downcast_ref::<Overflow>().is_some() {
writeln!(io::stderr(), "{}", "[OFLW]".bold().white().on_red())?;
} else if let Some(err) = err.downcast_ref::<io::Error>() {
match err.kind() {
io::ErrorKind::UnexpectedEof => {
writeln!(io::stderr(), "{}", "[EOF]".red())?;
thread::sleep(Duration::from_millis(100));
}
kind => {
let message = format!("[IO: {:?}]", kind);
writeln!(io::stderr(), "{}", message.red())?;
}
}
}
}
}
}
}
fn read<'a, 'b>(
stream: &'a mut io::BufReader<File>,
buffer: &'b mut [u8],
_selected_port: u8,
debug: bool,
) -> Result<Option<&'b [u8]>, Error> {
stream.read_exact(&mut buffer[0..1])?;
let header = buffer[0];
if debug {
debug_print_byte(header)?;
}
if header == 0 {
return Ok(None);
}
let size = header & 0b11;
if size == 0 {
if header == 0b0111_0000 {
Err(Overflow)?
} else {
Ok(None)
}
} else if header & 0b100 == 0 {
let _port = header >> 3;
let payload = match size {
0b01 => &mut buffer[0..1],
0b10 => &mut buffer[0..2],
0b11 => &mut buffer[0..4],
_ => unreachable!(),
};
if debug {
for byte in payload.chunks_mut(1) {
stream.read_exact(byte)?;
debug_print_byte(byte[0])?;
}
} else {
stream.read_exact(payload)?;
}
Ok(Some(payload))
} else {
Ok(None)
}
}
fn debug_print_byte(byte: u8) -> Result<(), Error> {
print!("{:08b} ", byte);
io::stdout().flush()?;
Ok(())
}