Skip to content

Instantly share code, notes, and snippets.

@setzer22
Last active December 2, 2023 14:03
Show Gist options
  • Star 31 You must be signed in to star a gist
  • Fork 5 You must be signed in to fork a gist
  • Save setzer22/77b1dc4b226fdf2dee83e6399e30558b to your computer and use it in GitHub Desktop.
Save setzer22/77b1dc4b226fdf2dee83e6399e30558b to your computer and use it in GitHub Desktop.
Linux command to hibernate and then reboot into a different OS

Linux command to hibernate and then reboot into a different OS

In this document I describe my setup about how to add a menu shortcut that will hibernate and reboot the system into a different OS (in my case, Windows), and then restore linux on the next reboot.

For this, I'll be using Arch Linux with systemd-boot as my boot manager, but in practice any bootloader that handles the LoaderEntryOneShot (a.k.a. BootNext) efivar should work.

NOTE It is advisable to not do this with window's fast boot feature active, since alternating the hibernation of two systems can cause shared partitions to get corrupted. However, if additional steps are taken in order to ensure the shared partition are unmounted before reboot, or no partitions are shared between the two OSs, this can be made to work with fastboot enabled which should give quite a boost in Windows' startup time.

Set the LoaderEntryOneShot/BootNext EFI variable

First, we want to set this efi variable in order to tell the system that a different OS should be loaded on next boot, and only that next boot. In systemd-boot this means that not even the OS selection screen will be shown and the selected OS will be loaded directly.

This can be accomplished using efibootmgr

To show the current boot entries:

# efibootmgr

Example output:

BootCurrent: 0002
Timeout: 1 seconds
BootOrder: 0002,0000,0005,0006
Boot0000* Windows Boot Manager
Boot0002* Linux Boot Manager
Boot0005* UEFI: IP4 Qualcomm Atheros PCIe Network Controller
Boot0006* UEFI: IP6 Qualcomm Atheros PCIe Network Controller

Here, we get the hex code of the OS we want to boot, in our case, 0000. Then, we can use efibootmgr to set the LoaderEntryOneShot efivar with --bootnext

efibootmgr --bootnext 0000

Now, upon reboot, entry 0000 will be loaded automatically, and the variable will be reset on the next boot.

Hibernate and then restart

The s2disk command, available as part of the uswsusp (AUR) package can hibernate the system, and has a flag which allows us to set the shutdown method to reboot just on a single hibernation. However, s2disk for some reason didn't work on my machine, so I made an equivalent (although less robust) systemd-based configuration.

First, a script enable-hibernate-reboot stored in my $PATH

#!/bin/bash

if [ -f /etc/systemd/sleep.conf ]; then
    sudo mv /etc/systemd/sleep.conf /etc/systemd/sleep.conf.bak
fi
sudo printf "[Sleep]\nHibernateMode=reboot" > /etc/systemd/sleep.conf

And also, a disable-hibernate-reboot stored at the special folder /usr/lib/systemd/system-sleep:

#!/bin/bash

if [ -f /etc/systemd/sleep.conf.bak ] && [ $1 == "post" ] && [ $2 == "hibernate" ]; then
  mv /etc/systemd/sleep.conf.bak /etc/systemd/sleep.conf
fi

The script in this folder will be run after hibernation with $1="post" and $2="hibernate" (see sleep.conf.d manpage) when resuming from hibernation, thus restoring the old sleep.conf. Note that for the hibernation that will reboot to windows, any configuration you had previously set up in /etc/systemd/sleep.conf (if any) will be disabled.

Now, after runing enable-hibernate-reboot the computer will reboot after hibernation, but only once.

Wrapping up

Finally, we can set up a wrapper script to glue everything we've done so far:

#!/bin/bash

sudo /path/to/enable-hibernate-reboot
sudo efibootmgr --bootnext 0000
sudo systemctl hibernate

Note that the script needs to be run as root. You can work around this by not requiring sudo password for your user just for this three commands.

Sources:

@frebib
Copy link

frebib commented Jan 25, 2018

https://gist.github.com/frebib/4d8eff2528237b86c7108dc5cbe6f54b

Thanks for your work here, it has been very useful!

@Oliph
Copy link

Oliph commented Feb 18, 2019

Thank you very much for this simple solution!

@giammi56
Copy link

giammi56 commented Feb 5, 2021

Do you think this could work for Ubuntu 20.04 too?

@mtfurlan
Copy link

Really appreciate this, got me 90% of the way to where I wanted to be.
Does have a bug though,

sudo printf "stuff" > /somewhere

will run printf as root, but then not have write permissions to /somewhere
I used

printf "[Sleep]\nHibernateMode=reboot\n" | sudo tee /etc/systemd/sleep.conf

Also because you didn't set -e I didn't get warned about this and it took a few tries to figure out what was wrong.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment