-/// Tape command implemented using scsi-generic raw commands
-///
-/// SCSI-generic command needs root priviledges, so this binary need
-/// to be setuid root.
+/// Helper to run tape commands as root. Currently only required
+/// to read and set the encryption key.
///
/// This command can use STDIN as tape device handle.
use anyhow::{bail, Error};
use serde_json::Value;
-use proxmox::{
- api::{
- api,
- cli::*,
- RpcEnvironment,
- },
+use proxmox_router::{cli::*, RpcEnvironment};
+use proxmox_schema::api;
+use proxmox_uuid::Uuid;
+
+use pbs_api_types::{
+ Fingerprint, LTO_DRIVE_PATH_SCHEMA, DRIVE_NAME_SCHEMA, TAPE_ENCRYPTION_KEY_FINGERPRINT_SCHEMA,
+ MEDIA_SET_UUID_SCHEMA, LtoTapeDrive,
};
+use pbs_tape::linux_list_drives::{open_lto_tape_device, check_tape_is_lto_tape_device};
+
use proxmox_backup::{
- config,
- backup::Fingerprint,
- api2::types::{
- LINUX_DRIVE_PATH_SCHEMA,
- DRIVE_NAME_SCHEMA,
- TAPE_ENCRYPTION_KEY_FINGERPRINT_SCHEMA,
- LinuxTapeDrive,
- },
tape::{
- TapeDriver,
- linux_tape::{
- LinuxTapeHandle,
- open_linux_tape_device,
- check_tape_is_linux_tape_device,
+ drive::{
+ TapeDriver,
+ LtoTapeHandle,
+ open_lto_tape_drive,
},
},
};
-fn get_tape_handle(param: &Value) -> Result<LinuxTapeHandle, Error> {
+fn get_tape_handle(param: &Value) -> Result<LtoTapeHandle, Error> {
let handle = if let Some(name) = param["drive"].as_str() {
- let (config, _digest) = config::drive::config()?;
- let drive: LinuxTapeDrive = config.lookup("linux", &name)?;
+ let (config, _digest) = pbs_config::drive::config()?;
+ let drive: LtoTapeDrive = config.lookup("lto", name)?;
eprintln!("using device {}", drive.path);
- drive.open()?
+ open_lto_tape_drive(&drive)?
} else if let Some(device) = param["device"].as_str() {
eprintln!("using device {}", device);
- LinuxTapeHandle::new(open_linux_tape_device(&device)?)
+ LtoTapeHandle::new(open_lto_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)?;
- 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)?;
+ check_tape_is_lto_tape_device(&file)?;
+ LtoTapeHandle::new(file)?
+ } else if let Ok(name) = std::env::var("PROXMOX_TAPE_DRIVE") {
+ let (config, _digest) = pbs_config::drive::config()?;
+ let drive: LtoTapeDrive = config.lookup("lto", &name)?;
eprintln!("using device {}", drive.path);
- drive.open()?
+ open_lto_tape_drive(&drive)?
} else {
- let (config, _digest) = config::drive::config()?;
+ let (config, _digest) = pbs_config::drive::config()?;
let mut drive_names = Vec::new();
for (name, (section_type, _)) in config.sections.iter() {
- if section_type != "linux" { continue; }
+ if section_type != "lto" { continue; }
drive_names.push(name);
}
if drive_names.len() == 1 {
let name = drive_names[0];
- let drive: LinuxTapeDrive = config.lookup("linux", &name)?;
+ let drive: LtoTapeDrive = config.lookup("lto", name)?;
eprintln!("using device {}", drive.path);
- drive.open()?
+ open_lto_tape_drive(&drive)?
} else {
bail!("no drive/device specified");
}
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(
- param: Value,
-) -> Result<(), Error> {
-
- let result = proxmox::try_block!({
- let mut handle = get_tape_handle(¶m)?;
- handle.get_drive_and_media_status()
- }).map_err(|err: Error| err.to_string());
-
- println!("{}", serde_json::to_string_pretty(&result)?);
-
- Ok(())
-}
-
-#[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(
- param: Value,
-) -> Result<(), Error> {
-
- let result = proxmox::try_block!({
- let mut handle = get_tape_handle(¶m)?;
-
- handle.cartridge_memory()
- }).map_err(|err| err.to_string());
-
- println!("{}", serde_json::to_string_pretty(&result)?);
-
- Ok(())
-}
-
-#[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(
- param: Value,
-) -> Result<(), Error> {
-
- let result = proxmox::try_block!({
- let mut handle = get_tape_handle(¶m)?;
-
- let flags = handle.tape_alert_flags()?;
- Ok(flags.bits())
- }).map_err(|err: Error| err.to_string());
-
- println!("{}", serde_json::to_string_pretty(&result)?);
-
- Ok(())
-}
-
#[api(
input: {
properties: {
schema: TAPE_ENCRYPTION_KEY_FINGERPRINT_SCHEMA,
optional: true,
},
+ uuid: {
+ schema: MEDIA_SET_UUID_SCHEMA,
+ optional: true,
+ },
drive: {
schema: DRIVE_NAME_SCHEMA,
optional: true,
},
device: {
- schema: LINUX_DRIVE_PATH_SCHEMA,
+ schema: LTO_DRIVE_PATH_SCHEMA,
optional: true,
},
stdin: {
/// Set or clear encryption key
fn set_encryption(
fingerprint: Option<Fingerprint>,
+ uuid: Option<Uuid>,
param: Value,
) -> Result<(), Error> {
- let result = proxmox::try_block!({
+ let result = proxmox_lang::try_block!({
let mut handle = get_tape_handle(¶m)?;
- handle.set_encryption(fingerprint)?;
- Ok(())
- }).map_err(|err: Error| err.to_string());
-
- println!("{}", serde_json::to_string_pretty(&result)?);
-
- Ok(())
-}
-
-#[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(
- param: Value,
-) -> Result<(), Error> {
+ match (fingerprint, uuid) {
+ (Some(fingerprint), Some(uuid)) => {
+ handle.set_encryption(Some((fingerprint, uuid)))?;
+ }
+ (Some(_), None) => {
+ bail!("missing media set uuid");
+ }
+ (None, _) => {
+ handle.set_encryption(None)?;
+ }
+ }
- let result = proxmox::try_block!({
- let mut handle = get_tape_handle(¶m)?;
- handle.volume_statistics()
+ Ok(())
}).map_err(|err: Error| err.to_string());
println!("{}", serde_json::to_string_pretty(&result)?);
fn main() -> Result<(), Error> {
// check if we are user root or backup
- let backup_uid = proxmox_backup::backup::backup_user()?.uid;
- let backup_gid = proxmox_backup::backup::backup_group()?.gid;
+ let backup_uid = pbs_config::backup_user()?.uid;
+ let backup_gid = pbs_config::backup_group()?.gid;
let running_uid = nix::unistd::Uid::current();
let running_gid = nix::unistd::Gid::current();
bail!("this program needs to be run with setuid root");
}
- if !running_uid.is_root() {
- if running_uid != backup_uid || running_gid != backup_gid {
- bail!(
- "Not running as backup user or group (got uid {} gid {})",
- running_uid, running_gid,
- );
- }
+ if !running_uid.is_root() && (running_uid != backup_uid || running_gid != backup_gid) {
+ bail!(
+ "Not running as backup user or group (got uid {} gid {})",
+ running_uid, running_gid,
+ );
}
let cmd_def = CliCommandMap::new()
- .insert(
- "status",
- CliCommand::new(&API_METHOD_STATUS)
- )
- .insert(
- "cartridge-memory",
- CliCommand::new(&API_METHOD_CARTRIDGE_MEMORY)
- )
- .insert(
- "tape-alert-flags",
- CliCommand::new(&API_METHOD_TAPE_ALERT_FLAGS)
- )
- .insert(
- "volume-statistics",
- CliCommand::new(&API_METHOD_VOLUME_STATISTICS)
- )
.insert(
"encryption",
CliCommand::new(&API_METHOD_SET_ENCRYPTION)