Run User Scripts on Suspend and Wakeup on Void Linux
Posted by Dave Eddy on Oct 01 2018 - tags: techWhile using Void Linux on my laptop, I wanted some way to trigger scripts as my user when the machine went to sleep and when it resumed. The main goal of this was to be able to lock my machine using i3lock on suspend.
I currently use xss-lock to register i3lock
to be called whenever
the screensaver is activated with this command (run at session start):
xss-lock -- ~/bin/i3lock-retry -enfi ~/Pictures/lock.png
With xss-lock
running, I set my machine to lock automatically after 600
seconds (10 minutes) of inactivity with:
xset s 600
And locking my machine can be done manually by activating the screensaver with:
xset s activate
Note: i3lock-retry is a simple wrapper-script that calls
i3lock
continuously until it exits successfully (i.e. when the correct
password has been entered). I’ve had some issues with i3lock
crashing in the
past and I just have this wrapper in place because of paranoia over ensuring
my system locks correctly.
Lid Close Event
Initially, to get the machine to lock automatically when I suspended it, I
had naively modified the acpi
handler for the button/lid/close
event (when
the laptop lid is closed). I originally had code like this:
/etc/acpi/handler.sh
button/lid)
case "$3" in
close)
# suspend-to-ram
logger "LID closed, suspending..."
xset s activate
sleep 1
zzz
;;
The handler was set up, by default with Void, to call zzz
, I just manually
added the lines to activate the screensaver and sleep for a second before
calling zzz
. This “worked” for the most part, but there were some issues.
The most obvious issue (that I didn’t think of at first, of course) was that
this didn’t lock the machine when it was slept, but instead locked the machine
when the lid was closed. This means that manually invoking sleep by running the
zzz
command - or just invoking sleep by any other means than closing the
lid - would leave the system unlocked.
To remedy this problem, I looked more closely into the zzz
command that came
with Void. By reading the zzz(8) manual, I found that the zzz
command
had the ability to invoke hooks on suspend and resume!
zzz User Hooks
zzz
will call any and all executables that live in /etc/zzz.d/suspend
and
/etc/zzz.d/resume
when the machine suspends and resumes, respectively. Using
this knowledge, I wrote a generic script that will:
- Figure out the user currently logged in with an active X session
- Determine if they have a user hook installed (script in
~/.onsuspend
or~/.onwakeup
) - Call the user script with the correct permissions (using
sudo
) andDISPLAY
environmental variable
The code is on GitHub:
https://github.com/bahamas10/zzz-user-hooks
The code was written specifically for Void Linux but should work on any OS that
has or uses the zzz
command to suspend.
Once the code is checked out, make
can be used to install the hooks:
$ sudo make install
cp user-script /etc/zzz.d
cp hooks/resume/99-user-script /etc/zzz.d/resume
cp hooks/suspend/99-user-script /etc/zzz.d/suspend
This will result in the following layout being created:
$ tree /etc/zzz.d/
/etc/zzz.d/
├── resume
│ └── 99-user-script
├── suspend
│ └── 99-user-script
└── user-script
2 directories, 3 files
With these scripts in place, the following scripts will be run for the currently logged in user:
~/.onsuspend
- called before the machine is suspended~/.onresume
- called when the machine wakes up
The above scripts will be called with the permissions of the user for whom they
are being called (using sudo -Hu <user>
). The DISPLAY
environmental
variable will be set to the currently active display. The timeout
command will be used to ensure the user scripts don’t take any longer than 5
seconds so they cannot hang the system indefinitely.
Example
I use the following scripts:
~/.onsuspend
#!/usr/bin/env bash
# activate the screensaver (lock)
xset s activate
sleep 1
~/.onresume
#!/usr/bin/env bash
# turn on the keyboard backlight
~/bin/keyboard dim
# ensure the output is set to the laptop display
~/bin/monitor laptop
keyboard
and monitor
are scripts in my dotfiles.
User scripts being called when using the zzz
command directly:
$ sudo zzz
Zzzz... [user-script] called Sun Sep 23 11:33:59 EDT 2018
[user-script] running /home/dave/.onsuspend for user dave (DISPLAY=:0)
[user-script] ran /home/dave/.onsuspend for user dave, exited 0
[user-script] called Sun Sep 23 11:34:05 EDT 2018
[user-script] running /home/dave/.onresume for user dave (DISPLAY=:0)
[user-script] ran /home/dave/.onresume for user dave, exited 0
yawn.
Note that any output generated by the user scripts will show up in the same
location as the zzz
logs.
User scripts being called when using acpid
to trigger zzz
when the laptop
lid is closed:
$ less /tmp/sv/log/acpid/current
2018-09-27_06:04:11.08679 rule from /etc/acpi/events/anything matched
2018-09-27_06:04:11.08723 executing action "/etc/acpi/handler.sh button/lid LID close"
2018-09-27_06:04:11.13167 Zzzz... [user-script] called Thu Sep 27 06:04:11 UTC 2018
2018-09-27_06:04:11.14506 [user-script] running /home/dave/.onsuspend for user dave (DISPLAY=:0)
2018-09-27_06:04:12.16758 [user-script] ran /home/dave/.onsuspend for user dave, exited 0
2018-09-28_00:57:20.98021 [user-script] called Fri Sep 28 00:57:20 UTC 2018
2018-09-28_00:57:20.98195 [user-script] running /home/dave/.onresume for user dave (DISPLAY=:0)
2018-09-28_00:57:20.99676 [user-script] ran /home/dave/.onresume for user dave, exited 0
2018-09-28_00:57:20.99684 yawn.
2018-09-28_00:57:20.99712 action exited with status 0
2018-09-28_00:57:20.99713 3 total rules matched
2018-09-28_00:57:20.99713 completed input layer event "button/lid LID close"