61

I've got a script that is executed in order to have suspending/resuming working in my laptop. Then I have another series of xinput,xkbset and xmodmap commands that are executed when I initiate a session to have two-finger scrolling and keyboard shortcuts set up. When I resume from suspend, two-finger scrolling and my keyboard shortcuts won't work. I need to manually execute the commands in the second file again. How can I add those to the suspend/resume script to have this done automatically? See below:

suspend/resume script

/etc/pm/sleep.d/20_custom-ehci_hcd

#!/bin/sh
#inspired by http://art.ubuntuforums.org/showpost.php?p=9744970&postcount=19
#...and http://thecodecentral.com/2011/01/18/fix-ubuntu-10-10-suspendhibernate-not-working-bug    
# tidied by tqzzaa :)

VERSION=1.1
DEV_LIST=/tmp/usb-dev-list
DRIVERS_DIR=/sys/bus/pci/drivers
DRIVERS="ehci xhci" # ehci_hcd, xhci_hcd
HEX="[[:xdigit:]]"
MAX_BIND_ATTEMPTS=2
BIND_WAIT=0.1

unbindDev() {
  echo -n > $DEV_LIST 2>/dev/null
  for driver in $DRIVERS; do
    DDIR=$DRIVERS_DIR/${driver}_hcd
    for dev in `ls $DDIR 2>/dev/null | egrep "^$HEX+:$HEX+:$HEX"`; do
      echo -n "$dev" > $DDIR/unbind
      echo "$driver $dev" >> $DEV_LIST
    done
  done
}

bindDev() {
  if [ -s $DEV_LIST ]; then
    while read driver dev; do
      DDIR=$DRIVERS_DIR/${driver}_hcd
      while [ $((MAX_BIND_ATTEMPTS)) -gt 0 ]; do
          echo -n "$dev" > $DDIR/bind
          if [ ! -L "$DDIR/$dev" ]; then
            sleep $BIND_WAIT
          else
            break
          fi
          MAX_BIND_ATTEMPTS=$((MAX_BIND_ATTEMPTS-1))
      done  
    done < $DEV_LIST
  fi
  rm $DEV_LIST 2>/dev/null
}

case "$1" in
  hibernate|suspend) unbindDev;;
  resume|thaw)       bindDev;;
esac

touchpad two-finger scrolling and keyboard shortcuts script

xinput set-int-prop "SynPS/2 Synaptics TouchPad" "Two-Finger Scrolling" 8 1
xinput set-int-prop "SynPS/2 Synaptics TouchPad" "Synaptics Two-Finger Scrolling" 8 1 1
xinput set-int-prop "SynPS/2 Synaptics TouchPad" "Synaptics Two-Finger Pressure" 32 10
xinput set-int-prop "SynPS/2 Synaptics TouchPad" "Synaptics Two-Finger Width" 32 8
setxkbmap -layout gb
xkbset m
xkbset exp =m
xmodmap -e "keycode 135 = Pointer_Button2"
1

4 Answers 4

48

You can place your scripts in the /etc/pm/sleep.d directory to have them run after suspend. You will need to add a conditional to make your script run only during resume and not during the suspend process as well. For example, your touchpad script would look like:

case "${1}" in
    resume|thaw)
        DISPLAY=:0.0 ; export DISPLAY
        xinput set-int-prop "SynPS/2 Synaptics TouchPad" "Two-Finger Scrolling" 8 1
        xinput set-int-prop "SynPS/2 Synaptics TouchPad" "Synaptics Two-Finger Scrolling" 8 1 1
        xinput set-int-prop "SynPS/2 Synaptics TouchPad" "Synaptics Two-Finger Pressure" 32 10
        xinput set-int-prop "SynPS/2 Synaptics TouchPad" "Synaptics Two-Finger Width" 32 8
        setxkbmap -layout gb
        xkbset m
        xkbset exp =m
        su $USER -c "sleep 3; /usr/bin/xmodmap -e "keycode 135 = Pointer_Button2"" &
;;
esac

Be sure your script is marked globally executable and change $USER to the corresponding username.

You can find more detailed information in the pm-suspend manpage (man pm-suspend) or by looking at the documentation in /usr/share/doc/pm-utils (particularly /usr/share/doc/pm-utils/HOWTO.hooks.gz).

9
  • 2
    It can be called whatever you like. It's a good idea to start it with a number between 00-49, per the pm-suspend manpage: "00 - 49 User and most package supplied hooks. If a hook assumes that all of the usual services and userspace infrastructure is still running, it should be here."
    – fader
    Jan 3, 2012 at 13:28
  • 6
    Another (now deleted) answer had this: 'please note the following bug report: launchpad.net/ubuntu/+source/pm-utils/+bug/1455097 after upgrading to vivid scripts need to be put into /lib/systemd/system-sleep/'
    – Wilf
    Aug 15, 2015 at 9:43
  • 10
    On Ubuntu 15.10, the script has to be in /lib/systemd/system-sleep/ instead of /etc/pm/sleep. Jan 25, 2016 at 14:00
  • 11
    On Ubuntu 16.04 the arguments given to the script are pre before entering suspend and post after resume instead of suspend and resume
    – Germar
    Jul 22, 2016 at 0:34
  • 3
    Tried the last two comments here on yakkety (16.10), and it didn't work. How to troubleshoot? Oct 18, 2016 at 18:53
12

On Ubuntu 16.04 I had to create service this way:

  1. create file

    sudo gedit /etc/systemd/system/somename.service
    
  2. put inside

    [Unit]
    Description=Some description
    Before=sleep.target
    StopWhenUnneeded=yes
    
    [Service]
    Type=oneshot
    RemainAfterExit=yes
    ExecStop=-/path/to/your/script.sh
    
    [Install]
    WantedBy=sleep.target
    
  3. enable service

    sudo systemctl enable somename
    
  4. (optional) if not working after resume from suspend > check for errors with

    journalctl -u somename.service
    
3
  • This also seems to work on Ubuntu 18.04, thanks!
    – kelunik
    Jun 18, 2018 at 7:02
  • 3
    Why does Ubuntu leave /etc/pm/sleep.d lying around if it doesn't use it? It is confusing and misleading.
    – Coder Guy
    Sep 23, 2018 at 3:42
  • This worked for me on ubuntu 18.04 (actually KDE Neon), but I had to a): Under [Service], put User=tim so that script runs as my user b) in my script, do DISPLAY=:0.0 ; export DISPLAY Sep 3, 2019 at 21:58
11

Open this file:

sudo vim /lib/systemd/system-sleep/hdparm

Contents:

#!/bin/sh

case $1 in 
  post)
    /usr/lib/pm-utils/power.d/95hdparm-apm resume
    ## Paste your command to run your script
    ;; esac

Your command will execute with admin privileges.

5
  • 1
    This worked with kubuntu 18.04. Using another file other than hdparm in the same directory didn't work.
    – Phil
    Mar 11, 2020 at 22:10
  • it does not work on Ubuntu 19.10 Mar 19, 2020 at 19:09
  • 1
    Works on Debian 10
    – john doe
    Apr 10, 2020 at 2:27
  • @Phil, maybe you did not give another file in /lib/systemd/system-sleep/ executable permission. Answer on duplicate Q here gives lots of details on systemd way: askubuntu.com/a/620328/1152748 Sep 21, 2021 at 6:20
  • This fails for X commands on Ubuntu because the root user doesn't have access to the display of the logged in user. The answer from janot worked for me.
    – AdamS
    Feb 19, 2023 at 17:17
3

Here is the version I use to restart my VPN daemon after resume:

#!/bin/sh

case "$1" in
        pre)
                echo "$(date) - $1: Restarting norvpnd" >> /tmp/nordvpn/suspend.txt
                /usr/bin/systemctl restart nordvpnd
                ;;
        post)
                echo "$(date)-  $1: Doing nothing" >> /tmp/nordvpn/suspend.txt
                ;;
esac

This file is put in:

/lib/systemd/system-sleep//00restart_nordvpnd.sh

This works fine in Ubuntu 20.4. The pre part is executed before putting the computer to sleep (suspend) and the post part is executed when it is resumed, as that can be verified by looking at the /tmp/nordvpn/suspend.txt file.

Side note (irrelevant to the subject but worth noting): Regarding the task in this example, it might seem illogical to restart a daemon before putting the computer to sleep, but it's the (only?) way it works.

2
  • This gives me "Failed to execute /lib/systemd/system-sleep/00_pre-and-post-suspend.sh: Not a directory" when I check with 'journalctl -u systemd-suspend.service' (in 20.04) - any idea what is wrong here?
    – Stefan
    Jan 30, 2021 at 21:01
  • @Stefan, do you have that entry in your file system, is it directory? check with ls -l /lib/systemd/system-sleep/00_pre-and-post-suspend.sh. Sep 21, 2021 at 6:01

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .