diff --git a/src/bin/sg-tape-cmd.rs b/src/bin/sg-tape-cmd.rs index 769b5c1b..c86ac6e6 100644 --- a/src/bin/sg-tape-cmd.rs +++ b/src/bin/sg-tape-cmd.rs @@ -8,7 +8,8 @@ use std::fs::File; use std::os::unix::io::{AsRawFd, FromRawFd}; -use anyhow::{bail, Error}; +use anyhow::{bail, format_err, Error}; +use serde_json::Value; use proxmox::{ api::{ @@ -19,8 +20,11 @@ use proxmox::{ }; use proxmox_backup::{ + config, api2::types::{ LINUX_DRIVE_PATH_SCHEMA, + DRIVE_NAME_SCHEMA, + LinuxTapeDrive, }, tape::{ TapeDriver, @@ -32,36 +36,78 @@ use proxmox_backup::{ }, }; -fn get_tape_handle(device: Option) -> Result { +fn get_tape_handle(param: &Value) -> Result { - let file = if let Some(device) = device { - open_linux_tape_device(&device)? - } else { + let handle = if let Some(name) = param["drive"].as_str() { + let (config, _digest) = config::drive::config()?; + let drive: LinuxTapeDrive = config.lookup("linux", &name)?; + eprintln!("using device {}", drive.path); + drive.open() + .map_err(|err| format_err!("open drive '{}' ({}) failed - {}", name, drive.path, err))? + } else if let Some(device) = param["device"].as_str() { + eprintln!("using device {}", device); + LinuxTapeHandle::new(open_linux_tape_device(&device)?) + } else if let Some(true) = param["stdin"].as_bool() { + eprintln!("using stdin"); let fd = std::io::stdin().as_raw_fd(); let file = unsafe { File::from_raw_fd(fd) }; check_tape_is_linux_tape_device(&file)?; - file + LinuxTapeHandle::new(file) + } else if let Some(name) = std::env::var("PROXMOX_TAPE_DRIVE").ok() { + let (config, _digest) = config::drive::config()?; + let drive: LinuxTapeDrive = config.lookup("linux", &name)?; + eprintln!("using device {}", drive.path); + drive.open() + .map_err(|err| format_err!("open drive '{}' ({}) failed - {}", name, drive.path, err))? + } else { + let (config, _digest) = config::drive::config()?; + + let mut drive_names = Vec::new(); + for (name, (section_type, _)) in config.sections.iter() { + if section_type != "linux" { continue; } + drive_names.push(name); + } + + if drive_names.len() == 1 { + let name = drive_names[0]; + let drive: LinuxTapeDrive = config.lookup("linux", &name)?; + eprintln!("using device {}", drive.path); + drive.open() + .map_err(|err| format_err!("open drive '{}' ({}) failed - {}", name, drive.path, err))? + } else { + bail!("no drive/device specified"); + } }; - Ok(LinuxTapeHandle::new(file)) + + Ok(handle) } #[api( input: { properties: { + drive: { + schema: DRIVE_NAME_SCHEMA, + optional: true, + }, device: { schema: LINUX_DRIVE_PATH_SCHEMA, optional: true, }, + stdin: { + description: "Use standard input as device handle.", + type: bool, + optional: true, + }, }, }, )] /// Tape/Media Status fn status( - device: Option, + param: Value, ) -> Result<(), Error> { let result = proxmox::try_block!({ - let mut handle = get_tape_handle(device)?; + let mut handle = get_tape_handle(¶m)?; handle.get_drive_and_media_status() }).map_err(|err: Error| err.to_string()); @@ -73,20 +119,29 @@ fn status( #[api( input: { properties: { + drive: { + schema: DRIVE_NAME_SCHEMA, + optional: true, + }, device: { schema: LINUX_DRIVE_PATH_SCHEMA, optional: true, }, + stdin: { + description: "Use standard input as device handle.", + type: bool, + optional: true, + }, }, }, )] /// Read Cartridge Memory (Medium auxiliary memory attributes) fn cartridge_memory( - device: Option, + param: Value, ) -> Result<(), Error> { let result = proxmox::try_block!({ - let mut handle = get_tape_handle(device)?; + let mut handle = get_tape_handle(¶m)?; handle.cartridge_memory() }).map_err(|err| err.to_string()); @@ -99,20 +154,29 @@ fn cartridge_memory( #[api( input: { properties: { + drive: { + schema: DRIVE_NAME_SCHEMA, + optional: true, + }, device: { schema: LINUX_DRIVE_PATH_SCHEMA, optional: true, }, + stdin: { + description: "Use standard input as device handle.", + type: bool, + optional: true, + }, }, }, )] /// Read Tape Alert Flags fn tape_alert_flags( - device: Option, + param: Value, ) -> Result<(), Error> { let result = proxmox::try_block!({ - let mut handle = get_tape_handle(device)?; + let mut handle = get_tape_handle(¶m)?; let flags = handle.tape_alert_flags()?; Ok(flags.bits()) @@ -126,20 +190,29 @@ fn tape_alert_flags( #[api( input: { properties: { + drive: { + schema: DRIVE_NAME_SCHEMA, + optional: true, + }, device: { schema: LINUX_DRIVE_PATH_SCHEMA, optional: true, }, + stdin: { + description: "Use standard input as device handle.", + type: bool, + optional: true, + }, }, }, )] /// Read volume statistics fn volume_statistics( - device: Option, + param: Value, ) -> Result<(), Error> { let result = proxmox::try_block!({ - let mut handle = get_tape_handle(device)?; + let mut handle = get_tape_handle(¶m)?; handle.volume_statistics() }).map_err(|err: Error| err.to_string()); diff --git a/src/tape/drive/linux_tape.rs b/src/tape/drive/linux_tape.rs index cef914bb..f0a5efc1 100644 --- a/src/tape/drive/linux_tape.rs +++ b/src/tape/drive/linux_tape.rs @@ -331,6 +331,7 @@ impl LinuxTapeHandle { let mut command = std::process::Command::new( "/usr/lib/x86_64-linux-gnu/proxmox-backup/sg-tape-cmd"); command.args(&["cartridge-memory"]); + command.args(&["--stdin"]); command.stdin(unsafe { std::process::Stdio::from_raw_fd(self.file.as_raw_fd())}); let output = run_command(command, None)?; let result: Result, String> = serde_json::from_str(&output)?; @@ -350,6 +351,7 @@ impl LinuxTapeHandle { let mut command = std::process::Command::new( "/usr/lib/x86_64-linux-gnu/proxmox-backup/sg-tape-cmd"); command.args(&["volume-statistics"]); + command.args(&["--stdin"]); command.stdin(unsafe { std::process::Stdio::from_raw_fd(self.file.as_raw_fd())}); let output = run_command(command, None)?; let result: Result = serde_json::from_str(&output)?; @@ -492,6 +494,7 @@ impl TapeDriver for LinuxTapeHandle { let mut command = std::process::Command::new( "/usr/lib/x86_64-linux-gnu/proxmox-backup/sg-tape-cmd"); command.args(&["tape-alert-flags"]); + command.args(&["--stdin"]); command.stdin(unsafe { std::process::Stdio::from_raw_fd(self.file.as_raw_fd())}); let output = run_command(command, None)?; let result: Result = serde_json::from_str(&output)?;