2024-10-14 12:11:27 +00:00

240 lines
9.6 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

use crate::driver::base::uevent::kobject_uevent::kobject_uevent_env;
use core::fmt::Write;
/*
Struct
kset_uevent_ops
Function
get_ktype
kobject_name
kset_get
kset_put
to_kset
*/
use crate::driver::base::kobject::KObject;
use crate::driver::net::Iface;
use crate::filesystem::sysfs::{Attribute, SysFSOpsSupport, SYSFS_ATTR_MODE_RW};
use alloc::string::{String, ToString};
use alloc::sync::Arc;
use alloc::vec::Vec;
use intertrait::cast::CastArc;
use log::warn;
use system_error::SystemError;
use super::block::block_device::{BlockDevice, BlockDeviceOps};
use super::char::CharDevice;
use super::device::{Device, DeviceType};
pub mod kobject_uevent;
// https://code.dragonos.org.cn/xref/linux-6.1.9/lib/kobject_uevent.c?fi=kobject_uevent#457
#[derive(Debug)]
pub enum KobjectAction {
KOBJADD,
KOBJREMOVE, // Kobject或上层数据结构的添加/移除事件
KOBJCHANGE, // Kobject或上层数据结构的状态或者内容发生改变; 如果设备驱动需要上报的事件不再上面事件的范围内或者是自定义的事件可以使用该event并携带相应的参数。
KOBJMOVE, // Kobject或上层数据结构更改名称或者更改Parent意味着在sysfs中更改了目录结构
KOBJONLINE,
KOBJOFFLINE, // Kobject或上层数据结构的上线/下线事件,其实是是否使能
KOBJBIND,
KOBJUNBIND,
}
/// 解析一个字符串,以确定它代表的是哪个 kobject_action并提取出随后的参数如果有的话
fn kobject_action_type(buf: &[u8]) -> Result<(KobjectAction, Vec<String>), SystemError> {
let mut action = KobjectAction::KOBJCHANGE;
let mut action_args: Vec<String> = Vec::new();
let mut count = buf.len();
if count != 0 && (buf[count - 1] == b'\n' || buf[count - 1] == b'\0') {
count -= 1;
}
if count == 0 {
return Err(SystemError::EINVAL);
}
let arg_start = buf.iter().position(|&c| c == b' ').unwrap_or(count);
let count_first = arg_start;
let args_start = arg_start + 1;
// 匹配KobjectAction
match &buf[..count_first] {
b"add" => action = KobjectAction::KOBJADD,
b"remove" => action = KobjectAction::KOBJREMOVE,
b"change" => action = KobjectAction::KOBJCHANGE,
b"move" => action = KobjectAction::KOBJMOVE,
b"online" => action = KobjectAction::KOBJONLINE,
b"offline" => action = KobjectAction::KOBJOFFLINE,
b"bind" => action = KobjectAction::KOBJBIND,
b"unbind" => action = KobjectAction::KOBJUNBIND,
_ => return Err(SystemError::EINVAL),
}
// 如果有参数,提取参数
if count - args_start > 0 {
action_args = buf[args_start..]
.split(|&c| c == b' ')
.map(|s| String::from_utf8_lossy(s).to_string())
.collect::<Vec<_>>();
}
Ok((action, action_args))
}
pub const UEVENT_NUM_ENVP: usize = 64;
pub const UEVENT_BUFFER_SIZE: usize = 2048;
pub const UEVENT_HELPER_PATH_LEN: usize = 256;
/// 表示处理内核对象 uevents 的环境
/// - envp指针数组用于保存每个环境变量的地址最多可支持的环境变量数量为UEVENT_NUM_ENVP。
/// - envp_idx用于访问环境变量指针数组的index。
/// - buf保存环境变量的buffer最大为UEVENT_BUFFER_SIZE。
/// - buflen访问buf的变量。
// https://code.dragonos.org.cn/xref/linux-6.1.9/include/linux/kobject.h#31
#[derive(Debug)]
pub struct KobjUeventEnv {
argv: Vec<String>,
envp: Vec<String>,
envp_idx: usize,
buf: Vec<u8>,
buflen: usize,
}
// kset_uevent_ops是为kset量身订做的一个数据结构里面包含filter和uevent两个回调函数用处如下
/*
filter当任何Kobject需要上报uevent时它所属的kset可以通过该接口过滤阻止不希望上报的event从而达到从整体上管理的目的。
name该接口可以返回kset的名称。如果一个kset没有合法的名称则其下的所有Kobject将不允许上报uvent
uevent当任何Kobject需要上报uevent时它所属的kset可以通过该接口统一为这些event添加环境变量。因为很多时候上报uevent时的环境变量都是相同的因此可以由kset统一处理就不需要让每个Kobject独自添加了。
*/
/// 设备文件夹下的`uevent`文件的属性
#[derive(Debug, Clone, Copy)]
pub struct UeventAttr;
impl Attribute for UeventAttr {
fn name(&self) -> &str {
"uevent"
}
fn mode(&self) -> crate::filesystem::vfs::syscall::ModeType {
SYSFS_ATTR_MODE_RW
}
fn support(&self) -> crate::filesystem::sysfs::SysFSOpsSupport {
SysFSOpsSupport::ATTR_SHOW | SysFSOpsSupport::ATTR_STORE
}
/// 用户空间读取 uevent 文件,返回 uevent 信息
fn show(&self, _kobj: Arc<dyn KObject>, _buf: &mut [u8]) -> Result<usize, SystemError> {
let device = _kobj.cast::<dyn Device>().map_err(|e: Arc<dyn KObject>| {
warn!("device:{:?} is not a device!", e);
SystemError::EINVAL
})?;
log::info!("show uevent");
let device_type = device.dev_type();
let mut uevent_content = String::new();
log::info!("device_type: {:?}", device_type);
match device_type {
DeviceType::Block => {
let major = device.id_table().device_number().major().data();
let minor = device.id_table().device_number().minor();
let device_name = device.id_table().name();
writeln!(&mut uevent_content, "MAJOR={:?}", major).unwrap();
writeln!(&mut uevent_content, "MINOR={:?}", minor).unwrap();
writeln!(&mut uevent_content, "DEVNAME={}", device_name).unwrap();
writeln!(&mut uevent_content, "DEVTYPE=disk").unwrap();
}
DeviceType::Char => {
let major = device.id_table().device_number().major().data();
let minor = device.id_table().device_number().minor();
let device_name = device.id_table().name();
writeln!(&mut uevent_content, "MAJOR={}", major).unwrap();
writeln!(&mut uevent_content, "MINOR={}", minor).unwrap();
writeln!(&mut uevent_content, "DEVNAME={}", device_name).unwrap();
writeln!(&mut uevent_content, "DEVTYPE=char").unwrap();
}
DeviceType::Net => {
let net_device =
device
.clone()
.cast::<dyn Iface>()
.map_err(|e: Arc<dyn Device>| {
warn!("device:{:?} is not a net device!", e);
SystemError::EINVAL
})?;
let iface_id = net_device.nic_id();
let device_name = device.name();
writeln!(&mut uevent_content, "INTERFACE={}", device_name).unwrap();
writeln!(&mut uevent_content, "IFINDEX={}", iface_id).unwrap();
}
DeviceType::Bus => {
// 处理总线设备类型
let device_name = device.name();
writeln!(&mut uevent_content, "DEVNAME={}", device_name).unwrap();
writeln!(&mut uevent_content, "DEVTYPE=bus").unwrap();
}
DeviceType::Rtc => {
// 处理RTC设备类型
let device_name = device.name();
writeln!(&mut uevent_content, "DEVNAME={}", device_name).unwrap();
writeln!(&mut uevent_content, "DEVTYPE=rtc").unwrap();
}
DeviceType::Pci => {
// 处理PCI设备类型
let device_name = device.name();
writeln!(&mut uevent_content, "DEVNAME={}", device_name).unwrap();
writeln!(&mut uevent_content, "DEVTYPE=pci").unwrap();
}
_ => {
// 处理其他设备类型
let device_name = device.name();
writeln!(&mut uevent_content, "DEVNAME={}", device_name).unwrap();
writeln!(&mut uevent_content, "DEVTYPE={:?}", device_type).unwrap();
}
}
sysfs_emit_str(_buf, &uevent_content)
}
/// 捕获来自用户空间对 uevent 文件的写操作触发uevent事件
fn store(&self, _kobj: Arc<dyn KObject>, _buf: &[u8]) -> Result<usize, SystemError> {
log::info!("store uevent");
return kobject_synth_uevent(_buf, _kobj);
}
}
/// 将设备的基本信息写入 uevent 文件
fn sysfs_emit_str(buf: &mut [u8], content: &str) -> Result<usize, SystemError> {
log::info!("sysfs_emit_str");
let bytes = content.as_bytes();
if buf.len() < bytes.len() {
return Err(SystemError::ENOMEM);
}
buf[..bytes.len()].copy_from_slice(bytes);
Ok(bytes.len())
}
/// 解析用户空间写入的 uevent 信息,触发 uevent 事件
fn kobject_synth_uevent(buf: &[u8], kobj: Arc<dyn KObject>) -> Result<usize, SystemError> {
let no_uuid_envp = vec!["SYNTH_UUID=0".to_string()];
let (action, action_args) = kobject_action_type(buf)?;
let result = if action_args.is_empty() {
kobject_uevent_env(kobj.clone(), action, no_uuid_envp)
} else {
kobject_uevent_env(kobj.clone(), action, action_args)
};
if let Err(e) = result {
let device = kobj.cast::<dyn Device>().map_err(|e: Arc<dyn KObject>| {
warn!("device:{:?} is not a device!", e);
SystemError::EINVAL
})?;
let devname = device.name();
log::error!("synth uevent: {}: {:?}", devname, e);
return Err(SystemError::EINVAL);
}
Ok(buf.len())
}