Running scripts before and after suspend with systemd

I’ve had this question a few times, so it’s probably a good candidate for my blog.

If you want to do something before you suspend, like unload a module or run some script, it’s quite easy with systemd. Similarly, you can easily do something when the system resumes (like reload the module).

The details are in the systemd-suspend man page:
man systemd-suspend.service

Simply put an executable script of any name under /usr/lib/systemd/system-sleep/ that checks whether the first argument is pre (for before the system suspends) or post (after the system wakes from suspend).

If it is pre, then do the thing you want to before suspend, if it’s post then do the thing you want to do after resume. Simple!

Here’s a useless example:
#!/bin/sh
if [ "${1}" == "pre" ]; then
  # Do the thing you want before suspend here, e.g.:
  echo "we are suspending at $(date)..." > /tmp/systemd_suspend_test
elif [ "${1}" == "post" ]; then
  # Do the thing you want after resume here, e.g.:
  echo "...and we are back from $(date)" >> /tmp/systemd_suspend_test
fi

22 thoughts on “Running scripts before and after suspend with systemd”

  1. Other users of Debian might want to take notice that the path to place the files under for that distribution is /lib/systemd/system-sleep/, i.e. without the initial /usr. Although this actually is properly documented with the correct path in the man page, it is a detail which is easy to miss.

  2. Thank you, this helped me a lot!
    I actually expected lots of hacking but it’s just a systemd thing.
    Still, saved me a lot of manpage digging!
    Worked on Fedora with systemd!

  3. Thanks, now my keyboard backlight settings get saved and restored correctly on suspend/resume 🙂

  4. Hi Klaus,

    I haven’t tested that, but it looks like by the time you get to running the script as per my blog, the suspend process has already begun which has taken out your networking service.

    The solution looks complicated, but basically it’s just a systemd service file which does something just before suspend. For you, that could be the server backup. Keep in mind though that even if you did this, there are timeouts you’ll need to contend with. Also, it seems to me that you won’t get any visibility into the backup (did it really finish before your system was suspended?).

    Is there a reason you have to do your backup before suspend? Can you just run backups on an hourly cronjob or something? If you’re using rsync (or rsnapshot) then you’ll just send the differences anyway.

    -c

  5. Hi Chris,

    Thanks for your answer and thanks for the good work.

    You are right that crontab is a way to go, though I would prefer to back-up automatically, when I am finished working and closing down.
    (combined with ad-hoc backups).

    With respect to timeouts etc. my plan was to make a check at restart.

    Yes, I am using rsync and it is working perfect, but since it is often remotely (ssh+internet) it can be slow and time consuming and annoying while doing other work.(Thunderbird is a bad choice in that respect, since even small changes can cause large files to be sync’ed).

  6. Hi,

    Thanks for the example code!

    I’ve just started using Linux and I’ve been pulling my hair over my tuner card crashing after suspend, but now I’m finally able to unload Tvheadend and my TV tuner driver before suspend and restart them after suspend.

    I had to make a small adjustment to the script, since I got an error “unexpected operator” in the if-statements.

    Before if [ “${1}” == “pre” ]; then
    After if [ “${1}” = “pre” ]; then

    So, one “equal” sign less.
    I’m running Linux Mint 19.1, kernel 4.18.0-13
    I hope this is helpful for someone.

  7. When I run the example script, nothing happens.

    I am running Ubuntu Mate 18.04.

    Thanks.

  8. Do you mean manually run it, or as part of suspend/resume? How do you know it’s not doing anything? The example script just writes to a file, do you have anything in that file?

    cat /tmp/systemd_suspend_test
  9. It does not create a file when run manually or part of resume.

    #!/bin/sh
    #
    # Created 3/31/19 in /usr/lib/systemd/system-sleep/
    if [ “${1}” = “pre” ]; then
    # Do the thing you want before suspend here
    echo “we are suspending at $(date)…” > /home/andy/Downloads/systemd_suspend_test
    elif [ “${1}” = “post” ]; then
    # Do the thing you want after resume here
    echo “…and we are back from $(date)” >> /home/andy/Downloads/systemd_suspend_test
    /usr/bin/gxmessage -fg red -font ‘sans 30’ -timeout 3 ‘ Computer has now resumed from suspend state.’
    fi

  10. This was in my syslog.

    Apr 1 10:14:33 7 systemd-sleep[32421]: System resumed.
    Apr 1 10:14:33 7 systemd-sleep[32421]: /lib/systemd/system-sleep/On_Resume.sh: 2: [: post: unexpected operator
    Apr 1 10:14:33 7 systemd-sleep[32421]: /lib/systemd/system-sleep/On_Resume.sh: 5: [: post: unexpected operator

  11. Hi Chris,

    Thanks for the script! I almost… got it to work. I wanted to include a quick loop which would pause all my media applications before suspend (say closing laptop lid) so they wouldn’t start playing as soon as I open the lid (even before I log in).

    So I tried this:

    if [ "${1}" = "pre" ]; then
    echo "start pre at $(date)..." > /tmp/systemd_suspend_test
    for OUTPUT in $(playerctl -l)
    do
    playerctl -p $OUTPUT pause
    done
    echo $(playerctl -l) >> /tmp/systemd_suspend_test
    elif [ "${1}" = "post" ]; then
    echo "start post at $(date)..." >> /tmp/systemd_suspend_test
    fi

    The loop itself works perfectly when I execute it in the terminal manually. Unfortunately, it seems that the output of “playerctl -l” is empty as indicated by an empty line in the systemd_suspend_test file:

    start pre at Thu 29 Oct 16:52:25 GMT 2020...

    start post at Thu 29 Oct 16:52:30 GMT 2020...

    Am I missing something? Any reason playerctl fails to run? I couldn’t find anything of use in the syslog file. I’m running Mint 20.

    Best
    Edvin

  12. hi, i am trying to run a Python Script as followed:

    #!/usr/bin/python3

    import openrazer.client
    devices = openrazer.client.DeviceManager().devices
    for device in devices:
    if device.name == “Razer Naga Trinity”:
    device.fx.static(255,255,255)

    this script works, it tells my mouse to set the leds to white.

    i made it executable and copied it to /usr/bin/wakeup_trinity

    next i copied an existing sycript in /usr/lib/systemd/system-sleep/ called hdparm to trinity and edited it like this:

    #!/bin/sh

    case $1 in
    post)
    python3 /usr/bin/wakeup_trinity
    ;;
    esac

    sadly it does not work. syslog tells me:

    Nov 5 20:28:44 mimicri systemd-sleep[47560]: File “/usr/bin/wakeup_trinity”, line 4, in
    Nov 5 20:28:44 mimicri [47545]: /usr/lib/systemd/system-sleep/trinity failed with exit status 1.

    Please help, what is going wrong?

    System is PopOS 20.10

    thanks,

    micha

  13. I’m not sure, I haven’t tried that, sorry.. if you’re using X probably, not sure about Wayland. It also might not happen at the time you want it to. Would be something interesting to play with!

Leave a Reply

Your email address will not be published. Required fields are marked *