summaryrefslogtreecommitdiff
path: root/scripts/native-utils/src
diff options
context:
space:
mode:
authorK900 <me@0upti.me>2023-02-01 12:15:04 +0300
committerK900 <me@0upti.me>2023-02-01 15:47:19 +0300
commitdeef7819e9863464365bc251c1070708e0925fc0 (patch)
tree253d10ccb9177bcbd723b06082ad73150e8d1d7f /scripts/native-utils/src
parent0487b4de4abc076d36325684226ea3bb312b88f8 (diff)
feat: use a Rust tool to do the PATH manipulations
Overkill? Yes. Fuck bash? Also yes.
Diffstat (limited to 'scripts/native-utils/src')
-rw-r--r--scripts/native-utils/src/shim.rs129
-rw-r--r--scripts/native-utils/src/split_path.rs38
2 files changed, 167 insertions, 0 deletions
diff --git a/scripts/native-utils/src/shim.rs b/scripts/native-utils/src/shim.rs
new file mode 100644
index 0000000..504335c
--- /dev/null
+++ b/scripts/native-utils/src/shim.rs
@@ -0,0 +1,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);
+}
diff --git a/scripts/native-utils/src/split_path.rs b/scripts/native-utils/src/split_path.rs
new file mode 100644
index 0000000..dd10745
--- /dev/null
+++ b/scripts/native-utils/src/split_path.rs
@@ -0,0 +1,38 @@
+use std::env;
+
+use clap::Parser;
+
+#[derive(Parser, Debug)]
+struct Args {
+ #[arg(long)]
+ automount_root: String,
+
+ #[arg(long)]
+ include_interop: bool,
+}
+
+fn main() -> anyhow::Result<()> {
+ let args = Args::parse();
+
+ let path = env::var("PATH")?;
+
+ let mut native = vec![];
+ let mut interop = vec![];
+
+ for part in path.split(':') {
+ if part.starts_with(&args.automount_root) {
+ interop.push(part);
+ } else {
+ native.push(part);
+ }
+ }
+
+ if args.include_interop {
+ native.extend(&interop);
+ };
+
+ println!("export PATH='{}'", native.join(":"));
+ println!("export WSLPATH='{}'", interop.join(":"));
+
+ Ok(())
+}