mirror of
https://github.com/joleuger/vuinputd.git
synced 2026-07-17 16:36:03 +00:00
Start implementation of --placement on-host. Not complete and no automated tests, yet. #1
This commit is contained in:
parent
b4c6c32431
commit
6bde733b09
13 changed files with 193 additions and 99 deletions
|
|
@ -126,8 +126,9 @@ on your container setup and isolation model.
|
|||
#### `--placement on-host`
|
||||
|
||||
* Device nodes and udev runtime data are created **on the host** under:
|
||||
* `/run/vuinputd/{devname}/dev`
|
||||
* `/run/vuinputd/{devname}/udev/data`
|
||||
* `/run/vuinputd/{devname}/dev-input`
|
||||
* `/run/vuinputd/{devname}/udev`
|
||||
* `/run/vuinputd/{devname}/dev-input` **must** have the mount option `dev`
|
||||
* The user is expected to **bind-mount these directories** into the container
|
||||
* Suitable for:
|
||||
* read-only containers
|
||||
|
|
|
|||
|
|
@ -16,14 +16,18 @@ pub enum Action {
|
|||
minor: u64,
|
||||
},
|
||||
|
||||
#[serde(rename = "emit-udev-event")]
|
||||
EmitUdevEvent {
|
||||
netlink_message: HashMap<String, String>,
|
||||
#[serde(rename = "write-udev-runtime-data")]
|
||||
WriteUdevRuntimeData {
|
||||
runtime_data: Option<String>,
|
||||
major: u64,
|
||||
minor: u64,
|
||||
},
|
||||
|
||||
#[serde(rename = "emit-netlink-message")]
|
||||
EmitNetlinkMessage {
|
||||
netlink_message: HashMap<String, String>,
|
||||
},
|
||||
|
||||
#[serde(rename = "remove-device")]
|
||||
RemoveDevice {
|
||||
path: String,
|
||||
|
|
|
|||
|
|
@ -21,20 +21,22 @@ fn handle_action(action: Action) -> anyhow::Result<()> {
|
|||
input_device::ensure_input_device(path, major.into(), minor.into())?;
|
||||
Ok(())
|
||||
}
|
||||
Action::EmitUdevEvent {
|
||||
netlink_message,
|
||||
Action::WriteUdevRuntimeData {
|
||||
runtime_data,
|
||||
major,
|
||||
minor,
|
||||
} => {
|
||||
netlink_message::send_udev_monitor_message_with_properties(netlink_message);
|
||||
runtime_data::ensure_udev_structure()?;
|
||||
runtime_data::ensure_udev_structure("/run",true)?;
|
||||
match runtime_data {
|
||||
Some(data) => runtime_data::write_udev_data(&data, major.into(), minor.into())?,
|
||||
None => runtime_data::delete_udev_data(major.into(), minor.into())?,
|
||||
Some(data) => runtime_data::write_udev_data("/run",&data, major.into(), minor.into())?,
|
||||
None => runtime_data::delete_udev_data("/run",major.into(), minor.into())?,
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
Action::EmitNetlinkMessage { netlink_message } => {
|
||||
netlink_message::send_udev_monitor_message_with_properties(netlink_message);
|
||||
Ok(())
|
||||
}
|
||||
Action::RemoveDevice { path, major, minor } => {
|
||||
input_device::remove_input_device(path, major.into(), minor.into())?;
|
||||
Ok(())
|
||||
|
|
|
|||
|
|
@ -9,11 +9,13 @@ use std::path::Path;
|
|||
use log::{info, warn};
|
||||
|
||||
/// Ensure required udev directories and files exist
|
||||
pub fn ensure_udev_structure() -> io::Result<()> {
|
||||
pub fn ensure_udev_structure(path_prefix: &str, warn_if_nonexistent: bool) -> io::Result<()> {
|
||||
// Note that this structure _must_ exist, before a service using libinput is run. The time of device creation might be too late.
|
||||
|
||||
let data_dir = Path::new("/run/udev/data");
|
||||
let control_file = Path::new("/run/udev/control");
|
||||
let data_dir = format!("{}/udev/data", path_prefix);
|
||||
let data_dir = Path::new(&data_dir);
|
||||
let control_file = format!("{}/udev/control", path_prefix);
|
||||
let control_file = Path::new(&control_file);
|
||||
|
||||
// Create directory like `mkdir -p`
|
||||
if !data_dir.exists() {
|
||||
|
|
@ -42,7 +44,7 @@ pub fn ensure_udev_structure() -> io::Result<()> {
|
|||
/// - remove all lines containing `seat_` references (G:, Q: lines)
|
||||
/// - replace ID_VUINPUT_* with ID_INPUT_*
|
||||
/// - write updated content to `/run/udev/data/c<major>:<minor>`
|
||||
pub fn write_udev_data(content: &str, major: u64, minor: u64) -> io::Result<()> {
|
||||
pub fn write_udev_data(path_prefix: &str, content: &str, major: u64, minor: u64) -> io::Result<()> {
|
||||
let mut cleaned = String::new();
|
||||
|
||||
for line in content.lines() {
|
||||
|
|
@ -60,7 +62,7 @@ pub fn write_udev_data(content: &str, major: u64, minor: u64) -> io::Result<()>
|
|||
cleaned.push('\n');
|
||||
}
|
||||
|
||||
let path = format!("/run/udev/data/c{}:{}", major, minor);
|
||||
let path = format!("{}/udev/data/c{}:{}", path_prefix, major, minor);
|
||||
let mut file = File::create(&path)?;
|
||||
file.write_all(cleaned.as_bytes())?;
|
||||
|
||||
|
|
@ -69,8 +71,8 @@ pub fn write_udev_data(content: &str, major: u64, minor: u64) -> io::Result<()>
|
|||
|
||||
/// Delete udev data for a given major/minor number
|
||||
/// - `major`, `minor` = device numbers
|
||||
pub fn delete_udev_data(major: u64, minor: u64) -> io::Result<()> {
|
||||
let path = format!("/run/udev/data/c{}:{}", major, minor);
|
||||
pub fn delete_udev_data(path_prefix: &str, major: u64, minor: u64) -> io::Result<()> {
|
||||
let path = format!("{}/udev/data/c{}:{}", path_prefix, major, minor);
|
||||
fs::remove_file(&path)?;
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -61,10 +61,10 @@ pub fn is_allowed(keytracker: &mut KeyTracker, policy: &DevicePolicy, event: &in
|
|||
}
|
||||
}
|
||||
|
||||
fn is_allowed_in_mute_sysrq(keytracker: &mut KeyTracker, event: &input_event) -> bool {
|
||||
fn is_allowed_in_mute_sysrq(_keytracker: &mut KeyTracker, event: &input_event) -> bool {
|
||||
if event.type_ == EV_KEY && event.code == KEY_SYSRQ {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -13,9 +13,9 @@ use uinput_ioctls::*;
|
|||
|
||||
use crate::cuse_device::{get_vuinput_state, VuFileHandle};
|
||||
use crate::job_engine::JOB_DISPATCHER;
|
||||
use crate::jobs::emit_udev_event_in_container_job::EmitUdevEventInContainerJob;
|
||||
use crate::jobs::mknod_device_in_container_job::MknodDeviceInContainerJob;
|
||||
use crate::jobs::remove_from_container_job::RemoveFromContainerJob;
|
||||
use crate::jobs::emit_udev_event_job::EmitUdevEventJob;
|
||||
use crate::jobs::mknod_device_job::MknodDeviceJob;
|
||||
use crate::jobs::remove_device_job::RemoveDeviceJob;
|
||||
use crate::process_tools::SELF_NAMESPACES;
|
||||
use crate::{cuse_device::*, jobs};
|
||||
|
||||
|
|
@ -164,7 +164,7 @@ pub unsafe extern "C" fn vuinput_ioctl(
|
|||
CStr::from_ptr(resultbuf.as_ptr()).to_string_lossy()
|
||||
);
|
||||
debug!("fh {}: syspath: {}", fh, sysname);
|
||||
let devnode = fetch_device_node(&sysname).unwrap();
|
||||
let (devname, devnode) = fetch_device_node(&sysname).unwrap();
|
||||
debug!("fh {}: devnode: {}", fh, devnode);
|
||||
let (major, minor) = fetch_major_minor(&devnode).unwrap();
|
||||
debug!("fh {}: major: {} minor: {} ", fh, major, minor);
|
||||
|
|
@ -181,9 +181,9 @@ pub unsafe extern "C" fn vuinput_ioctl(
|
|||
.unwrap()
|
||||
.equal_mnt_and_net(&vuinput_state.requesting_process.namespaces)
|
||||
{
|
||||
let mknod_job = MknodDeviceInContainerJob::new(
|
||||
let mknod_job = MknodDeviceJob::new(
|
||||
vuinput_state.requesting_process.clone(),
|
||||
devnode.clone(),
|
||||
devname.clone(),
|
||||
sysname.clone(),
|
||||
major,
|
||||
minor,
|
||||
|
|
@ -195,12 +195,12 @@ pub unsafe extern "C" fn vuinput_ioctl(
|
|||
.lock()
|
||||
.unwrap()
|
||||
.dispatch(Box::new(mknod_job));
|
||||
awaiter(&jobs::mknod_device_in_container_job::State::Finished);
|
||||
awaiter(&jobs::mknod_device_job::State::Finished);
|
||||
debug!("fh {}: mknod_device in container has been finished ", fh);
|
||||
fuse_lowlevel::fuse_reply_ioctl(_req, 0, std::ptr::null(), 0);
|
||||
|
||||
// we do not wait for the udev stuff
|
||||
let emit_udev_event_job = EmitUdevEventInContainerJob::new(
|
||||
let emit_udev_event_job = EmitUdevEventJob::new(
|
||||
vuinput_state.requesting_process.clone(),
|
||||
devnode.clone(),
|
||||
sysname.clone(),
|
||||
|
|
@ -229,7 +229,7 @@ pub unsafe extern "C" fn vuinput_ioctl(
|
|||
.equal_mnt_and_net(&vuinput_state.requesting_process.namespaces)
|
||||
{
|
||||
let input_device = input_device.unwrap();
|
||||
let remove_job = RemoveFromContainerJob::new(
|
||||
let remove_job = RemoveDeviceJob::new(
|
||||
vuinput_state.requesting_process.clone(),
|
||||
input_device.devnode.clone(),
|
||||
input_device.syspath.clone(),
|
||||
|
|
@ -243,7 +243,7 @@ pub unsafe extern "C" fn vuinput_ioctl(
|
|||
.lock()
|
||||
.unwrap()
|
||||
.dispatch(Box::new(remove_job));
|
||||
awaiter(&jobs::remove_from_container_job::State::Finished);
|
||||
awaiter(&jobs::remove_device_job::State::Finished);
|
||||
debug!(
|
||||
"fh {}: removing dev-nodes from container has been finished ",
|
||||
fh
|
||||
|
|
@ -415,12 +415,12 @@ pub unsafe extern "C" fn vuinput_ioctl(
|
|||
}
|
||||
}
|
||||
|
||||
pub fn fetch_device_node(path: &str) -> io::Result<String> {
|
||||
pub fn fetch_device_node(path: &str) -> io::Result<(String, String)> {
|
||||
for entry in fs::read_dir(path)? {
|
||||
let entry = entry?; // propagate per-entry errors
|
||||
if let Some(name) = entry.file_name().to_str() {
|
||||
if name.starts_with("event") {
|
||||
return Ok(format!("/dev/input/{}", name));
|
||||
return Ok((name.to_string(), format!("/dev/input/{}", name)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
// Author: Johannes Leupolz <dev@leupolz.eu>
|
||||
|
||||
use crate::job_engine::JOB_DISPATCHER;
|
||||
use crate::jobs::remove_from_container_job::RemoveFromContainerJob;
|
||||
use crate::jobs::remove_device_job::{self, RemoveDeviceJob};
|
||||
use crate::process_tools::SELF_NAMESPACES;
|
||||
use crate::{cuse_device::*, jobs};
|
||||
use ::cuse_lowlevel::*;
|
||||
|
|
@ -32,7 +32,7 @@ pub unsafe extern "C" fn vuinput_release(
|
|||
.equal_mnt_and_net(&vuinput_state.requesting_process.namespaces)
|
||||
{
|
||||
let input_device = input_device.unwrap();
|
||||
let remove_job = RemoveFromContainerJob::new(
|
||||
let remove_job = RemoveDeviceJob::new(
|
||||
vuinput_state.requesting_process.clone(),
|
||||
input_device.devnode.clone(),
|
||||
input_device.syspath.clone(),
|
||||
|
|
@ -46,7 +46,7 @@ pub unsafe extern "C" fn vuinput_release(
|
|||
.lock()
|
||||
.unwrap()
|
||||
.dispatch(Box::new(remove_job));
|
||||
awaiter(&jobs::remove_from_container_job::State::Finished);
|
||||
awaiter(&jobs::remove_device_job::State::Finished);
|
||||
}
|
||||
|
||||
drop(vuinput_state);
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ use std::sync::OnceLock;
|
|||
pub struct GlobalConfig {
|
||||
pub policy: DevicePolicy,
|
||||
pub placement: Placement,
|
||||
pub devname: String,
|
||||
}
|
||||
|
||||
// The actual static variable. It starts empty and is set once in main().
|
||||
|
|
@ -33,18 +34,23 @@ pub enum DevicePolicy {
|
|||
pub enum Placement {
|
||||
#[default]
|
||||
/// Create inside the container
|
||||
Inject,
|
||||
InContainer,
|
||||
/// Create on the host (user is expected to bind-mount)
|
||||
Host,
|
||||
/// Do not create any artifacts
|
||||
OnHost,
|
||||
/// Do not create any artifacts (netlink message in container is unaffected)
|
||||
None,
|
||||
}
|
||||
|
||||
pub fn initialize_global_config(device_policy: &DevicePolicy, placement: &Placement) {
|
||||
pub fn initialize_global_config(
|
||||
device_policy: &DevicePolicy,
|
||||
placement: &Placement,
|
||||
devname: &Option<String>,
|
||||
) {
|
||||
if CONFIG
|
||||
.set(GlobalConfig {
|
||||
policy: device_policy.clone(),
|
||||
placement: placement.clone(),
|
||||
devname: devname.clone().unwrap_or("vuinput".to_string()),
|
||||
})
|
||||
.is_err()
|
||||
{
|
||||
|
|
@ -60,3 +66,7 @@ pub fn get_device_policy<'a>() -> &'a DevicePolicy {
|
|||
pub fn get_placement<'a>() -> &'a Placement {
|
||||
&CONFIG.get().unwrap().placement
|
||||
}
|
||||
|
||||
pub fn get_devname<'a>() -> &'a String {
|
||||
&CONFIG.get().unwrap().devname
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,7 +14,12 @@ use async_io::Timer;
|
|||
use log::debug;
|
||||
|
||||
use crate::{
|
||||
actions::{action::Action, runtime_data::read_udev_data},
|
||||
actions::{
|
||||
self,
|
||||
action::Action,
|
||||
runtime_data::{self, read_udev_data},
|
||||
},
|
||||
global_config::{self, get_placement, Placement},
|
||||
job_engine::job::{Job, JobTarget},
|
||||
jobs::monitor_udev_job::EVENT_STORE,
|
||||
process_tools::{self, await_process, Pid, RequestingProcess},
|
||||
|
|
@ -28,7 +33,7 @@ pub enum State {
|
|||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct EmitUdevEventInContainerJob {
|
||||
pub struct EmitUdevEventJob {
|
||||
requesting_process: RequestingProcess,
|
||||
target: JobTarget,
|
||||
dev_path: String,
|
||||
|
|
@ -38,7 +43,7 @@ pub struct EmitUdevEventInContainerJob {
|
|||
sync_state: Arc<(Mutex<State>, Condvar)>,
|
||||
}
|
||||
|
||||
impl EmitUdevEventInContainerJob {
|
||||
impl EmitUdevEventJob {
|
||||
pub fn new(
|
||||
requesting_process: RequestingProcess,
|
||||
dev_path: String,
|
||||
|
|
@ -79,7 +84,7 @@ impl EmitUdevEventInContainerJob {
|
|||
}
|
||||
}
|
||||
|
||||
impl Job for EmitUdevEventInContainerJob {
|
||||
impl Job for EmitUdevEventJob {
|
||||
fn desc(&self) -> &str {
|
||||
"emit udev event into container"
|
||||
}
|
||||
|
|
@ -88,8 +93,8 @@ impl Job for EmitUdevEventInContainerJob {
|
|||
false
|
||||
}
|
||||
|
||||
fn create_task(self: &EmitUdevEventInContainerJob) -> Pin<Box<dyn Future<Output = ()>>> {
|
||||
Box::pin(self.clone().inject_in_container())
|
||||
fn create_task(self: &EmitUdevEventJob) -> Pin<Box<dyn Future<Output = ()>>> {
|
||||
Box::pin(self.clone().emit_udev_event())
|
||||
}
|
||||
|
||||
fn job_target(&self) -> JobTarget {
|
||||
|
|
@ -97,8 +102,8 @@ impl Job for EmitUdevEventInContainerJob {
|
|||
}
|
||||
}
|
||||
|
||||
impl EmitUdevEventInContainerJob {
|
||||
async fn inject_in_container(self) {
|
||||
impl EmitUdevEventJob {
|
||||
async fn emit_udev_event(self) {
|
||||
// temporary hack that needs to be replaced. We try 50 times
|
||||
// Should be: Wait for the device to be created, the runtime data to be written and the
|
||||
// netlink message to be sent
|
||||
|
|
@ -144,18 +149,46 @@ impl EmitUdevEventInContainerJob {
|
|||
let runtime_data = runtime_data.unwrap();
|
||||
let netlink_data = netlink_data.unwrap();
|
||||
|
||||
let emit_udev_event_action = Action::EmitUdevEvent {
|
||||
match get_placement() {
|
||||
Placement::InContainer => {
|
||||
let write_udev_runtime_data = Action::WriteUdevRuntimeData {
|
||||
runtime_data: Some(runtime_data),
|
||||
major: self.major,
|
||||
minor: self.minor,
|
||||
};
|
||||
|
||||
let child_pid =
|
||||
process_tools::start_action(write_udev_runtime_data, &self.requesting_process)
|
||||
.expect("subprocess should work");
|
||||
|
||||
let _exit_info = await_process(Pid::Pid(child_pid)).await.unwrap();
|
||||
}
|
||||
Placement::OnHost => {
|
||||
let path_prefix = format!("/run/vuinputd/{}", global_config::get_devname());
|
||||
runtime_data::write_udev_data(
|
||||
&path_prefix,
|
||||
&runtime_data,
|
||||
self.major.into(),
|
||||
self.minor.into(),
|
||||
)
|
||||
.expect(&format!(
|
||||
"VUI-UDEV-002: could not write into {}",
|
||||
&path_prefix
|
||||
)); //TODO: somewhat costly
|
||||
}
|
||||
Placement::None => {}
|
||||
}
|
||||
|
||||
// this is always in the container
|
||||
let emit_netlink_message = Action::EmitNetlinkMessage {
|
||||
netlink_message: netlink_data.clone(),
|
||||
runtime_data: Some(runtime_data),
|
||||
major: self.major,
|
||||
minor: self.minor,
|
||||
};
|
||||
|
||||
let child_pid =
|
||||
process_tools::start_action(emit_udev_event_action, &self.requesting_process)
|
||||
.expect("subprocess should work");
|
||||
let child_pid = process_tools::start_action(emit_netlink_message, &self.requesting_process)
|
||||
.expect("subprocess should work");
|
||||
|
||||
let _exit_info = await_process(Pid::Pid(child_pid)).await.unwrap();
|
||||
|
||||
self.set_state(&State::Finished);
|
||||
}
|
||||
}
|
||||
|
|
@ -9,11 +9,14 @@ use std::{
|
|||
};
|
||||
|
||||
use crate::{
|
||||
actions::action::Action,
|
||||
actions::{action::Action, input_device},
|
||||
global_config::{self, Placement},
|
||||
job_engine::job::{Job, JobTarget},
|
||||
process_tools::{self, await_process, Pid, RequestingProcess},
|
||||
};
|
||||
|
||||
use crate::actions::runtime_data::write_udev_data;
|
||||
|
||||
#[derive(Clone, Debug, Copy, PartialOrd, PartialEq)]
|
||||
pub enum State {
|
||||
Initialized,
|
||||
|
|
@ -22,20 +25,20 @@ pub enum State {
|
|||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct MknodDeviceInContainerJob {
|
||||
pub struct MknodDeviceJob {
|
||||
requesting_process: RequestingProcess,
|
||||
target: JobTarget,
|
||||
dev_path: String,
|
||||
devname: String,
|
||||
sys_path: String,
|
||||
major: u64,
|
||||
minor: u64,
|
||||
sync_state: Arc<(Mutex<State>, Condvar)>,
|
||||
}
|
||||
|
||||
impl MknodDeviceInContainerJob {
|
||||
impl MknodDeviceJob {
|
||||
pub fn new(
|
||||
requesting_process: RequestingProcess,
|
||||
dev_path: String,
|
||||
devname: String,
|
||||
sys_path: String,
|
||||
major: u64,
|
||||
minor: u64,
|
||||
|
|
@ -43,7 +46,7 @@ impl MknodDeviceInContainerJob {
|
|||
Self {
|
||||
requesting_process: requesting_process.clone(),
|
||||
target: JobTarget::Container(requesting_process),
|
||||
dev_path: dev_path,
|
||||
devname: devname,
|
||||
sys_path: sys_path,
|
||||
major: major,
|
||||
minor: minor,
|
||||
|
|
@ -73,7 +76,7 @@ impl MknodDeviceInContainerJob {
|
|||
}
|
||||
}
|
||||
|
||||
impl Job for MknodDeviceInContainerJob {
|
||||
impl Job for MknodDeviceJob {
|
||||
fn desc(&self) -> &str {
|
||||
"mknod input device in container"
|
||||
}
|
||||
|
|
@ -82,8 +85,8 @@ impl Job for MknodDeviceInContainerJob {
|
|||
false
|
||||
}
|
||||
|
||||
fn create_task(self: &MknodDeviceInContainerJob) -> Pin<Box<dyn Future<Output = ()>>> {
|
||||
Box::pin(self.clone().inject_in_container())
|
||||
fn create_task(self: &MknodDeviceJob) -> Pin<Box<dyn Future<Output = ()>>> {
|
||||
Box::pin(self.clone().mknod_device())
|
||||
}
|
||||
|
||||
fn job_target(&self) -> JobTarget {
|
||||
|
|
@ -91,18 +94,35 @@ impl Job for MknodDeviceInContainerJob {
|
|||
}
|
||||
}
|
||||
|
||||
impl MknodDeviceInContainerJob {
|
||||
async fn inject_in_container(self) {
|
||||
let mknod_device_action = Action::MknodDevice {
|
||||
path: self.dev_path.clone(),
|
||||
major: self.major,
|
||||
minor: self.minor,
|
||||
};
|
||||
impl MknodDeviceJob {
|
||||
async fn mknod_device(self) {
|
||||
match global_config::get_placement() {
|
||||
Placement::InContainer => {
|
||||
let mknod_device_action = Action::MknodDevice {
|
||||
path: format!("/dev/input/{}", &self.devname),
|
||||
major: self.major,
|
||||
minor: self.minor,
|
||||
};
|
||||
|
||||
let child_pid = process_tools::start_action(mknod_device_action, &self.requesting_process)
|
||||
.expect("subprocess should work");
|
||||
let child_pid =
|
||||
process_tools::start_action(mknod_device_action, &self.requesting_process)
|
||||
.expect("subprocess should work");
|
||||
|
||||
let _exit_info = await_process(Pid::Pid(child_pid)).await.unwrap();
|
||||
}
|
||||
Placement::OnHost => {
|
||||
let path = format!(
|
||||
"/run/vuinputd/{}/dev-input/{}",
|
||||
global_config::get_devname(),
|
||||
self.devname
|
||||
);
|
||||
input_device::ensure_input_device(path.clone(), self.major, self.minor)
|
||||
.expect(&format!("VUI-DEV-001: could not create {}", &path));
|
||||
//TODO: somewhat costly
|
||||
}
|
||||
Placement::None => {}
|
||||
}
|
||||
|
||||
let _exit_info = await_process(Pid::Pid(child_pid)).await.unwrap();
|
||||
self.set_state(&State::Finished);
|
||||
}
|
||||
}
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
//
|
||||
// Author: Johannes Leupolz <dev@leupolz.eu>
|
||||
|
||||
pub mod emit_udev_event_in_container_job;
|
||||
pub mod mknod_device_in_container_job;
|
||||
pub mod emit_udev_event_job;
|
||||
pub mod mknod_device_job;
|
||||
pub mod monitor_udev_job;
|
||||
pub mod remove_from_container_job;
|
||||
pub mod remove_device_job;
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ use log::debug;
|
|||
|
||||
use crate::{
|
||||
actions::action::Action,
|
||||
global_config::{self, Placement},
|
||||
job_engine::job::{Job, JobTarget},
|
||||
jobs::monitor_udev_job::EVENT_STORE,
|
||||
process_tools::{self, await_process, Pid, RequestingProcess},
|
||||
|
|
@ -25,7 +26,7 @@ pub enum State {
|
|||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct RemoveFromContainerJob {
|
||||
pub struct RemoveDeviceJob {
|
||||
requesting_process: RequestingProcess,
|
||||
target: JobTarget,
|
||||
dev_path: String,
|
||||
|
|
@ -35,7 +36,7 @@ pub struct RemoveFromContainerJob {
|
|||
sync_state: Arc<(Mutex<State>, Condvar)>,
|
||||
}
|
||||
|
||||
impl RemoveFromContainerJob {
|
||||
impl RemoveDeviceJob {
|
||||
pub fn new(
|
||||
requesting_process: RequestingProcess,
|
||||
dev_path: String,
|
||||
|
|
@ -75,7 +76,7 @@ impl RemoveFromContainerJob {
|
|||
}
|
||||
}
|
||||
|
||||
impl Job for RemoveFromContainerJob {
|
||||
impl Job for RemoveDeviceJob {
|
||||
fn desc(&self) -> &str {
|
||||
"Remove input device from container"
|
||||
}
|
||||
|
|
@ -84,8 +85,8 @@ impl Job for RemoveFromContainerJob {
|
|||
false
|
||||
}
|
||||
|
||||
fn create_task(self: &RemoveFromContainerJob) -> Pin<Box<dyn Future<Output = ()>>> {
|
||||
Box::pin(self.clone().remove_from_container())
|
||||
fn create_task(self: &RemoveDeviceJob) -> Pin<Box<dyn Future<Output = ()>>> {
|
||||
Box::pin(self.clone().remove_device())
|
||||
}
|
||||
|
||||
fn job_target(&self) -> JobTarget {
|
||||
|
|
@ -93,8 +94,8 @@ impl Job for RemoveFromContainerJob {
|
|||
}
|
||||
}
|
||||
|
||||
impl RemoveFromContainerJob {
|
||||
async fn remove_from_container(self) {
|
||||
impl RemoveDeviceJob {
|
||||
async fn remove_device(self) {
|
||||
self.set_state(&State::Started);
|
||||
|
||||
let netlink_event = match EVENT_STORE
|
||||
|
|
@ -124,29 +125,50 @@ impl RemoveFromContainerJob {
|
|||
|
||||
let _ = netlink_data.insert("ACTION".to_string(), "remove".to_string());
|
||||
|
||||
let remove_device_action = Action::RemoveDevice {
|
||||
path: dev_path.clone(),
|
||||
major: self.major,
|
||||
minor: self.minor,
|
||||
};
|
||||
match global_config::get_placement() {
|
||||
Placement::InContainer => {
|
||||
let remove_device_action = Action::RemoveDevice {
|
||||
path: dev_path.clone(),
|
||||
major: self.major,
|
||||
minor: self.minor,
|
||||
};
|
||||
|
||||
let child_pid_1 =
|
||||
process_tools::start_action(remove_device_action, &self.requesting_process)
|
||||
let child_pid_1 =
|
||||
process_tools::start_action(remove_device_action, &self.requesting_process)
|
||||
.expect("subprocess should work");
|
||||
|
||||
let write_udev_runtime_data_action = Action::WriteUdevRuntimeData {
|
||||
runtime_data: None,
|
||||
major: self.major,
|
||||
minor: self.minor,
|
||||
};
|
||||
|
||||
let child_pid_2 = process_tools::start_action(
|
||||
write_udev_runtime_data_action,
|
||||
&self.requesting_process,
|
||||
)
|
||||
.expect("subprocess should work");
|
||||
|
||||
let emit_udev_event_action = Action::EmitUdevEvent {
|
||||
let _exit_info = await_process(Pid::Pid(child_pid_1)).await;
|
||||
let _exit_info = await_process(Pid::Pid(child_pid_2)).await;
|
||||
}
|
||||
Placement::OnHost => {
|
||||
todo!();
|
||||
}
|
||||
Placement::None => {}
|
||||
}
|
||||
|
||||
// this is always in the container
|
||||
let emit_netlink_message = Action::EmitNetlinkMessage {
|
||||
netlink_message: netlink_data.clone(),
|
||||
runtime_data: None,
|
||||
major: self.major,
|
||||
minor: self.minor,
|
||||
};
|
||||
|
||||
let child_pid_2 =
|
||||
process_tools::start_action(emit_udev_event_action, &self.requesting_process)
|
||||
let child_pid_netlink =
|
||||
process_tools::start_action(emit_netlink_message, &self.requesting_process)
|
||||
.expect("subprocess should work");
|
||||
|
||||
let _exit_info = await_process(Pid::Pid(child_pid_1)).await;
|
||||
let _exit_info = await_process(Pid::Pid(child_pid_2)).await;
|
||||
let _exit_info = await_process(Pid::Pid(child_pid_netlink)).await;
|
||||
|
||||
self.set_state(&State::Finished);
|
||||
}
|
||||
}
|
||||
|
|
@ -191,7 +191,7 @@ fn main() -> std::io::Result<()> {
|
|||
check_permissions().expect("failed to read the capabilities of the vuinputd process");
|
||||
vt_tools::check_vt_status();
|
||||
|
||||
global_config::initialize_global_config(&args.device_policy, &args.placement);
|
||||
global_config::initialize_global_config(&args.device_policy, &args.placement, &args.devname);
|
||||
initialize_vuinput_state();
|
||||
VUINPUT_COUNTER.set(AtomicU64::new(3)).expect(
|
||||
"failed to initialize the counter that provides the values of the CUSE file handles",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue