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.'
'; } elsif ($VFSType eq 'mnt') { $out .= $c->l('bac_WORKSTN_BACKUP_MNT').' '.$backupwkMount.'
'; } else { $out .= $c->l('bac_WORKSTN_BACKUP_HOST').' '.$backupwkStation.' '; $out .= $c->l('bac_WORKSTN_BACKUP_VFSTYPE').' '.$VFSType.'
'; $out .= $c->l('bac_WORKSTN_BACKUP_SHARE').' '.$backupwkFolder.'
'; } if ($VFSType eq 'cifs') { $out .= $c->l('bac_LOGIN').' '.$backupwkLogin.'
'; $out .= $c->l('PASSWORD').' ********
'; } $out .= $c->l('bac_WORKSTN_BACKUP_SETSNUM').' '.$setsNumber.'
'; $out .= $c->l('bac_WORKSTN_BACKUP_DAYSINSET').' '.$filesinset.'
'; $out .= $c->l('bac_WORKSTN_BACKUP_COMPRESSION').' '.$compression.'
'; $out .= $c->l('bac_WORKSTN_BACKUP_TOD').' '.$backupwkTime.'
'; $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 .= '
'; if ( $dof eq '7' ) { $out .= $c->l('bac_WORKSTN_FULL_BACKUP_EVERYDAY').'
'; } else { $out .= $c->l('bac_WORKSTN_FULL_BACKUP_DAY').' '.$dlabels[$dof].'
'; } } 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 .= ''.$c->l('bac_TESTING_NEEDED_BACKUPS_FOR_RESTORE').''; my $message; $out .= ''; if (!close RD) { $out .= $c->l('bac_RESTORE_VERIFY_FAILED'); } else { $out .= $c->l('bac_VERIFY_COMPLETE'); } $out .= ''; } 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 .= ''.$c->l('bac_FILES_IN_BACKUP').''; my $status = close RD ? ($complete ? $c->l('bac_VERIFY_COMPLETE') : $c->l('bac_BACKUP_FILE_INCOMPLETE')) : ($c->l('bac_ERROR_READING_FILE').' : '.$backupkey); $out .= " $status "; } 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')
($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 .= ''; 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 () { 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'). "
$error_message"; } } return '#OK#'.$c->l('bac_SUCCESSFULLY_ENABLED_WORKSTN'). '
'. $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 .= "". $c->l('bac_FILES_HAVE_BEEN_RESTORED') ." \n"; $out .= ''; 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 .= "$message \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 () { 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 () { 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 () { 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 () { 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 () { 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') . "\n" . $err) if $err; # mount the backup directory $err = dmount($host,$share,$mntdir,'','',$VFSType); return ($c->l('bac_ERR_MOUNTING_SMBSHARE') . "\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;