An init daemon written in rust to replace kernel/init/init.c
This commit is contained in:
parent
babd7c6585
commit
42070f7532
14
ph-init/Cargo.lock
generated
Normal file
14
ph-init/Cargo.lock
generated
Normal 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
7
ph-init/Cargo.toml
Normal 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
123
ph-init/src/main.rs
Normal 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
162
ph-init/src/sys.rs
Normal 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(())
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user