";
# Local file field
$rv .= "| ".&ui_oneradio("$_[0]_mode", 0, undef, $mode == 0)." | \n";
$rv .= "$text{'backup_mode0'} | ".
&ui_textbox("$_[0]_file", $mode == 0 ? $path : "", 60, undef, undef,
($_[2] != 1 && $config{'date_subs'}) ?
'placeholder="/backups/configs-%y-%m-%d-%H-%M-%S.tar.gz"' : undef).
" ".&file_chooser_button("$_[0]_file")." |
\n";
# FTP file fields
$rv .= "| ".&ui_oneradio("$_[0]_mode", 1, undef, $mode == 1)." | \n";
$rv .= "$text{'backup_mode1'} | ".
&ui_textbox("$_[0]_server", $mode == 1 ? $server : undef, 20).
" | \n";
$rv .= " $text{'backup_path'} | ".
&ui_textbox("$_[0]_path", $mode == 1 ? $path : undef, 20).
" |
\n";
$rv .= " | \n";
$rv .= "$text{'backup_login'} | ".
&ui_textbox("$_[0]_user", $mode == 1 ? $user : undef, 20).
" | \n";
$rv .= " $text{'backup_pass'} | ".
&ui_password("$_[0]_pass", $mode == 1 ? $pass : undef, 20).
" |
\n";
$rv .= " | \n";
$rv .= "$text{'backup_port'} ".
&ui_opt_textbox("$_[0]_port", $mode == 1 ? $port : undef, 5,
$text{'default'})." |
\n";
# SCP file fields
$rv .= "| ".&ui_oneradio("$_[0]_mode", 2, undef, $mode == 2)." | \n";
$rv .= "$text{'backup_mode2'} | ".
&ui_textbox("$_[0]_sserver", $mode == 2 ? $server : undef, 20).
" | \n";
$rv .= " $text{'backup_path'} | ".
&ui_textbox("$_[0]_spath", $mode == 2 ? $path : undef, 20).
" |
\n";
$rv .= " | \n";
$rv .= "$text{'backup_login'} | ".
&ui_textbox("$_[0]_suser", $mode == 2 ? $user : undef, 20).
" | \n";
$rv .= " $text{'backup_pass'} | ".
&ui_password("$_[0]_spass", $mode == 2 ? $pass : undef, 20).
" |
\n";
$rv .= " | \n";
$rv .= "$text{'backup_port'} ".
&ui_opt_textbox("$_[0]_sport", $mode == 2 ? $port : undef, 5,
$text{'default'})." |
\n";
if ($_[2] == 1) {
# Uploaded file field
$rv .= "| ".&ui_oneradio("$_[0]_mode", 3, undef, $mode == 3).
" | \n";
$rv .= "$text{'backup_mode3'} ".
&ui_upload("$_[0]_upload", 40).
" |
\n";
}
elsif ($_[2] == 2) {
# Output to browser option
$rv .= "| ".&ui_oneradio("$_[0]_mode", 4, undef, $mode == 4).
" | \n";
$rv .= "$text{'backup_mode4'} |
\n";
}
$rv .= "
\n";
return $rv;
}
=head2 parse_backup_destination(name, &in)
Returns a backup destination string, or calls error.
=cut
sub parse_backup_destination
{
my %in = %{$_[1]};
my $mode = $in{"$_[0]_mode"} || 0;
if ($mode == 0) {
# Local file
$in{"$_[0]_file"} && $in{"$_[0]_file"} =~ /^\/\S/ ||
&error($text{'backup_edest'});
return $in{"$_[0]_file"};
}
elsif ($mode == 1) {
# FTP server
&to_ipaddress($in{"$_[0]_server"}) ||
&to_ip6address($in{"$_[0]_server"}) ||
&error($text{'backup_eserver1'});
$in{"$_[0]_path"} =~ /^\/\S/ || &error($text{'backup_epath'});
$in{"$_[0]_user"} =~ /^[^:]*$/ || &error($text{'backup_euser'});
$in{"$_[0]_pass"} =~ /^[^\@]*$/ || &error($text{'backup_epass'});
$in{"$_[0]_port_def"} || $in{"$_[0]_port"} =~ /^\d+$/ ||
&error($text{'backup_eport'});
return "ftp://".$in{"$_[0]_user"}.":".$in{"$_[0]_pass"}."\@".
$in{"$_[0]_server"}.
($in{"$_[0]_port_def"} ? "" : ":".$in{"$_[0]_port"}).
$in{"$_[0]_path"};
}
elsif ($mode == 2) {
# SSH server
&to_ipaddress($in{"$_[0]_sserver"}) ||
&to_ip6address($in{"$_[0]_sserver"}) ||
&error($text{'backup_eserver2'});
$in{"$_[0]_spath"} =~ /^\/\S/ || &error($text{'backup_epath2'});
$in{"$_[0]_suser"} =~ /^[^:]*$/ || &error($text{'backup_euser'});
$in{"$_[0]_spass"} =~ /^[^\@]*$/ || &error($text{'backup_epass'});
$in{"$_[0]_sport_def"} || $in{"$_[0]_sport"} =~ /^\d+$/ ||
&error($text{'backup_esport'});
return "ssh://".$in{"$_[0]_suser"}.":".$in{"$_[0]_spass"}."\@".
$in{"$_[0]_sserver"}.
($in{"$_[0]_sport_def"} ? "" : ":".$in{"$_[0]_sport"}).
$in{"$_[0]_spath"};
}
elsif ($mode == 3) {
# Uploaded file .. save as temp file?
$in{"$_[0]_upload"} || &error($text{'backup_eupload'});
return "upload:$_[0]_upload";
}
elsif ($mode == 4) {
return "download:";
}
}
=head2 execute_backup(&modules, dest, &size, &files, include-webmin, exclude-files, &others)
Backs up the configuration files for the modules to the selected destination.
The backup is simply a tar file of config files. Returns undef on success,
or an error message on failure.
=cut
sub execute_backup
{
# Work out modules we can use
my @mods;
foreach my $m (@{$_[0]}) {
my $mdir = &module_root_directory($m);
if ($m && &foreign_check($m) && -r "$mdir/backup_config.pl") {
push(@mods, $m);
}
}
# Work out where to write to
my ($mode, $user, $pass, $host, $path, $port) = &parse_backup_url($_[1]);
my $file;
if ($mode == 0) {
$file = &date_subs($path);
}
else {
my $ext = &has_command("gzip") ? '.tar.gz' : '.tar';
$file = &transname_timestamped("backup", $ext);
}
# Get module descriptions
my $m;
my %desc;
foreach $m (@mods) {
my %minfo = &get_module_info($m);
$desc{$m} = $minfo{'desc'};
}
my @files;
my %manifestfiles;
if (!$_[5]) {
# Build list of all files to save from modules
foreach my $m (@mods) {
&foreign_require($m, "backup_config.pl");
my @mfiles = &foreign_call($m, "backup_config_files");
foreach my $f (@mfiles) {
next if (!$f);
if (-d $f) {
# A directory .. recursively expand
foreach my $sf (&expand_directory($f)) {
next if (!$sf);
push(@files, $sf);
push(@{$manifestfiles{$m}}, $sf);
}
}
else {
# Just one file
push(@files, $f);
push(@{$manifestfiles{$m}}, $f);
}
}
}
}
# Add module config files and custom langs
if ($_[4]) {
foreach $m (@mods) {
my @cfiles = ( "$config_directory/$m/config" );
push(@cfiles, glob("$config_directory/$m/custom-lang*"));
push(@files, @cfiles);
push(@{$manifestfiles{$m}}, @cfiles);
}
}
# Add other files
foreach my $f (@{$_[6]}) {
next if (!$f);
if (-d $f) {
# A directory .. recursively expand
foreach my $sf (&expand_directory($f)) {
next if (!$sf);
push(@files, $sf);
push(@{$manifestfiles{"other"}}, $sf);
}
}
else {
# Just one file
push(@files, $f);
push(@{$manifestfiles{"other"}}, $f);
}
}
# Save the manifest files
&execute_command("rm -rf ".quotemeta($manifests_dir));
mkdir($manifests_dir, 0755);
my @manifests;
foreach $m (@mods, "_others") {
next if (!defined($manifestfiles{$m}));
my $man = "$manifests_dir/$m";
my $fh;
&open_tempfile($fh, ">$man");
&print_tempfile($fh, map { "$_\n" } @{$manifestfiles{$m}});
&close_tempfile($fh);
push(@manifests, $man);
}
# Make sure we have something to do
@files = grep { $_ && -e $_ } @files;
@files || (return $text{'backup_enone'});
if (!$_[5]) {
# Call all module pre functions
my $m;
foreach $m (@mods) {
if (&foreign_defined($m, "pre_backup")) {
my $err = &foreign_call($m, "pre_backup", \@files);
if ($err) {
return &text('backup_epre', $desc{$m}, $err);
}
}
}
}
# Make the tar (possibly .gz) file
my $filestemp = &transname();
my $fh;
&open_tempfile($fh, ">$filestemp");
foreach my $f (&unique(@files), @manifests) {
my $frel = $f;
$frel =~ s/^\///;
&print_tempfile($fh, $frel."\n");
}
&close_tempfile($fh);
my $qfile = quotemeta($file);
my $out;
if (&has_command("gzip")) {
&execute_command("cd / ; tar cfT - $filestemp | gzip -c >$qfile",
undef, \$out, \$out);
}
else {
&execute_command("cd / ; tar cfT $qfile $filestemp",
undef, \$out, \$out);
}
my $ex = $?;
&unlink_file($filestemp);
if ($ex) {
&unlink_file($file) if ($mode != 0);
return &text('backup_etar', "