package MDV::Snapshot::Restore; ################################################################################ # Backup Configuration Tool # # # # Copyright (C) 2008 Mandriva # # # # Thierry Vignaud # # # # This program is free software; you can redistribute it and/or modify # # it under the terms of the GNU General Public License Version 2 as # # published by the Free Software Foundation. # # # # This program is distributed in the hope that it will be useful, # # but WITHOUT ANY WARRANTY; without even the implied warranty of # # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # # GNU General Public License for more details. # # # # You should have received a copy of the GNU General Public License # # along with this program; if not, write to the Free Software # # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # ################################################################################ use strict; use warnings; use lib qw(/usr/lib/libDrakX); use c; use locale; use MDV::Snapshot::Common; use common; use interactive; use POSIX; use run_program; use fsedit; use fs::type; use fs; use any; sub get_fstab() { my $all_hds = fsedit::get_hds(); fs::get_raw_hds('', $all_hds); fs::get_info_from_fstab($all_hds); [ fs::get::fstab($all_hds) ]; # $fstab } sub get_handle { my ($part, $o_rw) = @_; my $mntpnt = $part->{mntpoint}; # do not bother failed to mount with ro b/c already mounted: $mntpnt ? { dir => $mntpnt } : any::inspect($part, $::prefix, $o_rw); } sub find_disks_with_rsnapshot { my ($fstab) = @_; my @true_fs = grep { isTrueLocalFS($_) && !member($_->{mntpoint}, '/home', grep { $_ ne '/' } fs::type::directories_needed_to_boot()); } @$fstab; log::l("looking for rsnapshot.conf on partitions " . join(' ', map { $_->{device} } @true_fs)); my @found; foreach my $part (@true_fs) { my $handle = get_handle($part); next if !$handle; next if ! -e "$handle->{dir}/etc/rsnapshot.conf"; if (my $f = common::release_file($handle->{dir})) { my $h = common::parse_release_file($handle->{dir}, $f, $part); $h->{name} = $h->{release}; push @found, $h; } } return @found; } sub get_snapshots() { my %backups = map { my $backup = $_; my ($type, $_number) = m!$backup_directory/([^/]*)\.([0-9]*)!; my $raw_date = [ stat($backup) ]->[-4]; my $date = POSIX::strftime($type eq 'hourly' ? "%c" : "%x", localtime($raw_date)); c::set_tagged_utf8($date); $backup => { raw_date => $raw_date, date => $date, backup => $backup, type => $type }; } glob_("$backup_directory/*"); %backups; } sub configure { my ($in) = @_; my $backup; my %backups = get_snapshots(); if (!%backups) { $in->ask_warn(N("Error"), N("No backup found!")); return; } my %i18n = ( 'hourly' => N("Hourly"), 'daily' => N("Daily"), 'weekly' => N("Weekly"), 'monthly' => N("Monthly"), ); $in->ask_from_( { title => N("Backup snapshots configuration"), }, [ { title => 1, label => N("Backup snapshots configuration") }, { label => N("Please select the backup you want to restore.") }, { val => \$backup, sort => 0, allow_empty_list => 1, format => sub { #-PO: eg: "Daily snapshot done on Sun Feb 4 N("%s snapshot done on %s", $i18n{$backups{$_[0]}{type}}, $backups{$_[0]}{date}); }, list => [ sort { $backups{$a}{raw_date} cmp $backups{$b}{raw_date} } keys %backups ], }, ]) or return; my $_wait = $in->wait_message(N("Please wait"), N("Restoring backup in progress")); my $backup_dir = $backups{$backup}{backup}; # FIXME: add a progress bar foreach (glob_("$backup_dir/localhost/*")) { my $dir = $_; s!^$backup_dir/localhost!!; log::l("would run system('rsync', '-vrlpt', $dir, $::prefix$_)\n") if $::testing; # FIXME: should we use --delete? run_program::run('rsync', '-vrlpt', $dir, "$::prefix$_") if !$::testing; } undef $_wait; $in->ask_from_no_check( { title => N("Congratulations"), messages => N("Congratulations, restoration is complete."), ok => $::isStandalone || $::local_install ? N("Quit") : N("Reboot"), }, []); } sub mount_all { my ($in, $fstab) = @_; local $::testing = 0; my @errs; foreach my $part (sort { $a->{mntpoint} cmp $b->{mntpoint} } grep { $_->{mntpoint} && $_->{mntpoint} ne '/' && maybeFormatted($_) && $_->{device} ne 'none' && !member($_->{fs_type}, 'swap', 'nfs', if_($::isInstall, 'ntfs')); } @$fstab) { eval { fs::mount::part($part) }; push @errs, $@ if $@; } $in->ask_warn(N("Warning"), N("mount failed: ") . join("\n", '', @errs)) if @errs; } sub main { my ($in) = @_; my ($system, $fstab, @found); refresh: $fstab = get_fstab(); @found = find_disks_with_rsnapshot($fstab); $in->ask_from_({ interactive_help_id => 'configureX_chooser', title => N("Restoring Backup"), messages => join("\n", N("Please select the partition of the system to restore."), N("Do not forget to plug the USB disk that contains your backups."), ) }, [ { label => N("System to restore"), }, { val => \$system, list => \@found, allow_empty_list => 1, format => sub { my $dev = $_[0]; N("\"%s\" (on %s)", $dev->{name}, $dev->{part}{device}); }, }, { val => N("Refresh"), clicked => sub { goto refresh }, }, ]); my $handle = get_handle($system->{part}, 1); local $::prefix = $handle->{dir}; # reinit paths according to temp mount point: MDV::Snapshot::Common::init(); my $ch_fstab; if (ref($handle) =~ /before_leaving/) { $ch_fstab = [ fs::read_fstab($::prefix, '/etc/fstab') ]; mount_all($in, $ch_fstab); } configure($in); # make sure everything is umounted: if (ref($handle) =~ /before_leaving/) { # reread for {real_mountpoint}: $ch_fstab = [ fs::read_fstab($::prefix, '/etc/fstab') ]; eval { fs::mount::umount_all($ch_fstab) }; } } 1;