shared: add better visibility into IO errors

pull/71/head^2
Jake McGinty 2021-05-09 21:34:11 +09:00
parent 9d69515d19
commit 981f7e8701
5 changed files with 32 additions and 15 deletions

View File

@ -1,7 +1,7 @@
use crate::Error; use crate::Error;
use colored::*; use colored::*;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use shared::{ensure_dirs_exist, Cidr, IoErrorContext, Peer, CLIENT_DATA_PATH}; use shared::{ensure_dirs_exist, Cidr, IoErrorContext, Peer, WrappedIoError, CLIENT_DATA_PATH};
use std::{ use std::{
fs::{File, OpenOptions}, fs::{File, OpenOptions},
io::{Read, Seek, SeekFrom, Write}, io::{Read, Seek, SeekFrom, Write},
@ -23,7 +23,10 @@ pub enum Contents {
} }
impl DataStore { impl DataStore {
pub(self) fn open_with_path<P: AsRef<Path>>(path: P, create: bool) -> Result<Self, Error> { pub(self) fn open_with_path<P: AsRef<Path>>(
path: P,
create: bool,
) -> Result<Self, WrappedIoError> {
let path = path.as_ref(); let path = path.as_ref();
let mut file = OpenOptions::new() let mut file = OpenOptions::new()
.read(true) .read(true)
@ -32,7 +35,7 @@ impl DataStore {
.open(path) .open(path)
.with_path(path)?; .with_path(path)?;
if shared::chmod(&file, 0o600)? { if shared::chmod(&file, 0o600).with_path(path)? {
println!( println!(
"{} updated permissions for {} to 0600.", "{} updated permissions for {} to 0600.",
"[!]".yellow(), "[!]".yellow(),
@ -56,16 +59,16 @@ impl DataStore {
.with_extension("json") .with_extension("json")
} }
fn _open(interface: &InterfaceName, create: bool) -> Result<Self, Error> { fn _open(interface: &InterfaceName, create: bool) -> Result<Self, WrappedIoError> {
ensure_dirs_exist(&[*CLIENT_DATA_PATH])?; ensure_dirs_exist(&[*CLIENT_DATA_PATH])?;
Self::open_with_path(Self::get_path(interface), create) Self::open_with_path(Self::get_path(interface), create)
} }
pub fn open(interface: &InterfaceName) -> Result<Self, Error> { pub fn open(interface: &InterfaceName) -> Result<Self, WrappedIoError> {
Self::_open(interface, false) Self::_open(interface, false)
} }
pub fn open_or_create(interface: &InterfaceName) -> Result<Self, Error> { pub fn open_or_create(interface: &InterfaceName) -> Result<Self, WrappedIoError> {
Self::_open(interface, true) Self::_open(interface, true)
} }

View File

@ -400,7 +400,7 @@ fn fetch(
let mut store = DataStore::open_or_create(&interface)?; let mut store = DataStore::open_or_create(&interface)?;
let State { peers, cidrs } = Api::new(&config.server).http("GET", "/user/state")?; let State { peers, cidrs } = Api::new(&config.server).http("GET", "/user/state")?;
let device_info = DeviceInfo::get_by_name(&interface)?; let device_info = DeviceInfo::get_by_name(&interface).with_str(interface.as_str_lossy())?;
let interface_public_key = device_info let interface_public_key = device_info
.public_key .public_key
.as_ref() .as_ref()
@ -716,7 +716,12 @@ fn show(short: bool, tree: bool, interface: Option<Interface>) -> Result<(), Err
let devices = interfaces.into_iter().filter_map(|name| { let devices = interfaces.into_iter().filter_map(|name| {
DataStore::open(&name) DataStore::open(&name)
.and_then(|store| Ok((DeviceInfo::get_by_name(&name)?, store))) .and_then(|store| {
Ok((
DeviceInfo::get_by_name(&name).with_str(name.as_str_lossy())?,
store,
))
})
.ok() .ok()
}); });
for (mut device_info, store) in devices { for (mut device_info, store) in devices {

View File

@ -31,22 +31,22 @@ pub type Error = Box<dyn std::error::Error>;
pub static WG_MANAGE_DIR: &str = "/etc/innernet"; pub static WG_MANAGE_DIR: &str = "/etc/innernet";
pub static WG_DIR: &str = "/etc/wireguard"; pub static WG_DIR: &str = "/etc/wireguard";
pub fn ensure_dirs_exist(dirs: &[&Path]) -> Result<(), Error> { pub fn ensure_dirs_exist(dirs: &[&Path]) -> Result<(), WrappedIoError> {
for dir in dirs { for dir in dirs {
match fs::create_dir(dir) { match fs::create_dir(dir).with_path(dir) {
Err(e) if e.kind() != io::ErrorKind::AlreadyExists => { Err(e) if e.kind() != io::ErrorKind::AlreadyExists => {
return Err(e.into()); return Err(e.into());
}, }
_ => { _ => {
let target_file = File::open(dir).with_path(dir)?; let target_file = File::open(dir).with_path(dir)?;
if chmod(&target_file, 0o700)? { if chmod(&target_file, 0o700).with_path(dir)? {
println!( println!(
"{} updated permissions for {} to 0700.", "{} updated permissions for {} to 0700.",
"[!]".yellow(), "[!]".yellow(),
dir.display() dir.display()
); );
} }
}, }
} }
} }
Ok(()) Ok(())
@ -55,7 +55,7 @@ pub fn ensure_dirs_exist(dirs: &[&Path]) -> Result<(), Error> {
/// Updates the permissions of a file or directory. Returns `Ok(true)` if /// Updates the permissions of a file or directory. Returns `Ok(true)` if
/// permissions had to be changed, `Ok(false)` if permissions were already /// permissions had to be changed, `Ok(false)` if permissions were already
/// correct. /// correct.
pub fn chmod(file: &File, new_mode: u32) -> Result<bool, Error> { pub fn chmod(file: &File, new_mode: u32) -> Result<bool, io::Error> {
let metadata = file.metadata()?; let metadata = file.metadata()?;
let mut permissions = metadata.permissions(); let mut permissions = metadata.permissions();
let mode = permissions.mode() & 0o777; let mode = permissions.mode() & 0o777;

View File

@ -73,7 +73,7 @@ impl FromStr for Endpoint {
let port = port.parse().map_err(|_| "couldn't parse port")?; let port = port.parse().map_err(|_| "couldn't parse port")?;
let host = Host::parse(host).map_err(|_| "couldn't parse host")?; let host = Host::parse(host).map_err(|_| "couldn't parse host")?;
Ok(Endpoint { host, port }) Ok(Endpoint { host, port })
}, }
_ => Err("couldn't parse in form of 'host:port'"), _ => Err("couldn't parse in form of 'host:port'"),
} }
} }
@ -606,6 +606,14 @@ impl std::fmt::Display for WrappedIoError {
} }
} }
impl Deref for WrappedIoError {
type Target = std::io::Error;
fn deref(&self) -> &Self::Target {
&self.io_error
}
}
impl std::error::Error for WrappedIoError {} impl std::error::Error for WrappedIoError {}
#[cfg(test)] #[cfg(test)]

View File

@ -252,6 +252,7 @@ impl DeviceInfo {
if backends::kernel::exists() { if backends::kernel::exists() {
backends::kernel::get_by_name(name) backends::kernel::get_by_name(name)
} else { } else {
println!("kernel module not detected. falling back to userspace backend.");
backends::userspace::get_by_name(name) backends::userspace::get_by_name(name)
} }
} }