]> git.proxmox.com Git - proxmox-backup.git/blame - src/bin/sg-tape-cmd.rs
tree-wide: fix needless borrows
[proxmox-backup.git] / src / bin / sg-tape-cmd.rs
CommitLineData
a79082a0
DM
1/// Helper to run tape commands as root. Currently only required
2/// to read and set the encryption key.
b27c3282
DM
3///
4/// This command can use STDIN as tape device handle.
5
6use std::fs::File;
7use std::os::unix::io::{AsRawFd, FromRawFd};
8
8a0046f5 9use anyhow::{bail, Error};
2d50a619 10use serde_json::Value;
b27c3282 11
6ef1b649
WB
12use proxmox_router::{cli::*, RpcEnvironment};
13use proxmox_schema::api;
14use proxmox_uuid::Uuid;
b27c3282 15
1ce8e905
DM
16use pbs_api_types::{
17 Fingerprint, LTO_DRIVE_PATH_SCHEMA, DRIVE_NAME_SCHEMA, TAPE_ENCRYPTION_KEY_FINGERPRINT_SCHEMA,
18 MEDIA_SET_UUID_SCHEMA, LtoTapeDrive,
19};
b2065dc7 20
048b43af
DM
21use pbs_tape::linux_list_drives::{open_lto_tape_device, check_tape_is_lto_tape_device};
22
b27c3282 23use proxmox_backup::{
b27c3282 24 tape::{
37796ff7
DM
25 drive::{
26 TapeDriver,
a79082a0 27 LtoTapeHandle,
1ce8e905 28 open_lto_tape_drive,
b27c3282
DM
29 },
30 },
31};
32
a79082a0 33fn get_tape_handle(param: &Value) -> Result<LtoTapeHandle, Error> {
2d50a619
DM
34
35 let handle = if let Some(name) = param["drive"].as_str() {
1ce8e905 36 let (config, _digest) = pbs_config::drive::config()?;
9a37bd6c 37 let drive: LtoTapeDrive = config.lookup("lto", name)?;
2d50a619 38 eprintln!("using device {}", drive.path);
1ce8e905 39 open_lto_tape_drive(&drive)?
2d50a619
DM
40 } else if let Some(device) = param["device"].as_str() {
41 eprintln!("using device {}", device);
9a37bd6c 42 LtoTapeHandle::new(open_lto_tape_device(device)?)?
2d50a619
DM
43 } else if let Some(true) = param["stdin"].as_bool() {
44 eprintln!("using stdin");
b27c3282
DM
45 let fd = std::io::stdin().as_raw_fd();
46 let file = unsafe { File::from_raw_fd(fd) };
a79082a0
DM
47 check_tape_is_lto_tape_device(&file)?;
48 LtoTapeHandle::new(file)?
ea368a06 49 } else if let Ok(name) = std::env::var("PROXMOX_TAPE_DRIVE") {
1ce8e905 50 let (config, _digest) = pbs_config::drive::config()?;
a79082a0 51 let drive: LtoTapeDrive = config.lookup("lto", &name)?;
2d50a619 52 eprintln!("using device {}", drive.path);
1ce8e905 53 open_lto_tape_drive(&drive)?
2d50a619 54 } else {
1ce8e905 55 let (config, _digest) = pbs_config::drive::config()?;
2d50a619
DM
56
57 let mut drive_names = Vec::new();
58 for (name, (section_type, _)) in config.sections.iter() {
a79082a0 59 if section_type != "lto" { continue; }
2d50a619
DM
60 drive_names.push(name);
61 }
62
63 if drive_names.len() == 1 {
64 let name = drive_names[0];
9a37bd6c 65 let drive: LtoTapeDrive = config.lookup("lto", name)?;
2d50a619 66 eprintln!("using device {}", drive.path);
1ce8e905 67 open_lto_tape_drive(&drive)?
2d50a619
DM
68 } else {
69 bail!("no drive/device specified");
70 }
b27c3282 71 };
2d50a619
DM
72
73 Ok(handle)
b27c3282
DM
74}
75
d5a48b5c
DM
76#[api(
77 input: {
78 properties: {
79 fingerprint: {
80 schema: TAPE_ENCRYPTION_KEY_FINGERPRINT_SCHEMA,
81 optional: true,
82 },
2b191385
DM
83 uuid: {
84 schema: MEDIA_SET_UUID_SCHEMA,
85 optional: true,
86 },
d5a48b5c
DM
87 drive: {
88 schema: DRIVE_NAME_SCHEMA,
89 optional: true,
90 },
91 device: {
a79082a0 92 schema: LTO_DRIVE_PATH_SCHEMA,
d5a48b5c
DM
93 optional: true,
94 },
95 stdin: {
96 description: "Use standard input as device handle.",
97 type: bool,
98 optional: true,
99 },
100 },
101 },
102)]
103/// Set or clear encryption key
104fn set_encryption(
105 fingerprint: Option<Fingerprint>,
2b191385 106 uuid: Option<Uuid>,
d5a48b5c
DM
107 param: Value,
108) -> Result<(), Error> {
109
6ef1b649 110 let result = proxmox_lang::try_block!({
d5a48b5c
DM
111 let mut handle = get_tape_handle(&param)?;
112
2b191385
DM
113 match (fingerprint, uuid) {
114 (Some(fingerprint), Some(uuid)) => {
115 handle.set_encryption(Some((fingerprint, uuid)))?;
116 }
117 (Some(_), None) => {
118 bail!("missing media set uuid");
119 }
120 (None, _) => {
121 handle.set_encryption(None)?;
122 }
123 }
124
d5a48b5c
DM
125 Ok(())
126 }).map_err(|err: Error| err.to_string());
127
128 println!("{}", serde_json::to_string_pretty(&result)?);
129
130 Ok(())
131}
132
b27c3282
DM
133fn main() -> Result<(), Error> {
134
135 // check if we are user root or backup
21211748
DM
136 let backup_uid = pbs_config::backup_user()?.uid;
137 let backup_gid = pbs_config::backup_group()?.gid;
b27c3282
DM
138 let running_uid = nix::unistd::Uid::current();
139 let running_gid = nix::unistd::Gid::current();
140
141 let effective_uid = nix::unistd::Uid::effective();
142 if !effective_uid.is_root() {
143 bail!("this program needs to be run with setuid root");
144 }
145
6334bdc1
FG
146 if !running_uid.is_root() && (running_uid != backup_uid || running_gid != backup_gid) {
147 bail!(
148 "Not running as backup user or group (got uid {} gid {})",
149 running_uid, running_gid,
150 );
b27c3282
DM
151 }
152
153 let cmd_def = CliCommandMap::new()
d5a48b5c
DM
154 .insert(
155 "encryption",
156 CliCommand::new(&API_METHOD_SET_ENCRYPTION)
157 )
b27c3282
DM
158 ;
159
160 let mut rpcenv = CliEnvironment::new();
161 rpcenv.set_auth_id(Some(String::from("root@pam")));
162
163 run_cli_command(cmd_def, rpcenv, None);
164
165 Ok(())
166}