Take the 2-minute tour ×
Ask Ubuntu is a question and answer site for Ubuntu users and developers. It's 100% free, no registration required.

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?

share|improve this question
    
In theory, if you can use date and time related commands on /boot/grub/grub.cfg, choosing a grub entry for a given hour should be possible just by editing the files on /etc/grub.d. But I think the date/time before grub loads wouldn't even be a calibrated source (like NTP, for example). So that would leave you with the PC internal clock. –  edwin Jul 22 '13 at 1:54
    
@edwin Your comment helped me answer the question. Thanks. –  Eric Carvalho Jul 23 '13 at 17:02

3 Answers 3

up vote 4 down vote accepted

This is a very interesting question. At first I thought it wasn't possible, but after edwin's comment I started to read grub's documentation and found a way to accomplish what you want.

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-252b0090-8eb8-4cf7-b852-e6991dc849bb' {
submenu 'Opções avançadas para Ubuntu' $menuentry_id_option 'gnulinux-advanced-252b0090-8eb8-4cf7-b852-e6991dc849bb' {
        menuentry 'Ubuntu, com Linux 3.8.0-26-generic' --class ubuntu --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-3.8.0-26-generic-advanced-252b0090-8eb8-4cf7-b852-e6991dc849bb' {
        menuentry 'Ubuntu, com Linux 3.8.0-26-generic (modo de recuperação)' --class ubuntu --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-3.8.0-26-generic-recovery-252b0090-8eb8-4cf7-b852-e6991dc849bb' {
        menuentry 'Ubuntu, com Linux 3.8.0-25-generic' --class ubuntu --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-3.8.0-25-generic-advanced-252b0090-8eb8-4cf7-b852-e6991dc849bb' {
        menuentry 'Ubuntu, com Linux 3.8.0-25-generic (modo de recuperação)' --class ubuntu --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-3.8.0-25-generic-recovery-252b0090-8eb8-4cf7-b852-e6991dc849bb' {
menuentry "Memory test (memtest86+)" {
menuentry "Memory test (memtest86+, serial console 115200)" {
menuentry 'Windows 7 (loader) (em /dev/sdb1)' --class windows --class os $menuentry_id_option 'osprober-chain-00D2FC19D2FC149E' {

Here you can see my first menu entry is Ubuntu (the default one, as I have GRUB_DEFAULT=0 in /etc/default/grub), followed by a "Advanced options" submenu (whith four other entries), memory tests and, at last, Windows 7.

The scripts in /etc/grub.d/ are executed sequencially to generate /boot/grub/grub.cfg, and /etc/grub.d/00_header is the one responsible for setting the default grub menu entry. I created a script named 01_time_based_selection that overrides the default entry specified in /etc/default/grub. I used grub's module datehook to get the current time.

/etc/grub.d/01_time_based_selection:

#!/bin/sh
cat <<EOF

# 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) (em /dev/sda1)"
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.8.0-25-generic" from 5PM to 11:59PM
if [ \$TIME -ge 1700 -a \$TIME -lt 2359 ]; then
    set default="1>Ubuntu, com Linux 3.8.0-25-generic"
fi
EOF

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) (em /dev/sda1)"), 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, com Linux 3.8.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" submenu is 1, that's why I had to add 1> before the entry name: set default="1>Ubuntu, com Linux 3.8.0-25-generic".

Of course, after making changes to /etc/grub.d/01_time_based_selection run sudo update-grub to rebuild the file /boot/grub/grub.cfg.

As said by edwin, the hardware clock may be unreliable, specially if the battery is dead. Also, enter BIOS setup and check the time. If it is UTC youl'll have to change the time range in the script.

share|improve this answer

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:

share|improve this answer

You have 2 possibilities. First, you can add to every OS a cron script that changes config by clock. However, you will not like what will happen if this script kicks in while OS is shutting down, so beware. A better idea would be to acquire a UEFI motherboard for your PC. There you can install Shellx86 which is a pre-bootloader scripting console. Creating script for what you want in Shellx64 is no harder than scripting in bash. I used it to boot different OS depending on if you have Internet connection.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.