init: Introduce Service type
A future commit will use it to define services in toml format.
This commit is contained in:
+9
-55
@@ -9,6 +9,7 @@ use libredox::flag::{O_RDONLY, O_WRONLY};
|
|||||||
use crate::script::Command;
|
use crate::script::Command;
|
||||||
|
|
||||||
mod script;
|
mod script;
|
||||||
|
mod service;
|
||||||
|
|
||||||
fn switch_stdio(stdio: &str) -> Result<()> {
|
fn switch_stdio(stdio: &str) -> Result<()> {
|
||||||
let stdin = libredox::Fd::open(stdio, O_RDONLY, 0)?;
|
let stdin = libredox::Fd::open(stdio, O_RDONLY, 0)?;
|
||||||
@@ -101,64 +102,17 @@ fn run_command(cmd: Command, config: &mut InitConfig) {
|
|||||||
eprintln!("init: failed to switch stdio to '{}': {}", stdio, err);
|
eprintln!("init: failed to switch stdio to '{}': {}", stdio, err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Command::Nowait(cmd) => {
|
Command::Service(service) => {
|
||||||
if config.skip_cmd.contains(&cmd.cmd) {
|
if config.skip_cmd.contains(&service.cmd) {
|
||||||
eprintln!("init: skipping '{} {}'", cmd.cmd, cmd.args.join(" "));
|
eprintln!(
|
||||||
|
"init: skipping '{} {}'",
|
||||||
|
service.cmd,
|
||||||
|
service.args.join(" ")
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut command = cmd.into_command(&config.envs);
|
service.spawn(&config.envs);
|
||||||
|
|
||||||
match command.spawn() {
|
|
||||||
Ok(_child) => {}
|
|
||||||
Err(err) => eprintln!("init: failed to execute '{:?}': {}", command, err),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Command::Notify(cmd) => {
|
|
||||||
if config.skip_cmd.contains(&cmd.cmd) {
|
|
||||||
eprintln!("init: skipping '{} {}'", cmd.cmd, cmd.args.join(" "));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let command = cmd.into_command(&config.envs);
|
|
||||||
|
|
||||||
daemon::Daemon::spawn(command);
|
|
||||||
}
|
|
||||||
Command::Scheme(scheme, cmd) => {
|
|
||||||
if config.skip_cmd.contains(&cmd.cmd) {
|
|
||||||
eprintln!("init: skipping '{} {}'", cmd.cmd, cmd.args.join(" "));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let command = cmd.into_command(&config.envs);
|
|
||||||
|
|
||||||
daemon::SchemeDaemon::spawn(command, &scheme);
|
|
||||||
}
|
|
||||||
Command::Regular(cmd) => {
|
|
||||||
if config.skip_cmd.contains(&cmd.cmd) {
|
|
||||||
eprintln!("init: skipping '{} {}'", cmd.cmd, cmd.args.join(" "));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut command = cmd.into_command(&config.envs);
|
|
||||||
|
|
||||||
let mut child = match command.spawn() {
|
|
||||||
Ok(child) => child,
|
|
||||||
Err(err) => {
|
|
||||||
eprintln!("init: failed to execute {:?}: {}", command, err);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
match child.wait() {
|
|
||||||
Ok(exit_status) => {
|
|
||||||
if !exit_status.success() {
|
|
||||||
eprintln!("{command:?} failed with {exit_status}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(err) => {
|
|
||||||
eprintln!("init: failed to wait for {:?}: {}", command, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+45
-22
@@ -1,7 +1,8 @@
|
|||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
use std::ffi::OsString;
|
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::{env, fs, io, iter, process};
|
use std::{env, fs, io, iter};
|
||||||
|
|
||||||
|
use crate::service::{Service, ServiceType};
|
||||||
|
|
||||||
fn subst_env<'a>(arg: &str) -> String {
|
fn subst_env<'a>(arg: &str) -> String {
|
||||||
if arg.starts_with('$') {
|
if arg.starts_with('$') {
|
||||||
@@ -39,10 +40,7 @@ impl Script {
|
|||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Command {
|
pub enum Command {
|
||||||
// Service
|
// Service
|
||||||
Nowait(Process),
|
Service(Service),
|
||||||
Notify(Process),
|
|
||||||
Scheme(String, Process),
|
|
||||||
Regular(Process),
|
|
||||||
|
|
||||||
// Modify env
|
// Modify env
|
||||||
Stdio(String),
|
Stdio(String),
|
||||||
@@ -79,18 +77,50 @@ impl Command {
|
|||||||
};
|
};
|
||||||
Ok(Command::Stdio(stdio))
|
Ok(Command::Stdio(stdio))
|
||||||
}
|
}
|
||||||
"nowait" => Ok(Command::Nowait(Process::parse(args)?)),
|
"notify" => {
|
||||||
"notify" => Ok(Command::Notify(Process::parse(args)?)),
|
let process = Process::parse(args)?;
|
||||||
|
|
||||||
|
Ok(Command::Service(Service {
|
||||||
|
cmd: process.cmd,
|
||||||
|
args: process.args,
|
||||||
|
envs: process.envs,
|
||||||
|
type_: ServiceType::Notify,
|
||||||
|
}))
|
||||||
|
}
|
||||||
"scheme" => {
|
"scheme" => {
|
||||||
let Some(scheme) = args.next() else {
|
let Some(scheme) = args.next() else {
|
||||||
return Err("init: failed to run scheme: no argument".to_owned());
|
return Err("init: failed to run scheme: no argument".to_owned());
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(Command::Scheme(scheme, Process::parse(args)?))
|
let process = Process::parse(args)?;
|
||||||
|
|
||||||
|
Ok(Command::Service(Service {
|
||||||
|
cmd: process.cmd,
|
||||||
|
args: process.args,
|
||||||
|
envs: process.envs,
|
||||||
|
type_: ServiceType::Scheme(scheme),
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
"nowait" => {
|
||||||
|
let process = Process::parse(args)?;
|
||||||
|
|
||||||
|
Ok(Command::Service(Service {
|
||||||
|
cmd: process.cmd,
|
||||||
|
args: process.args,
|
||||||
|
envs: process.envs,
|
||||||
|
type_: ServiceType::OneshotAsync,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
let process = Process::parse(iter::once(cmd).chain(args))?;
|
||||||
|
|
||||||
|
Ok(Command::Service(Service {
|
||||||
|
cmd: process.cmd,
|
||||||
|
args: process.args,
|
||||||
|
envs: process.envs,
|
||||||
|
type_: ServiceType::Oneshot,
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
_ => Ok(Command::Regular(Process::parse(
|
|
||||||
iter::once(cmd).chain(args),
|
|
||||||
)?)),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -99,14 +129,14 @@ impl Command {
|
|||||||
pub struct Process {
|
pub struct Process {
|
||||||
pub cmd: String,
|
pub cmd: String,
|
||||||
pub args: Vec<String>,
|
pub args: Vec<String>,
|
||||||
pub envs: Vec<(String, String)>,
|
pub envs: BTreeMap<String, String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Process {
|
impl Process {
|
||||||
fn parse(parts: impl Iterator<Item = String>) -> Result<Process, String> {
|
fn parse(parts: impl Iterator<Item = String>) -> Result<Process, String> {
|
||||||
let mut cmd = None;
|
let mut cmd = None;
|
||||||
let mut args = vec![];
|
let mut args = vec![];
|
||||||
let mut envs = vec![];
|
let mut envs = BTreeMap::new();
|
||||||
|
|
||||||
for arg in parts {
|
for arg in parts {
|
||||||
if cmd.is_none() {
|
if cmd.is_none() {
|
||||||
@@ -117,7 +147,7 @@ impl Process {
|
|||||||
subst_env(value)
|
subst_env(value)
|
||||||
};
|
};
|
||||||
if !value.is_empty() {
|
if !value.is_empty() {
|
||||||
envs.push((env.to_owned(), value));
|
envs.insert(env.to_owned(), value);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
cmd = Some(arg);
|
cmd = Some(arg);
|
||||||
@@ -133,11 +163,4 @@ impl Process {
|
|||||||
Err("no command given".to_owned())
|
Err("no command given".to_owned())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn into_command(self, base_envs: &BTreeMap<String, OsString>) -> process::Command {
|
|
||||||
let mut command = process::Command::new(self.cmd);
|
|
||||||
command.args(self.args);
|
|
||||||
command.env_clear().envs(base_envs).envs(self.envs);
|
|
||||||
command
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,60 @@
|
|||||||
|
use std::collections::BTreeMap;
|
||||||
|
use std::ffi::OsString;
|
||||||
|
use std::process::Command;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Service {
|
||||||
|
pub cmd: String,
|
||||||
|
pub args: Vec<String>,
|
||||||
|
pub envs: BTreeMap<String, String>,
|
||||||
|
pub type_: ServiceType,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Default)]
|
||||||
|
pub enum ServiceType {
|
||||||
|
#[default]
|
||||||
|
Notify,
|
||||||
|
Scheme(String),
|
||||||
|
Oneshot,
|
||||||
|
OneshotAsync,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Service {
|
||||||
|
pub fn spawn(self, base_envs: &BTreeMap<String, OsString>) {
|
||||||
|
let mut command = Command::new(self.cmd);
|
||||||
|
command.args(self.args);
|
||||||
|
command.env_clear().envs(base_envs).envs(self.envs);
|
||||||
|
|
||||||
|
match self.type_ {
|
||||||
|
ServiceType::Notify => {
|
||||||
|
daemon::Daemon::spawn(command);
|
||||||
|
}
|
||||||
|
ServiceType::Scheme(scheme) => {
|
||||||
|
daemon::SchemeDaemon::spawn(command, &scheme);
|
||||||
|
}
|
||||||
|
ServiceType::Oneshot => {
|
||||||
|
let mut child = match command.spawn() {
|
||||||
|
Ok(child) => child,
|
||||||
|
Err(err) => {
|
||||||
|
eprintln!("init: failed to execute {:?}: {}", command, err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
match child.wait() {
|
||||||
|
Ok(exit_status) => {
|
||||||
|
if !exit_status.success() {
|
||||||
|
eprintln!("{command:?} failed with {exit_status}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
eprintln!("init: failed to wait for {:?}: {}", command, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ServiceType::OneshotAsync => match command.spawn() {
|
||||||
|
Ok(_child) => {}
|
||||||
|
Err(err) => eprintln!("init: failed to execute '{:?}': {}", command, err),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+1
-1
@@ -15,7 +15,7 @@ impl SchemeSync for ZeroScheme {
|
|||||||
fn openat(
|
fn openat(
|
||||||
&mut self,
|
&mut self,
|
||||||
dirfd: usize,
|
dirfd: usize,
|
||||||
path: &str,
|
_path: &str,
|
||||||
_flags: usize,
|
_flags: usize,
|
||||||
_fcntl_flags: u32,
|
_fcntl_flags: u32,
|
||||||
_ctx: &CallerCtx,
|
_ctx: &CallerCtx,
|
||||||
|
|||||||
Reference in New Issue
Block a user