I thought someone else might find this slightly useful.  I'm doing a lot
of automated testing of development versions of the Linux kernel.  I
needed to be able to recover when a kernel goes bad on me.  I have some
neat Cisco hardware that allows me to telnet to a port on a server and
get access to a serial port.  This expect script attaches to one of
those ports where GRUB is waiting.

Handed a GRUB title, this will find it in the menu and boot it.  The
only real caveat is that you need to escape regular expression
characters in your kernel titles.  For instance: "Linux (2.4.17) works "
needs to be passed as "Linux \(2\.4\.17\) works ".

I think hacks like this demonstrate how useful a full-featured scripting
laguage in the menu syntax would be, including the ability to save some
state across a power cycle without the OS being involved.

-- 
Dave Hansen
[EMAIL PROTECTED]
#!/usr/bin/expect 
#
# Written by Dave Hansen <[EMAIL PROTECTED]>
#
# This script watches a serial line for a GRUB menu, then finds and boots
# the kernel that you request.
#
# Before you run this script, you should be quite sure that the machine
# is rebooting and will present a GRUB prompt.  It is not this script's
# job to decide which kind of bootloader you have or if you're at a login
# prompt, a fsck prompt, or anything else.  GRUB only.
# 
# This script correctly handles GRUB being at a the menu, or different 
# GRUB command prompts when the script is handed the serial line.  
#
# exit codes:
# 0 - GRUB successfully loaded a kernel
# 1 - there was a problem with telnet
# 2 - a GRUB prompt was never seen.  The machine might still be powered
#     off or hung
# 3 - the specified GRUB menu item was never seen.  The name
#     passed in the 3rd argument is probably not in the GRUB menu
# 4 - a GRUB error was encountered while trying to load the specified
#     kernel.  The kernel probably doesn't exist on the disk
# 5 - a Linux kernel header was never seen.  The loaded kernel may
#     have crashed.

log_user 1
stty echo
set argc [llength $argv]
set name [lindex $argv 0]
set port [lindex $argv 1]
set kernel [lindex $argv 2]

# wait 20 minutes for any grub activity
set start_timeout 1200 
set elapsed_time 0
set timeout 1

spawn telnet $name $port

# sit around on the serial port and send stuff to try and get a response
# from GRUB.  
expect {
        "grub>" {
        }
        # someone left GRUB at a prompt with stuff there already
        # This should even recover from things at the GRUB line-edit
        # prompt, or even in the middle of a device string
        -re "Error \[0-9]+:" {
                send \033
                send \033
        }
        "Connection closed by foreign host." {
                puts "Telnet connection closed."
                puts "Does someone else have the serial line?"
                exit 1;
        }
        timeout { 
                send "c\t";
                incr elapsed_time "1";
                puts "timeout: $elapsed_time of $start_timeout";
                if { $elapsed_time >= $start_timeout } {
                        puts "wait for grub timeout expired.";
                        exit 2;
                }
                exp_continue;
        }
}

sleep 1

# send ESC, to have grub give us the menu
send \033
send \033

set timeout 3;
set movechar "v";

set   restr "\\\[0m.\\\[.+;3H ";  # [0m means unhighlight.  There should only
                                  # be one of these per screen redraw or ^ or v
                                  # key press
set hirestr "\\\[7m.\\\[.+;3H ";  # [7m means highlight.  
append hirestr $kernel;

# let it go back and forth in the menu a couple of times
set change_dir_retries 6

expect {
        # the control sequence to highlight a GRUB entry on the serial 
        # console always ends with "3H " and the grub title.  
        -re $hirestr {
        }

        # when GRUB reaches the end of its menus, it doesn't send 
        # anything as a response to key input.  This is a heartbeat of 
        # sorts to check for when we're *not* at the end of the menu
        -re $restr {
                send $movechar;
                set timeout 4;
                exp_continue;
        }
        # if we're pressing keys and not getting responses, we're at the
        # end of the menu
        timeout {
                if { $movechar == "v" } {
                        set movechar "^";
                } else {
                        set movechar "v";
                }
                incr change_dir_retries "-1";
                if { $change_dir_retries < 0 } {
                        puts "could not find requested GRUB menu entry";
                        exit 3;
                }
                send $movechar;
                exp_continue;
        }
}

send "\r"

set timeout 60;
expect {
        "^Linux version " {
                exit 0
        }
        "Error " {
                puts "GRUB Error";
                exit 4;
        }
        timeout {
                puts "Linux boot prompt never seen";
        }
}
exit 5;
_______________________________________________
Bug-grub mailing list
[EMAIL PROTECTED]
http://mail.gnu.org/mailman/listinfo/bug-grub

Reply via email to