Writing a systemd service to be executed at resume
Solution 1
I know this is an old question, but the following unit file worked for me to run a script upon resume from sleep:
[Unit]
Description=<your description>
After=suspend.target
[Service]
User=root
Type=oneshot
ExecStart=<your script here>
TimeoutSec=0
StandardOutput=syslog
[Install]
WantedBy=suspend.target
I believe it is the After=suspend.target
that makes it run on resume, rather than when the computer goes to sleep.
Solution 2
As an alternative to writing and enabling a unit file, you can also put a shell script (or a symlink to your script) into /lib/systemd/system-sleep/
.
It will be called before sleep/hibernate, and at resume time.
From man systemd-suspend.service
:
Immediately before entering system suspend and/or hibernation systemd-suspend.service (and the other mentioned units, respectively) will run all executables in /usr/lib/systemd/system-sleep/ and pass two arguments to them. The first argument will be "pre", the second either "suspend", "hibernate", or "hybrid-sleep" depending on the chosen action. Immediately after leaving system suspend and/or hibernation the same executables are run, but the first argument is now "post". All executables in this directory are executed in parallel, and execution of the action is not continued until all executables have finished.
Test it with this:
#!/bin/sh
## This file (or a link to it) must be in /lib/systemd/system-sleep/
logger -t "test" "\$0=$0, \$1=$1, \$2=$2"
Solution 3
Followup to mivk's answer, in which I avoid mucking with a new unit file (see my question here How to react to laptop lid events?). Here's my solution; it's not 100% straightforward (sigh) because the system is not stable when it's coming out of sleep:
On my Fedora 26 box I put a symlink here: /usr/lib/systemd/system-sleep/sleepyhead
which points here: /root/bin/sleepyhead
, which contains:
#!/bin/sh
## This file (or a link to it) must be in /lib/systemd/system-sleep/
# This is called when the lid is closed, as follows:
# $0=/usr/lib/systemd/system-sleep/sleepyhead, $1=pre, $2=suspend
# ...and when the lid is opened, as follows:
# $0=/usr/lib/systemd/system-sleep/sleepyhead, $1=post, $2=suspend
touch /tmp/sleepyrun
logger -t "sleepyhead" "Start: \$1=$1, \$2=$2"
if [ "$1" = "post" ] ; then
action="RUN trackpoint"
bash /root/bin/trackpoint >/tmp/trackpoint-run 2>&1
else
action="NO ACTION"
fi
logger -t "sleepyhead" "${action}: " "\$1=$1, \$2=$2"
The /root/bin/trackpoint
script follows. Note that the first sleep is critical. The device is set up every time the lid is opened, so it doesn't exist at first. If I try to do anything but sleep, the "sleepyhead" script takes a really long time to exit and my pointer will be frozen for at least 60 seconds. Furthermore, note that you cannot put the /root/bin/trackpoint
script in the background in sleepyhead
, above. If you do, the process will be killed when sleepyhead
exits.
#!/bin/bash
# This is /root/bin/trackpoint
echo "Start $0"
date
found=false
dir=""
# dirlist can look like:
# /sys/devices/platform/i8042/serio1/serio25/speed
# /sys/devices/platform/i8042/serio1/serio24/speed
# ...the older one appears to get cleaned a little later.
sleep 1 # If I don't put this in here, my pointer locks up for a really long time...
for i in 1 2 3 4; do
speedfiles=$(find /sys/devices/platform/i8042 -name speed) # There may be multiple speed files at this point.
[ -z "$speedfiles" ] && { sleep 1; continue; }
dirlist=$(dirname $speedfiles)
printf "Speed file(s) at $(find /sys/devices/platform/i8042 -name speed | tail -1) \n"
# All this remaking of the path is here because the filenames change with
# every resume, and what's bigger: 9 or 10? ...Depends if you're
# lexicographical or numerical. We need to always be numerical.
largest_number="$(echo $dirlist | tr ' ' '\n' | sed -e 's/.*serio//' | sort -n | tail -1)"
dir="$(echo $dirlist | tr ' ' '\n' | egrep serio${largest_number}\$ )"
echo "Dir is $dir number is $largest_number"
[ -n "$dir" ] && found=true && break
done
$found || exit 1
date
echo -n 4 > $dir/inertia
echo -n 220 > $dir/sensitivity
echo -n 128 > $dir/speed
date
echo "Done $0"
Related videos on Youtube
Jean Felipe
I've a 20y experience in the eLearning and Computer Based Training, with a special focus on aviation (pilots and maintenance staff) training. I've good design and programming skill, including the following languges and toolkits, tools and Operarting Systems: Java (special focus on server side and client side cross-platform development and deployment) JavaScript / HTML5 / CSS3 (special focus on cross browser and cross devices development and optimizations for Mobile) C# C++ / Vala C / Objective-C PHP SQL SWT, GTK+, Cocoa ANT Flash and ActionScript 3 and 2 Inkscape, Gimp, Photoshop etc 3D Studio Max and Blender (basic) Linux, Windows, OS X, Android an iOS SVN, GIT Bugzilla, Mantis, JIRA I've a long experience in team working and management, software management, bug tracking and quality assurance, customer relationship management and problem solving. I'm a big fan of the OpenSource world and GNU/Linux. Most of my knowledge and skills come from passion, self-training and direct experience. SOreadytohelp
Updated on September 18, 2022Comments
-
Jean Felipe about 1 year
my Dell laptop is subject to this bug with kernel 3.14. As a workaround I wrote a simple script
/usr/bin/brightness-fix:
#!/bin/bash echo 0 > /sys/class/backlight/intel_backlight/brightnes
(and made executable:
chmod +x /usr/bin/brightness-fix
)and a systemd service calling it that is executed at startup:
/etc/systemd/system/brightness-fix.service
[Unit] Description=Fixes intel backlight control with Kernel 3.14 [Service] Type=forking ExecStart=/usr/bin/brightness-fix TimeoutSec=0 StandardOutput=syslog #RemainAfterExit=yes #SysVStartPriority=99 [Install] WantedBy=multi-user.target
and enabled:
systemctl enable /etc/systemd/system/brightness-fix.service
That works like a charm and I can control my display brightness as wanted. The problem comes when the laptop resumes after going to sleep mode (e.g. when closing the laptop lip): brightness control doesn't work anymore unless I manually execute my fisrt script above:
/usr/bin/brightness-fix
How can I create another systemd service like mine above to be executed at resume time?
EDIT: According to comments below I have modified my
brightness-fix.service
like this:[Unit] Description=Fixes intel backlight control with Kernel 3.14 [Service] Type=oneshot ExecStart=/usr/local/bin/brightness-fix TimeoutSec=0 StandardOutput=syslog [Install] WantedBy=multi-user.target sleep.target
also I have added
echo "$1 $2" > /home/luca/br.log
to my script to check whether it is actually executed. The script it is actually executed also at resume (post suspend
) but it has no effect (backlit is 100% and cannot be changed). I also tried logging$DISPLAY
and$USER
and, at resume time, they are empty. So my guess is that the script is executed too early when waking up from sleep. Any hint?-
jasonwryan over 9 years
WantedBy=sleep.target
... -
Jean Felipe over 9 yearsReally?! Is that so simple?! :) Can I add 'sleep.target' to my script above or shall I create a new dedicated systemd service script for it?
-
Jean Felipe over 9 years...according to documentation "This option may be used more than once, or a space-separated list of unit names may be given". I'm gonna try now.
-
user2914606 over 9 yearsyou must add it to your existing systemd service file (which, by the way, is not a script; it's a static configuration file). and as a side note, the Filesystem Hierarchy Standard states that the proper place to put scripts you wrote yourself is
/usr/local/bin
, not/usr/bin
. that directory is reserved for the package manager only. -
Jean Felipe over 9 yearsThanks for the information. I tried adding sleep.target to my systemd configuration file as suggested but it doesn't work. COuld it be that it is actually executed at resume too but perhaps too ealry (e.g. before the screen/video card driver is actuvated again?)
-
user2914606 over 9 yearsno idea. run a test using
touch
. (put atouch foobar
in your script and check for the existence offoobar
afterwards) -
fooot over 9 yearsMaybe just do a short
sleep
at the beginning of the script? -
jat255 about 8 yearsI believe using the
sleep.target
will run the unit when the computer sleeps, rather than when it resumes. See my answer below for a unit file that worked for me with a similar problem.
-
-
Emmanuel over 7 yearsWorks with
After=suspend.target
in Unit andWantedBy=multi-user.target sleep.target
in Install. -
mivk about 6 years@qdii : it may depend on the distribution and/or version. In Debian 8 Jessie and Ubuntu 16.04, the
system-sleep
directory appears to be in/lib/systemd/
, and/usr/lib/systemd
contains other stuff. -
Naftuli Kay almost 6 yearsI'm using the following units successfully here on Ubuntu 16.04 (elementary Loki).
-
Jarek almost 5 yearsVery nicely organized and documented. I'd give you multiple up votes if I could!
-
SebMa over 3 years@Emmanuel I don't understand why the
WantedBy
parameter is not enough. Once I click on the power button to resume the computer, am I not back inside themulti-user.target
? Can you please explain theWantedBy
parameter because theman systemd.unit
is not clear to me ? -
tanius about 3 yearsThe first script says "RUN trackpoint in background" but then runs it in the foreground. I guess that's from before you found out that it cannot be run in the background? Because you also write "you cannot put the … trackpoint script in the background … if you do, the process will be killed when sleepyhead exits."
-
tanius about 3 yearsJust for awareness, this solution is a bit of a hack. Because the manpage also says: "Note that scripts or binaries dropped in /usr/lib/systemd/system-sleep/ are intended for local use only and should be considered hacks."