Some refactorings to prepare the switch from calling a lambda function from the forked process to reinvoking the whole process with the job description as json

This commit is contained in:
Johannes Leupolz 2025-12-17 21:12:53 +00:00
parent 364b86a190
commit d86a90e2b1
13 changed files with 125 additions and 46 deletions

View file

@ -13,8 +13,6 @@ use std::mem::{self, size_of, zeroed};
use std::os::fd::AsRawFd;
use std::os::raw::{c_char, c_void};
use std::ptr;
use std::thread::sleep;
use std::time::Duration;
pub use uinput_ioctls::*;
// Constants (same numeric values as in linux headers)

View file

@ -27,3 +27,5 @@ futures = "0.3.31"
async-io = "2.6.0"
anyhow = "1.0.100"
clap = { version = "4", features = ["derive"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"

View file

@ -0,0 +1,27 @@
// SPDX-License-Identifier: MIT
//
// Author: Johannes Leupolz <dev@leupolz.eu>
use serde::{Serialize, Deserialize};
#[derive(Serialize,Deserialize)]
#[serde(tag = "action")]
pub enum Action {
#[serde(rename = "mknod-device")]
MknodDevice {
path: String,
major: u32,
minor: u32,
mode: u32,
},
#[serde(rename = "announce-via-netlink")]
AnnounceViaNetlink {
message: String,
},
#[serde(rename = "remove-device")]
RemoveDevice {
path: String,
},
}

View file

@ -0,0 +1,30 @@
// SPDX-License-Identifier: MIT
//
// Author: Johannes Leupolz <dev@leupolz.eu>
use super::action::Action;
pub fn handle_cli_action(json: String) -> i32 {
let action: Action = serde_json::from_str(&json)
.expect("invalid action JSON");
handle_action(action).unwrap_or_else(|err|
{
panic!("Error handling action: {}",err);
});
0
}
fn handle_action(action: Action) -> Result<(), String> {
match action {
Action::MknodDevice { .. } => {
Ok(())
}
Action::AnnounceViaNetlink { .. } => {
Ok(())
}
Action::RemoveDevice { .. } => {
Ok(())
}
}
}

View file

@ -0,0 +1,9 @@
// SPDX-License-Identifier: MIT
//
// Author: Johannes Leupolz <dev@leupolz.eu>
pub mod action;
pub mod handle_action;
pub mod mknod_input_device;
pub mod netlink_message;
pub mod runtime_data;

View file

@ -5,7 +5,7 @@
use std::future::Future;
use std::pin::Pin;
use crate::job_engine::job::{Dispatcher, Job, JobTarget};
use super::job::{Job, JobTarget};
pub struct ClosureJob {
desc: String,
@ -55,34 +55,40 @@ impl Job for ClosureJob {
}
}
/// Example usage
#[test]
pub fn example() {
let mut dispatcher = Dispatcher::new();
#[cfg(test)]
mod tests {
use super::super::job::{Dispatcher, JobTarget};
use super::ClosureJob;
// Send a Host job
dispatcher.dispatch(Box::new(ClosureJob::new(
"Host maintenance",
JobTarget::Host,
false,
Box::new(|job: &ClosureJob| {
let target = job.target.clone();
Box::pin(async move {
println!("Running host job on {:?}", target);
})
}),
)));
/// Example usage
#[test]
pub fn example() {
let mut dispatcher = Dispatcher::new();
// Sending a Container job works the same
// dispatcher.dispatch(Job::new(JobTarget::Container(ns.clone()), "Container task", false, |target| async move {
// println!("Running container job for {:?}", target);
// }));
// Send a Host job
dispatcher.dispatch(Box::new(ClosureJob::new(
"Host maintenance",
JobTarget::Host,
false,
Box::new(|job: &ClosureJob| {
let target = job.target.clone();
Box::pin(async move {
println!("Running host job on {:?}", target);
})
}),
)));
//
// JOB_DISPATCHER.get().unwrap().lock().unwrap().dispatch(Box::new(ClosureJob::new("Monitor udev events", JobTarget::BackgroundLoop,false,
// Box::new(move |_target| Box::pin(monitor_udev::udev_monitor_loop(cancel_token.clone()))))));
// Sending a Container job works the same
// dispatcher.dispatch(Job::new(JobTarget::Container(ns.clone()), "Container task", false, |target| async move {
// println!("Running container job for {:?}", target);
// }));
// Allow loops to run briefly before dropping all senders -> graceful shutdown
dispatcher.close();
dispatcher.wait_until_finished();
//
// JOB_DISPATCHER.get().unwrap().lock().unwrap().dispatch(Box::new(ClosureJob::new("Monitor udev events", JobTarget::BackgroundLoop,false,
// Box::new(move |_target| Box::pin(monitor_udev::udev_monitor_loop(cancel_token.clone()))))));
// Allow loops to run briefly before dropping all senders -> graceful shutdown
dispatcher.close();
dispatcher.wait_until_finished();
}
}

View file

@ -14,14 +14,7 @@ use async_io::Timer;
use log::debug;
use crate::{
job_engine::job::{Job, JobTarget},
jobs::{
mknod_input_device::ensure_input_device,
monitor_udev_job::EVENT_STORE,
netlink_message::send_udev_monitor_message_with_properties,
runtime_data::{ensure_udev_structure, read_udev_data, write_udev_data},
},
process_tools::{await_process, run_in_net_and_mnt_namespace, Pid, RequestingProcess},
actions::{mknod_input_device::ensure_input_device, netlink_message::send_udev_monitor_message_with_properties, runtime_data::{ensure_udev_structure, read_udev_data, write_udev_data}}, job_engine::job::{Job, JobTarget}, jobs::monitor_udev_job::EVENT_STORE, process_tools::{Pid, RequestingProcess, await_process, run_in_net_and_mnt_namespace}
};
#[derive(Clone, Debug, Copy, PartialOrd, PartialEq)]

View file

@ -3,8 +3,5 @@
// Author: Johannes Leupolz <dev@leupolz.eu>
pub mod inject_in_container_job;
pub mod mknod_input_device;
pub mod monitor_udev_job;
pub mod netlink_message;
pub mod remove_from_container_job;
pub mod runtime_data;

View file

@ -11,12 +11,7 @@ use std::{
use log::debug;
use crate::{
job_engine::job::{Job, JobTarget},
jobs::{
mknod_input_device::remove_input_device, monitor_udev_job::EVENT_STORE,
netlink_message::send_udev_monitor_message_with_properties, runtime_data::delete_udev_data,
},
process_tools::{await_process, run_in_net_and_mnt_namespace, Pid, RequestingProcess},
actions::{mknod_input_device::remove_input_device, netlink_message::send_udev_monitor_message_with_properties, runtime_data::delete_udev_data}, job_engine::job::{Job, JobTarget}, jobs::monitor_udev_job::EVENT_STORE, process_tools::{Pid, RequestingProcess, await_process, run_in_net_and_mnt_namespace}
};
#[derive(Clone, Debug, Copy, PartialOrd, PartialEq)]

View file

@ -37,6 +37,8 @@ pub mod job_engine;
use crate::job_engine::{job::*, JOB_DISPATCHER};
use crate::process_tools::*;
pub mod actions;
pub mod jobs;
use clap::Parser;
@ -58,9 +60,24 @@ struct Args {
/// Device name (without /dev/)
#[arg(long)]
devname: Option<String>,
/// Action to execute (JSON encoded). Note that this excludes all other options.
#[arg(long, value_name = "JSON")]
pub action: Option<String>,
}
fn validate_args(args: &Args) -> Result<(), String> {
// action might only occur alone
match (&args.major,&args.minor,&args.devname,&args.action) {
(None,None,None,Some(_)) => {},
(_,_,_,None) => {},
_ => {
return Err(
"--action must not be used in combination with any other argument".into(),
);
}
}
// major/minor must appear together
match (&args.major, &args.minor) {
(Some(_), Some(_)) | (None, None) => {}
@ -97,6 +114,11 @@ fn main() -> std::io::Result<()> {
std::process::exit(2);
}
if args.action.is_some() {
let error_code=actions::handle_action::handle_cli_action(args.action.unwrap());
std::process::exit(error_code);
}
initialize_vuinput_state();
VUINPUT_COUNTER.set(AtomicU64::new(3)).expect(