1 /// Tape command implemented using scsi-generic raw commands
3 /// SCSI-generic command needs root priviledges, so this binary need
6 /// This command can use STDIN as tape device handle.
9 use std
::os
::unix
::io
::{AsRawFd, FromRawFd}
;
11 use anyhow
::{bail, Error}
;
12 use serde_json
::Value
;
26 LINUX_DRIVE_PATH_SCHEMA
,
28 TAPE_ENCRYPTION_KEY_FINGERPRINT_SCHEMA
,
35 open_linux_tape_device
,
36 check_tape_is_linux_tape_device
,
41 fn get_tape_handle(param
: &Value
) -> Result
<LinuxTapeHandle
, Error
> {
43 let handle
= if let Some(name
) = param
["drive"].as_str() {
44 let (config
, _digest
) = config
::drive
::config()?
;
45 let drive
: LinuxTapeDrive
= config
.lookup("linux", &name
)?
;
46 eprintln
!("using device {}", drive
.path
);
48 } else if let Some(device
) = param
["device"].as_str() {
49 eprintln
!("using device {}", device
);
50 LinuxTapeHandle
::new(open_linux_tape_device(&device
)?
)
51 } else if let Some(true) = param
["stdin"].as_bool() {
52 eprintln
!("using stdin");
53 let fd
= std
::io
::stdin().as_raw_fd();
54 let file
= unsafe { File::from_raw_fd(fd) }
;
55 check_tape_is_linux_tape_device(&file
)?
;
56 LinuxTapeHandle
::new(file
)
57 } else if let Ok(name
) = std
::env
::var("PROXMOX_TAPE_DRIVE") {
58 let (config
, _digest
) = config
::drive
::config()?
;
59 let drive
: LinuxTapeDrive
= config
.lookup("linux", &name
)?
;
60 eprintln
!("using device {}", drive
.path
);
63 let (config
, _digest
) = config
::drive
::config()?
;
65 let mut drive_names
= Vec
::new();
66 for (name
, (section_type
, _
)) in config
.sections
.iter() {
67 if section_type
!= "linux" { continue; }
68 drive_names
.push(name
);
71 if drive_names
.len() == 1 {
72 let name
= drive_names
[0];
73 let drive
: LinuxTapeDrive
= config
.lookup("linux", &name
)?
;
74 eprintln
!("using device {}", drive
.path
);
77 bail
!("no drive/device specified");
88 schema
: DRIVE_NAME_SCHEMA
,
92 schema
: LINUX_DRIVE_PATH_SCHEMA
,
96 description
: "Use standard input as device handle.",
103 /// Tape/Media Status
106 ) -> Result
<(), Error
> {
108 let result
= proxmox
::try_block
!({
109 let mut handle
= get_tape_handle(¶m
)?
;
110 handle
.get_drive_and_media_status()
111 }).map_err(|err
: Error
| err
.to_string());
113 println
!("{}", serde_json
::to_string_pretty(&result
)?
);
122 schema
: DRIVE_NAME_SCHEMA
,
126 schema
: LINUX_DRIVE_PATH_SCHEMA
,
130 description
: "Use standard input as device handle.",
137 /// Read Cartridge Memory (Medium auxiliary memory attributes)
140 ) -> Result
<(), Error
> {
142 let result
= proxmox
::try_block
!({
143 let mut handle
= get_tape_handle(¶m
)?
;
145 handle
.cartridge_memory()
146 }).map_err(|err
| err
.to_string());
148 println
!("{}", serde_json
::to_string_pretty(&result
)?
);
157 schema
: DRIVE_NAME_SCHEMA
,
161 schema
: LINUX_DRIVE_PATH_SCHEMA
,
165 description
: "Use standard input as device handle.",
172 /// Read Tape Alert Flags
175 ) -> Result
<(), Error
> {
177 let result
= proxmox
::try_block
!({
178 let mut handle
= get_tape_handle(¶m
)?
;
180 let flags
= handle
.tape_alert_flags()?
;
182 }).map_err(|err
: Error
| err
.to_string());
184 println
!("{}", serde_json
::to_string_pretty(&result
)?
);
193 schema
: TAPE_ENCRYPTION_KEY_FINGERPRINT_SCHEMA
,
197 schema
: DRIVE_NAME_SCHEMA
,
201 schema
: LINUX_DRIVE_PATH_SCHEMA
,
205 description
: "Use standard input as device handle.",
212 /// Set or clear encryption key
214 fingerprint
: Option
<Fingerprint
>,
216 ) -> Result
<(), Error
> {
218 let result
= proxmox
::try_block
!({
219 let mut handle
= get_tape_handle(¶m
)?
;
221 handle
.set_encryption(fingerprint
)?
;
223 }).map_err(|err
: Error
| err
.to_string());
225 println
!("{}", serde_json
::to_string_pretty(&result
)?
);
234 schema
: DRIVE_NAME_SCHEMA
,
238 schema
: LINUX_DRIVE_PATH_SCHEMA
,
242 description
: "Use standard input as device handle.",
249 /// Read volume statistics
250 fn volume_statistics(
252 ) -> Result
<(), Error
> {
254 let result
= proxmox
::try_block
!({
255 let mut handle
= get_tape_handle(¶m
)?
;
256 handle
.volume_statistics()
257 }).map_err(|err
: Error
| err
.to_string());
259 println
!("{}", serde_json
::to_string_pretty(&result
)?
);
264 fn main() -> Result
<(), Error
> {
266 // check if we are user root or backup
267 let backup_uid
= proxmox_backup
::backup
::backup_user()?
.uid
;
268 let backup_gid
= proxmox_backup
::backup
::backup_group()?
.gid
;
269 let running_uid
= nix
::unistd
::Uid
::current();
270 let running_gid
= nix
::unistd
::Gid
::current();
272 let effective_uid
= nix
::unistd
::Uid
::effective();
273 if !effective_uid
.is_root() {
274 bail
!("this program needs to be run with setuid root");
277 if !running_uid
.is_root() && (running_uid
!= backup_uid
|| running_gid
!= backup_gid
) {
279 "Not running as backup user or group (got uid {} gid {})",
280 running_uid
, running_gid
,
284 let cmd_def
= CliCommandMap
::new()
287 CliCommand
::new(&API_METHOD_STATUS
)
291 CliCommand
::new(&API_METHOD_CARTRIDGE_MEMORY
)
295 CliCommand
::new(&API_METHOD_TAPE_ALERT_FLAGS
)
299 CliCommand
::new(&API_METHOD_VOLUME_STATISTICS
)
303 CliCommand
::new(&API_METHOD_SET_ENCRYPTION
)
307 let mut rpcenv
= CliEnvironment
::new();
308 rpcenv
.set_auth_id(Some(String
::from("root@pam")));
310 run_cli_command(cmd_def
, rpcenv
, None
);