mirror of
https://github.com/joleuger/vuinputd.git
synced 2026-07-17 16:36:03 +00:00
Implementation of the remove-device-step for --placement on-host. Not tested, yet
This commit is contained in:
parent
350a80644a
commit
fd55bffddb
13 changed files with 125 additions and 33 deletions
|
|
@ -24,6 +24,8 @@ Error messages may change over time; error codes do not.
|
|||
|------|------|--------|
|
||||
| VUI-UDEV-001 | udev | udev control socket not reachable |
|
||||
| VUI-UDEV-002 | udev | could not write into /run/vuinputd/... |
|
||||
| VUI-UDEV-003 | udev | could not remove udev data from ... |
|
||||
| VUI-DEV-001 | ddev | could not remove device node ... |
|
||||
|
||||
---
|
||||
|
||||
|
|
|
|||
|
|
@ -26,10 +26,12 @@ fn handle_action(action: Action) -> anyhow::Result<()> {
|
|||
major,
|
||||
minor,
|
||||
} => {
|
||||
runtime_data::ensure_udev_structure("/run",true)?;
|
||||
runtime_data::ensure_udev_structure()?;
|
||||
match runtime_data {
|
||||
Some(data) => runtime_data::write_udev_data("/run",&data, major.into(), minor.into())?,
|
||||
None => runtime_data::delete_udev_data("/run",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(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ pub struct VuInputDevice {
|
|||
pub major: u64,
|
||||
pub minor: u64,
|
||||
pub syspath: String,
|
||||
pub devname: String,
|
||||
pub devnode: String,
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -172,6 +172,7 @@ pub unsafe extern "C" fn vuinput_ioctl(
|
|||
major: major,
|
||||
minor: minor,
|
||||
syspath: sysname.clone(),
|
||||
devname: devname.clone(),
|
||||
devnode: devnode.clone(),
|
||||
});
|
||||
|
||||
|
|
@ -231,7 +232,7 @@ pub unsafe extern "C" fn vuinput_ioctl(
|
|||
let input_device = input_device.unwrap();
|
||||
let remove_job = RemoveDeviceJob::new(
|
||||
vuinput_state.requesting_process.clone(),
|
||||
input_device.devnode.clone(),
|
||||
input_device.devname.clone(),
|
||||
input_device.syspath.clone(),
|
||||
input_device.major,
|
||||
input_device.minor,
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
// Author: Johannes Leupolz <dev@leupolz.eu>
|
||||
|
||||
use crate::job_engine::JOB_DISPATCHER;
|
||||
use crate::jobs::remove_device_job::{self, RemoveDeviceJob};
|
||||
use crate::jobs::remove_device_job::RemoveDeviceJob;
|
||||
use crate::process_tools::SELF_NAMESPACES;
|
||||
use crate::{cuse_device::*, jobs};
|
||||
use ::cuse_lowlevel::*;
|
||||
|
|
@ -34,7 +34,7 @@ pub unsafe extern "C" fn vuinput_release(
|
|||
let input_device = input_device.unwrap();
|
||||
let remove_job = RemoveDeviceJob::new(
|
||||
vuinput_state.requesting_process.clone(),
|
||||
input_device.devnode.clone(),
|
||||
input_device.devname.clone(),
|
||||
input_device.syspath.clone(),
|
||||
input_device.major,
|
||||
input_device.minor,
|
||||
|
|
|
|||
|
|
@ -2,14 +2,14 @@
|
|||
//
|
||||
// Author: Johannes Leupolz <dev@leupolz.eu>
|
||||
|
||||
use clap::{Parser, ValueEnum};
|
||||
use clap::ValueEnum;
|
||||
use std::sync::OnceLock;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct GlobalConfig {
|
||||
pub policy: DevicePolicy,
|
||||
pub placement: Placement,
|
||||
pub devname: String,
|
||||
pub vudevname: String,
|
||||
}
|
||||
|
||||
// The actual static variable. It starts empty and is set once in main().
|
||||
|
|
@ -50,7 +50,7 @@ pub fn initialize_global_config(
|
|||
.set(GlobalConfig {
|
||||
policy: device_policy.clone(),
|
||||
placement: placement.clone(),
|
||||
devname: devname.clone().unwrap_or("vuinput".to_string()),
|
||||
vudevname: devname.clone().unwrap_or("vuinput".to_string()),
|
||||
})
|
||||
.is_err()
|
||||
{
|
||||
|
|
@ -67,6 +67,6 @@ pub fn get_placement<'a>() -> &'a Placement {
|
|||
&CONFIG.get().unwrap().placement
|
||||
}
|
||||
|
||||
pub fn get_devname<'a>() -> &'a String {
|
||||
&CONFIG.get().unwrap().devname
|
||||
pub fn get_vudevname<'a>() -> &'a String {
|
||||
&CONFIG.get().unwrap().vudevname
|
||||
}
|
||||
|
|
|
|||
80
vuinputd/src/input_realizer/host_fs.rs
Normal file
80
vuinputd/src/input_realizer/host_fs.rs
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
// SPDX-License-Identifier: MIT
|
||||
//
|
||||
// Author: Johannes Leupolz <dev@leupolz.eu>
|
||||
|
||||
use std::io::{self, BufRead};
|
||||
use std::{
|
||||
fs::{self, File},
|
||||
path::Path,
|
||||
};
|
||||
|
||||
/// Ensure required dev-input, udev directories and files exist
|
||||
pub fn ensure_host_fs_structure(path_prefix: &str) -> io::Result<()> {
|
||||
let _ = check_if_path_allows_char_devs(&path_prefix);
|
||||
let dev_input_dir = format!("{}/dev-input", path_prefix);
|
||||
let dev_input_dir = Path::new(&dev_input_dir);
|
||||
// Create directory like `mkdir -p`
|
||||
if !dev_input_dir.exists() {
|
||||
fs::create_dir_all(dev_input_dir)?;
|
||||
}
|
||||
|
||||
// Note that this structure _must_ exist, before a service using libinput is run.
|
||||
let data_dir = format!("{}/udev/data", path_prefix);
|
||||
let data_dir = Path::new(&data_dir);
|
||||
// Create directory like `mkdir -p`
|
||||
if !data_dir.exists() {
|
||||
fs::create_dir_all(data_dir)?;
|
||||
}
|
||||
|
||||
let control_file = format!("{}/udev/control", path_prefix);
|
||||
let control_file = Path::new(&control_file);
|
||||
// Ensure /run/udev/control exists, create empty if not
|
||||
if !control_file.exists() {
|
||||
File::create(control_file)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// simple heuristic that checks whether path_prefix allows the hosting of character devices
|
||||
/// This heuristic is not 100%, but a simple indicator
|
||||
pub fn check_if_path_allows_char_devs(path: &str) -> io::Result<()> {
|
||||
let file = File::open("/proc/self/mountinfo")?;
|
||||
let reader = io::BufReader::new(file);
|
||||
|
||||
for line in reader.lines() {
|
||||
let line = line?;
|
||||
|
||||
let (left, _) = match line.split_once(" - ") {
|
||||
Some(v) => v,
|
||||
None => continue,
|
||||
};
|
||||
|
||||
let fields: Vec<&str> = left.split_whitespace().collect();
|
||||
|
||||
// mount point is field 5
|
||||
let mount_point = fields.get(4).copied().unwrap_or("");
|
||||
// mount options are field 6
|
||||
let options = fields.get(5).copied().unwrap_or("");
|
||||
|
||||
if mount_point.contains(path) {
|
||||
if options.split(',').any(|o| o == "nodev") {
|
||||
log::warn!(
|
||||
"mount {} is present but mounted with nodev; device nodes will not work",
|
||||
path
|
||||
);
|
||||
} else {
|
||||
log::info!("mount {} is present and allows device nodes", path);
|
||||
}
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
|
||||
log::warn!(
|
||||
"expected mount {} not found; user likely forgot to mount tmpfs with dev-option on it",
|
||||
path
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
@ -2,6 +2,7 @@
|
|||
//
|
||||
// Author: Johannes Leupolz <dev@leupolz.eu>
|
||||
|
||||
pub mod host_fs;
|
||||
pub mod input_device;
|
||||
pub mod netlink_message;
|
||||
pub mod runtime_data;
|
||||
|
|
|
|||
|
|
@ -9,12 +9,12 @@ use std::path::Path;
|
|||
use log::{info, warn};
|
||||
|
||||
/// Ensure required udev directories and files exist
|
||||
pub fn ensure_udev_structure(path_prefix: &str, warn_if_nonexistent: bool) -> io::Result<()> {
|
||||
pub fn ensure_udev_structure() -> 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 = format!("{}/udev/data", path_prefix);
|
||||
let data_dir = format!("/run/udev/data");
|
||||
let data_dir = Path::new(&data_dir);
|
||||
let control_file = format!("{}/udev/control", path_prefix);
|
||||
let control_file = format!("/run/udev/control");
|
||||
let control_file = Path::new(&control_file);
|
||||
|
||||
// Create directory like `mkdir -p`
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ use async_io::Timer;
|
|||
use log::debug;
|
||||
|
||||
use crate::{
|
||||
actions::{self, action::Action},
|
||||
actions::action::Action,
|
||||
global_config::{self, get_placement, Placement},
|
||||
input_realizer::runtime_data,
|
||||
job_engine::job::{Job, JobTarget},
|
||||
|
|
@ -161,7 +161,7 @@ impl EmitUdevEventJob {
|
|||
let _exit_info = await_process(Pid::Pid(child_pid)).await.unwrap();
|
||||
}
|
||||
Placement::OnHost => {
|
||||
let path_prefix = format!("/run/vuinputd/{}", global_config::get_devname());
|
||||
let path_prefix = format!("/run/vuinputd/{}", global_config::get_vudevname());
|
||||
runtime_data::write_udev_data(
|
||||
&path_prefix,
|
||||
&runtime_data,
|
||||
|
|
|
|||
|
|
@ -16,8 +16,6 @@ use crate::{
|
|||
process_tools::{self, await_process, Pid, RequestingProcess},
|
||||
};
|
||||
|
||||
use crate::input_realizer::runtime_data::write_udev_data;
|
||||
|
||||
#[derive(Clone, Debug, Copy, PartialOrd, PartialEq)]
|
||||
pub enum State {
|
||||
Initialized,
|
||||
|
|
@ -112,11 +110,8 @@ impl MknodDeviceJob {
|
|||
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
|
||||
);
|
||||
let path_prefix = format!("/run/vuinputd/{}", global_config::get_vudevname());
|
||||
let path = format!("{}/dev-input/{}", path_prefix, 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
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ pub enum State {
|
|||
pub struct RemoveDeviceJob {
|
||||
requesting_process: RequestingProcess,
|
||||
target: JobTarget,
|
||||
dev_path: String,
|
||||
dev_name: String,
|
||||
sys_path: String,
|
||||
major: u64,
|
||||
minor: u64,
|
||||
|
|
@ -40,7 +40,7 @@ pub struct RemoveDeviceJob {
|
|||
impl RemoveDeviceJob {
|
||||
pub fn new(
|
||||
requesting_process: RequestingProcess,
|
||||
dev_path: String,
|
||||
dev_name: String,
|
||||
sys_path: String,
|
||||
major: u64,
|
||||
minor: u64,
|
||||
|
|
@ -48,7 +48,7 @@ impl RemoveDeviceJob {
|
|||
Self {
|
||||
requesting_process: requesting_process.clone(),
|
||||
target: JobTarget::Container(requesting_process),
|
||||
dev_path: dev_path,
|
||||
dev_name: dev_name,
|
||||
sys_path: sys_path,
|
||||
major: major,
|
||||
minor: minor,
|
||||
|
|
@ -122,14 +122,14 @@ impl RemoveDeviceJob {
|
|||
let netlink_data = netlink_event.add_data;
|
||||
|
||||
let mut netlink_data = netlink_data.unwrap().clone();
|
||||
let dev_path = self.dev_path.clone();
|
||||
|
||||
let _ = netlink_data.insert("ACTION".to_string(), "remove".to_string());
|
||||
|
||||
match global_config::get_placement() {
|
||||
Placement::InContainer => {
|
||||
let dev_path = format!("/dev/input/{}", &self.dev_name);
|
||||
let remove_device_action = Action::RemoveDevice {
|
||||
path: dev_path.clone(),
|
||||
path: dev_path,
|
||||
major: self.major,
|
||||
minor: self.minor,
|
||||
};
|
||||
|
|
@ -154,9 +154,17 @@ impl RemoveDeviceJob {
|
|||
let _exit_info = await_process(Pid::Pid(child_pid_2)).await;
|
||||
}
|
||||
Placement::OnHost => {
|
||||
todo!();
|
||||
//input_device::remove_input_device(path, major.into(), minor.into())?;
|
||||
//runtime_data::delete_udev_data("/run",major.into(), minor.into())?;
|
||||
let path_prefix = format!("/run/vuinputd/{}", global_config::get_vudevname());
|
||||
let devnode = format!("{}/dev-input/{}", path_prefix, self.dev_name);
|
||||
input_device::remove_input_device(devnode.clone(), self.major, self.minor).expect(
|
||||
&format!("VUI-DEV-003: could not remove device node {}", &devnode),
|
||||
);
|
||||
runtime_data::delete_udev_data(&path_prefix, self.major, self.minor).expect(
|
||||
&format!(
|
||||
"VUI-UDEV-003: could not remove udev data from {}",
|
||||
&path_prefix
|
||||
),
|
||||
);
|
||||
}
|
||||
Placement::None => {}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ use crate::cuse_device::state::{initialize_dedup_last_error, initialize_vuinput_
|
|||
use crate::cuse_device::vuinput_make_cuse_ops;
|
||||
use crate::cuse_device::vuinput_open::VUINPUT_COUNTER;
|
||||
use crate::global_config::{DevicePolicy, Placement};
|
||||
use crate::input_realizer::host_fs;
|
||||
use crate::jobs::monitor_udev_job::MonitorBackgroundLoop;
|
||||
|
||||
pub mod process_tools;
|
||||
|
|
@ -219,8 +220,9 @@ fn main() -> std::io::Result<()> {
|
|||
None => "vuinput",
|
||||
Some(devname) => devname,
|
||||
};
|
||||
if args.placement==Placement::OnHost {
|
||||
todo!("ensure structure and writablity of dev-input")
|
||||
if args.placement == Placement::OnHost {
|
||||
let path_prefix = format!("/run/vuinputd/{}", global_config::get_vudevname());
|
||||
let _ = host_fs::ensure_host_fs_structure(&path_prefix);
|
||||
}
|
||||
|
||||
let vuinput_devicename = CString::new(format!("DEVNAME={}", vuinput_devicename)).unwrap();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue