This post describes how to enable (delayed) hibernation on Arch Linux. It is less for tutorial purposes and more to allow me to make a note to myself of one of the many crazy customizations I have done on Arch Linux in case I need to do them again someday.

The final goal is to be able to close your laptop lid, and let your system go into the suspended state, and if you don't open your lid for a couple of hours, automatically hibernate to disk.

Most of the instructions are taken from the Arch Wiki.

Assumptions:

  • Your system is running with systemd and grub2
  • Suspend already works without issues.

To enable hibernate:

This a condensed version of the instructions on the power management page on the arch wiki:

  1. The file /sys/power/image_size lists the size of the hibernate image created (in bytes). Since you're hibernating to your swap partition, make sure the size listed in this file is less than or equal to the size of your swap partition
  2. You can find your swap partition by running lsblk and seeing which partition has [SWAP] listed next to it.
  3. Edit the variable GRUB_CMDLINE_LINUX_DEFAULT in the file /etc/default/grub and append resume=/dev/sda1 to the string, assuming /dev/sda1 is your swap partition.
  4. Then run grub-mkconfig -o /boot/grub/grub.cfg to regenerate your grub.cfg
  5. Edit the variable HOOKS in the file /etc/mkinitcpio.conf to add the resume hook. Make sure you add it after the udev hook. Now HOOKS looks like this:
     HOOKS="base udev resume autodetect modconf ..."
  6. Then run mkinitcpio -p linux to rebuild the initramfs.

That's it. Now your should be able to hibernate by typing in systemctl hibernate.

To enable delayed hibernation:

What this does is suspends your laptop when you close the lid. Then, if the laptop hasn't been used in 2 hours, it hibernates the laptop to disk.

  1. Create a file /etc/systemd/system/suspend-to-hibernate.service with the following contents:
    [Unit]
    Description=Delayed hibernation trigger
    Documentation=https://bbs.archlinux.org/viewtopic.php?pid=1420279#p1420279
    Documentation=https://wiki.archlinux.org/index.php/Power_management
    Before=suspend.target
    Conflicts=hibernate.target hybrid-suspend.target
    StopWhenUnneeded=true
    
    [Service]
    Type=oneshot
    RemainAfterExit=yes
    Environment="WAKEALARM=/sys/class/rtc/rtc0/wakealarm"
    Environment="SLEEPLENGTH=+2hour"
    ExecStart=-/usr/bin/sh -c 'echo -n "alarm set for "; date +%%s -d$SLEEPLENGTH | tee $WAKEALARM'
    ExecStop=-/usr/bin/sh -c '\
     alarm=$(cat $WAKEALARM); \
     now=$(date +%%s); \
     if [ -z "$alarm" ] || [ "$now" -ge "$alarm" ]; then \
     echo "hibernate triggered"; \
     systemctl hibernate; \
     else \
     echo "normal wakeup"; \
     fi; \
     echo 0 > $WAKEALARM; \
    '
    
    [Install]
    WantedBy=sleep.target
  2. Then copy /usr/lib/systemd/system/suspend.target to /etc/systemd/system and edit it to add Requires=suspend-to-hibernate.service to it (source):
    cp /usr/lib/systemd/system/suspend.target /etc/systemd/system && \
    echo "Requires=suspend-to-hibernate.service" >> /etc/systemd/system/suspend.target
  3. Enable the suspend-to-hibernate.service using systemctl:
    systemctl enable suspend-to-hibernate.service

And that's it. Now you can close your laptop lid, and open it after a long time without your battery having run out!