diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
commit | 2aa4a82499d4becd2284cdb482213d541b8804dd (patch) | |
tree | b80bf8bf13c3766139fbacc530efd0dd9d54394c /third_party/rust/devd-rs/src | |
parent | Initial commit. (diff) | |
download | firefox-2aa4a82499d4becd2284cdb482213d541b8804dd.tar.xz firefox-2aa4a82499d4becd2284cdb482213d541b8804dd.zip |
Adding upstream version 86.0.1.upstream/86.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/rust/devd-rs/src')
-rw-r--r-- | third_party/rust/devd-rs/src/data.rs | 9 | ||||
-rw-r--r-- | third_party/rust/devd-rs/src/lib.rs | 84 | ||||
-rw-r--r-- | third_party/rust/devd-rs/src/parser.rs | 158 | ||||
-rw-r--r-- | third_party/rust/devd-rs/src/result.rs | 26 |
4 files changed, 277 insertions, 0 deletions
diff --git a/third_party/rust/devd-rs/src/data.rs b/third_party/rust/devd-rs/src/data.rs new file mode 100644 index 0000000000..52084362e5 --- /dev/null +++ b/third_party/rust/devd-rs/src/data.rs @@ -0,0 +1,9 @@ +pub use std::collections::BTreeMap; + +#[derive(Debug, Clone, PartialEq)] +pub enum Event { + Notify { system: String, subsystem: String, kind: String, data: BTreeMap<String, String> }, + Attach { dev: String, parent: BTreeMap<String, String>, location: String }, + Detach { dev: String, parent: BTreeMap<String, String>, location: String }, + Nomatch { parent: BTreeMap<String, String>, location: String }, +} diff --git a/third_party/rust/devd-rs/src/lib.rs b/third_party/rust/devd-rs/src/lib.rs new file mode 100644 index 0000000000..f872167a73 --- /dev/null +++ b/third_party/rust/devd-rs/src/lib.rs @@ -0,0 +1,84 @@ +extern crate libc; +#[macro_use] +extern crate nom; + +pub mod data; +pub mod parser; +pub mod result; + +use io::{BufRead, BufReader}; +use libc::{c_int, connect, nfds_t, poll, pollfd, sockaddr_un, socket, AF_UNIX, POLLIN, SOCK_SEQPACKET}; +use std::os::unix::io::{FromRawFd, RawFd}; +use std::os::unix::net::UnixStream; +use std::{io, mem, ptr}; + +pub use data::*; +pub use result::*; + +const SOCKET_PATH: &'static str = "/var/run/devd.seqpacket.pipe"; + +pub fn parse_devd_event(e: String) -> Result<Event> { + match parser::event(e.as_str()) { + Ok((_, x)) => Ok(x), + _ => Err(Error::Parse), + } +} + +#[derive(Debug)] +pub struct Context { + sock: BufReader<UnixStream>, + sockfd: RawFd, +} + +impl Context { + pub fn new() -> Result<Context> { + unsafe { + let sockfd = socket(AF_UNIX, SOCK_SEQPACKET, 0); + if sockfd < 0 { + return Err(io::Error::last_os_error().into()); + } + let mut sockaddr = sockaddr_un { sun_family: AF_UNIX as _, ..mem::zeroed() }; + ptr::copy_nonoverlapping(SOCKET_PATH.as_ptr(), sockaddr.sun_path.as_mut_ptr() as *mut u8, SOCKET_PATH.len()); + if connect(sockfd, &sockaddr as *const sockaddr_un as *const _, (mem::size_of_val(&AF_UNIX) + SOCKET_PATH.len()) as _) < 0 { + return Err(io::Error::last_os_error().into()); + } + Ok(Context { + sock: BufReader::new(UnixStream::from_raw_fd(sockfd)), + sockfd: sockfd, + }) + } + } + + /// Waits for an event using poll(), reads it but does not parse + pub fn wait_for_event_raw(&mut self, timeout_ms: usize) -> Result<String> { + let mut fds = vec![pollfd { fd: self.sockfd, events: POLLIN, revents: 0 }]; + let x = unsafe { poll((&mut fds).as_mut_ptr(), fds.len() as nfds_t, timeout_ms as c_int) }; + if x < 0 { + Err(io::Error::last_os_error().into()) + } else if x == 0 { + Err(Error::Timeout) + } else { + let mut s = String::new(); + let _ = self.sock.read_line(&mut s); + Ok(s) + } + } + + /// Waits for an event using poll(), reads and parses it + pub fn wait_for_event<'a>(&mut self, timeout_ms: usize) -> Result<Event> { + self.wait_for_event_raw(timeout_ms).and_then(parse_devd_event) + } + + /// Returns the devd socket file descriptor in case you want to select/poll on it together with + /// other file descriptors + pub fn fd(&self) -> RawFd { + self.sockfd + } + + /// Reads an event and parses it. Use when polling on the raw fd by yourself + pub fn read_event(&mut self) -> Result<Event> { + let mut s = String::new(); + let _ = self.sock.read_line(&mut s); + parse_devd_event(s) + } +} diff --git a/third_party/rust/devd-rs/src/parser.rs b/third_party/rust/devd-rs/src/parser.rs new file mode 100644 index 0000000000..45738aa40c --- /dev/null +++ b/third_party/rust/devd-rs/src/parser.rs @@ -0,0 +1,158 @@ +use data::*; +use nom::branch::alt; +use nom::bytes::complete::take_while; +use nom::character::complete::{alphanumeric1, char, multispace1}; +use nom::sequence::delimited; + +fn val(i: &str) -> nom::IResult<&str, &str> { + alt((delimited(char('"'), take_while(|c| c != '"'), char('"')), take_while(|c| c != '\n' && c != ' ')))(i) +} + +named!(keyval <&str, (&str, &str)>, + do_parse!( + key: alphanumeric1 + >> char!('=') + >> val: val + >> (key, val) + ) + ); + +named!(keyvals <&str, BTreeMap<String, String> >, + map!( + many0!(terminated!(keyval, opt!(multispace1))), + |vec: Vec<_>| vec.into_iter().map(|(k, v)| (k.to_string(), v.to_string())).collect() + ) + ); + +named!(pub event <&str, Event>, + alt!( + do_parse!( + tag!("!") >> + tag!("system=") >> + sys: val >> + multispace1 >> + tag!("subsystem=") >> + subsys: val >> + multispace1 >> + tag!("type=") >> + kind: val >> + multispace1 >> + data: keyvals >> + (Event::Notify { system: sys.to_string(), subsystem: subsys.to_string(), kind: kind.to_string(), data: data }) + ) + | + do_parse!( + tag!("+") >> + dev: alphanumeric1 >> + multispace1 >> + tag!("at") >> + multispace1 >> + parent: keyvals >> + tag!("on") >> + multispace1 >> + loc: val >> + (Event::Attach { dev: dev.to_string(), parent: parent, location: loc.to_string() }) + ) + | + do_parse!( + tag!("-") >> + dev: alphanumeric1 >> + multispace1 >> + tag!("at") >> + multispace1 >> + parent: keyvals >> + tag!("on") >> + multispace1 >> + loc: val >> + (Event::Detach { dev: dev.to_string(), parent: parent, location: loc.to_string() }) + ) + | + do_parse!( + tag!("?") >> + multispace1 >> + tag!("at") >> + multispace1 >> + parent: keyvals >> + tag!("on") >> + multispace1 >> + loc: val >> + (Event::Nomatch { parent: parent, location: loc.to_string() }) + ) + ) +); + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_notify() { + let txt = "!system=USB subsystem=INTERFACE type=ATTACH ugen=ugen0.2 vendor=0x1050 sernum=\"\" mode=host\n"; + let res = event(txt); + let mut data = BTreeMap::new(); + data.insert("ugen".to_owned(), "ugen0.2".to_owned()); + data.insert("vendor".to_owned(), "0x1050".to_owned()); + data.insert("sernum".to_owned(), "".to_owned()); + data.insert("mode".to_owned(), "host".to_owned()); + assert_eq!( + res, + Ok(( + "", + Event::Notify { + system: "USB".to_owned(), + subsystem: "INTERFACE".to_owned(), + kind: "ATTACH".to_owned(), + data: data, + } + )) + ) + } + + #[test] + fn test_attach() { + let txt = "+uhid1 at bus=0 sernum=\"\" on uhub1"; + let res = event(txt); + let mut data = BTreeMap::new(); + data.insert("bus".to_owned(), "0".to_owned()); + data.insert("sernum".to_owned(), "".to_owned()); + assert_eq!( + res, + Ok(( + "", + Event::Attach { + dev: "uhid1".to_owned(), + parent: data, + location: "uhub1".to_owned(), + } + )) + ) + } + + #[test] + fn test_detach() { + let txt = "-uhid1 at on uhub1"; + let res = event(txt); + let data = BTreeMap::new(); + assert_eq!( + res, + Ok(( + "", + Event::Detach { + dev: "uhid1".to_owned(), + parent: data.to_owned(), + location: "uhub1".to_owned(), + } + )) + ) + } + + #[test] + fn test_nomatch() { + let txt = "? at bus=0 on uhub1"; + let res = event(txt); + let mut data = BTreeMap::new(); + data.insert("bus".to_owned(), "0".to_owned()); + + assert_eq!(res, Ok(("", Event::Nomatch { parent: data, location: "uhub1".to_owned() }))) + } +} diff --git a/third_party/rust/devd-rs/src/result.rs b/third_party/rust/devd-rs/src/result.rs new file mode 100644 index 0000000000..481cd808ed --- /dev/null +++ b/third_party/rust/devd-rs/src/result.rs @@ -0,0 +1,26 @@ +use std::{io, result}; + +#[derive(Debug)] +pub enum Error { + IoError(io::Error), + Timeout, + Parse, +} + +impl Into<io::Error> for Error { + fn into(self) -> io::Error { + match self { + Error::IoError(e) => e, + Error::Timeout => io::Error::new(io::ErrorKind::Other, "devd poll timeout"), + Error::Parse => io::Error::new(io::ErrorKind::Other, "devd parse error"), + } + } +} + +impl From<io::Error> for Error { + fn from(err: io::Error) -> Error { + Error::IoError(err) + } +} + +pub type Result<T> = result::Result<T, Error>; |