]> git.proxmox.com Git - proxmox-backup-restore-image.git/blob - src/init-shim-rs/src/main.rs
update/rework packaging and buildsys
[proxmox-backup-restore-image.git] / src / init-shim-rs / src / main.rs
1 use anyhow::Error;
2 use std::ffi::CStr;
3 use std::fs;
4
5 const URANDOM_MAJ: u64 = 1;
6 const URANDOM_MIN: u64 = 9;
7
8 /// Set up a somewhat normal linux userspace environment before starting the restore daemon, and
9 /// provide error messages to the user if doing so fails.
10 ///
11 /// This is supposed to run as /init in an initramfs image.
12 fn main() {
13 println!("[init-shim] beginning user space setup");
14
15 // /dev is mounted automatically
16 wrap_err("mount /sys", || do_mount("/sys", "sysfs"));
17 wrap_err("mount /proc", || do_mount("/proc", "proc"));
18
19 // make device nodes required by daemon
20 wrap_err("mknod /dev/urandom", || {
21 do_mknod("/dev/urandom", URANDOM_MAJ, URANDOM_MIN)
22 });
23
24 let uptime = read_uptime();
25 println!("[init-shim] reached daemon start after {:.2}s", uptime);
26
27 do_run("/proxmox-restore-daemon");
28 }
29
30 fn do_mount(target: &str, fstype: &str) -> Result<(), Error> {
31 use nix::mount::{mount, MsFlags};
32 fs::create_dir(target)?;
33 let none_type: Option<&CStr> = None;
34 mount(
35 none_type,
36 target,
37 Some(fstype),
38 MsFlags::MS_NOSUID | MsFlags::MS_NOEXEC,
39 none_type,
40 )?;
41 Ok(())
42 }
43
44 fn do_mknod(path: &str, maj: u64, min: u64) -> Result<(), Error> {
45 use nix::sys::stat;
46 let dev = stat::makedev(maj, min);
47 stat::mknod(path, stat::SFlag::S_IFCHR, stat::Mode::S_IRWXU, dev)?;
48 Ok(())
49 }
50
51 fn read_uptime() -> f32 {
52 let uptime = wrap_err("read /proc/uptime", || {
53 fs::read_to_string("/proc/uptime").map_err(|e| e.into())
54 });
55 // this can never fail on a sane kernel, so just unwrap
56 uptime
57 .split_ascii_whitespace()
58 .next()
59 .unwrap()
60 .parse()
61 .unwrap()
62 }
63
64 fn do_run(cmd: &str) -> ! {
65 use std::io::ErrorKind;
66 use std::process::Command;
67
68 let spawn_res = Command::new(cmd).env("RUST_BACKTRACE", "1").spawn();
69
70 match spawn_res {
71 Ok(mut child) => {
72 let res = wrap_err("wait failed", || child.wait().map_err(|e| e.into()));
73 error(&format!(
74 "child process {} (pid={} exitcode={}) exited unexpectedly, check log for more info",
75 cmd,
76 child.id(),
77 res.code().unwrap_or(-1),
78 ));
79 }
80 Err(err) if err.kind() == ErrorKind::NotFound => {
81 error(&format!(
82 concat!(
83 "{} missing from image.\n",
84 "This initramfs should only be run with proxmox-file-restore!"
85 ),
86 cmd
87 ));
88 }
89 Err(err) => {
90 error(&format!(
91 "unexpected error during start of {}: {}",
92 cmd, err
93 ));
94 }
95 }
96 }
97
98 fn wrap_err<R, F: FnOnce() -> Result<R, Error>>(op: &str, f: F) -> R {
99 match f() {
100 Ok(r) => r,
101 Err(e) => error(&format!("operation '{}' failed: {}", op, e)),
102 }
103 }
104
105 fn error(msg: &str) -> ! {
106 use nix::sys::reboot;
107
108 println!("\n--------");
109 println!("ERROR: Init shim failed\n");
110 println!("{}", msg);
111 println!("--------\n");
112
113 // in case a fatal error occurs we shut down the VM, there's no sense in continuing and this
114 // will certainly alert whoever started us up in the first place
115 let err = reboot::reboot(reboot::RebootMode::RB_POWER_OFF).unwrap_err();
116 println!("'reboot' syscall failed: {} - cannot continue", err);
117
118 // in case 'reboot' fails just loop forever
119 loop {
120 std::thread::sleep(std::time::Duration::from_secs(600));
121 }
122 }