10

I am on Arch Linux where I am trying to create a systemd timer as a cron alternative for hibernating my laptop on low battery. So I wrote these three files:

/etc/systemd/system/battery.service

[Unit]
Description=Preko skripte preveri stanje baterije in hibernira v kolikor je stanje prenizko

[Service]
Type=oneshot
ExecStart=/home/ziga/Dropbox/workspace/operacijski/archlinux/hibernate/hibernatescript
User=nobody
Group=systemd-journal

/etc/systemd/system/battery.timer

[Unit]
Description=Periodical checking of battery status every two minutes

[Timer]
OnUnitActiveSec=2min 

[Install]
WantedBy=timers.target

/home/ziga/Dropbox/workspace/operacijski/archlinux/hibernate/hibernatescript

#!/bin/sh
/usr/bin/acpi -b | /usr/bin/awk -F'[,:%]' '{print $2, $3}' | (
        read -r status capacity
        if [ "$status" = Discharging ] && [ "$capacity" -lt 50 ]; then
                /usr/bin/systemctl hibernate
        fi                                                                                                                
)    

And then to enable timer I executed:

sudo systemctl enable battery.timer
sudo systemctl start battery.timer

And somehow it isn't working. Script works on its own. This means that if I execute command below, my computer hibernates just fine.

/home/ziga/Dropbox/workspace/operacijski/archlinux/hibernate/hibernatescript

ADD1:

After enabling and starting timer I ran some checks and this is what I get:

[ziga@ziga-laptop ~]$ systemctl list-timers
NEXT                          LEFT       LAST                          PASSED    UNIT                         ACTIVATES
n/a                           n/a        n/a                           n/a       battery.timer                battery.serv
Tue 2016-06-28 00:00:00 CEST  42min left Mon 2016-06-27 00:01:54 CEST  23h ago   logrotate.timer              logrotate.se
Tue 2016-06-28 00:00:00 CEST  42min left Mon 2016-06-27 00:01:54 CEST  23h ago   shadow.timer                 shadow.servi
Tue 2016-06-28 00:00:00 CEST  42min left Mon 2016-06-27 00:01:54 CEST  23h ago   updatedb.timer               updatedb.ser
Tue 2016-06-28 22:53:58 CEST  23h left   Mon 2016-06-27 22:53:58 CEST  23min ago systemd-tmpfiles-clean.timer systemd-tmpf

and

[ziga@ziga-laptop ~]$ systemctl | grep battery
battery.timer  loaded active elapsed   Periodical checking of battery status every two minutes

ADD2:

After applying solution from Alexander T my timer starts (check the code below) but script doesn't hibernate my laptop while it hibernates it if I execute it directly.

[ziga@ziga-laptop ~]$ systemctl list-timers
NEXT                          LEFT          LAST                          PASSED       UNIT                         ACTIVATES
Tue 2016-06-28 19:17:30 CEST  1min 43s left Tue 2016-06-28 19:15:30 CEST  16s ago      battery.timer                battery.service
71GA
  • 1,056
  • 5
  • 18
  • 38
  • 2
    Is it possibly a permissions issue? When you say *you* ran it, was it as the `nobody` user, or as ziga (I see `/home/ziga`)? [User nobody may not have sufficient permissions](http://unix.stackexchange.com/a/186581/147451). When you say it *isn't working*, how far does it get? – tniles Jun 27 '16 at 20:33
  • I have tried to change the user to `ziga` but it doesn't work. – 71GA Jun 27 '16 at 21:18
  • I tried changing `WantedBy=timers.target`to `WantedBy=battery.service` in **/etc/systemd/system/battery.timer** but this doesn't do anything. – 71GA Jun 28 '16 at 17:38

2 Answers2

7

An answer to this question is to swap User=nobody not with User=ziga but with User=root in /etc/systemd/system/battery.service. Somehow even if user ziga has all the privileges of using sudo command it can't execute systemctl hibernate inside of the bash script. I really don't know why this happens. So the working files are as follows:

/etc/systemd/system/battery.service

[Unit]
Description=Preko skripte preveri stanje baterije in hibernira v kolikor je stanje prenizko

[Service]
Type=oneshot
ExecStart=/home/ziga/Dropbox/workspace/operacijski/archlinux/hibernate/hibernatescript
User=root
Group=systemd-journal

/etc/systemd/system/battery.timer

[Unit]
Description=Periodical checking of battery status every two minutes

[Timer]
OnBootSec=2min
OnUnitActiveSec=2min 

[Install]
WantedBy=battery.service

/home/ziga/Dropbox/workspace/operacijski/archlinux/hibernate/hibernatescript

#!/bin/sh
/usr/bin/acpi -b | /usr/bin/awk -F'[,:%]' '{print $2, $3}' | (
        read -r status capacity
        if [ "$status" = Discharging ] && [ "$capacity" -lt 7 ]; then
                /usr/bin/systemctl hibernate
        fi
)

I tried it and it allso works with User=ziga or User=nobody but we need to change /usr/bin/systemctl hibernate into sudo /usr/bin/systemctl hibernate in the last script. So it looks like User variable somehow doesn't even matter... Oh and you can as well remove absolute names from the last script and change first line from #!/bin/sh to #!/bin/bash. I also changed WantedBy=timers.target to WantedBy=battery.service in /etc/systemd/system/battery.timer.

There you go. The best cron alternative to hibernate laptops on low battery. =)

71GA
  • 1,056
  • 5
  • 18
  • 38
  • No part of the system is going to automatically use `sudo`. If you run the systemd service as non-root user, it will execute commands as that user without executing `sudo` unless you explicitly add `sudo`. As a result, the `hibernatescript` is executed as the user defined by `User=ziga` in `.service` file and if that command cannot execute without using `sudo`, it will obviously fail every time. The correct fix is to use `User=root`, not sprinkle `sudo` commands around. – Mikko Rantalainen Aug 23 '23 at 11:38
2

May be you shoul try to add first start after boot, like this:

[Timer] OnBootSec=15min OnUnitActiveSec=2m

  • Did you read this here? https://wiki.archlinux.org/index.php/Systemd/Timers#Monotonic_timer – 71GA Jun 28 '16 at 14:59
  • @71GA, Yes, read it there. I think topic starter problem caused by absence of first start. – Alexander Tolkachev Jun 28 '16 at 16:56
  • This changes some things. Please check my **ADD2** to the question. – 71GA Jun 28 '16 at 17:17
  • Have you tried to call /usr/bin/systemctl hibernate not from the script? It working? Because when i try to do it n my centos not from root account I get error `Authentication is required for hibernating the system.` and request root password. May be you have same issue and you should start it under `sudo`? – Alexander Tolkachev Jun 28 '16 at 17:31
  • My user `ziga` is in group `users` and I have this rule `%users ALL=(ALL) NOPASSWD: ALL` in the **/etc/sudoers** file and this rule enables all users from group `users` to execute `sudo` command without inputting any password. So user `ziga` should be fine right? What kind of user does a systemd service use? I tried setting `User=nobody` and `User=ziga` in **/etc/systemd/system/battery.service** but nothing works. – 71GA Jun 28 '16 at 17:45