#!/usr/local/bin/perl
# fsdump-lib.pl
# Common functions for doing filesystem backups with dump
# XXX multi-volume tar restore

do '../web-lib.pl';
&init_config();
require '../ui-lib.pl';
if ($gconfig{'os_type'} =~ /^\S+\-linux$/) {
	do "linux-lib.pl";
	}
else {
	do "$gconfig{'os_type'}-lib.pl";
	}
&foreign_require("mount", "mount-lib.pl");
%access = &get_module_acl();

$cron_cmd = "$module_config_directory/backup.pl";
$newtape_cmd = "$module_config_directory/newtape.pl";
$notape_cmd = "$module_config_directory/notape.pl";
$multi_cmd = "$module_config_directory/multi.pl";
$rmulti_cmd = "$module_config_directory/rmulti.pl";

# list_dumps()
# Returns a list of all scheduled dumps
sub list_dumps
{
local (@rv, $f);
opendir(DIR, $module_config_directory);
foreach $f (sort { $a cmp $b } readdir(DIR)) {
	next if ($f !~ /^(\S+)\.dump$/);
	push(@rv, &get_dump($1));
	}
closedir(DIR);
return @rv;
}

# get_dump(id)
sub get_dump
{
local %dump;
&read_file("$module_config_directory/$_[0].dump", \%dump) || return undef;
$dump{'id'} = $_[0];
return \%dump;
}

# save_dump(&dump)
sub save_dump
{
$_[0]->{'id'} = $$.time() if (!$_[0]->{'id'});
&lock_file("$module_config_directory/$_[0]->{'id'}.dump");
&write_file("$module_config_directory/$_[0]->{'id'}.dump", $_[0]);
&unlock_file("$module_config_directory/$_[0]->{'id'}.dump");
}

# delete_dump(&dump)
sub delete_dump
{
&lock_file("$module_config_directory/$_[0]->{'id'}.dump");
unlink("$module_config_directory/$_[0]->{'id'}.dump");
&unlock_file("$module_config_directory/$_[0]->{'id'}.dump");
}

# directory_filesystem(dir)
# Returns the filesystem type of some directory 
sub directory_filesystem
{
local $type;
foreach $m (sort { length($a->[0]) <=> length($b->[0]) }
	         &foreign_call("mount", "list_mounted")) {
	local $l = length($m->[0]);
	if ($m->[0] eq $_[0] || $m->[0] eq "/" ||
	    (length($_[0]) >= $l && substr($_[0], 0, $l+1) eq $m->[0]."/")) {
		$type = $m->[2];
		}
	}
return $type;
}

# date_subs(string)
sub date_subs
{
if ($config{'date_subs'}) {
	eval "use POSIX";
	eval "use posix" if ($@);
	local @tm = localtime(time());
	return strftime($_[0], @tm);
	}
else {
	return $_[0];
	}
}

# execute_before(&dump, handle, escape)
sub execute_before
{
if ($_[0]->{'before'}) {
	local $h = $_[1];
	open(before, "($_[0]->{'before'}) 2>&1 </dev/null |");
	while(<before>) {
		print $h $_[2] ? &html_escape($_) : $_;
		}
	close(before);
	}
}

# execute_after(&dump, handle, escape)
sub execute_after
{
if ($_[0]->{'after'}) {
	local $h = $_[1];
	open(after, "($_[0]->{'after'}) 2>&1 </dev/null |");
	while(<after>) {
		print $h $_[2] ? &html_escape($_) : $_;
		}
	close(after);
	}
}

# running_dumps(&procs)
# Returns a list of backup jobs currently in progress, and their statuses
sub running_dumps
{
local ($p, @rv, %got);
foreach $p (@{$_[0]}) {
	if ($p->{'args'} =~ /$cron_cmd\s+(\S+)/ ||
	    $p->{'args'} =~ /$module_root_directory\/backup.pl\s+(\S+)/) {
		local $backup = &get_dump($1);
		local $sfile = "$module_config_directory/$1.$p->{'pid'}.status";
		local %status;
		&read_file($sfile, \%status);
		$backup->{'status'} = \%status;
		$backup->{'pid'} = $p->{'pid'};
		push(@rv, $backup);
		$got{$sfile} = 1 if (!$status{'end'});
		}
	}
# Remove any left over .status files
opendir(DIR, $module_config_directory);
local $f;
foreach $f (readdir(DIR)) {
	local $path = "$module_config_directory/$f";
	unlink($path) if ($path =~ /\.status$/ && !$got{$path});
	}
closedir(DIR);
return @rv;
}

# can_edit_dir(dir)
# Returns 1 if some backup can be used or edited
sub can_edit_dir
{
return 1 if ($access{'dirs'} eq '*');
local ($d, $dd);
local @ddirs = !ref($_[0]) ? ( $_[0] ) :
	       $supports_multiple ? split(/\s+/, $_[0]->{'dir'}) :
				    ( $_[0]->{'dir'} );
foreach $dd (@ddirs) {
	local $anyok = 0;
	foreach $d (split(/\t+/, $access{'dirs'})) {
		$anyok = 1 if (&is_under_directory($d, $dd));
		}
	return 0 if (!$anyok);
	}
return 1;
}

sub create_wrappers
{
&foreign_require("cron", "cron-lib.pl");
&cron::create_wrapper($notape_cmd, $module_name, "notape.pl");
&cron::create_wrapper($newtape_cmd, $module_name, "newtape.pl");
&cron::create_wrapper($multi_cmd, $module_name, "multi.pl");
&cron::create_wrapper($rmulti_cmd, $module_name, "rmulti.pl");
}

# new_header(title)
sub new_header
{
print "</table></td></tr></table><br>\n";
print "<table border width=100%>\n";
print "<tr $tb> <td><b>$_[0]</b></td> </tr>\n";
print "<tr $cb> <td><table width=100%>\n";
}

# dump_directories(&dump)
sub dump_directories
{
if (!&multiple_directory_support($_[0]->{'fs'})) {
	return $_[0]->{'dir'};
	}
elsif ($_[0]->{'tabs'}) {
	return split(/\t+/, $_[0]->{'dir'});
	}
else {
	return split(/\s+/, $_[0]->{'dir'});
	}
}

1;

