Can GRUB be scheduled? This means: changing default 'entry' (auto login) at defined periods of time automatically?
For example:
00:00:00 to 06:00:00 -> Slitaz
06:00:01 to 13:00:00 -> Ubuntu
13:00:01 to 19:00:00 -> Fedora
19:00:01 to 23:59:59 -> openSUSE
Can grub change default 'entry' automatically?
Solution 1:
First, run grep -E '(menuentry |submenu )' /boot/grub/grub.cfg
to get a list of your grub menu entries. You should see something like:
menuentry 'Ubuntu' --class ubuntu --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-simple-7820cc72-dac4-447f-bba0-996ed1a12fa5' {
submenu 'Advanced options for Ubuntu' $menuentry_id_option 'gnulinux-advanced-7820cc72-dac4-447f-bba0-996ed1a12fa5' {
menuentry 'Ubuntu, with Linux 3.16.0-28-generic' --class ubuntu --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-3.16.0-28-generic-advanced-7820cc72-dac4-447f-bba0-996ed1a12fa5' {
menuentry 'Ubuntu, with Linux 3.16.0-28-generic (recovery mode)' --class ubuntu --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-3.16.0-28-generic-recovery-7820cc72-dac4-447f-bba0-996ed1a12fa5' {
menuentry 'Ubuntu, with Linux 3.16.0-25-generic' --class ubuntu --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-3.16.0-25-generic-advanced-7820cc72-dac4-447f-bba0-996ed1a12fa5' {
menuentry 'Ubuntu, with Linux 3.16.0-25-generic (recovery mode)' --class ubuntu --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-3.16.0-25-generic-recovery-7820cc72-dac4-447f-bba0-996ed1a12fa5' {
menuentry 'Memory test (memtest86+)' {
menuentry 'Memory test (memtest86+, serial console 115200)' {
menuentry 'Windows 7 (loader) (on /dev/sda2)' --class windows --class os $menuentry_id_option 'osprober-chain-C84087BD4087B12C' {
Here you can see my first menu entry is Ubuntu, followed by a Advanced options for Ubuntu submenu (with four other entries), 2 memory tests and, at last, Windows 7.
If we create a file named /boot/grub/custom.cfg
, it will be loaded after /boot/grub/grub.cfg
, so we can easily change GRUB's default configuration.
I used GRUB's module datehook
to get the current time.
/boot/grub/custom.cfg
:
# This module creates special variables that return the current date/time
insmod datehook
# Add and extra 0 to minutes if it's less than 10 (force a 2-digit minute)
if [ $MINUTE -lt 10 ]; then PADDING="0"; else PADDING=""; fi
TIME=$HOUR$PADDING$MINUTE
# Boot "Ubuntu" from midnight to 5:59AM
if [ $TIME -ge 0 -a $TIME -lt 559 ]; then
set default="Ubuntu"
fi
# Boot "Windows 7" from 6AM to 4:59PM
if [ $TIME -ge 600 -a $TIME -lt 1659 ]; then
set default="Windows 7 (loader) (on /dev/sda2)"
fi
# If you want to boot an entry that's inside a submenu,
# you have to prepend its name with the submenu position, starting from 0.
# Boot "Ubuntu, with kernel 3.16.0-25-generic" from 5PM to 11:59PM
if [ $TIME -ge 1700 -a $TIME -lt 2359 ]; then
set default="1>Ubuntu, with Linux 3.16.0-25-generic"
fi
The module datehook
makes available the variables: DAY, HOUR, MINUTE, MONTH, SECOND, WEEKDAY and YEAR, which return the actual date/time values based on hardware clock.
Let's take if [ $TIME -ge 600 -a $TIME -lt 1659 ]; then
as an example. It means: if the current time is greater than or equal to 6AM and less than 4:59PM (16:59) then execute the next command (set default="Windows 7 (loader) (on /dev/sda2)"
), which set the default
variable with the Windows 7 menu entry name taken from that grep
command above.
The last if
block exemplifies the selection of a submenu entry. In that case "Ubuntu, with Linux 3.16.0-25-generic" lies inside a submenu that is the second entry in the main menu. As an entry position in a menu starts from 0, the menu entry named "Ubuntu" is 0
and the "Advanced options for Ubuntu" submenu is 1
, that's why I had to add 1>
before the entry name: set default="1>Ubuntu, with Linux 3.16.0-25-generic"
.
There no need to run update-grub
.
The hardware clock may be unreliable, specially if the battery is dead. Also, enter BIOS setup and check the time. If it is UTC you'll have to change the time range in the script.
Solution 2:
For the beginning, run the following command in terminal:
grep -E '^menuentry|^submenu' /boot/grub/grub.cfg | cut -d '"' -f2 | cut -d "'" -f2
This will return a list of your grub menu entries. I assume that in your case this list is something like this:
Slitaz
Advanced options
Memory test (memtest86+)
Memory test (memtest86+, serial console 115200)
Ubuntu
Fedora
openSUSE
Now, for each of these entries you should assign a number in ascending order starting with 0 (for "Slitaz" - 0
, for "Advanced options" - 1
and so on). You will use this numbers to set default entry in grub menu.
Next, and the last thing, you should edit /boot/grub/grub.cfg
file as follow:
-
From terminal open in gedit the file using:
sudo -H gedit /boot/grub/grub.cfg
-
Find the line where
default
variable is set; it should look something similar with:set default="..."
-
Replace the above line with next code:
insmod datehook if [ "$HOUR" -ge "0" -a "$HOUR" -lt "6" ]; then set default="0" #Slitaz time elif [ "$HOUR" -ge "6" -a "$HOUR" -lt "13" ]; then set default="4" #Ubuntu time elif [ "$HOUR" -ge "13" -a "$HOUR" -lt "19" ]; then set default="5" #Fedora time else set default="6" #openSUSE time fi
Save the file and close it.
That's all! Restart your PC and check if it is working.
Note: to revert these settings, just run
sudo update-grub
in terminal. In fact, this command will automatically generate and replace/boot/grub/grub.cfg
file using templates from/etc/grub.d
and settings from/etc/default/grub
. So it will be better to put the above code in one template inside/etc/grub.d
directory.
Source of inspiration: Scripting a Simple Boot Time State Machine in GRUB2.
Other sources:
- http://www.gnu.org/software/grub/manual/grub.html
- http://members.iinet.net/~herman546/p20/GRUB2%20CLI%20Mode%20Commands.html