diff --git a/src/api2/tape/drive.rs b/src/api2/tape/drive.rs index 6ec8fc84..ee5f5c8a 100644 --- a/src/api2/tape/drive.rs +++ b/src/api2/tape/drive.rs @@ -51,7 +51,10 @@ use crate::{ open_drive, media_changer, update_changer_online_status, - mam_extract_media_usage, + linux_tape::{ + LinuxTapeHandle, + open_linux_tape_device, + }, file_formats::{ MediaLabel, MediaSetLabel, @@ -818,27 +821,13 @@ pub fn status(drive: String) -> Result { let drive_config: LinuxTapeDrive = config.lookup("linux", &drive)?; - let mut handle = drive_config.open() + // Note: use open_linux_tape_device, because this also works if no medium loaded + let file = open_linux_tape_device(&drive_config.path) .map_err(|err| format_err!("open drive '{}' ({}) failed - {}", drive, drive_config.path, err))?; - let drive_status = handle.get_drive_status()?; + let mut handle = LinuxTapeHandle::new(file); - let mam = handle.cartridge_memory()?; - - let usage = mam_extract_media_usage(&mam)?; - - let status = LinuxDriveAndMediaStatus { - blocksize: drive_status.blocksize, - density: drive_status.density, - status: format!("{:?}", drive_status.status), - file_number: drive_status.file_number, - block_number: drive_status.block_number, - manufactured: usage.manufactured, - bytes_read: usage.bytes_read, - bytes_written: usage.bytes_written, - }; - - Ok(status) + handle.get_drive_and_media_status() } #[sortable] diff --git a/src/api2/types/tape/drive.rs b/src/api2/types/tape/drive.rs index f599f08a..e42072e9 100644 --- a/src/api2/types/tape/drive.rs +++ b/src/api2/types/tape/drive.rs @@ -115,7 +115,7 @@ pub struct MamAttribute { } #[api()] -#[derive(Serialize,Deserialize,Debug)] +#[derive(Serialize,Deserialize,Copy,Clone,Debug)] pub enum TapeDensity { /// No tape loaded None, @@ -182,9 +182,12 @@ pub struct LinuxDriveAndMediaStatus { /// Current block number pub block_number: i32, /// Medium Manufacture Date (epoch) - pub manufactured: i64, + #[serde(skip_serializing_if="Option::is_none")] + pub manufactured: Option, /// Total Bytes Read in Medium Life - pub bytes_read: u64, + #[serde(skip_serializing_if="Option::is_none")] + pub bytes_read: Option, /// Total Bytes Written in Medium Life - pub bytes_written: u64, + #[serde(skip_serializing_if="Option::is_none")] + pub bytes_written: Option, } diff --git a/src/bin/sg-tape-cmd.rs b/src/bin/sg-tape-cmd.rs index d0fa04ed..5e1ff5dd 100644 --- a/src/bin/sg-tape-cmd.rs +++ b/src/bin/sg-tape-cmd.rs @@ -21,10 +21,8 @@ use proxmox::{ use proxmox_backup::{ api2::types::{ LINUX_DRIVE_PATH_SCHEMA, - LinuxDriveAndMediaStatus, }, tape::{ - mam_extract_media_usage, linux_tape::{ LinuxTapeHandle, open_linux_tape_device, @@ -63,24 +61,8 @@ fn status( let result = proxmox::try_block!({ let mut handle = get_tape_handle(device)?; - - let drive_status = handle.get_drive_status()?; - - let mam = handle.cartridge_memory()?; - - let usage = mam_extract_media_usage(&mam)?; - - Ok(LinuxDriveAndMediaStatus { - blocksize: drive_status.blocksize, - density: drive_status.density, - status: format!("{:?}", drive_status.status), - file_number: drive_status.file_number, - block_number: drive_status.block_number, - manufactured: usage.manufactured, - bytes_read: usage.bytes_read, - bytes_written: usage.bytes_written, - }) - }).map_err(|err: Error| err.to_string()); + handle.get_drive_and_media_status() + }).map_err(|err: Error| err.to_string()); println!("{}", serde_json::to_string_pretty(&result)?); diff --git a/src/tape/drive/linux_tape.rs b/src/tape/drive/linux_tape.rs index d3d35377..4b44ce2d 100644 --- a/src/tape/drive/linux_tape.rs +++ b/src/tape/drive/linux_tape.rs @@ -13,11 +13,13 @@ use crate::{ api2::types::{ TapeDensity, MamAttribute, + LinuxDriveAndMediaStatus, }, tape::{ TapeRead, TapeWrite, read_mam_attributes, + mam_extract_media_usage, drive::{ LinuxTapeDrive, TapeDriver, @@ -65,7 +67,7 @@ impl LinuxTapeDrive { let file = open_linux_tape_device(&self.path)?; - let handle = LinuxTapeHandle::new(file); + let mut handle = LinuxTapeHandle::new(file); let drive_status = handle.get_drive_status()?; println!("drive status: {:?}", drive_status); @@ -201,10 +203,40 @@ impl LinuxTapeHandle { Ok(()) } - /// Get Tape configuration with MTIOCGET ioctl - pub fn get_drive_status(&self) -> Result { + /// Get Tape and Media status + pub fn get_drive_and_media_status(&mut self) -> Result { - self.mtnop()?; + let drive_status = self.get_drive_status()?; + + let mut status = LinuxDriveAndMediaStatus { + blocksize: drive_status.blocksize, + density: drive_status.density, + status: format!("{:?}", drive_status.status), + file_number: drive_status.file_number, + block_number: drive_status.block_number, + manufactured: None, + bytes_read: None, + bytes_written: None, + }; + + if drive_status.tape_is_ready() { + + let mam = self.cartridge_memory()?; + + let usage = mam_extract_media_usage(&mam)?; + + status.manufactured = Some(usage.manufactured); + status.bytes_read = Some(usage.bytes_read); + status.bytes_written = Some(usage.bytes_written); + } + + Ok(status) + } + + /// Get Tape status/configuration with MTIOCGET ioctl + pub fn get_drive_status(&mut self) -> Result { + + let _ = self.mtnop(); // ignore errors (i.e. no tape loaded) let mut status = mtget::default();