65 lines
2.8 KiB
Bash
65 lines
2.8 KiB
Bash
#!/usr/bin/env bash
|
|
# WHY: a global hidraw trigger would affect unrelated devices. Discover exactly
|
|
# one I2C/ASUS/5570 controller and trigger only its current hidraw sysfs node.
|
|
# CONTRACT: default/--check is read-only. --apply requires root AND the owner's
|
|
# prior approval; no sudo, chmod of /dev, module change or HID report is issued.
|
|
set -euo pipefail
|
|
mode=${1:---check}
|
|
if [[ $# -gt 1 || ( $mode != --check && $mode != --apply ) ]]; then
|
|
printf 'Usage: %s [--check|--apply]\n' "$0" >&2
|
|
exit 2
|
|
fi
|
|
script_dir=$(CDPATH= cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd -P)
|
|
rule=$script_dir/70-labfy-rgb.rules
|
|
target=/etc/udev/rules.d/70-labfy-rgb.rules
|
|
udevadm verify "$rule"
|
|
# Refuse a broadened proposal, even if its udev syntax is valid.
|
|
expected='SUBSYSTEM=="hidraw", KERNEL=="hidraw*", SUBSYSTEMS=="hid", KERNELS=="0018:0B05:5570.*", TAG+="uaccess"'
|
|
mapfile -t active_lines < <(sed '/^[[:space:]]*#/d; /^[[:space:]]*$/d' "$rule")
|
|
if [[ ${#active_lines[@]} -ne 1 || ${active_lines[0]} != "$expected" ]]; then
|
|
printf 'Rule differs from the reviewed narrow match; refusing.\n' >&2
|
|
exit 5
|
|
fi
|
|
shopt -s nullglob
|
|
matches=()
|
|
for candidate in /sys/class/hidraw/hidraw*; do
|
|
identity=''
|
|
while IFS= read -r line; do
|
|
if [[ $line == HID_ID=* ]]; then identity=${line#HID_ID=}; fi
|
|
done < "$candidate/device/uevent"
|
|
[[ $identity == 0018:00000B05:00005570 ]] || continue
|
|
parent=$(readlink -f -- "$candidate/device")
|
|
[[ ${parent##*/} == 0018:0B05:5570.* ]] || continue
|
|
matches+=("$candidate")
|
|
done
|
|
if [[ ${#matches[@]} -ne 1 ]]; then
|
|
printf 'Expected exactly one matching controller; found %s. No changes.\n' "${#matches[@]}" >&2
|
|
exit 3
|
|
fi
|
|
sysfs=${matches[0]}
|
|
node=/dev/${sysfs##*/}
|
|
if [[ -L $target ]]; then
|
|
printf 'Refusing existing symlink: %s\n' "$target" >&2
|
|
exit 5
|
|
fi
|
|
if [[ -e $target ]] && ! cmp -s -- "$rule" "$target"; then
|
|
printf 'Refusing to overwrite a different existing rule: %s\n' "$target" >&2
|
|
exit 5
|
|
fi
|
|
printf 'Rule: %s\nTarget: %s\nDevice: %s\nSysfs: %s\n' "$rule" "$target" "$node" "$sysfs"
|
|
if [[ $mode == --check ]]; then
|
|
printf 'Read-only plan: install rule root:root 0644, reload rules, trigger change on this node only, settle, inspect ACL.\nNo changes applied.\n'
|
|
exit 0
|
|
fi
|
|
if (( EUID != 0 )); then
|
|
printf -- '--apply requires administrator execution and prior explicit approval. No changes.\n' >&2
|
|
exit 4
|
|
fi
|
|
# No overwrite of an unrelated file. A reload reparses all rules, while the
|
|
# event is limited to the one discovered node; neither operation sends HID data.
|
|
if [[ ! -e $target ]]; then install -o root -g root -m 0644 -- "$rule" "$target"; fi
|
|
udevadm control --reload-rules
|
|
udevadm trigger --action=change "$sysfs"
|
|
udevadm settle --timeout=10
|
|
getfacl -p -- "$node"
|
|
printf 'Rule application completed. Run labfy-rgb status as your normal user to verify access.\n'
|