-
Notifications
You must be signed in to change notification settings - Fork 12
/
usb-power
executable file
·193 lines (166 loc) · 5.4 KB
/
usb-power
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
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
#!/bin/bash
#
# usb-power - Control USB ports power using uhubctl
#
# Copyright (C) 2020 Rodrigo Silva (MestreLion) <linux@rodrigosilva.com>
# License: GPLv3 or later, at your choice. See <http://www.gnu.org/licenses/gpl>
#
# TODO: add 'toggle' action, parsing uhubctl with no action to determine status
# TODO: gsettings for keyboard shortcuts
# FIXME: implement 'config' action
#------------------------------------------------------------------------------
set -Eeuo pipefail # exit on any error
trap '>&2 echo "error: line $LINENO, status $?: $BASH_COMMAND"' ERR
#------------------------------------------------------------------------------
action=cycle
port=
location=
vendor=
message=
verbose=0
#------------------------------------------------------------------------------
url=https://github.com/mvp/uhubctl.git
myname=${0##*/}
mydir=$(dirname "$(readlink -f "$0")")
config=${XDG_CONFIG_HOME:-$HOME/.config}/usb-power.conf
destdir=${XDG_DATA_HOME:-$HOME/.local/share}/uhubctl
bindir=${XDG_BIN_HOME:-$HOME/.local/bin}
udev=/etc/udev/rules.d/52-usb-hub.rules
#------------------------------------------------------------------------------
install_package() {
local pkg=
local pkgs=()
for pkg in "$@"; do
if ! dpkg-query --show "$pkg" &>/dev/null; then pkgs+=("$pkg"); fi
done
if ((${#pkgs[@]})); then
sudo apt install -y "${pkgs[@]}"
fi
}
install_uhubctl() {
install_package git libusb-1.0-0-dev
if ! [[ -d "$destdir" ]]; then git clone "$url" -- "$destdir"; fi
cd -- "$destdir"
git reset --hard && git pull
make
make install sbindir="$bindir"
exit
}
udev() {
echo "# Added by $myname for USB hub power control via uhubctl" |
sudo tee -- "$udev" >/dev/null
while IFS=: read -r idVendor idProduct; do
echo "SUBSYSTEMS==\"usb\"," \
"ATTRS{idVendor}==\"${idVendor}\"," \
"ATTRS{idProduct}==\"${idProduct}\", TAG+=\"uaccess\"" |
sudo tee -a -- "$udev" >/dev/null
done < <(
sudo "$bindir"/uhubctl |
awk -F'[,[]' '/^[^ ]/ { sub(/ .*/, "", $2)
if ($2 != prev) { print $2; prev = $2 }
}'
)
sudo udevadm trigger --attr-match=subsystem=usb
exit
}
#------------------------------------------------------------------------------
fatal() { if (($#)); then echo "$myname: error: $@" >&2; fi; exit 1; }
message() { if (($# && verbose)); then printf '%s\n' "$@"; fi; }
argerr() { printf "%s: %s\n" "$myname" "${1:-error}" >&2; usage 1; }
invalid() { argerr "invalid ${2:-option}: ${1:-}"; }
missing() { argerr "missing ${1:+$1 }argument${2:+ from $2}."; }
user_config() {
local uconfig=${1:-}
if [[ -z "$uconfig" ]]; then missing FILE --config; fi
if ! [[ -f "$uconfig" ]]; then
fatal "could not find config file: $uconfig"
fi
source "$uconfig"
}
#------------------------------------------------------------------------------
usage() {
if [[ "${1:-}" ]] ; then exec >&2; fi
cat <<-USAGE
Usage: $myname [OPTIONS] [ACTION]
USAGE
if [[ "${1:-}" ]] ; then
cat <<- USAGE
Try '$myname --help' for more information.
USAGE
exit 1
fi
cat <<-USAGE
Control USB port power
Options:
-h|--help - show this page.
-v|--verbose - print more details about what is being done.
-c|--config FILE - Extra configuration file. Will override settings in
master config file $config
-m|--message MSG - A message to display via notifications
-V|--vendor ID - limit ACTION usage to the specified Vendor ID
ACTION might be one of:
on - turn port on
off - turn port off
cycle - turn port off for 2 seconds, then back on (default)
install - download uhubctl from $url,
install it at $destdir,
and symlink executable to $bindir
May require installing dependency packages using sudo
config - run 'cycle' on each USB hub port to aid creating the config file
udev - generate udev rules for the USB hub port. Uses sudo
Copyright (C) 2020 Rodrigo Silva (MestreLion) <linux@rodrigosilva.com>
License: GPLv3 or later. See <http://www.gnu.org/licenses/gpl.html>
USAGE
exit 0
}
# Pre-parse for -h|--help, ignoring if after '--'
for arg in "$@"; do
if [[ "$arg" == '--' ]]; then break; fi
if [[ "$arg" == "-h" || "$arg" == "--help" ]]; then usage; fi
done
# Pre-parse master config file. Silently ignore if it does not exist
if [[ -f "$config" ]]; then
source "$config"
fi
args=()
while (($#)); do
case "$1" in
-v|--verbose) verbose=1;;
-V|--vendor) shift; vendor=${1:-};;
-c|--config) shift; user_uconfig "${1:-}";;
-m|--message) shift; message=${1:-};;
--vendor=*) vendor=${1#*=};;
--config=*) user_uconfig "${1#*=}";;
--message=*) message=${1#*=};;
-*) invalid "$1";;
* ) args+=( "$1" );;
esac
shift || break
done
args+=("$@")
case ${#args[@]} in
0) info=1;;
1) action=${args[0]}; if [[ -z "$action" ]]; then missing ACTION; fi;;
*) invalid "${args[1]}" ACTION;;
esac
#------------------------------------------------------------------------------
args=()
case "$action" in
on|off|cycle) args+=(-a "$action");;
install) install_uhubctl;;
udev) udev;;
config) cycle;;
*) invalid "$action" ACTION;;
esac
if [[ "$port" ]]; then args+=(--port "$port"); fi
if [[ "$location" ]]; then args+=(--location "$location"); fi
if [[ "$vendor" ]]; then args+=(--vendor "$vendor"); fi
message uhubctl "${args[@]}"
if [[ "$message" ]]; then
case "$action" in
off) icon=brasero-disc-00;;
*) icon=brasero-disc-100;;
esac
notify-send --app-name "$myname" --icon "$icon" -- "$message" || :
fi
uhubctl "${args[@]}"