Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6e906f31 authored by Archie Pusaka's avatar Archie Pusaka
Browse files

Floss: Allow input from stdin as an alternative to reading file

Feedback report analyzer has the snoop file in memory, so allow it to
pipe it via stdin to avoid writing it to a temporary file.

Bug: 276750818
Test: ./hcidoc < test.snoop

Change-Id: I0055b28ad3c082dbfdd191e1874165783a1c712c
parent e759dd8d
Loading
Loading
Loading
Loading
+11 −7
Original line number Diff line number Diff line
@@ -17,7 +17,10 @@ fn main() {
        .version("0.1")
        .author("Abhishek Pandit-Subedi <abhishekpandit@google.com>")
        .about("Analyzes a linux HCI snoop log for specific behaviors and errors.")
        .arg(Arg::new("filename"))
        .arg(
            Arg::new("filename")
                .help("Path to the snoop log. If omitted, read from stdin instead."),
        )
        .arg(
            Arg::new("signals")
                .short('s')
@@ -28,10 +31,7 @@ fn main() {

    let filename = match matches.get_one::<String>("filename") {
        Some(f) => f,
        None => {
            println!("No filename parameter given.");
            return;
        }
        None => "",
    };

    let report_signals = match matches.get_one::<bool>("signals") {
@@ -39,10 +39,14 @@ fn main() {
        None => false,
    };

    let mut parser = match LogParser::new(filename.as_str()) {
    let mut parser = match LogParser::new(filename) {
        Ok(p) => p,
        Err(e) => {
            println!("Failed to load parser on {}: {}", filename, e);
            println!(
                "Failed to load parser on {}: {}",
                if filename.len() == 0 { "stdin" } else { filename },
                e
            );
            return;
        }
    };
+22 −25
Original line number Diff line number Diff line
@@ -3,7 +3,7 @@ use chrono::NaiveDateTime;
use num_traits::cast::FromPrimitive;
use std::convert::TryFrom;
use std::fs::File;
use std::io::{Error, ErrorKind, Read, Seek};
use std::io::{BufRead, BufReader, Error, ErrorKind, Read};

use bt_packets::hci::{AclPacket, CommandPacket, EventPacket};

@@ -169,11 +169,11 @@ impl TryFrom<&[u8]> for LinuxSnoopPacket {

/// Reader for Linux snoop files.
pub struct LinuxSnoopReader<'a> {
    fd: &'a File,
    fd: Box<dyn BufRead + 'a>,
}

impl<'a> LinuxSnoopReader<'a> {
    fn new(fd: &'a File) -> Self {
    fn new(fd: Box<dyn BufRead + 'a>) -> Self {
        LinuxSnoopReader { fd }
    }
}
@@ -183,8 +183,8 @@ impl<'a> Iterator for LinuxSnoopReader<'a> {

    fn next(&mut self) -> Option<Self::Item> {
        let mut data = [0u8; LINUX_SNOOP_PACKET_PREAMBLE_SIZE];
        let bytes = match self.fd.read(&mut data) {
            Ok(b) => b,
        match self.fd.read_exact(&mut data) {
            Ok(()) => {}
            Err(e) => {
                // |UnexpectedEof| could be seen since we're trying to read more
                // data than is available (i.e. end of file).
@@ -195,22 +195,14 @@ impl<'a> Iterator for LinuxSnoopReader<'a> {
            }
        };

        match LinuxSnoopPacket::try_from(&data[0..bytes]) {
        match LinuxSnoopPacket::try_from(&data[0..LINUX_SNOOP_PACKET_PREAMBLE_SIZE]) {
            Ok(mut p) => {
                if p.included_length > 0 {
                    let size: usize = p.included_length.try_into().unwrap();
                    let mut rem_data = [0u8; LINUX_SNOOP_MAX_PACKET_SIZE];
                    match self.fd.read(&mut rem_data[0..size]) {
                        Ok(b) => {
                            if b != size {
                                eprintln!(
                                    "Size({}) doesn't match bytes read({}). Aborting...",
                                    size, b
                                );
                                return None;
                            }

                            p.data = rem_data[0..b].to_vec();
                    match self.fd.read_exact(&mut rem_data[0..size]) {
                        Ok(()) => {
                            p.data = rem_data[0..size].to_vec();
                            Some(p)
                        }
                        Err(e) => {
@@ -236,25 +228,30 @@ pub enum LogType {

/// Parses different Bluetooth log types.
pub struct LogParser {
    fd: File,
    fd: Box<dyn BufRead>,
    log_type: Option<LogType>,
}

impl<'a> LogParser {
    pub fn new(filepath: &str) -> std::io::Result<Self> {
        Ok(Self { fd: File::open(filepath)?, log_type: None })
        let fd: Box<dyn BufRead>;
        if filepath.len() == 0 {
            fd = Box::new(BufReader::new(std::io::stdin()));
        } else {
            fd = Box::new(BufReader::new(File::open(filepath)?));
        }

        Ok(Self { fd, log_type: None })
    }

    /// Check the log file type for the current log file. This rewinds the position of the file.
    /// Check the log file type for the current log file. This advances the read pointer.
    /// For a non-intrusive query, use |get_log_type|.
    pub fn read_log_type(&mut self) -> std::io::Result<LogType> {
        let mut buf = [0; LINUX_SNOOP_HEADER_SIZE];

        // First rewind to start of the file.
        self.fd.rewind()?;
        let bytes = self.fd.read(&mut buf)?;
        self.fd.read_exact(&mut buf)?;

        if let Ok(header) = LinuxSnoopHeader::try_from(&buf[0..bytes]) {
        if let Ok(header) = LinuxSnoopHeader::try_from(&buf[0..LINUX_SNOOP_HEADER_SIZE]) {
            let log_type = LogType::LinuxSnoop(header);
            self.log_type = Some(log_type.clone());
            Ok(log_type)
@@ -274,7 +271,7 @@ impl<'a> LogParser {
            return None;
        }

        Some(LinuxSnoopReader::new(&mut self.fd))
        Some(LinuxSnoopReader::new(Box::new(BufReader::new(&mut self.fd))))
    }
}