1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
|
use anyhow::Context;
use nix::errno::Errno;
use nix::mount::{mount, MsFlags};
use nix::sys::wait::{waitid, Id, WaitPidFlag};
use nix::unistd::Pid;
use std::env;
use std::fs::{create_dir_all, metadata, remove_dir_all, remove_file, OpenOptions};
use std::os::unix::io::{FromRawFd, IntoRawFd};
use std::os::unix::process::CommandExt;
use std::path::Path;
use std::process::{Command, Stdio};
fn unscrew_dev_shm() -> anyhow::Result<()> {
log::trace!("Unscrewing /dev/shm...");
let dev_shm = Path::new("/dev/shm");
if dev_shm.is_symlink() {
remove_file(dev_shm).context("When removing /dev/shm symlink")?;
} else if dev_shm.is_dir() {
remove_dir_all(dev_shm).context("When removing old /dev/shm")?;
}
create_dir_all("/dev/shm").context("When creating new /dev/shm")?;
mount(
Some("/run/shm"),
"/dev/shm",
None::<&str>,
MsFlags::MS_MOVE,
None::<&str>,
)
.context("When relocating /dev/shm")?;
mount(
Some("/dev/shm"),
"/run/shm",
None::<&str>,
MsFlags::MS_BIND,
None::<&str>,
)
.context("When bind mounting /run/shm to /dev/shm")?;
Ok(())
}
fn real_main() -> anyhow::Result<()> {
if metadata("/dev/shm")
.context("When checking /dev/shm")?
.is_symlink()
{
unscrew_dev_shm()?;
} else {
log::trace!("/dev/shm is not a symlink, leaving as-is...");
};
log::trace!("Remounting / shared...");
mount(
None::<&str>,
"/",
None::<&str>,
MsFlags::MS_REC | MsFlags::MS_SHARED,
None::<&str>,
)
.context("When remounting /")?;
log::trace!("Remounting /nix/store read-only...");
mount(
Some("/nix/store"),
"/nix/store",
None::<&str>,
MsFlags::MS_BIND,
None::<&str>,
)
.context("When bind mounting /nix/store")?;
mount(
Some("/nix/store"),
"/nix/store",
None::<&str>,
MsFlags::MS_BIND | MsFlags::MS_REMOUNT | MsFlags::MS_RDONLY,
None::<&str>,
)
.context("When remounting /nix/store read-only")?;
log::trace!("Running activation script...");
let kmsg_fd = OpenOptions::new()
.write(true)
.open("/dev/kmsg")
.context("When opening /dev/kmsg")?
.into_raw_fd();
let child = Command::new("/nix/var/nix/profiles/system/activate")
.env("LANG", "C.UTF-8")
// SAFETY: we just opened this
.stdout(unsafe { Stdio::from_raw_fd(kmsg_fd) })
.stderr(unsafe { Stdio::from_raw_fd(kmsg_fd) })
.spawn()
.context("When activating")?;
let pid = Pid::from_raw(child.id() as i32);
// If the child catches SIGCHLD, `waitid` will wait for it to exit, then return ECHILD.
// Why? Because POSIX is terrible.
let result = waitid(Id::Pid(pid), WaitPidFlag::WEXITED);
match result {
Ok(_) | Err(Errno::ECHILD) => {}
Err(e) => return Err(e).context("When waiting"),
};
log::trace!("Spawning real systemd...");
// if things go right, we will never return from here
Err(
Command::new("/nix/var/nix/profiles/system/systemd/lib/systemd/systemd")
.arg0(env::args_os().next().expect("arg0 missing"))
.args(env::args_os().skip(1))
.exec()
.into(),
)
}
fn main() {
env::set_var("RUST_BACKTRACE", "1");
kernlog::init().expect("Failed to set up logger...");
let result = real_main();
log::error!("Error: {:?}", result);
}
|