Merge branch 'init_rework9' into 'main'
Some preparations for parallel service spawning See merge request redox-os/base!218
This commit is contained in:
Generated
+3
-1
@@ -1085,8 +1085,10 @@ name = "init"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"config",
|
||||
"daemon",
|
||||
"libc",
|
||||
"libredox",
|
||||
"plain",
|
||||
"redox_syscall 0.7.3",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"toml",
|
||||
|
||||
+2
-49
@@ -55,6 +55,8 @@ impl Daemon {
|
||||
}
|
||||
|
||||
/// Executes `Command` as a child process.
|
||||
// FIXME remove once the service spawning of hwd and pcid-spawner is moved to init
|
||||
#[deprecated]
|
||||
pub fn spawn(mut cmd: Command) {
|
||||
let (mut read_pipe, write_pipe) = io::pipe().unwrap();
|
||||
|
||||
@@ -124,53 +126,4 @@ impl SchemeDaemon {
|
||||
let cap_fd = socket.create_this_scheme_fd(0, cap_id, 0, 0)?;
|
||||
self.ready_with_fd(Fd::new(cap_fd))
|
||||
}
|
||||
|
||||
/// Executes `Command` as a child process registering it to the scheme namespace.
|
||||
pub fn spawn(mut cmd: Command, scheme_name: &str) {
|
||||
let (read_pipe, write_pipe) = io::pipe().unwrap();
|
||||
|
||||
unsafe { pass_fd(&mut cmd, "INIT_NOTIFY", write_pipe.into()) };
|
||||
|
||||
if let Err(err) = cmd.spawn() {
|
||||
eprintln!("daemon: failed to execute {cmd:?}: {err}");
|
||||
return;
|
||||
}
|
||||
|
||||
let mut new_fd = usize::MAX;
|
||||
let fd_bytes = unsafe {
|
||||
core::slice::from_raw_parts_mut(
|
||||
core::slice::from_mut(&mut new_fd).as_mut_ptr() as *mut u8,
|
||||
core::mem::size_of::<usize>(),
|
||||
)
|
||||
};
|
||||
loop {
|
||||
match syscall::call_ro(
|
||||
read_pipe.as_raw_fd() as usize,
|
||||
fd_bytes,
|
||||
syscall::CallFlags::FD | syscall::CallFlags::FD_UPPER,
|
||||
&[],
|
||||
) {
|
||||
Err(syscall::Error {
|
||||
errno: syscall::EINTR,
|
||||
}) => continue,
|
||||
Ok(0) => {
|
||||
eprintln!("daemon: {cmd:?} exited without notifying readiness");
|
||||
return;
|
||||
}
|
||||
Ok(1) => break,
|
||||
Ok(n) => {
|
||||
eprintln!("daemon: incorrect amount of fds {n} returned");
|
||||
return;
|
||||
}
|
||||
Err(err) => {
|
||||
eprintln!("daemon: failed to wait for {cmd:?}: {err}");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let current_namespace_fd = libredox::call::getns().expect("TODO");
|
||||
libredox::call::register_scheme_to_ns(current_namespace_fd, scheme_name, new_fd)
|
||||
.expect("TODO");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ impl Backend for AcpiBackend {
|
||||
|
||||
// Spawn acpid
|
||||
//TODO: pass rxsdt data to acpid?
|
||||
#[allow(deprecated, reason = "we can't yet move this to init")]
|
||||
daemon::Daemon::spawn(Command::new("acpid"));
|
||||
|
||||
Ok(Self { rxsdt })
|
||||
|
||||
@@ -37,6 +37,7 @@ fn daemon(daemon: daemon::Daemon) -> ! {
|
||||
|
||||
//TODO: launch pcid based on backend information?
|
||||
// Must launch after acpid but before probe calls /scheme/acpi/symbols
|
||||
#[allow(deprecated, reason = "we can't yet move this to init")]
|
||||
daemon::Daemon::spawn(process::Command::new("pcid"));
|
||||
|
||||
daemon.ready();
|
||||
|
||||
@@ -92,6 +92,7 @@ fn main() -> Result<()> {
|
||||
let channel_fd = handle.into_inner_fd();
|
||||
command.env("PCID_CLIENT_CHANNEL", channel_fd.to_string());
|
||||
|
||||
#[allow(deprecated, reason = "we can't yet move this to init")]
|
||||
daemon::Daemon::spawn(command);
|
||||
syscall::close(channel_fd as usize).unwrap();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
[unit]
|
||||
description = "Logger"
|
||||
default_dependencies = false
|
||||
|
||||
[service]
|
||||
cmd = "logd"
|
||||
type = { scheme = "log" }
|
||||
@@ -2,6 +2,7 @@
|
||||
description = "Services that relibc needs to function"
|
||||
default_dependencies = false
|
||||
requires_weak = [
|
||||
"00_logd.service",
|
||||
"00_nulld.service",
|
||||
"00_randd.service",
|
||||
"00_rtcd.service",
|
||||
+3
-1
@@ -6,13 +6,15 @@ edition = "2024"
|
||||
license = "MIT"
|
||||
|
||||
[dependencies]
|
||||
libc.workspace = true
|
||||
libredox.workspace = true
|
||||
plain.workspace = true
|
||||
redox_syscall.workspace = true
|
||||
serde.workspace = true
|
||||
serde_json.workspace = true
|
||||
toml.workspace = true
|
||||
|
||||
config = { path = "../config" }
|
||||
daemon = { path = "../daemon" }
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
+8
-8
@@ -137,20 +137,20 @@ fn main() {
|
||||
Path::new("/scheme/initfs/etc"),
|
||||
);
|
||||
|
||||
// Start logd first such that we can pass /scheme/log as stdio to all other services
|
||||
scheduler
|
||||
.schedule_start_and_report_errors(&mut unit_store, UnitId("00_logd.service".to_owned()));
|
||||
scheduler.step(&mut unit_store, &mut init_config);
|
||||
if let Err(err) = switch_stdio("/scheme/log") {
|
||||
eprintln!("init: failed to switch stdio to '/scheme/log': {err}");
|
||||
}
|
||||
|
||||
let runtime_target = UnitId("00_runtime.target".to_owned());
|
||||
scheduler.schedule_start_and_report_errors(&mut unit_store, runtime_target.clone());
|
||||
unit_store.set_runtime_target(runtime_target);
|
||||
|
||||
scheduler
|
||||
.schedule_start_and_report_errors(&mut unit_store, UnitId("90_initfs.target".to_owned()));
|
||||
|
||||
let mut command = std::process::Command::new("logd");
|
||||
command.env_clear().envs(&init_config.envs);
|
||||
daemon::SchemeDaemon::spawn(command, "log");
|
||||
if let Err(err) = switch_stdio("/scheme/log") {
|
||||
eprintln!("init: failed to switch stdio to '/scheme/log': {err}");
|
||||
}
|
||||
|
||||
scheduler.step(&mut unit_store, &mut init_config);
|
||||
|
||||
switch_root(
|
||||
|
||||
+70
-16
@@ -1,7 +1,10 @@
|
||||
use std::collections::{BTreeMap, BTreeSet};
|
||||
use std::env;
|
||||
use std::ffi::OsString;
|
||||
use std::io::Read;
|
||||
use std::os::fd::{AsRawFd, OwnedFd};
|
||||
use std::os::unix::process::CommandExt;
|
||||
use std::process::Command;
|
||||
use std::{env, io};
|
||||
|
||||
use serde::Deserialize;
|
||||
|
||||
@@ -43,21 +46,61 @@ impl Service {
|
||||
}
|
||||
command.envs(base_envs).envs(&self.envs);
|
||||
|
||||
match &self.type_ {
|
||||
ServiceType::Notify => {
|
||||
daemon::Daemon::spawn(command);
|
||||
let (mut read_pipe, write_pipe) = io::pipe().unwrap();
|
||||
unsafe { pass_fd(&mut command, "INIT_NOTIFY", write_pipe.into()) };
|
||||
|
||||
let mut child = match command.spawn() {
|
||||
Ok(child) => child,
|
||||
Err(err) => {
|
||||
eprintln!("init: failed to execute {:?}: {}", command, err);
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
match &self.type_ {
|
||||
ServiceType::Notify => match read_pipe.read_exact(&mut [0]) {
|
||||
Ok(()) => {}
|
||||
Err(err) if err.kind() == io::ErrorKind::UnexpectedEof => {
|
||||
eprintln!("init: {command:?} exited without notifying readiness");
|
||||
}
|
||||
Err(err) => {
|
||||
eprintln!("init: failed to wait for {command:?}: {err}");
|
||||
}
|
||||
},
|
||||
ServiceType::Scheme(scheme) => {
|
||||
daemon::SchemeDaemon::spawn(command, &scheme);
|
||||
let mut new_fd = usize::MAX;
|
||||
loop {
|
||||
match syscall::call_ro(
|
||||
read_pipe.as_raw_fd() as usize,
|
||||
unsafe { plain::as_mut_bytes(&mut new_fd) },
|
||||
syscall::CallFlags::FD | syscall::CallFlags::FD_UPPER,
|
||||
&[],
|
||||
) {
|
||||
Err(syscall::Error {
|
||||
errno: syscall::EINTR,
|
||||
}) => continue,
|
||||
Ok(0) => {
|
||||
eprintln!("init: {command:?} exited without notifying readiness");
|
||||
return;
|
||||
}
|
||||
Ok(1) => break,
|
||||
Ok(n) => {
|
||||
eprintln!("init: incorrect amount of fds {n} returned");
|
||||
return;
|
||||
}
|
||||
Err(err) => {
|
||||
eprintln!("init: failed to wait for {command:?}: {err}");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let current_namespace_fd = libredox::call::getns().expect("TODO");
|
||||
libredox::call::register_scheme_to_ns(current_namespace_fd, scheme, new_fd)
|
||||
.expect("TODO");
|
||||
}
|
||||
ServiceType::Oneshot => {
|
||||
let mut child = match command.spawn() {
|
||||
Ok(child) => child,
|
||||
Err(err) => {
|
||||
eprintln!("init: failed to execute {:?}: {}", command, err);
|
||||
return;
|
||||
}
|
||||
};
|
||||
drop(read_pipe);
|
||||
match child.wait() {
|
||||
Ok(exit_status) => {
|
||||
if !exit_status.success() {
|
||||
@@ -69,10 +112,21 @@ impl Service {
|
||||
}
|
||||
}
|
||||
}
|
||||
ServiceType::OneshotAsync => match command.spawn() {
|
||||
Ok(_child) => {}
|
||||
Err(err) => eprintln!("init: failed to execute '{:?}': {}", command, err),
|
||||
},
|
||||
ServiceType::OneshotAsync => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn pass_fd(cmd: &mut Command, env: &str, fd: OwnedFd) {
|
||||
cmd.env(env, format!("{}", fd.as_raw_fd()));
|
||||
unsafe {
|
||||
cmd.pre_exec(move || {
|
||||
// Pass notify pipe to child
|
||||
if libc::fcntl(fd.as_raw_fd(), libc::F_SETFD, 0) == -1 {
|
||||
Err(io::Error::last_os_error())
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user