#!/usr/bin/perl -w
#
# Creates common environment for distributions
#
# $Id$
#

use strict;

sub pb_distro_init {

my $ddir = shift || undef;
my $dver = shift || undef;
my $dfam = "unknown";
my $dtype = "unknown";
my $dsuf = "unknown";

# If we don't know which distribution we're on, then guess it
($ddir,$dver) = pb_get_distro() if ((not defined $ddir) || (not defined $dver));

# There should be unicity of names between ddir dfam and dtype
# In case of duplicate, bad things can happen
if (($ddir =~ /debian/) ||
	($ddir =~ /ubuntu/)) {
	$dfam="du";
	$dtype="deb";
	$dsuf=".$ddir$dver";
} elsif ($ddir =~ /gentoo/) {
	$dfam="gen";
	$dtype="ebuild";
	$dver="nover";
	$dsuf=".$ddir";
} elsif ($ddir =~ /slackware/) {
	$dfam="slack";
	$dtype="tgz";
	$dsuf=".$dfam$dver";
} elsif (($ddir =~ /suse/) ||
		($ddir =~ /sles/)) {
	if ($ddir =~ /opensuse/) {
		$ddir = "suse";
	}
	$dfam="novell";
	$dtype="rpm";
	$dsuf=".$ddir$dver";
} elsif (($ddir =~ /redhat/) ||
		($ddir =~ /rhel/) ||
		($ddir =~ /fedora/) ||
		($ddir =~ /vmware/) ||
		($ddir =~ /centos/)) {
	$dfam="rh";
	$dtype="rpm";
	my $dver1 = $dver;
	$dver1 =~ s/\.//;
	if ($ddir =~ /fedora/) {
		$dsuf=".fc$dver1";
	} elsif ($ddir =~ /redhat/) {
		$dsuf=".rh$dver1";
	} elsif ($ddir =~ /vmware/) {
		$dsuf=".vwm$dver1";
	} else {
		$dsuf=".$ddir$dver1";
	}
} elsif (($ddir =~ /mandrake/) ||
		($ddir =~ /mandrakelinux/) ||
		($ddir =~ /mandriva/)) {
	$dfam="md";
	$dtype="rpm";
	if ($ddir =~ /mandrakelinux/) {
		$ddir = "mandrake";
	}
	if ($ddir =~ /mandrake/) {
		my $dver1 = $dver;
		$dver1 =~ s/\.//;
		$dsuf=".mdk$dver1";
	} else {
		$dsuf=".mdv$dver";
	}
} elsif ($ddir =~ /freebsd/) {
	$dfam="bsd";
	$dtype="port";
	my $dver1 = $dver;
	$dver1 =~ s/\.//;
	$dsuf=".$dfam$dver1";
} else {
	$dfam="unknown";
	$dtype="unknown";
	$dsuf="unknown";
}

return($ddir, $dver, $dfam, $dtype, $dsuf);
}

sub pb_get_distro {

# Cf: http://linuxmafia.com/faq/Admin/release-files.html
# Ideas taken from 
# http://search.cpan.org/~kerberus/Linux-Distribution-0.14/lib/Linux/Distribution.pm

my $base="/etc";

# List of files that unambiguously indicates what distro we have
my %single_rel_files = (
# Tested
	'gentoo'			=>	'gentoo-release',		# >= 1.6
	'debian'			=>	'debian_version',		# >= 3.1
	'slackware'			=>	'slackware-version',	# >= 10.2
	'mandriva'			=>	'mandriva-release',		# >=2006.0
	'mandrakelinux'		=>	'mandrakelinux-release',# = 10.2
	'fedora'			=>	'fedora-release',		# >= 4
	'vmware'			=>	'vmware-release',		# >= 3
	'sles'				=>	'sles-release',			# Doesn't exist as of 10
# Untested
	'knoppix'			=>	'knoppix_version',		#
	'yellowdog'			=>	'yellowdog-release',	#
	'esmith'			=>	'e-smith-release',		#
	'turbolinux'		=>	'turbolinux-release',	#
	'blackcat'			=>	'blackcat-release',		#
	'aurox'				=>	'aurox-release',		#
	'annvix'			=>	'annvix-release',		#
	'cobalt'			=>	'cobalt-release',		#
	'redflag'			=>	'redflag-release',		#
	'ark'				=>	'ark-release',			#
	'pld'				=>	'pld-release',			#
	'nld'				=>	'nld-release',			#
	'lfs'				=>	'lfs-release',			#
	'mk'				=>	'mk-release',			#
	'conectiva'			=>	'conectiva-release',	#
	'immunix'			=>	'immunix-release',		#
	'tinysofa'			=>	'tinysofa-release',		#
	'trustix'			=>	'trustix-release',		#
	'adamantix'			=>	'adamantix_version',	#
	'yoper'				=>	'yoper-release',		#
	'arch'				=>	'arch-release',			#
	'libranet'			=>	'libranet_version',		#
	'valinux'			=>	'va-release',			#
	'yellowdog'			=>	'yellowdog-release',	#
	'ultrapenguin'		=>	'ultrapenguin-release',	#
	);

# List of files that ambiguously indicates what distro we have
my %ambiguous_rel_files = (
	'mandrake'			=>	'mandrake-release',		# <= 10.1
	'suse'				=>	'SuSE-release',			# >= 10.0
	'redhat'			=>	'redhat-release',		# >= 7.3
	'lsb'				=>	'lsb-release',			# ???
	);

# Should have the same keys as the previous one.
# If ambiguity, which other distributions should be checked
my %distro_similar = (
	'mandrake'			=> ['mandrake', 'mandrakelinux'],
	'suse'				=> ['suse', 'sles', 'opensuse'],
	'redhat'			=> ['redhat', 'rhel', 'centos', 'mandrake', 'vmware'],
	'lsb'				=> ['ubuntu', 'debian', 'lsb'],
	);

my %distro_match = (
# Tested
	'gentoo'				=> '.* version (.+)',
	'slackware'			 	=> 'S[^ ]* (.+)$',
# There should be no ambiguity between potential ambiguous distro
	'mandrakelinux'			=> 'Mandrakelinux release (.+) \(',
	'mandrake'				=> 'Mandr[^ ]* release (.+) \(',
	'mandriva'				=> 'Mandr[^ ]* [^ ]* release (.+) \(',
	'fedora'				=> 'Fedora .*release (\d+) \(',
	'vmware'				=> 'VMware ESX Server (\d+) \(',
	'rhel'					=> 'Red Hat Enterprise Linux .*release (.+) \(',
	'centos'				=> '.*CentOS .*release (.+) ',
	'redhat'				=> 'Red Hat Linux release (.+) \(',
	'sles'					=> 'SUSE .* Enterprise Server (\d+) \(',
	'suse'					=> 'SUSE LINUX (\d.+) \(',
	'opensuse'				=> 'openSUSE (\d.+) \(',
	'debian'				=> '(.+)',
	'lsb'					=> '.*[^Ubunt].*\nDISTRIB_RELEASE=(.+)',
# Ubuntu 6.06 includes a /etc/debian_version file that needs to be 
# renamed to /etc/debian_version.sav as there is no way to distinguish
# Ubuntu 6.06 from debian testing otherwise
# Same is true for Ubuntu 7.10 :-(
	'ubuntu'				=> '.*Ubuntu.*\nDISTRIB_RELEASE=(.+)',
# Not tested
	'arch'					=> '.* ([0-9.]+) .*',
	'redflag'				=> 'Red Flag (?:Desktop|Linux) (?:release |\()(.*?)(?: \(.+)?\)',
);

my $release;
my $distro;

# Begin to test presence of non-amiguous files
# that way we reduce the choice
my ($d,$r);
while (($d,$r) = each %single_rel_files) {
	if (-f "$base/$r" && ! -l "$base/$r") {
		my $tmp=pb_get_content("$base/$r");
		# Found the only possibility. 
		# Try to get version and return
		if (defined ($distro_match{$d})) {
			($release) = $tmp =~ m/$distro_match{$d}/m;
		} else {
			print STDERR "Unable to find $d version in $r\n";
			print STDERR "Please report to the maintainer bruno_at_project-builder.org\n";
			$release = "unknown";
		}
		return($d,$release);
	}
}

while (($d,$r) = each %ambiguous_rel_files) {
	if (-f "$base/$r" && !-l "$base/$r"){
		# Found one possibility. 
		# Get all distros concerned by that file
		my $tmp=pb_get_content("$base/$r");
		my $found = 0;
		my $ptr = $distro_similar{$d};
		#pb_log(2,$LOG "amb: ".Dumper($ptr)."\n" if ($debug >= 1);
		$release = "unknown";
		foreach my $dd (@$ptr) {
			#pb_log(2,$LOG "check $dd\n" if ($debug >= 1);
			# Try to check pattern
			if (defined $distro_match{$dd}) {
				#pb_log(2,$LOG "cmp: $distro_match{$dd} - vs - $tmp\n" if ($debug >= 1);
				($release) = $tmp =~ m/$distro_match{$dd}/m;
				if ((defined $release) && ($release ne "unknown")) {
					$distro = $dd;
					$found = 1;
					last;
				}
			}
		}
		if ($found == 0) {
			print STDERR "Unable to find $d version in $r\n";
			print STDERR "Please report to the maintainer bruno_at_project-builder.org\n";
			$release = "unknown";
		} else {
			return($distro,$release);
		}
	}
}
return("unknown","unknown");
}

# get content of a file in a variable
sub pb_get_content {

my $file=shift;

my $bkp = $/;
undef $/;
open(R,$file) || die "Unable to open $file: $!";
my $content=<R>;
close(R);
chomp($content);
$/ = $bkp;
return($content);
}
1;
