]> git.proxmox.com Git - pve-installer.git/blob - proxmox-fetch-answer/src/fetch_plugins/partition.rs
1d80847959879e8e771a02482982cb9c1dd8332e
[pve-installer.git] / proxmox-fetch-answer / src / fetch_plugins / partition.rs
1 use anyhow::{bail, format_err, Result};
2 use log::{info, warn};
3 use std::{
4 fs::{self, create_dir_all},
5 path::{Path, PathBuf},
6 process::Command,
7 };
8
9 static ANSWER_FILE: &str = "answer.toml";
10 static ANSWER_MP: &str = "/mnt/answer";
11 // FAT can only handle 11 characters, so shorten Automated Installer Source to AIS
12 static PARTLABEL: &str = "proxmox-ais";
13 static SEARCH_PATH: &str = "/dev/disk/by-label";
14
15 pub struct FetchFromPartition;
16
17 impl FetchFromPartition {
18 /// Returns the contents of the answer file
19 pub fn get_answer() -> Result<String> {
20 info!("Checking for answer file on partition.");
21
22 let mut mount_path = PathBuf::from(mount_proxmoxinst_part()?);
23 mount_path.push(ANSWER_FILE);
24 let answer = fs::read_to_string(mount_path)
25 .map_err(|err| format_err!("failed to read answer file - {err}"))?;
26
27 info!("Found answer file on partition.");
28
29 Ok(answer)
30 }
31 }
32
33 /// Searches for upper and lower case existence of the partlabel in the search_path
34 ///
35 /// # Arguemnts
36 /// * `partlabel_source` - Partition Label, used as upper and lower case
37 /// * `search_path` - Path where to search for the partiiton label
38 fn scan_partlabels(partlabel_source: &str, search_path: &str) -> Result<PathBuf> {
39 let partlabel = partlabel_source.to_uppercase();
40 let path = Path::new(search_path).join(&partlabel);
41 match path.try_exists() {
42 Ok(true) => {
43 info!("Found partition with label '{partlabel}'");
44 return Ok(path);
45 }
46 Ok(false) => info!("Did not detect partition with label '{partlabel}'"),
47 Err(err) => info!("Encountered issue, accessing '{path:?}': {err}"),
48 }
49
50 let partlabel = partlabel_source.to_lowercase();
51 let path = Path::new(search_path).join(&partlabel);
52 match path.try_exists() {
53 Ok(true) => {
54 info!("Found partition with label '{partlabel}'");
55 return Ok(path);
56 }
57 Ok(false) => info!("Did not detect partition with label '{partlabel}'"),
58 Err(err) => info!("Encountered issue, accessing '{path:?}': {err}"),
59 }
60 bail!("Could not detect upper or lower case labels for '{partlabel_source}'");
61 }
62
63 /// Will search and mount a partition/FS labeled PARTLABEL (proxmox-ais) in lower or uppercase
64 /// to ANSWER_MP
65 fn mount_proxmoxinst_part() -> Result<String> {
66 if let Ok(true) = check_if_mounted(ANSWER_MP) {
67 info!("Skipping: '{ANSWER_MP}' is already mounted.");
68 return Ok(ANSWER_MP.into());
69 }
70 let part_path = scan_partlabels(PARTLABEL, SEARCH_PATH)?;
71 info!("Mounting partition at {ANSWER_MP}");
72 // create dir for mountpoint
73 create_dir_all(ANSWER_MP)?;
74 match Command::new("mount")
75 .args(["-o", "ro"])
76 .arg(part_path)
77 .arg(ANSWER_MP)
78 .output()
79 {
80 Ok(output) => {
81 if output.status.success() {
82 Ok(ANSWER_MP.into())
83 } else {
84 warn!("Error mounting: {}", String::from_utf8(output.stderr)?);
85 Ok(ANSWER_MP.into())
86 }
87 }
88 Err(err) => bail!("Error mounting: {err}"),
89 }
90 }
91
92 fn check_if_mounted(target_path: &str) -> Result<bool> {
93 let mounts = fs::read_to_string("/proc/mounts")?;
94 for line in mounts.lines() {
95 if let Some(mp) = line.split(' ').nth(1) {
96 if mp == target_path {
97 return Ok(true);
98 }
99 }
100 }
101 Ok(false)
102 }