use crate::{BlockResult, BlockUtilsError};
use serde::{Deserialize, Serialize};
use std::path::Path;
use std::process::Command;
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "PascalCase")]
pub struct NvmeDevice {
pub name_space: u64,
pub device_path: String,
pub index: Option<u64>,
pub model_number: String,
pub product_name: Option<String>,
pub firmware: Option<String>,
pub serial_number: String,
pub used_bytes: u64,
#[serde(rename = "MaximumLBA")]
pub maximum_lba: u64,
pub physical_size: u64,
pub sector_size: u32,
}
#[derive(Deserialize)]
#[serde(rename_all = "PascalCase")]
struct NvmeDeviceContainer {
devices: Vec<NvmeDevice>,
}
pub fn get_error_log(dev: &Path) -> BlockResult<serde_json::Value> {
let out = Command::new("nvme")
.args(&["error-log", &dev.to_string_lossy(), "-o", "json"])
.output()?;
if !out.status.success() {
return Err(BlockUtilsError::new(
String::from_utf8_lossy(&out.stderr).into_owned(),
));
}
let stdout = String::from_utf8_lossy(&out.stdout);
let deserialized: serde_json::Value = serde_json::from_str(&stdout)?;
Ok(deserialized)
}
pub fn get_firmware_log(dev: &Path) -> BlockResult<serde_json::Value> {
let out = Command::new("nvme")
.args(&["fw-log", &dev.to_string_lossy(), "-o", "json"])
.output()?;
if !out.status.success() {
return Err(BlockUtilsError::new(
String::from_utf8_lossy(&out.stderr).into_owned(),
));
}
let stdout = String::from_utf8_lossy(&out.stdout);
let deserialized: serde_json::Value = serde_json::from_str(&stdout)?;
Ok(deserialized)
}
pub fn get_smart_log(dev: &Path) -> BlockResult<serde_json::Value> {
let out = Command::new("nvme")
.args(&["smart-log", &dev.to_string_lossy(), "-o", "json"])
.output()?;
if !out.status.success() {
return Err(BlockUtilsError::new(
String::from_utf8_lossy(&out.stderr).into_owned(),
));
}
let stdout = String::from_utf8_lossy(&out.stdout);
let deserialized: serde_json::Value = serde_json::from_str(&stdout)?;
Ok(deserialized)
}
pub fn get_log(dev: &Path, id: u8, len: u16) -> BlockResult<Vec<u8>> {
let out = Command::new("nvme")
.args(&[
"get-log",
&dev.to_string_lossy(),
"-i",
id.to_string().as_str(),
"-l",
len.to_string().as_str(),
"-b",
])
.output()?;
if !out.status.success() {
return Err(BlockUtilsError::new(
String::from_utf8_lossy(&out.stderr).into_owned(),
));
}
let stdout: Vec<u8> = out.stdout;
Ok(stdout)
}
pub fn format(dev: &Path) -> BlockResult<()> {
let out = Command::new("nvme")
.args(&["format", &dev.to_string_lossy()])
.output()?;
if !out.status.success() {
return Err(BlockUtilsError::new(
String::from_utf8_lossy(&out.stderr).into_owned(),
));
}
Ok(())
}
pub fn list_nvme_namespaces(dev: &Path) -> BlockResult<Vec<String>> {
let out = Command::new("nvme")
.args(&["list-ns", &dev.to_string_lossy(), "-o", "json"])
.output()?;
if !out.status.success() {
return Err(BlockUtilsError::new(
String::from_utf8_lossy(&out.stderr).into_owned(),
));
}
let stdout = String::from_utf8_lossy(&out.stdout);
let deserialized: Vec<String> = serde_json::from_str(&stdout)?;
Ok(deserialized)
}
pub fn list_nvme_controllers() -> BlockResult<Vec<String>> {
let out = Command::new("nvme-list").args(&["-o", "json"]).output()?;
if !out.status.success() {
return Err(BlockUtilsError::new(
String::from_utf8_lossy(&out.stderr).into_owned(),
));
}
let stdout = String::from_utf8_lossy(&out.stdout);
let deserialized: Vec<String> = serde_json::from_str(&stdout)?;
Ok(deserialized)
}
pub fn list_nvme_devices() -> BlockResult<Vec<NvmeDevice>> {
let out = Command::new("nvme")
.args(&["list", "-o", "json"])
.output()?;
if !out.status.success() {
return Err(BlockUtilsError::new(
String::from_utf8_lossy(&out.stderr).into_owned(),
));
}
let stdout = String::from_utf8_lossy(&out.stdout);
let deserialized: NvmeDeviceContainer = serde_json::from_str(&stdout)?;
Ok(deserialized.devices)
}