use serde::{Deserialize, Serialize};
use serde_json::json;
use std::fs;
use std::io::{self, Read};
use std::path::Path;
use std::path::PathBuf;
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct DeviceInfo {
pub device_name: String,
pub vendor_name: String,
pub model_name: String,
pub removable: u8,
pub size: u64,
}
fn get_file_content(input_file: String) -> Result<String, Box<dyn std::error::Error>> {
let content = match fs::read_to_string(input_file.clone()) {
Ok(s) => s,
Err(e) => {
format!(
"error coccured while reading :{}: {}",
input_file.clone(),
e
);
"".to_string()
}
};
Ok(content)
}
pub fn is_removable_device(device_path: &str) -> io::Result<bool> {
let device_name = Path::new(device_path)
.file_name()
.ok_or_else(|| io::Error::new(io::ErrorKind::InvalidInput, "Invalid device path"))?
.to_str()
.ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, "Non UTF-8 device name"))?;
let removable_path = format!("/sys/block/{}/removable", device_name);
println!("removable_path: {}", removable_path);
let mut file = fs::File::open(removable_path)?;
let mut contents = String::new();
file.read_to_string(&mut contents)?;
Ok(contents.trim() == "1")
}
pub fn get_storage_devices() -> Result<Vec<String>, String> {
let paths = match fs::read_dir("/sys/block/") {
Ok(paths) => paths,
Err(e) => {
println!("could not get the subdirs of /sys/block/: {}", e);
return Err("".to_string());
}
};
let mut devices: Vec<String> = Vec::new();
for path in paths {
let p = match path {
Ok(p) => p,
Err(e) => {
println!("could not get the path: {}", e);
return Err("".to_string());
}
};
let mut dev = p.path().clone();
let device_end_name = match p.path().clone().file_name() {
Some(device) => match device.to_str() {
Some(dev) => dev.to_string(),
None => {
println!("could not get the device name");
"".to_string()
}
},
None => {
println!("could not get the device name ");
"".to_string()
}
};
dev.push("device");
if dev.exists() {
dev.push("vendor");
let vendor_name_file = match dev.clone().into_os_string().to_str() {
Some(name) => name.to_string(),
None => "".to_string(),
};
let mut dev_vendor_name = "".to_string();
if !vendor_name_file.is_empty() {
dev_vendor_name = match get_file_content(vendor_name_file) {
Ok(name) => name.replace('\n', ""),
Err(e) => {
println!("error occurred while reading vendor name: {}", e);
"".to_string()
}
};
}
dev.pop();
dev.push("model");
let model_name_file = match dev.clone().into_os_string().to_str() {
Some(name) => name.to_string(),
None => "".to_string(),
};
let model_name = match get_file_content(model_name_file) {
Ok(model) => model.replace('\n', ""),
Err(e) => {
println!("error occurred while reading model name: {}", e);
"".to_string()
}
};
dev.pop();
dev.pop();
dev.push("removable");
let mut removable = "".to_string();
if dev.exists() {
removable = match fs::read_to_string(dev.clone()) {
Ok(removable) => removable,
Err(e) => {
println!("error occurred while reading removable: {}", e);
"".to_string()
}
}
}
dev.pop();
dev.push("size");
let size: u64 = match fs::read_to_string(dev.clone()) {
Ok(size_str) => {
match size_str.trim().parse::<u64>() {
Ok(s) => s,
Err(e) => {
println!("error occurred while parsing size: {}", e);
0
}
}
}
Err(e) => {
println!("error occurred while reading size: {}", e);
0
}
};
if !device_end_name.is_empty() {
let mut dev_path = PathBuf::from("/dev/");
dev_path.push(device_end_name);
if dev_path.exists() {
if removable == "1\n" {
let dev_info = DeviceInfo {
device_name: dev_path.display().to_string(),
vendor_name: dev_vendor_name,
model_name,
removable: 1,
size,
};
let device_json = json!(dev_info).to_string();
devices.push(device_json);
} else if removable == "0\n" {
let dev_info = DeviceInfo {
device_name: dev_path.display().to_string(),
vendor_name: dev_vendor_name,
model_name,
removable: 0,
size,
};
let dev_json = json!(dev_info).to_string();
devices.push(dev_json);
}
}
}
}
}
println!("devices: {:?}", devices);
Ok(devices)
}