#!/usr/bin/perl
# -*- Mode: cperl -*-
# Copyright (C) 2000, 2001, 2002 by MandrakeSoft, Pixel <pixel@mandrakesoft.com>
# and others MandrakeSoft folks.
# Redistribution of this file is permitted under the terms of the GNU
# Public License (GPL)
##
# Description: Detect what type of loader you have on your MBR
# If neither LILO nor GRUB is found on MBR, try partitions too.
# $Id: detectloader,v 1.25 2003/11/12 12:38:24 prigaux Exp $

use MDK::Common;

my ($quiet);

if ($ARGV[0] =~ /^-q/) {
    $quiet=1;
    shift;
}

my $loader = $ENV{DEFAULT_LOADER} || detect();
print uc($loader), "\n";


sub detect {
    return "aboot" if arch() =~ /alpha/;

    my @all = read_partitions();
    my @parts = grep { $_->{dev} =~ /\d$/ } @all;
    my @disks = grep { $_->{dev} !~ /\d$/ } @all;
    my $from_lilo = get_boot_from_lilo();
    my $loader;
    my $from_lilo_devfs = "/dev/" . readlink($from_lilo);

    foreach (@disks) {
	my $dev = "/dev/$_->{dev}";
	$loader = typeOfMBR($_) and return $loader if $dev =~ $from_lilo || $dev =~ $from_lilo_devfs;
    }

    foreach (@disks) {
	$loader = typeOfMBR($_) and return $loader;
    }
    warn "no bootloader on MBR, trying partitions!\n" if !$quiet;
    foreach (@parts) {
	$loader = typeOfMBR($_) and return $loader;
    }
}

BEGIN {

@known_boot_loaders = qw(lilo grub yaboot);

# keep this in sync with DrakX
@MBR_signatures = (
if_(arch() =~ /ppc/,
    map { [ 'yaboot', 0, "PM", 0x200 * $_ + 0x10, "bootstrap\0" ] } 0 .. 61
),
    [ 'empty', 0, "\0\0\0\0" ],
    [ 'grub', 0, "\xEBG", 0x17d, "stage1 \0" ],
    [ 'grub', 0, "\xEBH", 0x17e, "stage1 \0" ],
    [ 'grub', 0, "\xEBH", 0x18a, "stage1 \0" ],
    [ 'grub', 0, "\xEBH", 0x181, "GRUB \0" ],
    [ 'lilo', 0x2,  "LILO" ],
    [ 'lilo', 0x6,  "LILO" ],
    [ 'grub', 0x6,  "GRUB" ],
    [ 'osbs', 0x2,  "OSBS" ], #- http://www.prz.tu-berlin.de/~wolf/os-bs.html
    [ 'pqmagic', 0xef, "PQV" ],
    [ 'BootStar', 0x130, "BootStar:" ],
    [ 'DocsBoot', 0x148, 'DocsBoot' ],
    [ 'system_commander', 0x1ad, "SYSCMNDRSYS" ],
    [ 'Be Os', 0x24, 'Boot Manager' ],
    [ 'os2', 0, "\xFA\xB8\x30\x00", 0xfA, "OS/2" ],
    [ 'TimO', 0, 'IBM Thinkpad hibernation partition' ],
    [ 'dos', 0xa0, "\x25\x03\x4E\x02\xCD\x13" ],
    [ 'dos', 0xa0, "\x00\xB4\x08\xCD\x13\x72" ], #- nt2k's
    [ 'dos', 0x60, "\xBB\x00\x7C\xB8\x01\x02\x57\xCD\x13\x5F\x73\x0C\x33\xC0\xCD\x13" ], #- nt's
    [ 'dos', 0x70, "\x0C\x33\xC0\xCD\x13\x4F\x75\xED\xBE\xA3" ],
    [ 'freebsd', 0xC0, "\x00\x30\xE4\xCD\x16\xCD\x19\xBB\x07\x00\xB4" ],
    [ 'freebsd', 0x160, "\x6A\x10\x89\xE6\x48\x80\xCC\x40\xCD\x13" ],
    [ 'dummy', 0xAC, "\x0E\xB3\x07\x56\xCD\x10\x5E\xEB" ], #- caldera?
    [ 'ranish', 0x100, "\x6A\x10\xB4\x42\x8B\xF4\xCD\x13\x8B\xE5\x73" ],
    [ 'os2', 0x1c2, "\x0A" ],
    [ 'Acronis', 0, "\xE8\x12\x01" ],
);

}

sub typeOfMBR {
    my ($disk) = @_;

    my $dev = "/dev/$disk->{dev}";
    my $tmp;
    if (! -e $dev) {
	$tmp = "/tmp/.detect_loader.tmpdev";
	-e $tmp and die "detectloader: block special file $tmp already exist\n";
	system("mknod", $tmp, "b", $disk->{major}, $disk->{minor});
	$? == 0 or die "detectloader: can't create block special file $tmp\n";
	-l $tmp and die "detectloader: something weird is happening";
    }
    my $t = typeFromMagic($tmp || $dev, @MBR_signatures);
    unlink $tmp if $tmp;

    member($t, @known_boot_loaders) or return;

    $t;
}

sub read_partitions {
    my (undef, undef, @all) = cat_("/proc/partitions");
    grep {
	$_->{size} != 0x3fffffff # skip cdroms (otherwise stops cd-audios)
    } map {
	my %l;
	@l{qw(major minor size dev)} = split;
	\%l;
    } @all;
}

sub get_boot_from_lilo {
    my $lilo_conf = "/etc/lilo.conf"; return unless $lilo_conf;
    local *F;open F, $lilo_conf or warn "Can't open $lilo_conf: $!\n";
    my $return;
    while (<F>) {
	$return = $1 if m|^boot=(\S*)$| and not $return;
    }
    close F;
    return $return;
}
