#!/usr/bin/perl -w
##
## Copyright (c) 2001, 2002, Amnon BARAK (amnon@MOSIX.org).
## All rights reserved.
## This software is subject to the MOSIX SOFTWARE LICENSE AGREEMENT.
##
## THIS SOFTWARE IS PROVIDED IN ITS "AS IS" CONDITION, WITH NO WARRANTY
## WHATSOEVER. NO LIABILITY OF ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING
## FROM THE USE OF THIS SOFTWARE WILL BE ACCEPTED.
##
##
## Author(s): A. Spanier 
##

# This script adds a compiled kernel to the GRUB configuration.

# Default arguments currently compatible with all linux distributions. 
# That is, if grub is used.

use FindBin;
use Getopt::Long;
use lib "$FindBin::Bin";
use File::Basename;
use common;

$kernel_dir	= "";
$boot_dir	= "/boot";         # the place where the kernel locate
$boot_path      = "/boot";         # the path to write in the grub.conf sometime
				   # it's relative to / and some time to /boot
$grub_conf	= "/etc/grub.conf";

GetOptions( 	"kernel_dir=s" ,	\$kernel_dir ,
		"kernel_on_location",	\$kernel_on_location ,
		"dont_delete_files" ,	\$dont_delete_files ,
		"boot_dir=s" ,		\$boot_dir ,
		"grub_conf=s" ,		\$grub_conf ,
		"no_default" ,		\$no_default ,
		"help" ,		\$usage ,
		"uninstall" ,		\$uninstall );


$kernel_dir =~ s/\/$// ;
$boot_dir =~ s/\/$// ;

usage() if defined $usage;
-w $boot_dir or dead "You do not have write permissions on $boot_dir\n";
-w $grub_conf or dead "You do not have write permissions on $grub_conf\n";

uninstall() and exit 1 if defined $uninstall ;
$kernel_on_location or $kernel_dir or dead "You must specify the compiled kernel's source tree root. Use --kernel_dir (--help for usage)";
$kernel_on_location or -r "$kernel_dir/arch/i386" or dead "You do not have read permissions on $kernel_dir\n";
install();
exit 1;
    
sub install
{
	# uninstall
	if (`grep MOSIX $grub_conf 2>&1` =~ /MOSIX/) { 
		dead "Please Uninstall MOSIX before reinstalling";
	}
	$kernel_name = "MOSIX-$mosix_version";
	$kernel_on_location and goto skip_kernel_copy;
	if (!(-d "$kernel_dir/mos")) {
		dead "Kernel in $kernel_dir does not look like a MOSIX kernel";
	}

	#copy kernel to boot directory
	if ((!-e ($kernel_image = "$kernel_dir/arch/i386/boot/bzImage") and
	    (!-e ($kernel_image = "$kernel_dir/arch/i386/boot/zImage")) and
	    (!-e ($kernel_image = "$kernel_dir/arch/i386/boot/Image")))) {
		dead "Kernel image was not found in $kernel_dir/arch/i386/boot/" ;
	}
	
	system( "cp -f $kernel_image $boot_dir/$kernel_name" ) and 
		dead "Unable to copy $kernel_image to $boot_dir/$kernel_name";
	system( "cp -f $kernel_dir/System.map $boot_dir/System.map-$kernel_name" ) and
		dead "Unable to copy $kernel_dir/System.map to $boot_dir";
skip_kernel_copy:
	system( "ln -sf $boot_dir/System.map-$kernel_name $boot_dir/System.map" ) and
		dead "Unable to link $boot_dir/System.map-MOSIX-$mosix_version to $boot_dir/System.map";
	#tamper with GRUB configuration file
	system( "cp -f $grub_conf $grub_conf.pre_mosix" ) and
		dead "Unable to backup old $grub_conf. Aborting";
	open( GRUB , $grub_conf ) or
		dead "Unable to open $grub_conf for reading";
	@grub = <GRUB> ;
	close( GRUB );
	
	# find the default $hd_dev and $root_dir and $boot_path
        ($hd_dev, $boot_path) = default_kernel_arguments( \@grub );
	
	$root_dev = find_root_dev();
	$root_dev or dead "unable to determine your root device please edit grub.conf manually";
	
	open( GRUB , ">>$grub_conf" ) or
		dead "Unable to open $grub_conf for writing";
	print GRUB "\n# The following image was added by the MOSIX installer.\n";
	print GRUB "# Do not remove manually. Please use the --uninstall\n";
	print GRUB "# option of the installer\n";
	print GRUB "# MOSIX IMAGE: $kernel_name\n";
        print GRUB "title MOSIX $mosix_version ( $kernel_version )\n";
        print GRUB "\troot $hd_dev\n";
        print GRUB "\tkernel $boot_path/$kernel_name ro root=$root_dev\n";
	close( GRUB );

	#make mosix the default kernel
        $no_default or make_default();

	exit ;}


sub usage {
	print "Usage : add_kernel_to_grub [OPTION]\n";
	print "--kernel_dir=   the compiled kernel source root directory (must specify!)\n";
	print "--boot_dir=     the binary kernels images directory (default: /boot)\n";
	print "--grub_conf=    the current configuration file of grub, to change (default: /etc/grub.conf)\n";
	print "--nodefault     do not assign MOSIX to be the default kernel\n";
	print "--uninstall     uninstall\n";
	print "--help          this message\n";
	exit ;
}

sub uninstall {
	`grep '# MOSIX' $grub_conf 2>&1` =~ /MOSIX\ IMAGE\:\s(.*)\n/ or
		print "\nYour previous MOSIX kernel was either not included in '$grub_conf',\n" and
		print "or it was included manually and cannot be removed automatically.\n" and
		system( "rm -f $grub_conf.pre_mosix" ),
		exit ;
	$kernel_image = $1 ;
	if(not -f "$grub_conf.pre_mosix") {
		print "\nSorry: could not find $grub_conf.pre_mosix!\n" ;
		exit 1;
	}
	chdir dirname( $grub_conf );
	system( "mv -f $grub_conf.pre_mosix ".trace_link($grub_conf) ) and
		dead "Unable to restore old grub.conf file from $grub_conf.pre_mosix\n";
	$dont_delete_files and exit;
	unlink( "$boot_dir/$kernel_image" ) or
		print "\nFailed to delete $boot_dir/$kernel_image\n";
	unlink "$boot_dir/System.map-$kernel_image" or
		print "\nFailed to delete $boot_dir/System.map-$kernel_image\n";
	exit;
}


sub default_kernel_arguments {
	$file = shift;


 	foreach $line (@$file) {
                if ($line =~ /default\W*?(\d*?)$/) {
                        $id = $1;
                }
        }
	
	my $grub_whole = join '' , @$file;
        my @kernel = split /\n\s*title/ , $grub_whole;
	
        $t_line = $kernel[$id+1];
        
	$t_line =~ /.*root\ (\(.*\)).*/;
        $hd = $1;

	if ($t_line =~ /\/boot/ ) {
		$boot_path = "/boot";
	} else {
		$boot_path = "";
	}


	if ($hd eq "" || $hd eq "") {
		dead "Unable to read pramters from $grub_conf\nprobably your \'default\' parameter have wrong value";  
	}
	
	return $hd,$boot_path;
}


sub make_default {
	#arguemt: name of kernel to make default
	
	open( GRUB , $grub_conf ) or
                dead "Unable to open $grub_conf for reading";
        @grub = <GRUB> ;
        close( GRUB );
	
	$def_num = scalar( grep /^title/ , @grub ) - 1;
	
 	open( GRUB , ">$grub_conf" )  or
                dead "Unable to open $grub_conf for writing";
 	
	if( scalar( grep /^\s*default/ , @grub ) ) {
		$_ = join '',@grub ;
		s/\ndefault\s*=.*\n/\ndefault\=$def_num\n/g;
		print GRUB $_;
	} else {
		print GRUB "default=$def_num\n";
		print GRUB join '' , @grub;
	}

       close( GRUB );

}
