Commit 860fb85f authored by SamwiseFilmore's avatar SamwiseFilmore

WIP: Allow legacy to run; Fix error handling; Docs

parent f2c9980b
Pipeline #2279 failed with stage
in 2 minutes
use std::collections::HashMap;
use failure::{Error, err_msg};
use generational_arena::Index;
use dependency_graph::DepGraph;
use service::{Service, State};
pub fn graph_from_services(mut services: Vec<Service>) -> DepGraph<Service> {
pub fn graph_from_services(services: Vec<Service>) -> DepGraph<Service> {
let mut graph = DepGraph::with_capacity(services.len());
graph_add_services(&mut graph, services);
graph
}
pub fn graph_add_services(graph: &mut DepGraph<Service>, mut services: Vec<Service>) {
let services: HashMap<String, Index> = services.drain(..)
.map(|service| (service.name.clone(), graph.insert(service)) )
.collect();
......@@ -31,10 +34,9 @@ pub fn graph_from_services(mut services: Vec<Service>) -> DepGraph<Service> {
}
}
}
graph
}
pub fn start_services(mut graph: DepGraph<Service>, provide_hooks: HashMap<String, impl Fn()>) -> Result<(), Error> {
pub fn start_services(mut graph: DepGraph<Service>, provide_hooks: HashMap<String, impl Fn()>) {
let resolved = graph.linear_resolve();
for index in resolved.iter() {
......@@ -43,10 +45,12 @@ pub fn start_services(mut graph: DepGraph<Service>, provide_hooks: HashMap<Strin
.expect("resolved service index did not exist");
if let Some(method) = service.methods.get("start") {
method.wait();
if !service.state.is_running() {
method.wait();
}
} else {
let msg = format!("service {} missing 'start' method", service.name);
return Err(err_msg(msg));
error!("service {} missing 'start' method", service.name);
service.state = State::Failed;
}
//TODO: Better solution to this
......@@ -61,5 +65,4 @@ pub fn start_services(mut graph: DepGraph<Service>, provide_hooks: HashMap<Strin
}
}
}
Ok(())
}
......@@ -2,6 +2,8 @@ use std::collections::HashSet;
use generational_arena::{Arena, Index};
/// A container struct that allows for a
/// nice abstraction of a dependency graph
struct Node<T> {
inner: T,
dependencies: Vec<Index>
......@@ -29,32 +31,38 @@ impl<T> Node<T> {
}
/// A sorta thin wrapper over a Generational arena that includes
/// dependency resolution and traversal methods
/// dependency relationships between nodes and some solvers
pub struct DepGraph<T> {
graph: Arena<Node<T>>
}
impl<T> DepGraph<T> {
/// Wrapper over `generational_arena::Arena::with_capacity`
pub fn with_capacity(n: usize) -> DepGraph<T> {
DepGraph {
graph: Arena::with_capacity(n)
}
}
/// Add an element to the graph, returning an index to the element
pub fn insert(&mut self, inner: T) -> Index {
self.graph.insert(Node::new(inner))
}
/// Get an immutable borrow of an element by index if it exists
pub fn get(&self, indx: Index) -> Option<&T> {
self.graph.get(indx)
.map(|node| node.get_inner() )
}
/// Get a mutable borrow of an element by index, if it exists
pub fn get_mut(&mut self, indx: Index) -> Option<&mut T> {
self.graph.get_mut(indx)
.map(|node| node.get_mut_inner() )
}
/// Remove an element from the graph by index, returning
/// the value if it exists
pub fn remove(&mut self, indx: Index) -> Option<T> {
self.graph.remove(indx)
.map(|node| node.unwrap() )
......
......@@ -67,7 +67,11 @@ pub fn run(file: &Path) -> Result<()> {
Ok(list) => for entry_res in list {
match entry_res {
Ok(entry) => {
entries.push(entry.path());
let path = entry.path();
// Ignore .toml service files
if let None = path.extension() {
entries.push(path);
}
},
Err(err) => {
println!("init: failed to run.d: '{}': {}", new_dir, err);
......
......@@ -17,7 +17,7 @@ mod service;
use std::collections::HashMap;
use std::env;
use std::fs::File;
use std::fs::{self, File};
use std::io::{Error, Result};
use std::os::unix::io::{AsRawFd, FromRawFd};
use std::path::Path;
......@@ -51,39 +51,51 @@ pub fn main() {
println!("init: failed to start logger: {}", err);
});
let services = services("initfs:/etc/init.d")
.unwrap_or_else(|err| {
warn!("{}", err);
vec![]
});
let services = graph_from_services(services);
let mut provide_hooks: HashMap<_, fn()> = HashMap::with_capacity(2);
provide_hooks.insert("file:".into(), || {
info!("setting cwd to file:");
if let Err(err) = env::set_current_dir("file:") {
error!("failed to set cwd: {}", err);
}
info!("setting PATH=file:/bin");
env::set_var("PATH", "file:/bin");
// This file has had the services removed now
if let Err(err) = legacy::run(&Path::new("initfs:etc/init.rc")) {
error!("failed to run initfs:etc/init.rc: {}", err);
}
});
provide_hooks.insert("display:".into(), || {
switch_stdio("display:1")
.unwrap_or_else(|err| {
warn!("{}", err);
});
});
info!("setting PATH=initfs:/bin");
env::set_var("PATH", "initfs:/bin");
start_services(services, provide_hooks).expect("failed to start services");
// This way we can continue to support old systems that still have init.rc
if let Err(_) = fs::metadata("initfs:/etc/init.rc") {
if let Err(err) = legacy::run(&Path::new("initfs:etc/init.rc")) {
error!("failed to run initfs:etc/init.rc: {}", err);
}
} else {
let service_list = services("initfs:/etc/init.d")
.unwrap_or_else(|err| {
warn!("{}", err);
vec![]
});
let service_graph = graph_from_services(service_list);
let mut provide_hooks = HashMap::with_capacity(2);
provide_hooks.insert("file:".into(), || {
info!("setting cwd to file:");
if let Err(err) = env::set_current_dir("file:") {
error!("failed to set cwd: {}", err);
}
info!("setting PATH=file:/bin");
env::set_var("PATH", "file:/bin");
let fs_services = services("/etc/init.d")
.unwrap_or_else(|err| {
warn!("{}", err);
vec![]
});
dependency::graph_add_services(&mut service_graph, fs_services);
start_services(service_graph, HashMap::new());
});
provide_hooks.insert("display:".into(), || {
switch_stdio("display:1")
.unwrap_or_else(|err| {
warn!("{}", err);
});
});
info!("setting PATH=initfs:/bin");
env::set_var("PATH", "initfs:/bin");
start_services(service_graph, provide_hooks);
}
syscall::setrens(0, 0).expect("init: failed to enter null namespace");
......
......@@ -17,6 +17,16 @@ pub enum State {
Failed
}
impl State {
pub fn is_running(&self) -> bool {
match self {
State::Offline => false,
State::Online => true,
State::Failed => false
}
}
}
impl Default for State {
fn default() -> State { State::Offline }
}
......@@ -49,6 +59,7 @@ impl Method {
pub fn wait(&self) {
let mut cmd = Command::new(&self.cmd[0]);
cmd.args(self.cmd[1..].iter());
info!("waiting on service method start: {:?}", cmd);
match cmd.spawn() {
Ok(mut child) => match child.wait() {
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment