2130 lines
57 KiB
Perl
2130 lines
57 KiB
Perl
package SrvMngr::Controller::Backup;
|
|
|
|
#----------------------------------------------------------------------
|
|
# heading : System
|
|
# description : Backup or restore
|
|
# navigation : 4000 200
|
|
# Copyright (C) 2002 Mitel Networks Corporation
|
|
#----------------------------------------------------------------------
|
|
# routes : end
|
|
|
|
# for information - routes
|
|
# $if_admin->get('/backup')->to('backup#main')->name('backup');
|
|
# $if_admin->post('/backup')->to('backup#do_display')->name('backupd');
|
|
# $if_admin->get('/backupd')->to('backup#do_display')->name('backupc');
|
|
# $if_admin->post('/backupd')->to('backup#do_update')->name('backupu');
|
|
|
|
use strict;
|
|
use warnings;
|
|
use Mojo::Base 'Mojolicious::Controller';
|
|
use utf8;
|
|
|
|
use Locale::gettext;
|
|
use SrvMngr::I18N;
|
|
use SrvMngr qw(theme_list init_session ip_number_or_blank);
|
|
|
|
use Quota;
|
|
use esmith::ConfigDB;
|
|
use esmith::AccountsDB;
|
|
|
|
use esmith::util;
|
|
use File::Basename;
|
|
use File::Find;
|
|
use File::Path qw(make_path remove_tree);
|
|
|
|
use esmith::Backup;
|
|
use esmith::BackupHistoryDB;
|
|
use esmith::util;
|
|
use esmith::lockfile;
|
|
|
|
use constant DEBUG => $ENV{MOJO_SMANAGER_DEBUG} || 0;
|
|
|
|
our $cdb = esmith::ConfigDB->open || die "Couldn't open config db";
|
|
our $adb = esmith::AccountsDB->open || die "Couldn't open accounts db";
|
|
our $rdb = esmith::ConfigDB->open('/etc/e-smith/restore')
|
|
|| die "Couldn't open restore db";
|
|
|
|
my $es_backup = new esmith::Backup or die "Couldn't create Backup object\n";
|
|
|
|
my @directories = $es_backup->restore_list;
|
|
@directories = grep { -e "/$_" } @directories;
|
|
|
|
my @backup_excludes = $es_backup->excludes;
|
|
|
|
# Unbuffer standard output so that files and directories are listed as
|
|
# they are restored
|
|
$| = 1;
|
|
|
|
# Store away current gid of 'www' group.
|
|
my $www_gid = getgrnam("www");
|
|
|
|
|
|
sub main {
|
|
|
|
my $c = shift;
|
|
$c->app->log->info($c->log_req);
|
|
|
|
my %bac_datas = ();
|
|
my $title = $c->l('bac_BACKUP_TITLE');
|
|
my $notif;
|
|
|
|
$bac_datas{'function'} = 'desktop_backup';
|
|
my ($tarsize, $dumpsize, undef, undef) = $c->CalculateSizes();
|
|
|
|
my $module = $cdb->get('backup');
|
|
if ($module) {
|
|
$module = $module->prop('Program');
|
|
}
|
|
|
|
# The default e-smith backup program is flexbackup.
|
|
unless (defined $module) {
|
|
$module = "flexbackup";
|
|
} elsif ($module eq '') {
|
|
$module = "flexbackup";
|
|
}
|
|
|
|
$bac_datas{'tarsize'} = $tarsize;
|
|
$bac_datas{'dumpsize'} = $dumpsize;
|
|
$bac_datas{'module'} = $module;
|
|
|
|
if ($tarsize =~ /Tb/ or $tarsize =~ /(\d+)Gb/ and $1 >= 2) {
|
|
$notif = $c->l("bac_BACKUP_DESKTOP_TOO_BIG").' : '.$tarsize;
|
|
}
|
|
|
|
my $rec = $cdb->get('backup');
|
|
my ($backup_status, $backupwk_status) = 'disabled';
|
|
|
|
if ($rec) {
|
|
$backup_status = $rec->prop('status') || 'disabled';
|
|
}
|
|
|
|
if ($backup_status eq "enabled") {
|
|
$bac_datas{'backupTime'} = $rec->prop('backupTime');
|
|
$bac_datas{'reminderTime'} = $rec->prop('reminderTime');
|
|
}
|
|
|
|
$rec = $cdb->get('backupwk');
|
|
if ($rec) {
|
|
$backupwk_status = $rec->prop('status') || 'disabled';
|
|
}
|
|
|
|
if ($backupwk_status eq "enabled") {
|
|
$bac_datas{'backupwkTime'} = $rec->prop('BackupTime');
|
|
}
|
|
|
|
$bac_datas{'backupStatus'} = $backup_status;
|
|
$bac_datas{'backupwkStatus'} = $backupwk_status;
|
|
|
|
$c->stash( warning => $notif ) if ( $notif );
|
|
$c->stash( title => $title, bac_datas => \%bac_datas );
|
|
$c->render(template => 'backup');
|
|
|
|
};
|
|
|
|
|
|
sub do_display {
|
|
|
|
my $c = shift;
|
|
$c->app->log->info($c->log_req);
|
|
|
|
my $rt = $c->current_route;
|
|
my ($res, $result) = '';
|
|
|
|
my $function = $c->param('Function');
|
|
|
|
if ($function =~ /^(\S+)$/) {
|
|
$function = $1;
|
|
} elsif ($function =~ /^\s*$/) {
|
|
$function = "zoverall";
|
|
} else {
|
|
$result = $c->l('bac_INVALID_FUNCTION') . $function;
|
|
$function = undef;
|
|
}
|
|
|
|
DEBUG && warn("do_display $function");
|
|
|
|
my %bac_datas = ();
|
|
$bac_datas{'function'} = $function;
|
|
|
|
my $title = $c->l('bac_BACKUP_TITLE');
|
|
my $dest = '';
|
|
|
|
|
|
if ( $function eq 'desktop_backup' ) {
|
|
|
|
my $CompressionLevel = $cdb->get_prop("backupconsole", "CompressionLevel") || "-6";
|
|
my @exclude = map (" --exclude=$_",@backup_excludes);
|
|
|
|
$c->stash( compressionlevel => $CompressionLevel, exclude => \@exclude, directories => \@directories );
|
|
|
|
# streaming download in template
|
|
return $c->render("/backdown");
|
|
}
|
|
|
|
|
|
if ( $function eq 'tape_configure' ) {
|
|
|
|
$bac_datas{'status'} = 'unchecked';
|
|
my $backupTime = "2:00";
|
|
|
|
my $rec = $cdb->get('backup');
|
|
if ($rec) {
|
|
$backupTime = $rec->prop('backupTime') || "2:00";
|
|
|
|
my $backup_status = $rec->prop('status');
|
|
if (defined $backup_status && $backup_status eq "enabled") {
|
|
$bac_datas{'status'} = "checked";
|
|
}
|
|
}
|
|
($bac_datas{backupAMPM}, $bac_datas{reminderAMPM}) = 'AM';
|
|
|
|
($bac_datas{backupHour}, $bac_datas{backupMin}) = split (":", $backupTime, -1);
|
|
if ($bac_datas{backupHour} > 11) {
|
|
if ($bac_datas{backupHour} > 12) {
|
|
$bac_datas{backupHour} -= 12;
|
|
}
|
|
$bac_datas{backupAMPM} = 'PM';
|
|
}
|
|
|
|
# Obtain time for reminder notice from the backup cron template
|
|
my $reminderTime = "14:00";
|
|
if ($rec) {
|
|
$reminderTime = $rec->prop('reminderTime') || "14:00";
|
|
}
|
|
|
|
($bac_datas{reminderHour}, $bac_datas{reminderMin}) = split (":", $reminderTime, -1);
|
|
if ($bac_datas{reminderHour} > 12) {
|
|
$bac_datas{reminderHour} -= 12;
|
|
$bac_datas{reminderAMPM} = 'PM';
|
|
}
|
|
}
|
|
|
|
|
|
if ( $function eq 'workstn_configure' ) {
|
|
|
|
my $rec = $cdb->get('backupwk');
|
|
$bac_datas{vfstype} = $rec->prop('VFSType') || 'cifs';
|
|
$bac_datas{status} = $rec->prop('status');
|
|
}
|
|
|
|
|
|
if ( $function eq 'workstn_configure1' ) {
|
|
|
|
$bac_datas{vfstype} = $c->param('VFSType');
|
|
$bac_datas{'status'} = '';
|
|
$bac_datas{ampm} = 'AM';
|
|
$bac_datas{min} = '';
|
|
$bac_datas{hour} = '';
|
|
$bac_datas{login} = 'backup';
|
|
$bac_datas{password} = 'backup';
|
|
$bac_datas{station} = 'host';
|
|
$bac_datas{folder} = 'share';
|
|
$bac_datas{mount} = '';
|
|
$bac_datas{setsNumber} = '';
|
|
$bac_datas{filesinset} = '';
|
|
$bac_datas{timeout} = '';
|
|
$bac_datas{incOnlyTimeout} = '';
|
|
$bac_datas{compression} = '';
|
|
$bac_datas{dof} = '';
|
|
|
|
# Obtain backup informations from configuration
|
|
my $rec = $cdb->get('backupwk');
|
|
my $Time = '2:00';
|
|
if ($rec) {
|
|
$Time = $rec->prop('BackupTime') || '2:00';
|
|
$bac_datas{login} = $rec->prop('Login') || 'backup';
|
|
$bac_datas{password} = $rec->prop('Password') || 'backup';
|
|
$bac_datas{station} = $rec->prop('SmbHost') || 'host';
|
|
$bac_datas{folder} = $rec->prop('SmbShare') || 'share';
|
|
$bac_datas{mount} = $rec->prop('Mount') || '';
|
|
$bac_datas{setsNumber} = $rec->prop('SetsMax') || '1';
|
|
$bac_datas{filesinset} = $rec->prop('DaysInSet') || '1';
|
|
$bac_datas{timeout} = $rec->prop('Timeout') || '12';
|
|
$bac_datas{incOnlyTimeout} = $rec->prop('IncOnlyTimeout') || 'yes';
|
|
$bac_datas{compression} = $rec->prop('Compression') || '0';
|
|
$bac_datas{dof} = (defined $rec->prop('FullDay')) ? $rec->prop('FullDay') : '7';
|
|
}
|
|
|
|
($bac_datas{hour}, $bac_datas{min}) = split (':', $Time, -1);
|
|
if ( $bac_datas{hour} > 12 ) {
|
|
$bac_datas{hour} -= 12;
|
|
$bac_datas{ampm} = 'PM';
|
|
}
|
|
|
|
my $backupwk_status;
|
|
if ($rec) {
|
|
$backupwk_status = $rec->prop('status');
|
|
}
|
|
|
|
if (defined $backupwk_status && $backupwk_status eq 'enabled') {
|
|
$bac_datas{status} = 'checked';
|
|
}
|
|
|
|
if (defined $bac_datas{incOnlyTimeout} && $bac_datas{incOnlyTimeout} eq 'yes') {
|
|
$bac_datas{incOnlyTimeout} = 'checked';
|
|
}
|
|
}
|
|
|
|
|
|
if ( $function eq 'workstn_verify' ) {
|
|
|
|
my $rec = $cdb->get('backupwk');
|
|
if ( $rec) {
|
|
$bac_datas{status} = $rec->prop('status') || 'disabled';
|
|
}
|
|
}
|
|
|
|
|
|
if ( $function eq 'workstn_verify1' ) {
|
|
|
|
$res = '';
|
|
if ( ! $result ) {
|
|
$bac_datas{function} = $function;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
if ( $function eq 'workstn_restore' ) {
|
|
|
|
my $rec = $cdb->get('backupwk');
|
|
if ( $rec) {
|
|
$bac_datas{status} = $rec->prop('status') || 'disabled';
|
|
}
|
|
}
|
|
|
|
|
|
$dest = "back_$function";
|
|
|
|
$c->stash( error => $result );
|
|
|
|
$c->stash( title => $title, bac_datas => \%bac_datas );
|
|
return $c->render( template => $dest );
|
|
|
|
};
|
|
|
|
|
|
sub do_update {
|
|
|
|
my $c = shift;
|
|
$c->app->log->info($c->log_req);
|
|
|
|
my $rt = $c->current_route;
|
|
my $function = $c->param('Function');
|
|
|
|
DEBUG && warn("do_update $function");
|
|
|
|
my %bac_datas = ();
|
|
|
|
$bac_datas{function} = $function;
|
|
my $title = $c->l('bac_BACKUP_TITLE');
|
|
my ($dest, $res, $result) = '';
|
|
|
|
|
|
if ( $function eq 'desktop_backup' ) {
|
|
# should not happen !! no desktop_backup template !!
|
|
$result .= ' ** Function error for desktop backup ** !';
|
|
}
|
|
|
|
|
|
if ( $function eq 'tape_configure' ) {
|
|
|
|
my $status = $c->param('Tapebackup');
|
|
my $backupHour = $c->param('BackupHour');
|
|
my $backupMin = $c->param('BackupMin');
|
|
my $bampm = $c->param('BackupAMPM');
|
|
my $reminderHour = $c->param('ReminderHour');
|
|
my $reminderMin = $c->param('ReminderMin');
|
|
my $rampm = $c->param('ReminderAMPM');
|
|
|
|
if (defined $status && $status eq "on") {
|
|
|
|
if ($backupHour =~ /^(.*)$/) {
|
|
$backupHour = $1;
|
|
} else {
|
|
$backupHour = "12";
|
|
}
|
|
if (($backupHour < 1) || ($backupHour > 12)) {
|
|
$result .= $c->l('bac_ERR_INVALID_HOUR').$backupHour.
|
|
' '.$c->l('bac_BETWEEN_0_AND_12').' ';
|
|
}
|
|
|
|
if ($backupMin =~ /^(.*)$/) {
|
|
$backupMin = $1;
|
|
} else {
|
|
$backupMin = "0";
|
|
}
|
|
if (($backupMin < 0) || ($backupMin > 59)) {
|
|
$result .= $c->l('bac_ERR_INVALID_MINUTE').$backupMin.
|
|
' '.$c->l('bac_BETWEEN_0_AND_59').' ';
|
|
}
|
|
|
|
if ($reminderHour =~ /^(.*)$/) {
|
|
$reminderHour = $1;
|
|
} else {
|
|
$reminderHour = "12";
|
|
}
|
|
if (($reminderHour < 1) || ($reminderHour > 12)) {
|
|
$result .= $c->l('bac_ERR_INVALID_REMINDER_HOUR').$reminderHour.
|
|
' '.$c->l('bac_BETWEEN_0_AND_12').' ';
|
|
}
|
|
|
|
if ($reminderMin =~ /^(.*)$/) {
|
|
$reminderMin = $1;
|
|
} else {
|
|
$reminderMin = "0";
|
|
}
|
|
if (($reminderMin < 0) || ($reminderMin > 59)) {
|
|
$result .= $c->l('bac_ERR_INVALID_REMINDER_MINUTE').$reminderMin.
|
|
' '.$c->l('bac_BETWEEN_0_AND_59').' ';
|
|
}
|
|
} else {
|
|
# service disabled no controls
|
|
}
|
|
|
|
##$result .= ' ** Blocked for testing ** !';
|
|
|
|
$res = '';
|
|
if ( ! $result ) {
|
|
$res = $c->tapeBackupConfig($status, $backupHour,
|
|
$backupMin, $bampm, $reminderHour, $reminderMin, $rampm);
|
|
|
|
$result .= $res unless $res eq 'OK';
|
|
if ( ! $result ) {
|
|
if (defined $status && $status eq "on") {
|
|
$result .= ($c->l('bac_SUCCESSFULLY_ENABLED_TAPE').' '.
|
|
$c->l('bac_WITH_BACKUP_TIME')."$backupHour:$backupMin".' '.
|
|
$c->l('bac_WITH_REMINDER_TIME')."$reminderHour:$reminderMin");
|
|
} else {
|
|
$result .= $c->l('bac_SUCCESSFULLY_DISABLED');
|
|
}
|
|
$cdb->reload;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
if ( $function eq 'tape_restore' ) {
|
|
|
|
my $lock_file = "/var/lock/subsys/e-smith-restore";
|
|
my $file_handle = &esmith::lockfile::LockFileOrReturn($lock_file);
|
|
|
|
unless ($file_handle) {
|
|
$result .= $c->l('bac_UNABLE_TO_RESTORE_CONF').' '.
|
|
$c->l('bac_ANOTHER_RESTORE_IN_PROGRESS');
|
|
}
|
|
|
|
##$result .= ' ** Blocked for testing ** !';
|
|
|
|
$res = '';
|
|
if ( ! $result ) {
|
|
$res = $c->tapeRestore( $lock_file, $file_handle );
|
|
$result .= $res unless $res eq 'OK';
|
|
#if ( ! $result ) {
|
|
#$result = $c->l('bac_SUCCESS');
|
|
#}
|
|
}
|
|
}
|
|
|
|
|
|
if ( $function eq 'workstn_configure' ) {
|
|
|
|
# should not happen !!
|
|
$result .= ' ** Function error for workstation configure *** !';
|
|
}
|
|
|
|
|
|
if ( $function eq 'workstn_configure1' ) {
|
|
|
|
#$result .= ' ** Blocked for testing ** !';
|
|
|
|
$res = '';
|
|
if ( ! $result ) {
|
|
$res = $c->updateWorkstnBackupConfig();
|
|
if ( ($result = $res) =~ s|^#OK#|| ) {
|
|
$res = 'OK';
|
|
$cdb->reload;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
if ( $function eq 'workstn_verify' ) {
|
|
|
|
# should not happen !!
|
|
$result .= ' ** Function error for workstation verify *** !';
|
|
}
|
|
|
|
|
|
if ( $function eq 'workstn_verify1' ) {
|
|
|
|
##$result .= ' ** Blocked for testing ** !';
|
|
|
|
$res = 'OK';
|
|
$result = '';
|
|
}
|
|
|
|
|
|
if ( $function eq 'workstn_restore' ) {
|
|
|
|
##$result .= ' ** Blocked for testing ** !';
|
|
|
|
$res = 'NOK';
|
|
if ( ! $result ) {
|
|
$res = $c->workstnRestore();
|
|
if ( ($result = $res) =~ s|^#OK#|| ) {
|
|
$bac_datas{restore_log} = $result;
|
|
$res = 'OK';
|
|
} else {
|
|
$c->stash( error => $result );
|
|
}
|
|
$bac_datas{function} = 'workstn_restore1';
|
|
$res = 'NEXT';
|
|
}
|
|
}
|
|
|
|
|
|
if ( $function eq 'workstn_restore1' ) {
|
|
|
|
my $state = 'unknown';
|
|
my $rec = $rdb->get('restore');
|
|
if ($rec) {
|
|
$state = $rec->prop('state') || 'unknown';
|
|
}
|
|
|
|
$result .= "Restore state unexpected: $state" if ($state ne 'complete');
|
|
|
|
$res = 'NOK';
|
|
if ( ! $result ) {
|
|
$res = $c->performReboot();
|
|
if ( ($result = $res) =~ s|^#OK#|| ) {
|
|
$res = 'OK';
|
|
} else {
|
|
$c->stash( error => $result );
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
if ( $function eq 'workstn_sel_restore' ) {
|
|
|
|
my $backupset = $c->param('Backupset');
|
|
my $filterexp = $c->param('Filterexp');
|
|
if ($filterexp =~ /^(.*)$/) {
|
|
$filterexp = $1;
|
|
} else {
|
|
$filterexp = '';
|
|
}
|
|
|
|
#$result .= ' ** Blocked for testing 1 ** !';
|
|
|
|
$res = '';
|
|
if ( ! $result ) {
|
|
$bac_datas{function} = 'workstn_sel_restore1';
|
|
$bac_datas{backupset} = $backupset;
|
|
$bac_datas{filterexp} = $filterexp;
|
|
$res = 'NEXT';
|
|
}
|
|
}
|
|
|
|
|
|
if ( $function eq 'workstn_sel_restore1' ) {
|
|
|
|
$bac_datas{backupset} = $c->param('Backupset');
|
|
$bac_datas{filterexp} = $c->param('Filterexp');
|
|
|
|
my @restorefiles = @{$c->every_param('Restorefiles')};
|
|
|
|
my $seldatebefore = $c->param('Seldatebefore');
|
|
if ($seldatebefore =~ /^(.*)$/) {
|
|
$seldatebefore = $1;
|
|
} else {
|
|
$result .= 'Unsecure data : ' . $seldatebefore;
|
|
}
|
|
|
|
my $tymd =
|
|
qr/((19|20)\d\d\/(?=\d\d\/\d\d-))?((0?[1-9]|1[0-2])\/(?=\d\d-))?((31|[123]0|[012]?[1-9])-)?/;
|
|
my $thms =
|
|
qr/([01]?[0-9]|2[0-3]):([0-5][0-9])(:[0-5][0-9])?/;
|
|
|
|
$result .= " $seldatebefore : " . $c->l('bac_ERR_INVALID_SELDATE')
|
|
unless (($seldatebefore =~ m/^$tymd$thms$/) || ($seldatebefore eq ""));
|
|
|
|
##$result .= ' ** Blocked for testing 2 ** !';
|
|
|
|
$res = '';
|
|
if ( ! $result ) {
|
|
$res = $c->performWorkstnSelRestore( $seldatebefore, \@restorefiles ); # restore log returned
|
|
if ( ($result = $res) =~ s|^#OK#|| ) {
|
|
$bac_datas{restore_log} = $result;
|
|
$res = 'OK';
|
|
} else {
|
|
$c->stash( error => $result );
|
|
}
|
|
$bac_datas{function} = 'workstn_sel_restore2';
|
|
$res = 'NEXT';
|
|
}
|
|
}
|
|
|
|
|
|
if ( $function eq 'workstn_sel_restore2' ) {
|
|
|
|
##$result .= ' ** Blocked for testing 3 ** !';
|
|
|
|
$res = 'OK';
|
|
$result = '';
|
|
}
|
|
|
|
|
|
# common part for all functions
|
|
if ($res ne 'OK') {
|
|
if ($res eq 'NEXT') {
|
|
$dest = 'back_' . $bac_datas{"function"};
|
|
} else {
|
|
$c->stash( error => $result );
|
|
$dest = "back_$function";
|
|
}
|
|
$c->stash( title => $title, bac_datas => \%bac_datas );
|
|
return $c->render($dest);
|
|
}
|
|
|
|
|
|
my $message = "'Backup' $function updates DONE";
|
|
$c->app->log->info($message);
|
|
$c->flash(success => $result);
|
|
|
|
$c->redirect_to('backup');
|
|
|
|
};
|
|
|
|
|
|
sub tapeBackupConfig {
|
|
|
|
my ($c, $status, $backupHour, $backupMin, $bampm,
|
|
$reminderHour, $reminderMin, $rampm) = @_;
|
|
|
|
if (defined $status && $status eq "on") {
|
|
|
|
$backupMin = sprintf("%02d", $backupMin);
|
|
|
|
if ($bampm =~ /^(.*)$/) {
|
|
$bampm = $1;
|
|
} else {
|
|
$bampm = "AM";
|
|
}
|
|
# convert to 24 hour time
|
|
$backupHour = $backupHour % 12;
|
|
if ($bampm eq "PM") {
|
|
$backupHour = $backupHour + 12;
|
|
}
|
|
|
|
$reminderMin = sprintf("%02d", $reminderMin);
|
|
|
|
if ($rampm =~ /^(.*)$/) {
|
|
$rampm = $1;
|
|
} else {
|
|
$rampm = "AM";
|
|
}
|
|
# convert to 24 hour time
|
|
$reminderHour = $reminderHour % 12;
|
|
if ($rampm eq "PM") {
|
|
$reminderHour = $reminderHour + 12;
|
|
}
|
|
|
|
# variables passed validity checks, set configuration database values
|
|
my $oldUnsav = $cdb->get('UnsavedChanges')->value;
|
|
|
|
my $rec = $cdb->get('backup');
|
|
unless (defined $rec) {
|
|
$rec = $cdb->new_record('backup', {type=>'service'});
|
|
}
|
|
|
|
$rec->set_prop('status', 'enabled');
|
|
|
|
my $module = $rec->prop('Program');
|
|
|
|
# The default e-smith backup program is flexbackup.
|
|
|
|
unless (defined $module) {
|
|
$module = "flexbackup";
|
|
} elsif ($module eq '') {
|
|
$module = "flexbackup";
|
|
}
|
|
|
|
$rec->set_prop('Program', $module);
|
|
$rec->set_prop('backupTime', "$backupHour:$backupMin");
|
|
$rec->set_prop('reminderTime', "$reminderHour:$reminderMin");
|
|
|
|
$cdb->get('UnsavedChanges')->set_value($oldUnsav);
|
|
|
|
system("/sbin/e-smith/signal-event", "conf-backup") == 0
|
|
or return ($c->l('bac_ERR_CONF_BACKUP'),"\n");
|
|
|
|
return 'OK';
|
|
} else {
|
|
# set service to disabled
|
|
my $oldUnsav = $cdb->get('UnsavedChanges')->value;
|
|
|
|
my $rec = $cdb->get('backup');
|
|
unless ($rec) {
|
|
$rec = $cdb->new_record('backup', {type=>'service'});
|
|
}
|
|
|
|
$rec->set_prop('status', 'disabled');
|
|
$cdb->get('UnsavedChanges')->set_value($oldUnsav);
|
|
|
|
system("/sbin/e-smith/signal-event", "conf-backup") == 0
|
|
or return ($c->l('bac_ERR_CONF_BACKUP')."\n");
|
|
|
|
return 'OK';
|
|
}
|
|
return undef;
|
|
}
|
|
|
|
|
|
sub tapeRestore {
|
|
|
|
my ($c, $lock_file, $file_handle) = @_;
|
|
|
|
my $rec = $rdb->get('restore');
|
|
$rec->set_prop('state', 'running');
|
|
$rec->set_prop('start', time);
|
|
|
|
my $child;
|
|
|
|
if ($child = fork) {
|
|
# Parent
|
|
$SIG{'CHLD'} = 'IGNORE';
|
|
&esmith::lockfile::UnlockFile($file_handle);
|
|
return 'OK';
|
|
} elsif (defined $child) {
|
|
# Child
|
|
# Re-establish the lock. Wait till it is relinquished by the parent.
|
|
|
|
$file_handle = &esmith::lockfile::LockFileOrWait($lock_file);
|
|
|
|
# Close STDOUT so that the web server connection is closed.
|
|
close STDOUT;
|
|
|
|
# Now reopen STDOUT for the child. Redirect it to STDERR.
|
|
open(STDOUT, ">&STDERR");
|
|
|
|
unless(system("/sbin/e-smith/signal-event", "pre-restore") == 0) {
|
|
$rec->set_prop('errmsg', $c->l('bac_ERR_PRE_RESTORE'));
|
|
$rec->delete_prop('state');
|
|
die ($c->l('bac_ERR_PRE_RESTORE'),"\n");
|
|
}
|
|
|
|
unless(system("/sbin/e-smith/signal-event", "restore-tape") == 0) {
|
|
$rec->set_prop('errmsg', $c->l('bac_ERR_RESTORING_FROM_TAPE'));
|
|
$rec->delete_prop('state');
|
|
die ($c->l('bac_ERR_RESTORING_FROM_TAPE')."\n");
|
|
}
|
|
|
|
#----------------------------------------
|
|
# regenerate configuration files
|
|
#----------------------------------------
|
|
unless(system("/usr/sbin/groupmod", "-g", "$www_gid", "www") == 0) {
|
|
$rec->set_prop('errmsg', $rec->prop('errmsg').', '.
|
|
$c->l('bac_ERR_RESTORING_GID'));
|
|
warn ($c->l('bac_ERR_RESTORING_GID')."\n");
|
|
}
|
|
unless(system("/usr/sbin/usermod", "-g", "$www_gid", "www") == 0) {
|
|
$rec->set_prop('errmsg', $rec->prop('errmsg').', '.
|
|
$c->l('bac_ERR_RESTORING_INITIAL_GRP'));
|
|
warn ($c->l('bac_ERR_RESTORING_INITIAL_GRP')."\n");
|
|
}
|
|
esmith::util::backgroundCommand(0,
|
|
"/sbin/e-smith/signal-event", "post-upgrade");
|
|
#unless(system("/sbin/e-smith/signal-event", "post-upgrade") == 0) {
|
|
# $rec->set_prop('errmsg', $rec->prop('errmsg').', '.
|
|
# $c->l('bac_ERR_UPDATING_CONF_AFTER_TAPE_RESTORE'));
|
|
# $rec->delete_prop('state');
|
|
# die ($c->l('bac_ERR_UPDATING_CONF_AFTER_TAPE_RESTORE'));
|
|
#}
|
|
|
|
my $finish = time;
|
|
$rec->set_prop('state', 'complete');
|
|
$rec->set_prop('finish', $finish);
|
|
|
|
my $start = $rec->prop('start');
|
|
$start = scalar localtime($start);
|
|
$finish = scalar localtime($finish);
|
|
|
|
&esmith::lockfile::UnlockFile($file_handle);
|
|
|
|
exit;
|
|
} else {
|
|
# Error
|
|
$rec->delete_prop('state');
|
|
$rec->set_prop('errmsg', $c->l('bac_COULD_NOT_FORK'));
|
|
die ($c->l("bac_COULD_NOT_FORK")." $!\n");
|
|
}
|
|
}
|
|
|
|
|
|
sub workstnBackupConfig {
|
|
|
|
# called by template
|
|
my ($c) = @_;
|
|
my $out;
|
|
|
|
my $backupwk_status;
|
|
my $enabledIncOnlyTimeout = "";
|
|
my $backupwkLogin = 'backup';
|
|
my $backupwkPassword = 'backup';
|
|
my $backupwkStation = 'host';
|
|
my $backupwkFolder = 'share';
|
|
my $backupwkMount = '/mnt/smb';
|
|
my $setsNumber;
|
|
my $filesinset;
|
|
my $backupwkTime;
|
|
my $backupwkTimeout;
|
|
my $backupwkIncOnlyTimeout;
|
|
my $VFSType;
|
|
my $compression;
|
|
my $dof;
|
|
my @dlabels = split(' ', $c->l('bac_DOW'));
|
|
|
|
# Obtain backup informations from configuration
|
|
my $rec = $cdb->get('backupwk');
|
|
if ($rec) {
|
|
$backupwkTime = $rec->prop('BackupTime') || '2:00';
|
|
$backupwkLogin = $rec->prop('Login') || 'backup';
|
|
$backupwkPassword = $rec->prop('Password') || 'backup';
|
|
$backupwkStation = $rec->prop('SmbHost') || 'host';
|
|
$backupwkFolder = $rec->prop('SmbShare') || 'share';
|
|
$backupwkMount = $rec->prop('Mount') || '/mnt/smb';
|
|
$VFSType = $rec->prop('VFSType') || 'cifs';
|
|
$setsNumber = $rec->prop('SetsMax') || '1';
|
|
$filesinset = $rec->prop('DaysInSet') || '1';
|
|
$backupwkTimeout = $rec->prop('Timeout') || '12';
|
|
$backupwkIncOnlyTimeout = $rec->prop('IncOnlyTimeout') || 'yes';
|
|
$compression = $rec->prop('Compression') || '0';
|
|
$dof = (defined $rec->prop('FullDay')) ? $rec->prop('FullDay') : '7';
|
|
$backupwk_status = $rec->prop('status');
|
|
}
|
|
|
|
if ($rec) {
|
|
if ($VFSType eq 'usb') {
|
|
$out .= $c->l('bac_WORKSTN_BACKUP_USB').' '.$backupwkFolder.'<br/>';
|
|
} elsif ($VFSType eq 'mnt') {
|
|
$out .= $c->l('bac_WORKSTN_BACKUP_MNT').' '.$backupwkMount.'<br/>';
|
|
} else {
|
|
$out .= $c->l('bac_WORKSTN_BACKUP_HOST').' '.$backupwkStation.' ';
|
|
$out .= $c->l('bac_WORKSTN_BACKUP_VFSTYPE').' '.$VFSType.'<br/>';
|
|
$out .= $c->l('bac_WORKSTN_BACKUP_SHARE').' '.$backupwkFolder.'<br/>';
|
|
}
|
|
if ($VFSType eq 'cifs') {
|
|
$out .= $c->l('bac_LOGIN').' '.$backupwkLogin.'<br/>';
|
|
$out .= $c->l('PASSWORD').' ********<br/>';
|
|
}
|
|
$out .= $c->l('bac_WORKSTN_BACKUP_SETSNUM').' '.$setsNumber.'<br/>';
|
|
$out .= $c->l('bac_WORKSTN_BACKUP_DAYSINSET').' '.$filesinset.'<br/>';
|
|
$out .= $c->l('bac_WORKSTN_BACKUP_COMPRESSION').' '.$compression.'<br/>';
|
|
$out .= $c->l('bac_WORKSTN_BACKUP_TOD').' '.$backupwkTime.'<br/>';
|
|
$out .= $c->l('bac_WORKSTN_BACKUP_TIMEOUT').' '.$backupwkTimeout.' '.$c->l('bac_HOURS');
|
|
|
|
if ( $backupwkIncOnlyTimeout eq 'yes' ) {
|
|
$out .= $c->l('bac_WORKSTN_BACKUP_INCONLY_TIMEOUT')
|
|
}
|
|
$out .= '<br/>';
|
|
|
|
if ( $dof eq '7' ) {
|
|
$out .= $c->l('bac_WORKSTN_FULL_BACKUP_EVERYDAY').'<br/>';
|
|
} else {
|
|
$out .= $c->l('bac_WORKSTN_FULL_BACKUP_DAY').' '.$dlabels[$dof].'<br/>';
|
|
}
|
|
} else {
|
|
$out = $c->l('bac_WORKSTN_BACKUP_NOT_CONFIGURED');
|
|
}
|
|
return $out;
|
|
}
|
|
|
|
|
|
sub workstnVerify {
|
|
|
|
my ($c) = @_;
|
|
my $out;
|
|
|
|
my $backupwkrec = $cdb->get('backupwk');
|
|
my $smbhost = $backupwkrec->prop('SmbHost');
|
|
my $smbshare = $backupwkrec->prop('SmbShare');
|
|
my $mntdir = $backupwkrec->prop('Mount') || '/mnt/smb';
|
|
my $key;
|
|
my $error_message;
|
|
my $id = $backupwkrec->prop('Id') ||
|
|
$cdb->get('SystemName')->value .'.'. $cdb->get('DomainName')->value;
|
|
my $err;
|
|
my $VFSType = $backupwkrec->prop('VFSType') || 'cifs';
|
|
my $verifyref = $c->param ('Backupset');
|
|
$mntdir = "/$smbshare" if ( $VFSType eq 'usb' );
|
|
|
|
# Mounting backup shared folder
|
|
$error_message = $c->bmount($mntdir,$smbhost,$smbshare,$VFSType);
|
|
if ($error_message) {
|
|
return $error_message .' '. $id;
|
|
}
|
|
|
|
# Test if backup subdirectory for our server
|
|
my $mntbkdir = $mntdir . "/$id";
|
|
unless (-d $mntbkdir) {
|
|
$error_message = $c->l('bac_ERR_NO_HOST_DIR')."\n";
|
|
$error_message .= $c->bunmount($mntdir,$VFSType);
|
|
return $error_message .' '. $id;
|
|
}
|
|
|
|
my $fullverify = $c->param('Verifyall') || '';
|
|
|
|
if ( $fullverify eq "on" ) {
|
|
# Test all backups needed to full restore
|
|
my %backupsetfiles = ();
|
|
my @restorefiles;
|
|
my $set = $verifyref;
|
|
$set =~ s/\/[^\/]*$//;
|
|
my $backupsetlist = sub {
|
|
if ( $_ =~ /\.dar/ ) {
|
|
my $backupref = $File::Find::name;
|
|
$backupref =~ s/\.[0-9]+\.dar//;
|
|
$_ =~ s/\..*\.dar//;
|
|
$_ =~ s/.*-//;
|
|
$backupsetfiles{$_} = $backupref;
|
|
}
|
|
};
|
|
# find list of available backups and verify
|
|
# it contains all backups needed for full restore
|
|
|
|
find { wanted => \&$backupsetlist, untaint => 1, untaint_pattern => qr|^([-+@\w\s./]+)$| }, $set ;
|
|
|
|
my $key;
|
|
my $num = 0;
|
|
foreach $key (sort keys %backupsetfiles)
|
|
{
|
|
push @restorefiles, $backupsetfiles{$key};
|
|
if ( $num == 0 ) {
|
|
unless ( $backupsetfiles{$key} =~ /\/full-/ ) {
|
|
$out .= $c->l('bac_ERR_NO_FULL_BACKUP');
|
|
return $out;
|
|
}
|
|
} else {
|
|
my $numf = sprintf("%03d", $num);
|
|
unless ( $backupsetfiles{$key} =~ /\/inc-$numf-/ ) {
|
|
$out .= $c->l('bac_ERR_NO_INC_BACKUP') . " " . $numf;
|
|
return $out;
|
|
}
|
|
}
|
|
$num++;
|
|
last if ( $backupsetfiles{$key} eq $verifyref );
|
|
}
|
|
|
|
if (open(RD, "-|")) {
|
|
|
|
$out .= '<b>'.$c->l('bac_TESTING_NEEDED_BACKUPS_FOR_RESTORE').'</b><UL>';
|
|
while (<RD>) {
|
|
$out .= "<li>$_</li>";
|
|
}
|
|
$out .= '</UL>';
|
|
|
|
my $message;
|
|
$out .= '<b>';
|
|
if (!close RD) {
|
|
$out .= $c->l('bac_RESTORE_VERIFY_FAILED');
|
|
} else {
|
|
$out .= $c->l('bac_VERIFY_COMPLETE');
|
|
}
|
|
$out .= '</b>';
|
|
} else {
|
|
select(STDOUT);
|
|
$| = 1;
|
|
|
|
my $file;
|
|
foreach $file (@restorefiles) {
|
|
if ($file =~ /^(.*)$/) {
|
|
$file = $1;
|
|
} else {
|
|
$error_message = "Unsecure data : $file\n";
|
|
$error_message .= $c->bunmount($mntdir,$VFSType);
|
|
die ($error_message);
|
|
}
|
|
print $c->l('bac_TESTED_BACKUP') .' '. $file;
|
|
system ("/usr/bin/dar", "-Q", "--test", "$file", "--noconf");
|
|
}
|
|
|
|
$error_message = $c->bunmount($mntdir,$VFSType);
|
|
die($error_message) if $error_message;
|
|
|
|
exit(0);
|
|
}
|
|
#return;
|
|
|
|
} else {
|
|
|
|
# verify selected backup only
|
|
# and display files saved in the backup
|
|
|
|
my $backupkey = $verifyref;
|
|
if ($backupkey =~ /^(.*)$/) {
|
|
$backupkey = $1;
|
|
} else {
|
|
$error_message = "Unsecure data : $backupkey\n";
|
|
$error_message .= $c->bunmount($mntdir,$VFSType);
|
|
die ($error_message);
|
|
}
|
|
|
|
if (open(RD, "-|")) {
|
|
$out .= '<b>'.$c->l('bac_FILES_IN_BACKUP').'</b><UL>';
|
|
my $complete = 0;
|
|
while (<RD>) {
|
|
$complete++ if /etc\/samba\/smbpasswd$/;
|
|
$out .= "<li>$_</li>";
|
|
}
|
|
$out .= '</UL>';
|
|
|
|
my $status = close RD ?
|
|
($complete ?
|
|
$c->l('bac_VERIFY_COMPLETE') :
|
|
$c->l('bac_BACKUP_FILE_INCOMPLETE'))
|
|
: ($c->l('bac_ERROR_READING_FILE').' : '.$backupkey);
|
|
$out .= "<b> $status </b>";
|
|
} else {
|
|
select(STDOUT);
|
|
$| = 1;
|
|
|
|
system ("/usr/bin/dar", "-Q", "--list", "$backupkey", "--noconf") == 0
|
|
or die ($c->l('bac_ERR_EXTRACT')." : ".$!);
|
|
|
|
$error_message = $c->bunmount($mntdir,$VFSType);
|
|
die($error_message) if $error_message;
|
|
exit(0);
|
|
}
|
|
}
|
|
$error_message .= $c->bunmount($mntdir,$VFSType);
|
|
return $out;
|
|
}
|
|
|
|
|
|
sub workstnRestore {
|
|
|
|
my ($c) = @_;
|
|
|
|
my $out;
|
|
my $restoreref = $c->param('Backupset');
|
|
my $set = $restoreref;
|
|
$set =~ s/\/[^\/]*$//;
|
|
my %backupsetfiles = ();
|
|
my @restorefiles;
|
|
|
|
my $backupsetlist = sub {
|
|
if ( $_ =~ /\.dar/ ) {
|
|
my $backupref = $File::Find::name;
|
|
$backupref =~ s/\.[0-9]+\.dar//;
|
|
$_ =~ s/\..*\.dar//;
|
|
$_ =~ s/.*-//;
|
|
$backupsetfiles{$_} = $backupref;
|
|
}
|
|
};
|
|
|
|
my $lock_file = "/var/lock/subsys/e-smith-restore";
|
|
my $file_handle = &esmith::lockfile::LockFileOrReturn($lock_file);
|
|
|
|
unless ($file_handle) {
|
|
return "$c->l('bac_RESTORE_CANNOT_PROCEED') <br> ($c->l('bac_ANOTHER_RESTORE_IN_PROGRESS')";
|
|
}
|
|
|
|
my $backupwkrec = $cdb->get('backupwk');
|
|
my $id = $backupwkrec->prop('Id')
|
|
|| $cdb->get('SystemName')->value . "." . $cdb->get('DomainName')->value;
|
|
my $mntdir = $backupwkrec->prop('Mount') || '/mnt/smb';
|
|
my $VFSType = $backupwkrec->prop('VFSType') || 'cifs';
|
|
my $smbhost = $backupwkrec->prop('SmbHost');
|
|
my $smbshare = $backupwkrec->prop('SmbShare');
|
|
$mntdir = "/$smbshare" if ( $VFSType eq 'usb' );
|
|
my $err;
|
|
my $error_message;
|
|
|
|
# Mounting backup shared folder
|
|
$error_message = $c->bmount($mntdir,$smbhost,$smbshare,$VFSType);
|
|
if ($error_message) {
|
|
return "$c->l('bac_RESTORE_CANNOT_PROCEED') $error_message : $id";
|
|
}
|
|
# Test if backup subdirectory for our server
|
|
my $mntbkdir = $mntdir . "/$id";
|
|
unless (-d $mntbkdir) {
|
|
$error_message = $c->l('bac_ERR_NO_HOST_DIR')."\n";
|
|
$error_message .= $c->bunmount($mntdir,$VFSType);
|
|
return "$c->l('bac_RESTORE_CANNOT_PROCEED') $error_message : $id";
|
|
}
|
|
# finding list of available backups
|
|
# and verifying all needed backup files are available
|
|
|
|
find { wanted => \&$backupsetlist, untaint => 1, untaint_pattern => qr|^([-+@\w\s./]+)$| }, $set ;
|
|
|
|
my $key;
|
|
my $num = 0;
|
|
foreach $key (sort keys %backupsetfiles) {
|
|
push @restorefiles, $backupsetfiles{$key};
|
|
if ( $num == 0 ) {
|
|
unless ( $backupsetfiles{$key} =~ /\/full-/ ) {
|
|
return "$c->l('bac_RESTORE_CANNOT_PROCEED') $c->l('bac_ERR_NO_FULL_BACKUP')";
|
|
}
|
|
} else {
|
|
my $numf = sprintf("%03d", $num);
|
|
unless ( $backupsetfiles{$key} =~ /\/inc-$numf-/ ) {
|
|
return "$c->l('bac_RESTORE_CANNOT_PROCEED') $c->l('bac_ERR_NO_INC_BACKUP') . $numf";
|
|
}
|
|
}
|
|
$num++;
|
|
last if ( $backupsetfiles{$key} eq $restoreref );
|
|
}
|
|
# backup is online, restoring now
|
|
|
|
my $rec = $rdb->get('restore');
|
|
$rec->set_prop('state','running');
|
|
$rec->set_prop('start', time);
|
|
$cdb->get('bootstrap-console')->set_prop('Run', 'yes');
|
|
|
|
unless (system("/sbin/e-smith/signal-event", "pre-restore") == 0) {
|
|
return "$c->l('bac_OPERATION_STATUS_REPORT') $c->l('bac_ERR_PRE_RESTORE')";
|
|
}
|
|
|
|
$| = 1;
|
|
if (open(RD, "-|")) {
|
|
|
|
#-----------------------------------------------------
|
|
# restore system from uploaded workstation backup file
|
|
#-----------------------------------------------------
|
|
$out .= $c->l('bac_FILES_HAVE_BEEN_RESTORED')."\n";
|
|
$out .= '<UL>';
|
|
my $complete = 0;
|
|
while (<RD>) {
|
|
$complete++ if /etc\/samba\/smbpasswd$/;
|
|
$out .= "<li>$_</li>\n";
|
|
}
|
|
$out .= '</UL>';
|
|
my $message;
|
|
|
|
if (!close RD) {
|
|
$message = $c->l('bac_RESTORE_FAILED_MSG');
|
|
} else {
|
|
#-----------------------------------------------------
|
|
# if restore completed, regenerate configuration files
|
|
#-----------------------------------------------------
|
|
|
|
if ($complete) {
|
|
$out .= $c->l('bac_RESTORE_COMPLETE');
|
|
system("/usr/sbin/groupmod", "-g", "$www_gid", "www") == 0
|
|
or warn ($c->l('bac_ERR_RESTORING_GID')."\n");
|
|
system("/usr/sbin/usermod", "-g", "$www_gid", "www") == 0
|
|
or warn ($c->l('bac_ERR_RESTORING_INITIAL_GRP')."\n");
|
|
esmith::util::backgroundCommand(0,
|
|
"/sbin/e-smith/signal-event", "post-upgrade");
|
|
# system("/sbin/e-smith/signal-event", "post-upgrade") == 0
|
|
# or die ($c->l('bac_ERROR_UPDATING_CONFIGURATION')."\n");
|
|
} else {
|
|
$message = $c->l('bac_RESTORE_FAILED');
|
|
}
|
|
}
|
|
return $message if $message;
|
|
|
|
$rec->set_prop('state', 'complete');
|
|
$rec->set_prop('finish', time);
|
|
|
|
&esmith::lockfile::UnlockFile($file_handle);
|
|
|
|
} else {
|
|
|
|
select(STDOUT);
|
|
$| = 1;
|
|
|
|
my $file;
|
|
foreach $file (@restorefiles) {
|
|
if ($file =~ /^(.*)$/) {
|
|
$file = $1;
|
|
} else {
|
|
$error_message = "Unsecure data : $file\n";
|
|
$error_message .= $c->bunmount($mntdir,$VFSType);
|
|
die ($error_message);
|
|
}
|
|
system ("/usr/bin/dar", "-Q", "-x", "$file", "-v", "-N", "-R", "/", "-wa");
|
|
}
|
|
$error_message = $c->bunmount($mntdir,$VFSType);
|
|
die($error_message) if $error_message;
|
|
exit(0);
|
|
}
|
|
|
|
$rdb->reload;
|
|
|
|
$error_message .= $c->bunmount($mntdir,$VFSType);
|
|
return '#OK#' . $out;
|
|
}
|
|
|
|
|
|
sub workstnSelRestore() {
|
|
|
|
my $c = shift;
|
|
|
|
my $rec = $cdb->get('backupwk');
|
|
|
|
my %backupfiles = ();
|
|
my $mntdir = $rec->prop('Mount') || '/mnt/smb';
|
|
my $mntbkdir;
|
|
my $key;
|
|
my $id = $rec->prop('Id') ||
|
|
$cdb->get('SystemName')->value . '.' . $cdb->get('DomainName')->value;
|
|
my %blabels = ();
|
|
my @blabels;
|
|
my $backups = 0;
|
|
my $filterexp;
|
|
my $VFSType = $rec->prop('VFSType') || 'cifs';
|
|
my $smbhost = $rec->prop('SmbHost');
|
|
my $smbshare = $rec->prop('SmbShare');
|
|
$mntdir = "/$smbshare" if ( $VFSType eq 'usb' );
|
|
my $err;
|
|
my $error_message;
|
|
|
|
my $setbackuplist = sub {
|
|
if ( $_ =~ /\.dar/ )
|
|
{
|
|
my $dir = $File::Find::dir;
|
|
my $backupref;
|
|
$dir =~ s/$mntbkdir\///;
|
|
$_ =~ s/\..*\.dar//;
|
|
$backupref = $_;
|
|
$_ =~ s/.*-//;
|
|
@{$backupfiles{$_}}[0] = $dir;
|
|
@{$backupfiles{$_}}[1] = $backupref;
|
|
}
|
|
};
|
|
|
|
# Mounting backup shared folder
|
|
$error_message = $c->bmount($mntdir,$smbhost,$smbshare,$VFSType);
|
|
if ($error_message) {
|
|
return ($error_message, $id);
|
|
}
|
|
|
|
# Test if backup subdirectory for our server
|
|
$mntbkdir = $mntdir . "/$id";
|
|
unless (-d $mntbkdir) {
|
|
$error_message = $c->l('bac_ERR_NO_HOST_DIR')."\n";
|
|
$error_message .= $c->bunmount($mntdir,$VFSType);
|
|
return ($error_message, $id);
|
|
}
|
|
|
|
my $catalog = "$mntbkdir/dar-catalog";
|
|
my $i = 0;
|
|
my $j = 0;
|
|
my @bknum;
|
|
my @setd;
|
|
my @bkname;
|
|
|
|
|
|
# update backups list from current catalog
|
|
|
|
open(DAR_LIST, "/usr/bin/dar_manager -B $catalog -l |") ;
|
|
|
|
$i = 0;
|
|
while (<DAR_LIST>)
|
|
{
|
|
next unless m/set/;
|
|
chomp;
|
|
($bknum[$i], $setd[$i], $bkname[$i]) = split(' ', $_, 3);
|
|
$i++;
|
|
}
|
|
close (DAR_LIST);
|
|
|
|
# set drop down list of backups
|
|
push @blabels, "0";
|
|
$blabels{"0"} = $c->l('ALL_BACKUPS');
|
|
$j = 0;
|
|
while ($j < $i)
|
|
{
|
|
push @blabels, $bknum[$j];
|
|
$blabels{$bknum[$j]} = $bkname[$j];
|
|
$j++
|
|
}
|
|
|
|
}
|
|
|
|
|
|
sub updateWorkstnBackupConfig {
|
|
|
|
my ($c) = @_;
|
|
|
|
my $status = $c->param('Workstnbackup') || "";
|
|
my $inconly = $c->param('IncOnlyTimeout');
|
|
my $dof = $c->param('Dof');
|
|
my $ampm;
|
|
my $incOnlyTimeout;
|
|
|
|
my $rec = $cdb->get('backupwk');
|
|
unless (defined $rec) {
|
|
$rec = $cdb->new_record('backupwk', {type=>'service'});
|
|
}
|
|
my $backupwkMount = $rec->prop('Mount') || '/mnt/smb';
|
|
|
|
unless ( $status eq 'on') {
|
|
# set service to disabled
|
|
my $old = $cdb->get('UnsavedChanges')->value;
|
|
|
|
$rec->set_prop('status', 'disabled');
|
|
$cdb->get('UnsavedChanges')->set_value($old);
|
|
|
|
system("/sbin/e-smith/signal-event", "conf-backup") == 0
|
|
or die($c->l('bac_ERR_CONF_BACKUP')."\n");
|
|
|
|
return '#OK#'.$c->l('bac_SUCCESSFULLY_DISABLED_WORKSTN');
|
|
}
|
|
|
|
#--------------------------------------------------
|
|
# Untaint parameters and check for validity
|
|
#--------------------------------------------------
|
|
|
|
my $VFSType = $c->param('VFSType');
|
|
if ( $VFSType eq 'nousb') {
|
|
return $c->l('bac_ERR_NO_USB_DISK')
|
|
}
|
|
if ( $VFSType eq 'nomnt') {
|
|
return $c->l('bac_ERR_NO_MOUNTED_DISK')
|
|
}
|
|
|
|
my $backupwkStation = $c->param('BackupwkStation');
|
|
if ( $VFSType =~ m/usb|mnt/s) { $backupwkStation = 'localhost' }
|
|
if ($backupwkStation =~ /^\s*(\S+)\s*$/) {
|
|
$backupwkStation = $1;
|
|
} else {
|
|
$backupwkStation = "";
|
|
}
|
|
if ( $backupwkStation eq "" ) {
|
|
return $c->l('bac_ERR_INVALID_WORKSTN')
|
|
}
|
|
|
|
my $backupwkFolder = $c->param('BackupwkFolder');
|
|
if ($backupwkFolder =~ /^(.*)$/) {
|
|
$backupwkFolder = $1;
|
|
} else {
|
|
$backupwkFolder = '';
|
|
}
|
|
if ( $VFSType eq 'usb' ) {
|
|
$backupwkFolder = 'media/' . $backupwkFolder;
|
|
}
|
|
if ( $VFSType eq 'mnt' ) {
|
|
$backupwkMount = $backupwkFolder;
|
|
if (checkMount ($backupwkMount)){$backupwkFolder = '';}
|
|
} else {
|
|
$backupwkFolder =~ s/^\///; # remove leading /
|
|
}
|
|
if ( $backupwkFolder eq '') {
|
|
return $c->l('bac_ERR_INVALID_FOLDER')
|
|
}
|
|
|
|
my $backupwkLogin = $c->param('BackupwkLogin') || '';
|
|
if ($backupwkLogin =~ /^(.*)$/) {
|
|
$backupwkLogin = $1;
|
|
} else {
|
|
$backupwkLogin = "";
|
|
}
|
|
if ( ( $backupwkLogin eq "" ) && ( $VFSType eq 'cifs' ) ) {
|
|
return $c->l('bac_ERR_INVALID_LOGIN')
|
|
}
|
|
|
|
my $backupwkPassword = $c->param('BackupwkPassword') || '';
|
|
if ($backupwkPassword =~ /^(.*)$/) {
|
|
$backupwkPassword = $1;
|
|
} else {
|
|
$backupwkPassword = "";
|
|
}
|
|
if ( ( $backupwkPassword eq "" ) && ( $VFSType eq 'cifs' ) ) {
|
|
return $c->l('bac_ERR_INVALID_PASSWORD')
|
|
}
|
|
|
|
my $setsNumber = $c->param('SetsNumber');
|
|
unless ( $setsNumber > 0 ) {
|
|
return $c->l('bac_ERR_INVALID_SETS_NUMBERFOLDER')
|
|
}
|
|
|
|
my $filesinset = $c->param('Filesinset');
|
|
unless ( $filesinset > 0 ) {
|
|
return $c->l('bac_ERR_INVALID_FILES_IN_SET_NUMBER')
|
|
}
|
|
|
|
my $timeout = $c->param('BackupwkTimeout');
|
|
if (( $timeout eq '') || ( $timeout == 0 )) {$timeout = 24 }
|
|
if (( $timeout < 1 ) || ( $timeout > 24 )) {
|
|
return $c->l('bac_ERR_INVALID_TIMEOUT')
|
|
}
|
|
|
|
if (defined $inconly && $inconly eq 'on') {
|
|
$incOnlyTimeout = 'yes';
|
|
} else {
|
|
$incOnlyTimeout = 'no';
|
|
}
|
|
|
|
my $compression = $c->param('Compression');
|
|
if (( $compression < 0 ) || ( $compression > 9 )) {
|
|
return $c->l('bac_ERR_INVALID_COMPRESSION')
|
|
}
|
|
|
|
$rec->set_prop('SmbHost', $backupwkStation);
|
|
$rec->set_prop('SmbShare', $backupwkFolder);
|
|
$rec->set_prop('Mount', $backupwkMount);
|
|
$rec->set_prop('Login', $backupwkLogin);
|
|
$rec->set_prop('Password', $backupwkPassword);
|
|
$rec->set_prop('SetsMax', $setsNumber);
|
|
$rec->set_prop('DaysInSet', $filesinset);
|
|
$rec->set_prop('Timeout', $timeout);
|
|
$rec->set_prop('IncOnlyTimeout', $incOnlyTimeout);
|
|
$rec->set_prop('Compression', $compression);
|
|
$rec->set_prop('FullDay', $dof);
|
|
$rec->set_prop('VFSType', $VFSType);
|
|
|
|
my $module = $rec->prop('Program');
|
|
|
|
# The default workstation backup program is dar.
|
|
|
|
unless (defined $module) {
|
|
$module = 'dar';
|
|
} elsif ($module eq '') {
|
|
$module = 'dar';
|
|
}
|
|
|
|
$rec->set_prop('Program', $module);
|
|
|
|
my $backupwkHour = $c->param('BackupwkHour');
|
|
if ($backupwkHour =~ /^(.*)$/) {
|
|
$backupwkHour = $1;
|
|
} else {
|
|
$backupwkHour = '12';
|
|
}
|
|
if (($backupwkHour < 0) || ($backupwkHour > 12)) {
|
|
return $c->l('bac_ERR_INVALID_HOUR').$backupwkHour.
|
|
$c->l('bac_BETWEEN_0_AND_12')
|
|
}
|
|
|
|
my $backupwkMin = $c->param('BackupwkMin');
|
|
if ($backupwkMin =~ /^(.*)$/) {
|
|
$backupwkMin = $1;
|
|
} else {
|
|
$backupwkMin = '0';
|
|
}
|
|
if (($backupwkMin < 0) || ($backupwkMin > 59)) {
|
|
return $c->l('bac_ERR_INVALID_MINUTE').$backupwkMin.
|
|
$c->l('bac_BETWEEN_0_AND_59');
|
|
}
|
|
|
|
$backupwkMin = sprintf("%02d", $backupwkMin);
|
|
|
|
$ampm = $c->param('BackupwkAMPM');
|
|
if ($ampm =~ /^(.*)$/) {
|
|
$ampm = $1;
|
|
} else {
|
|
$ampm = 'AM';
|
|
}
|
|
|
|
# convert to 24 hour time
|
|
$backupwkHour = $backupwkHour % 12;
|
|
if ($ampm eq 'PM') {
|
|
$backupwkHour = $backupwkHour + 12;
|
|
}
|
|
|
|
# variables passed validity checks, set configuration database values
|
|
my $old = $cdb->get('UnsavedChanges')->value;
|
|
$rec->set_prop('status', 'enabled');
|
|
$rec->set_prop('BackupTime', "$backupwkHour:$backupwkMin");
|
|
$cdb->get('UnsavedChanges')->set_value($old);
|
|
|
|
system("/sbin/e-smith/signal-event", "conf-backup") == 0
|
|
or die($c->l('bac_ERR_CONF_BACKUP'),"\n");
|
|
|
|
# we test if the remote host is reachable, else we simply display a warning
|
|
if ( $VFSType =~ m/cifs|nfs/s ) {
|
|
my $error_message = vmount($backupwkStation,$backupwkFolder,$backupwkMount,$VFSType);
|
|
if (! $error_message) {
|
|
$c->bunmount($backupwkMount,$VFSType);
|
|
} elsif ($error_message) {
|
|
return $c->l('bac_ERROR_WHEN_TESTING_REMOTE_SERVER'). "<br>$error_message";
|
|
}
|
|
}
|
|
|
|
return '#OK#'.$c->l('bac_SUCCESSFULLY_ENABLED_WORKSTN'). '<br>'.
|
|
$c->l('bac_WITH_BACKUP_TIME')." $backupwkHour:$backupwkMin";
|
|
}
|
|
|
|
|
|
sub performWorkstnSelRestore {
|
|
|
|
my ($c, $seldatebefore, $restorefiles) = @_;
|
|
|
|
my $out;
|
|
my @restorelist;
|
|
|
|
foreach ( @{$restorefiles} ) {
|
|
push @restorelist, "\"".$1."\"" if ($_ =~ /^(.*)$/);
|
|
}
|
|
|
|
my $backupwkrec = $cdb->get('backupwk');
|
|
my $id = $backupwkrec->prop('Id') ||
|
|
$cdb->get('SystemName')->value . "." . $cdb->get('DomainName')->value;
|
|
my $mntdir = $backupwkrec->prop('Mount') || '/mnt/smb';
|
|
my $VFSType = $backupwkrec->prop('VFSType') || 'cifs';
|
|
my $smbhost = $backupwkrec->prop('SmbHost');
|
|
my $smbshare = $backupwkrec->prop('SmbShare');
|
|
my $err;
|
|
my $error_message;
|
|
$mntdir = "/$smbshare" if ( $VFSType eq 'usb' );
|
|
|
|
# Mounting backup shared folder
|
|
$error_message = $c->bmount($mntdir,$smbhost,$smbshare,$VFSType);
|
|
if ($error_message) {
|
|
$error_message .= " : $id";
|
|
return $error_message;
|
|
}
|
|
|
|
# Test if backup subdirectory for our server
|
|
my $mntbkdir = $mntdir . "/$id";
|
|
unless (-d $mntbkdir) {
|
|
$error_message = $c->l('bac_ERR_NO_HOST_DIR')."\n";
|
|
$error_message .= $c->bunmount($mntdir,$VFSType);
|
|
$error_message .= " : $id";
|
|
return $error_message;
|
|
}
|
|
|
|
# backup is online, restoring now
|
|
$| = 1;
|
|
my $restorerr;
|
|
|
|
if (open(RD, "-|")) {
|
|
#-----------------------------------------------------
|
|
# restore system from uploaded workstation backup file
|
|
#-----------------------------------------------------
|
|
$out .= "<b>". $c->l('bac_FILES_HAVE_BEEN_RESTORED') ."</b> \n";
|
|
$out .= '<UL>';
|
|
while (<RD>) {
|
|
$out .= "<li>$_</li>\n";
|
|
}
|
|
$out .= '</UL>';
|
|
my $message;
|
|
if (!close RD) {
|
|
$message = $c->l('bac_RESTORE_FAILED_MSG');
|
|
} else {
|
|
if ($restorerr) {
|
|
$message = $c->l('bac_RESTORE_FAILED');
|
|
} else {
|
|
$message = $c->l('bac_RESTORE_COMPLETE');
|
|
}
|
|
}
|
|
$out .= "<b>$message </b>\n";
|
|
} else {
|
|
select(STDOUT);
|
|
$| = 1;
|
|
if ($seldatebefore) {
|
|
$restorerr = system("/usr/bin/dar_manager -B \"$mntbkdir/dar-catalog\" -Q -w $seldatebefore -e '-v -N -R / -w' -r @restorelist");
|
|
} else {
|
|
$restorerr = system("/usr/bin/dar_manager -B \"$mntbkdir/dar-catalog\" -Q -k -e '-v -N -R / -w' -r @restorelist");
|
|
}
|
|
$error_message = $c->bunmount($mntdir,$VFSType);
|
|
die($error_message) if $error_message;
|
|
exit(0);
|
|
}
|
|
return "#OK#" . $out;
|
|
}
|
|
|
|
|
|
sub performReboot {
|
|
|
|
my ($c) = @_;
|
|
|
|
#print "$c->l('bac_SERVER_REBOOT')";
|
|
#print "$c->l('bac_SERVER_WILL_REBOOT')";
|
|
|
|
esmith::util::backgroundCommand( 2, "/sbin/e-smith/signal-event", "reboot" );
|
|
return "#OK#" . $c->l('bac_SERVER_WILL_REBOOT');
|
|
}
|
|
|
|
|
|
sub get_VFSType_options {
|
|
|
|
my $c = shift;
|
|
return [[ $c->l('cifs') => 'cifs' ], [ $c->l('nfs') => 'nfs' ],
|
|
[ $c->l('local removable disk') => 'usb' ], [ $c->l('Mounted disk') => 'mnt' ]];
|
|
}
|
|
|
|
|
|
sub get_dow_list {
|
|
|
|
my $c = shift;
|
|
|
|
my @list = ();
|
|
my @dlabels = split(' ', $c->l('bac_DOW'));
|
|
|
|
my $i = 0;
|
|
foreach (@dlabels) {
|
|
push @list, [ "$_" => "$i" ];
|
|
$i++;
|
|
}
|
|
|
|
# put 'everyday' first
|
|
my $lastr = pop @list;
|
|
unshift @list, $lastr;
|
|
|
|
return \@list;
|
|
}
|
|
|
|
|
|
sub get_BackupwkDest_options {
|
|
|
|
my ($c, $VFSType) = @_;
|
|
my @usbdisks = ();
|
|
|
|
if ( $VFSType eq 'usb' ) {
|
|
foreach my $udi (qx(hal-find-by-property --key volume.fsusage --string filesystem)) {
|
|
$udi =~ m/^(\S+)/;
|
|
|
|
my $is_mounted = qx(hal-get-property --udi $1 --key volume.is_mounted);
|
|
|
|
if ($is_mounted eq "false\n") {
|
|
my $vollbl = qx(hal-get-property --udi $1 --key volume.label);
|
|
$vollbl =~ m/^(\S+)/;
|
|
if ($vollbl =~ /^\s/) {$vollbl = 'nolabel';}
|
|
chomp $vollbl;
|
|
push @usbdisks, $vollbl;
|
|
}
|
|
}
|
|
# return undef unless ($usbdisks[0]);
|
|
}
|
|
|
|
if ( $VFSType eq 'mnt' ) {
|
|
@usbdisks = findmnt ();
|
|
# return undef unless ($usbdisks[0]);
|
|
}
|
|
return \@usbdisks
|
|
}
|
|
|
|
|
|
sub get_function_options {
|
|
|
|
my $c = shift;
|
|
|
|
return [[ $c->l('bac_DESKTOP_BACKUP') => 'desktop_backup' ],
|
|
[ $c->l('bac_TAPE_CONFIGURE') => 'tape_configure' ],
|
|
[ $c->l('bac_TAPE_RESTORE') => 'tape_restore' ],
|
|
[ $c->l('bac_WORKSTN_CONFIGURE') => 'workstn_configure' ],
|
|
[ $c->l('bac_WORKSTN_VERIFY') => 'workstn_verify' ],
|
|
[ $c->l('bac_WORKSTN_RESTORE') => 'workstn_restore' ],
|
|
[ $c->l('bac_WORKSTN_SEL_RESTORE') => 'workstn_sel_restore']];
|
|
|
|
}
|
|
|
|
|
|
sub get_shared_folder_to_verify () {
|
|
|
|
my ($c) = @_;
|
|
|
|
my $rec = $cdb->get('backupwk');
|
|
return undef unless $rec;
|
|
|
|
my $id = $rec->prop('Id') || $cdb->get('SystemName')->value . "." . $cdb->get('DomainName')->value;
|
|
my $smbhost = $rec->prop('SmbHost');
|
|
my $smbshare = $rec->prop('SmbShare');
|
|
|
|
return "$smbhost/$smbshare/$id";
|
|
}
|
|
|
|
|
|
sub get_Backupset_options () {
|
|
|
|
my ($c) = @_;
|
|
|
|
my $rec = $cdb->get('backupwk');
|
|
return undef unless $rec;
|
|
|
|
my %backupfiles = ();
|
|
my $mntdir = $rec->prop('Mount') || '/mnt/smb';
|
|
my $id = $rec->prop('Id') || $cdb->get('SystemName')->value . "." . $cdb->get('DomainName')->value;
|
|
my $smbhost = $rec->prop('SmbHost');
|
|
my $smbshare = $rec->prop('SmbShare');
|
|
my $mntbkdir;
|
|
my $key;
|
|
my $VFSType = $rec->prop('VFSType') || 'cifs';
|
|
my $err;
|
|
$mntdir = "/$smbshare" if ( $VFSType eq 'usb' );
|
|
|
|
my $setbackuplist = sub {
|
|
if ( $_ =~ /\.dar/ ) {
|
|
my $dir = $File::Find::dir;
|
|
my $backupref;
|
|
$dir =~ s/$mntbkdir\///;
|
|
$_ =~ s/\..*\.dar//;
|
|
$backupref = $_;
|
|
$_ =~ s/.*-//;
|
|
@{$backupfiles{$_}}[0] = $dir;
|
|
@{$backupfiles{$_}}[1] = $backupref;
|
|
}
|
|
};
|
|
|
|
|
|
# Mounting backup shared folder
|
|
my $error_message = $c->bmount($mntdir,$smbhost,$smbshare,$VFSType);
|
|
return [] if $error_message;
|
|
|
|
# Test if backup subdirectory for our server
|
|
$mntbkdir = $mntdir . "/$id";
|
|
unless (-d $mntbkdir) {
|
|
$error_message .= $c->bunmount($mntdir,$VFSType);
|
|
return [];
|
|
}
|
|
|
|
# Finding existing backups
|
|
find { wanted => \&$setbackuplist, untaint => 1, untaint_pattern => qr|^([-+@\w\s./]+)$|}, $mntbkdir ;
|
|
|
|
my %blabels = ();
|
|
my @list;
|
|
|
|
foreach $key (sort keys %backupfiles) {
|
|
my $labkey = $mntbkdir . '/' . $backupfiles{$key}[0] . '/' . $backupfiles{$key}[1];
|
|
$blabels{$labkey} = $backupfiles{$key}[1] . " (" . $backupfiles{$key}[0] . ")";
|
|
push @list, [ "$blabels{$labkey}" => "$labkey" ];
|
|
}
|
|
|
|
$error_message .= $c->bunmount($mntdir,$VFSType);
|
|
return \@list;
|
|
}
|
|
|
|
|
|
sub get_Restoreset_options () {
|
|
|
|
my ($c) = @_;
|
|
|
|
my $rec = $cdb->get('backupwk');
|
|
return [] unless $rec;
|
|
|
|
my %backupfiles = ();
|
|
my $mntdir = $rec->prop('Mount') || '/mnt/smb';
|
|
my $id = $rec->prop('Id') || $cdb->get('SystemName')->value . "." . $cdb->get('DomainName')->value;
|
|
my $smbhost = $rec->prop('SmbHost');
|
|
my $smbshare = $rec->prop('SmbShare');
|
|
my $mntbkdir;
|
|
my $key;
|
|
my $VFSType = $rec->prop('VFSType') || 'cifs';
|
|
my $err;
|
|
$mntdir = "/$smbshare" if ( $VFSType eq 'usb' );
|
|
|
|
my $setbackuplist = sub {
|
|
if ( $_ =~ /\.dar/ ) {
|
|
my $dir = $File::Find::dir;
|
|
my $backupref;
|
|
$dir =~ s/$mntbkdir\///;
|
|
$_ =~ s/\..*\.dar//;
|
|
$backupref = $_;
|
|
$_ =~ s/.*-//;
|
|
@{$backupfiles{$_}}[0] = $dir;
|
|
@{$backupfiles{$_}}[1] = $backupref;
|
|
}
|
|
};
|
|
|
|
# Mounting backup shared folder
|
|
my $error_message = $c->bmount($mntdir,$smbhost,$smbshare,$VFSType);
|
|
return [] if $error_message;
|
|
|
|
# Test if backup subdirectory for our server
|
|
$mntbkdir = $mntdir . "/$id";
|
|
unless (-d $mntbkdir) {
|
|
$error_message .= $c->bunmount($mntdir,$VFSType);
|
|
return [];
|
|
}
|
|
|
|
my $catalog = "$mntbkdir/dar-catalog";
|
|
my $i = 0; my $j = 0;
|
|
my @bknum; my @setd; my @bkname;
|
|
|
|
# update backups list from current catalog
|
|
open(DAR_LIST, "/usr/bin/dar_manager -B $catalog -l |") ;
|
|
$i = 0;
|
|
while (<DAR_LIST>) {
|
|
next unless m/set/;
|
|
chomp;
|
|
($bknum[$i], $setd[$i], $bkname[$i]) = split(' ', $_, 3);
|
|
$i++;
|
|
}
|
|
close (DAR_LIST);
|
|
|
|
my @list;
|
|
|
|
# set drop down list of backups
|
|
push @list, [ $c->l('bac_ALL_BACKUPS') => "0" ];
|
|
$j = 0;
|
|
while ($j < $i) {
|
|
push @list, [ $bkname[$j] => "$bknum[$j]" ];
|
|
$j++
|
|
}
|
|
|
|
$error_message .= $c->bunmount($mntdir,$VFSType);
|
|
return \@list;
|
|
}
|
|
|
|
|
|
sub get_Restorefiles_options {
|
|
|
|
my ($c, $filterexp, $backupkey) = @_;
|
|
|
|
my $rgfilter;
|
|
if ($filterexp =~ /^(.*)$/) {
|
|
$filterexp = $1;
|
|
$rgfilter = qr/$filterexp/;
|
|
} else {
|
|
$filterexp = "";
|
|
}
|
|
if ($backupkey =~ /^(.*)$/) {
|
|
$backupkey = $1;
|
|
} else {
|
|
die('Unsecure data : ' . $backupkey);
|
|
}
|
|
my $seldatebf;
|
|
|
|
my $backupwkrec = $cdb->get('backupwk');
|
|
my $smbhost = $backupwkrec->prop('SmbHost');
|
|
my $smbshare = $backupwkrec->prop('SmbShare');
|
|
my $mntdir = $backupwkrec->prop('Mount') || '/mnt/smb';
|
|
my $key;
|
|
my $id = $backupwkrec->prop('Id') ||
|
|
$cdb->get('SystemName')->value . "." . $cdb->get('DomainName')->value;
|
|
my @flabels;
|
|
my %flabels = ();
|
|
my $VFSType = $backupwkrec->prop('VFSType') || 'cifs';
|
|
my $err;
|
|
my $error_message;
|
|
$mntdir = "/$smbshare" if ( $VFSType eq 'usb' );
|
|
|
|
# Mounting backup shared folder
|
|
$error_message = $c->bmount($mntdir,$smbhost,$smbshare,$VFSType);
|
|
if ($error_message) {
|
|
warn "Backup - restore files: $error_message, $id \n";
|
|
return undef;
|
|
}
|
|
|
|
# Test if backup subdirectory for our server
|
|
my $mntbkdir = $mntdir . "/$id";
|
|
unless (-d $mntbkdir) {
|
|
$error_message = $c->l('bac_ERR_NO_HOST_DIR')."\n";
|
|
$error_message .= $c->bunmount($mntdir,$VFSType);
|
|
warn "Backup - restore files: $error_message, $id \n";
|
|
return undef;
|
|
}
|
|
|
|
# Read wanted file list from selected backup
|
|
if (open(RD, "-|")) {
|
|
my $regex = qr/\[.*\] */;
|
|
while (<RD>) {
|
|
chomp;
|
|
$_ =~ s/$regex//;
|
|
if ($filterexp) {next unless m/$rgfilter/};
|
|
push @flabels, $_;
|
|
}
|
|
my $status = close RD ?
|
|
$c->l('bac_READ_COMPLETE')
|
|
: ($c->l('bac_ERROR_READING_FILE').' : '.$backupkey);
|
|
} else {
|
|
select(STDOUT);
|
|
$| = 1;
|
|
|
|
system("/usr/bin/dar_manager", "-B", "$mntbkdir/dar-catalog", "-u", "$backupkey") == 0
|
|
or die ($c->l('bac_ERR_EXTRACT')." : ".$!);
|
|
|
|
$error_message = $c->bunmount($mntdir,$VFSType);
|
|
die($error_message) if $error_message;
|
|
exit(0);
|
|
}
|
|
|
|
$error_message .= $c->bunmount($mntdir,$VFSType);
|
|
return \@flabels;
|
|
}
|
|
|
|
|
|
sub CalculateSizes () {
|
|
|
|
my $c = shift;
|
|
|
|
#------------------------------------------------------------
|
|
# figure out the size of the tar file.
|
|
#------------------------------------------------------------
|
|
|
|
my $tarsize = 0;
|
|
|
|
# It takes way too much time to do a du on /home/e-smith. So we'll
|
|
# estimate the current size.
|
|
# We do this by checking the quota used by each user on the system.
|
|
|
|
# Get a $dev value appropriate for use in Quota::query call.
|
|
my $dev = Quota::getqcarg("/home/e-smith/files");
|
|
|
|
foreach my $user ($adb->users())
|
|
{
|
|
my $name = $user->key;
|
|
my $uid = getpwnam($name);
|
|
unless ($uid)
|
|
{
|
|
warn ($c->l('bac_NO_UID_FOR_NAME').$name."\n");
|
|
# We shouldn't ever get here. If we do, we can't get
|
|
# the quota value for this user, so we just skip to
|
|
# the next one.
|
|
next;
|
|
}
|
|
|
|
# Get current quota settings.
|
|
my ($blocks) = Quota::query($dev, $uid, 0);
|
|
$tarsize += $blocks;
|
|
}
|
|
|
|
# We add to this the size of root owned firectories, estimated using du.
|
|
# If this takes too long, then the admin only has his or
|
|
# herself to blame!
|
|
|
|
# Remove /home/e-smith from backup list, and make paths absolute
|
|
my @list = map { "/$_" } grep { !/home\/e-smith/ } @directories;
|
|
open(DU, "-|")
|
|
or exec '/usr/bin/du', '-s', @list;
|
|
|
|
while (<DU>) {
|
|
my ($du) = split(/\s+/);
|
|
$tarsize += $du;
|
|
}
|
|
close DU;
|
|
|
|
$tarsize = showSize($tarsize);
|
|
#------------------------------------------------------------
|
|
# figure out the size of the dump files
|
|
#------------------------------------------------------------
|
|
my $dumpsize = 0;
|
|
|
|
open(DF, "-|")
|
|
or exec '/bin/df', '-P', '-t', 'ext4', '-t', 'xfs';
|
|
|
|
while (<DF>) {
|
|
next unless (/^\//);
|
|
(undef, undef, my $s, undef) = split(/\s+/, $_);
|
|
$dumpsize += $s;
|
|
}
|
|
# increase size by 10% to cope with dump overhead.
|
|
$dumpsize *= 1.1;
|
|
|
|
close DF;
|
|
$dumpsize = showSize($dumpsize);
|
|
|
|
#------------------------------------------------------------
|
|
# how much free space is in /tmp
|
|
#------------------------------------------------------------
|
|
my $tmpfree = 0;
|
|
my $halffree = 0;
|
|
|
|
open(DF, "-|")
|
|
or exec '/bin/df', '-P', '-t', 'ext4', '-t', 'xfs', '/tmp';
|
|
|
|
while (<DF>) {
|
|
next unless (/^\//);
|
|
(undef, undef, undef, my $s) = split(/\s+/, $_);
|
|
$tmpfree += $s;
|
|
}
|
|
|
|
close DF;
|
|
$halffree = $tmpfree / 2;
|
|
$tmpfree = showSize($tmpfree);
|
|
$halffree = showSize($halffree);
|
|
|
|
return ($tarsize, $dumpsize, $tmpfree, $halffree);
|
|
}
|
|
|
|
|
|
sub showSize {
|
|
|
|
# convert size to Mb or Gb or Tb :) Remember, df reports in kb.
|
|
my $size = shift;
|
|
|
|
my $Mb = 1024;
|
|
my $Gb = $Mb * $Mb;
|
|
my $Tb = $Mb * $Mb * $Mb;
|
|
|
|
if ($size >= $Tb) {
|
|
$size /= $Tb;
|
|
$size = int($size) . "Tb";
|
|
} elsif ($size >= $Gb) {
|
|
$size /= $Gb;
|
|
$size = int($size) . "Gb";
|
|
} elsif ($size >= $Mb) {
|
|
$size /= $Mb;
|
|
$size = int($size) . "Mb";
|
|
} else {
|
|
$size .= "kb";
|
|
}
|
|
|
|
return $size;
|
|
}
|
|
|
|
|
|
sub desktopBackupRecordStatus {
|
|
|
|
my ($backup, $phase, $status) = @_;
|
|
my $now = time();
|
|
|
|
warn("Backup terminated: $phase failed - status: $status\n");
|
|
$backup->set_prop('EndEpochTime', "$now");
|
|
$backup->set_prop('Result', "$phase:$status");
|
|
}
|
|
|
|
|
|
sub dmount {
|
|
|
|
# mount dar unit according to dar-workstation configuration
|
|
# return nothing if mount successfull
|
|
|
|
my ($host,$share,$mountdir,$login,$password,$VFSType) = @_;
|
|
|
|
if ($VFSType eq 'cifs')
|
|
{
|
|
return ( qx(/bin/mount -t cifs "//$host/$share" $mountdir -o credentials=/etc/dar/CIFScredentials,nounix 2>&1) );
|
|
}
|
|
elsif ($VFSType eq 'nfs') {
|
|
return ( qx(/bin/mount -t nfs -o nolock "$host:/$share" $mountdir 2>&1) );
|
|
}
|
|
elsif ($VFSType eq 'usb') {
|
|
my $device = "";
|
|
my $blkdev = "";
|
|
my $vollbl = "";
|
|
foreach my $udi (qx(hal-find-by-property --key volume.fsusage --string filesystem)) {
|
|
$udi =~ m/^(\S+)/;
|
|
my $is_mounted = qx(hal-get-property --udi $1 --key volume.is_mounted);
|
|
|
|
if ($is_mounted eq "false\n") {
|
|
$blkdev = qx(hal-get-property --udi $1 --key block.device);
|
|
if ($blkdev =~ m/^(\S+)/) {$blkdev = $1;}
|
|
}
|
|
if ($is_mounted eq "false\n") {
|
|
$vollbl = qx(hal-get-property --udi $1 --key volume.label);
|
|
$vollbl =~ m/^(\S+)/;
|
|
if ($vollbl =~ /^\s/) {$vollbl = 'nolabel';}
|
|
}
|
|
|
|
chomp $vollbl;
|
|
chomp $blkdev;
|
|
$vollbl = "media/$vollbl";
|
|
if ($vollbl eq $share) {
|
|
$device = $blkdev;
|
|
}
|
|
}
|
|
return ( qx(/bin/mount $device "/$share" 2>&1) );
|
|
} else {
|
|
return ("Error while mounting $host/$share : $VFSType not supported.\n");
|
|
}
|
|
}
|
|
|
|
|
|
sub checkMount {
|
|
|
|
# check if $mountdir is mounted
|
|
my $mountdir = shift;
|
|
$|=1; # Auto-flush
|
|
|
|
# copy STDOUT to another filehandle
|
|
open (my $STDOLD, '>&', STDOUT);
|
|
|
|
open(STDOUT, ">/dev/null");
|
|
if ( open(MOUNTDIR, "|-", "/bin/findmnt", $mountdir)){;}
|
|
|
|
# restore STDOUT
|
|
open (STDOUT, '>&', $STDOLD);
|
|
|
|
return (!close(MOUNTDIR));
|
|
}
|
|
|
|
|
|
sub bmount {
|
|
|
|
my ($c, $mntdir, $host, $share, $VFSType) = @_;
|
|
# verify backup directory not already mounted
|
|
|
|
if (!checkMount ($mntdir)) {
|
|
return if ($VFSType eq 'mnt');
|
|
return ($c->l('bac_ERR_ALREADY_MOUNTED'));
|
|
} else {
|
|
if ($VFSType eq 'mnt') {
|
|
return ($c->l('bac_ERR_NOT_MOUNTED'));
|
|
}
|
|
}
|
|
|
|
# create the directory mount point if it does not exist
|
|
my $err = createTree ($mntdir);
|
|
return ($c->l('bac_ERR_MOUNTING_SMBSHARE') . "<//$host/$share>\n" . $err) if $err;
|
|
|
|
# mount the backup directory
|
|
$err = dmount($host,$share,$mntdir,'','',$VFSType);
|
|
return ($c->l('bac_ERR_MOUNTING_SMBSHARE') . "<//$host/$share>\n" . $err) if $err;
|
|
|
|
# verify $mntdir is mounted
|
|
if (checkMount ($mntdir)) {
|
|
# The mount should have suceeded, but sometimes it needs more time,
|
|
# so sleep and then check again.
|
|
sleep 5;
|
|
if (checkMount ($mntdir)) {
|
|
return ($c->l('bac_ERR_NOT_MOUNTED'));
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
sub bunmount {
|
|
|
|
my ($c, $mount, $type) = @_;
|
|
return if ($type eq 'mnt'); # Don't unmount for type 'mnt'
|
|
|
|
if (!checkMount ($mount)) {
|
|
system('/bin/umount', '-f', $mount) == 0
|
|
or return ($c->l('bac_ERR_WHILE_UNMOUNTING'));
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
sub findmnt {
|
|
|
|
my @mntin = qx( findmnt -n -l -o TARGET );
|
|
my @mntout;
|
|
|
|
foreach my $mount (@mntin) {
|
|
next if ($mount =~ m/^\/proc|^\/dev|^\/sys|^\/boot/s);
|
|
chomp $mount;
|
|
next if ($mount eq '/');
|
|
push @mntout, $mount;
|
|
}
|
|
return @mntout;
|
|
}
|
|
|
|
|
|
sub createTree {
|
|
|
|
my $tree = shift;
|
|
|
|
if (! -d "$tree") {
|
|
eval {make_path("$tree")};
|
|
return ("Error while creating $tree : $@. Maybe insufficient rights directory.\n") if $@;
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
sub vmount {
|
|
|
|
#Used to test if the remote share is mountable when you save settings in database
|
|
# mount dar unit according to dar-workstation configuration in order to test the remote host
|
|
# return nothing if mount successfull
|
|
|
|
my ($host,$share,$mountdir,$VFSType) = @_;
|
|
|
|
if ($VFSType eq 'cifs') {
|
|
return ( qx(/bin/mount -t cifs "//$host/$share" $mountdir -o credentials=/etc/dar/CIFScredentials,nounix 2>&1) );
|
|
} elsif ($VFSType eq 'nfs') {
|
|
return ( qx(/bin/mount -t nfs -o nolock,timeo=30,retrans=1,retry=0 "$host:/$share" $mountdir 2>&1) );
|
|
}
|
|
}
|
|
|
|
|
|
1;
|