#!/usr/bin/perl
#
# (C) 2014 mchang@suse.com
#
# 2014-02-20 jw@suse.de

use strict;

my $grub2_dir;
my $grub2_reboot;
my $show_mapped;
my $id_name;
my @menuentry;

sub parse_menuentry {

    my ($parent, $menu) = @_;
    my @m = $menu =~ /(submenu|menuentry) \s+ (.*?) ( \{ (?: [^{}]* | (?3))* \} )/sxg;

    for (my $i = 0; $i <= $#m; $i += 3) {

        my $type  = $m[$i];
        my $title = `printf "%s\n" $m[$i+1] | head -1 | tr -d '\n'`;
        my $data  = $m[$i+2];
        my $name = ($parent) ? "$parent>$title" : "$title";

        if ($type eq "menuentry") {
            push @menuentry, $name;
        } elsif ($type eq "submenu") {
            &parse_menuentry ($name, $data);
        }
    }
}

# Enable restore grubenv service (bnc#892358)
# Restore grubenv settings for booting default entry to workaround the grub2-once cannot
# work and function properly on lvm, md and s390.
sub enable_restore_grubenv_service {

    my $systemctl="/usr/bin/systemctl";

    if (-x $systemctl) {
      system "$systemctl --no-reload enable grub2-once >/dev/null 2>&1";
    } 
}

$id_name = "";
if (@ARGV == 2 && ($ARGV[0] eq "--show-mapped")) {
    $show_mapped = 1;
    $id_name = $ARGV[1];
} elsif (@ARGV == 1) {
    $show_mapped = 0;
    $id_name = $ARGV[0];
} 

die "wrong command line options, try --help\n" if ($id_name eq "");

open(SYSCONF, "</etc/sysconfig/bootloader") || die "cannot read bootloader sysconfig: $!\n";

$grub2_dir = "";
while (<SYSCONF>) {
    if (/^#/) {
	next
    };
    if (/LOADER_TYPE="(.*)"/) {
        my $bl = $1; 
        if ($bl eq "grub2" || $bl eq "grub2-efi") {
            $grub2_dir = "/boot/grub2";
            $grub2_reboot = "/usr/sbin/grub2-reboot";
        }
        last;
    }
}

close (SYSCONF);

if ($id_name eq "--help" or $id_name eq "-h")
  {
    print "Usage: grub2-once [--show-mapped ID | --list | ID | NAME_SUBSTRING ]\n";
    system "$grub2_reboot \"--help\"";
    exit 0;
  }

die "no grub2_dir" if ($grub2_dir eq "");

open(MENU, "<$grub2_dir/grub.cfg") || die "cannot read grub.cfg in $grub2_dir: $!\n";
undef $/;

while (<MENU>) {
    &parse_menuentry ("", $_);
}

close (MENU);

if (open(MENU, "<$grub2_dir/custom.cfg")) {
    while (<MENU>) {
	&parse_menuentry ("", $_);
    }
    close (MENU);
}

my $ret = "";
my $name = "";
my $id = -1;

if ($id_name eq '--list')
  {
    my $c = 0;
    foreach my $e (@menuentry) 
      {
        printf "%6d %s\n", $c, $e;
	$c++;
      }
    exit 0;
  }

if ($id_name =~ m!^[0-9]+$!) {

    if ($id_name < @menuentry) {
        $id = $id_name;
        $name = $menuentry[$id];
        $ret = $name;
    }

} else {

    my $i = -1;
    my $c = 0;

    $name = $id_name;

    foreach my $e (@menuentry) {
        if ($e =~ qr!\Q$name\E!) {
            $i = $c;
            last;
        }
    } continue {
        ++$c;
    }

    if ($i >= 0) {
        $id = $i;
        $name = $menuentry[$id];
        $ret = "$id";
    }
}

if ($show_mapped > 0) {
    print $ret;
} else {
    system "$grub2_reboot \"$name\"";
    enable_restore_grubenv_service;
}