3

I did an experiment. I used K3b to burn an iso on a CD-RW. During that process, I issued systemctl suspend.

The computer did suspend.

Am I misunderstanding systemd-inhibit?

I looked at this and not sure if it could help.

How to inhibit suspend temporarily?

  systemd-inhibit may be used to execute a program with a shutdown, sleep, or idle inhibitor
       lock taken. The lock will be acquired before the specified command line is executed and
       released afterwards.
   Inhibitor locks may be used to block or delay system sleep and shutdown requests from the
   user, as well as automatic idle handling of the OS. This is useful to avoid system
   suspends while an optical disc is being recorded, or similar operations that should not be
   interrupted.

Artur Meinild
  • 26,018
fixit7
  • 3,127
  • There is a bug reported about the command working, but not the dbus interface: https://github.com/systemd/systemd/issues/29818 – jrpear Nov 12 '23 at 15:00

1 Answers1

1

I had the same problem - after calling command wrapped by systemd-inhibit my laptop successfully went to a sleep state. I haven't found a solution to this issue, but i have a good workaround. (I'm using archlinux, yet, i believe it should work in most cases.)

The main idea is to wrap the main service (binary or script) that is implementing sleeping functionality.

1. Find the main service

$ systemctl status systemd-suspend.service
○ systemd-suspend.service - System Suspend
     Loaded: loaded (/usr/lib/systemd/system/systemd-suspend.service; static)

Check contents of /usr/lib/systemd/system/systemd-suspend.service

$ cat /usr/lib/systemd/system/systemd-suspend.service
...
[Service]
Type=oneshot
ExecStart=/usr/lib/systemd/systemd-sleep suspend

And the winner is /usr/lib/systemd/systemd-sleep. Note that it consumes one argument, so wrapper script shouldn't lose it. As a bonus, we will fix all other modes (poweroff and hibernate) in a one place.

$ file /usr/lib/systemd/systemd-sleep
/usr/lib/systemd/systemd-sleep: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=fa6da37bf95f4a7255909a8e18fecbc1f3910acc, for GNU/Linux 4.4.0, stripped

2. Move it

sudo mv /usr/lib/systemd/systemd-sleep /usr/lib/systemd/systemd-sleep.bin

3. Create a wrapper script

For example, in my .bash_aliases i have:
alias lxcexport="systemd-inhibit lxc image export". Export called by this alias should block sleep service until lxc finishes container export.

In systemd-inhibit report it's marked blocked by a systemd-inhibit COMMand:

$ systemd-inhibit --list --no-pager
WHO                                UID  USER PID    COMM            WHAT                                WHY      MODE 
...
lxc image export server:container… 1000 cot 868971 systemd-inhibit shutdown:sleep:idle                 Unknown… block
...

So in wrapper script we delay called sleep action for a predefined delay (e.g. 5 sec) while systemd-inhibit --list --no-pager --no-legend|grep systemd-inhibit returns non-empty result. After lock is released, grep will return nothing and the script will continue and call the main sleep service binary with passed argument.

NB Keep in mind once it fires, it won't automatically stop on user re-activation. i.e. it will continue action ignoring you.

sudo vi /usr/lib/systemd/systemd-sleep.wrapper

#!/bin/sh
while test -n "$(systemd-inhibit --list --no-pager --no-legend|grep systemd-inhibit)" ; do 
    printf '.'
    sleep 5
done

/usr/lib/systemd/systemd-sleep.bin $1

Make it executable.

sudo chmod +x /usr/lib/systemd/systemd-sleep

Finally, create a link to the wrapper script. That way, you won't lose the wrapper script if a planned system update overwrites systemd-sleep.

sudo ln -s /usr/lib/systemd/systemd-sleep.wrapper /usr/lib/systemd/systemd-sleep

In log it looks smth like that:

May 09 08:54:53 LIVE.ARCH.BOX systemd-logind[798]: The system will suspend now!
May 09 08:54:53 LIVE.ARCH.BOX systemd[1]: Reached target Sleep.
May 09 08:54:53 LIVE.ARCH.BOX systemd[1]: Starting System Suspend...
May 09 08:54:53 LIVE.ARCH.BOX systemd-logind[798]: Operation 'sleep' finished.
May 09 08:58:27 LIVE.ARCH.BOX systemd[1545]: snap.lxd.lxc.9a9d4293-449f-4314-91b3-02aca1c4006b.scope: Consumed 4min 39.349s CPU time.
May 09 08:58:29 LIVE.ARCH.BOX systemd-sleep[859442]: ...........................................
May 09 08:58:29 LIVE.ARCH.BOX systemd-sleep[863081]: Going to suspend...
May 09 08:58:29 LIVE.ARCH.BOX systemd-sleep[863080]: Going to suspend...
May 09 08:58:29 LIVE.ARCH.BOX systemd-sleep.bin[863078]: Entering sleep state 'suspend'...
May 09 08:58:29 LIVE.ARCH.BOX kernel: PM: suspend entry (deep)
May 09 08:58:29 LIVE.ARCH.BOX kernel: Filesystems sync: 0.487 seconds

TIP The same can be done with pm-utils (but this time i've modified action script directly) :

$ which pm-hibernate
/usr/bin/pm-hibernate
10:24:34 [cot@LIVE ~]$ ls -la /usr/bin/pm-hibernate
lrwxrwxrwx 1 root root 31 May  8  2021 /usr/bin/pm-hibernate -> /usr/lib/pm-utils/bin/pm-action

.

$ cat /usr/lib/pm-utils/bin/pm-action

... command_exists "check_$METHOD" && command_exists "do_$METHOD" || { log "pm-utils does not know how to $METHOD on this system." exit 1 }

##delay if systemd-inhibit was called by someone while test -n "$(systemd-inhibit --list --no-pager --no-legend|grep systemd-inhibit)" ; do printf '.' sleep 55 done ...

diabolusss
  • 63
  • 5