From 42070f7532be51616837ad7e4871e50f0406a82d Mon Sep 17 00:00:00 2001 From: Bruce Leidl Date: Wed, 18 Oct 2017 19:09:14 +0000 Subject: [PATCH] An init daemon written in rust to replace kernel/init/init.c --- ph-init/Cargo.lock | 14 ++++ ph-init/Cargo.toml | 7 ++ ph-init/src/main.rs | 123 +++++++++++++++++++++++++++++++++ ph-init/src/sys.rs | 162 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 306 insertions(+) create mode 100644 ph-init/Cargo.lock create mode 100644 ph-init/Cargo.toml create mode 100644 ph-init/src/main.rs create mode 100644 ph-init/src/sys.rs diff --git a/ph-init/Cargo.lock b/ph-init/Cargo.lock new file mode 100644 index 0000000..50ccd65 --- /dev/null +++ b/ph-init/Cargo.lock @@ -0,0 +1,14 @@ +[root] +name = "ph-init" +version = "0.1.0" +dependencies = [ + "libc 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "libc" +version = "0.2.32" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[metadata] +"checksum libc 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)" = "56cce3130fd040c28df6f495c8492e5ec5808fb4c9093c310df02b0c8f030148" diff --git a/ph-init/Cargo.toml b/ph-init/Cargo.toml new file mode 100644 index 0000000..941de73 --- /dev/null +++ b/ph-init/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "ph-init" +version = "0.1.0" +authors = ["Bruce Leidl "] + +[dependencies] +libc = "0.2" diff --git a/ph-init/src/main.rs b/ph-init/src/main.rs new file mode 100644 index 0000000..53667fc --- /dev/null +++ b/ph-init/src/main.rs @@ -0,0 +1,123 @@ +extern crate libc; + +use std::env; +use std::io; +use std::process::{self, Child,Command,Stdio}; + +mod sys; + +use sys::*; + +fn setup_overlay() -> io::Result<()> { + + // Just using /tmp temporarily as a path expected to exist + // pivot_root() call will move this tmpfs mount + mount_tmpfs("/tmp")?; + mkdir("/tmp/ro")?; + pivot_root("/tmp", "/tmp/ro")?; + + // Current layout: + // + // /ro real root fs is now mounted here + // / tmpfs has been swapped as / by pivot_root() + // + mkdir("/rw")?; + mount_tmpfs("/rw")?; + mkdir("/rw/upper")?; + mkdir("/rw/work")?; + + // Add this to current layout: + // + // /rw 2nd tmpfs mounted here + // /rw/upper empty dir on 2nd tmpfs + // /rw/work empty dir on 2nd tmpfs + + mkdir("/overlay")?; + mount_overlay("/overlay", "lowerdir=/ro,upperdir=/rw/upper,workdir=/rw/work")?; + mkdir("/overlay/ro")?; + mkdir("/overlay/rw")?; + mkdir("/overlay/old-root")?; + + // And this: + // + // /overlay overlay fs mounted here + // /overlay/ro empty dir + // /overlay/rw empty dir + // /overlay/old-root empty dir + + // About to pivot_root() to make /overlay new root fs. + // Move /ro and /rw to expected post-pivot location. + move_mount("/ro", "/overlay/ro")?; + move_mount("/rw", "/overlay/rw")?; + + // swap in overlay as rootfs + pivot_root("/overlay", "/overlay/old-root")?; + + // finally throw away 1st tmpfs + umount("/old-root")?; + rmdir("/old-root")?; + Ok(()) +} + +fn setup_mounts() -> io::Result<()> { + mount_sysfs("/sys")?; + mount_procfs("/proc")?; + mount_devtmpfs("/dev")?; + mkdir("/dev/pts")?; + mount_devpts("/dev/pts")?; + Ok(()) +} + +fn setup() -> io::Result<()> { + setup_overlay()?; + setup_mounts()?; + sethostname("Airwolf")?; + setsid()?; + set_controlling_tty(0, true)?; + Ok(()) +} + +fn run_shell() -> io::Result{ + Command::new("/bin/bash") + .env_clear() + .env("TERM", "xterm-256color") + .env("HOME", "/home/user") + .stdin(Stdio::inherit()) + .stdout(Stdio::inherit()) + .stderr(Stdio::inherit()) + .spawn() +} + +fn handle_waitpid_err(err: io::Error) -> ! { + if let Some(errno) = err.raw_os_error() { + if errno == libc::ECHILD { + if let Err(err) = reboot(libc::RB_AUTOBOOT) { + println!("reboot() failed: {:?}", err); + process::exit(-1); + } + } + } + println!("error on waitpid: {:?}", err); + process::exit(-1); +} + +fn wait_for_child() -> i32 { + let r = waitpid(-1, 0); + if let Ok(pid) = r { + return pid; + } + handle_waitpid_err(r.err().unwrap()); +} + +fn main() { + if let Err(err) = setup() { + println!("Error on setup(): {:?}", err); return; + } + let _child = match run_shell() { + Ok(child) => child, + Err(err) => { println!("Error launching shell: {:?}", err); return; } + }; + loop { + let _ = wait_for_child(); + } +} diff --git a/ph-init/src/sys.rs b/ph-init/src/sys.rs new file mode 100644 index 0000000..e226dfa --- /dev/null +++ b/ph-init/src/sys.rs @@ -0,0 +1,162 @@ +use std::io; +use std::ptr; +use std::ffi::{CString,OsStr}; +use std::os::unix::ffi::OsStrExt; + +use libc; + + +pub fn mount_tmpfs(target: &str) -> io::Result<()> { + mount("tmpfs", target, "tmpfs", 0, Some("mode=755")) +} + +pub fn mount_procfs(target: &str) -> io::Result<()> { + mount("proc", target, "proc", 0, None) +} + +pub fn mount_sysfs(target: &str) -> io::Result<()> { + mount("sysfs", target, "sysfs", 0, None) +} + +pub fn mount_devtmpfs(target: &str) -> io::Result<()> { + mount("devtmpfs", target, "devtmpfs", 0, None) +} + +pub fn mount_devpts(target: &str) -> io::Result<()> { + mount("devpts", target, "devpts", 0, None) +} + +pub fn mount_overlay(target: &str, args: &str) -> io::Result<()> { + mount("overlay", target, "overlay", 0, Some(args)) +} + +pub fn move_mount(source: &str, target: &str) -> io::Result<()> { + mount(source, target, "", libc::MS_MOVE, None) +} + + +fn cstr(s: &str) -> CString { + CString::new(s).unwrap() +} + + +pub fn mkdir(path: &str) -> io::Result<()> { + + let path = cstr(path); + unsafe { + if libc::mkdir(path.as_ptr(), 0o755) == -1 { + return Err(io::Error::last_os_error()); + } + } + Ok(()) +} + +pub fn rmdir(path: &str) -> io::Result<()> { + let path = cstr(path); + unsafe { + if libc::rmdir(path.as_ptr()) == -1 { + return Err(io::Error::last_os_error()); + } + } + Ok(()) + +} + +pub fn sethostname>(name: S) -> io::Result<()> { + let ptr = name.as_ref().as_bytes().as_ptr() as *const libc::c_char; + let len = name.as_ref().len() as libc::size_t; + unsafe { + if libc::sethostname(ptr, len) < 0 { + return Err(io::Error::last_os_error()); + } + } + Ok(()) +} + +pub fn setsid() -> io::Result { + unsafe { + let res = libc::setsid(); + if res == -1 { + return Err(io::Error::last_os_error()); + } + Ok(res as u32) + } +} + +fn mount(source: &str, target: &str, fstype: &str, flags: u64, data: Option<&str>) + -> io::Result<()> where { + + let source = cstr(source); + let target = cstr(target); + let fstype = cstr(fstype); + + + let data = data.map(|s| cstr(s) ); + let data_ptr = match data { + Some(ref s) => s.as_ptr(), + None => ptr::null(), + }; + + unsafe { + if libc::mount(source.as_ptr(), + target.as_ptr(), + fstype.as_ptr(), + flags, + data_ptr as *const libc::c_void) == -1 { + return Err(io::Error::last_os_error()); + } + } + Ok(()) +} + +pub fn pivot_root(new_root: &str, put_old: &str) -> io::Result<()> { + let new_root = cstr(new_root); + let put_old = cstr(put_old); + unsafe { + if libc::syscall(libc::SYS_pivot_root, new_root.as_ptr(), put_old.as_ptr()) == -1 { + return Err(io::Error::last_os_error()); + } + } + Ok(()) +} + +pub fn umount(path: &str) -> io::Result<()> { + let path = cstr(path); + unsafe { + if libc::umount(path.as_ptr()) == -1 { + return Err(io::Error::last_os_error()); + } + } + Ok(()) +} + +pub fn set_controlling_tty(fd: libc::c_int, force: bool) -> io::Result<()> { + let flag: libc::c_int = if force { 1 } else { 0 }; + unsafe { + if libc::ioctl(fd, libc::TIOCSCTTY, flag) == -1 { + return Err(io::Error::last_os_error()); + } + Ok(()) + } +} + +pub fn waitpid(pid: libc::pid_t, options: libc::c_int) -> io::Result { + let mut status = 0 as libc::c_int; + unsafe { + if libc::waitpid(pid, &mut status, options) == -1 { + return Err(io::Error::last_os_error()); + } + } + Ok(status) +} + +pub fn reboot(cmd: libc::c_int) -> io::Result<()> { + unsafe { + if libc::reboot(cmd) == -1 { + return Err(io::Error::last_os_error()); + } + Ok(()) + } + + +} \ No newline at end of file