# slackware-lib.pl
# Functions for slackware package management

$package_dir = "/var/log/packages";
%class_map = (	'a',	'Base Linux system',
		'ap',	'Applications',
		'd',	'Program development',
		'des',	'Crypt library',
		'e',	'GNU Emacs',
		'f',	'FAQs and documentation',
		'gtk',	'GTK+ and GNOME programs',
		'k',	'Linux kernel source',
		'kde',	'KDE desktop and programs',
		'n',	'Networking',
		't',	'TeX',
		'tcl',	'TcL/Tk',
		'xap',	'X applications',
		'xd',	'X server development',
		'xv',	'XView programs',
		'y',	'Games' );
use POSIX;
chop($system_arch = `uname -m`);

# list_packages([package]*)
# Fills the array %packages with a list of all packages
sub list_packages
{
local ($i, $f, @list);
opendir(DIR, $package_dir);
local @list = @_ ? @_ : grep { !/^\./ } readdir(DIR);
$i = 0;
foreach $f (@list) {
	$packages{$i,'name'} = $f;
	$packages{$i,'class'} = $text{'slack_unclass'};
	open(PKG, "$package_dir/$f");
	while(<PKG>) {
		if (/^PACKAGE LOCATION:\s+disk([a-z]+)\d+/i) {
			$packages{$i,'class'} = $class_map{$1};
			}
		elsif (/^PACKAGE DESCRIPTION:/i) {
			local $desc = <PKG>;
			$desc =~ s/^\S+:\s+//;
			$desc =~ s/\n//;
			$packages{$i,'desc'} = $desc;
			}
		}
	close(PKG);
	$i++;
	}
closedir(DIR);
return $i;
}

# package_info(package)
# Returns an array of package information in the order
#  name, class, description, arch, version, vendor, installtime
sub package_info
{
local @rv = ( $_[0], $text{'slack_unclass'}, $text{'slack_unknown'},
	      $system_arch, $text{'slack_unknown'}, "Slackware" );
local @st = stat("$package_dir/$_[0]");
$rv[6] = ctime($st[9]);
open(PKG, "$package_dir/$_[0]");
while(<PKG>) {
	if (/^PACKAGE LOCATION:\s+disk([a-z]+)\d+/i) {
		$rv[1] = $class_map{$1};
		}
	elsif (/^PACKAGE DESCRIPTION:/i) {
		$rv[2] = "";
		while(<PKG>) {
			last if (/^FILE LIST/i);
			s/^\S+: *//;
			if (!$rv[2] && /([0-9][0-9\.]*)/) {
				$rv[4] = $1;
				}
			$rv[2] .= $_;
			}
		$rv[2] =~ s/\s+$//;
		}
	}
close(PKG);
return @rv;
}

# check_files(package)
# Fills in the %files array with information about the files belonging
# to some package. Values in %files are  path type user group mode size error
sub check_files
{
local $i = 0;
local $file;
open(PKG, "$package_dir/$_[0]");
while(<PKG>) {
	last if (/^FILE LIST:/i);
	}
while($file = <PKG>) {
	$file =~ s/\r|\n//g;
	next if ($file eq "./");
	$file = '/'.$file;
	$files{$i,'path'} = $file;
	local @st = stat($file);
	if (@st) {
		$files{$i,'type'} = -l $file ? 3 :
				    -d $file ? 1 : 0;
		$files{$i,'user'} = getpwuid($st[4]);
		$files{$i,'group'} = getgrgid($st[5]);
		$files{$i,'mode'} = sprintf "%o", $st[2] & 07777;
		$files{$i,'size'} = $st[7];
		$files{$i,'link'} = readlink($file);
		}
	else {
		$files{$i,'type'} = $file =~ /\// ? 1 : 0;
		$files{$i,'user'} = $files{$i,'group'} =
		 $files{$i,'mode'} = $files{$i,'size'} = $text{'slack_unknown'};
		$files{$i,'error'} = $text{'slack_missing'};
		}
	$i++;
	}
return $i;
}

# installed_file(file)
# Given a filename, fills %file with details of the given file and returns 1.
# If the file is not known to the package system, returns 0
# Usable values in %file are  path type user group mode size packages
sub installed_file
{
local ($f, $file, @pkgin);
opendir(DIR, $package_dir);
while($f = readdir(DIR)) {
	next if ($f =~ /^\./);
	open(PKG, "$package_dir/$f");
	while(<PKG>) {
		last if (/^FILE LIST:/);
		}
	while($file = <PKG>) {
		next if ($file eq "./");
		$file =~ s/[\/\r\n]+$//;
		$file = '/'.$file;
		if ($_[0] eq $file) {
			# found it!
			push(@pkgin, $f);
			last;
			}
		}
	close(PKG);
	}
closedir(DIR);
if (@pkgin) {
	local @st = stat($_[0]);
	$file{'path'} = $_[0];
	$file{'type'} = -l $_[0] ? 3 :
			-d $_[0] ? 1 : 0;
	$file{'user'} = getpwuid($st[4]);
	$file{'group'} = getgrgid($st[5]);
	$file{'mode'} = sprintf "%o", $st[2] & 07777;
	$file{'size'} = $st[7];
	$file{'link'} = readlink($_[0]);
	$file{'packages'} = join(" ", @pkgin);
	return 1;
	}
else {
	return 0;
	}
}

# is_package(file)
sub is_package
{
local $count;
open(TAR, "gunzip -c $_[0] | tar tf - 2>&1 |");
while(<TAR>) {
	$count++ if (/^[^\/\s]\S+/);
	}
close(TAR);
return $count < 2 ? 0 : 1;
}

# file_packages(file)
# Returns a list of all packages in the given file, in the form
#  package description
sub file_packages
{
if ($_[0] !~ /^(.*)\/(([^\/]+)(\.tgz|\.tar\.gz))$/) {
	return "$_[0] $text{'slack_unknown'}";
	}
local ($dir, $file, $base) = ($1, $2, $3);
local $diskfile;
opendir(DIR, $dir);
while($f = readdir(DIR)) {
	if ($f =~ /^disk\S+\d+$/ || $f eq 'package_descriptions') {
		# found the slackware disk file
		$diskfile = "$dir/$f";
		last;
		}
	}
closedir(DIR);
return "$base $text{'slack_unknown'}" if (!$diskfile);

# read the disk file
local $desc;
open(DISK, $diskfile);
while(<DISK>) {
	if (/^$base:\s*(.*)/) {
		$desc = $1;
		last;
		}
	}
close(DISK);
return $desc ? "$base $desc" : "$base $text{'slack_unknown'}";
}

# install_options(file, package)
# Outputs HTML for choosing install options
sub install_options
{
print "<tr> <td><b>$text{'slack_root'}</b></td>\n";
print "<td colspan=3><input name=root size=30 value='/'> ",
	&file_chooser_button("root", 1),"</td> </tr>\n";
}

# install_package(file, package)
# Installs the package in the given file, with options from %in
sub install_package
{
local $in = $_[2] ? $_[2] : \%in;
return $text{'slack_eroot'} if (!-d $in->{'root'});
$ENV{'ROOT'} = $in->{'root'};
local $out = &backquote_logged("installpkg $_[0] 2>&1");
if ($?) {
	return "<pre>$out</pre>";
	}
return undef;
}

# delete_package(package)
# Totally remove some package
sub delete_package
{
local $out = &backquote_logged("removepkg $_[0] 2>&1");
if ($?) { return "<pre>$out</pre>"; }
return undef;
}

sub package_system
{
return $text{'slack_manager'};
}

sub package_help
{
return "installpkg removepkg";
}

1;

