#!/usr/bin/perl -w
#
# $Id: ase-check-prereq.pl,v 1.3 2004/12/07 14:59:13 mpeppler Exp $

use strict;

my $VERSION = substr(q$Revision: 1.3 $, 10);

my @version = qw(slackware-version redhat-release gentoo-release SuSE-release
		 mandrake-release debian-version);
my $min_glibc = '2.2.4';
my $min_kernel = '2.4.9';
my $min_shmmax = 67108864;

my $fmt = "%-20.20s %-25s %s\n";

my @instructions;
my $unsupported = 0;
my $fail = 0;

my $uname = get_uname();
my $processor = `uname -m`;
chomp($uname);
chomp($processor);

print "\nASE installation pre-requisites checker for linux (version $VERSION)\n\n";
print "System: $uname\n\n";
if($processor =~ /i(\d+)/) {
    if($1 < 586) {
	print <<EOF;
Attempting to install ASE on a $processor architecture machine.
This will not work - ASE requires are least an i586 processor to run.
EOF
	exit(0);
    }
}

print <<EOF;
WARNING - the distribution detection code is incomplete. If you run one
of SuSE/Mandrake/Debian and the distribution is detected as "UNKNOWN"
then please check the /etc directory for a file called "<distro>-release"
or something similar (Red Hat/Fedora uses /etc/redhat-release, for example).
Please send me (Michael Peppler - mpeppler\@peppler.org) the name of 
this file and its contents so that I can update this little script.

Thank you.

EOF

check_distro();
check_kernel();
check_glibc();
check_libstdc();
check_shmmax();

if($fail) {
    print <<EOF;
WARNING:
-------
One or more issues are known to cause the installation to fail. These must be remedied before attemtping the install
EOF
}

if(@instructions) {
    print "You should fix the following issues before attempting to install ASE:\n";
    foreach (@instructions) {
	print;
    }
}
if($unsupported) {
    print <<EOF;

You are attempting to install ASE on an unsupported platform. 
While ASE will most likely install and run without problems you may 
encounter difficulties if you try to obtain support from Sybase.
You can get help for various problems on the net (public forums, 
mailing lists, etc.) or you can purchase support through one of the 
independent Sybase consultants (Michael Peppler, etc.)
EOF
}

sub check_distro {
    my $found = 0;
    foreach (@version) {
	if(-e "/etc/$_") {
	    ++$found;
	    my $ver = `cat /etc/$_`;
	    # SuSE uses two lines.
	    $ver =~ s/\n/ /g;
	    if($_ =~ /debian/) { # debian doesn't include it's name in the file
		$ver = "debian $ver";
	    }
	    #chomp($ver);
	    my $ok = supported_distro($ver);
	    if($ok =~ /^un/i) {
		++$unsupported;
	    }
	    # Remove trailing VERSION stuff from SuSE line because
	    # it screws up the display.
	    $ver =~ s/\sVERSION\s*=\s*[\d\.]+//;
	    printf($fmt, "Distro", $ver, $ok);
	}
    }
    if(!$found) {
	printf($fmt, "Distro", "unknown");
    }
}

sub check_kernel {
    my $data = `cat /proc/sys/kernel/osrelease`;
    chomp($data);
    my $ok;

#    print "Checking kernel: ";
    if(compare_rev($min_kernel, $data)) {
	$ok = 'OK';
    } else {
	++$fail;
	$ok = 'FAIL';
	push(@instructions, "Please install a newer kernel ($min_kernel requried)\n");
    }
    printf($fmt, "Checking kernel", $data, "$ok ($min_kernel required)");
}

sub check_shmmax {
    my $data = `cat /proc/sys/kernel/shmmax`;
    chomp($data);
    my $ok;

#    print "Checking shmmax: ";
    if(compare_rev($min_shmmax, $data)) {
	$ok = 'OK';
    } else {
	++$fail;
	$ok = 'FAIL';
	push(@instructions, "Please edit /etc/sysctl.conf and add a like with
    kernel.shmmax = $min_shmmax
and then run /sbin/sysctl -p\n");
    }
    printf($fmt, "Checking shmmax", $data, "$ok ($min_shmmax required)");
}

sub check_glibc {
    if(-x '/bin/rpm') {
	check_glibc_rpm();
    } else {
	check_glibc_raw()
    }
}

sub check_glibc_rpm {
    my $glibc = `rpm -q glibc`;
    if($glibc =~ /glibc-([\d\.\-]+)/) {
	my $ver = $1;
	my $ok = 'FAIL';
	if(compare_rev($min_glibc, $ver)) {
	    $ok = 'OK';
	} else {
	    ++$fail;
	    push(@instructions, "The glibc version found on this machine is too old. You need to upgrade the glibc package. However, as the glibc requirements are fairly wide this probably means that a full upgrade of the system is required.\n");
	}
	printf($fmt, "Checking glibc", $ver, "$ok ($min_glibc required)");
    }
}

sub check_glibc_raw {
    my $libc = "/lib/libc.so.6";
    if(!-e $libc) {
	++$fail;
	printf($fmt, "Checking glibc", "FAIL", "no valid libc.so.6 found!");
	return;
    }
    my $ver;
    my $data;
    if(!-x $libc) {
	my $real = readink($libc);
	if($real =~ /libc-([\d\.]+)/) {
	    $ver = $1;
	}
    } else {
	$data = `$libc`;
	if($data =~ /release version ([\d\.]+)/) {
	    $ver = $1;
	}
    }
    my $ok = 'FAIL';
    if($ver) {
	if(compare_rev($min_glibc, $ver)) {
	    $ok = 'OK';
	}  else {
	    ++$fail;
	    push(@instructions, "The glibc version found on this machine is too old. You need to upgrade the glibc package. However, as the glibc requirements are fairly wide this probably means that a full upgrade of the system is required.\n");
	}
	printf($fmt, "Checking glibc", $ver, "$ok ($min_glibc required)");
    } else {
	printf($fmt, "Checking glibc", "unknown", "($min_glibc required)");
    }
	
    if($data =~ /linuxthreads/) {
	printf($fmt, "Glibc", "linuxthreads available", "");
    }
}

sub check_libstdc {
    if(-e '/usr/lib/libstdc++-libc6.2-2.so.3') {
	printf($fmt, "Checking for libstdc++", "OK", "");
    } else {
	++$fail;
	printf($fmt, "Checking for libstdc++", "FAIL", "");
	push(@instructions, "Please install the compat-libstdc++ package (Red Hat/ Fedora), the 'compat' package (SuSE), or emerge lib-compat (Gentoo)\n");
    }
}

sub supported_distro {
    my $distro = shift;

    if($distro =~ /Red Hat Linux release ([\d\.]+)/) {
	if($1 >= 7.2 && $1 != 9) {
	    return "UNSUPPORTED";
	} elsif($1 == 9) {
	    push(@instructions, "You are trying to install ASE on Red Hat 9. This requires the installation of a glibc patch. We strongly recommended upgrading to either Fedora Core or Red Hat Enterprise 3.x instead");
	    return "REQUIRES glibc PATCH (not recommended)";
	} else {
	    push(@instructions, "This version of Red Hat is too old to support ASE. Please upgrade to Red Hat Enterprise 3.x, or (for an 'unsupported' platform) to Fedora Core\n");
	    ++$fail;
	    return "FAIL";
	}
    }
    if($distro =~ /Red Hat Enterprise Linux .+ release ([\d\.]+)/) {
	return "OK";
    }
    if($distro =~ /Fedora Core/ || $distro =~ /Gentoo/) {
	return "UNSUPPORTED";
    }
    if($distro =~ /slack/i) {
	++$fail;
	push(@instructions, "Slackware will not run ASE out of the box. It is highly recommended that you move to Red Hat Enterprise Linux, SuSE Enterprise, or, for an 'unsupported' platform to Fedora Core");
	return "FAIL";
    }
    if($distro =~ /SuSE/) {
	if($distro =~ /SLES-8/) {
	    return "OK";
	} else {
	    return "UNSUPPORTED";
	}
    }
    if($distro =~ /Mandrake/i) {
	return "UNSUPPORTED";
    }
    if($distro =~ /debian/i) {
	return "UNSUPPORTED";
    }

    return "UNKNOWN";
}

sub compare_rev {
    my $min = shift;
    my $rev = shift;

    my(@min) = split(/\./, $min);
    my(@rev) = split(/\./, $rev);

    for(my $i = 0; $i < @min; ++$i) {
	local $^W = 0;
	if($rev[$i] > $min[$i]) {
	    return 1;
	}
    }
    if($rev[$#min] == $min[$#min]) {
	return 1;
    }

    return 0;
}

sub get_uname {
    my $uname = '';
    foreach (qw(-s -n -r -m)) {
	my $t = `uname $_`;
	chomp($t);
	$uname .= "$t ";
    }

    return $uname;
}
