diff options
Diffstat (limited to 'third_party/rust/devd-rs')
-rw-r--r-- | third_party/rust/devd-rs/.cargo-checksum.json | 1 | ||||
-rw-r--r-- | third_party/rust/devd-rs/CODE_OF_CONDUCT.md | 74 | ||||
-rw-r--r-- | third_party/rust/devd-rs/Cargo.lock | 37 | ||||
-rw-r--r-- | third_party/rust/devd-rs/Cargo.toml | 30 | ||||
-rw-r--r-- | third_party/rust/devd-rs/README.md | 27 | ||||
-rw-r--r-- | third_party/rust/devd-rs/UNLICENSE | 24 | ||||
-rw-r--r-- | third_party/rust/devd-rs/examples/main.rs | 12 | ||||
-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 |
11 files changed, 482 insertions, 0 deletions
diff --git a/third_party/rust/devd-rs/.cargo-checksum.json b/third_party/rust/devd-rs/.cargo-checksum.json new file mode 100644 index 0000000000..df23cf3721 --- /dev/null +++ b/third_party/rust/devd-rs/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"CODE_OF_CONDUCT.md":"62f073941a34756006851cef8d5d081f6332a986063e87deafeb621f3f6ff554","Cargo.lock":"bc2219b06850f8a2660bfd2f8af2c30ec5893f51d9e067f4489fc342f42754ee","Cargo.toml":"1c0d31cba751ef65905017ac764bfb82682125d9fc08d39f9976301c4c365bd4","README.md":"88550411d0440cc5931cff6e4265ec676291b2b18989f4fb5779c493e40392ae","UNLICENSE":"7e12e5df4bae12cb21581ba157ced20e1986a0508dd10d0e8a4ab9a4cf94e85c","examples/main.rs":"734a87846b61d09d2aaca444c69dc61765f66df34602f3a4acf1255f95404226","src/data.rs":"677b52a636deb1f0ffc623dbdc5ed7acd78d915117825ced7031c6fa6f0c861e","src/lib.rs":"41f7a2a7170f238ce368e0b1c540f77afadf911cd141d3652302355babf7eefc","src/parser.rs":"b32cc1a50c598cdb810914792de8aa4bf52a28002e8f4df578a271bab8e02bc2","src/result.rs":"4088fc879652c115a13d8a6e6a71fab8571a7982e740af6a91115f3a82aef236"},"package":"1945ccb7caedabdfb9347766ead740fb1e0582b7425598325f546adbd832cce1"}
\ No newline at end of file diff --git a/third_party/rust/devd-rs/CODE_OF_CONDUCT.md b/third_party/rust/devd-rs/CODE_OF_CONDUCT.md new file mode 100644 index 0000000000..a375db8308 --- /dev/null +++ b/third_party/rust/devd-rs/CODE_OF_CONDUCT.md @@ -0,0 +1,74 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to making participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, gender identity and expression, level of experience, +nationality, personal appearance, race, religion, or sexual identity and +orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment +include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or +advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic + address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. Examples of +representing a project or community include using an official project e-mail +address, posting via an official social media account, or acting as an appointed +representative at an online or offline event. Representation of a project may be +further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting the project owner at greg@unrelenting.technology. All +complaints will be reviewed and investigated and will result in a response that +is deemed necessary and appropriate to the circumstances. The project owner is +obligated to maintain confidentiality with regard to the reporter of an incident. +Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, +available at [http://contributor-covenant.org/version/1/4][version] + +[homepage]: http://contributor-covenant.org +[version]: http://contributor-covenant.org/version/1/4/ diff --git a/third_party/rust/devd-rs/Cargo.lock b/third_party/rust/devd-rs/Cargo.lock new file mode 100644 index 0000000000..4ba5bed600 --- /dev/null +++ b/third_party/rust/devd-rs/Cargo.lock @@ -0,0 +1,37 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "devd-rs" +version = "0.3.1" +dependencies = [ + "libc", + "nom", +] + +[[package]] +name = "libc" +version = "0.2.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d515b1f41455adea1313a4a2ac8a8a477634fbae63cc6100e3aebb207ce61558" + +[[package]] +name = "memchr" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53445de381a1f436797497c61d851644d0e8e88e6140f22872ad33a704933978" + +[[package]] +name = "nom" +version = "5.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c433f4d505fe6ce7ff78523d2fa13a0b9f2690e181fc26168bcbe5ccc5d14e07" +dependencies = [ + "memchr", + "version_check", +] + +[[package]] +name = "version_check" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd" diff --git a/third_party/rust/devd-rs/Cargo.toml b/third_party/rust/devd-rs/Cargo.toml new file mode 100644 index 0000000000..4a7aa49735 --- /dev/null +++ b/third_party/rust/devd-rs/Cargo.toml @@ -0,0 +1,30 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "devd-rs" +version = "0.3.1" +authors = ["Greg V <greg@unrelenting.technology>"] +description = "An interface to devd, the device hotplug daemon on FreeBSD and DragonFlyBSD" +homepage = "https://github.com/myfreeweb/devd-rs" +readme = "README.md" +keywords = ["System", "FreeBSD", "DragonFlyBSD", "devd", "hotplug"] +categories = ["os::unix-apis"] +license = "Unlicense/MIT" +repository = "https://github.com/myfreeweb/devd-rs" +[dependencies.libc] +version = "0" + +[dependencies.nom] +version = "5" +features = ["std"] +default-features = false diff --git a/third_party/rust/devd-rs/README.md b/third_party/rust/devd-rs/README.md new file mode 100644 index 0000000000..650560d172 --- /dev/null +++ b/third_party/rust/devd-rs/README.md @@ -0,0 +1,27 @@ +[](https://crates.io/crates/devd-rs) +[](http://unlicense.org) + +# devd-rs + +A Rust library for listening to FreeBSD (also DragonFlyBSD) [devd](https://www.freebsd.org/cgi/man.cgi?devd)'s device attach-detach notifications. + +Listens on `/var/run/devd.seqpacket.pipe` and parses messages using [nom](https://github.com/Geal/nom). + +## Usage + +See [examples/main.rs](https://github.com/myfreeweb/devd-rs/blob/master/examples/main.rs). + +## Contributing + +Please feel free to submit pull requests! + +By participating in this project you agree to follow the [Contributor Code of Conduct](http://contributor-covenant.org/version/1/4/). + +[The list of contributors is available on GitHub](https://github.com/myfreeweb/devd-rs/graphs/contributors). + +## License + +This is free and unencumbered software released into the public domain. +For more information, please refer to the `UNLICENSE` file or [unlicense.org](http://unlicense.org). + +It is also available under the MIT License. diff --git a/third_party/rust/devd-rs/UNLICENSE b/third_party/rust/devd-rs/UNLICENSE new file mode 100644 index 0000000000..68a49daad8 --- /dev/null +++ b/third_party/rust/devd-rs/UNLICENSE @@ -0,0 +1,24 @@ +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. + +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +For more information, please refer to <http://unlicense.org/> diff --git a/third_party/rust/devd-rs/examples/main.rs b/third_party/rust/devd-rs/examples/main.rs new file mode 100644 index 0000000000..fee8612f1e --- /dev/null +++ b/third_party/rust/devd-rs/examples/main.rs @@ -0,0 +1,12 @@ +extern crate devd_rs; + +use devd_rs::*; + +fn main() { + let mut ctx = Context::new().unwrap(); + loop { + if let Ok(ev) = ctx.wait_for_event(1000) { + println!("{:?}", ev); + } + } +} 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>; |