#! /usr/bin/perl
#
# genlilo v1.1 - todd j. derr <tjd@barefoot.org>
#
# genlilo [ -d path ] [ -z name ] [ -l base_label ]
#
#	-d: path to images
#	-z: basename of images
#	-l: basename of lilo label
#
# builds /etc/lilo.conf from /etc/lilo.conf.proto and zImages in /boot
# then runs lilo.
#
# lilo.conf.proto format:
#
# lines to insert before kernel images
# [PROTO_START]
# lines to insert for each kernel image (/boot/zImage.*)
# [PROTO_END]
# lines to insert after kernel images
#
# assumes kernel images are in $BOOT and named $ZIMAGE.v.s.p[extra_label]

# Configuration section: fs dependent stuff
$LILO="/sbin/lilo";	# path to lilo
$BOOT="/boot";	 	# path to kernel images (zimage.*) [ -d ]
$CONF="/etc/lilo.conf";	# path to lilo config file
$PROTO="$CONF.proto";	# path to lilo prototype file

$ZIMAGE="zImage";	# basename for zImage files [ -z ]
$LABEL="linux.";	# base part of label in lilo.conf [ -l ]

$BACKUP=0;		# make a backup of lilo.conf first? (0=no/1=yes)
$SORT_BY_TIME=1;	# sort zImages: 1=by time 0=by name

# You shouldn't need to change anything below here.

$prog=$0;
$prog =~ s#.*/##g;

require "stat.pl" if $SORT_BY_TIME;
require "getopts.pl";

# command line options
&Getopts("d:z:l:n");

if($opt_d) { $BOOT="$opt_d"; }
if($opt_z) { $ZIMAGE="$opt_z"; }
if($opt_l) { $LABEL="$opt_l"; }
if($opt_n) { $fake_it=1; }	# undocumented, for debugging, like make -n

# ready to roll

chdir($BOOT) || die("$prog: chdir($BOOT): $!\n");

if($fake_it)
{
	open(C,">&STDOUT");
}
else
{
	if($BACKUP)
	{
		rename("$CONF","$CONF.old") ||
			die("$prog: rename($CONF): $!\n");
	}
	else
	{
		unlink("$CONF") || die ("$prog: unlink($CONF): $!\n");
	}

	open(C,">$CONF") || die("$prog: open($CONF): $!\n");
}

open(P,"$PROTO") || die("$prog: open($PROTO): $!\n");

print "$prog: generating lilo configuration...\n";

$_=<P>;
while(!/[PROTO_START]/) {
	print C;
	$_=<P>;
}

print C "\n";
$_=<P>;
while(!/[PROTO_END]/) {
	push(@proto,$_);
	$_=<P>;
}

@kerns=<${ZIMAGE}*>;

if($SORT_BY_TIME)
{
	# build assoc of mtimes.
	foreach $k (@kerns)
	{
		(@s=stat($k)) || die("$k: $!\n");
		$ktime{$k}=@s[$ST_MTIME];
	}

	@kerns=sort(sortbytime @kerns);
}
else
{
	@kerns=sort(sortbyname @kerns);
}

foreach $k (@kerns) {
	($ver) = ($k =~ /$ZIMAGE\.(.*)/);

	print C "image =\t/boot/$k\n";
	print C "\tlabel=$LABEL$ver\n";
	print C "@proto";
	print C "\n";
}

while(<P>) { print C; }

close(P);
close(C);

exit 0 if $fake_it;
system("$LILO") && die("$prog: can't execute $LILO!\n");

exit 0;

# ------ end of main ------

# requires ktime to be initialized above (to avoid unnecessary stat()s
sub sortbytime {
	(($ktime{$a} < $ktime{$b})? 1 : -1);
}

# sorts zImage.v.s.p[extra_tag] by name
sub sortbyname {
	($va,$sa,$pa,$stuffa)=($a =~ /(\d+)\.(\d+).(\d+)(.*)/);
	($vb,$sb,$pb,$stuffb)=($b =~ /(\d+)\.(\d+).(\d+)(.*)/);

	return -1 if $va>$vb;
	return  1 if $va<$vb;
	return -1 if $sa>$sb;
	return  1 if $sa<$sb;
	return -1 if $pa>$pb;
	return  1 if $pa<$pb;
	return -1 if $stuffa<$stuffb;
	return  1 if $stuffa>$stuffb;
	return 0;
}
