#!/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'