#!/usr/bin/perl -w
#
#
# Copywrite 2005 - Steven Rostedt
#
# This code has no restrictions and NO WARRANTY. 
#  Use it at your own risk, do what you want with it,
#  Just don't blame me.
#
# This program is used to clean up the /boot and /lib/modules
# directories.  It searches all the config-*, vmlinuz-*, 
# System.map-* and initrd.img-* found in /boot as well all
# the directories that start with a digit in /lib/modules.
# Then after displaying the versions found, it goes through
# each one asking if you would like to remove all the files
# found.
#
require 'sys/ioctl.ph';

my $VERSION = "0.2";

chomp(my $pwd = `pwd`);

my $bootdir = "/boot";
my $moduledir = "/lib/modules";

while ($#ARGV >= 0) {
    if ($ARGV[0] eq "-b") {
	shift;
	usage(-1) if ($#ARGV < 0);
	$bootdir = $ARGV[0];
    } elsif ($ARGV[0] eq "-m") {
	shift;
	usage(-1) if ($#ARGV < 0);
	$moduledir = $ARGV[0];
    } else {
	usage(0);
    }
    shift;
}

my %configs;
my %vmlinux;
my %initrd;
my %maps;
my %modules;
my %versions;

my $colsize = 80;
my $winsize;
if (ioctl(STDOUT, &TIOCGWINSZ, $winsize='')) {
    my ($row, $col, $xpixel, $ypixel) = unpack('S4', $winsize);
    $colsize = $col;
}

chdir $bootdir || die "Can't entering $bootdir";

open(IN, "ls|") || die "Error listing $bootdir\n";
while (<IN>) {
    chomp;
    if (/(vmlinuz|config|initrd\.img|System\.map)-(.*)/) {
	my $type = $1;
	my $name = $2;
	$versions{$name} = 1;
	$configs{$name} = $_ if ($type eq "config");
	$vmlinux{$name} = $_ if ($type eq "vmlinuz");
	$initrd{$name} = $_ if ($type eq "initrd.img");
	$maps{$name} = $_ if ($type eq "System.map");
    }
}
close IN;

chdir $pwd;  # may be a relative path

chdir $moduledir || die "Error entering $moduledir\n";

open(IN, "ls|") || die "Error listing $bootdir\n";
while (<IN>) {
    chomp;
    if (/(\d.*)/) {
	my $name = $1;
	$versions{$name} = 1;
	$modules{$name} = $_;
    }
}
close IN;

my $maxsize = 0;
foreach my $key (sort keys %versions) {
    my $len = length $key;
    $maxsize = $len if ($len > $maxsize);
}

my $cols = int ($colsize / ($maxsize + 3));
my $pad = 0;
if (!$cols) {
    $cols = 1;
} elsif ($cols > 1) {
    $pad = int (($colsize - ($maxsize * $cols)) / $cols);
    $pad = 3 if ($pad < 3);
}
$pad += $maxsize;

list_versions();

foreach my $key (sort keys %versions) {
    next if ($key =~ /\.old$/);
repeat:
    print "Remove files for version $key [y/N/l/q/?]:  ";
    goto repeat if (process_answer($key));

    $key .= ".old";
    if (defined($versions{$key})) {
repeat2:
	print "Remove files for older version $key [y/N/l/q/?]:  ";
	goto repeat2 if (process_answer($key));
    }
}

exit 0;

sub usage {
    my ($err) = @_;

    print "\n";
    print "usage: clean-boot.pl [-b boot_dir] [-m module_dir]\n";
    print "  (version $VERSION)\n";
    print "   default boot_dir = /boot\n";
    print "   default module_dir = /lib/modules\n";
    print "\n";

    exit $err;
}
    
sub list_versions {
    print "List of versions found: \n";
    my $cnt = 1;
    foreach my $key (sort keys %versions) {
	print ("  ") if ($cnt == 1);
	if ($cnt < $cols) {
	    printf "%-*s",$pad,$key;
	    $cnt++;
	} else {
	    print "$key\n";
	    $cnt = 1;
	}
    }
    print "\n" if ($cnt != 1);
}

sub process_answer {
    my ($ver) = @_;

    chomp(my $answer = <STDIN>);
    $answer =~ tr/A-Z/a-z/;
    if ($answer =~ /^y(e(s)?)?$/) {
	remove_files($ver);
    }
    exit 0 if ($answer eq "q");
    if ($answer eq "l") {
	list_versions();
	return 1;
    }
    if ($answer eq "?") {
	print "  y - remove files from boot and modules\n";
	print "  n [default] - skip this version\n";
	print "  l - list the found versions again\n";
	print "  q - quit\n";
	print "  ? - display this message\n";
	return 1;
    }
    return 0;
}
    
sub remove_files {
    local ($ver) = @_;

    chdir $pwd;
    unlink "$bootdir/config-$ver" if (defined($configs{$ver}));
    unlink "$bootdir/vmlinuz-$ver" if (defined($vmlinux{$ver}));
    unlink "$bootdir/initrd.img-$ver" if (defined($initrd{$ver}));
    unlink "$bootdir/System.map-$ver" if (defined($maps{$ver}));

    if (defined($modules{$ver})) {
	`rm -rf "$moduledir/$ver"` if ( -d "$moduledir/$ver");
    }
}
