summaryrefslogtreecommitdiffstats
path: root/third_party/rust/devd-rs
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/devd-rs')
-rw-r--r--third_party/rust/devd-rs/.cargo-checksum.json1
-rw-r--r--third_party/rust/devd-rs/CODE_OF_CONDUCT.md74
-rw-r--r--third_party/rust/devd-rs/Cargo.lock37
-rw-r--r--third_party/rust/devd-rs/Cargo.toml30
-rw-r--r--third_party/rust/devd-rs/README.md27
-rw-r--r--third_party/rust/devd-rs/UNLICENSE24
-rw-r--r--third_party/rust/devd-rs/examples/main.rs12
-rw-r--r--third_party/rust/devd-rs/src/data.rs9
-rw-r--r--third_party/rust/devd-rs/src/lib.rs84
-rw-r--r--third_party/rust/devd-rs/src/parser.rs158
-rw-r--r--third_party/rust/devd-rs/src/result.rs26
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 @@
+[![crates.io](https://img.shields.io/crates/v/devd-rs.svg)](https://crates.io/crates/devd-rs)
+[![unlicense](https://img.shields.io/badge/un-license-green.svg?style=flat)](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>;