blob: 6f35843e010606c4c6ba9d2d9bc2fe0b756866c9 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
|
#!/usr/bin/env bash
# webcam-toggle-setup — Interactive setup for webcam-toggle.
# Lists all connected uvcvideo webcams and lets the user choose which one
# to target. Saves the selection to /var/lib/webcam-toggle/device.
#
# Must be run as root: sudo webcam-toggle-setup
#
# Can also be run non-interactively:
# sudo webcam-toggle-setup --list Print detected webcams
# sudo webcam-toggle-setup --device 1-5 Set the target device directly
# --- Hardened PATH --------------------------------------------------------
export PATH="/usr/bin:/bin:/usr/sbin:/sbin"
set -euo pipefail
STATE_DIR="/var/lib/webcam-toggle"
DEVICE_FILE="${STATE_DIR}/device"
mkdir -p "$STATE_DIR"
chmod 0755 "$STATE_DIR"
# ---------------------------------------------------------------------------
# validate_dev_id
# ---------------------------------------------------------------------------
validate_dev_id() {
local id="$1"
if [[ ! "$id" =~ ^[0-9]+-[0-9]+(\.[0-9]+)*$ ]]; then
echo "error: invalid device id: '$id'" >&2
exit 1
fi
}
# ---------------------------------------------------------------------------
# get_product_name — read the USB product string for a device.
# ---------------------------------------------------------------------------
get_product_name() {
local dev_id="$1"
local product_file="/sys/bus/usb/devices/${dev_id}/product"
if [ -r "$product_file" ]; then
cat "$product_file"
else
echo "(unknown)"
fi
}
# ---------------------------------------------------------------------------
# list_webcam_devices — enumerate uvcvideo-bound USB devices (deduplicated).
# ---------------------------------------------------------------------------
list_webcam_devices() {
local seen="" intf intf_dir intf_name dev_id
for intf in /sys/bus/usb/drivers/uvcvideo/*/driver; do
[ -e "$intf" ] || continue
intf_dir="$(dirname "$intf")"
intf_name="$(basename "$intf_dir")"
dev_id="${intf_name%%:*}"
case "$seen" in
*"|${dev_id}|"*) continue ;;
esac
seen="${seen}|${dev_id}|"
echo "$dev_id"
done
}
# ---------------------------------------------------------------------------
# save_device — persist the chosen device id.
# ---------------------------------------------------------------------------
save_device() {
local dev_id="$1"
validate_dev_id "$dev_id"
echo "$dev_id" > "$DEVICE_FILE"
chmod 0600 "$DEVICE_FILE"
# Clear stale state so the next toggle reads live status.
rm -f "${STATE_DIR}/unbound"
echo "Saved device $dev_id ($(get_product_name "$dev_id")) as the target webcam."
}
# ---------------------------------------------------------------------------
# print_list — display a numbered list of webcams.
# Expects the CAMS array to be populated by the caller.
# ---------------------------------------------------------------------------
print_list() {
local current=""
[ -f "$DEVICE_FILE" ] && current="$(cat "$DEVICE_FILE")"
local i
for i in "${!CAMS[@]}"; do
local dev_id="${CAMS[$i]}"
local name
name="$(get_product_name "$dev_id")"
local marker=""
[ "$dev_id" = "$current" ] && marker=" [current]"
printf " %d) %-12s %s%s\n" $((i + 1)) "$dev_id" "$name" "$marker"
done
}
# ---------------------------------------------------------------------------
# Main
# ---------------------------------------------------------------------------
# Populate CAMS once — all subcommands and interactive mode use this snapshot.
mapfile -t CAMS < <(list_webcam_devices)
case "${1:-}" in
--list)
if [ "${#CAMS[@]}" -eq 0 ]; then
echo "No webcams detected."
exit 1
fi
print_list
exit
;;
--device)
if [ -z "${2:-}" ]; then
echo "usage: webcam-toggle-setup --device <bus-port>" >&2
exit 1
fi
save_device "$2"
exit
;;
"")
# Interactive mode — fall through
;;
*)
echo "usage: webcam-toggle-setup [--list | --device <bus-port>]" >&2
exit 1
;;
esac
# --- Interactive selection ------------------------------------------------
if [ "${#CAMS[@]}" -eq 0 ]; then
echo "No webcams detected."
exit 1
fi
echo "Detected webcams:"
print_list
echo ""
if [ "${#CAMS[@]}" -eq 1 ]; then
save_device "${CAMS[0]}"
exit
fi
while true; do
printf "Select the webcam to toggle [1-%d]: " "${#CAMS[@]}"
read -r choice
if [[ "$choice" =~ ^[0-9]+$ ]] && [ "$choice" -ge 1 ] && [ "$choice" -le "${#CAMS[@]}" ]; then
save_device "${CAMS[$((choice - 1))]}"
exit
fi
echo "Invalid selection."
done
|