diff --git a/Cargo.toml b/Cargo.toml index 4e6da30ff..e5c4b9560 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,6 +4,7 @@ description = """ The type-safe wrapper around mount system call """ license = "MIT/Apache-2.0" +edition = "2018" readme = "README.md" keywords = ["linux", "container", "mount", "volume", "filesystem"] homepage = "http://github.com/tailhook/libmount" @@ -12,14 +13,15 @@ version = "0.1.15" authors = ["paul@colomiets.name"] [dependencies] -libc = "0.2.28" -nix = "0.14" -quick-error = "1.2.0" +libc = "^0.2.30" +nix = "0.16" +thiserror = "1.0" +fs-err = "*" [dev-dependencies] -argparse = "0.2.1" -env_logger = "0.5.10" -log = "0.4.1" +argparse = "0.2" +env_logger = "0.8" +log = "0.4" [lib] name = "libmount" diff --git a/examples/overlay_readonly.rs b/examples/overlay_readonly.rs index 546d611dc..fa909be3a 100644 --- a/examples/overlay_readonly.rs +++ b/examples/overlay_readonly.rs @@ -1,7 +1,7 @@ -extern crate libmount; -extern crate argparse; -extern crate env_logger; -#[macro_use] extern crate log; + + + +use log::error; use std::path::PathBuf; use std::process::exit; diff --git a/src/bind.rs b/src/bind.rs index f69b046b4..3f4e6d052 100644 --- a/src/bind.rs +++ b/src/bind.rs @@ -5,10 +5,10 @@ use std::path::Path; use nix::mount::{MsFlags, mount}; -use {OSError, Error}; -use util::{path_to_cstring, as_path}; -use explain::{Explainable, exists, user}; -use remount::Remount; +use crate::{OSError, Error}; +use crate::util::{path_to_cstring, as_path}; +use crate::explain::{Explainable, exists, user}; +use crate::remount::Remount; /// A mount bind definition @@ -60,7 +60,7 @@ impl BindMount { pub fn bare_mount(self) -> Result<(), OSError> { let mut flags = MsFlags::MS_BIND; if self.recursive { - flags = flags | MsFlags::MS_REC; + flags |= MsFlags::MS_REC; } if let Err(err) = mount( Some(&*self.source), @@ -72,10 +72,10 @@ impl BindMount { return Err(OSError::from_nix(err, Box::new(self))); } if self.readonly { - try!(Remount::new(OsStr::from_bytes(self.target.as_bytes())) + Remount::new(OsStr::from_bytes(self.target.as_bytes())) .bind(true) .readonly(true) - .bare_remount()); + .bare_remount()?; } Ok(()) } @@ -89,7 +89,7 @@ impl BindMount { impl fmt::Display for BindMount { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { if self.recursive { - try!(write!(fmt, "recursive ")); + write!(fmt, "recursive ")?; } write!(fmt, "bind mount {:?} -> {:?}", as_path(&self.source), as_path(&self.target)) @@ -101,7 +101,7 @@ impl Explainable for BindMount { [ format!("source: {}", exists(as_path(&self.source))), format!("target: {}", exists(as_path(&self.target))), - format!("{}", user()), + user().to_string(), ].join(", ") } } diff --git a/src/error.rs b/src/error.rs index 95a086004..e889dd418 100644 --- a/src/error.rs +++ b/src/error.rs @@ -2,8 +2,8 @@ use std::io; use std::fmt; use std::error::Error as StdError; -use {OSError, Error, MountError}; -use remount::RemountError; +use crate::{OSError, Error, MountError}; +use crate::remount::RemountError; impl OSError { /// Convert error to the one providing extra useful information @@ -11,8 +11,8 @@ impl OSError { let text = self.1.explain(); match self.0 { MountError::Io(e) => Error(self.1, e, text), - MountError::Remount(RemountError::Io(msg, io_err)) => { - Error(self.1, io_err, format!("{}, {}", msg, text)) + MountError::Remount(RemountError::Io(io_err)) => { + Error(self.1, io_err, text) }, MountError::Remount(err) => { let text = format!("{}, {}", &err, text); @@ -32,12 +32,9 @@ impl fmt::Display for OSError { } impl StdError for OSError { - fn cause(&self) -> Option<&StdError> { + fn source(&self) -> Option<&(dyn StdError + 'static)> { Some(&self.0) } - fn description(&self) -> &str { - self.0.description() - } } impl fmt::Display for Error { @@ -47,10 +44,7 @@ impl fmt::Display for Error { } impl StdError for Error { - fn cause(&self) -> Option<&StdError> { + fn source(&self) -> Option<&(dyn StdError + 'static)> { Some(&self.1) } - fn description(&self) -> &str { - self.1.description() - } } diff --git a/src/explain.rs b/src/explain.rs index 3be2a9e0d..3fcb4a3b3 100644 --- a/src/explain.rs +++ b/src/explain.rs @@ -1,12 +1,12 @@ use std::io::Read; -use std::fs::File; +use fs_err::File; use std::fmt::{Display, Debug}; use std::path::Path; use nix::unistd::getuid; -pub trait Explainable: Display + Debug { +pub trait Explainable: Display + Debug + Send + Sync { fn explain(&self) -> String; } diff --git a/src/lib.rs b/src/lib.rs index e53c3f6bd..94c8d3022 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -22,10 +22,6 @@ #![warn(missing_debug_implementations)] #![warn(missing_docs)] -extern crate libc; -extern crate nix; -#[macro_use] extern crate quick_error; - mod util; mod error; mod explain; @@ -38,26 +34,20 @@ pub mod mountinfo; use std::io; -use explain::Explainable; -use remount::RemountError; +use crate::explain::Explainable; pub use bind::BindMount; pub use overlay::Overlay; pub use tmpfs::Tmpfs; pub use modify::Move; -pub use remount::Remount; +pub use crate::remount::{Remount,RemountError}; -quick_error! { - #[derive(Debug)] - enum MountError { - Io(err: io::Error) { - cause(err) - from() - } - Remount(err: RemountError) { - cause(err) - from() - } - } +#[derive(Debug, thiserror::Error)] +#[allow(missing_docs)] +enum MountError { + #[error(transparent)] + Io(#[from] io::Error), + #[error(transparent)] + Remount(#[from] RemountError), } /// The raw os error @@ -75,14 +65,14 @@ quick_error! { /// path. /// #[derive(Debug)] -pub struct OSError(MountError, Box); +pub struct OSError(MountError, Box); impl OSError { - fn from_remount(err: RemountError, explain: Box) -> OSError { + fn from_remount(err: RemountError, explain: Box) -> OSError { OSError(MountError::Remount(err), explain) } - fn from_nix(err: nix::Error, explain: Box) -> OSError { + fn from_nix(err: nix::Error, explain: Box) -> OSError { OSError( MountError::Io( err.as_errno().map_or_else(|| io::Error::new(io::ErrorKind::Other, err), io::Error::from), @@ -94,8 +84,5 @@ impl OSError { /// The error holder which contains as much information about why failure /// happens as the library implementors could gain -/// -/// This type only provides `Display` for now, but some programmatic interface -/// is expected in future. #[derive(Debug)] -pub struct Error(Box, io::Error, String); +pub struct Error(Box, io::Error, String); diff --git a/src/modify.rs b/src/modify.rs index 15187a6b6..69141c497 100644 --- a/src/modify.rs +++ b/src/modify.rs @@ -4,9 +4,9 @@ use std::path::Path; use nix::mount::{MsFlags, mount}; -use {OSError, Error}; -use util::{path_to_cstring, as_path}; -use explain::{Explainable, exists}; +use crate::{OSError, Error}; +use crate::util::{path_to_cstring, as_path}; +use crate::explain::{Explainable, exists}; /// A move operation definition /// diff --git a/src/mountinfo.rs b/src/mountinfo.rs index 58e9113fe..b0e46b9db 100644 --- a/src/mountinfo.rs +++ b/src/mountinfo.rs @@ -1,6 +1,6 @@ //! This module contains parser for /proc/PID/mountinfo //! -use std; + use std::fmt; use std::ffi::{OsStr, OsString}; use std::os::unix::ffi::{OsStrExt, OsStringExt}; @@ -23,7 +23,7 @@ impl fmt::Display for ParseRowError { impl Error for ParseRowError { fn description(&self) -> &str { - return &self.0; + &self.0 } } @@ -38,9 +38,9 @@ pub struct ParseError { impl ParseError { fn new(msg: String, row_num: usize, row: String) -> ParseError { ParseError { - msg: msg, - row_num: row_num, - row: row, + msg, + row_num, + row, } } } @@ -48,13 +48,13 @@ impl ParseError { impl fmt::Display for ParseError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "Parse error at line {}: {}\n{}", - self.row_num, self.description(), self.row) + self.row_num, self, self.row) } } impl Error for ParseError { fn description(&self) -> &str { - return &self.msg; + &self.msg } } @@ -73,7 +73,7 @@ impl<'a> Parser<'a> { /// `data` should contain whole contents of `mountinfo` file of any process pub fn new(data: &'a [u8]) -> Parser<'a> { Parser { - data: data, + data, row_num: 0, exhausted: false, } @@ -172,29 +172,29 @@ pub(crate) fn parse_mount_point<'a>(row: &'a [u8]) return Ok(None); } - let (mount_id, row) = try!(parse_int(row)); - let (parent_id, row) = try!(parse_int(row)); - let (major, minor, row) = try!(parse_major_minor(row)); - let (root, row) = try!(parse_os_str(row)); - let (mount_point, row) = try!(parse_os_str(row)); - let (mount_options, row) = try!(parse_os_str(row)); - let (optional_fields, row) = try!(parse_optional(row)); - let (fstype, row) = try!(parse_os_str(row)); - let (mount_source, row) = try!(parse_os_str(row)); - let (super_options, _) = try!(parse_os_str(row)); + let (mount_id, row) = parse_int(row)?; + let (parent_id, row) = parse_int(row)?; + let (major, minor, row) = parse_major_minor(row)?; + let (root, row) = parse_os_str(row)?; + let (mount_point, row) = parse_os_str(row)?; + let (mount_options, row) = parse_os_str(row)?; + let (optional_fields, row) = parse_optional(row)?; + let (fstype, row) = parse_os_str(row)?; + let (mount_source, row) = parse_os_str(row)?; + let (super_options, _) = parse_os_str(row)?; // TODO: should we ignore extra fields? Ok(Some(MountPoint { - mount_id: mount_id, - parent_id: parent_id, - major: major, - minor: minor, - root: root, - mount_point: mount_point, - mount_options: mount_options, - optional_fields: optional_fields, - fstype: fstype, - mount_source: mount_source, - super_options: super_options, + mount_id, + parent_id, + major, + minor, + root, + mount_point, + mount_options, + optional_fields, + fstype, + mount_source, + super_options, })) } @@ -211,7 +211,7 @@ fn is_comment_line(row: &[u8]) -> bool { } return false; } - return false; + false } fn rstrip_cr(row: &[u8]) -> &[u8] { @@ -226,7 +226,7 @@ fn parse_field<'a>(data: &'a [u8], delimit: &'a [u8]) -> Result<(&'a [u8], &'a [u8]), ParseRowError> { if data.is_empty() { - return Err(ParseRowError(format!("Expected more fields"))); + return Err(ParseRowError("Expected more fields".to_string())); } let data = lstrip_whitespaces(data); Ok(split_by(data, delimit)) @@ -235,38 +235,38 @@ fn parse_field<'a>(data: &'a [u8], delimit: &'a [u8]) fn parse_os_str<'a>(data: &'a [u8]) -> Result<(Cow<'a, OsStr>, &'a [u8]), ParseRowError> { - let (field, tail) = try!(parse_field(data, b" ")); + let (field, tail) = parse_field(data, b" ")?; Ok((unescape_octals(OsStr::from_bytes(field)), tail)) } fn parse_int(data: &[u8]) -> Result<(c_ulong, &[u8]), ParseRowError> { - let (field, tail) = try!(parse_field(data, b" ")); - let v = try!(std::str::from_utf8(field).map_err(|e| { + let (field, tail) = parse_field(data, b" ")?; + let v = std::str::from_utf8(field).map_err(|e| { ParseRowError(format!("Cannot parse integer {:?}: {}", - String::from_utf8_lossy(field).into_owned(), e))})); + String::from_utf8_lossy(field).into_owned(), e))})?; - let v = try!(c_ulong::from_str_radix(v, 10).map_err(|e| { + let v = c_ulong::from_str_radix(v, 10).map_err(|e| { ParseRowError(format!("Cannot parse integer {:?}: {}", - String::from_utf8_lossy(field).into_owned(), e))})); + String::from_utf8_lossy(field).into_owned(), e))})?; Ok((v, tail)) } fn parse_major_minor(data: &[u8]) -> Result<(c_ulong, c_ulong, &[u8]), ParseRowError> { - let (major_field, data) = try!(parse_field(data, b":")); - let (minor_field, tail) = try!(parse_field(data, b" ")); - let (major, _) = try!(parse_int(major_field)); - let (minor, _) = try!(parse_int(minor_field)); + let (major_field, data) = parse_field(data, b":")?; + let (minor_field, tail) = parse_field(data, b" ")?; + let (major, _) = parse_int(major_field)?; + let (minor, _) = parse_int(minor_field)?; Ok((major, minor, tail)) } fn parse_optional<'a>(data: &'a [u8]) -> Result<(Cow<'a, OsStr>, &'a [u8]), ParseRowError> { - let (field, tail) = try!(parse_field(data, b"- ")); + let (field, tail) = parse_field(data, b"- ")?; let field = rstrip_whitespaces(field); Ok((unescape_octals(OsStr::from_bytes(field)), tail)) } @@ -277,7 +277,7 @@ fn lstrip_whitespaces(v: &[u8]) -> &[u8] { return &v[i..]; } } - return &v[0..0]; + &v[0..0] } fn rstrip_whitespaces(v: &[u8]) -> &[u8] { @@ -286,7 +286,7 @@ fn rstrip_whitespaces(v: &[u8]) -> &[u8] { return &v[..i + 1]; } } - return &v[0..0]; + &v[0..0] } fn split_by<'a, 'b>(v: &'a [u8], needle: &'b [u8]) -> (&'a [u8], &'a [u8]) { @@ -301,7 +301,7 @@ fn split_by<'a, 'b>(v: &'a [u8], needle: &'b [u8]) -> (&'a [u8], &'a [u8]) { } i += 1; } - return (&v[0..], &v[0..0]); + (&v[0..], &v[0..0]) } fn unescape_octals(s: &OsStr) -> Cow { @@ -342,7 +342,7 @@ fn is_octal_encoding(v: &[u8]) -> bool { } fn is_oct(c: u8) -> bool { - c >= b'0' && c <= b'7' + (b'0'..=b'7').contains(&c) } fn parse_octal(v: &[u8]) -> u8 { diff --git a/src/overlay.rs b/src/overlay.rs index bccd8676c..0766dc00b 100644 --- a/src/overlay.rs +++ b/src/overlay.rs @@ -1,15 +1,15 @@ use std::fmt; use std::path::{Path, PathBuf}; -use std::fs::metadata; +use fs_err::metadata; use std::ffi::{CStr, CString}; use std::os::unix::fs::MetadataExt; use std::os::unix::ffi::OsStrExt; use nix::mount::{MsFlags, mount}; -use util::{path_to_cstring, as_path}; -use {OSError, Error}; -use explain::{Explainable, exists, user}; +use crate::util::{path_to_cstring, as_path}; +use crate::{OSError, Error}; +use crate::explain::{Explainable, exists, user}; /// An overlay mount point @@ -147,8 +147,8 @@ impl Explainable for Overlay { info.push(format!("workdir: {}", exists(&wdir))); if let (Some(u), Some(w)) = (umeta, wmeta) { - info.push(format!("{}", if u.dev() == w.dev() - { "same-fs" } else { "different-fs" })); + info.push(if u.dev() == w.dev() + { "same-fs" } else { "different-fs" }.to_string()); } if udir.starts_with(wdir) { info.push("upperdir-prefix-of-workdir".to_string()); @@ -157,7 +157,7 @@ impl Explainable for Overlay { } info.push(format!("target: {}", exists(as_path(&self.target)))); } - if self.lowerdirs.len() < 1 { + if self.lowerdirs.is_empty() { info.push("no-lowerdirs".to_string()); } else if self.upperdir.is_none() && self.lowerdirs.len() < 2 { info.push("single-lowerdir".to_string()); diff --git a/src/remount.rs b/src/remount.rs index 807626f86..26a3a5c9a 100644 --- a/src/remount.rs +++ b/src/remount.rs @@ -1,7 +1,7 @@ use std::io; use std::fmt; use std::ffi::CStr; -use std::fs::File; +use fs_err::File; use std::io::Read; use std::path::{Path, PathBuf}; use std::env::current_dir; @@ -9,10 +9,10 @@ use std::default::Default; use nix::mount::{MsFlags, mount}; -use {OSError, Error}; -use util::path_to_cstring; -use explain::{Explainable, exists, user}; -use mountinfo::{parse_mount_point}; +use crate::{OSError, Error}; +use crate::util::path_to_cstring; +use crate::explain::{Explainable, exists, user}; +use crate::mountinfo::{parse_mount_point}; /// A remount definition /// @@ -67,23 +67,17 @@ fn apply_flag(flags: MsFlags, flag: MsFlags, set: Option) -> MsFlags { } } -quick_error! { - #[derive(Debug)] - pub enum RemountError { - Io(msg: String, err: io::Error) { - cause(err) - display("{}: {}", msg, err) - description(err.description()) - from(err: io::Error) -> (String::new(), err) - } - ParseMountInfo(err: String) { - display("{}", err) - from() - } - UnknownMountPoint(path: PathBuf) { - display("Cannot find mount point: {:?}", path) - } - } +#[derive(Debug, thiserror::Error)] +#[allow(missing_docs)] +pub enum RemountError { + #[error(transparent)] + Io(#[from] io::Error), + + #[error("{0}")] + ParseMountInfo(String), + + #[error("Cannot find mount point: {0:?}")] + UnknownMountPoint(PathBuf), } impl Remount { @@ -188,51 +182,51 @@ impl fmt::Display for MountFlags { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { let mut prefix = ""; if let Some(true) = self.bind { - try!(write!(fmt, "{}bind", prefix)); + write!(fmt, "{}bind", prefix)?; prefix = ","; } if let Some(true) = self.readonly { - try!(write!(fmt, "{}ro", prefix)); + write!(fmt, "{}ro", prefix)?; prefix = ","; } if let Some(true) = self.nodev { - try!(write!(fmt, "{}nodev", prefix)); + write!(fmt, "{}nodev", prefix)?; prefix = ","; } if let Some(true) = self.noexec { - try!(write!(fmt, "{}noexec", prefix)); + write!(fmt, "{}noexec", prefix)?; prefix = ","; } if let Some(true) = self.nosuid { - try!(write!(fmt, "{}nosuid", prefix)); + write!(fmt, "{}nosuid", prefix)?; prefix = ","; } if let Some(true) = self.noatime { - try!(write!(fmt, "{}noatime", prefix)); + write!(fmt, "{}noatime", prefix)?; prefix = ","; } if let Some(true) = self.nodiratime { - try!(write!(fmt, "{}nodiratime", prefix)); + write!(fmt, "{}nodiratime", prefix)?; prefix = ","; } if let Some(true) = self.relatime { - try!(write!(fmt, "{}relatime", prefix)); + write!(fmt, "{}relatime", prefix)?; prefix = ","; } if let Some(true) = self.strictatime { - try!(write!(fmt, "{}strictatime", prefix)); + write!(fmt, "{}strictatime", prefix)?; prefix = ","; } if let Some(true) = self.dirsync { - try!(write!(fmt, "{}dirsync", prefix)); + write!(fmt, "{}dirsync", prefix)?; prefix = ","; } if let Some(true) = self.synchronous { - try!(write!(fmt, "{}sync", prefix)); + write!(fmt, "{}sync", prefix)?; prefix = ","; } if let Some(true) = self.mandlock { - try!(write!(fmt, "{}mand", prefix)); + write!(fmt, "{}mand", prefix)?; } Ok(()) } @@ -241,7 +235,7 @@ impl fmt::Display for MountFlags { impl fmt::Display for Remount { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { if !self.flags.apply_to_flags(MsFlags::empty()).is_empty() { - try!(write!(fmt, "{} ", self.flags)); + write!(fmt, "{} ", self.flags)?; } write!(fmt, "remount {:?}", &self.path) } @@ -251,7 +245,7 @@ impl Explainable for Remount { fn explain(&self) -> String { [ format!("path: {}", exists(&self.path)), - format!("{}", user()), + user().to_string(), ].join(", ") } } @@ -260,18 +254,14 @@ fn get_mountpoint_flags(path: &Path) -> Result { let mount_path = if path.is_absolute() { path.to_path_buf() } else { - let mut mpath = try!(current_dir()); + let mut mpath = current_dir()?; mpath.push(path); mpath }; let mut mountinfo_content = Vec::with_capacity(4 * 1024); let mountinfo_path = Path::new("/proc/self/mountinfo"); - let mut mountinfo_file = try!(File::open(mountinfo_path) - .map_err(|e| RemountError::Io( - format!("Cannot open file: {:?}", mountinfo_path), e))); - try!(mountinfo_file.read_to_end(&mut mountinfo_content) - .map_err(|e| RemountError::Io( - format!("Cannot read file: {:?}", mountinfo_path), e))); + let mut mountinfo_file = File::open(mountinfo_path)?; + mountinfo_file.read_to_end(&mut mountinfo_content)?; match get_mountpoint_flags_from(&mountinfo_content, &mount_path) { Ok(Some(flags)) => Ok(flags), Ok(None) => Err(RemountError::UnknownMountPoint(mount_path)), @@ -303,7 +293,7 @@ mod test { use nix::mount::MsFlags; - use Error; + use crate::Error; use super::{Remount, RemountError, MountFlags}; use super::{get_mountpoint_flags, get_mountpoint_flags_from}; diff --git a/src/tmpfs.rs b/src/tmpfs.rs index 5c9f3e7a0..f347455d5 100644 --- a/src/tmpfs.rs +++ b/src/tmpfs.rs @@ -7,9 +7,9 @@ use std::path::Path; use libc::{uid_t, gid_t, mode_t}; use nix::mount::{MsFlags, mount}; -use {OSError, Error}; -use util::{path_to_cstring, as_path}; -use explain::{Explainable, exists, user}; +use crate::{OSError, Error}; +use crate::util::{path_to_cstring, as_path}; +use crate::explain::{Explainable, exists, user}; #[derive(Debug, Clone, Copy)] @@ -108,12 +108,12 @@ impl Tmpfs { } write!(cur, "gid={}", gid).unwrap(); } - return cur.into_inner(); + cur.into_inner() } /// Mount the tmpfs pub fn bare_mount(self) -> Result<(), OSError> { - let mut options = self.format_options(); + let options = self.format_options(); mount( Some(CStr::from_bytes_with_nul(b"tmpfs\0").unwrap()), &*self.target, @@ -141,7 +141,7 @@ impl Explainable for Tmpfs { fn explain(&self) -> String { [ format!("target: {}", exists(as_path(&self.target))), - format!("{}", user()), + user().to_string(), ].join(", ") } }