kms: Add allow/deny-listing of drm devices
This commit is contained in:
parent
b5d5479b86
commit
913ed90b04
2 changed files with 203 additions and 0 deletions
|
|
@ -149,6 +149,48 @@ impl State {
|
|||
return Ok(());
|
||||
}
|
||||
|
||||
if let Some(allowlist) = dev_list_var("COSMIC_DRM_ALLOW_DEVICES") {
|
||||
let mut matched = false;
|
||||
if let Ok(node) = DrmNode::from_dev_id(dev) {
|
||||
let node = node
|
||||
.node_with_type(NodeType::Render)
|
||||
.map(|res| res.ok())
|
||||
.flatten()
|
||||
.unwrap_or(node);
|
||||
for ident in allowlist {
|
||||
if ident.matches(&node) {
|
||||
matched = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if !matched {
|
||||
info!(
|
||||
"Skipping device {} due to COSMIC_DRM_ALLOW_DEVICE list.",
|
||||
path.display()
|
||||
);
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
}
|
||||
if let Some(blocklist) = dev_list_var("COSMIC_DRM_BLOCK_DEVICES") {
|
||||
if let Ok(node) = DrmNode::from_dev_id(dev) {
|
||||
let node = node
|
||||
.node_with_type(NodeType::Render)
|
||||
.map(|res| res.ok())
|
||||
.flatten()
|
||||
.unwrap_or(node);
|
||||
for ident in blocklist {
|
||||
if ident.matches(&node) {
|
||||
info!(
|
||||
"Skipping device {} due to COSMIC_DRM_BLOCK_DEVICE list.",
|
||||
path.display()
|
||||
);
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let fd = DrmDeviceFd::new(DeviceFd::from(
|
||||
self.backend
|
||||
.kms()
|
||||
|
|
|
|||
161
src/utils/env.rs
161
src/utils/env.rs
|
|
@ -1,6 +1,167 @@
|
|||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
use smithay::backend::drm::{DrmNode, NodeType};
|
||||
use tracing::{info, warn};
|
||||
|
||||
pub fn bool_var(name: &str) -> Option<bool> {
|
||||
let value = std::env::var(name).ok()?.to_lowercase();
|
||||
Some(["1", "true", "yes", "y"].contains(&value.as_str()))
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum DeviceIdentifier {
|
||||
Id { vendor: u32, device: u32 },
|
||||
Node(DrmNode),
|
||||
}
|
||||
|
||||
impl DeviceIdentifier {
|
||||
pub fn matches(&self, dev_node: &DrmNode) -> bool {
|
||||
match self {
|
||||
DeviceIdentifier::Node(id_node) => id_node == dev_node,
|
||||
DeviceIdentifier::Id { vendor, device } => {
|
||||
let (major, minor) = (dev_node.major(), dev_node.minor());
|
||||
let Some(dev_vendor) = std::fs::read_to_string(format!(
|
||||
"/sys/dev/char/{}:{}/device/vendor",
|
||||
major, minor
|
||||
))
|
||||
.ok()
|
||||
.and_then(|ven| u32::from_str_radix(ven[2..].trim(), 16).ok()) else {
|
||||
return false;
|
||||
};
|
||||
let Some(dev_device) = std::fs::read_to_string(format!(
|
||||
"/sys/dev/char/{}:{}/device/device",
|
||||
major, minor
|
||||
))
|
||||
.ok()
|
||||
.and_then(|dev| u32::from_str_radix(dev[2..].trim(), 16).ok()) else {
|
||||
return false;
|
||||
};
|
||||
info!(
|
||||
"{:x}:{:x} == {:x}:{:x}",
|
||||
*vendor, *device, dev_vendor, dev_device
|
||||
);
|
||||
dev_vendor == *vendor && dev_device == *device
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn dev_var(name: &str) -> Option<DeviceIdentifier> {
|
||||
let value = std::env::var(name).ok()?;
|
||||
try_parse_dev_from_str(&value)
|
||||
}
|
||||
|
||||
pub fn dev_list_var(name: &str) -> Option<Vec<DeviceIdentifier>> {
|
||||
let value = std::env::var(name).ok()?;
|
||||
Some(value.split(',').flat_map(try_parse_dev_from_str).collect())
|
||||
}
|
||||
|
||||
fn try_parse_dev_from_str(val: &str) -> Option<DeviceIdentifier> {
|
||||
let val = val.trim();
|
||||
if val.starts_with("0x") && val.contains(':') {
|
||||
let (vendor, device) = val.split_once(':').unwrap();
|
||||
if !device.starts_with("0x") {
|
||||
warn!(
|
||||
"Failed to parse device entry {}, device id doesn't start with '0x'. Skipping",
|
||||
val
|
||||
);
|
||||
return None;
|
||||
}
|
||||
let vendor = u32::from_str_radix(&vendor[2..], 16)
|
||||
.inspect_err(|err| {
|
||||
warn!(
|
||||
"Failed to parse device entry {}, vendor_id is no hex integer: {}. Skipping",
|
||||
val, err
|
||||
);
|
||||
})
|
||||
.ok()?;
|
||||
let device = u32::from_str_radix(&device[2..], 16)
|
||||
.inspect_err(|err| {
|
||||
warn!(
|
||||
"Failed to parse device entry {}, device_id is no hex integer: {}. Skipping",
|
||||
val, err
|
||||
);
|
||||
})
|
||||
.ok()?;
|
||||
Some(DeviceIdentifier::Id { vendor, device })
|
||||
} else if val.starts_with("pci-") {
|
||||
let path = std::fs::read_link(format!("/dev/dri/by-path/{}-render", val))
|
||||
.inspect_err(|err| {
|
||||
warn!(
|
||||
"Failed to parse device entry {}, no known pci path: {}. Skipping",
|
||||
val, err
|
||||
);
|
||||
})
|
||||
.ok()?;
|
||||
let node = DrmNode::from_path(&path)
|
||||
.inspect_err(|err| {
|
||||
warn!(
|
||||
"Failed to parse device entry {}, failed to get node from path {}: {}",
|
||||
val,
|
||||
path.display(),
|
||||
err
|
||||
)
|
||||
})
|
||||
.ok()?;
|
||||
|
||||
let node = node
|
||||
.node_with_type(NodeType::Render)
|
||||
.map(|res| res.ok())
|
||||
.flatten()
|
||||
.unwrap_or(node);
|
||||
Some(DeviceIdentifier::Node(node))
|
||||
} else if val.contains(':') {
|
||||
let (major, minor) = val.split_once(':').unwrap();
|
||||
let major = str::parse::<u32>(major)
|
||||
.inspect_err(|err| {
|
||||
warn!(
|
||||
"Failed to parse device entry {}, major is no integer: {}. Skipping",
|
||||
val, err
|
||||
)
|
||||
})
|
||||
.ok()?;
|
||||
let minor = str::parse::<u32>(minor)
|
||||
.inspect_err(|err| {
|
||||
warn!(
|
||||
"Failed to parse device entry {}, minor is no integer: {}. Skipping",
|
||||
val, err
|
||||
)
|
||||
})
|
||||
.ok()?;
|
||||
let dev = rustix::fs::makedev(major, minor);
|
||||
let node = DrmNode::from_dev_id(dev)
|
||||
.inspect_err(|err| {
|
||||
warn!(
|
||||
"Failed to parse device entry {}, failed to get node from dev_t {}: {}",
|
||||
val, dev, err
|
||||
);
|
||||
})
|
||||
.ok()?;
|
||||
|
||||
let node = node
|
||||
.node_with_type(NodeType::Render)
|
||||
.map(|res| res.ok())
|
||||
.flatten()
|
||||
.unwrap_or(node);
|
||||
Some(DeviceIdentifier::Node(node))
|
||||
} else {
|
||||
// try to parse as device path
|
||||
|
||||
let path = format!("/dev/dri/{}", val);
|
||||
let node = DrmNode::from_path(&path)
|
||||
.inspect_err(|err| {
|
||||
warn!(
|
||||
"Failed to parse device entry {}, failed to get node from path {}: {}",
|
||||
val, path, err
|
||||
);
|
||||
})
|
||||
.ok()?;
|
||||
|
||||
let node = node
|
||||
.node_with_type(NodeType::Render)
|
||||
.map(|res| res.ok())
|
||||
.flatten()
|
||||
.unwrap_or(node);
|
||||
Some(DeviceIdentifier::Node(node))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue