An init daemon written in rust to replace kernel/init/init.c

This commit is contained in:
Bruce Leidl 2017-10-18 19:09:14 +00:00
parent babd7c6585
commit 42070f7532
4 changed files with 306 additions and 0 deletions

14
ph-init/Cargo.lock generated Normal file
View File

@ -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"

7
ph-init/Cargo.toml Normal file
View File

@ -0,0 +1,7 @@
[package]
name = "ph-init"
version = "0.1.0"
authors = ["Bruce Leidl <bruce@subgraph.com>"]
[dependencies]
libc = "0.2"

123
ph-init/src/main.rs Normal file
View File

@ -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<Child>{
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();
}
}

162
ph-init/src/sys.rs Normal file
View File

@ -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<S: AsRef<OsStr>>(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<u32> {
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<i32> {
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(())
}
}