Created
September 19, 2014 23:38
-
-
Save altercation/bd9d4b4bb7149b4825b2 to your computer and use it in GitHub Desktop.
script to conditionally sleep surface pro 3 on removal of all external usb devices, with installers to set correct udev wake rules
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env zsh | |
setopt EXTENDED_GLOB NO_UNSET ERR_EXIT | |
typeset -g SCRIPTUSERHOME=/${(j:/:)${(s:/:)0:A}[1,2]} # TODO: probably a better way than this | |
typeset -g SCRIPTUSER=${${(s:/:)0:A}[2]} # TODO: probably a better way than this | |
typeset -g SCRIPTNAME="${${SCRIPTPATH:=$0:A}:t}" | |
typeset -g SCRIPTROOT="${SCRIPTPATH:h}" | |
typeset -g FUNCPATH=$SCRIPTROOT/functions | |
fpath=($FUNCPATH $fpath) | |
autoload $FUNCPATH/*(#q.:t) | |
typeset -g SCRIPTCONF="$SCRIPTUSERHOME/${XDG_CONFIG_HOME:-.config}/$SCRIPTNAME" | |
typeset -g SCRIPTSTATE="$SCRIPTCONF/state" | |
typeset -g I3INDICATORS="$SCRIPTUSERHOME/${XDG_CONFIG_HOME:-.config}/i3status" | |
typeset -g I3INDICATOR="$I3INDICATORS/$SCRIPTNAME" | |
[[ -d $SCRIPTCONF ]] || { mkdir $SCRIPTCONF; chown $SCRIPTUSER:$SCRIPTUSER $SCRIPTCONF} &>/dev/null | |
touch $SCRIPTSTATE | |
[[ -d $I3INDICATORS ]] || { mkdir $I3INDICATORS; chown $SCRIPTUSER:$SCRIPTUSER $I3INDICATORS; } &>/dev/null | |
alias runonce='${(P)${(U)0}:-false} && return 0 || eval typeset -g ${(U)0}=true' | |
# following .X11-unix line is breaking when called by root | |
#[[ -n $DISPLAY ]] || typeset -gx DISPLAY="$(print /tmp/.X11-unix/*(:t:s/X/:))" | |
typeset -gx DISPLAY=:0 | |
[[ $(loginctl list-sessions) =~ "seat0" ]] || { | |
logger -s "${SCRIPTNAME:-$0}${SCRIPTNAME:+>$0}: No X Session identified" | |
exit 1 | |
} | |
if [[ $USERNAME == root ]] | |
then | |
xauth_xauthority=/home/${${(s:/:)SCRIPTPATH}[2]}/.Xauthority | |
xhost_xauthority=/var/run/gdm/auth-for-gdm*/database | |
[[ -f $xhost_xauthority ]] && typeset -gx XAUTHORITY=$xhost_xauthority || { | |
[[ -f $xauth_xauthority ]] && typeset -gx XAUTHORITY=$xhost_xauthority } | |
fi | |
# plug/unplug usb to internal usb hub will suspend/resume machine | |
# script development clues | |
# # udevadm info -a -p /sys/devices/pci0000:00/0000:00:14.0/usb1/1-1 | |
# # udevadm test --action remove /sys/devices/pci0000:00/0000:00:14.0/usb1/1-1 | |
# # udevadm monitor --environment --udev | |
# # cat /usr/lib/udev/rules.d/* | grep -i remove | |
# --------------------------------------------------------------------- | |
# script values | |
# --------------------------------------------------------------------- | |
typeset -g SCRIPTNAME="${${SCRIPTPATH:=$(readlink -f $0)}:t}" | |
typeset -g SCRIPTROOT="${SCRIPTPATH:h}" | |
typeset -g SCRIPTLOCK="/var/run/$SCRIPTNAME/lock" | |
[[ -d ${SCRIPTLOCK:h} ]] || mkdir ${SCRIPTLOCK:h} &>/dev/null | |
# --------------------------------------------------------------------- | |
# initializers | |
# --------------------------------------------------------------------- | |
install () { | |
[[ $USER == root ]] || { print "run with sudo or as root when calling $SCRIPTNAME $0"; exit 1 } | |
typeset -A rules | |
rules=( | |
99-$SCRIPTNAME.rules 'ACTION=="remove", ENV{ID_USB_INTERFACE_NUM}=="*", RUN+="'$SCRIPTPATH' conditional_suspend $parent"' | |
99-usb-hub-wakeup.rules "ACTION==\"add\", SUBSYSTEM==\"usb\", ATTRS{idVendor}==\"1d6b\", RUN+=\"/bin/sh -c \'echo enabled > /sys\$env{DEVPATH}/power/wakeup\'\"" | |
99-usb-hid-wakeup.rules "ACTION==\"add\", SUBSYSTEM==\"usb\", DRIVER==\"usbhid\", RUN+=\"/bin/sh -c \'echo enabled > /sys\$env{DEVPATH}/../../power/wakeup\'\", RUN+=\"/bin/sh -c \'echo enabled > /sys\$env{DEVPATH}/../power/wakeup\'\", RUN+=\"/bin/sh -c \'echo enabled > /sys\$env{DEVPATH}/power/wakeup\'\"" | |
) | |
#99-usb-hub-wakeup.rules 'SUBSYSTEM=="usb", ATTRS{idVendor}=="1d6b", ATTRS{idProduct}=="*", RUN+="/usr/bin/echo enabled > /sys\$env{DEVPATH}/power/wakeup"' | |
for rulename in ${(k)rules} | |
do | |
rulepath=/etc/udev/rules.d/$rulename | |
rule=${rules[$rulename]} | |
[[ -f $rulepath ]] && rm -f $rulepath | |
print $rule > $rulepath \ | |
&& { print "Successfully wrote udev rules file $rulepath" } \ | |
|| { print "Failed to write udev rules file $rulepath"; exit 1 } | |
done | |
# service=" | |
# [Unit] | |
# Description=Suspend system if all usb devices unplugged | |
# | |
# [Service] | |
# Type=simple | |
# ExecStart=$SCRIPTPATH %I" | |
# | |
# print -l -- "${(@)${(@f)service}##[[:space:]]#}" > /etc/systemd/system/$SCRIPTNAME\@.service \ | |
# && { print "Successfully wrote systemd service unit" } \ | |
# || { print "Failed to write systemd service unit"; exit 1 } | |
# | |
# systemctl daemon-reload | |
udevadm control --reload | |
} | |
lock () { | |
print $(date +%N) > $SCRIPTLOCK || { | |
notify-send "failed to make lock" | |
exit 1 } | |
} | |
unlock () { | |
rm $SCRIPTLOCK | |
} | |
conditional_suspend () { | |
(( $(cat /sys/class/power_supply/*/online) >0 )) && exit 0 # if on ac | |
# there are four builtin usb hub devices, so that's the count if we've unplugged everything | |
if [[ -z ${*:-} ]] && (( ${#${(f)"$(lsusb -s 001:)"}} == 4 )) | |
then | |
# make sure that usb hub is set to resume and then suspend | |
#if [[ "$(</sys/devices/pci0000:00/0000:00:14.0/usb1/power/wakeup)" != enabled ]] | |
#then | |
# envinit | |
# notify-send "Setting usb hub to wakeup mode (check udev rule!)" | |
# print "enabled" > /sys/devices/pci0000:00/0000:00:14.0/usb1/power/wakeup || { | |
# notify-send "Failed!"; exit 1 } | |
#fi | |
# disable all except hub, hub parents, hub descendants | |
for w in /sys/devices/**/wakeup; do print disabled > $w; done | |
device=/sys/devices/pci0000:00/0000:00:14.0/usb1 | |
while [[ -n $device && $device != "/" ]] | |
do | |
[[ -f $device/power/wakeup ]] && print enabled > $device/power/wakeup | |
device=${device:h} | |
done | |
if (( ${#${(f)"$(lsusb -s 001:)"}} <= 4 )) \ | |
&& (( $(cat /sys/class/power_supply/*/online) == 0 )) \ | |
&& [[ ! -f $SCRIPTLOCK ]] | |
then | |
lock | |
systemctl suspend | |
unlock | |
elif [[ -f $SCRIPTLOCK ]] | |
then | |
# script lock present, skip suspend | |
: | |
elif (( ${#${(f)"$(lsusb -s 001:)"}} > 4 )) | |
then | |
# more than 4 devices attached, skip suspend | |
: | |
elif (( $(cat /sys/class/power_supply/*/online) == 1 )) | |
then | |
# still plugged in to power, skip suspend | |
: | |
else | |
notify-send --urgency=critical "$SCRIPTNAME: Unknown state encountered in $0" | |
fi | |
fi | |
} | |
${*:-} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
did you ever come up with a better solution than this?