diff --git a/src/bin/sg-tape-cmd.rs b/src/bin/sg-tape-cmd.rs index 7a16642d..769b5c1b 100644 --- a/src/bin/sg-tape-cmd.rs +++ b/src/bin/sg-tape-cmd.rs @@ -23,6 +23,7 @@ use proxmox_backup::{ LINUX_DRIVE_PATH_SCHEMA, }, tape::{ + TapeDriver, linux_tape::{ LinuxTapeHandle, open_linux_tape_device, diff --git a/src/tape/drive/linux_tape.rs b/src/tape/drive/linux_tape.rs index 28527ee5..0fb7e67a 100644 --- a/src/tape/drive/linux_tape.rs +++ b/src/tape/drive/linux_tape.rs @@ -317,27 +317,6 @@ impl LinuxTapeHandle { result.map_err(|err| format_err!("{}", err)) } - /// Read Tape Alert Flags - /// - /// Note: Only 'root' user may run RAW SG commands, so we need to - /// spawn setuid binary 'sg-tape-cmd'. - pub fn tape_alert_flags(&mut self) -> Result { - - if nix::unistd::Uid::effective().is_root() { - return read_tape_alert_flags(&mut self.file); - } - - let mut command = std::process::Command::new( - "/usr/lib/x86_64-linux-gnu/proxmox-backup/sg-tape-cmd"); - command.args(&["tape-alert-flags"]); - 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)?; - result - .map_err(|err| format_err!("{}", err)) - .map(|bits| TapeAlertFlags::from_bits_truncate(bits)) - } - /// Read Volume Statistics /// /// Note: Only 'root' user may run RAW SG commands, so we need to @@ -479,6 +458,27 @@ impl TapeDriver for LinuxTapeHandle { Ok(()) } + + /// Read Tape Alert Flags + /// + /// Note: Only 'root' user may run RAW SG commands, so we need to + /// spawn setuid binary 'sg-tape-cmd'. + fn tape_alert_flags(&mut self) -> Result { + + if nix::unistd::Uid::effective().is_root() { + return read_tape_alert_flags(&mut self.file); + } + + let mut command = std::process::Command::new( + "/usr/lib/x86_64-linux-gnu/proxmox-backup/sg-tape-cmd"); + command.args(&["tape-alert-flags"]); + 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)?; + result + .map_err(|err| format_err!("{}", err)) + .map(|bits| TapeAlertFlags::from_bits_truncate(bits)) + } } /// Write a single EOF mark without flushing buffers diff --git a/src/tape/drive/mod.rs b/src/tape/drive/mod.rs index db1a89a3..7f059313 100644 --- a/src/tape/drive/mod.rs +++ b/src/tape/drive/mod.rs @@ -151,6 +151,14 @@ pub trait TapeDriver { /// Eject media fn eject_media(&mut self) -> Result<(), Error>; + + /// Read Tape Alert Flags + /// + /// This make only sense for real LTO drives. Virtual tape drives should + /// simply return empty flags (default). + fn tape_alert_flags(&mut self) -> Result { + Ok(TapeAlertFlags::empty()) + } } /// Get the media changer (MediaChange + name) associated with a tape drive. diff --git a/src/tape/pool_writer.rs b/src/tape/pool_writer.rs index 88e2c2a3..13b6caf8 100644 --- a/src/tape/pool_writer.rs +++ b/src/tape/pool_writer.rs @@ -25,6 +25,7 @@ use crate::{ MediaSetCatalog, tape_write_snapshot_archive, request_and_load_media, + tape_alert_flags_critical, file_formats::MediaSetLabel, }, }; @@ -150,6 +151,15 @@ impl PoolWriter { let (mut drive, old_media_id) = request_and_load_media(worker, &drive_config, &self.drive_name, media.label())?; + // test for critical tape alert flags + let alert_flags = drive.tape_alert_flags()?; + if !alert_flags.is_empty() { + worker.log(format!("TapeAlertFlags: {:?}", alert_flags)); + if tape_alert_flags_critical(alert_flags) { + bail!("aborting due to critical tape alert flags: {:?}", alert_flags); + } + } + let catalog = update_media_set_label( worker, drive.as_mut(),