Bootloader::Core::GRUB.3pm

Langue: en

Version: 2007-09-26 (openSuse - 09/10/07)

Section: 3 (Bibliothèques de fonctions)

NAME

Bootlader::Core::GRUB - GRUB library for bootloader configuration

PREFACE

This package is the GRUB library of the bootloader configuration

SYNOPSIS

use Bootloader::Core::GRUB;

"$obj_ref = Bootloader::Core::GRUB->new ();"

"$unquoted = Bootloader::Core::GRUB->Unquote ($text);"

"$quoted = Bootloader::Core::GRUB->Quote ($text, $when);"

"$unix_dev = Bootloader::Core::GRUB->UnixFile2UnixDev ($unix_file);"

"$unix_dev = Bootloader::Core::GRUB->GrubDev2UnixDev ($grub_dev);"

"$grub_dev = Bootloader::Core::GRUB->UnixDev2GrubDev ($unix_dev);"

"$unix_path = Bootloader::Core::GRUB->GrubPath2UnixPath ($grub_path, $grub_dev_prefix);"

"$grub_path = Bootloader::Core::GRUB->UnixPath2GrubPath ($unix_path, $grub_dev_prefix);"

"$grub_conf_line_ref = Bootloader::Core::GRUB->CreateGrubConfLine ($target, $discswitch);"

"$files_ref = Bootloader::Core::GRUB->ListFiles ();"

"$status = Bootloader::Core::GRUB->ParseLines (\%files, $avoid_reading_device_map);"

"$files_ref = Bootloader::Core::GRUB->CreateLines ();"

"$dev = Bootloader::Core::GRUB->GetCommonDevice (@paths);"

"$line = Bootloader::Core::GRUB->CreateKernelLine (\%sectingo, $grub_root);"

"$line = Bootloader::Core::GRUB->CreateChainloaderLine (\%sectinfo, $grub_root);"

"$disk = Bootloader::Core::GRUB->Partition2Disk ($partition);"

"$sectin_info_ref = Bootloader::Core::GRUB->Section2Info (\@section_lines);"

"$lines_ref = Bootloader::Core::GRUB->Info2Section (\%section_info);"

"$glob_info = $Bootloader::Core::GRUB->Global2Info (\@glob_lines, \@section_names);"

"$lines_ref = Bootloader::Core::GRUB->Info2Global (\%section_info, \@section_names);"

"$settings_ref = Bootloader::Core::GRUB->GetSettings ();"

"$status = Bootloader::Core::GRUB->SetSettings (\%settings);"

"$status = Bootloader::Core::GRUB->InitializeBootloader ();"

"$opt_types_ref = BootGrub->GetOptTypes ();"

"$mountpoint = Bootloader::Core::GRUB->GrubDev2MountPoint ($grub_dev);"

DESCRIPTION

$obj_ref = Bootloader::Core::GRUB->new ();
Creates an instance of the Bootloader::Core::GRUB class.
$unquoted = Bootloader::Core::GRUB->Unquote ($text);
Just override of Bootloader::Core->Unquote function, returning the first parameter.
$quoted = Bootloader::Core::GRUB->Quote ($text, $when);
Just override of Bootloader::Core->Quote function, returning the first parameter.
$unix_dev = Bootloader::Core::GRUB->UnixFile2UnixDev ($unix_file);
Detects the underlying partition (e.g. '/dev/sda1') a given UNIX file (e.g. '/boot') is located on. Takes a UNIX file as argument and returns the corresponding UNIX device.
$unix_dev = Bootloader::Core::GRUB->GrubDev2UnixDev ($grub_dev);
Translates the GRUB device (eg. '(hd0,0)') to UNIX device (eg. '/dev/hda1'). As argument takes the GRUB device, returns the UNIX device (both strings).
$grub_dev = Bootloader::Core::GRUB->UnixDev2GrubDev ($unix_dev);
Translates the UNIX device (eg. '/dev/hda1') to GRUB device (eg. '(hd0,0)'). As argument takes the UNIX device, returns the GRUB device (both strings).
$unix_path = Bootloader::Core::GRUB->GrubPath2UnixPath ($grub_path, $grub_dev_prefix);
Translates the GRUB path (eg. '(hd0,0)/grub/device.map') to UNIX path (eg. '/boot/grub/device.map'). If the GRUB path does not contain the device, the one specified in the argument is used instead. As arguments, the function takes the GRUB path and the device to be used if not specified in the GRUB path, and returns the UNIX path (all strings).
$grub_path = Bootloader::Core::GRUB->UnixPath2GrubPath ($unix_path, $grub_dev_prefix);
Translates the UNIX path (eg. '/boot/grub/device.map') to GRUB path (eg. '(hd0,0)/grub/device.map'). If the device (as specified in GRUB configuration files via the 'root' option) is the same as the device in the resulting path, the resulting path does not contain the device. As arguments, the function takes the UNIX path and the device as specified via 'root' option, and returns the GRUB path (all strings).
$grub_conf_line_ref = Bootloader::Core::GRUB->CreateGrubConfLine ($target, $discswitch);
Creates a hash representing a line of /etc/grub.conf file. As arguments, it takes the device to install GRUB to, and the discswitch argument ('d' or ''). Returns a reference to a hash containing info about the 'install' line.
$files_ref = Bootloader::Core::GRUB->ListFiles ();
Returns the list of the configuration files of the bootloader Returns undef on fail
$status = Bootloader::Core::GRUB->ParseLines (\%files, $avoid_reading_device_map);
Parses the contents of all files and stores the settings in the internal structures. As first argument, it takes a hash reference, where keys are file names and values are references to lists, each member is one line of the file. As second argument, it takes a boolean flag that, if set to a true value, causes it to skip updating the internal device_map information. Returns undef on fail, defined nonzero value on success.
$files_ref = Bootloader::Core::GRUB->CreateLines ();
creates contents of all files from the internal structures. Returns a hash reference in the same format as argument of ParseLines on success, or undef on fail.
$sectin_info_ref = Bootloader::Core::GRUB->Section2Info (\@section_lines);
Gets the information about the section. As argument, takes a reference to the list of lines building the section, returns a reference to a hash containing information about the section. =cut

# map<string,string> Section2Info (list<map<string,any>> section) sub Section2Info {
    my $self = shift;
    my @lines = @{+shift};


    my %ret = ();

    my $grub_root = "";

    my $modules = 0;

    my $type = $self->EvalSectionType (\@lines);

    $ret{"type"} = $type;




    foreach my $line_ref (@lines) {

        my $key = $line_ref->{"key"};

        my $val = $line_ref->{"value"};




        # do mapping of config file names to internal

        if ($type eq "xen") {

            if ($key eq "kernel") {

                $key = "xen";

            }

            elsif ($line_ref->{"key"} eq "module") {

                if ($modules == 0) {

                    $key = "image";

                }

                elsif ($modules == 1) {

                    $key = "initrd";

                }

                $modules++;

            }

        }

        elsif ($type eq "image") {

            if ($key eq "kernel") {

                $key = "image";

            }

        }

        # remapping end, start processing




        # FIXME : check against metadata?




        if ($key eq "root" || $key eq "rootnoverify")

        {

            if ($type eq "menu") {

                $ret{"root"} = $self->GrubDev2UnixDev ($val);

                # FIXME: do we need to set $grub_root here?

#               $grub_root = $val;

            }

            else {

                $grub_root = $val;

                $ret{"noverifyroot"} = "true" if ($key eq "rootnoverify");

            }

        }

        elsif ($key eq "title")

        {

            $ret{"name"} = $val;

            my $on = $self->Comment2OriginalName ($line_ref->{"comment_before"});

            $ret{"original_name"} = $on if ($on ne "");

        }

        elsif ($key eq "image")

        {

            # split into loader and parameter, note that the regex does

            # always match, then split out root= vgamode= and append= values

            $val =~ /^\s*(\S+)(?:\s+(.*))?$/;




            $ret{"image"} = $self->GrubPath2UnixPath ($1, $grub_root);

            $val = $2 || "";




            if ($val =~ /^(?:(.*)\s+)?root=(\S+)(?:\s+(.*))?$/)

            {

                $ret{"root"} = $2 if $2 ne "";

                $val = $self->MergeIfDefined ($1, $3);

            }

            if ($val =~ /^(?:(.*)\s+)?vga=(\S+)(?:\s+(.*))?$/)

            {

                $ret{"vgamode"} = $2 if $2 ne "";

                $val = $self->MergeIfDefined ($1, $3);

            }

            if ($val ne "")

            {

                $ret{"append"} = $val;

                if ($type eq "xen") {

                    if ($val =~ /console=ttyS(\d+),(\d+)/) {

                        # merge console and speed into xen_append

                        my $console = sprintf("com%d", $1+1);

                        my $speed   = sprintf("%s=%d", $console, $2);

                        if (exists $ret{"xen_append"}) {

                            my $xen_append = $ret{"xen_append"};

                            while ($xen_append =~

                                   s/(.*)console=(\S+)\s*(.*)$/$1$3/o) {

                                my $del_console = $2;

                                $xen_append =~

                                    s/(.*)${del_console}=\d+\s*(.*)$/$1$2/g;

                            }

                            $ret{"xen_append"} = "console=$console $speed $xen_append";

                        } else {

                            $ret{"xen_append"} = "console=$console $speed";

                        }

                    }

                }

            }

        }

        elsif ($key eq "xen")

        {

            # split into loader and parameter, note that the regex does

            # always match

            $val =~ /^\s*(\S+)(?:\s+(.*))?$/;




            $ret{"xen"} = $self->GrubPath2UnixPath ($1, $grub_root);

            $ret{"xen_append"} = $2 if defined $2;

        }

        elsif ($key eq "initrd" || $key eq "wildcard" || $key eq "configfile")

        {

            $ret{$key} = $self->GrubPath2UnixPath ($val, $grub_root);

        }

        elsif ($key eq "chainloader")

        {

            if ($val =~ /^(.*)\+(\d+)/)

            {

                $val = $1;

                $ret{"blockoffset"} = $2;

                if ($val eq "")

                {

                    $val = $grub_root;

                }

                $val = $self->GrubDev2UnixDev ($val);

            }

            else

            {

                $val = $self->GrubPath2UnixPath ($val, $grub_root);

            }

            $ret{$key} = $val;

        }

    }




    $ret{"__lines"} = \@lines;

    return \%ret;

}



*
"$dev = Bootloader::Core::GRUB->GetCommonDevice (@paths);"

Checks all paths given as arguments if they are on the same device. If so, returns the common device, otherwise returns empty string.

*
"$line = Bootloader::Core::GRUB->CreateKernelLine (\%sectingo, $grub_root);"

Creates a line with the kernel command for GRUB's menu.lst. As arguments. it takes a hash containing information about the section and the root device specified by the GRUB's root command. Returns the line to be written to menu.lst (without the leading kernel keyword).

*
"$line = Bootloader::Core::GRUB->CreateChainloaderLine (\%sectinfo, $grub_root);"

Creates a line with the chainloader command for GRUB's menu.lst. As arguments. it takes a hash containing information about the section and the root device specified by the GRUB's root command. Returns the line to be written to menu.lst (without the leading chainloader keyword).

$disk = Bootloader::Core::Grub->Partition2Disk ($partition);
Gets the disk a partition resides on. As argument, it takes the partition device node (eg. '/dev/hda3'), returns the device node of the disk holding the partition (eg. "/dev/hda"), or undef if checking failed.
$lines_ref = Bootloader::Core::GRUB->Info2Section (\%section_info);
Takes the info about the section and uses it to construct the list of lines. The info about the section also contains the original lines. As parameter, takes the section info (reference to a hash), returns the lines (a list of hashes). =cut

# list<map<string,any>> Info2Section (map<string,string> info) sub Info2Section {
    my $self = shift;
    my %sectinfo = %{+shift};


    my @lines = @{$sectinfo{"__lines"} || []};

    my $type = $sectinfo{"type"} || "";

    my $so = $self->{"exports"}{"section_options"};

    my $modules = 0;




    # allow to keep the section unchanged

    if (! ($sectinfo{"__modified"} || 0))

    {

        return $self->FixSectionLineOrder (

            \@lines,

            ["title"]);

    }




    #if section type is not known, don't touch it.

    if ($type ne "image" and $type ne "other" and $type ne "xen" and $type ne "menu")

    {

        return \@lines;

    }

    my $grub_root = "";

    if (defined ($sectinfo{"image"}) && defined ($sectinfo{"initrd"}))

    {

        $grub_root = $self->GetCommonDevice ($sectinfo{"image"}, $sectinfo{"initrd"});

        $grub_root = $self->UnixDev2GrubDev ($grub_root);

    }

    elsif ($type eq "menu" or $type eq "other") {

        # FIXME: using the boot device of the current installation as the

        # "root" parameter in sections for other installations does not make

        # sense to me -- are there cases where this does make sense?

        my ($boot_dev,) = $self->SplitDevPath ("/boot");

        $grub_root = $self->UnixDev2GrubDev (

            exists $sectinfo{"root"} ? delete($sectinfo{"root"}) : $boot_dev

        );

    }




    if ($type eq "xen") {

        if (exists($sectinfo{"append"}) and

            ($sectinfo{"append"} =~ /console=ttyS(\d+),(\d+)/) )

        {

            # merge console and speed into xen_append

            my $console = sprintf("com%d", $1+1);

            my $speed   = sprintf("%s=%d", $console, $2);

            if (exists $sectinfo{"xen_append"}) {

                my $xen_append = $sectinfo{"xen_append"};

                while ($xen_append =~

                       s/(.*)console=(\S+)\s*(.*)$/$1$3/o) {

                    my $del_console = $2;

                    $xen_append =~

                        s/(.*)${del_console}=\d+\s*(.*)$/$1$2/g;

                }

                $sectinfo{"xen_append"} = "console=$console $speed $xen_append";

            } else {

                $sectinfo{"xen_append"} = "console=$console $speed";

            }

        }

    }




    @lines = map {

        my $line_ref = $_;

        my $key = $line_ref->{"key"};




        if ($key eq "root" or $key eq "rootnoverify")

        {

            # always remove old root line

            $line_ref = undef;

        }

        elsif ($key eq "title")

        {

            $line_ref = $self->UpdateSectionNameLine ($sectinfo{"name"}, $line_ref, $sectinfo{"original_name"});

            delete ($sectinfo{"name"});

        }

        elsif ($key eq "module") {

            # put module lines always at the end.

            $line_ref = undef;

        }

        elsif ($key eq "kernel") {

            if ($type eq "xen") {

                $line_ref->{"value"} =

                    $self->UnixPath2GrubPath (delete($sectinfo{"xen"}), $grub_root)

                    . " " . (delete($sectinfo{"xen_append"}) || "");

            }

            elsif ($type eq "image") {

                $line_ref->{"value"} = $self->CreateKernelLine (\%sectinfo, $grub_root);

                delete ($sectinfo{"root"});

                delete ($sectinfo{"vgamode"});

                delete ($sectinfo{"append"});

                delete ($sectinfo{"image"});

            }

        }

        elsif ($key eq "initrd" || $key eq "wildcard")

        {

            if ($type eq "other" or not defined ($sectinfo{$key})) {

                $line_ref = undef;

            }

            else {

                $line_ref->{"value"} = $self->UnixPath2GrubPath ($sectinfo{$key}, $grub_root);

            }

            delete ($sectinfo{$key});

        }

        elsif ($key eq "chainloader")

        {

            # This handles chainloader lines that specify a device name only --

            # a single block offset may have been passed down in our internal

            # variable "blockoffset": this will be added to the constructed

            # "chainloader" line.

            #

            # The general case, i.e. translating between

            # "/dev/disk/by-label/testlabel/boot/grub/stage1" and

            # "(hd0,1)/boot/grub/stage1" cannot be handled with our device name

            # translation scheme. There is no reliable way to find the end of

            # the device name in the above string, esp. since the device does

            # not necessarily exist yet.

            #

            # Probably a different interface is needed to reliably pass

            # "converted GRUB paths" that include UNIX device names between us

            # and the upper layers.

            # 

            # The same problem exists e.g. for "configfile" entries, but there

            # we have no "common simple case" that we could still handle (as we

            # do in the "chainloader" case). We usually would need to translate

            # between "/dev/disk/by-label/testlabel/boot/grub/menu.lst" and

            # "(hd0,3)/boot/grub/menu.lst". We rather choose to require the

            # device in the "root" key and do not expect and handle UNIX device

            # names in the "configfile" value at all.

            if ($type eq "other" and defined ($sectinfo{$key})) {

                $line_ref->{"value"} = $self->CreateChainloaderLine (\%sectinfo, $grub_root);

                delete ($sectinfo{$key});

                delete ($sectinfo{"blockoffset"});

            }

            else {

                $line_ref = undef;

            }

        }

        defined $line_ref ? $line_ref : ();

    } @lines;




    # prepend a root/rootnoverify line where appropriate

    # handle noverify flag and do never verify on chainloader sections

    my $noverify = ($type eq "other");

    if ( exists $sectinfo{"noverifyroot"} and

         defined $sectinfo{"noverifyroot"})

    {

        $noverify = ($noverify or ($sectinfo{"noverifyroot"} eq "true"));

        delete($sectinfo{"noverifyroot"});

    }

    if ($grub_root ne "" or $noverify) {

        unshift @lines, {

            "key" => $noverify ? "rootnoverify" : "root",

            "value" => $grub_root ne "" ? $grub_root : "(hd)",

#           "value" => $grub_root ne "" ? $grub_root : "(hd0,0)",

        };

    }




    # keep a hard order for the following three entries

    if (exists $sectinfo{"xen"}) {

        push @lines, {

            "key" => "kernel",

            "value" => $self->UnixPath2GrubPath ($sectinfo{"xen"}, $grub_root)

                . " " . ($sectinfo{"xen_append"} || ""),

            };

    }

    if (exists $sectinfo{"image"}) {

        my $val = $self->CreateKernelLine (\%sectinfo, $grub_root);

        push @lines, {

            "key" => ($type eq "xen") ? "module" : "kernel",

            "value" => $val,

        };

    }

    if (exists $sectinfo{"initrd"}) {

        push @lines, {

            "key" => ($type eq "xen") ? "module" : "initrd",

            "value" => $self->UnixPath2GrubPath ($sectinfo{"initrd"}, $grub_root),

        };

    }




    # adapt entries if the menu.lst uses different key names etc.

    while ((my $key, my $value) = each (%sectinfo))

    {

        if ($key eq "name")

        {

            my $line_ref = $self->UpdateSectionNameLine ($value, {}, $sectinfo{"original_name"});

            $line_ref->{"key"} = "title";

            unshift @lines, $line_ref;

        }

        elsif ($key eq "chainloader")

        {

            # FIXME: is this necessary? It seems this is already handled in a

            # loop above (where the sectinfo stuff for chainloader is deleted).

            push @lines, {

                "key" => $key,

                "value" => $self->CreateChainloaderLine (\%sectinfo, $grub_root), 

            };

        }

        elsif ($key eq "configfile")

        {

            # dummy/placeholder entry: do we need this?

            push @lines, {

                "key" => $key,

                "value" => $value,

            };

        }

    }




    my $ret = $self->FixSectionLineOrder (\@lines,

        ["title"]);

    return $ret;

}



$glob_info = $Bootloader::Core::GRUB->Global2Info (\@glob_lines, \@section_names);
Gets the general information from the global section of the menu file. This information usually means the default section, graphical menu, timeout etc. As argument it takes a reference to the list of hashes representing lines of the section, returns a reference to a hash containing the important information.
$lines_ref = Bootloader::Core::GRUB->Info2Global (\%section_info, \@section_names);
Takes the info about the global options and uses it to construct the list of lines. The info about global option also contains the original lines. As parameter, takes the section info (reference to a hash) and a list of sectino names, returns the lines (a list of hashes).
$settings_ref = Bootloader::Core::GRUB->GetSettings ();
returns the complete settings in a hash. Does not read the settings from the system, but returns internal structures.
$status = Bootloader::Core::GRUB->SetSettings (\%settings);
Stores the settings in the given parameter to the internal structures. Does not touch the system. Returns undef on fail, defined nonzero value on success.
$status = Bootloader::Core::GRUB->InitializeBootloader ();
Initializes the firmware to boot the bootloader. Returns undef on fail, defined nonzero value otherwise
$mountpoint = Bootloader::Core::GRUB->GrubDev2MountPoint ();
creates the mountpoint from a Grub Device (hdX,Y), be it a udev device, a udev link or a device mapper device

returns the mountpoint or the grub device, if it couldn't be resolved