Results 1 to 3 of 3

Thread: Script to configure GRUB

  1. #1
    Join Date
    Aug 2007
    Location
    Near Seattle, WA
    Beans
    196
    Distro
    Ubuntu 7.04 Feisty Fawn

    Script to configure GRUB

    I have created a script which can be used to configure GRUB. It has a command line interface. I believe I have tested most of the options that you can choose, and I believe it should run pretty well. You can use it to set the default OS, the timer, and whether you want to have the GRUB menu hidden. Also, it will set up a splash image, and if you have none, it will install grub-splashimages from the repositories. If you do not use a splash image, You can use it to set your GRUB menu colors. Finally, it will make a backup of the menu.lst before it makes any changes. The name of the backup file is /boot/grub/menu.lst.bak.

    To use it, open a text editor of your choice and copy and paste it into the editor. I call this script grub-configure. So after you save this script, go to the directory and (assuming you named it grub-configure), enter:
    Code:
    chmod 755 grub-configure
    To run the script, since it manipulates files in the /boot/grub directory, it has to have super user privileges. To start it, type:
    Code:
    sudo ./grub-configure
    Simply follow the prompts. If an item is listed as a default, if you were to simply push the enter button without giving any input, the default will be applied. You can answer the Yes/No questions with just y or n. Or you could write it out. Either way is fine.
    Here is the code:
    Code:
    #!/usr/bin/perl -w
    
    # Written by Eric Haslehurst 2007
    
    # The purpose of this script is to manage your GRUB menu.
    
    use strict;
    
    # File name constants
    my $ORIG_MENU_LST = "/boot/grub/menu.lst";
    my $TEMP_MENU_LST = "/boot/grub/menu.tmp";
    my $BACKUP_FILE = "/boot/grub/menu.lst.bak";
    
    # Hashes
    my %menu_hash;              # hash that keeps track of which place on the menu each menu choice is at           
    
    # Arrays
    my @operating_systems;      # Holds the names of the different Operating Systems available on the computer.
    
    # Scalars
    my $is_root_partition;
    my $root_partition; 
    my $menu_length;
    my $menu_choice;
    my $response;               # Used throughout the script to record user responses.
    my $default_os;
    my $grub_index_num = -1;    # The total number of choices in the GRUB menu (including 'Other Operating Systems:', etc.)
    my $orig_timeout;
    my $hidden_menu;
    my $splash_image;
    my $splash_image_line;
    my $splash_image_exists;
    my $pretty_colors;
    my $pretty_colors_line;
    my $pretty_colors_state;    # Determines if the GRUB menu colors setting needs to be commented out or uncommented
    
    # Begin function definitions
    
    # Self-descriptive name
    sub createMenu{
      my $menu_reference = shift @_;
      my $menu_number = 1;
      printf "%s) $_\n", $menu_number++ for @$menu_reference;
      return $menu_number unless !@$menu_reference;
      return 0;                  # The function was passed an empty list if this 0 is returned
    }
    
    # Checks user input is numeric and in range of the menu generated by createMenu()
    sub validateChoice{
      my $choice = <STDIN>;
      chomp $choice;
      $choice = int($choice);
      return 0 if($choice <= 0 || $choice > $menu_length || $choice =~ /\D/);  # Returns 0 on invalid menu choice
      return $choice;
    }
    
    # If the user already has a splash image, this function replaces it
    sub splash{
      my @splash_arg = split ("/", $splash_image);
      my $splash_file = pop(@splash_arg);
      my $splash_directory = join ("/", @splash_arg);
      my $directory_to_check;
      if($splash_directory =~ /\(hd.*\)/){
        $directory_to_check = "$'";
      } else {
        $directory_to_check = $splash_directory;
      }
      if($splash_file ne "NoSplashImage"){
        print "You are currently using the file $splash_file in $splash_directory\nDo you want to keep this splash image? (Yes or No) [Default = Yes]: ";
        $response = <STDIN>;
      }
      if($response =~ /n/i || $splash_file eq "NoSplashImage"){
        print "Would you like to use .xpm files from $directory_to_check?\n(Yes or No) [Default = Yes]: ";
        $response = <STDIN>;
        if($response =~ /n/i){
          print "Which directory should I look in for splash images?\n";
          $directory_to_check = <STDIN>;
          chomp $directory_to_check;
          opendir SPLASH, $directory_to_check;
        } else {
          opendir SPLASH, $directory_to_check;
        }
      } else {
        return;
      }
      my @response_directory = readdir SPLASH;
      my @xpm_files;
      for(@response_directory){
        push(@xpm_files, $_) if /\.xpm/;
      }
      if(!@xpm_files){
        print "No .xpm files found in that directory!  Let's try this again.\n";
        &splash();
      } else {
        &getSplashChoice(\@xpm_files, $directory_to_check); 
      }
    }
    
    # If the user does not already have a splash image, this function assigns it
    sub getSplash{
      if(opendir GRUB_SPLASH, "/boot/grub/splashimages"){
        closedir GRUB_SPLASH;
        $splash_image = $root_partition . "/boot/grub/splashimages/NoSplashImage";
        &splash();
      } else {
        print "You do not have grub-splashimages installed.  Do you want to install it?\n(Yes or No): ";
        $response = <STDIN>;
        if($response =~ /y/i){
          system "sudo apt-get -y install grub-splashimages";
          print "\nDo you want to use a splash image from grub-splashimages?\n(Yes or No): ";
          $response = <STDIN>;
          if($response =~ /y/i){
            $splash_image = $root_partition . "/boot/grub/splashimages/NoSplashImage";
            &splash();
          } else {
            &customSplash();
          }
        } else {
          &customSplash();
        }
      }
    }
    
    # If the user does not have a splash image, and wants a custom one (one not included with grub-splashimages)
    # this function checks for it, and gives the user an opportunity to back out of setting the splash image
    # feature if they desire to.
    sub customSplash{
      print "Please enter the directory for your desired splash image.\nDo not use '~' for your home directory: ";
      $response = <STDIN>;
      while(1){
        if(opendir SPLASH, $response){
          my @response_directory = readdir SPLASH;
          my @xpm_files;
          for(@response_directory){
            push(@xpm_files, $_) if /.xpm/;
          }
          if(@xpm_files){
            &getSplashChoice(\@xpm_files, $response);
            return;
          } else {
            print "No .xpm files in that directory!  Do you want to specify another directory?\n(Yes or No): ";
            $response = <STDIN>;
            if($response =~ /y/i){
              &customSplash();
            } else {
              return;
            }
          }
        } else {
          print "Invalid directory specified!  Do you want to specify another directory?\n(Yes or No): ";
          $response = <STDIN>;
          if($response =~ /y/i){
            &customSplash();
          } else {
            return;
          }
        }
      }
    }  
    
    # This function is used in splash() and customSplash() to assign a splash image.
    sub getSplashChoice{
      my $xpm_files_ref = shift @_;
      my $xpm_directory = shift @_;
      print "Found the following .xpm files in the specified directory.\nEnter the corresponding number to use that splash file:\n";
      while(1){
        $menu_length = &createMenu($xpm_files_ref);
        $menu_choice = &validateChoice();
        last if $menu_choice;
        print "Invalid menu selection.  Please try again.\n";
      }
      $menu_choice--;
      $splash_image = $root_partition . $xpm_directory . "/" . $$xpm_files_ref[$menu_choice];
    }
    
    # This function sets the pretty colors (GRUB menu colors if there is no splash image).
    sub noSplashColors{
      my @background_colors = qw( black blue green cyan red magenta brown light-gray );
      my @foreground_colors = qw( dark-gray light-blue light-green light-cyan light-red light-magenta yellow white);
      my $background;
      my $background_index;
      my $foreground;
      my $foreground_index;
      print "Your choice of background colors is:\n@background_colors\n";
      print "Your choice of foreground colors is:\n@foreground_colors\n";
      $menu_length = &createMenu(\@background_colors);
      print "Select a background color: ";
      $background_index = &validateChoice();
      if($background_index--){
        $background = $background_colors[$background_index];
      } else {
        print "Invalid menu selection.  Do you wish to try again?\n(Yes or No) [Default is No]: ";
        $response = <STDIN>;
        if ($response =~ /y/i){
          &noSplashColors;
        } else {
          $pretty_colors = "\#color cyan/blue white/blue\n" unless $pretty_colors_state =~ /\#/;
        }
      }
      $menu_length = &createMenu(\@foreground_colors);
      print "Select a foreground color: ";
      $foreground_index = &validateChoice();
      if($foreground_index--){
        $foreground = $foreground_colors[$foreground_index];
      } else {
        print "Invalid menu selection.  Do you wish to try again?\n(Yes or No) [Default is No]: ";
        $response = <STDIN>;
        if ($response =~ /y/i){
          &noSplashColors;
        } else {
          $pretty_colors = "\#color cyan/blue white/blue\n" unless $pretty_colors_state =~ /\#/;
        }
      }
      $pretty_colors = "color $foreground/$background\n";
    }
    # End of function definitions
      
    open MENU_LST, $ORIG_MENU_LST or die "Could not open $ORIG_MENU_LST: $!\n";
    open TEMP_MENU, "> $TEMP_MENU_LST" or die "Could not open temporary file: $!\nPlease run this script with the command 'sudo'\n";
    open BACKUP, "> $BACKUP_FILE" or die "Could not create backup file: $!\n";
    
    # While loop to create a backup file, and to put the current settings into various scalars, arrays, and hash.
    while(<MENU_LST>){
      print BACKUP "$_";
      chomp;
      if(/^\s*title\s*/i){
        $grub_index_num++;
        push(@operating_systems, "$'") if !(/:|memtest|recovery mode/);
        $menu_hash{"$'"} = $grub_index_num;
        if(/kernel/i && !$is_root_partition){
          $is_root_partition = 1;
        }
      } elsif(/^\s*timeout\s*/i){
        $orig_timeout = "$'";
        chomp $orig_timeout;
      } elsif(/^splashimage\s*=?\s*/){
        $splash_image = "$'";
        $splash_image_exists = 1;
      } elsif($is_root_partition && !$root_partition){
        if(/root\s*/){
          my $line = "$'";
          $root_partition = $& if $line =~ /\(hd.*\)/;
        }
      } elsif(/\#?\s*color/){
        $pretty_colors_state = $&;
        $pretty_colors = $_;
      }
    }
    
    # Done backing up the file.
    close BACKUP;
    
    # Closing and reopening to go back to the beginning of the file.
    close MENU_LST;
    open MENU_LST, $ORIG_MENU_LST or die "Could not open $ORIG_MENU_LST: $!";
    
    # Beginning the user interface
    print "grub-configure v0.1\n\n";
    
    # Choose the default OS
    while(1){
      $menu_length = &createMenu(\@operating_systems);
      die "\nCould not locate any valid operating system choices in menu.lst.  Exiting to prevent errors\n" unless $menu_length;
      print "\nPlease enter a number corresponding to\nthe OS you would like to be the default: ";
      $menu_choice = &validateChoice();
      last if $menu_choice;
      print "Invalid menu selection.\n";
    }
    $menu_choice--;
    $default_os = $operating_systems[$menu_choice];
    
    # Set the timeout
    print "\nYour current timeout before GRUB chooses your default selection is $orig_timeout seconds.\nIf you like this time, just press <Enter>\nIf you would like to change it, enter a new number of seconds GRUB should wait\n: ";
    $response = <STDIN>;
    chomp $response;
    if($response =~ /\d+/){                        # I use $orig_timeout to make the replacements in the while loop below, this checks
      $orig_timeout = $& if ($& > 0 && $& < 30000);   # for valid input to $new_timeout before replacing the value of $orig_timeout 
    } else {
      print "Invalid entry, continuing to use $orig_timeout seconds as the default timeout\n" if $response;
    }
    
    # Choose whether the GRUB menu should be hidden or not
    print "\nDo you want your GRUB menu to be hidden at start up?\n(Yes or No?) [Default is not hidden]: ";
    $hidden_menu = <STDIN>;
    if($hidden_menu =~ /y/i){
      $hidden_menu = "hiddenmenu\n";
    } else {
      $hidden_menu = "\#hiddenmenu\n";
    }
    
    # Set the splash image
    if($splash_image){
      print "\nYou currently have a splash image.  Do you want to remove it?\n(Yes or No) [Default is No]: ";
      $response = <STDIN>;
      if($response =~ /y/i){
        $splash_image = ();
      } else {
        &splash();
      }
    } else {
      print "\nI see you do not have a GRUB splash image.  Do you want one?\n(Yes or No) [Default is No]: ";
      $response = <STDIN>;
      if($response =~ /y/i){
        &getSplash();
      }
    }
    
    # Set the GRUB menu colors if there is no splash image
    unless($splash_image){
      print "\nDo you want to change the colors of your GRUB menu? (Yes or No) [Default is No]: ";
      $response = <STDIN>;
      if($response =~ /y/i){
        &noSplashColors();
      } else {
        $pretty_colors = "\#color cyan/blue white/blue\n" unless $pretty_colors_state =~ /\#/;
      } 
    }
    if($splash_image){
      $pretty_colors = "\#color cyan/blue white/blue\n" unless $pretty_colors_state =~ /\#/;
    }
    
    # Review of the choices by the user
    print "\nYour new default will be $default_os\n";
    print "Your default timeout will be $orig_timeout\n";
    if($hidden_menu eq "hiddenmenu\n"){
      print "Your menu will be hidden\n";
    } else {
      print "Your menu will not be hidden\n";
    }
    print "Your splash image will be $splash_image\n" if $splash_image;
    if($pretty_colors){
      if($pretty_colors =~ /^color\s*/){
        my $colors = "$'";
        chomp $colors;
        print "Your GRUB menu colors will be $colors.\n";
      }
    }
    
    # Last statement before selected actions are implemented, last chance to abort the program.
    print "Press enter to continue or q to abort\n";  
    $response = <STDIN>;
    if($response =~ /Q/i){
      close MENU_LST;
      close TEMP_MENU;
      unlink $TEMP_MENU_LST or warn "Could not delete temporary file $TEMP_MENU_LST: $!\n";
      die "\nAborting.  No changes have been made to $ORIG_MENU_LST\n";
    }
    
    # Rewrites menu.lst to a temporary file with the changes.
    while(<MENU_LST>){
      my $menu_line = $_;
    
      if(/\#\s+\w+\s+\/usr\/share\/doc\/grub-doc\//){
        $splash_image_line = 1;
      }
    # Replaces the splash image
      elsif($menu_line =~ /^splashimage/ || ($splash_image_line && !$splash_image_exists)){
        if($splash_image){
          print TEMP_MENU "splashimage $splash_image\n";
          $splash_image_line = 0;
          next;
        } else {
          print TEMP_MENU "\n";
          $splash_image_line = 0;
          next;
        }
      }
     
    # Replaces the default number with the new choice  
      elsif($menu_line =~ /^\s*default/){
        $menu_line =~ s/\d+/$menu_hash{$default_os}/;
        print TEMP_MENU $menu_line;
        next;
      }
      
    # Replaces the timout number with the new timeout value   
      elsif($menu_line =~ /^\s*timeout/){
        $menu_line =~ s/\d+/$orig_timeout/;
        print TEMP_MENU $menu_line;
        next;
      }
      
    # Replaces the hidden menu choice
      elsif($menu_line =~ /^\#?hiddenmenu/){
        print TEMP_MENU $hidden_menu;
        next;
      }
    # Replaces GRUB menu colors (if no splash image)
      elsif($menu_line =~ /^\#\s*Pretty\s+colours/){
        print TEMP_MENU $menu_line;
        $pretty_colors_line = 1;
        next;
      } elsif($pretty_colors_line){
        print TEMP_MENU "$pretty_colors\n";
        $pretty_colors_line = 0;
        next;
      }
    # Placing unaffected lines  
      print TEMP_MENU $menu_line;
    }
    close MENU_LST;
    close TEMP_MENU;
    
    # Beginning the actual replacement of menu.lst from the temporary file, followed by clean up from the program
    open TEMP_MENU, $TEMP_MENU_LST or die "Could not reopen temorary file: $!\n$ORIG_MENU_LST not modified\n";
    open MENU_LST, "> $ORIG_MENU_LST" or die "Could not reopen $ORIG_MENU_LST for changes: $!\n$ORIG_MENU_LST not modified\n";
    print MENU_LST "$_" while <TEMP_MENU>;
    close MENU_LST;
    close TEMP_MENU;
    unlink $TEMP_MENU_LST or warn "Could not delete temporary file $TEMP_MENU_LST: $!\n";
    print "Completed changing your default selection in menu.lst.\nThe backup file for your previous menu.lst is $BACKUP_FILE\n";
    Currently, the color choices is somewhat limited (I don't list the blinking option, or allow for specifying the highlighted colors). Also, I do not currently have support for changing colors if you use a splash image. If there is a lot of interest in these features, I can add it. Hope some people find this useful.
    Last edited by eph1973; October 6th, 2007 at 05:06 PM. Reason: Added required 'sudo' command in the description on how to start the script.
    .
    There is no 'i' in sudo.
    If it isn't utterly ridiculous, it isn't worth saying.

  2. #2
    Join Date
    Jan 2006
    Beans
    Hidden!
    Distro
    Ubuntu 10.10 Maverick Meerkat

    Re: Script to configure GRUB

    the code could probably be reorganized better and cleaned up a bit ... other than that seems fine to me so far.
    I am infallible, you should know that by now.
    "My favorite language is call STAR. It's extremely concise. It has exactly one verb '*', which does exactly what I want at the moment." --Larry Wall
    (02:15:31 PM) ***TimToady and snake oil go way back...
    42 lines of Perl - SHI - Home Site

  3. #3
    Join Date
    Apr 2006
    Location
    Surrounded by idiots!
    Beans
    1,295
    Distro
    Kubuntu 4.10

    Re: Script to configure GRUB

    It might be a lot of work, but have you thought about extending this to help with the grub-gfxboot installation, (which is a pain in the rear).

    And also maybe graphically display the images contained in the bootsplash files, so you can choose which one you want?

    That would be an awesome piece of kit!

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •