mirror of
https://github.com/veeso/termscp.git
synced 2025-12-07 09:36:00 -08:00
Working on logging
This commit is contained in:
@@ -319,14 +319,14 @@ impl std::string::ToString for FileTransferProtocol {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl std::str::FromStr for FileTransferProtocol {
|
impl std::str::FromStr for FileTransferProtocol {
|
||||||
type Err = ();
|
type Err = String;
|
||||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
match s.to_ascii_uppercase().as_str() {
|
match s.to_ascii_uppercase().as_str() {
|
||||||
"FTP" => Ok(FileTransferProtocol::Ftp(false)),
|
"FTP" => Ok(FileTransferProtocol::Ftp(false)),
|
||||||
"FTPS" => Ok(FileTransferProtocol::Ftp(true)),
|
"FTPS" => Ok(FileTransferProtocol::Ftp(true)),
|
||||||
"SCP" => Ok(FileTransferProtocol::Scp),
|
"SCP" => Ok(FileTransferProtocol::Scp),
|
||||||
"SFTP" => Ok(FileTransferProtocol::Sftp),
|
"SFTP" => Ok(FileTransferProtocol::Sftp),
|
||||||
_ => Err(()),
|
_ => Err(s.to_string()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
212
src/host/mod.rs
212
src/host/mod.rs
@@ -125,12 +125,17 @@ impl Localhost {
|
|||||||
///
|
///
|
||||||
/// Instantiates a new Localhost struct
|
/// Instantiates a new Localhost struct
|
||||||
pub fn new(wrkdir: PathBuf) -> Result<Localhost, HostError> {
|
pub fn new(wrkdir: PathBuf) -> Result<Localhost, HostError> {
|
||||||
|
debug!("Initializing localhost at {}", wrkdir.display());
|
||||||
let mut host: Localhost = Localhost {
|
let mut host: Localhost = Localhost {
|
||||||
wrkdir,
|
wrkdir,
|
||||||
files: Vec::new(),
|
files: Vec::new(),
|
||||||
};
|
};
|
||||||
// Check if dir exists
|
// Check if dir exists
|
||||||
if !host.file_exists(host.wrkdir.as_path()) {
|
if !host.file_exists(host.wrkdir.as_path()) {
|
||||||
|
error!(
|
||||||
|
"Failed to initialize localhost: {} doesn't exist",
|
||||||
|
host.wrkdir.display()
|
||||||
|
);
|
||||||
return Err(HostError::new(
|
return Err(HostError::new(
|
||||||
HostErrorType::NoSuchFileOrDirectory,
|
HostErrorType::NoSuchFileOrDirectory,
|
||||||
None,
|
None,
|
||||||
@@ -140,8 +145,15 @@ impl Localhost {
|
|||||||
// Retrieve files for provided path
|
// Retrieve files for provided path
|
||||||
host.files = match host.scan_dir(host.wrkdir.as_path()) {
|
host.files = match host.scan_dir(host.wrkdir.as_path()) {
|
||||||
Ok(files) => files,
|
Ok(files) => files,
|
||||||
Err(err) => return Err(err),
|
Err(err) => {
|
||||||
|
error!(
|
||||||
|
"Failed to initialize localhost: could not scan wrkdir: {}",
|
||||||
|
err
|
||||||
|
);
|
||||||
|
return Err(err);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
info!("Localhost initialized with success");
|
||||||
Ok(host)
|
Ok(host)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -165,8 +177,10 @@ impl Localhost {
|
|||||||
/// Change working directory with the new provided directory
|
/// Change working directory with the new provided directory
|
||||||
pub fn change_wrkdir(&mut self, new_dir: &Path) -> Result<PathBuf, HostError> {
|
pub fn change_wrkdir(&mut self, new_dir: &Path) -> Result<PathBuf, HostError> {
|
||||||
let new_dir: PathBuf = self.to_abs_path(new_dir);
|
let new_dir: PathBuf = self.to_abs_path(new_dir);
|
||||||
|
info!("Changing localhost directory to {}...", new_dir.display());
|
||||||
// Check whether directory exists
|
// Check whether directory exists
|
||||||
if !self.file_exists(new_dir.as_path()) {
|
if !self.file_exists(new_dir.as_path()) {
|
||||||
|
error!("Could not change directory: No such file or directory");
|
||||||
return Err(HostError::new(
|
return Err(HostError::new(
|
||||||
HostErrorType::NoSuchFileOrDirectory,
|
HostErrorType::NoSuchFileOrDirectory,
|
||||||
None,
|
None,
|
||||||
@@ -174,10 +188,11 @@ impl Localhost {
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
// Change directory
|
// Change directory
|
||||||
if std::env::set_current_dir(new_dir.as_path()).is_err() {
|
if let Err(err) = std::env::set_current_dir(new_dir.as_path()) {
|
||||||
|
error!("Could not enter directory: {}", err);
|
||||||
return Err(HostError::new(
|
return Err(HostError::new(
|
||||||
HostErrorType::NoSuchFileOrDirectory,
|
HostErrorType::NoSuchFileOrDirectory,
|
||||||
None,
|
Some(err),
|
||||||
new_dir.as_path(),
|
new_dir.as_path(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
@@ -189,11 +204,13 @@ impl Localhost {
|
|||||||
self.files = match self.scan_dir(self.wrkdir.as_path()) {
|
self.files = match self.scan_dir(self.wrkdir.as_path()) {
|
||||||
Ok(files) => files,
|
Ok(files) => files,
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
|
error!("Could not scan new directory: {}", err);
|
||||||
// Restore directory
|
// Restore directory
|
||||||
self.wrkdir = prev_dir;
|
self.wrkdir = prev_dir;
|
||||||
return Err(err);
|
return Err(err);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
debug!("Changed directory to {}", self.wrkdir.display());
|
||||||
Ok(self.wrkdir.clone())
|
Ok(self.wrkdir.clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -210,6 +227,7 @@ impl Localhost {
|
|||||||
/// ignex: don't report error if directory already exists
|
/// ignex: don't report error if directory already exists
|
||||||
pub fn mkdir_ex(&mut self, dir_name: &Path, ignex: bool) -> Result<(), HostError> {
|
pub fn mkdir_ex(&mut self, dir_name: &Path, ignex: bool) -> Result<(), HostError> {
|
||||||
let dir_path: PathBuf = self.to_abs_path(dir_name);
|
let dir_path: PathBuf = self.to_abs_path(dir_name);
|
||||||
|
info!("Making directory {}", dir_path.display());
|
||||||
// If dir already exists, return Error
|
// If dir already exists, return Error
|
||||||
if dir_path.exists() {
|
if dir_path.exists() {
|
||||||
match ignex {
|
match ignex {
|
||||||
@@ -229,13 +247,17 @@ impl Localhost {
|
|||||||
if dir_name.is_relative() {
|
if dir_name.is_relative() {
|
||||||
self.files = self.scan_dir(self.wrkdir.as_path())?;
|
self.files = self.scan_dir(self.wrkdir.as_path())?;
|
||||||
}
|
}
|
||||||
|
info!("Created directory {}", dir_path.display());
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
Err(err) => Err(HostError::new(
|
Err(err) => {
|
||||||
HostErrorType::CouldNotCreateFile,
|
error!("Could not make directory: {}", err);
|
||||||
Some(err),
|
Err(HostError::new(
|
||||||
dir_path.as_path(),
|
HostErrorType::CouldNotCreateFile,
|
||||||
)),
|
Some(err),
|
||||||
|
dir_path.as_path(),
|
||||||
|
))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -246,7 +268,9 @@ impl Localhost {
|
|||||||
match entry {
|
match entry {
|
||||||
FsEntry::Directory(dir) => {
|
FsEntry::Directory(dir) => {
|
||||||
// If file doesn't exist; return error
|
// If file doesn't exist; return error
|
||||||
|
debug!("Removing directory {}", dir.abs_path.display());
|
||||||
if !dir.abs_path.as_path().exists() {
|
if !dir.abs_path.as_path().exists() {
|
||||||
|
error!("Directory doesn't exist");
|
||||||
return Err(HostError::new(
|
return Err(HostError::new(
|
||||||
HostErrorType::NoSuchFileOrDirectory,
|
HostErrorType::NoSuchFileOrDirectory,
|
||||||
None,
|
None,
|
||||||
@@ -258,18 +282,24 @@ impl Localhost {
|
|||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
// Update dir
|
// Update dir
|
||||||
self.files = self.scan_dir(self.wrkdir.as_path())?;
|
self.files = self.scan_dir(self.wrkdir.as_path())?;
|
||||||
|
info!("Removed directory {}", dir.abs_path.display());
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
Err(err) => Err(HostError::new(
|
Err(err) => {
|
||||||
HostErrorType::DeleteFailed,
|
error!("Could not remove directory: {}", err);
|
||||||
Some(err),
|
Err(HostError::new(
|
||||||
dir.abs_path.as_path(),
|
HostErrorType::DeleteFailed,
|
||||||
)),
|
Some(err),
|
||||||
|
dir.abs_path.as_path(),
|
||||||
|
))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
FsEntry::File(file) => {
|
FsEntry::File(file) => {
|
||||||
// If file doesn't exist; return error
|
// If file doesn't exist; return error
|
||||||
|
debug!("Removing file {}", file.abs_path.display());
|
||||||
if !file.abs_path.as_path().exists() {
|
if !file.abs_path.as_path().exists() {
|
||||||
|
error!("File doesn't exist");
|
||||||
return Err(HostError::new(
|
return Err(HostError::new(
|
||||||
HostErrorType::NoSuchFileOrDirectory,
|
HostErrorType::NoSuchFileOrDirectory,
|
||||||
None,
|
None,
|
||||||
@@ -281,13 +311,17 @@ impl Localhost {
|
|||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
// Update dir
|
// Update dir
|
||||||
self.files = self.scan_dir(self.wrkdir.as_path())?;
|
self.files = self.scan_dir(self.wrkdir.as_path())?;
|
||||||
|
info!("Removed file {}", file.abs_path.display());
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
Err(err) => Err(HostError::new(
|
Err(err) => {
|
||||||
HostErrorType::DeleteFailed,
|
error!("Could not remove file: {}", err);
|
||||||
Some(err),
|
Err(HostError::new(
|
||||||
file.abs_path.as_path(),
|
HostErrorType::DeleteFailed,
|
||||||
)),
|
Some(err),
|
||||||
|
file.abs_path.as_path(),
|
||||||
|
))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -302,13 +336,26 @@ impl Localhost {
|
|||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
// Scan dir
|
// Scan dir
|
||||||
self.files = self.scan_dir(self.wrkdir.as_path())?;
|
self.files = self.scan_dir(self.wrkdir.as_path())?;
|
||||||
|
debug!(
|
||||||
|
"Moved file {} to {}",
|
||||||
|
entry.get_abs_path().display(),
|
||||||
|
dst_path.display()
|
||||||
|
);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
Err(err) => Err(HostError::new(
|
Err(err) => {
|
||||||
HostErrorType::CouldNotCreateFile,
|
error!(
|
||||||
Some(err),
|
"Failed to move {} to {}: {}",
|
||||||
abs_path.as_path(),
|
entry.get_abs_path().display(),
|
||||||
)),
|
dst_path.display(),
|
||||||
|
err
|
||||||
|
);
|
||||||
|
Err(HostError::new(
|
||||||
|
HostErrorType::CouldNotCreateFile,
|
||||||
|
Some(err),
|
||||||
|
abs_path.as_path(),
|
||||||
|
))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -318,6 +365,11 @@ impl Localhost {
|
|||||||
pub fn copy(&mut self, entry: &FsEntry, dst: &Path) -> Result<(), HostError> {
|
pub fn copy(&mut self, entry: &FsEntry, dst: &Path) -> Result<(), HostError> {
|
||||||
// Get absolute path of dest
|
// Get absolute path of dest
|
||||||
let dst: PathBuf = self.to_abs_path(dst);
|
let dst: PathBuf = self.to_abs_path(dst);
|
||||||
|
info!(
|
||||||
|
"Copying file {} to {}",
|
||||||
|
entry.get_abs_path().display(),
|
||||||
|
dst.display()
|
||||||
|
);
|
||||||
// Match entry
|
// Match entry
|
||||||
match entry {
|
match entry {
|
||||||
FsEntry::File(file) => {
|
FsEntry::File(file) => {
|
||||||
@@ -333,16 +385,19 @@ impl Localhost {
|
|||||||
};
|
};
|
||||||
// Copy entry path to dst path
|
// Copy entry path to dst path
|
||||||
if let Err(err) = std::fs::copy(file.abs_path.as_path(), dst.as_path()) {
|
if let Err(err) = std::fs::copy(file.abs_path.as_path(), dst.as_path()) {
|
||||||
|
error!("Failed to copy file: {}", err);
|
||||||
return Err(HostError::new(
|
return Err(HostError::new(
|
||||||
HostErrorType::CouldNotCreateFile,
|
HostErrorType::CouldNotCreateFile,
|
||||||
Some(err),
|
Some(err),
|
||||||
file.abs_path.as_path(),
|
file.abs_path.as_path(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
info!("File copied");
|
||||||
}
|
}
|
||||||
FsEntry::Directory(dir) => {
|
FsEntry::Directory(dir) => {
|
||||||
// If destination path doesn't exist, create destination
|
// If destination path doesn't exist, create destination
|
||||||
if !dst.exists() {
|
if !dst.exists() {
|
||||||
|
debug!("Directory {} doesn't exist; creating it", dst.display());
|
||||||
self.mkdir(dst.as_path())?;
|
self.mkdir(dst.as_path())?;
|
||||||
}
|
}
|
||||||
// Scan dir
|
// Scan dir
|
||||||
@@ -386,15 +441,17 @@ impl Localhost {
|
|||||||
/// Stat file and create a FsEntry
|
/// Stat file and create a FsEntry
|
||||||
#[cfg(any(target_os = "unix", target_os = "macos", target_os = "linux"))]
|
#[cfg(any(target_os = "unix", target_os = "macos", target_os = "linux"))]
|
||||||
pub fn stat(&self, path: &Path) -> Result<FsEntry, HostError> {
|
pub fn stat(&self, path: &Path) -> Result<FsEntry, HostError> {
|
||||||
|
info!("Stating file {}", path.display());
|
||||||
let path: PathBuf = self.to_abs_path(path);
|
let path: PathBuf = self.to_abs_path(path);
|
||||||
let attr: Metadata = match fs::metadata(path.as_path()) {
|
let attr: Metadata = match fs::metadata(path.as_path()) {
|
||||||
Ok(metadata) => metadata,
|
Ok(metadata) => metadata,
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
|
error!("Could not read file metadata: {}", err);
|
||||||
return Err(HostError::new(
|
return Err(HostError::new(
|
||||||
HostErrorType::FileNotAccessible,
|
HostErrorType::FileNotAccessible,
|
||||||
Some(err),
|
Some(err),
|
||||||
path.as_path(),
|
path.as_path(),
|
||||||
))
|
));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let file_name: String = String::from(path.file_name().unwrap().to_str().unwrap_or(""));
|
let file_name: String = String::from(path.file_name().unwrap().to_str().unwrap_or(""));
|
||||||
@@ -454,14 +511,16 @@ impl Localhost {
|
|||||||
#[cfg(not(tarpaulin_include))]
|
#[cfg(not(tarpaulin_include))]
|
||||||
pub fn stat(&self, path: &Path) -> Result<FsEntry, HostError> {
|
pub fn stat(&self, path: &Path) -> Result<FsEntry, HostError> {
|
||||||
let path: PathBuf = self.to_abs_path(path);
|
let path: PathBuf = self.to_abs_path(path);
|
||||||
|
info!("Stating file {}", path.display());
|
||||||
let attr: Metadata = match fs::metadata(path.as_path()) {
|
let attr: Metadata = match fs::metadata(path.as_path()) {
|
||||||
Ok(metadata) => metadata,
|
Ok(metadata) => metadata,
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
|
error!("Could not read file metadata: {}", err);
|
||||||
return Err(HostError::new(
|
return Err(HostError::new(
|
||||||
HostErrorType::FileNotAccessible,
|
HostErrorType::FileNotAccessible,
|
||||||
Some(err),
|
Some(err),
|
||||||
path.as_path(),
|
path.as_path(),
|
||||||
))
|
));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let file_name: String = String::from(path.file_name().unwrap().to_str().unwrap_or(""));
|
let file_name: String = String::from(path.file_name().unwrap().to_str().unwrap_or(""));
|
||||||
@@ -523,16 +582,23 @@ impl Localhost {
|
|||||||
let args: Vec<&str> = cmd.split(' ').collect();
|
let args: Vec<&str> = cmd.split(' ').collect();
|
||||||
let cmd: &str = args.first().unwrap();
|
let cmd: &str = args.first().unwrap();
|
||||||
let argv: &[&str] = &args[1..];
|
let argv: &[&str] = &args[1..];
|
||||||
|
info!("Executing command: {} {:?}", cmd, argv);
|
||||||
match std::process::Command::new(cmd).args(argv).output() {
|
match std::process::Command::new(cmd).args(argv).output() {
|
||||||
Ok(output) => match std::str::from_utf8(&output.stdout) {
|
Ok(output) => match std::str::from_utf8(&output.stdout) {
|
||||||
Ok(s) => Ok(s.to_string()),
|
Ok(s) => {
|
||||||
|
info!("Command output: {}", s);
|
||||||
|
Ok(s.to_string())
|
||||||
|
}
|
||||||
Err(_) => Ok(String::new()),
|
Err(_) => Ok(String::new()),
|
||||||
},
|
},
|
||||||
Err(err) => Err(HostError::new(
|
Err(err) => {
|
||||||
HostErrorType::ExecutionFailed,
|
error!("Failed to run command: {}", err);
|
||||||
Some(err),
|
Err(HostError::new(
|
||||||
self.wrkdir.as_path(),
|
HostErrorType::ExecutionFailed,
|
||||||
)),
|
Some(err),
|
||||||
|
self.wrkdir.as_path(),
|
||||||
|
))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -548,19 +614,32 @@ impl Localhost {
|
|||||||
let mut mpex = metadata.permissions();
|
let mut mpex = metadata.permissions();
|
||||||
mpex.set_mode(self.mode_to_u32(pex));
|
mpex.set_mode(self.mode_to_u32(pex));
|
||||||
match set_permissions(path.as_path(), mpex) {
|
match set_permissions(path.as_path(), mpex) {
|
||||||
Ok(_) => Ok(()),
|
Ok(_) => {
|
||||||
Err(err) => Err(HostError::new(
|
info!("Changed mode for {} to {:?}", path.display(), pex);
|
||||||
HostErrorType::FileNotAccessible,
|
Ok(())
|
||||||
Some(err),
|
}
|
||||||
path.as_path(),
|
Err(err) => {
|
||||||
)),
|
error!("Could not change mode for file {}: {}", path.display(), err);
|
||||||
|
Err(HostError::new(
|
||||||
|
HostErrorType::FileNotAccessible,
|
||||||
|
Some(err),
|
||||||
|
path.as_path(),
|
||||||
|
))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(err) => Err(HostError::new(
|
Err(err) => {
|
||||||
HostErrorType::FileNotAccessible,
|
error!(
|
||||||
Some(err),
|
"Chmod failed; could not read metadata for file {}: {}",
|
||||||
path.as_path(),
|
path.display(),
|
||||||
)),
|
err
|
||||||
|
);
|
||||||
|
Err(HostError::new(
|
||||||
|
HostErrorType::FileNotAccessible,
|
||||||
|
Some(err),
|
||||||
|
path.as_path(),
|
||||||
|
))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -569,7 +648,9 @@ impl Localhost {
|
|||||||
/// Open file for read
|
/// Open file for read
|
||||||
pub fn open_file_read(&self, file: &Path) -> Result<File, HostError> {
|
pub fn open_file_read(&self, file: &Path) -> Result<File, HostError> {
|
||||||
let file: PathBuf = self.to_abs_path(file);
|
let file: PathBuf = self.to_abs_path(file);
|
||||||
|
info!("Opening file {} for read", file.display());
|
||||||
if !self.file_exists(file.as_path()) {
|
if !self.file_exists(file.as_path()) {
|
||||||
|
error!("File doesn't exist!");
|
||||||
return Err(HostError::new(
|
return Err(HostError::new(
|
||||||
HostErrorType::NoSuchFileOrDirectory,
|
HostErrorType::NoSuchFileOrDirectory,
|
||||||
None,
|
None,
|
||||||
@@ -583,11 +664,14 @@ impl Localhost {
|
|||||||
.open(file.as_path())
|
.open(file.as_path())
|
||||||
{
|
{
|
||||||
Ok(f) => Ok(f),
|
Ok(f) => Ok(f),
|
||||||
Err(err) => Err(HostError::new(
|
Err(err) => {
|
||||||
HostErrorType::FileNotAccessible,
|
error!("Could not open file for read: {}", err);
|
||||||
Some(err),
|
Err(HostError::new(
|
||||||
file.as_path(),
|
HostErrorType::FileNotAccessible,
|
||||||
)),
|
Some(err),
|
||||||
|
file.as_path(),
|
||||||
|
))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -596,6 +680,7 @@ impl Localhost {
|
|||||||
/// Open file for write
|
/// Open file for write
|
||||||
pub fn open_file_write(&self, file: &Path) -> Result<File, HostError> {
|
pub fn open_file_write(&self, file: &Path) -> Result<File, HostError> {
|
||||||
let file: PathBuf = self.to_abs_path(file);
|
let file: PathBuf = self.to_abs_path(file);
|
||||||
|
info!("Opening file {} for write", file.display());
|
||||||
match OpenOptions::new()
|
match OpenOptions::new()
|
||||||
.create(true)
|
.create(true)
|
||||||
.write(true)
|
.write(true)
|
||||||
@@ -603,18 +688,21 @@ impl Localhost {
|
|||||||
.open(file.as_path())
|
.open(file.as_path())
|
||||||
{
|
{
|
||||||
Ok(f) => Ok(f),
|
Ok(f) => Ok(f),
|
||||||
Err(err) => match self.file_exists(file.as_path()) {
|
Err(err) => {
|
||||||
true => Err(HostError::new(
|
error!("Failed to open file: {}", err);
|
||||||
HostErrorType::ReadonlyFile,
|
match self.file_exists(file.as_path()) {
|
||||||
Some(err),
|
true => Err(HostError::new(
|
||||||
file.as_path(),
|
HostErrorType::ReadonlyFile,
|
||||||
)),
|
Some(err),
|
||||||
false => Err(HostError::new(
|
file.as_path(),
|
||||||
HostErrorType::FileNotAccessible,
|
)),
|
||||||
Some(err),
|
false => Err(HostError::new(
|
||||||
file.as_path(),
|
HostErrorType::FileNotAccessible,
|
||||||
)),
|
Some(err),
|
||||||
},
|
file.as_path(),
|
||||||
|
)),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -629,13 +717,15 @@ impl Localhost {
|
|||||||
///
|
///
|
||||||
/// Get content of the current directory as a list of fs entry
|
/// Get content of the current directory as a list of fs entry
|
||||||
pub fn scan_dir(&self, dir: &Path) -> Result<Vec<FsEntry>, HostError> {
|
pub fn scan_dir(&self, dir: &Path) -> Result<Vec<FsEntry>, HostError> {
|
||||||
|
info!("Reading directory {}", dir.display());
|
||||||
match std::fs::read_dir(dir) {
|
match std::fs::read_dir(dir) {
|
||||||
Ok(e) => {
|
Ok(e) => {
|
||||||
let mut fs_entries: Vec<FsEntry> = Vec::new();
|
let mut fs_entries: Vec<FsEntry> = Vec::new();
|
||||||
for entry in e.flatten() {
|
for entry in e.flatten() {
|
||||||
// NOTE: 0.4.1, don't fail if stat for one file fails
|
// NOTE: 0.4.1, don't fail if stat for one file fails
|
||||||
if let Ok(entry) = self.stat(entry.path().as_path()) {
|
match self.stat(entry.path().as_path()) {
|
||||||
fs_entries.push(entry);
|
Ok(entry) => fs_entries.push(entry),
|
||||||
|
Err(e) => error!("Failed to stat {}: {}", entry.path().display(), e),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(fs_entries)
|
Ok(fs_entries)
|
||||||
|
|||||||
@@ -68,9 +68,11 @@ impl BookmarksClient {
|
|||||||
) -> Result<BookmarksClient, SerializerError> {
|
) -> Result<BookmarksClient, SerializerError> {
|
||||||
// Create default hosts
|
// Create default hosts
|
||||||
let default_hosts: UserHosts = Default::default();
|
let default_hosts: UserHosts = Default::default();
|
||||||
|
debug!("Setting up bookmarks client...");
|
||||||
// Make a key storage (windows / macos)
|
// Make a key storage (windows / macos)
|
||||||
#[cfg(any(target_os = "windows", target_os = "macos"))]
|
#[cfg(any(target_os = "windows", target_os = "macos"))]
|
||||||
let (key_storage, service_id): (Box<dyn KeyStorage>, &str) = {
|
let (key_storage, service_id): (Box<dyn KeyStorage>, &str) = {
|
||||||
|
debug!("Setting up KeyStorage");
|
||||||
let username: String = whoami::username();
|
let username: String = whoami::username();
|
||||||
let storage: KeyringStorage = KeyringStorage::new(username.as_str());
|
let storage: KeyringStorage = KeyringStorage::new(username.as_str());
|
||||||
// Check if keyring storage is supported
|
// Check if keyring storage is supported
|
||||||
@@ -79,8 +81,14 @@ impl BookmarksClient {
|
|||||||
#[cfg(test)] // NOTE: when running test, add -test
|
#[cfg(test)] // NOTE: when running test, add -test
|
||||||
let app_name: &str = "termscp-test";
|
let app_name: &str = "termscp-test";
|
||||||
match storage.is_supported() {
|
match storage.is_supported() {
|
||||||
true => (Box::new(storage), app_name),
|
true => {
|
||||||
false => (Box::new(FileStorage::new(storage_path)), "bookmarks"),
|
debug!("Using KeyringStorage");
|
||||||
|
(Box::new(storage), app_name)
|
||||||
|
}
|
||||||
|
false => {
|
||||||
|
warn!("KeyringStorage is not supported; using FileStorage");
|
||||||
|
(Box::new(FileStorage::new(storage_path)), "bookmarks")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
// Make a key storage (linux / unix)
|
// Make a key storage (linux / unix)
|
||||||
@@ -90,16 +98,22 @@ impl BookmarksClient {
|
|||||||
let app_name: &str = "bookmarks";
|
let app_name: &str = "bookmarks";
|
||||||
#[cfg(test)] // NOTE: when running test, add -test
|
#[cfg(test)] // NOTE: when running test, add -test
|
||||||
let app_name: &str = "bookmarks-test";
|
let app_name: &str = "bookmarks-test";
|
||||||
|
debug!("Using FileStorage");
|
||||||
(Box::new(FileStorage::new(storage_path)), app_name)
|
(Box::new(FileStorage::new(storage_path)), app_name)
|
||||||
};
|
};
|
||||||
// Load key
|
// Load key
|
||||||
let key: String = match key_storage.get_key(service_id) {
|
let key: String = match key_storage.get_key(service_id) {
|
||||||
Ok(k) => k,
|
Ok(k) => {
|
||||||
|
debug!("Key loaded with success");
|
||||||
|
k
|
||||||
|
}
|
||||||
Err(e) => match e {
|
Err(e) => match e {
|
||||||
KeyStorageError::NoSuchKey => {
|
KeyStorageError::NoSuchKey => {
|
||||||
// If no such key, generate key and set it into the storage
|
// If no such key, generate key and set it into the storage
|
||||||
let key: String = Self::generate_key();
|
let key: String = Self::generate_key();
|
||||||
|
debug!("Key doesn't exist yet or could not be loaded; generated a new key");
|
||||||
if let Err(e) = key_storage.set_key(service_id, key.as_str()) {
|
if let Err(e) = key_storage.set_key(service_id, key.as_str()) {
|
||||||
|
error!("Failed to set new key into storage: {}", e);
|
||||||
return Err(SerializerError::new_ex(
|
return Err(SerializerError::new_ex(
|
||||||
SerializerErrorKind::IoError,
|
SerializerErrorKind::IoError,
|
||||||
format!("Could not write key to storage: {}", e),
|
format!("Could not write key to storage: {}", e),
|
||||||
@@ -109,10 +123,11 @@ impl BookmarksClient {
|
|||||||
key
|
key
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
|
error!("Failed to get key from storage: {}", e);
|
||||||
return Err(SerializerError::new_ex(
|
return Err(SerializerError::new_ex(
|
||||||
SerializerErrorKind::IoError,
|
SerializerErrorKind::IoError,
|
||||||
format!("Could not get key from storage: {}", e),
|
format!("Could not get key from storage: {}", e),
|
||||||
))
|
));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@@ -124,15 +139,19 @@ impl BookmarksClient {
|
|||||||
};
|
};
|
||||||
// If bookmark file doesn't exist, initialize it
|
// If bookmark file doesn't exist, initialize it
|
||||||
if !bookmarks_file.exists() {
|
if !bookmarks_file.exists() {
|
||||||
|
info!("Bookmarks file doesn't exist yet; creating it...");
|
||||||
if let Err(err) = client.write_bookmarks() {
|
if let Err(err) = client.write_bookmarks() {
|
||||||
|
error!("Failed to create bookmarks file: {}", err);
|
||||||
return Err(err);
|
return Err(err);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Load bookmarks from file
|
// Load bookmarks from file
|
||||||
if let Err(err) = client.read_bookmarks() {
|
if let Err(err) = client.read_bookmarks() {
|
||||||
|
error!("Failed to load bookmarks: {}", err);
|
||||||
return Err(err);
|
return Err(err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
info!("Bookmarks client initialized");
|
||||||
// Load key
|
// Load key
|
||||||
Ok(client)
|
Ok(client)
|
||||||
}
|
}
|
||||||
@@ -152,19 +171,29 @@ impl BookmarksClient {
|
|||||||
key: &str,
|
key: &str,
|
||||||
) -> Option<(String, u16, FileTransferProtocol, String, Option<String>)> {
|
) -> Option<(String, u16, FileTransferProtocol, String, Option<String>)> {
|
||||||
let entry: &Bookmark = self.hosts.bookmarks.get(key)?;
|
let entry: &Bookmark = self.hosts.bookmarks.get(key)?;
|
||||||
|
debug!("Getting bookmark {}", key);
|
||||||
Some((
|
Some((
|
||||||
entry.address.clone(),
|
entry.address.clone(),
|
||||||
entry.port,
|
entry.port,
|
||||||
match FileTransferProtocol::from_str(entry.protocol.as_str()) {
|
match FileTransferProtocol::from_str(entry.protocol.as_str()) {
|
||||||
Ok(proto) => proto,
|
Ok(proto) => proto,
|
||||||
Err(_) => FileTransferProtocol::Sftp, // Default
|
Err(err) => {
|
||||||
|
error!(
|
||||||
|
"Found invalid protocol in bookmarks: {}; defaulting to SFTP",
|
||||||
|
err
|
||||||
|
);
|
||||||
|
FileTransferProtocol::Sftp // Default
|
||||||
|
}
|
||||||
},
|
},
|
||||||
entry.username.clone(),
|
entry.username.clone(),
|
||||||
match &entry.password {
|
match &entry.password {
|
||||||
// Decrypted password if Some; if decryption fails return None
|
// Decrypted password if Some; if decryption fails return None
|
||||||
Some(pwd) => match self.decrypt_str(pwd.as_str()) {
|
Some(pwd) => match self.decrypt_str(pwd.as_str()) {
|
||||||
Ok(decrypted_pwd) => Some(decrypted_pwd),
|
Ok(decrypted_pwd) => Some(decrypted_pwd),
|
||||||
Err(_) => None,
|
Err(err) => {
|
||||||
|
error!("Failed to decrypt password for bookmark: {}", err);
|
||||||
|
None
|
||||||
|
}
|
||||||
},
|
},
|
||||||
None => None,
|
None => None,
|
||||||
},
|
},
|
||||||
@@ -184,9 +213,11 @@ impl BookmarksClient {
|
|||||||
password: Option<String>,
|
password: Option<String>,
|
||||||
) {
|
) {
|
||||||
if name.is_empty() {
|
if name.is_empty() {
|
||||||
|
error!("Fatal error; bookmark name is empty");
|
||||||
panic!("Bookmark name can't be empty");
|
panic!("Bookmark name can't be empty");
|
||||||
}
|
}
|
||||||
// Make bookmark
|
// Make bookmark
|
||||||
|
info!("Added bookmark {} with address {}", name, addr);
|
||||||
let host: Bookmark = self.make_bookmark(addr, port, protocol, username, password);
|
let host: Bookmark = self.make_bookmark(addr, port, protocol, username, password);
|
||||||
self.hosts.bookmarks.insert(name, host);
|
self.hosts.bookmarks.insert(name, host);
|
||||||
}
|
}
|
||||||
@@ -196,6 +227,7 @@ impl BookmarksClient {
|
|||||||
/// Delete entry from bookmarks
|
/// Delete entry from bookmarks
|
||||||
pub fn del_bookmark(&mut self, name: &str) {
|
pub fn del_bookmark(&mut self, name: &str) {
|
||||||
let _ = self.hosts.bookmarks.remove(name);
|
let _ = self.hosts.bookmarks.remove(name);
|
||||||
|
info!("Removed bookmark {}", name);
|
||||||
}
|
}
|
||||||
/// ### iter_recents
|
/// ### iter_recents
|
||||||
///
|
///
|
||||||
@@ -209,13 +241,20 @@ impl BookmarksClient {
|
|||||||
/// Get recent associated to key
|
/// Get recent associated to key
|
||||||
pub fn get_recent(&self, key: &str) -> Option<(String, u16, FileTransferProtocol, String)> {
|
pub fn get_recent(&self, key: &str) -> Option<(String, u16, FileTransferProtocol, String)> {
|
||||||
// NOTE: password is not decrypted; recents will never have password
|
// NOTE: password is not decrypted; recents will never have password
|
||||||
|
info!("Getting bookmark {}", key);
|
||||||
let entry: &Bookmark = self.hosts.recents.get(key)?;
|
let entry: &Bookmark = self.hosts.recents.get(key)?;
|
||||||
Some((
|
Some((
|
||||||
entry.address.clone(),
|
entry.address.clone(),
|
||||||
entry.port,
|
entry.port,
|
||||||
match FileTransferProtocol::from_str(entry.protocol.as_str()) {
|
match FileTransferProtocol::from_str(entry.protocol.as_str()) {
|
||||||
Ok(proto) => proto,
|
Ok(proto) => proto,
|
||||||
Err(_) => FileTransferProtocol::Sftp, // Default
|
Err(err) => {
|
||||||
|
error!(
|
||||||
|
"Found invalid protocol in bookmarks: {}; defaulting to SFTP",
|
||||||
|
err
|
||||||
|
);
|
||||||
|
FileTransferProtocol::Sftp // Default
|
||||||
|
}
|
||||||
},
|
},
|
||||||
entry.username.clone(),
|
entry.username.clone(),
|
||||||
))
|
))
|
||||||
@@ -236,6 +275,7 @@ impl BookmarksClient {
|
|||||||
// Check if duplicated
|
// Check if duplicated
|
||||||
for recent_host in self.hosts.recents.values() {
|
for recent_host in self.hosts.recents.values() {
|
||||||
if *recent_host == host {
|
if *recent_host == host {
|
||||||
|
debug!("Discarding recent since duplicated ({})", host.address);
|
||||||
// Don't save duplicates
|
// Don't save duplicates
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -252,6 +292,7 @@ impl BookmarksClient {
|
|||||||
// Delete keys starting from the last one
|
// Delete keys starting from the last one
|
||||||
for key in keys.iter() {
|
for key in keys.iter() {
|
||||||
let _ = self.hosts.recents.remove(key);
|
let _ = self.hosts.recents.remove(key);
|
||||||
|
debug!("Removed recent bookmark {}", key);
|
||||||
// If length is < self.recents_size; break
|
// If length is < self.recents_size; break
|
||||||
if self.hosts.recents.len() < self.recents_size {
|
if self.hosts.recents.len() < self.recents_size {
|
||||||
break;
|
break;
|
||||||
@@ -259,6 +300,7 @@ impl BookmarksClient {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
let name: String = fmt_time(SystemTime::now(), "ISO%Y%m%dT%H%M%S");
|
let name: String = fmt_time(SystemTime::now(), "ISO%Y%m%dT%H%M%S");
|
||||||
|
info!("Saved recent host {} ({})", name, host.address);
|
||||||
self.hosts.recents.insert(name, host);
|
self.hosts.recents.insert(name, host);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -267,6 +309,7 @@ impl BookmarksClient {
|
|||||||
/// Delete entry from recents
|
/// Delete entry from recents
|
||||||
pub fn del_recent(&mut self, name: &str) {
|
pub fn del_recent(&mut self, name: &str) {
|
||||||
let _ = self.hosts.recents.remove(name);
|
let _ = self.hosts.recents.remove(name);
|
||||||
|
info!("Removed recent host {}", name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ### write_bookmarks
|
/// ### write_bookmarks
|
||||||
@@ -274,6 +317,7 @@ impl BookmarksClient {
|
|||||||
/// Write bookmarks to file
|
/// Write bookmarks to file
|
||||||
pub fn write_bookmarks(&self) -> Result<(), SerializerError> {
|
pub fn write_bookmarks(&self) -> Result<(), SerializerError> {
|
||||||
// Open file
|
// Open file
|
||||||
|
debug!("Writing bookmarks");
|
||||||
match OpenOptions::new()
|
match OpenOptions::new()
|
||||||
.create(true)
|
.create(true)
|
||||||
.write(true)
|
.write(true)
|
||||||
@@ -284,10 +328,13 @@ impl BookmarksClient {
|
|||||||
let serializer: BookmarkSerializer = BookmarkSerializer {};
|
let serializer: BookmarkSerializer = BookmarkSerializer {};
|
||||||
serializer.serialize(Box::new(writer), &self.hosts)
|
serializer.serialize(Box::new(writer), &self.hosts)
|
||||||
}
|
}
|
||||||
Err(err) => Err(SerializerError::new_ex(
|
Err(err) => {
|
||||||
SerializerErrorKind::IoError,
|
error!("Failed to write bookmarks: {}", err);
|
||||||
err.to_string(),
|
Err(SerializerError::new_ex(
|
||||||
)),
|
SerializerErrorKind::IoError,
|
||||||
|
err.to_string(),
|
||||||
|
))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -296,6 +343,7 @@ impl BookmarksClient {
|
|||||||
/// Read bookmarks from file
|
/// Read bookmarks from file
|
||||||
fn read_bookmarks(&mut self) -> Result<(), SerializerError> {
|
fn read_bookmarks(&mut self) -> Result<(), SerializerError> {
|
||||||
// Open bookmarks file for read
|
// Open bookmarks file for read
|
||||||
|
debug!("Reading bookmarks");
|
||||||
match OpenOptions::new()
|
match OpenOptions::new()
|
||||||
.read(true)
|
.read(true)
|
||||||
.open(self.bookmarks_file.as_path())
|
.open(self.bookmarks_file.as_path())
|
||||||
@@ -311,10 +359,13 @@ impl BookmarksClient {
|
|||||||
Err(err) => Err(err),
|
Err(err) => Err(err),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(err) => Err(SerializerError::new_ex(
|
Err(err) => {
|
||||||
SerializerErrorKind::IoError,
|
error!("Failed to read bookmarks: {}", err);
|
||||||
err.to_string(),
|
Err(SerializerError::new_ex(
|
||||||
)),
|
SerializerErrorKind::IoError,
|
||||||
|
err.to_string(),
|
||||||
|
))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -58,6 +58,11 @@ impl ConfigClient {
|
|||||||
pub fn new(config_path: &Path, ssh_key_dir: &Path) -> Result<ConfigClient, SerializerError> {
|
pub fn new(config_path: &Path, ssh_key_dir: &Path) -> Result<ConfigClient, SerializerError> {
|
||||||
// Initialize a default configuration
|
// Initialize a default configuration
|
||||||
let default_config: UserConfig = UserConfig::default();
|
let default_config: UserConfig = UserConfig::default();
|
||||||
|
info!(
|
||||||
|
"Setting up config client with config path {} and SSH key directory {}",
|
||||||
|
config_path.display(),
|
||||||
|
ssh_key_dir.display()
|
||||||
|
);
|
||||||
// Create client
|
// Create client
|
||||||
let mut client: ConfigClient = ConfigClient {
|
let mut client: ConfigClient = ConfigClient {
|
||||||
config: default_config,
|
config: default_config,
|
||||||
@@ -67,6 +72,7 @@ impl ConfigClient {
|
|||||||
// If ssh key directory doesn't exist, create it
|
// If ssh key directory doesn't exist, create it
|
||||||
if !ssh_key_dir.exists() {
|
if !ssh_key_dir.exists() {
|
||||||
if let Err(err) = create_dir(ssh_key_dir) {
|
if let Err(err) = create_dir(ssh_key_dir) {
|
||||||
|
error!("Failed to create SSH key dir: {}", err);
|
||||||
return Err(SerializerError::new_ex(
|
return Err(SerializerError::new_ex(
|
||||||
SerializerErrorKind::IoError,
|
SerializerErrorKind::IoError,
|
||||||
format!(
|
format!(
|
||||||
@@ -76,17 +82,22 @@ impl ConfigClient {
|
|||||||
),
|
),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
debug!("Created SSH key directory");
|
||||||
}
|
}
|
||||||
// If Config file doesn't exist, create it
|
// If Config file doesn't exist, create it
|
||||||
if !config_path.exists() {
|
if !config_path.exists() {
|
||||||
if let Err(err) = client.write_config() {
|
if let Err(err) = client.write_config() {
|
||||||
|
error!("Couldn't create configuration file: {}", err);
|
||||||
return Err(err);
|
return Err(err);
|
||||||
}
|
}
|
||||||
|
debug!("Config file didn't exist; created file");
|
||||||
} else {
|
} else {
|
||||||
// otherwise Load configuration from file
|
// otherwise Load configuration from file
|
||||||
if let Err(err) = client.read_config() {
|
if let Err(err) = client.read_config() {
|
||||||
|
error!("Couldn't read configuration file: {}", err);
|
||||||
return Err(err);
|
return Err(err);
|
||||||
}
|
}
|
||||||
|
debug!("Read configuration file");
|
||||||
}
|
}
|
||||||
Ok(client)
|
Ok(client)
|
||||||
}
|
}
|
||||||
@@ -230,12 +241,18 @@ impl ConfigClient {
|
|||||||
p.push(format!("{}.key", host_name));
|
p.push(format!("{}.key", host_name));
|
||||||
p
|
p
|
||||||
};
|
};
|
||||||
|
info!(
|
||||||
|
"Writing SSH file to {} for host {}",
|
||||||
|
ssh_key_path.display(),
|
||||||
|
host_name
|
||||||
|
);
|
||||||
// Write key to file
|
// Write key to file
|
||||||
let mut f: File = match File::create(ssh_key_path.as_path()) {
|
let mut f: File = match File::create(ssh_key_path.as_path()) {
|
||||||
Ok(f) => f,
|
Ok(f) => f,
|
||||||
Err(err) => return Self::make_io_err(err),
|
Err(err) => return Self::make_io_err(err),
|
||||||
};
|
};
|
||||||
if let Err(err) = f.write_all(ssh_key.as_bytes()) {
|
if let Err(err) = f.write_all(ssh_key.as_bytes()) {
|
||||||
|
error!("Failed to write SSH key to file: {}", err);
|
||||||
return Self::make_io_err(err);
|
return Self::make_io_err(err);
|
||||||
}
|
}
|
||||||
// Add host to keys
|
// Add host to keys
|
||||||
@@ -251,6 +268,7 @@ impl ConfigClient {
|
|||||||
/// and also commits changes to configuration, to prevent incoerent data
|
/// and also commits changes to configuration, to prevent incoerent data
|
||||||
pub fn del_ssh_key(&mut self, host: &str, username: &str) -> Result<(), SerializerError> {
|
pub fn del_ssh_key(&mut self, host: &str, username: &str) -> Result<(), SerializerError> {
|
||||||
// Remove key from configuration and get key path
|
// Remove key from configuration and get key path
|
||||||
|
info!("Removing key for {}@{}", host, username);
|
||||||
let key_path: PathBuf = match self
|
let key_path: PathBuf = match self
|
||||||
.config
|
.config
|
||||||
.remote
|
.remote
|
||||||
@@ -262,6 +280,7 @@ impl ConfigClient {
|
|||||||
};
|
};
|
||||||
// Remove file
|
// Remove file
|
||||||
if let Err(err) = remove_file(key_path.as_path()) {
|
if let Err(err) = remove_file(key_path.as_path()) {
|
||||||
|
error!("Failed to remove key file {}: {}", key_path.display(), err);
|
||||||
return Self::make_io_err(err);
|
return Self::make_io_err(err);
|
||||||
}
|
}
|
||||||
// Commit changes to configuration
|
// Commit changes to configuration
|
||||||
@@ -310,10 +329,13 @@ impl ConfigClient {
|
|||||||
let serializer: ConfigSerializer = ConfigSerializer {};
|
let serializer: ConfigSerializer = ConfigSerializer {};
|
||||||
serializer.serialize(Box::new(writer), &self.config)
|
serializer.serialize(Box::new(writer), &self.config)
|
||||||
}
|
}
|
||||||
Err(err) => Err(SerializerError::new_ex(
|
Err(err) => {
|
||||||
SerializerErrorKind::IoError,
|
error!("Failed to write configuration file: {}", err);
|
||||||
err.to_string(),
|
Err(SerializerError::new_ex(
|
||||||
)),
|
SerializerErrorKind::IoError,
|
||||||
|
err.to_string(),
|
||||||
|
))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -337,10 +359,13 @@ impl ConfigClient {
|
|||||||
Err(err) => Err(err),
|
Err(err) => Err(err),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(err) => Err(SerializerError::new_ex(
|
Err(err) => {
|
||||||
SerializerErrorKind::IoError,
|
error!("Failed to read configuration: {}", err);
|
||||||
err.to_string(),
|
Err(SerializerError::new_ex(
|
||||||
)),
|
SerializerErrorKind::IoError,
|
||||||
|
err.to_string(),
|
||||||
|
))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ impl SshKeyStorage {
|
|||||||
pub fn storage_from_config(cfg_client: &ConfigClient) -> Self {
|
pub fn storage_from_config(cfg_client: &ConfigClient) -> Self {
|
||||||
let mut hosts: HashMap<String, PathBuf> =
|
let mut hosts: HashMap<String, PathBuf> =
|
||||||
HashMap::with_capacity(cfg_client.iter_ssh_keys().count());
|
HashMap::with_capacity(cfg_client.iter_ssh_keys().count());
|
||||||
|
debug!("Setting up SSH key storage");
|
||||||
// Iterate over keys
|
// Iterate over keys
|
||||||
for key in cfg_client.iter_ssh_keys() {
|
for key in cfg_client.iter_ssh_keys() {
|
||||||
match cfg_client.get_ssh_key(key) {
|
match cfg_client.get_ssh_key(key) {
|
||||||
@@ -52,8 +53,12 @@ impl SshKeyStorage {
|
|||||||
}
|
}
|
||||||
None => continue,
|
None => continue,
|
||||||
},
|
},
|
||||||
Err(_) => continue,
|
Err(err) => {
|
||||||
|
error!("Failed to get SSH key for {}: {}", key, err);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
info!("Got SSH key for {}", key);
|
||||||
}
|
}
|
||||||
// Return storage
|
// Return storage
|
||||||
SshKeyStorage { hosts }
|
SshKeyStorage { hosts }
|
||||||
|
|||||||
Reference in New Issue
Block a user