62

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"
719016
  • 6,217
  • This seems to be a duplicate of http://askubuntu.com/questions/226278/run-script-on-wakeup/483714. See also my comment at http://askubuntu.com/a/483714/170127. – jamadagni Jun 15 '14 at 16:40

4 Answers4

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).

fader
  • 5,571
  • 1
    How do I need to call this script if the suspend/resume is called 20_something? – 719016 Jan 03 '12 at 10:50
  • 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 03 '12 at 13:28
  • 7
    Another (now deleted) answer had this: 'please note the following bug report: https://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 '15 at 09:43
  • 11
    On Ubuntu 15.10, the script has to be in /lib/systemd/system-sleep/ instead of /etc/pm/sleep. – Marc Belmont Jan 25 '16 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 '16 at 00:34
  • 3
    Tried the last two comments here on yakkety (16.10), and it didn't work. How to troubleshoot? – Gringo Suave Oct 18 '16 at 18:53
  • 1
    Didn't worked any of the locations in 16.04... any workaround or sugestion? – Rho Aug 03 '17 at 23:31
  • 2
    16.04 uses systemd. This answer is outdated for systemd systems. See the other answer here. – MountainX Dec 23 '18 at 18:00
  • thanks for showing the DISPLAY setting; xinput scripts need this. – Tim Richardson May 28 '19 at 05:28
13

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
    
janot
  • 1,672
  • 1
    This also seems to work on Ubuntu 18.04, thanks! – kelunik Jun 18 '18 at 07: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 '18 at 03:42
  • 1
    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 – Tim Richardson Sep 03 '19 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.

4

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.

  • 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 '21 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. – Martian2020 Sep 21 '21 at 06:01