1 //! Tape drive/changer configuration
3 //! This configuration module is based on [`SectionConfig`], and
4 //! provides a type safe interface to store [`LtoTapeDrive`],
5 //! [`VirtualTapeDrive`] and [`ScsiTapeChanger`] configurations.
7 //! Drive type [`VirtualTapeDrive`] is only useful for debugging.
9 //! [LtoTapeDrive]: crate::api2::types::LtoTapeDrive
10 //! [VirtualTapeDrive]: crate::api2::types::VirtualTapeDrive
11 //! [ScsiTapeChanger]: crate::api2::types::ScsiTapeChanger
12 //! [SectionConfig]: proxmox::api::section_config::SectionConfig
14 use std
::collections
::HashMap
;
16 use anyhow
::{bail, Error}
;
17 use lazy_static
::lazy_static
;
19 use proxmox_schema
::*;
20 use proxmox_section_config
::{SectionConfig, SectionConfigData, SectionConfigPlugin}
;
22 use crate::{open_backup_lockfile, replace_backup_config, BackupLockGuard}
;
25 DRIVE_NAME_SCHEMA
, VirtualTapeDrive
, LtoTapeDrive
, ScsiTapeChanger
,
30 /// Static [`SectionConfig`] to access parser/writer functions.
31 pub static ref CONFIG
: SectionConfig
= init();
35 fn init() -> SectionConfig
{
36 let mut config
= SectionConfig
::new(&DRIVE_NAME_SCHEMA
);
38 let obj_schema
= match VirtualTapeDrive
::API_SCHEMA
{
39 Schema
::Object(ref obj_schema
) => obj_schema
,
42 let plugin
= SectionConfigPlugin
::new("virtual".to_string(), Some("name".to_string()), obj_schema
);
43 config
.register_plugin(plugin
);
45 let obj_schema
= match LtoTapeDrive
::API_SCHEMA
{
46 Schema
::Object(ref obj_schema
) => obj_schema
,
49 let plugin
= SectionConfigPlugin
::new("lto".to_string(), Some("name".to_string()), obj_schema
);
50 config
.register_plugin(plugin
);
52 let obj_schema
= match ScsiTapeChanger
::API_SCHEMA
{
53 Schema
::Object(ref obj_schema
) => obj_schema
,
56 let plugin
= SectionConfigPlugin
::new("changer".to_string(), Some("name".to_string()), obj_schema
);
57 config
.register_plugin(plugin
);
61 /// Configuration file name
62 pub const DRIVE_CFG_FILENAME
: &str = "/etc/proxmox-backup/tape.cfg";
63 /// Lock file name (used to prevent concurrent access)
64 pub const DRIVE_CFG_LOCKFILE
: &str = "/etc/proxmox-backup/.tape.lck";
66 /// Get exclusive lock
67 pub fn lock() -> Result
<BackupLockGuard
, Error
> {
68 open_backup_lockfile(DRIVE_CFG_LOCKFILE
, None
, true)
71 /// Read and parse the configuration file
72 pub fn config() -> Result
<(SectionConfigData
, [u8;32]), Error
> {
74 let content
= proxmox_sys
::fs
::file_read_optional_string(DRIVE_CFG_FILENAME
)?
75 .unwrap_or_else(|| "".to_string());
77 let digest
= openssl
::sha
::sha256(content
.as_bytes());
78 let data
= CONFIG
.parse(DRIVE_CFG_FILENAME
, &content
)?
;
82 /// Save the configuration file
83 pub fn save_config(config
: &SectionConfigData
) -> Result
<(), Error
> {
84 let raw
= CONFIG
.write(DRIVE_CFG_FILENAME
, &config
)?
;
85 replace_backup_config(DRIVE_CFG_FILENAME
, raw
.as_bytes())
88 /// Check if the specified drive name exists in the config.
89 pub fn check_drive_exists(config
: &SectionConfigData
, drive
: &str) -> Result
<(), Error
> {
90 match config
.sections
.get(drive
) {
91 Some((section_type
, _
)) => {
92 if !(section_type
== "lto" || section_type
== "virtual") {
93 bail
!("Entry '{}' exists, but is not a tape drive", drive
);
96 None
=> bail
!("Drive '{}' does not exist", drive
),
102 // shell completion helper
104 /// List all drive names
105 pub fn complete_drive_name(_arg
: &str, _param
: &HashMap
<String
, String
>) -> Vec
<String
> {
107 Ok((data
, _digest
)) => data
.sections
.iter()
108 .map(|(id
, _
)| id
.to_string())
110 Err(_
) => return vec
![],
114 /// List Lto tape drives
115 pub fn complete_lto_drive_name(_arg
: &str, _param
: &HashMap
<String
, String
>) -> Vec
<String
> {
117 Ok((data
, _digest
)) => data
.sections
.iter()
118 .filter(|(_id
, (section_type
, _
))| {
119 section_type
== "lto"
121 .map(|(id
, _
)| id
.to_string())
123 Err(_
) => return vec
![],
127 /// List Scsi tape changer names
128 pub fn complete_changer_name(_arg
: &str, _param
: &HashMap
<String
, String
>) -> Vec
<String
> {
130 Ok((data
, _digest
)) => data
.sections
.iter()
131 .filter(|(_id
, (section_type
, _
))| {
132 section_type
== "changer"
134 .map(|(id
, _
)| id
.to_string())
136 Err(_
) => return vec
![],