12

Ubuntu 20.04

I have done a number of searches for ways to execute a script or command on resume from suspend, and come up with several different methods for doing this, such as what is described here - none of which worked for me.

The first method I found was using pm-utils. Apparently this method has been removed from Ubuntu, starting at or around 15.04

The next thing I found was to use systemd/system-sleep - this also didn't work for me. I tried creating a script in the /usr/lib/systemd/system-sleep directory, also tried the /lib/systemd/system-sleep directory (which is apparently linked to /usr/lib/systemd/system-sleep as changes in one appear in the other). I also tried modifying a script already present, called hdparm - this also didn't work (the modification I made was touch /tmp/xmodlog.log but the file never appeared).

So, can someone tell me what the correct way to run a script or command upon resume is?

Thanks for any input/suggestions/websites - especially ones with detailed instructions and explanations of what is happening along the way...

Edit:

Based on the answer provided by Matigo, I did the following:

In /etc/pm/sleep.d I created a script, called 00xmodkey.sh. I added the following script code into this file, then made sure it was owned by root, and that it had execute permissions.

Script contents (tried both sh and bash as the shell):

#!/bin/sh

case "${1}" in resume|thaw) touch /tmp/xmodlog.log echo "$(date) - lib testing" >> /tmp/xmodlog.log ;; esac

Verified ownership and permissions:

ls -l 00xmodkey.sh
-rwxr-xr-x 1 root root 257 Feb  4 22:49 00xmodkey.sh

Then I put the system into suspend. Waited `~20 seconds. Woke the system. Looked in /tmp for a file called xmodlog.log. No file.

So, I must still be missing something...

Edit 2:

Based on the response by blitzter47, I placed a script in /lib/systemd/system-sleep/ called 20xmodmap which I subsequently marked executable. The script file contained the following:

#!/bin/sh
# Remap a key to allow context menu access

case "$1" in post) echo "$(date) - lib testing" >> /tmp/xmodlog.log ;; *) echo "$(date) - $(1) $(2) - lib testing" >> /tmp/xmodlog.log ;; esac

exit 0

The file xmodlog.log never shows up in /tmp, so either something is wrong with the script, or the script is never being executed.

Edit 3:

Based on comments below, I changed the script to explicitly path the commands, and used touch rather than echo. No change in results. Also tried moving the location of the temporary file, just to make sure it wasn't something weird happening because of using /tmp, but again, no change. Here's the modified script:

#!/bin/sh
# Remap a key to allow context menu access

case "$1" in post) /bin/touch /home/tracy/xmodlog.log ;; *) /bin/touch /home/tracy/xmodlog.log ;; esac

exit 0

So, even with everything explicitly pathed, and using a folder that I know my user has access to (system should have access to anything, if it's running in system context), it still doesn't seem to be working.

Edit 4:

Requested output from 'sudo systemctl status sleep.target suspend.target hibernate.target hybrid-sleep.target':

tracy@tracy-HP17:~$ sudo systemctl status sleep.target suspend.target hibernate.target hybrid-sleep.target
● sleep.target - Sleep
     Loaded: loaded (/lib/systemd/system/sleep.target; static; vendor preset: e>
     Active: inactive (dead)
       Docs: man:systemd.special(7)

● suspend.target - Suspend Loaded: loaded (/lib/systemd/system/suspend.target; static; vendor preset:> Active: inactive (dead) Docs: man:systemd.special(7)

● hibernate.target - Hibernate Loaded: loaded (/lib/systemd/system/hibernate.target; static; vendor prese> Active: inactive (dead) Docs: man:systemd.special(7)

● hybrid-sleep.target - Hybrid Suspend+Hibernate Loaded: loaded (/lib/systemd/system/hybrid-sleep.target; static; vendor pr> Active: inactive (dead) Docs: man:systemd.special(7)

Edit 5:

So, I went in and cleaned up the script, and made sure that everything is functional (running from the command line works). Here are the commands and the output from setting up and running the script:

tracy@tracy-HP17:/usr/lib/systemd/system-sleep$ which ls
/usr/bin/ls
tracy@tracy-HP17:/usr/lib/systemd/system-sleep$ which echo
/usr/bin/echo
tracy@tracy-HP17:/usr/lib/systemd/system-sleep$ ls -la /lib/systemd/system-sleep
total 32
drwxr-xr-x  2 root root  4096 Mar  9 21:30 .
drwxr-xr-x 17 root root 12288 Jan 19 13:39 ..
-rwxr-xr-x  1 root root   405 Mar  9 21:22 20xmodmap
-rwxr-xr-x  1 root root   148 Feb 26 22:01 hdparm
-rw-r--r--  1 root root   404 Mar  9 20:54 holding.txt
-rwxr-xr-x  1 root root   219 Jul 21  2020 unattended-upgrades
tracy@tracy-HP17:/usr/lib/systemd/system-sleep$ nl 20xmodmap
     1  #!/bin/sh
     2  # Remap a key to allow context menu access
 3  /usr/bin/ls /home/tracy/TestScript/

 4  case "$1" in
 5      post) 
 6  #       /usr/bin/touch /home/tracy/TestScript/xmodlog.log
 7          /usr/bin/echo "post" > /home/tracy/TestScript/xmodlog.log
 8          ;;
 9      *)
10  #       /usr/bin/touch /home/tracy/TestScript/xmodlog.log
11          /usr/bin/echo "default" > /home/tracy/TestScript/xmodlog.log
12          ;;
13  esac

14  /usr/bin/ls /home/tracy/TestScript/

15  exit 0

tracy@tracy-HP17:/usr/lib/systemd/system-sleep$ ls /home/tracy/TestScript tracy@tracy-HP17:/usr/lib/systemd/system-sleep$ sudo ./20xmodmap [sudo] password for tracy: xmodlog.log tracy@tracy-HP17:/usr/lib/systemd/system-sleep$ ls /home/tracy/TestScript xmodlog.log tracy@tracy-HP17:/usr/lib/systemd/system-sleep$ nl /home/tracy/TestScript/xmodlog.log 1 default tracy@tracy-HP17:/usr/lib/systemd/system-sleep$ rm /home/tracy/TestScript/xmodlog.log rm: remove write-protected regular file '/home/tracy/TestScript/xmodlog.log'? y tracy@tracy-HP17:/usr/lib/systemd/system-sleep$ ls /home/tracy/TestScript

Also, below are the last two lines (by time stamp) shown by journalctl from both before sleep and after resume:

Last two lines before sleep

tracy@tracy-HP17:/usr/lib/systemd/system-sleep$ journalctl -xe | grep 'sleep\|suspend'
Mar 09 21:30:21 tracy-HP17 sudo[132552]:    tracy : TTY=pts/0 ; PWD=/usr/lib/systemd/system-sleep ; USER=root ; COMMAND=./20xmodmap
Mar 09 21:37:40 tracy-HP17 sudo[132821]:    tracy : TTY=pts/0 ; PWD=/usr/lib/systemd/system-sleep ; USER=root ; COMMAND=./20xmodmap

Last two lines after resume

tracy@tracy-HP17:/usr/lib/systemd/system-sleep$ journalctl -xe | grep 'sleep\|suspend'
Mar 09 21:30:21 tracy-HP17 sudo[132552]:    tracy : TTY=pts/0 ; PWD=/usr/lib/systemd/system-sleep ; USER=root ; COMMAND=./20xmodmap
Mar 09 21:37:40 tracy-HP17 sudo[132821]:    tracy : TTY=pts/0 ; PWD=/usr/lib/systemd/system-sleep ; USER=root ; COMMAND=./20xmodmap

It appears that the script is not being run upon resume, as the output from journalctl both before and after are identical....

Edit 6:

OK, so based on a comment below by blitzter47, I dug deeper into what all is happening here from a power management standpoint. And it looks like I had some (incorrect) preconceptions of what was going on.

First, following the lead in the comment, issuing sudo systemctl suspend then waking the system does execute the script located in /lib/systemd/system-sleep, as indicated by the target file being created and containing the word "post". This is the first time (other than executing the script from the command line) that this has happened (and I am understandably excited that this progress is being made).

So, this led me to wonder what the difference was in that command, and what I had been doing. And after reading the article Understanding Suspend I believe what had been happening is that I was reaching the S1 state, but that the sudo systemctl suspend command was reaching the S3 state. Or, to put it another way, I was merely locking the screen, but not actually suspending the computer (except when the machine was untended for an extended period of time, which I will touch on in just a minute).

So, I went back over what I was actually trying to accomplish - which is to cause a particular keyboard shortcut to survive when the system "suspended". I had previously noted that there were some occasions where the keyboard shortcut would survive when I returned to the computer, and some occasions where it didn't, but I hadn't figured out exactly where that was coming from. Well, I now posit that the times it survived were the times when the system simply locked the screen (ie. reached the S1 state), but didn't actually suspend (ie. didn't reach S3 state). Whereas the times the keyboard shortcut didn't survive, the machine had actually reached the suspect (S3) state - possibly by being left undisturbed for a longer period of time.

So, the bottom line seems to be that system-sleep does work correctly for what I am trying to do (now that I actually understand what that is). So, my next step will be to actually update the script from Edit 5 (which is working correctly when I reach suspend (ie. S3 state)) with the command to restore my keyboard shortcut, then see if there are situations where the keyboard shortcut fails to survive, then re-evaluate what is happening at that point.

So, given all of this, I am going to mark blitzter47's original answer as accepted, and if/when I note that my keyboard shortcut doesn't survive a particular state, I will post a new question with (hopefully) a better idea of what the underlying cause is.

Tracy
  • 417
  • You should also consider that the command echo might not be recognized because the environment variable PATH might not have been sourced by systemd. Same thing with date. Use instead absolute path: /bin/echo and /bin/date. Because of this, it's why my template has the variable PATH defined manually. To make your test simpler with less unknown variables while debugging, I suggest just to use the command /bin/touch /tmp/xmodlog.log first to check if the script has been executed. I would avoid /tmp/ during testing, just in case something else erases its content at the same moment. – Lilly-R B Feb 26 '21 at 00:41
  • I'm unsure if systemd runs as root or as the user. So make sure the place where you put the log file for your test is at least writable by you. – Lilly-R B Feb 26 '21 at 00:44
  • If I open a terminal in /tmp, then do the command touch xmodlog.log, the file is created. This would tend to indicate that I have write access to /tmp – Tracy Feb 27 '21 at 02:41
  • I will try modifying the script to use /bin/touch and see if that makes a difference. – Tracy Feb 27 '21 at 02:44
  • Still no dice. I don't know if it's possible to make the script any more basic, so I'm not sure what else to look at.... – Tracy Feb 27 '21 at 02:59
  • May you provide the output of terminal command sudo systemctl status sleep.target suspend.target hibernate.target hybrid-sleep.target to see of systemd related targets are enabled? What is expected is those targets are enabled, so a line for each target should output e.g. Loaded: loaded (/lib/systemd/system/sleep.target; static; vendor preset: enabled). – Lilly-R B Mar 04 '21 at 19:24
  • Also, I may have mistaken with the path of /bin/touch. If you call the terminal command whereis touch, one of the path shown is "/usr/bin/touch", not "/bin/touch". My apologies. – Lilly-R B Mar 04 '21 at 19:29
  • Changed the path for touch to /usr/bin/touch with no change. Edited the original post to include the output requested. – Tracy Mar 06 '21 at 03:26
  • Does your script work if you run it manually in terminal $ ./00xmodkey.sh ? – Lilly-R B Mar 08 '21 at 22:38
  • What is the output when listing files in terminal : $ ls -la /lib/systemd/system-sleep/ – Lilly-R B Mar 08 '21 at 23:08
  • And let's have a look in the logs right after you resume from suspend : $ journalctl -xe | grep 'sleep\|suspend'. Then check output to remove personal information before publishing here, just in case. – Lilly-R B Mar 08 '21 at 23:17
  • Editing with requested information, and showing that the script does work from the command line – Tracy Mar 10 '21 at 02:43
  • 1
    If you send the command $ sudo systemctl suspend to trigger suspend, is there any change in the logs and the execution of the script? – Lilly-R B Mar 12 '21 at 00:26
  • You might want to uninstall pm-utils by the way to avoid any possible interference. – Lilly-R B Mar 12 '21 at 00:27
  • OK, I think we might be hitting pay dirt here - and partly this comes from a "misunderstanding" over terminology. See Edit 6 in my post for discussion – Tracy Mar 13 '21 at 03:24

2 Answers2

19

First, Ubuntu 20.04 uses systemd, not pm. Second, the script content with systemd is different. You should try with this template below and put your script in /lib/systemd/system-sleep/ with executable bit:

#!/bin/sh

PATH=/sbin:/usr/sbin:/bin:/usr/bin

case "$1" in pre) #code execution BEFORE sleeping/hibernating/suspending ;; post) #code execution AFTER resuming ;; esac

exit 0

The line where PATH=/sbin:/usr/sbin:/bin:/usr/bin is assigned explicitely is required if you intend to call commands as you would do in terminal command-line. If not, you must use absolute path of the related command binary file e.g. $ /usr/bin/touch /myfile instead of $ touch /myfile.

Find absolute path of a command binary file

You can get/check absolute path of a specific command binary file with e.g. $ whereis touch, which will output the absolute path of the binary /usr/bin/touch which interests us :

$ whereis touch
touch: /usr/bin/touch /usr/share/man/man1/touch.1.gz

Is systemd suspend.target enabled?

In case it doesn't work, you may check if systemd related targets are enabled with

$ sudo systemctl status sleep.target suspend.target hibernate.target hybrid-sleep.target

The output should look like :

● sleep.target - Sleep
     Loaded: loaded (/lib/systemd/system/sleep.target; static; vendor preset: enabled)
     Active: inactive (dead)
       Docs: man:systemd.special(7)

[...]

● suspend.target - Suspend Loaded: loaded (/lib/systemd/system/suspend.target; static; vendor preset: enabled) Active: inactive (dead) Docs: man:systemd.special(7)

[...]

● hibernate.target - Hibernate Loaded: loaded (/lib/systemd/system/hibernate.target; static; vendor preset: enabled) Active: inactive (dead) Docs: man:systemd.special(7)

[...]

● hybrid-sleep.target - Hybrid Suspend+Hibernate Loaded: loaded (/lib/systemd/system/hybrid-sleep.target; static; vendor preset: enabled) Active: inactive (dead) Docs: man:systemd.special(7)

Lilly-R B
  • 368
  • I'm editing my original question to include the script I placed in /lib/systemd/system-sleep/ - which didn't produce any output - it's pretty basic, so I think if this approach were working, the script should have worked... – Tracy Feb 24 '21 at 23:40
  • As per Edit 6 in my original posting, it appears that we have gotten the script working in the correct settings. Now I need to dig deeper into my "expectations" and make sure that this solves what started all this. Thank you for sticking with me on this one. – Tracy Mar 13 '21 at 03:49
  • Kudos for mentioning the PATH, that was the missing puzzle for my script and all the other answers overlooked it! – HumbleBee Oct 11 '21 at 07:58
  • Hi Tracy, I found your answer via this https://askubuntu.com/questions/1407516/play-an-notification-sound-to-confirm-sleep-is-triggered. I can get this to work, e.g. by printing a date to a logfile, but I am trying to play sound, which doesn't seem to work. I have a full path. – bjohas May 10 '22 at 19:30
0

The simplest way to execute a script on resume is to put an executable file in /etc/pm/sleep.d. These are the steps that I have had success with when using Ubuntu 18.04 and newer:

  1. Save a script to /etc/pm/sleep.d with a name like 10_action_description

  2. Ensure the file is owned by root:

    sudo chown root:root /etc/pm/sleep.d/10_play_windows_xp_chimes
    
  3. Ensure the file is executable:

    sudo chmod +x /etc/pm/sleep.d/10_play_windows_xp_chimes
    

A recent example of this process — with a working script — can be found here.

Hope this helps you accomplish your goals

  • 2
    Tried what you suggested, with no luck. You mention having done with under 18.04 - I'm running 20.04. I wonder if there's a dfference in there somewhere.... – Tracy Feb 05 '21 at 04:09
  • I can not get any script to execute after resume from sleep either. – fixit7 Feb 27 '21 at 03:08