#!/usr/bin/perl # # Copyright (C) 2001-2002 MandrakeSoft by Sebastien DUPONT <dupont_s@epita.fr> # Updated 2002 by Stew Benedict <sbenedict@mandrakesoft.com> # Redistribution of this file is permitted under the terms of the GNU # Public License (GPL) # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # 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. # #________________________________________________________________ # # Description: # # Drakbackup is used to backup your system. # During the configuration you can select # - System files, # - Users files, # - Other files. # or All your system ... and Other (like windows Partitions) # # Drakbackup allows you to backup your system on: # - Harddrive. # - NFS. # - CDROM (CDRW), DVDROM (with autoboot, rescue and autoinstall.). # - FTP. # - Rsync. # - Webdav. # - Tape. # # Drakbackup allows you to Restore your system on # choosen directory. # # Per default all backup will be stored on your # /var/lib/drakbackup directory # # Configuration file: # /etc/drakconf/drakbackup/drakbackup.conf # #________________________________________________________________ # # Backup files formats: # # no incremental backup: # backup_sys_date_hour.tar.* # backup_user_toto_date_hour.tar.* # backup_other_date_hour.tar.* # # first incremental backup: (if backup_base* does not exist) # # backup_base_sys_date_hour.tar.* # backup_base_user_toto_date_hour.tar.* # backup_base_other_date_hour.tar.* # # other incremental backup: (if backup_base* already exist) # # backup_incr_sys_date_hour.tar.* # backup_incr_user_toto_date_hour.tar.* # backup_incr_other_date_hour.tar.* # # all backup runs will generate: # # drakbackup_date_hour.txt # # this will contain media & hostname #________________________________________________________________ # # REQUIRE: cron if daemon # cdrecord & mkisofs # perl Net::FTP # ssh-askpass # sitecopy - for webdav # rsync # perl Expect # BUGS: #DONE restore->other_media->next->previous => crash ... #DONE selection des sources a inclure dans le backup cd. #DONE help -> ok after install_rpm # sort of fixed - doesn't always land where you would expect # but at least it doesn't die # # TODO: # 1 - print ftp problem for user. # 2 - calcul disk space. # use quota. #WHY? - Apple can read Joliet - would you really be restoring on MacOS? #Or for bootable - PPC is being deprecated anyway ;( # 4 - write on cd --> ! change Joliet to HFS for Apple # 6 - total backup.( all partitions wanted, windows partitions for example!) # dump use for total backup. # 7 - custom deamon # 10- backend: --resore_all, --restore_sys, --restore_users #WHAT IS THIS? # --build_cd_autoinst # 12- cpio use !! # 13- boot floppy disk (with dialog) # 14- build autoboot with backup and install cd # 15- use .backupignore like on CVS # 16- afficher les modif dans un fichier texte du meme nom # pour afficher durant le restore. # 17- futur: could be possible to restore a specific file # or directory at specific date. # 18- possible all files each time from directory. # # DONE TODAY: #________________________________________________________________ use strict; use lib qw(/usr/lib/libDrakX); use standalone; #- warning, standalone must be loaded very first, for 'explanations' use interactive; #- to make perl_checker happy - comment out to use daemon/command line mode use ugtk2 qw(:helpers :wrappers :create); use common; use Time::localtime; use detect_devices; # Backend Options. # make this global for status screen my ($window1, $my_win); my $central_widget; my $previous_widget; my $current_widget; my $interactive; my $up_box; my $advanced_box; my $box2; my $cfg_file_exist = 0; my @all_user_list; my $list_other; my $DEBUG = 0; my $restore_sys = 1; my $restore_user = 1; my $restore_other = 1; my $restore_step_sys_date = ""; my @user_backuped; my @sys_backuped; my $sys_backuped = 0; my $other_backuped = 0; my @user_list_to_restore; my @sys_list_to_restore; my $cd_device_entry; my $custom_help; my $button_box; my $button_box_tmp; my $next_widget; my $sav_next_widget; my $system_state; my $restore_state; my $save_path_entry; my $restore_find_path_entry; my $new_path_entry; my $pbar; my $pbar1; my $pbar2; my $pbar3; my $plabel; my $plabel1; my $plabel2; my $plabel3; my $stext; my $the_time; my @user_list_to_restore2; my @data_backuped; my $label_tail; my @list_to_build_on_cd; my $restore_path = "/"; my $restore_other_path = 0; my $restore_other_src; my $path_to_find_restore; my $other_media_hd; my $backup_bef_restore = 0; my $table; my @user_list_backuped; my @files_corrupted; #- ack - not a great default - changed 20020814 (SB) my $remove_user_before_restore = 0; my @file_list_to_send_by_ftp; my $results; my @net_methods = ("ftp", "rsync", "ssh", "webdav"); my @media_types = ("cd", "hd", "tape"); my %cd_devices; my $std_device; my @tape_devices; my $tar_ext = "tar.gz"; # config. FILES -> Default PATH & Global variables. my %config; my @sys_files = "/etc"; my @user_list; my @list_other; my $cfg_dir = "/etc/drakxtools/drakbackup/"; my $cfg_file = $cfg_dir . "drakbackup.conf"; my $save_path = "/var/lib/drakbackup"; my $log_buff; my $comp_mode = 0; my $backup_sys = 1; my $backup_user = 1; my $backup_daemon = 1; my $backup_sys_versions = 0; my $backup_user_versions = 0; my $backup_other_versions = 0; my $what_no_browser = 1; my $cdrw = 0; my $dvdr = 0; my $dvdram = 0; my $net_proto = ''; my $host_path = ''; my $login_user = ''; my $daemon = 0; my $backend_only = 0; my $daemon_media = ''; my $hd_quota = 0; #- 7/4/2002 SB - consolidate net methods my $where_use_net = 0; my $where_net = 0; my $where_hd = 1; my $del_hd_files = 0; my $where_cd = 0; my $where_tape = 0; my $cd_time = 650; my $when_space; my $cd_with_install_boot = 0; my $cd_device = ''; my $host_name = ''; my $backupignore = 0; my $remember_pass = 0; my $passwd_user = ''; my $tape_device; my $media_erase = 0; my $media_eject = 0; my $multi_session = 0; my $session_offset = ''; my $tape_norewind = 0; my $no_critical_sys = 1; my $send_mail = 0; my $user_mail; my $scp_port = 22; my $use_expect = 0; my $xfer_keys = 0; my $user_keys = 1; my $user_home = $ENV{HOME}; my $backup_key = $user_home . "/.ssh/identity-drakbackup"; my $nonroot_user = 0; my $not_warned = 0; my $media_problem = 0; my $vol_name = 'Drakbackup'; my $good_restore_path = 1; foreach (@ARGV) { /--default/ and backend_mode(); /--daemon/ and daemon_mode(); /--show-conf/ and show_conf(); /--config-info/ and explain_conf(); /--cd-info/ and get_cd_info(), exit(0); /--debug/ and $DEBUG = 1, next; } # allow not-root user with own config if ($ENV{HOME} ne '/root') { standalone::explanations("Running as $ENV{USER}..."); $cfg_dir = "$user_home/.drakbackup/"; $save_path = $cfg_dir . "backups"; -d $save_path or mkdir_p $save_path; $nonroot_user = 1; $not_warned = 1; $backup_sys = 0; $backup_daemon = 0; $daemon = 0; @user_list = $ENV{USER}; } $cfg_file = $cfg_dir . "drakbackup.conf"; sub show_conf { print "DrakBackup configuration:\n\n"; read_conf_file(); system_state(); print "$system_state\n"; exit(0); } sub explain_conf { print "\nConfiguration File Options: \n\n"; print "Configuration file is located in:\n"; print " Root Mode: /etc/drakxtools/drakbackup/drakbackup.conf.\n"; print " User Mode: ~/.drakbackup/drakbackup.conf.\n\n"; print "SYS_FILES= Space seperated list of system directories to backup.\n"; print "HOME_FILES= Space seperated list of user home directories to backup.\n"; print "OTHER_FILES= Space seperated list of other files to backup.\n"; print "PATH_TO_SAVE= Default Hard Drive path to create backup files in.\n"; print " Root Mode: default is /var/lib/drakbackup.\n"; print " User Mode: default is ~/.drakbackup/backups.\n"; print "NO_SYS_FILES Don't backup system files.\n"; print "NO_USER_FILES Don't backup user files.\n"; print "OPTION_COMP Compression option - TAR.GZ or TAR.BZ2 (tar.gz is default).\n"; print "BROWSER_CACHE Backup web browser cache also.\n"; print "CDRW Backup media is re-writable CD.\n"; print "DVDR Backup media is recordable DVD (not fully supported yet).\n"; print "DVDRAM Backup media is DVDRAM (not fully supported yet).\n"; print "NET_PROTO= Network protocol to use for remote backups: \n"; print " ftp, rsync, ssh, or webdav.\n"; print "HOST_NAME= Remote backup host.\n"; print "HOST_PATH= Backup storage path or module on remote host.\n"; print "REMEMBER_PASS Remember password on remote host in config file.\n"; print "USER_KEYS Ssh keys are already setup for communicating with remote host.\n"; print "DRAK_KEYS Use special drakbackup generated host keys.\n"; print " (requires perl-Expect).\n"; print "USE_EXPECT Use expect to do the whole scp transfer, without keys.\n"; print " (requires perl-Expect).\n"; print "LOGIN= Remote host login name.\n"; print "PASSWD= Password on remote host (if REMEMBER_PASS is enabled).\n"; print "DAEMON_MEDIA= Daemon mode backup via given media.\n"; print " (hd, cd, tape, ftp, rsync, ssh, or webdav).\n"; print "HD_QUOTA Use quota to limit hard drive space used for backups.\n"; print " (not supported yet).\n"; print "USE_HD Use Hard Drive for backups (currently all modes use HD also).\n"; print "USE_CD Use CD for backups.\n"; print "USE_NET Use network for backups (driven by NET_PROTO).\n"; print "USE_TAPE Use tape for backup.\n"; print "DEL_HD_FILES Delete local hard drive tar files after backup to other media.\n"; print "TAPE_NOREWIND Use non-rewinding tape device.\n"; print "CD_TIME= Length of CD media (not currently utilized).\n"; print "DAEMON_TIME_SPACE= Interval between daemon backup runs (hourly, daily, weekly)..\n"; print "CD_WITH_INSTALL_BOOT Build a bootable restore CD (currently not utilized).\n"; print "CD_DEVICE= Cdrecord style CD device name (ie: 1,3,0).\n"; print "USER_MAIL= User to send backup results to via email.\n"; print "SEND_MAIL Do send backup results via email.\n"; print "TAPE_DEVICE Device to use for tape backup (ie: /dev/st0).\n"; print "MEDIA_ERASE Erase media before new backup (applies to tape, CD).\n"; print "MEDIA_EJECT Eject media after backup completes.\n"; print "MULTI_SESSION Allow muliple sessions to be written to CD media.\n"; print "SYS_INCREMENTAL_BACKUPS Do incremental backups of system files.\n"; print "USER_INCREMENTAL_BACKUPS Do imcremental backups of user files.\n"; print "OTHER_INCREMENTAL_BACKUPS Do incremental backups if other files.\n"; print "NO_CRITICAL_SYS Do not backup critical system files:\n"; print " passwd, fstab, group, mtab\n"; print "CRITICAL_SYS Do backup above system files.\n"; exit(0); } sub backend_mode { $backend_only = 1; build_backup_files(); exit(0); } sub daemon_mode { $daemon = 1; build_backup_files(); exit(0); } interactive_mode(); sub all_user_list { my $passwdfile = "/etc/passwd"; my $user; my $uid; @all_user_list = (); local *PASSWD; open(PASSWD, $passwdfile) or exit 1; while (defined(my $line = <PASSWD>)) { chomp($line); ($user, $uid) = (split(/:/, $line))[0, 2]; if ($uid >= 500 || $uid == 0) { push @all_user_list, $user; } } close(PASSWD); if ($DEBUG) { print "/-- User list --/ \n"; print " -> $_\n" foreach @all_user_list; print "\n"; } } sub the_time { $the_time = "_"; $the_time .= localtime->year() + 1900; if (localtime->mon() < 9) { $the_time .= "0" } $the_time .= localtime->mon() + 1; if (localtime->mday() < 10) { $the_time .= "0" } $the_time .= localtime->mday(); $the_time .= "_"; if (localtime->hour() < 10) { $the_time .= "0" } $the_time .= localtime->hour(); if (localtime->min() < 10) { $the_time .= "0" } $the_time .= localtime->min(); if (localtime->sec() < 10) { $the_time .= "0" } $the_time .= localtime->sec(); } sub get_tape_info { my @line_data; my $info = "/tmp/dmesg"; @tape_devices = (); system("dmesg | grep 'st[0-9] at' > $info"); local *INFO; open(INFO, $info) || warn("Can't open $info\n"); local $_; while (<INFO>) { @line_data = split(/[ \t,]+/, $_); push @tape_devices, "/dev/" . $line_data[3]; } close(INFO); unlink($info); } sub get_cd_info { my @cd_info = cat_("/proc/sys/dev/cdrom/info"); my @line_data; my @drive_names; my $i; my $info; my %data => ( "drive speed" => 'speed', "Can change speed" => 'chg_speed', "Can read multisession" => 'multisession', "Can write CD-R" => 'cdr', "Can write CD-RW" => 'cdrw', "Can write DVD-R" => 'dvdr', "Can write DVD-RAM" => 'dvdram', ); #- kind of ugly - I'm sure Pixel could improve this, but it works #- parse /proc/sys/dev/cdrom/info and get all the cd device capabilities my $cd_drives; foreach (@cd_info) { @line_data = split(/[:\t]+/, $_); if ($line_data[0] =~ /drive name/) { $cd_drives = @line_data-1; chop($line_data[$cd_drives]); @drive_names = @line_data; print "drives: $cd_drives\n" unless $interactive; } chop($line_data[$cd_drives]) if $cd_drives; foreach my $key (keys %data) { if ($line_data[0] =~ $key) { for ($i = 1; $i <= $cd_drives; $i++) { $cd_devices{$drive_names[$i]}{$data{$key}} = $line_data[$i]; } } } } #- now we know all the capabilities, we need the cdrecord device id #- this is scsi-channel, id, lun from /dev/scsi/host* #- oops - can't count on devfs - use dmesg $info = "/tmp/dmesg"; system("dmesg | grep sr[0-9] > $info"); local *INFO; open(INFO, $info) || warn("Can't open $info\n"); local $_; while (<INFO>) { if (/sr[0-9] at/) { @line_data = split(/[ \t,]+/, $_); chop($line_data[11]); $line_data[5] =~ s/scsi//; $cd_devices{$line_data[3]}{rec_dev} = $line_data[5] . "," . $line_data[9] . "," . $line_data[11]; } } close(INFO); unlink($info); #- should we also try to get the human readable name for display purposes? #- now just report the data if we called --cd-info from the command line if (!$interactive) { foreach my $key (keys %cd_devices) { print "\n{$key}->{rec_dev} = $cd_devices{$key}->{rec_dev}\n"; print "{$key}->{speed} = $cd_devices{$key}->{speed}\n"; print "{$key}->{chg_speed} = $cd_devices{$key}->{chg_speed}\n"; print "{$key}->{multisession} = $cd_devices{$key}->{multisession}\n"; print "{$key}->{cdr} = $cd_devices{$key}->{cdr}\n"; print "{$key}->{cdrw} = $cd_devices{$key}->{cdrw}\n"; print "{$key}->{dvdr} = $cd_devices{$key}->{dvdr}\n"; print "{$key}->{dvdram} = $cd_devices{$key}->{dvdram}\n"; } } else { #- in non-interactive mode we just let all the devices through #- as a general purpose probe - in reality we want only burners foreach my $key (keys %cd_devices) { delete $cd_devices{$key} if $cd_devices{$key}{rec_dev} eq '' } } } sub save_conf_file { write_sitecopyrc() if $net_proto eq 'webdav'; write_password_file() if $net_proto eq 'rsync' && $passwd_user; my @cfg_list = ("SYS_FILES=@sys_files\n", "HOME_FILES=@user_list\n", "OTHER_FILES=@list_other\n", "PATH_TO_SAVE=$save_path\n", "HOST_PATH=$host_path\n", "NET_PROTO=$net_proto\n", "CD_TIME=$cd_time\n", "USER_MAIL=$user_mail\n", "DAEMON_TIME_SPACE=$when_space\n", "CD_DEVICE=$cd_device\n", "LOGIN=$login_user\n", "TAPE_DEVICE=$tape_device\n", "HOST_NAME=$host_name\n" ); $no_critical_sys and push @cfg_list, "NO_CRITICAL_SYS\n"; $no_critical_sys or push @cfg_list, "CRITICAL_SYS\n"; $send_mail and push @cfg_list, "SEND_MAIL\n"; $backup_sys_versions and push @cfg_list, "SYS_INCREMENTAL_BACKUPS\n"; $backup_user_versions and push @cfg_list, "USER_INCREMENTAL_BACKUPS\n"; $backup_other_versions and push @cfg_list, "OTHER_INCREMENTAL_BACKUPS\n"; $media_erase and push @cfg_list, "MEDIA_ERASE\n"; $media_eject and push @cfg_list, "MEDIA_EJECT\n"; $multi_session and push @cfg_list, "MULTI_SESSION\n"; $remember_pass and push @cfg_list, "LOGIN=$login_user\n"; $remember_pass and push @cfg_list, "PASSWD=$passwd_user\n"; $remember_pass and push @cfg_list, "REMEMBER_PASS\n"; $user_keys and push @cfg_list, "USER_KEYS\n"; $xfer_keys and push @cfg_list, "DRAK_KEYS\n"; $use_expect and push @cfg_list, "USE_EXPECT\n"; $cd_with_install_boot and push @cfg_list, "CD_WITH_INSTALL_BOOT\n"; $daemon_media eq 'ssh' and $backup_daemon and push @cfg_list, "DAEMON_MEDIA=ssh\n"; $daemon_media eq 'ftp' and $backup_daemon and push @cfg_list, "DAEMON_MEDIA=ftp\n"; $daemon_media eq 'hd' and $backup_daemon and push @cfg_list, "DAEMON_MEDIA=hd\n"; $daemon_media eq 'cd' and $backup_daemon and push @cfg_list, "DAEMON_MEDIA=cd\n"; $daemon_media eq 'tape' and $backup_daemon and push @cfg_list, "DAEMON_MEDIA=tape\n"; $daemon_media eq 'webdav' and $backup_daemon and push @cfg_list, "DAEMON_MEDIA=webdav\n"; $daemon_media eq 'rsync' and $backup_daemon and push @cfg_list, "DAEMON_MEDIA=rsync\n"; $hd_quota and push @cfg_list, "HD_QUOTA\n"; $where_hd and push @cfg_list, "USE_HD\n"; $where_cd and push @cfg_list, "USE_CD\n"; $where_tape and push @cfg_list, "USE_TAPE\n"; $tape_norewind and push @cfg_list, "TAPE_NOREWIND\n"; $where_net and push @cfg_list, "USE_NET\n"; $cdrw and push @cfg_list, "CDRW\n"; $dvdr and push @cfg_list, "DVDR\n"; $dvdram and push @cfg_list, "DVDRAM\n"; $what_no_browser or push @cfg_list, "BROWSER_CACHE\n"; $backup_sys or push @cfg_list, "NO_SYS_FILES\n"; if ($comp_mode) { push @cfg_list, "OPTION_COMP=TAR.BZ2\n"; } else { push @cfg_list, "OPTION_COMP=TAR.GZ\n"; } $del_hd_files and push @cfg_list, "DEL_HD_FILES\n"; output_p($cfg_file, @cfg_list); chmod(0600, $cfg_file); save_cron_files() if $backup_daemon; } sub read_cron_files { my $daemon_found = 0; foreach (qw(hourly daily weekly monthly)) { if (-f "/etc/cron.$_/drakbackup") { $when_space = $_; $daemon_found = 1; last; } } !$daemon_found and $backup_daemon = 0; } sub save_cron_files { if ($nonroot_user) { show_warning("w", N_("Cron not available yet as non-root")) if $not_warned; $not_warned = 0; $backup_daemon = 0; return(1); } my @cron_file = ("#!/bin/sh\n", "export USER=root\n", "/usr/sbin/drakbackup --daemon > /dev/null 2>&1\n"); if ($backup_daemon) { foreach (qw(hourly daily weekly monthly)) { -f "/etc/cron.$_/drakbackup" and rm_rf("/etc/cron.$_/drakbackup"); } output_p("/etc/cron.$when_space/drakbackup", @cron_file); system("chmod +x /etc/cron.$when_space/drakbackup"); } else { foreach (qw(hourly daily weekly monthly)) { -f "/etc/cron.$_/drakbackup" and rm_rf("/etc/cron.$_/drakbackup"); } } } sub read_conf_file { if (-e $cfg_file) { # %config = getVarsFromSh($cfg_file) || print "You must be root to read configuration file. \n"; local *CONF_FILE; open(CONF_FILE, "<" . $cfg_file) || print "You must be root to read configuration file. \n"; local $_; while (<CONF_FILE>) { next unless /\S/; next if /^#/; chomp; if (/^SYS_FILES/) { s/^SYS_FILES=//gi; @sys_files = split(' ', $_) } if (/^HOME_FILES/) { s/^HOME_FILES=//gi; @user_list = split(' ', $_) } if (/^OTHER_FILES/) { s/^OTHER_FILES=//gi; @list_other = split(' ', $_) } if (/^PATH_TO_SAVE/) { s/^PATH_TO_SAVE=//gi; $save_path = $_ } if (/^NO_SYS_FILES/) { $backup_sys = 0 } if (/^NO_USER_FILES/) { $backup_user = 0 } if (/^OPTION_COMP/) { s/^OPTION_COMP=//gi; /TAR.GZ/ and $comp_mode = 0; /TAR.BZ2/ and $comp_mode = 1 } if (/^BROWSER_CACHE/) { $what_no_browser = 0 } if (/^CDRW/) { $cdrw = 1 } if (/^DVDR/) { $dvdr = 1 } if (/^DVDRAM/) { $dvdram = 1 } if (/^NET_PROTO/) { s/^NET_PROTO=//gi; $net_proto = $_ } if (/^HOST_PATH/) { s/^HOST_PATH=//gi; $host_path = $_ } if (/^DAEMON_MEDIA/) { s/^DAEMON_MEDIA=//gi; $daemon_media = $_ } if (/^HD_QUOTA/) { $hd_quota = 1 } if (/^USE_HD/) { $where_hd = 1 } if (/^USE_CD/) { $where_cd = 1 } if (/^USE_NET/) { $where_net = 1 } if (/^USE_TAPE/) { $where_tape = 1 } if (/^TAPE_NOREWIND/) { $tape_norewind = 1 } if (/^CD_TIME/) { s/^CD_TIME=//gi; $cd_time = $_ } if (/^DAEMON_TIME_SPACE/) { s/^DAEMON_TIME_SPACE=//gi; $when_space = $_ } if (/^CD_WITH_INSTALL_BOOT/) { $cd_with_install_boot = 1 } if (/^CD_DEVICE/) { s/^CD_DEVICE=//gi; $cd_device = $_ } if (/^HOST_NAME/) { s/^HOST_NAME=//gi; $host_name = $_ } if (/^REMEMBER_PASS/) { $remember_pass = 1 } if (/^USER_KEYS/) { $user_keys = 1 } if (/^DRAK_KEYS/) { $xfer_keys = 1; $user_keys = 0 } if (/^USE_EXPECT/) { $use_expect = 1; $user_keys = 0 } if (/^LOGIN/) { s/^LOGIN=//gi; $login_user = $_ } if (/^PASSWD/) { s/^PASSWD=//gi; $passwd_user = $_; $remember_pass = 1 } if (/^USER_MAIL/) { s/^USER_MAIL=//gi; $user_mail = $_ } if (/^SEND_MAIL/) { $send_mail = 1 } if (/^TAPE_DEVICE/) { s/TAPE_DEVICE=//gi; $tape_device = $_ } if (/^MEDIA_ERASE/) { $media_erase = 1 } if (/^MEDIA_EJECT/) { $media_eject = 1 } if (/^MULTI_SESSION/) { $multi_session = 1 } if (/^SYS_INCREMENTAL_BACKUPS/) { $backup_sys_versions = 1 } if (/^USER_INCREMENTAL_BACKUPS/) { $backup_user_versions = 1 } if (/^OTHER_INCREMENTAL_BACKUPS/) { $backup_other_versions = 1 } if (/^NO_CRITICAL_SYS/) { $no_critical_sys = 1 } if (/^CRITICAL_SYS/) { $no_critical_sys = 0 } if (/^DEL_HD_FILES/) { $del_hd_files = 1 } } close(CONF_FILE); read_cron_files(); $cfg_file_exist = 1; } else { $cfg_file_exist = 0; #- these were 1 by default, but that made it so the user could never save the #- inverse behavior. this allows incremental as the default if not configured $backup_sys_versions = 1; $backup_user_versions = 1; } } sub write_sitecopyrc { #- FIXME - how to deal with existing sitecopyrc my @cfg_list = ("site drakbackup\n", "\tserver $host_name\n", "\tremote /$host_path\n", "\tlocal $save_path\n", "\tusername $login_user\n", "\tpassword $passwd_user\n", "\tprotocol webdav\n" ); output_p("$user_home/.sitecopyrc", @cfg_list); chmod(0600, "$user_home/.sitecopyrc"); -d "$user_home/.sitecopy" or mkdir_p("$user_home/.sitecopy"); chmod(0700, "$user_home/.sitecopy"); } sub write_password_file { output_p("$cfg_dir/rsync.user", "$passwd_user\n"); chmod(0600, "$cfg_dir/rsync.user"); } my $in; sub show_warning { my ($mode, $warning) = @_; $mode = N_("WARNING") if $mode eq "w"; $mode = N_("FATAL") if $mode eq "f"; $mode = N_("INFO") if $mode eq "i"; if ($interactive) { $in->ask_warn('', translate($mode).": ".translate($warning)); } else { warn "$mode: $warning\n"; } $log_buff .= "\n$mode: $warning\n"; } sub complete_results { system_state(); $results .= "***********************************************************************\n\n"; $daemon or $results .= N("\n DrakBackup Report \n\n"); $daemon and $results .= N("\n DrakBackup Daemon Report\n\n\n"); $results .= "***********************************************************************\n\n"; $results .= $system_state; $results .= "\n\n***********************************************************************\n\n"; $results .= N("\n DrakBackup Report Details\n\n\n"); $results .= "***********************************************************************\n\n"; } sub ftp_client { use Net::FTP; my $ftp; $DEBUG and print "file list to send: $_\n " foreach @file_list_to_send_by_ftp; if ($DEBUG && $interactive) { $ftp = Net::FTP->new($host_name, Debug => 1) or return(1) } elsif ($interactive) { $ftp = Net::FTP->new($host_name, Debug => 0) or return(1) } else { $ftp = Net::FTP->new($host_name, Debug => 0) or return(1) } $ftp->login($login_user, $passwd_user); $ftp->cwd($host_path); foreach (@file_list_to_send_by_ftp) { $interactive and $pbar->set_fraction(0); $interactive and progress($pbar, 0.5, $_); $interactive and $pbar->set_text($_); $ftp->put($_); $interactive and progress($pbar, 0.5, $_); $interactive and $pbar->set_text($_); $interactive and progress($pbar3, 1/@file_list_to_send_by_ftp, N("Total progess")); } $ftp->quit; return(0); } sub do_expect { #- Sort of a general purpose expect routine, we use it to backup files to #- a remote server, as well as transfer a key and restore. #- Using the key after it is setup is preferred. my ($mode) = @_; eval { require Expect }; if ($@) { if ($mode eq 'sendkey') { destroy_widget(); check_pkg_needs(); } else { $log_buff .= "perl-Expect not installed!", } return(1); } #- for debugging set to 1 $Expect::Exp_Internal = 0; #- for debugging set to 1 $Expect::Debug = 0; $Expect::Log_Stdout = 0; my $spawn_ok; my $no_perm; my $bad_passwd; my $bad_dir; my $timeout = 20; my $exp_command; my @send_files = "$backup_key.pub"; #- just bypass progress for sendkey for now $interactive = 0 if $mode eq "sendkey"; @send_files = @file_list_to_send_by_ftp if $mode eq "backup"; $interactive and $pbar->set_fraction(0); $interactive and $pbar3->set_fraction(0); $interactive and progress($pbar, 0.5, "File Transfer..."); foreach (@send_files) { $exp_command = "scp -P $scp_port $_ $login_user\@$host_name:$host_path" if $mode eq "backup"; $exp_command = "ssh-copy-id -i $_ $login_user\@$host_name" if $mode eq "sendkey"; if (-e $backup_key && $mode eq "sendkey") { if ($in->ask_yesorno('', N("%s exists, delete?\n\nWarning: If you've already done this process you'll probably\n need to purge the entry from authorized_keys on the server.", $backup_key))) { unlink($backup_key); unlink($backup_key . '.pub'); } else { return(0); } } if (!(-e $backup_key) && $mode eq "sendkey") { $in->ask_warn('', N("This may take a moment to generate the keys.")); cursor_wait(); #- not using a passphrase for the moment system("ssh-keygen -P '' -t dsa -f $backup_key"); cursor_norm(); } my $exp = Expect->spawn($exp_command) or $in->ask_warn('', N("ERROR: Cannot spawn %s.", $exp_command)); $interactive and progress($pbar3, 1/@send_files, N("Total progess")); $interactive and $stext->set_text($_); #- run scp, look for some common errors and try to track successful progress for GUI $exp->expect($timeout, [ qr 'password: $', sub { $spawn_ok = 1; my $fh = shift; $fh->send("$passwd_user\n"); Expect::exp_continue() } ], [ '-re', 'please try again', sub { $bad_passwd = 1; Expect::exp_continue() } ], [ '-re', 'Permission denied', sub { $no_perm = 1; Expect::exp_continue() } ], [ '-re', 'No such file or directory', sub { $bad_dir = 1; Expect::exp_continue() } ], # [ '-re', '%', sub { update_scp_progress(); Expect::exp_continue(); } ], [ eof => sub { if (!$spawn_ok) { show_warning("f", N("No password prompt on %s at port %s", $host_name, $scp_port)) } if ($bad_passwd) { show_warning("f", N("Bad password on %s", $host_name)) } if ($no_perm) { show_warning("f", N("Permission denied transferring %s to %s", $_, $host_name)) } if ($bad_dir) { show_warning("f", N("Can't find %s on %s", $host_path, $host_name)) } } ], [ timeout => sub { show_warning("f", N("%s not responding", $host_name)) } ], ); my $exit_stat = $exp->exitstatus; $in->ask_warn('', N("Transfer successful\nYou may want to verify you can login to the server with:\n\nssh -i %s %s\@%s\n\nwithout being prompted for a password.", $backup_key, $login_user, $host_name)) if $exit_stat eq 0 && $mode eq "sendkey"; $log_buff .= "$_\n" if $exit_stat eq 0 && $mode eq "backup"; $exp->hard_close(); } $interactive and progress($pbar, 0.5, "Done..."); $interactive = 1 if $mode eq "sendkey"; } sub ssh_client { $DEBUG and print "file list to send: $_\n " foreach @file_list_to_send_by_ftp; my $command; my $value; foreach (@file_list_to_send_by_ftp) { if ($user_keys) { $command = "scp -P $scp_port $_ $login_user\@$host_name:$host_path"; } else { $command = "scp -P $scp_port -i $backup_key $_ $login_user\@$host_name:$host_path"; } $interactive and $pbar->set_fraction(0); $interactive and progress($pbar, 0.5, "File Transfer..."); $interactive and $stext->set_text($_); $log_buff .= $command . "\n\n"; local *TMP; open TMP, "$command 2>&1 |"; while ($value = <TMP>) { $log_buff .= $value; } close TMP; $log_buff .= "\n"; $interactive and progress($pbar, 0.5, "Done..."); $interactive and progress($pbar3, 1/@file_list_to_send_by_ftp, N("Total progess")); } return(0); } sub webdav_client { $DEBUG and print "file list to send: $_\n " foreach @file_list_to_send_by_ftp; if (!(-e "$user_home/.sitecopy/drakbackup")) { my $command = "sitecopy -f $host_path"; spawn_progress($command, "Initializing sitecopy"); } my $command = "sitecopy -u drakbackup"; spawn_progress($command, "Running sitecopy..."); if ($log_buff =~ /Nothing to do - no changes found/) { show_warning("w", N_("WebDAV remote site already in sync!")); return(1); } if ($log_buff !~ /Update completed successfully/) { show_warning("f", N_("WebDAV transfer failed!")); return(1); } return(0); } sub rsync_client { $DEBUG and print "file list to send: $_\n " foreach @file_list_to_send_by_ftp; my $rsync_cmd = "rsync -tv $save_path/* "; $rsync_cmd = $rsync_cmd . "--password-file=$cfg_dir/rsync.user " if $passwd_user; $rsync_cmd = $rsync_cmd . "$login_user\@" if $login_user; $rsync_cmd = $rsync_cmd . "$host_name\:\:$host_path"; spawn_progress($rsync_cmd, "Running rsync"); return(0); } sub check_for_cd { #- check for a cd my $command = "cdrecord dev=$cd_device -atip"; spawn_progress($command, "Check for media in drive"); if ($log_buff =~ /No disk/) { show_warning("f", N_("No CDR/DVDR in drive!")); return(1); } if ($log_buff !~ /ATIP info from disk/) { show_warning("f", N_("Does not appear to be recordable media!")); return(1); } if ($log_buff =~ /Is not erasable/ && $media_erase) { show_warning("f", N_("Not erasable media!")); return(1); } if ($multi_session) { $command = "cdrecord dev=$cd_device -msinfo"; spawn_progress($command, "Check for previous session status"); #- if we don't find a previous session, start fresh if ($log_buff =~ /Cannot read session offset/) { $media_erase = 1; return(0); } else { #- extract the session info from $log_buff my $code_loc = rindex($log_buff, "msinfo") + 8; if ($code_loc != -1) { my $bufflen = length($log_buff); $session_offset = substr($log_buff, $code_loc, $bufflen-$code_loc-1); return(0); } return(1); } } } sub write_on_cd { my $command = "cdrecord -v dev=$cd_device -data "; #- only blank if it's the first session $command .= "blank=fast " if $media_erase && $session_offset eq ''; #- multi-session mode $command .= "-multi -pad " if $multi_session; $command .= "$save_path/drakbackup.iso"; spawn_progress($command, "Running cdrecord"); unlink("$save_path/drakbackup.iso"); } sub erase_cdrw { #- we can only hit this via interactive $interactive = 0; $in->ask_warn('', N("This may take a moment to erase the media.")); cursor_wait(); my $command = "cdrecord dev=$cd_device -blank=fast"; spawn_progress($command, "Erasing CDRW..."); cursor_norm(); $interactive = 1; } sub spawn_progress { my ($command, $descr) = @_; my $value; my $timer; $interactive and progress($pbar3, 0, translate($descr)); # $interactive and $pbar3->set_activity_mode(1); $interactive and $pbar3->set_fraction(0); $interactive and $timer = Gtk2->timeout_add(2, \&progress_timeout); $log_buff .= "\n" . $descr . ":\n"; $log_buff .= $command . "\n\n"; local *TMP; open TMP, "$command 2>&1 |"; while ($value = <TMP>) { $log_buff .= $value; if ($interactive) { $stext->set_text($value); gtkflush(); } } close TMP; # $interactive and $pbar3->set_activity_mode(0); $interactive and Gtk2->timeout_remove($timer); } sub progress_timeout { my $new_val; my $adj; $new_val = $pbar3->get_value() + 1; $adj = $pbar3->adjustment; $new_val = $adj->lower if $new_val > $adj->upper; $pbar3->set_fraction($new_val); return(1); } sub get_cd_device { my $check_device = "/dev/cdrom"; get_cd_info(); foreach (keys %cd_devices) { if ($cd_devices{$_}{rec_dev} eq $cd_device) { s/sr/scd/; $check_device = "/dev/" . $_; } } $check_device; } sub get_cd_volname { #- we want the volname for the catalog my $check_device = get_cd_device(); local *TMP; open TMP, "volname $check_device 2>&1 |"; local $_; while (<TMP>) { $vol_name = $_; } close TMP; $vol_name =~ s/[ \t]+\n$//; $vol_name; } sub build_iso { if ($multi_session && $session_offset) { $vol_name = get_cd_volname(); } else { $vol_name = "Drakbackup" . $the_time; } #this is safe to change the volname on rewrites, as is seems to get ignored anyway my $command = "mkisofs -r -J -T -v -V '$vol_name' "; $command .= "-C $session_offset -M $cd_device " if $multi_session && $session_offset; $command .= "-o $save_path/drakbackup.iso @file_list_to_send_by_ftp"; spawn_progress($command, "Running mkisofs..."); } sub build_cd { if (!check_for_cd()) { build_iso(); if ($log_buff =~ /Permission denied/) { show_warning("f", N_("Permission problem accessing CD.")); $media_problem = 1; return(1); } else { write_on_cd(); } } } sub get_tape_label { my ($device) = @_; cursor_wait(); system("mt -f $device rewind"); system("tar -C $cfg_dir -xf $device"); my @volname = cat_("$cfg_dir/drakbackup.label"); unlink("$cfg_dir/drakbackup.label"); $vol_name = $volname[0]; cursor_norm(); $vol_name; } sub build_tape { my $command; #- do we have a tape? $command = "mt -f $tape_device status"; spawn_progress($command, "Checking for tape"); if ($log_buff =~ /DR_OPEN/) { show_warning("f", N("No tape in %s!", $tape_device)); return(1); } #- try to roll to the end of the data if we're not erasing if (!$media_erase) { $command = "mt -f $tape_device rewind"; spawn_progress($command, "Rewind to find tape label"); $command = "tar -tf $tape_device"; spawn_progress($command, "Check for label"); if ($log_buff =~ /drakbackup.label/) { if ($tape_norewind) { $command = "mt -f $tape_device rewind"; spawn_progress($command, "Rewind to get tape label"); } $command = "tar -C $cfg_dir -xf $tape_device"; spawn_progress($command, "Reading tape label"); my @volname = cat_("$cfg_dir/drakbackup.label"); unlink("$cfg_dir/drakbackup.label"); $vol_name = $volname[0]; } $command = "mt -f $tape_device eod"; spawn_progress($command, "Running mt to find eod"); } else { $command = "mt -f $tape_device rewind"; spawn_progress($command, "Running mt to rewind"); # make a tape label for the catalog # if we're using the rewinding device, change modes briefly if (!$tape_norewind) { $tape_device =~ s/\/st/\/nst/; } $vol_name = "Drakbackup" . $the_time; my $f = "$cfg_dir/drakbackup.label"; output($f, $vol_name); $command = "tar -C $cfg_dir -cf $tape_device drakbackup.label;"; spawn_progress($command, "Creating tape label"); unlink $f; if (!$tape_norewind) { $tape_device =~ s/\/nst/\/st/; } } #- do the backup $command = "tar -cvf $tape_device @file_list_to_send_by_ftp"; spawn_progress($command, "Running tar to tape"); #- eject the tape? if ($media_eject) { $command = "mt -f $tape_device rewoff"; spawn_progress($command, "Running mt to eject tape"); } } # share this with logdrake sub send_mail { my ($result) = @_; my $datem = `date`; local *F; open F, "|/usr/sbin/sendmail -f$user_mail $user_mail" or return(1); print F "From: drakbackup\n"; print F "To: $user_mail \n"; print F "Subject: DrakBackup report on $datem \n"; print F "\n"; print F "$result\n"; close F or return(1); return(0); } sub build_backup_files { my $path_name; my $tar_cmd; my $more_recent; my $tar_cmd_sys; my $tar_cmd_user; my $tar_cmd_other; my $base_sys_exist = 0; my @list_other_; my @dir_content; local $_; $results = ""; $log_buff = ""; #- flush this so if the user does 2 runs in a row we don't try to send the same files @file_list_to_send_by_ftp = (); $interactive and cursor_wait(); read_conf_file(); the_time(); $send_mail and complete_results(); -d $save_path or mkdir_p($save_path); if ($comp_mode) { $DEBUG and $tar_cmd = "tar cv --use-compress-program /usr/bin/bzip2 "; $DEBUG or $tar_cmd = "tar c --use-compress-program /usr/bin/bzip2 "; $tar_ext = "tar.bz2"; } else { $DEBUG and $tar_cmd = "tar cvpz "; $DEBUG or $tar_cmd = "tar cpz "; $tar_ext = "tar.gz" } $tar_cmd_sys = $tar_cmd; $tar_cmd_user = $tar_cmd; $tar_cmd_other = $tar_cmd; $no_critical_sys and $tar_cmd_sys .= "--exclude passwd --exclude fstab --exclude group --exclude mtab"; $what_no_browser and $tar_cmd_user .= "--exclude NewCache --exclude Cache --exclude cache"; $nonroot_user and $tar_cmd_user .= " --exclude .drakbackup"; -d $save_path and @dir_content = all($save_path); grep(/^backup\_base\_sys/, @dir_content) and $base_sys_exist = 1; if ($where_hd && !$daemon || $daemon) { $interactive and progress($pbar, $plabel, 0.5, N("Backup system files...")); if ($backup_sys) { if ($backup_sys_versions) { #- 8/19/2002 - changed these greps to look at the list, rather than the tar file #- we retain the list for other media backups, but the tar file goes away, potentially if (grep /^list\_incr\_sys/, @dir_content) { my @more_recent = grep /^list\_incr\_sys/, sort @dir_content; $more_recent = pop @more_recent; $DEBUG and print "more recent file: $more_recent\n"; system("find @sys_files -cnewer $save_path/$more_recent \! -type d -print > $save_path/list_incr_sys$the_time.txt"); if (!cat_("$save_path/list_incr_sys$the_time.txt")) { system("rm $save_path/list_incr_sys$the_time.txt"); } else { system("$tar_cmd_sys -f $save_path/backup_incr_sys$the_time.$tar_ext -T $save_path/list_incr_sys$the_time.txt"); push @file_list_to_send_by_ftp, "$save_path/backup_incr_sys$the_time.$tar_ext"; push @file_list_to_send_by_ftp, "$save_path/list_incr_sys$the_time.txt"; $results .= "\nfile: $save_path/backup_incr_sys$the_time.$tar_ext\n"; $results .= cat_("$save_path/list_incr_sys$the_time.txt"); } } elsif (grep /^list_base\_sys/, @dir_content) { my @more_recent = grep /^list\_base\_sys/, sort @dir_content; $more_recent = pop @more_recent; $DEBUG and print "more recent file: $more_recent\n"; system("find @sys_files -cnewer $save_path/$more_recent \! -type d -print > $save_path/list_incr_sys$the_time.txt"); if (!cat_("$save_path/list_incr_sys$the_time.txt")) { system("rm $save_path/list_incr_sys$the_time.txt"); } else { system("$tar_cmd_sys -f $save_path/backup_incr_sys$the_time.$tar_ext -T $save_path/list_incr_sys$the_time.txt"); push @file_list_to_send_by_ftp, "$save_path/backup_incr_sys$the_time.$tar_ext"; push @file_list_to_send_by_ftp, "$save_path/list_incr_sys$the_time.txt"; $results .= "\nfile: $save_path/backup_incr_sys$the_time.$tar_ext\n"; $results .= cat_("$save_path/list_incr_sys$the_time.txt"); } } else { #- need this for the first pass too, if we're offloading the backups to other media (sb) system("find $path_name \! -type d -print > $save_path/list_base_sys$the_time.txt"); system("$tar_cmd_sys -f $save_path/backup_base_sys$the_time.$tar_ext @sys_files"); push @file_list_to_send_by_ftp, "$save_path/backup_base_sys$the_time.$tar_ext"; push @file_list_to_send_by_ftp, "$save_path/list_base_sys$the_time.txt"; $results .= "\nfile: $save_path/backup_base_sys$the_time.$tar_ext\n"; } } else { system("cd $save_path && rm -f backup_sys* backup_base_sys* backup_incr_sys*"); system("$tar_cmd_sys -f $save_path/backup_sys$the_time.$tar_ext @sys_files"); push @file_list_to_send_by_ftp, "$save_path/backup_sys$the_time.$tar_ext"; $results .= "\nfile: $save_path/backup_sys$the_time.$tar_ext\n"; } } $interactive and progress($pbar, $plabel, 0.5, N("Backup system files...")); $interactive and progress($pbar3, $plabel3, 0.3, N("Hard Disk Backup files...")); if (@list_other) { system("cd $save_path && rm -f backup_other* "); system("$tar_cmd_other -f $save_path/backup_other$the_time.$tar_ext @list_other"); push @file_list_to_send_by_ftp, "$save_path/backup_other$the_time.$tar_ext"; $results .= "\nfile: $save_path/backup_other$the_time.$tar_ext\n"; #old foreach (@list_other) { push @list_other_, $_ . "\n"; } @list_other_ = map { "$_\n" } @list_other; output_p($save_path . '/list_other', @list_other_); } $interactive and progress($pbar1, $plabel1, 1, N("Backup User files...")); $interactive and progress($pbar3, $plabel3, 0.3, N("Hard Disk Backup Progress...")); if ($backup_user) { foreach (@user_list) { my $user = $_; $path_name = return_path($user); if ($backup_user_versions) { #- 8/19/2002 - changed these greps to look at the list, rather than the tar file #- we retain the list for other media backups, but the tar file goes away, potentially if (grep(/^list\_incr\_user\_$user\_/, @dir_content)) { my @more_recent = grep /^list\_incr\_user\_$user\_/, sort @dir_content; $more_recent = pop @more_recent; $DEBUG and print "more recent file: $more_recent\n"; system("find $path_name -cnewer $save_path/$more_recent \! -type d -print > $save_path/list_incr_user_$user$the_time.txt"); if (!cat_("$save_path/list_incr_user_$user$the_time.txt")) { system("rm $save_path/list_incr_user_$user$the_time.txt"); } else { system("$tar_cmd_user -f $save_path/backup_incr_user_$user$the_time.$tar_ext -T $save_path/list_incr_user_$user$the_time.txt"); push @file_list_to_send_by_ftp, "$save_path/backup_incr_user_$user$the_time.$tar_ext"; push @file_list_to_send_by_ftp, "$save_path/list_incr_user_$user$the_time.txt"; $results .= " \nfile: $save_path/backup_incr_user_$user$the_time.$tar_ext\n"; $results .= cat_("$save_path/list_incr_user_$user$the_time.txt"); } } elsif (grep /^list\_base\_user\_$user\_/, @dir_content) { my @more_recent = grep /^list\_base\_user\_$user\_/, sort @dir_content; $more_recent = pop @more_recent; $DEBUG and print "more recent file: $more_recent\n"; system("find $path_name -cnewer $save_path/$more_recent \! -type d -print > $save_path/list_incr_user_$user$the_time.txt"); if (!cat_("$save_path/list_incr_user_$user$the_time.txt")) { system("rm $save_path/list_incr_user_$user$the_time.txt"); } else { system("$tar_cmd_user -f $save_path/backup_incr_user_$user$the_time.$tar_ext -T $save_path/list_incr_user_$user$the_time.txt"); push @file_list_to_send_by_ftp, "$save_path/backup_incr_user_$user$the_time.$tar_ext"; push @file_list_to_send_by_ftp, "$save_path/list_incr_user_$user$the_time.txt"; $results .= "\nfile: $save_path/backup_incr_user_$user$the_time.$tar_ext\n"; $results .= cat_("$save_path/list_incr_user_$user$the_time.txt"); } } else { #- need this for the first pass too, if we're offloading the backups to other media (sb) system("find $path_name \! -type d -print > $save_path/list_base_user_$user$the_time.txt"); system("$tar_cmd_user -f $save_path/backup_base_user_$user$the_time.$tar_ext $path_name"); push @file_list_to_send_by_ftp, "$save_path/backup_base_user_$user$the_time.$tar_ext"; push @file_list_to_send_by_ftp, "$save_path/list_base_user_$user$the_time.txt"; $results .= "\nfile: $save_path/backup_base_user_$user$the_time.$tar_ext\n"; } } else { system("cd $save_path && rm -f backup_user_$_* backup_base_user_$_* backup_incr_user_$_*"); system("$tar_cmd_user -f $save_path/backup_user_$_$the_time.$tar_ext $path_name"); push @file_list_to_send_by_ftp, "$save_path/backup_user_$_$the_time.$tar_ext"; $results .= "\nfile: $save_path/backup_user_$user$the_time.$tar_ext\n"; } } } $interactive and progress($pbar2, $plabel2, 1, N("Backup Other files...")); $interactive and progress($pbar3, $plabel3, 0.4, N("Hard Disk Backup files...")); } my $filecount = @file_list_to_send_by_ftp; if (!$filecount) { show_warning("w", N_("No changes to backup!")); $interactive and cursor_norm(); $interactive and interactive_mode(); return(1); } #- should hit this block if running daemon mode only if ($daemon && $daemon_media) { # ftp_client() if $ftp_daemon; rsync_client() if $daemon_media eq 'rsync'; ssh_client() if $daemon_media eq 'ssh' && !$use_expect; do_expect("backup") if $daemon_media eq 'ssh' && $use_expect; webdav_client() if $daemon_media eq 'webdav'; build_cd() if $daemon_media eq 'cd'; build_tape() if $daemon_media eq 'tape'; $results .= N("\nDrakbackup activities via %s:\n\n", $daemon_media); $results .= $log_buff; } #- leave this one alone for now - works well #- integrate with other methods later if (($where_net && !$daemon && $net_proto eq 'ftp') || $daemon && $daemon_media eq 'ftp') { $results .= N("file list sent by FTP: %s\n ", $_) foreach @file_list_to_send_by_ftp; $interactive and build_backup_ftp_status(); if (ftp_client()) { $results .= N("\n FTP connection problem: It was not possible to send your backup files by FTP.\n"); $interactive and client_ftp_pb(); } } #- consolidate all the other methods under here - interactive and --default should land here if (!$daemon) { if ($where_net && $net_proto && $net_proto ne 'ftp') { rsync_client() if $net_proto eq 'rsync'; ssh_client() if $net_proto eq 'ssh' && !$use_expect; do_expect("backup") if $net_proto eq 'ssh' && $use_expect; webdav_client() if $net_proto eq 'webdav'; $results .= N("\nDrakbackup activities via %s:\n\n", $net_proto); } if ($where_cd) { build_cd(); $results .= N("\nDrakbackup activities via CD:\n\n"); } if ($where_tape) { build_tape(); $results .= N("\nDrakbackup activities via tape:\n\n"); } $results .= $log_buff; } if ($send_mail) { if (send_mail($results)) { $interactive and send_mail_pb(); $interactive or print N(" Error while sending mail. \n"); } } #- write our catalog file if (!$media_problem) { my $catalog = substr($the_time, 1); if (!$where_net && !$where_tape && !$where_cd) { $catalog .= ":HD:localhost:$save_path"; $net_proto = ''; } $catalog .= ":$net_proto:$login_user\@$host_name:$host_path" if $net_proto; $catalog .= ":CD:$vol_name:$cd_device" if $where_cd; $catalog .= ":Tape:$vol_name:$tape_device" if $where_tape; $catalog .= ":System" if $backup_sys; $catalog .= ":I" if $backup_sys_versions && $backup_sys; $catalog .= ":F" if !$backup_sys_versions && $backup_sys; $catalog .= ":Users=(@user_list)" if $backup_user; $catalog .= ":I" if $backup_user_versions && $backup_user; $catalog .= ":F" if !$backup_user_versions && $backup_user; $catalog .= ":Other=(@list_other)" if @list_other; $catalog .= ":I" if $backup_other_versions && @list_other; $catalog .= ":F" if !$backup_other_versions && @list_other; $catalog .= "\n"; local *CATALOG; open(CATALOG, ">> $cfg_dir/drakbackup_catalog") || show_warning("w", N_("Can't create catalog!")); print CATALOG $catalog; close(CATALOG); } #- clean up HD files if del_hd_files and media isn't hd if ($del_hd_files && ($where_cd || $where_tape || $where_net) && $daemon_media ne 'hd') { foreach (@file_list_to_send_by_ftp) { # unlink($_) if (/$tar_ext$/) && (!/backup_base/); unlink($_) if /$tar_ext$/; } } #- if we had a media problem then get rid of the text log of the backed up files too if ($media_problem) { system("rm $save_path/list\*$the_time.txt"); } $interactive and cursor_norm(); $interactive and show_status(); } my @list_of_rpm_to_install; sub require_rpm { my $all_rpms_found = 1; my $res; # my @file_cache = cat_("/var/log/rpmpkgs"); @list_of_rpm_to_install = (); #- reverted to old method - /var/log/rpmpkgs is not always accurate # my($pkg) = @_; foreach my $pkg (@_) { # $res = grep /$pkg/, @file_cache; $res = system("rpm -q $pkg > /dev/null"); if ($res == 256) { $all_rpms_found = 0; push @list_of_rpm_to_install, $pkg; } } return($all_rpms_found); } sub check_pkg_needs { my $extra_pkg = ''; if ($where_net) { $extra_pkg = 'rsync' if $net_proto eq 'rsync'; $extra_pkg = 'sitecopy wget' if $net_proto eq 'webdav'; $extra_pkg = 'perl-Expect' if $net_proto eq 'ssh' && ($use_expect || $xfer_keys); } $extra_pkg = 'mt-st' if $where_tape; if ($extra_pkg) { if (require_rpm($extra_pkg)) { return(0); } else { #- this isn't entirely good, but it's the only way we get here currently #- was getting strange return behavior before #- still a problem, we can also get here from the cron screen install_rpm(\&advanced_where); return(1); } } } sub cursor_wait { # turn the cursor to a watch $window1->window->set_cursor(new Gtk2::Gdk::Cursor("GDK_WATCH")); gtkflush(); } sub cursor_norm { # restore normal cursor $window1->window->set_cursor(new Gtk2::Gdk::Cursor("GDK_LEFT_PTR")); gtkflush(); } sub show_status { #- just a generic routine to display an array of text in the GUI screen my $text = new Gtk2::TextView; destroy_widget(); my $scrolled_window = Gtk2::ScrolledWindow->new; $scrolled_window->set_border_width(10); $scrolled_window->add_with_viewport($text); gtktext_insert(gtkset_editable($text, 0), [ [ $results ] ]); gtkpack($advanced_box, $table = gtkpack_(new Gtk2::VBox(0,10), 1, $scrolled_window) ); $central_widget = \$table; $table->show_all(); } sub file_ok_sel { my ($file_selection) = @_; my $file_name = $file_selection->get_filename(); if (!member($file_name, @list_other)) { push(@list_other, $file_name); $list_other->add(gtkshow(new Gtk2::ListItem($file_name))); } } sub filedialog_where_hd { my $file_dialog; $file_dialog = gtksignal_connect(new Gtk2::FileSelection(N("File Selection")), destroy => sub { $file_dialog->destroy() }); $file_dialog->ok_button->signal_connect(clicked => sub { $save_path_entry->set_text($file_dialog->get_filename()); $file_dialog->destroy() }); $file_dialog->cancel_button->signal_connect(clicked => sub { $file_dialog->destroy() }); $file_dialog->show(); } sub filedialog_restore_find_path { my $file_dialog; $file_dialog = gtksignal_connect(new Gtk2::FileSelection(N("File Selection")), destroy => sub { $file_dialog->destroy() }); $file_dialog->ok_button->signal_connect(clicked => sub { $restore_find_path_entry->set_text($file_dialog->get_filename()); $file_dialog->destroy() }); $file_dialog->cancel_button->signal_connect(clicked => sub { $file_dialog->destroy() }); $file_dialog->show(); } sub filedialog_generic { #- a more generic file dialog #- a title prompt, the widget to get updated and the variable to update my ($prompt, $widget, $set_var) = @_; my $file_dialog; $file_dialog = gtksignal_connect(new Gtk2::FileSelection(translate($prompt)), destroy => sub { $file_dialog->destroy() }); $file_dialog->ok_button->signal_connect(clicked => sub { ${$set_var} = $file_dialog->get_filename(); ${$widget}->set_text(${$set_var}); $file_dialog->destroy() }); $file_dialog->cancel_button->signal_connect(clicked => sub { $file_dialog->destroy() }); $file_dialog->show(); } sub filedialog { my $file_dialog; $file_dialog = gtksignal_connect(new Gtk2::FileSelection(N("Select the files or directories and click on 'Add'")), destroy => sub { $file_dialog->destroy() }); $file_dialog->ok_button->signal_connect(clicked => sub { file_ok_sel($file_dialog) }); $file_dialog->cancel_button->signal_connect(clicked => sub { $file_dialog->destroy() }); $file_dialog->show(); } ################################################ ADVANCED ################################################ sub check_list { foreach (@_) { my $ref = $_->[1]; gtksignal_connect(gtkset_active($_->[0], ${$ref}), toggled => sub { invbool $ref; destroy_widget(); $current_widget->(); }); } } sub fonction_env { ($central_widget, $current_widget, $previous_widget, $custom_help, $next_widget) = @_; } sub advanced_what_sys { my $box_what_sys; gtkpack($advanced_box, $box_what_sys = gtkpack_(new Gtk2::VBox(0, 15), 1, N("\nPlease check all options that you need.\n"), 1, N("These options can backup and restore all files in your /etc directory.\n"), 0, my $check_what_sys = new Gtk2::CheckButton(N("Backup your System files. (/etc directory)")), 0, my $check_what_versions = new Gtk2::CheckButton(N("Use incremental backup (do not replace old backups)")), 0, my $check_what_critical = new Gtk2::CheckButton(N("Do not include critical files (passwd, group, fstab)")), 0, N("With this option you will be able to restore any version\n of your /etc directory."), 1, new Gtk2::VBox(0, 15), ), ); check_list([$check_what_sys, \$backup_sys], [$check_what_critical, \$no_critical_sys], [$check_what_versions, \$backup_sys_versions]); fonction_env(\$box_what_sys, \&advanced_what_sys, \&advanced_what, "what"); $up_box->show_all(); } sub advanced_what_user { my ($previous_function) = @_, my $box_what_user; my %check_what_user; all_user_list(); gtkpack($advanced_box, $box_what_user = gtkpack_(new Gtk2::VBox(0, 15), 0, N("Please check all users that you want to include in your backup."), 0, new Gtk2::HSeparator, 1, create_scrolled_window( gtkpack__(new Gtk2::VBox(0,0), map { my $name = $_; my @user_list_tmp; my $b = new Gtk2::CheckButton($name); if (grep /^$name$/, @user_list) { $check_what_user{$_}[1] = 1; gtkset_active($b, 1); } else { $check_what_user{$_}[1] = 0; gtkset_active($b, 0); } $b->signal_connect(toggled => sub { if ($check_what_user{$name}[1]) { $check_what_user{$name}[1] = 0; @user_list_tmp = grep(!/^$name$/, @user_list); @user_list = @user_list_tmp; } else { $check_what_user{$name}[1] = 1; if (!member($name, @user_list)) { push @user_list, $name } } }); $b } (@all_user_list) ), ), 0, my $check_what_browser = new Gtk2::CheckButton(N("Do not include the browser cache")), 0, my $check_what_user_versions = new Gtk2::CheckButton(N("Use Incremental Backups (do not replace old backups)")), ), ); check_list([$check_what_browser, \$what_no_browser], [$check_what_user_versions, \$backup_user_versions]); if ($previous_function) { fonction_env(\$box_what_user, \&advanced_what_user, \&$previous_function, "what", \&$previous_function) } else { fonction_env(\$box_what_user, \&advanced_what_user, \&advanced_what, "what") } $up_box->show_all(); } sub advanced_what_other { my $box_what_other; my $file_iter; my $iter = Gtk2::TreeIter->new; my $other_file; my @to_remove; my $list_model = Gtk2::ListStore->new(Gtk2::GType->STRING); my $list_other = Gtk2::TreeView->new_with_model($list_model); $list_other->append_column(Gtk2::TreeViewColumn->new_with_attributes(undef, Gtk2::CellRendererText->new, 'text' => 0)); $list_other->set_headers_visible(0); foreach (@list_other) { $list_model->append($iter); $list_model->set($iter, [ 0 => $_ ]); } $list_other->get_selection->signal_connect(changed => sub { my ($model, $iter) = $_[0]->get_selected; $model && $iter or return; $other_file = $model->get($iter, 0); $file_iter = $iter; }); gtkpack($advanced_box, $box_what_other = gtkpack_(new Gtk2::VBox(0, 15), 1, gtkpack_(new Gtk2::HBox(0,4), 1, create_scrolled_window($list_other), ), 0, gtkadd(gtkset_layout(new Gtk2::HButtonBox, 'spread'), gtksignal_connect(new Gtk2::Button(N("Add")), clicked => sub { filedialog() }), gtksignal_connect(new Gtk2::Button(N("Remove Selected")), clicked => sub { $list_model->remove($file_iter); push @to_remove, $other_file; splice @list_other, $_, 1 foreach reverse sort @to_remove; }), ), 0, gtkset_sensitive(my $check_what_other_versions = new Gtk2::CheckButton(N("Use Incremental Backups (do not replace old backups)")), 0), ), ); check_list([$check_what_other_versions, \$backup_other_versions]); fonction_env(\$box_what_other, \&advanced_what_other, \&advanced_what, "what"); $up_box->show_all(); } sub advanced_what_entire_sys { my $box_what; gtkpack($advanced_box, $box_what = gtkpack_(new Gtk2::HBox(0, 15), 1, new Gtk2::VBox(0, 5), 1, gtkpack_(new Gtk2::VBox(0, 15), 1, new Gtk2::VBox(0, 5), 1, gtksignal_connect(my $button_what_other = new Gtk2::Button(), clicked => sub { destroy_widget(); message_underdevel() }), 1, gtksignal_connect(my $button_what_all = new Gtk2::Button(), clicked => sub { destroy_widget(); message_underdevel() }), 1, new Gtk2::VBox(0, 5), ), 1, new Gtk2::VBox(0, 5), ), ); $button_what_other->add(gtkpack(new Gtk2::HBox(0,10), gtkcreate_img("bootloader"), new Gtk2::Label(N("Linux")), new Gtk2::HBox(0, 5) )); $button_what_all->add(gtkpack(new Gtk2::HBox(0,10), gtkcreate_img("user"), new Gtk2::Label(N("Windows (FAT32)")), new Gtk2::HBox(0, 5) )); fonction_env(\$box_what, \&advanced_what_entire_sys, \&advanced_what, ""); $up_box->show_all(); } sub advanced_what { my $box_what; gtkpack($advanced_box, $box_what = gtkpack_(new Gtk2::HBox(0, 15), 1, new Gtk2::VBox(0, 5), 1, gtkpack_(new Gtk2::VBox(0, 15), 1, new Gtk2::VBox(0, 5), 1, gtksignal_connect(my $button_what_sys = new Gtk2::Button(), clicked => sub { $box_what->destroy(); advanced_what_sys() }), 1, gtksignal_connect(my $button_what_user = new Gtk2::Button(), clicked => sub { destroy_widget(); advanced_what_user() }), 1, gtksignal_connect(my $button_what_other = new Gtk2::Button(), clicked => sub { destroy_widget(); advanced_what_other() }), # 1, gtksignal_connect(my $button_what_all = new Gtk2::Button(), # clicked => sub { destroy_widget(); advanced_what_entire_sys(); }), 1, new Gtk2::VBox(0, 5), ), 1, new Gtk2::VBox(0, 5), ), ); $button_what_sys->add(gtkpack(new Gtk2::HBox(0,10), gtkcreate_img("ic82-system-40"), new Gtk2::Label(N("System")), new Gtk2::HBox(0, 5) )); $button_what_user->add(gtkpack(new Gtk2::HBox(0,10), gtkcreate_img("ic82-users-40"), new Gtk2::Label(N("Users")), new Gtk2::HBox(0, 5) )); $button_what_other->add(gtkpack(new Gtk2::HBox(0,10), gtkcreate_img("ic82-others-40"), new Gtk2::Label(N("Other")), new Gtk2::HBox(0, 5) )); # $button_what_all->add(gtkpack(new Gtk2::HBox(0,10), # gtkcreate_img("ic82-systemeplus-40"), # new Gtk2::Label(N("An Entire System")), # new Gtk2::HBox(0, 5) # )); fonction_env(\$box_what, \&advanced_what, \&advanced_box, ""); $up_box->show_all(); } sub advanced_where_net_types { my ($previous_function) = @_, my $box_where_net; gtkpack($advanced_box, $box_where_net = gtkpack_(new Gtk2::VBox(0, 10), 0, new Gtk2::HSeparator, 0, gtkpack_(new Gtk2::HBox(0,10), 0, my $check_where_use_net = new Gtk2::CheckButton(N("Use network connection to backup")), 1, new Gtk2::HBox(0,10), 0, new Gtk2::Label(N("Net Method:")), 0, gtkset_sensitive(my $entry_net_type = new Gtk2::Combo(), $where_net), ), 0, gtkpack_(new Gtk2::HBox(0,5), 0, gtkset_sensitive(my $check_use_expect = new Gtk2::CheckButton(N("Use Expect for SSH")), ($where_net && $net_proto eq 'ssh')), 0, gtkset_sensitive(my $check_xfer_keys = new Gtk2::CheckButton(N("Create/Transfer\nbackup keys for SSH")), ($where_net && $net_proto eq 'ssh')), 0, gtkset_sensitive(my $button_xfer_keys = new Gtk2::Button(N(" Transfer \nNow")), $xfer_keys), 0, gtkset_sensitive(my $check_user_keys = new Gtk2::CheckButton(N("Other (not drakbackup)\nkeys in place already")), ($where_net && $net_proto eq 'ssh')), ), 0, new Gtk2::HSeparator, 0, gtkpack_(new Gtk2::HBox(0,10), 0, gtkset_sensitive(new Gtk2::Label(N("Please enter the host name or IP.")), $where_net), 1, new Gtk2::HBox(0,10), 0, gtkset_sensitive(my $host_name_entry = new Gtk2::Entry(), $where_net), ), 0, gtkpack_(new Gtk2::HBox(0,10), 0, gtkset_sensitive(new Gtk2::Label(N("Please enter the directory (or module) to\n put the backup on this host.")), $where_net), 1, new Gtk2::HBox(0,10), 0, gtkset_sensitive(my $host_path_entry = new Gtk2::Entry(), $where_net), ), 0, gtkpack_(new Gtk2::HBox(0,10), 0, gtkset_sensitive(new Gtk2::Label(N("Please enter your login")), $where_net), 1, new Gtk2::HBox(0,10), 0, gtkset_sensitive(my $login_user_entry = new Gtk2::Entry(), $where_net), ), 0, gtkpack_(new Gtk2::HBox(0,10), 0, gtkset_sensitive(new Gtk2::Label(N("Please enter your password")), $where_net), 1, new Gtk2::HBox(0,10), 0, gtkset_sensitive(my $passwd_user_entry = new Gtk2::Entry(), $where_net), ), 0, gtkpack_(new Gtk2::HBox(0,10), 1, new Gtk2::HBox(0,10), 0, gtkset_sensitive(my $check_remember_pass = new Gtk2::CheckButton(N("Remember this password")), $where_net), ), ), ); $entry_net_type->set_popdown_strings(@net_methods); $entry_net_type->entry->set_text($net_proto); $entry_net_type->entry->set_property('editable', 0); $button_xfer_keys->signal_connect('clicked', sub { if ($passwd_user && $login_user && $host_name) { do_expect("sendkey"); } else { $in->ask_warn('', N("Need hostname, username and password!")); } }); $passwd_user_entry->set_visibility(0); $passwd_user_entry->set_text($passwd_user); $passwd_user_entry->signal_connect('changed', sub { $passwd_user = $passwd_user_entry->get_text() }); $host_path_entry->set_text($host_path); $host_name_entry->set_text($host_name); $login_user_entry->set_text($login_user); $host_name_entry->signal_connect('changed', sub { $host_name = $host_name_entry->get_text() }); $host_path_entry->signal_connect('changed', sub { $host_path = $host_path_entry->get_text() }); $login_user_entry->signal_connect('changed', sub { $login_user = $login_user_entry->get_text() }); $entry_net_type->entry->signal_connect('changed', sub { $net_proto = $entry_net_type->entry->get_text(); my $sensitive = 0; $sensitive = 1 if $net_proto eq 'ssh'; $check_use_expect->set_sensitive($sensitive); $check_xfer_keys->set_sensitive($sensitive); $button_xfer_keys->set_sensitive($sensitive); $check_user_keys->set_sensitive($sensitive); }); check_list([$check_remember_pass, \$remember_pass]); gtksignal_connect(gtkset_active($check_where_use_net, $where_net), toggled => sub { invbool \$where_net; #- assure other methods disabled if ($where_net eq 1) { $where_cd = 0; $where_tape = 0; } $net_proto = '' if $where_net eq 0; destroy_widget(); $current_widget->(); }); gtksignal_connect(gtkset_active($check_use_expect, $use_expect), toggled => sub { invbool \$use_expect; #- assure other methods disabled if ($use_expect eq 1) { $xfer_keys = 0; $user_keys = 0; } destroy_widget(); $current_widget->(); }); gtksignal_connect(gtkset_active($check_xfer_keys, $xfer_keys), toggled => sub { invbool \$xfer_keys; #- assure other methods disabled if ($xfer_keys eq 1) { $use_expect = 0; $user_keys = 0; } destroy_widget(); $current_widget->(); }); gtksignal_connect(gtkset_active($check_user_keys, $user_keys), toggled => sub { invbool \$user_keys; #- assure other methods disabled if ($user_keys eq 1) { $xfer_keys = 0; $use_expect = 0; } destroy_widget(); $current_widget->(); }); if ($previous_function) { fonction_env(\$box_where_net, \&advanced_where_net_types, \&$previous_function, "net"); } else { fonction_env(\$box_where_net, \&advanced_where_net_types, \&advanced_where, "net"); } $up_box->show_all(); } sub advanced_where_cd { my ($previous_function) = @_; my $box_where_cd; get_cd_info(); my $combo_where_cd_device = new Gtk2::Combo(); $combo_where_cd_device->set_popdown_strings(sort keys %cd_devices) if keys %cd_devices; my $combo_where_cd_time = new Gtk2::Combo(); $combo_where_cd_time->set_popdown_strings("650 Mb", "700 Mb", "750 Mb", "800 Mb"); my $combo_where_cdrecord_device = new Gtk2::Combo(); my @dev_codes; foreach my $key (keys %cd_devices) { push(@dev_codes, $cd_devices{$key}{rec_dev}); } $combo_where_cdrecord_device->set_popdown_strings(@dev_codes) if keys %cd_devices; gtkpack($advanced_box, $box_where_cd = gtkpack_(new Gtk2::VBox(0, 6), 0, my $check_where_cd = new Gtk2::CheckButton(N("Use CD/DVDROM to backup")), 0, new Gtk2::HSeparator, 0, gtkpack_(new Gtk2::HBox(0,10), 0, gtkset_sensitive(new Gtk2::Label(N("Please choose your CD/DVD device\n(Press Enter to propogate settings to other fields.\nThis field isn't necessary, only a tool to fill in the form.)")), $where_cd), 1, new Gtk2::VBox(0, 5), 0, gtkset_sensitive(gtkset_size_request($combo_where_cd_device, 200, 20), $where_cd), ), 0, gtkpack_(new Gtk2::HBox(0,10), 0, gtkset_sensitive(new Gtk2::Label(N("Please choose your CD/DVD media size (Mb)")), $where_cd), 1, new Gtk2::VBox(0, 5), 0, gtkset_sensitive(gtkset_size_request($combo_where_cd_time, 200, 20), $where_cd), ), 0, new Gtk2::VBox(0, 5), 0, gtkpack_(new Gtk2::HBox(0,10), 0, gtkset_sensitive(new Gtk2::Label(N("Please check for multisession CD")), $where_cd), 1, new Gtk2::VBox(0, 5), 0, gtkset_sensitive(my $check_multisession = new Gtk2::CheckButton(), $where_cd), ), 0, new Gtk2::VBox(0, 5), 0, gtkpack_(new Gtk2::HBox(0,10), 0, gtkset_sensitive(new Gtk2::Label(N("Please check if you are using CDRW media")), $where_cd), 1, new Gtk2::VBox(0, 5), 0, gtkset_sensitive(my $check_cdrw = new Gtk2::CheckButton(), $where_cd), ), 0, new Gtk2::VBox(0, 5), 0, gtkpack_(new Gtk2::HBox(0,10), 0, gtkset_sensitive(new Gtk2::Label(N("Please check if you want to erase your RW media (1st Session)")), $cdrw && $where_cd), 0, gtkset_sensitive(my $button_erase_now = new Gtk2::Button(N(" Erase Now ")), $cdrw), 1, new Gtk2::VBox(0, 5), 0, gtkset_sensitive(my $check_cdrw_erase = new Gtk2::CheckButton(), $cdrw && $where_cd), ), 0, new Gtk2::VBox(0, 5), 0, gtkpack_(new Gtk2::HBox(0,10), 0, gtkset_sensitive(new Gtk2::Label(N("Please check if you are using a DVDR device")), $where_cd), 1, new Gtk2::VBox(0, 5), 0, gtkset_sensitive(my $check_dvdr = new Gtk2::CheckButton(), $where_cd), ), 0, new Gtk2::VBox(0, 5), 0, gtkpack_(new Gtk2::HBox(0,10), 0, gtkset_sensitive(new Gtk2::Label(N("Please check if you are using a DVDRAM device")), $where_cd), 1, new Gtk2::VBox(0, 5), 0, gtkset_sensitive(my $check_dvdram = new Gtk2::CheckButton(), $where_cd), ), # don't know what this is about - hold off for now (SB) # 0, new Gtk2::VBox(0, 5), # 0, gtkpack_(new Gtk2::HBox(0,10), # 0, gtkset_sensitive(new Gtk2::Label(N("Please check if you want to include\n install boot on your CD.")), $where_cd), # 1, new Gtk2::VBox(0, 5), # 0, gtkset_sensitive(my $check_cd_with_install_boot = new Gtk2::CheckButton(), $where_cd), # ), 0, new Gtk2::VBox(0, 5), 0, gtkpack_(new Gtk2::HBox(0,10), 0, gtkset_sensitive(new Gtk2::Label(N("Please enter your CD Writer device name\n ex: 0,1,0")), $where_cd), 1, new Gtk2::VBox(0, 5), # 0, gtkset_size_request(gtkset_sensitive($cd_device_entry = new Gtk2::Entry(), $where_cd), 200, 20), 0, gtkset_sensitive(gtkset_size_request($combo_where_cdrecord_device, 200, 20), $where_cd), ), ), ); # foreach ([$check_cdrw_erase, \$media_erase], [$check_cd_with_install_boot, \$cd_with_install_boot ]) { foreach ([$check_cdrw_erase, \$media_erase], [$check_dvdr, \$dvdr], [$check_dvdram, \$dvdram], [$check_multisession, \$multi_session]) { my $ref = $_->[1]; gtksignal_connect(gtkset_active($_->[0], ${$ref}), toggled => sub { ${$ref} = ${$ref} ? 0 : 1 }) } gtksignal_connect(gtkset_active($check_where_cd, $where_cd), toggled => sub { $where_cd = $where_cd ? 0 : 1; #- toggle where_net, where_tape off if ($where_cd eq 1) { $where_net = 0; $where_tape = 0; } destroy_widget(); $current_widget->(); }); gtksignal_connect(gtkset_active($check_cdrw, $cdrw), toggled => sub { $cdrw = $cdrw ? 0 : 1; $check_cdrw_erase->set_sensitive($cdrw); destroy_widget(); $current_widget->(); }); $button_erase_now->signal_connect('clicked', sub { if ($cd_device) { erase_cdrw(); } else { $in->ask_warn('', N("No CD device defined!")); } }); $combo_where_cdrecord_device->entry->set_text($cd_device); $combo_where_cdrecord_device->entry->signal_connect('changed', sub { $cd_device = $combo_where_cdrecord_device->entry->get_text() }); $combo_where_cd_time->entry->set_text($cd_time); $combo_where_cd_time->entry->signal_connect('changed', sub { $cd_time = $combo_where_cd_time->entry->get_text() }); #- this one drives changes in the other entries #- still not getting quite the desired behavior, but combo box signals seem to be limited #- tried to trigger from the selection, but it either does nothing or crashes! #- $combo_where_cd_device->entry->set_text($std_device); $combo_where_cd_device->entry->signal_connect('activate', sub { $std_device = $combo_where_cd_device->entry->get_text(); $combo_where_cdrecord_device->entry->set_text($cd_devices{$std_device}{rec_dev}); $check_dvdr->set_active($cd_devices{$std_device}{dvdr}); $check_dvdram->set_active($cd_devices{$std_device}{dvdram}); #- do this one last or the widget destory mucks up the others $check_cdrw->set_active($cd_devices{$std_device}{cdrw}); }); if ($previous_function) { fonction_env(\$box_where_cd, \&advanced_where_cd, \&$previous_function, ""); } else { fonction_env(\$box_where_cd, \&advanced_where_cd, \&advanced_where, ""); } $up_box->show_all(); } sub advanced_where_tape { my ($previous_function) = @_, #- look for tape devices; get_tape_info(); my $combo_where_tape_device = new Gtk2::Combo(); $combo_where_tape_device->set_popdown_strings(@tape_devices) if @tape_devices; my $box_where_tape; my $adj = new Gtk2::Adjustment(550.0, 1.0, 10000.0, 1.0, 5.0, 0.0); #my ($pix_fs_map, $pix_fs_mask) = gtkcreate_img("filedialog"); local $_; my $spinner; gtkpack($advanced_box, $box_where_tape = gtkpack_(new Gtk2::VBox(0, 6), 0, new Gtk2::HSeparator, 0, my $check_where_tape = new Gtk2::CheckButton(N("Use tape to backup")), 0, new Gtk2::HSeparator, 0, gtkpack_(new Gtk2::HBox(0,10), 0, gtkset_sensitive(new Gtk2::Label(N("Please enter the device name to use for backup")), $where_tape), 1, new Gtk2::VBox(0, 6), 0, gtkset_sensitive(gtkset_size_request($combo_where_tape_device, 200, 20), $where_tape), ), 0, new Gtk2::VBox(0, 5), 0, gtkpack_(new Gtk2::HBox(0,10), 0, gtkset_sensitive(new Gtk2::Label(N("Please check if you want to use the non-rewinding device.")), $where_tape), 1, new Gtk2::VBox(0, 5), 0, gtkset_sensitive(my $check_tape_rewind = new Gtk2::CheckButton(), $where_tape), ), 0, new Gtk2::VBox(0, 5), 0, gtkpack_(new Gtk2::HBox(0,10), 0, gtkset_sensitive(new Gtk2::Label(N("Please check if you want to erase your tape before the backup.")), $where_tape), 1, new Gtk2::VBox(0, 5), 0, gtkset_sensitive(my $check_tape_erase = new Gtk2::CheckButton(), $where_tape), ), 0, new Gtk2::VBox(0, 5), 0, gtkpack_(new Gtk2::HBox(0,10), 0, gtkset_sensitive(new Gtk2::Label(N("Please check if you want to eject your tape after the backup.")), $where_tape), 1, new Gtk2::VBox(0, 5), 0, gtkset_sensitive(my $check_tape_eject = new Gtk2::CheckButton(), $where_tape), ), 0, new Gtk2::VBox(0, 6), 0, gtkpack_(new Gtk2::HBox(0,10), 0, gtkset_sensitive(new Gtk2::Label(N("Please enter the maximum size\n allowed for Drakbackup")), $where_tape), 1, new Gtk2::VBox(0, 6), 0, gtkset_size_request(gtkset_sensitive($spinner = new Gtk2::SpinButton($adj, 0, 0), $where_tape), 200, 20), ), 0, gtkpack_(new Gtk2::HBox(0,10),), ), ); gtksignal_connect(gtkset_active($check_where_tape, $where_tape), toggled => sub { $where_tape = $where_tape ? 0 : 1; #- assure other methods are off if ($where_tape eq 1) { $where_net = 0; $where_cd = 0; } destroy_widget(); $current_widget->(); }); gtksignal_connect(gtkset_active($check_tape_rewind, $tape_norewind), toggled => sub { $tape_norewind = $tape_norewind ? 0 : 1; $_ = $tape_device; if ($tape_norewind) { $tape_device =~ s/\/st/\/nst/; } else { $tape_device =~ s/\/nst/\/st/; } $combo_where_tape_device->entry->set_text($tape_device); destroy_widget(); $current_widget->(); }); gtksignal_connect(gtkset_active($check_tape_erase, $media_erase), toggled => sub { $media_erase = $media_erase ? 0 : 1; destroy_widget(); $current_widget->(); }); gtksignal_connect(gtkset_active($check_tape_eject, $media_eject), toggled => sub { $media_eject = $media_eject ? 0 : 1; destroy_widget(); $current_widget->(); }); $combo_where_tape_device->entry->set_text($tape_device); $combo_where_tape_device->entry->signal_connect('changed', sub { $tape_device = $combo_where_tape_device->entry->get_text(); }); if ($previous_function) { fonction_env(\$box_where_tape, \&advanced_where_tape, \&$previous_function, ""); } else { fonction_env(\$box_where_tape, \&advanced_where_tape, \&advanced_where, ""); } $up_box->show_all(); } sub advanced_where_hd { my ($previous_function) = @_, my $box_where_hd; my $button; my $adj = new Gtk2::Adjustment(550.0, 1.0, 10000.0, 1.0, 5.0, 0.0); my $spinner; gtkpack($advanced_box, $box_where_hd = gtkpack_(new Gtk2::VBox(0, 6), 0, new Gtk2::HSeparator, # 0, my $check_where_hd = new Gtk2::CheckButton( N("Use Hard Disk to backup")), # 0, new Gtk2::HSeparator, 0, gtkpack_(new Gtk2::HBox(0,10), 0, gtkset_sensitive(new Gtk2::Label(N("Please enter the directory to save to:")), $where_hd), 1, new Gtk2::VBox(0, 6), 0, gtkset_size_request(gtkset_sensitive($save_path_entry = new Gtk2::Entry(), $where_hd), 152, 20), 0, gtkset_sensitive($button = gtksignal_connect(new Gtk2::Button(), clicked => sub { filedialog_where_hd() }), $where_hd), ), 0, new Gtk2::VBox(0, 6), 0, gtkpack_(new Gtk2::HBox(0,10), 0, gtkset_sensitive(new Gtk2::Label(N("Please enter the maximum size\n allowed for Drakbackup")), $where_hd), 1, new Gtk2::VBox(0, 6), 0, gtkset_size_request(gtkset_sensitive($spinner = new Gtk2::SpinButton($adj, 0, 0), $where_hd), 200, 20), ), 0, gtkpack_(new Gtk2::HBox(0,10), 1, new Gtk2::VBox(0, 6), 0, gtkset_sensitive(my $check_where_hd_quota = new Gtk2::CheckButton(N("Use quota for backup files.")), $where_hd), 0, new Gtk2::VBox(0, 6), ), ), ); foreach ([$check_where_hd_quota, \$hd_quota]) { my $ref = $_->[1]; gtksignal_connect(gtkset_active($_->[0], ${$ref}), toggled => sub { ${$ref} = ${$ref} ? 0 : 1 }) } # gtksignal_connect(gtkset_active($check_where_hd, $where_hd), toggled => sub { # $where_hd = $where_hd ? 0 : 1; # $where_hd = 1; # destroy_widget(); # $current_widget->(); # }); $button->add(gtkpack(new Gtk2::HBox(0,10), gtkcreate_img("ic82-dossier-32"))); $save_path_entry->set_text($save_path); $save_path_entry->signal_connect('changed', sub { $save_path = $save_path_entry->get_text() }); if ($previous_function) { fonction_env(\$box_where_hd, \&advanced_where_hd, \&$previous_function, ""); } else { fonction_env(\$box_where_hd, \&advanced_where_hd, \&advanced_where, ""); } $up_box->show_all(); } sub advanced_where { my $box_where; gtkpack($advanced_box, $box_where = gtkpack_(new Gtk2::HBox(0, 15), 1, new Gtk2::VBox(0, 5), 1, gtkpack_(new Gtk2::VBox(0, 15), 1, new Gtk2::VBox(0, 5), 1, gtksignal_connect(my $button_where_net = new Gtk2::Button(), clicked => sub { destroy_widget(); advanced_where_net_types(); }), 1, gtksignal_connect(my $button_where_cd = new Gtk2::Button(), clicked => sub { destroy_widget(); if (require_rpm("mkisofs", "cdrecord")) { advanced_where_cd(); } else { destroy_widget(); install_rpm(\&advanced_where); } }), 1, gtksignal_connect(my $button_where_hd = new Gtk2::Button(), clicked => sub { destroy_widget(); advanced_where_hd(); }), 1, gtksignal_connect(my $button_where_tape = new Gtk2::Button(), clicked => sub { destroy_widget(); # message_underdevel(); advanced_where_tape() }), 1, new Gtk2::VBox(0, 5), ), 1, new Gtk2::VBox(0, 5), ), ); $button_where_net->add(gtkpack(new Gtk2::HBox(0,10), gtkcreate_img("ic82-network-40"), new Gtk2::Label(N("Network")), new Gtk2::HBox(0, 5) )); $button_where_cd->add(gtkpack(new Gtk2::HBox(0,10), gtkcreate_img("ic82-CD-40"), new Gtk2::Label(N("CDROM / DVDROM")), new Gtk2::HBox(0, 5) )); $button_where_hd->add(gtkpack(new Gtk2::HBox(0,10), gtkcreate_img("ic82-discdurwhat-40"), new Gtk2::Label(N("HardDrive / NFS")), new Gtk2::HBox(0, 5) )); $button_where_tape->add(gtkpack(new Gtk2::HBox(0,10), gtkcreate_img("ic82-tape-40"), new Gtk2::Label(N("Tape")), new Gtk2::HBox(0, 5) )); fonction_env(\$box_where, \&advanced_where, \&advanced_box, ""); $up_box->show_all(); } #- 7/7/2002 - S.Benedict reworked when - drop all the checkboxes and use a list #- chances that we want to do backups via multiple medias in cron are slim sub advanced_when { my $box_when; # $daemon_media = ''; my $combo_when_space = new Gtk2::Combo(); my %trans = (N("hourly") => 'hourly', N("daily") => 'daily', N("weekly") => 'weekly', N("monthly") => 'monthly'); my %trans2 = ('hourly' => N("hourly"), 'daily' => N("daily"), 'weekly' => N("weekly"), 'monthly' => N("monthly")); $combo_when_space->set_popdown_strings(N("hourly"), N("daily"), N("weekly"), N("monthly")); #- drop down list of possible medias - default to config value my $entry_media_type = new Gtk2::Combo(); $entry_media_type->set_popdown_strings(@media_types, @net_methods); # $entry_media_type->set_value_in_list(1, 0); $entry_media_type->entry->set_text($daemon_media); gtkpack($advanced_box, $box_when = gtkpack_(new Gtk2::VBox(0, 15), 0, gtkpack_(new Gtk2::HBox(0,10), 1, new Gtk2::HBox(0,10), 1, gtkcreate_img("ic82-when-40"), 0, my $check_when_daemon = new Gtk2::CheckButton(N("Use daemon")), 1, new Gtk2::HBox(0,10), ), 0, new Gtk2::HSeparator, 0, gtkpack_(new Gtk2::HBox(0,10), 0, gtkset_sensitive(new Gtk2::Label(N("Please choose the time \ninterval between each backup")), $backup_daemon), 1, new Gtk2::HBox(0,10), 0, gtkset_sensitive($combo_when_space, $backup_daemon), ), 0, new Gtk2::HBox(0,10), 0, gtkpack_(new Gtk2::HBox(0,10), 0, gtkset_sensitive(new Gtk2::Label(N("Please choose the\nmedia for backup.")), $backup_daemon), 1, new Gtk2::HBox(0,10), 0, gtkpack_(new Gtk2::VBox(0,10), 0, gtkset_sensitive($entry_media_type, $backup_daemon), ), ), 0, new Gtk2::HSeparator, 1, gtkset_sensitive(new Gtk2::Label(N("Please be sure that the cron daemon is included in your services. \nNote that currently all 'net' medias also use the hard drive.")), $backup_daemon), ), ); gtksignal_connect(gtkset_active($check_when_daemon, $backup_daemon), toggled => sub { $backup_daemon = $backup_daemon ? 0 : 1; destroy_widget(); advanced_when(); }); $combo_when_space->entry->set_text($trans2{$when_space}); $combo_when_space->entry->signal_connect('changed', sub { $when_space = $trans{$combo_when_space->entry->get_text()} }); $entry_media_type->entry->signal_connect('changed', sub { $daemon_media = $entry_media_type->entry->get_text(); }); fonction_env(\$box_when, \&advanced_when, \&advanced_box, ""); $up_box->show_all(); } sub advanced_options { my $box_options; gtkpack($advanced_box, $box_options = gtkpack_(new Gtk2::VBox(0, 15), # 0, gtkpack_(new Gtk2::HBox(0,10), # 1, new Gtk2::VBox(0,10), # 1, gtkcreate_img("ic82-moreoption-40"), # 1, N("Please choose correct options to backup."), # 1, new Gtk2::VBox(0,10), # ), # 0, new Gtk2::HSeparator, # 0, gtkpack_(new Gtk2::VBox(0,10), # 0, gtkset_sensitive(my $check_tar_bz2 = new Gtk2::CheckButton( N("Use Tar and bzip2 (very slow) [Please be careful if you\n (un)select this option, as all your old backups will be deleted.]")), 0), # 0, gtkset_sensitive(my $check_backupignore = new Gtk2::CheckButton( N("Use .backupignore files")), 0), 0, new Gtk2::VBox(0,10), 0, gtkpack_(new Gtk2::HBox(0,10), 0, my $check_mail = new Gtk2::CheckButton(N("Send mail report after each backup to:")), 1, new Gtk2::HBox(0,10), 0, my $mail_entry = new Gtk2::Entry(), ), # ), 0, gtkpack_(new Gtk2::HBox(0,10), 0, my $check_del_hd_files = new Gtk2::CheckButton(N("Delete Hard Drive tar files after backup to other media.")), ), ), ); check_list([$check_mail, \$send_mail], [$check_del_hd_files, \$del_hd_files]); # check_list([$check_mail, \$send_mail], [$check_tar_bz2, \$comp_mode], [$check_backupignore, \$backupignore]); $mail_entry->set_text($user_mail); $mail_entry->signal_connect('changed', sub { $user_mail = $mail_entry->get_text() }); fonction_env(\$box_options, \&advanced_options, \&advanced_box, "options"); $up_box->show_all(); } sub advanced_box { my $box_adv; gtkpack($advanced_box, $box_adv = gtkpack_(new Gtk2::HBox(0, 15), 1, new Gtk2::VBox(0, 5), 1, gtkpack_(new Gtk2::VBox(0, 15), 1, new Gtk2::VBox(0, 5), 1, gtksignal_connect(my $button_what = new Gtk2::Button(), clicked => sub { destroy_widget(); advanced_what() }), 1, gtksignal_connect(my $button_where = new Gtk2::Button(), clicked => sub { destroy_widget(); advanced_where() }), 1, gtksignal_connect(my $button_when = new Gtk2::Button(), clicked => sub { destroy_widget(); advanced_when() }), 1, gtksignal_connect(my $button_options = new Gtk2::Button(), clicked => sub { destroy_widget(); advanced_options() }), 1, new Gtk2::VBox(0, 5), ), 1, new Gtk2::VBox(0, 5), ), ); $button_what->add(gtkpack(new Gtk2::HBox(0,10), gtkcreate_img("ic82-discdurwhat-40"), new Gtk2::Label(N("What")), new Gtk2::HBox(0, 5) )); $button_where->add(gtkpack(new Gtk2::HBox(0,10), gtkcreate_img("ic82-where-40"), new Gtk2::Label(N("Where")), new Gtk2::HBox(0, 5) )); $button_when->add(gtkpack(new Gtk2::HBox(0,10), gtkcreate_img("ic82-when-40"), new Gtk2::Label(N("When")), new Gtk2::HBox(0, 5) )); $button_options->add(gtkpack(new Gtk2::HBox(0,10), gtkcreate_img("ic82-moreoption-40"), new Gtk2::Label(N("More Options")), new Gtk2::HBox(0, 5) )); fonction_env(\$box_adv, \&advanced_box, \&interactive_mode_box, ""); $up_box->show_all(); } ################################################ WIZARD ################################################ sub wizard_step3 { my $box2; my $text = new Gtk2::TextView; save_conf_file(); read_conf_file(); system_state(); gtktext_insert($text, [ [ $system_state ] ]); button_box_restore_main(); gtkpack($advanced_box, $box2 = gtkpack_(new Gtk2::HBox(0, 15), 1, gtkpack_(new Gtk2::VBox(0,10), 0, N("Drakbackup Configuration"), 1, create_scrolled_window($text), ), ), ); fonction_env(\$box2, \&wizard_step3, \&wizard_step2, ""); button_box_wizard_end(); $up_box->show_all(); } sub wizard_step2 { my $box2; gtkpack($advanced_box, $box2 = gtkpack_(new Gtk2::HBox(0, 15), 1, new Gtk2::VBox(0, 5), 1, gtkpack_(new Gtk2::VBox(0, 15), 1, new Gtk2::VBox(0, 5), 0, N("Please choose where you want to backup"), 0, gtkpack_(new Gtk2::HBox(0, 15), 0, my $check_wizard_hd = new Gtk2::CheckButton(N("on Hard Drive")), 1, new Gtk2::VBox(0, 5), 0, gtkset_sensitive(gtksignal_connect(new Gtk2::Button(N("Configure")), clicked => sub { destroy_widget(); to_ok(); advanced_where_hd(\&wizard_step2); to_normal(); }), $where_hd), ), 0, gtkpack_(new Gtk2::HBox(0, 15), 0, my $check_wizard_net = new Gtk2::CheckButton(N("across Network")), 1, new Gtk2::VBox(0, 5), 0, gtkset_sensitive(gtksignal_connect(new Gtk2::Button(N("Configure")), clicked => sub { destroy_widget(); to_ok(); advanced_where_net_types(\&wizard_step2); to_normal(); }), $where_net), ), 0, gtkpack_(new Gtk2::HBox(0, 15), 0, my $check_wizard_cd = new Gtk2::CheckButton(N("on CDROM")), 1, new Gtk2::VBox(0, 5), 0, gtkset_sensitive(gtksignal_connect(new Gtk2::Button(N("Configure")), clicked => sub { destroy_widget(); advanced_where_cd(\&wizard_step2); }), $where_cd), ), 0, gtkpack_(new Gtk2::HBox(0, 15), 0, my $check_wizard_tape = new Gtk2::CheckButton(N("on Tape Device")), 1, new Gtk2::VBox(0, 5), 0, gtkset_sensitive(gtksignal_connect(new Gtk2::Button(N("Configure")), clicked => sub { destroy_widget(); advanced_where_tape(\&wizard_step2); }), $where_tape), ), 1, new Gtk2::VBox(0, 5), ), 1, new Gtk2::VBox(0, 5), ), ); foreach ([$check_wizard_hd, \$where_hd], [$check_wizard_cd, \$where_cd], [$check_wizard_tape, \$where_tape], [$check_wizard_net, \$where_net]) { my $ref = $_->[1]; gtksignal_connect(gtkset_active($_->[0], ${$ref}), toggled => sub { ${$ref} = ${$ref} ? 0 : 1; $where_hd = 1; if (!$where_hd && !$where_cd && !$where_net) { $next_widget = \&message_noselect_box } else { $next_widget = \&wizard_step3 } destroy_widget(); wizard_step2(); }) } if (!$where_hd && !$where_cd && !$where_net) { fonction_env(\$box2, \&wizard_step2, \&wizard, "", \&message_noselect_box) } else { fonction_env(\$box2, \&wizard_step2, \&wizard, "", \&wizard_step3) } button_box_wizard(); $up_box->show_all(); } sub wizard { my $box2; gtkpack($advanced_box, $box2 = gtkpack_(new Gtk2::HBox(0, 15), 1, new Gtk2::VBox(0, 5), 1, gtkpack_(new Gtk2::VBox(0, 15), 1, new Gtk2::VBox(0, 5), 0, N("Please choose what you want to backup"), 0, my $check_wizard_sys = new Gtk2::CheckButton(N("Backup system")), 0, my $check_wizard_user = new Gtk2::CheckButton(N("Backup Users")), 0, gtkpack_(new Gtk2::HBox(0, 15), 1, new Gtk2::VBox(0, 5), 0, gtksignal_connect(new Gtk2::Button(N("Select user manually")), clicked => sub { destroy_widget(); advanced_what_user(\&wizard); }), ), 1, new Gtk2::VBox(0, 5), ), 1, new Gtk2::VBox(0, 5), ), ); foreach ([$check_wizard_sys, \$backup_sys], [$check_wizard_user, \$backup_user]) { my $ref = $_->[1]; gtksignal_connect(gtkset_active($_->[0], ${$ref}), toggled => sub { ${$ref} = ${$ref} ? 0 : 1; if ($backup_sys || $backup_user && @user_list) { $next_widget = \&wizard_step2 } else { $next_widget = \&message_noselect_what_box } }) } if ($backup_sys || $backup_user && @user_list) { fonction_env(\$box2, \&wizard, \&interactive_mode_box, "", \&wizard_step2) } else { fonction_env(\$box2, \&wizard, \&interactive_mode_box, "", \&message_noselect_what_box) } button_box_wizard(); $up_box->show_all(); } ################################################ RESTORE ################################################ sub find_backup_to_restore { my @list_backup; my @list_backup_tmp2; my $to_put; @sys_backuped = (); local $_; @user_backuped = (); -d $path_to_find_restore and @list_backup_tmp2 = all($path_to_find_restore); foreach (@list_backup_tmp2) { s/\_base//gi; s/\_incr//gi; push @list_backup , $_; } if (grep /^backup_other/, @list_backup) { $other_backuped = 1 } if (grep /^backup_sys/, @list_backup) { $sys_backuped = 1 } foreach (grep /^backup_sys_/, @list_backup) { chomp; s/^backup_sys_//gi; s/.tar.gz$//gi; s/.tar.bz2$//gi; my ($date, $heure) = /^(.*)_([^_]*)$/; my $year = substr($date, 0, 4); my $month = substr($date, 4, 2); my $day = substr($date, 6, 2); my $hour = substr($heure, 0, 2); my $min = substr($heure, 2, 2); $to_put = "$day/$month/$year $hour:$min $_"; push @sys_backuped , $to_put; } $restore_step_sys_date = $to_put; foreach (grep /^backup_user_/, @list_backup) { chomp; s/^backup_user_//gi; s/.tar.gz$//gi; s/.tar.bz2$//gi; my ($nom, $date, $heure) = /^(.*)_([^_]*)_([^_]*)$/; my $year = substr($date, 0, 4); my $month = substr($date, 4, 2); my $day = substr($date, 6, 2); my $hour = substr($heure, 0, 2); my $min = substr($heure, 2, 2); # my $to_put = " $nom, (date: $date, hour: $heure)"; $to_put = "$_ user: $nom, date: $day/$month/$year, hour: $hour:$min"; push @user_backuped , $to_put; grep(/^$nom$/, @user_list_backuped) or push @user_list_backuped, $nom; } } sub system_state { $system_state; if ($cfg_file_exist) { $system_state .= N("\nBackup Sources: \n"); $backup_sys and $system_state .= N("\n- System Files:\n"); $backup_sys and $system_state .= "\t\t$_\n" foreach @sys_files; $backup_user and $system_state .= N("\n- User Files:\n"); $backup_user and $system_state .= "\t\t$_\n" foreach @user_list; @list_other and $system_state .= N("\n- Other Files:\n"); @list_other and $system_state .= "\t\t$_\n" foreach @list_other; $where_hd and $system_state .= N("\n- Save on Hard drive on path: %s\n", $save_path); if ($del_hd_files && ($where_cd || $where_tape || $where_net) && $daemon_media ne 'hd') { $system_state .= N("\n- Delete hard drive tar files after backup.\n"); } #- tape and CDRW share some features my $erase_media = 'NO'; $erase_media = 'YES' if $media_erase && ($where_cd || $where_tape); $where_cd and $system_state .= N("\n- Burn to CD"); $where_cd and $cdrw and $system_state .= N("RW"); $where_cd and $system_state .= N(" on device: %s", $cd_device); $where_cd and $multi_session and $system_state .= N(" (multi-session)"); $where_tape and $system_state .= N("\n- Save to Tape on device: %s", $tape_device); (($where_cd || $where_tape) && $media_erase) and $system_state .= N("\t\tErase=%s", $erase_media); $where_cd || $where_tape and $system_state .= "\n"; $where_net and $system_state .= N("\n- Save via %s on host: %s\n", $net_proto, $host_name); $where_net and $system_state .= N("\t\t user name: %s\n\t\t on path: %s \n", $login_user, $host_path); $system_state .= N("\n- Options:\n"); $backup_sys or $system_state .= N("\tDo not include System Files\n"); if ($comp_mode) { $system_state .= N("\tBackups use tar and bzip2\n"); } else { $system_state .= N("\tBackups use tar and gzip\n"); } $daemon_media and $system_state .= N("\n- Daemon (%s) include:\n", $when_space); $daemon_media eq 'hd' and $system_state .= N("\t-Hard drive.\n"); $daemon_media eq 'cd' and $system_state .= N("\t-CDROM.\n"); $daemon_media eq 'tape' and $system_state .= N("\t-Tape \n"); $daemon_media eq 'ftp' and $system_state .= N("\t-Network by FTP.\n"); $daemon_media eq 'ssh' and $system_state .= N("\t-Network by SSH.\n"); $daemon_media eq 'rsync' and $system_state .= N("\t-Network by rsync.\n"); $daemon_media eq 'webdav' and $system_state .= N("\t-Network by webdav.\n"); } else { $system_state = N("No configuration, please click Wizard or Advanced.\n"); } } sub restore_state { my @tmp = split(' ', $restore_step_sys_date); $restore_state = N("List of data to restore:\n\n"); if ($restore_sys) { $restore_state .= "- Restore System Files.\n"; $restore_state .= " - from date: $tmp[0] $tmp[1]\n"; } if ($restore_user) { $restore_state .= "- Restore User Files: \n"; $restore_state .= "\t\t$_\n" foreach @user_list_to_restore2; push @user_list_to_restore, (split(',', $_))[0] foreach @user_list_to_restore2; } if ($restore_other) { $restore_state .= "- Restore Other Files: \n"; -f "$path_to_find_restore/list_other" and $restore_state .= "\t\t$_\n" foreach split("\n", cat_("$path_to_find_restore/list_other")); } if ($restore_other_path) { $restore_state .= "- Path to Restore: $restore_path \n"; } } sub select_most_recent_selected_of { my ($user_name) = @_; my @list_tmp2; local $_; my @tmp = sort @user_list_to_restore2; foreach (grep /$user_name\_/, sort @tmp) { push @list_tmp2 , $_ } return pop @list_tmp2; } sub select_user_data_to_restore { my $var_eq = 1; my @list_backup; my @list_tmp; my @list_tmp2; @user_list_to_restore = (); local $_; -d $path_to_find_restore and my @list_backup_tmp2 = grep /^backup/, all($path_to_find_restore); @list_tmp2 = @list_backup_tmp2; foreach (@list_backup_tmp2) { s/\_base//gi; s/\_incr//gi; push @list_backup , $_; } foreach my $var_tmp (@user_list_backuped) { $var_eq = 1; my $more_recent = (split(' ', select_most_recent_selected_of($var_tmp)))[0]; foreach (grep /^backup\_user\_$var_tmp\_/, sort @list_backup) { s/.tar.gz//gi; s/.tar.bz2//gi; if ($more_recent) { if (/$more_recent/) { push @list_tmp , $_; $var_eq = 0; } else { #- only if user asked for it - previously this was restoring everything (SB) my $tmp_name = $_; s/backup\_user\_//gi; foreach my $buff (@user_list_to_restore2) { if (index($buff, $_) >= 0) { $var_eq and push @list_tmp , $tmp_name; } } } } } } foreach my $var_to_restore (@list_tmp) { $var_to_restore =~ s/backup_//gi; foreach my $var_exist (sort @list_tmp2) { if ($var_exist =~ /$var_to_restore/) { push @user_list_to_restore, $var_exist; } } } $DEBUG and print "real user list to restore: $_ \n" foreach @user_list_to_restore; } sub select_sys_data_to_restore { my $var_eq = 1; my @list_tmp; local $_; -d $path_to_find_restore and @list_tmp = grep /^backup/, all($path_to_find_restore); my @more_recent = split(' ', $restore_step_sys_date); my $more_recent = pop @more_recent; foreach my $var_exist (grep /\_sys\_/, sort @list_tmp) { if ($var_exist =~ /$more_recent/) { push @sys_list_to_restore, $var_exist; $var_eq = 0; } else { $var_eq and push @sys_list_to_restore, $var_exist; } } $DEBUG and print "sys list to restore: $_\n " foreach @sys_list_to_restore; } sub show_backup_details { my ($function, $mode, $name) = @_; my $archive_file_detail; my $value; # dies in gtk2 # my $fixed_font = Gtk2::Gdk::Font->load("-misc-fixed-medium-r-*-*-*-100-*-*-*-*-*-*"); my $command2; my $tarfile; # FIXME - only tar.gz at the moment my $extension = ".tar.gz"; if ($mode eq "user") { #- we've only got a partial filename in this case $tarfile = "$path_to_find_restore/backup_*" . $name . $extension; } if ($mode eq "sys") { #- funky string here we need to use to reconstruct the filename my @flist = split(/[ \t,]+/, $name); $tarfile = "$path_to_find_restore/backup_*" . $flist[2] . $extension; } my $command1 = "stat " . $tarfile; $command2 = "tar -tzvf " . $tarfile; local *TMP; open TMP, "$command1 2>&1 |"; while ($value = <TMP>) { $archive_file_detail .= $value; } close TMP; $archive_file_detail .= "\n\n"; open TMP, "$command2 2>&1 |"; while ($value = <TMP>) { #- drop the permissions display for the sake of readability $archive_file_detail .= substr($value, 11); } close TMP; my $text = new Gtk2::Text; my $advanced_box_archive; $text->insert_text($archive_file_detail, 0); gtkpack($advanced_box, $advanced_box_archive = gtkpack_(new Gtk2::VBox(0,10), 1, gtkpack_(new Gtk2::HBox(0,0), 1, $text, 0, new Gtk2::VScrollbar($text->vadj), ), 0, gtkadd(gtkset_layout(new Gtk2::HButtonBox, 'spread'), gtksignal_connect(new Gtk2::Button(N("Done")), clicked => sub { destroy_widget(); $function->() }), ), ) ); $central_widget = \$advanced_box_archive; $up_box->show_all(); } sub valid_backup_test { my (@files_list) = @_; @files_corrupted = (); my $is_corrupted = 0; foreach (@files_list) { #- let's quiet this down (SB) if (system("gzip -l $path_to_find_restore/$_ > /dev/null 2>&1") > 1) { push @files_corrupted, $_; $is_corrupted = -1; } } return $is_corrupted; } sub restore_aff_backup_problems { my $do_restore; my $text = new Gtk2::TextView; my $restore_pbs_state = N("List of data corrupted:\n\n"); $restore_pbs_state .= "\t\t$_\n" foreach @files_corrupted; $restore_pbs_state .= N("Please uncheck or remove it on next time."); gtktext_insert($text, [ [ $restore_pbs_state ] ]); button_box_restore_main(); gtkpack($advanced_box, $do_restore = gtkpack_(new Gtk2::VBox(0,10), 0, new Gtk2::VBox(0,10), 1, gtkpack_(new Gtk2::HBox(0, 15), 1, new Gtk2::VBox(0, 5), 0, gtkcreate_img('warning'), 0, N("Backup files are corrupted"), 1, new Gtk2::VBox(0, 5), ), 0, new Gtk2::VBox(0,10), 1, create_scrolled_window($text), ), ); button_box_restore_pbs_end(); fonction_env(\$do_restore, \&restore_aff_backup_problems, "", "restore_pbs"); $up_box->show_all(); } sub restore_aff_result { my $do_restore; my $text = new Gtk2::TextView; gtktext_insert($text, [ [ $restore_state ] ]); button_box_restore_main(); gtkpack($advanced_box, $do_restore = gtkpack_(new Gtk2::VBox(0,10), 1, new Gtk2::VBox(0,10), 0, N(" All of your selected data have been "), 0, N(" Successfuly Restored on %s ", $restore_path), 1, new Gtk2::VBox(0,10), ), ); button_box_build_backup_end(); $central_widget = \$do_restore; $up_box->show_all(); } sub return_path { my ($username) = @_; my $usr; my $home_dir; my $passwdfile = "/etc/passwd"; local *PASSWD; open(PASSWD, $passwdfile) or exit 1; while (defined(my $line = <PASSWD>)) { chomp($line); ($usr, $home_dir) = (split(/:/, $line))[0,5]; last if $usr eq $username; } close(PASSWD); return $home_dir; } sub restore_backend { my $untar_cmd; my $exist_problem = 0; my $user_dir; my $tnom; my $username; my $theure2; local $_; if (grep /tar.gz$/, all($path_to_find_restore)) { $untar_cmd = 0; } else { $untar_cmd = 1; } if ($restore_user) { select_user_data_to_restore(); if (valid_backup_test(@user_list_to_restore) == -1) { $exist_problem = 1; restore_aff_backup_problems(); } else { foreach (@user_list_to_restore) { if ($backup_user_versions) { ($tnom, $username, $theure2) = /^(\w+\_\w+\_user_)(.*)_(\d+\_\d+.*)$/; } else { ($tnom, $username, $theure2) = /^(\w+\_user_)(.*)_(\d+\_\d+.*)$/; } $user_dir = return_path($username); -d $user_dir and rm_rf($user_dir) if $remove_user_before_restore; $DEBUG and print "user name to restore: $username, user directory: $user_dir\n"; $untar_cmd or system(" tar xfz $path_to_find_restore/$_ -C $restore_path"); $untar_cmd and system("/usr/bin/bzip2 -cd $path_to_find_restore/$_ | tar xf -C $restore_path "); } #- flush this out for another cycle (SB) @user_list_to_restore2 = (); } } if ($restore_sys) { if ($backup_sys_versions) { select_sys_data_to_restore(); if (valid_backup_test(@sys_list_to_restore) == -1) { $exist_problem = 1; restore_aff_backup_problems(); } else { $untar_cmd or system("tar xfz $path_to_find_restore/$_ -C $restore_path ") foreach @sys_list_to_restore; $untar_cmd and system("/usr/bin/bzip2 -cd $path_to_find_restore/$_ | tar xf -C $restore_path ") foreach @sys_list_to_restore; } } else { $untar_cmd or system("tar xfz $path_to_find_restore/backup_sys.tar.gz -C $restore_path "); $untar_cmd and system("/usr/bin/bzip2 -cd $path_to_find_restore/backup_sys.tar.bz2 | tar xf -C $restore_path "); } } if ($restore_other) { $untar_cmd or system("tar xfz $path_to_find_restore/backup_other.tar.gz -C $restore_path "); $untar_cmd and system("/usr/bin/bzip2 -cd $path_to_find_restore/backup_other.tar.bz2 | tar xf -C $restore_path "); } $exist_problem or restore_aff_result(); } sub restore_do { if ($backup_bef_restore) { if ($restore_sys) { $backup_sys = 1; } else { $backup_sys = 0; } if ($restore_user) { $backup_user = 1; @user_list = @user_list_to_restore; } else { $backup_user = 0; } build_backup_status(); read_conf_file(); build_backup_files(); $table->destroy(); } restore_do2(); } sub restore_do2 { my $do_restore; my $text = new Gtk2::TextView; restore_state(); gtktext_insert($text, [ [ $restore_state ] ]); button_box_restore_main(); gtkpack($advanced_box, $do_restore = gtkpack_(new Gtk2::VBox(0,10), 0, N(" Restore Configuration "), 1, create_scrolled_window($text), ), ); button_box_restore_end(); fonction_env(\$do_restore, \&restore_do2, \&restore_box, "restore"); $up_box->show_all(); } sub restore_step_other { my $retore_step_other; my $text = new Gtk2::TextView; my $other_rest = cat_("$path_to_find_restore/list_other"); gtktext_insert($text, [ [ $other_rest ] ]); gtkpack($advanced_box, $retore_step_other = gtkpack_(new Gtk2::VBox(0,10), 1, new Gtk2::VBox(0,10), 1, create_scrolled_window($text), 0, my $check_restore_other_sure = new Gtk2::CheckButton(N("OK to restore the other files.")), 1, new Gtk2::VBox(0,10), ), ); check_list([$check_restore_other_sure, \$restore_other]); fonction_env(\$retore_step_other, \&restore_step_other, \&restore_step2, "restore", \&restore_do); $up_box->show_all(); } my %check_user_to_restore; sub restore_step_user { my $retore_step_user; my @tmp_list = sort @user_backuped; @user_backuped = @tmp_list; gtkpack($advanced_box, $retore_step_user = gtkpack_(new Gtk2::VBox(0,10), 0, new Gtk2::VBox(0,10), 0, N("User list to restore (only the most recent date per user is important)"), 1, create_scrolled_window(gtkpack__(new Gtk2::VBox(0,0), map { my $name; my $var2; my $name_complet = $_; $name = (split(' ', $name_complet))[0]; my @user_list_tmp; my $restore_row = new Gtk2::HBox(0,5); my $b = new Gtk2::CheckButton($name_complet); my $details = new Gtk2::Button(" Details "); $restore_row->pack_start($b, 1, 1, 0); $restore_row->pack_end(new Gtk2::VBox(1,5), 0, 0, 0); $restore_row->pack_end($details, 0, 0, 0); # this doesn't work - I don't understand why - but you end up with # everything selected when you hit the screen a second time, after selecting one # if (grep $name_complet, @user_list_to_restore2) { # gtkset_active($b, 1); # $check_user_to_restore{$name_complet}[1] = 1; # } else { # gtkset_active($b, 0); # $check_user_to_restore{$name_complet}[1] = 0; # } # this doesn't work right either - returning to the screen only 1 is selected # yet several are scheduled to be restored foreach (@user_list_to_restore2) { if ($name_complet eq $_) { gtkset_active($b, 1); $check_user_to_restore{$name_complet}[1] = 1; } else { gtkset_active($b, 0); $check_user_to_restore{$name_complet}[1] = 0; } } $b->signal_connect(toggled => sub { if (!$check_user_to_restore{$name_complet}[1]) { $check_user_to_restore{$name_complet}[1] = 1; if (!grep(/$name/, @user_list_to_restore2)) { push @user_list_to_restore2, $name_complet } } else { $check_user_to_restore{$name_complet}[1] = 0; foreach (@user_list_to_restore2) { $var2 = (split(' ', $_))[0]; if ($name ne $var2) { push @user_list_tmp, $_; } } @user_list_to_restore2 = @user_list_tmp; } }); $details->signal_connect('clicked', sub { #- we're only passing a portion of the filename to #- the subroutine so we need to let it know this destroy_widget(); show_backup_details(\&restore_step_user, "user", $name); }); $restore_row } (@user_backuped) ), ), ), ); if ($restore_other) { fonction_env(\$retore_step_user, \&restore_step_user, "", "restore", \&restore_step_other) } elsif ($restore_sys) { fonction_env(\$retore_step_user, \&restore_step_user, \&restore_step_sys, "restore", \&restore_step_other) } else { fonction_env(\$retore_step_user, \&restore_step_user, \&restore_step2, "restore", \&restore_do) } $up_box->show_all(); } sub restore_step_sys { my $restore_step_sys; my $check_backup_before; my $combo_restore_step_sys = new Gtk2::Combo(); $combo_restore_step_sys->set_popdown_strings(@sys_backuped); gtkpack($advanced_box, $restore_step_sys = gtkpack_(new Gtk2::VBox(0,10), 1, new Gtk2::VBox(0,10), 0, $check_backup_before = new Gtk2::CheckButton(N("Backup the system files before:")), 0, gtkpack_(new Gtk2::HBox(0,10), 1, N("please choose the date to restore"), 0, $combo_restore_step_sys, 0, my $details = new Gtk2::Button(" Details "), 0, new Gtk2::HBox(0,10), ), 1, new Gtk2::VBox(0,10), ), ); $combo_restore_step_sys->entry->signal_connect('changed', sub { $restore_step_sys_date = $combo_restore_step_sys->entry->get_text(); }); $details->signal_connect('clicked', sub { #- we're only passing a portion of the filename to #- the subroutine so we need to let it know this my $backup_date = $combo_restore_step_sys->entry->get_text(); destroy_widget(); show_backup_details(\&restore_step_sys, "sys", $backup_date); }); $combo_restore_step_sys->entry->set_text($restore_step_sys_date); fonction_env(\$restore_step_sys, \&restore_step_sys, \&restore_step2, "restore"); if ($restore_user) { fonction_env(\$restore_step_sys, \&restore_step_sys, \&restore_step2, "restore", \&restore_step_user) } elsif ($restore_other) { fonction_env(\$restore_step_sys, \&restore_step_sys, \&restore_step2, "restore", \&restore_step_other) } else { fonction_env(\$restore_step_sys, \&restore_step_sys, \&restore_step2, "restore", \&restore_do) } $up_box->show_all(); } sub restore_other_media_hd { my ($previous_function) = @_, my $box_where_hd; my $button; my $adj = new Gtk2::Adjustment(550.0, 1.0, 10000.0, 1.0, 5.0, 0.0); my $spinner; gtkpack($advanced_box, $box_where_hd = gtkpack_(new Gtk2::VBox(0, 6), 0, new Gtk2::HSeparator, 0, my $check_where_hd = new Gtk2::CheckButton(N("Use Hard Disk to backup")), 0, new Gtk2::HSeparator, 0, gtkpack_(new Gtk2::HBox(0,10), 0, gtkset_sensitive(new Gtk2::Label(N("Please enter the directory to save:")), $where_hd), 1, new Gtk2::VBox(0, 6), 0, gtkset_size_request(gtkset_sensitive($save_path_entry = new Gtk2::Entry(), $where_hd), 152, 20), 0, gtkset_sensitive($button = gtksignal_connect(new Gtk2::Button(), clicked => sub { filedialog_where_hd() }), $where_hd), ), 0, new Gtk2::VBox(0, 6), 0, gtkpack_(new Gtk2::HBox(0,10), 0, gtkset_sensitive(new Gtk2::Label(N("Please enter the maximum size\n allowed for Drakbackup")), $where_hd), 1, new Gtk2::VBox(0, 6), 0, gtkset_size_request(gtkset_sensitive($spinner = new Gtk2::SpinButton($adj, 0, 0), $where_hd), 200, 20), ), 0, gtkpack_(new Gtk2::HBox(0,10), 1, new Gtk2::VBox(0, 6), 0, gtkset_sensitive(my $check_where_hd_quota = new Gtk2::CheckButton(N("Use quota for backup files.")), $where_hd), 0, new Gtk2::VBox(0, 6), ), ), ); check_list([$check_where_hd_quota, \$hd_quota]); gtksignal_connect(gtkset_active($check_where_hd, $where_hd), toggled => sub { $where_hd = $where_hd ? 0 : 1; destroy_widget(); $current_widget->(); }); $button->add(gtkpack(new Gtk2::HBox(0,10), gtkcreate_img("ic82-dossier-32"))); $save_path_entry->set_text($save_path); $save_path_entry->signal_connect('changed', sub { $save_path = $save_path_entry->get_text() }); if ($previous_function) { fonction_env(\$box_where_hd, \&advanced_where_hd, \&$previous_function, "") } else { fonction_env(\$box_where_hd, \&advanced_where_hd, \&advanced_where, "") } $up_box->show_all(); } sub restore_other_media { my $box_find_restore; my $button; gtkpack($advanced_box, $box_find_restore = gtkpack_(new Gtk2::VBox(0, 6), 0, new Gtk2::HSeparator, 0, my $check_other_media_hd = new Gtk2::CheckButton(N("Restore from Hard Disk.")), 0, gtkpack_(new Gtk2::HBox(0,10), 0, gtkset_sensitive(new Gtk2::Label(N("Please enter the directory where backups are stored")), $other_media_hd), 1, new Gtk2::VBox(0, 6), 0, gtkset_size_request(gtkset_sensitive($restore_find_path_entry = new Gtk2::Entry(), $other_media_hd), 152, 20), 0, gtkset_sensitive($button = gtksignal_connect(new Gtk2::Button(), clicked => sub { filedialog_restore_find_path(); }), $other_media_hd), ), 1, new Gtk2::VBox(0, 6), # 0, new Gtk2::HSeparator, # 0, my $check_other_media_net = new Gtk2::CheckButton( N("Restore from Network")), # 0, new Gtk2::VBox(0, 6), # 1, gtkpack(new Gtk2::HBox(0,10), # new Gtk2::VBox(0, 6), # gtkset_sensitive(gtksignal_connect(new Gtk2::Button("Network"), clicked => sub { # destroy_widget(); # restore_find_net(\&restore_other_media);}), !$other_media_hd), # new Gtk2::VBox(0, 6), # ), # 1, new Gtk2::VBox(0, 6), # 0, new Gtk2::HSeparator, 0, new Gtk2::VBox(0, 6), ), ); gtksignal_connect(gtkset_active($check_other_media_hd, $other_media_hd), toggled => sub { $other_media_hd = $other_media_hd ? 0 : 1; destroy_widget(); $current_widget->(); }); # gtksignal_connect(gtkset_active($check_other_media_net, !$other_media_hd), toggled => sub { # $other_media_hd = $other_media_hd ? 0 : 1; # destroy_widget(); # $current_widget->(); # }); $button->add(gtkpack(new Gtk2::HBox(0,10), gtkcreate_img("ic82-dossier-32"))); $restore_find_path_entry->set_text($path_to_find_restore); $restore_find_path_entry->signal_connect('changed', sub { $path_to_find_restore = $restore_find_path_entry->get_text() }); #- not sure if this was the original intent - address the crash at "Next" fonction_env(\$box_find_restore, \&restore_other_media, \&restore_step2, "other_media", \&restore_do); $up_box->show_all(); } sub restore_step2 { my $retore_step2; my $other_exist; my $sys_exist; my $user_exist; local $_; my $restore_info_path = $save_path; $restore_info_path = $path_to_find_restore if $where_hd || $where_cd; my $info_prefix = "backup"; $info_prefix = "list" if $where_net || $where_tape; if (-f "$restore_info_path/$info_prefix\_other*") { $other_exist = 1 } else { $other_exist = 0; $restore_other = 0 } if (grep /\_sys\_/, grep /^$info_prefix/, all("$restore_info_path/")) { $sys_exist = 1 } else { $sys_exist = 0; $restore_sys = 0 } if (grep /\_user\_/, grep /^$info_prefix/, all("$restore_info_path/")) { $user_exist = 1 } else { $user_exist = 0; $restore_user = 0 } # disabling this (sb) - very nicely wipes out your backup media if the user isn't very careful # cycling through the GUI turns it back on for you!!! # $backup_sys_versions || $backup_user_versions and $backup_bef_restore = 1; gtkpack($advanced_box, $retore_step2 = gtkpack_(new Gtk2::VBox(0,10), 1, new Gtk2::VBox(0,10), 1, new Gtk2::VBox(0,10), 0, gtkpack_(new Gtk2::HBox(0,10), 0, my $check_restore_other_src = new Gtk2::CheckButton(N("Select another media to restore from")), 1, new Gtk2::HBox(0,10), 0, gtkset_sensitive(gtksignal_connect(new Gtk2::Button(N("Other Media")), clicked => sub { destroy_widget(); restore_other_media(); }), $restore_other_src), ), 0, gtkset_sensitive(my $check_restore_sys = new Gtk2::CheckButton(N("Restore system")), $sys_exist), 0, gtkset_sensitive(my $check_restore_user = new Gtk2::CheckButton(N("Restore Users")), $user_exist), 0, gtkset_sensitive(my $check_restore_other = new Gtk2::CheckButton(N("Restore Other")), $other_exist), 0, gtkpack_(new Gtk2::HBox(0,10), 0, my $check_restore_other_path = new Gtk2::CheckButton(N("select path to restore (instead of /)")), 1, new Gtk2::HBox(0,10), 0, gtkset_sensitive(my $restore_path_entry = new Gtk2::Entry(), $restore_other_path), ), 0, gtkset_sensitive(my $check_backup_bef_restore = new Gtk2::CheckButton(N("Do new backup before restore (only for incremental backups.)")), $backup_sys_versions || $backup_user_versions), 0, gtkset_sensitive(my $check_remove_user_dir = new Gtk2::CheckButton(N("Remove user directories before restore.")), $user_exist), 1, new Gtk2::VBox(0,10), ), ); foreach ([$check_restore_sys, \$restore_sys], [$check_backup_bef_restore, \$backup_bef_restore], [$check_restore_user, \$restore_user], [$check_remove_user_dir, \$remove_user_before_restore], [$check_restore_other, \$restore_other]) { my $ref = $_->[1]; gtksignal_connect(gtkset_active($_->[0], ${$ref}), toggled => sub { ${$ref} = ${$ref} ? 0 : 1; if (!$restore_sys && !$restore_user && !$restore_other) { $next_widget = \&message_norestore_box } elsif ($restore_sys && $backup_sys_versions) { $next_widget = \&restore_step_sys } elsif ($restore_user) { $next_widget = \&restore_step_user } elsif ($restore_other) { $next_widget = \&restore_step_other } else { $next_widget = \&restore_do } }) } gtksignal_connect(gtkset_active($check_restore_other_path, $restore_other_path), toggled => sub { $restore_other_path = $restore_other_path ? 0 : 1; destroy_widget(); $current_widget->(); }); gtksignal_connect(gtkset_active($check_restore_other_src, $restore_other_src), toggled => sub { $restore_other_src = $restore_other_src ? 0 : 1; destroy_widget(); $current_widget->(); }); $central_widget = \$retore_step2; fonction_env(\$retore_step2, \&restore_step2, \&restore_box, "restore"); if (!$restore_sys && !$restore_user && !$restore_other) { $next_widget = \&message_norestore_box } elsif ($restore_sys && $backup_sys_versions) { $next_widget = \&restore_step_sys } elsif ($restore_user) { $next_widget = \&restore_step_user } elsif ($restore_other) { $next_widget = \&restore_step_other } else { $next_widget = \&restore_do } $restore_path_entry->set_text($restore_path); $restore_path_entry->signal_connect('changed', sub { $restore_path = $restore_path_entry->get_text() }); $up_box->show_all(); } sub catalog_restore { my $catalog_box; my $cat_entry; my @restore_files; my $restore_path_entry; #- catalog info in tree view my $model = Gtk2::TreeStore->new(Gtk2::GType->STRING); my $tree_catalog = Gtk2::TreeView->new_with_model($model); $tree_catalog->append_column(Gtk2::TreeViewColumn->new_with_attributes(undef, Gtk2::CellRendererText->new, 'text' => 0)); $tree_catalog->set_headers_visible(0); $tree_catalog->get_selection->set_mode('single'); # file details in list widget my $list_bu_files = new Gtk2::List(); $list_bu_files->set_selection_mode('extended'); #- read the catalog my @catalog = cat_("$cfg_dir/drakbackup_catalog"); foreach (@catalog) { chop; my $full_cat_entry = $_; my @line_data = split(':', $_); my $t = $line_data[0]; my $t_catalog = Gtk2::TreeIter->new; $model->append($t_catalog, undef); $model->set($t_catalog, [ 0 => $t ]); gtksignal_connect($t_catalog, select => sub { $cat_entry = $full_cat_entry; @restore_files = (); foreach my $filename (glob("$save_path/list*$t.txt")) { my @contents = cat_($filename); $list_bu_files->clear; foreach (@contents) { chop; my $s = $_; my $f_item = $list_bu_files->add(gtkshow(new Gtk2::ListItem($s))); gtksignal_connect($f_item, select => sub { push @restore_files, $s }); gtksignal_connect($f_item, deselect => sub { @restore_files = () }); } } }); my $c_detail = Gtk2::TreeIter->new; my $indexer = 0; foreach (@line_data) { if ($indexer != 0) { my $m; $m = "Media: " if $indexer == 1; $m = "Label or Host: " if $indexer == 2; $m = "Device or Path: " if $indexer == 3; $m = "Type: Incremental" if $_ eq "I"; $m = "Type: Full" if $_ eq "F"; $m .= $_ if $_ ne "I" && $_ ne "F"; $model->append($c_detail, $t_catalog); $model->set($c_detail, [ 0 => $m ]); } $indexer++; } $c_detail->free; } gtkpack($advanced_box, $catalog_box = gtkpack_(new Gtk2::HBox(0,10), 0, new Gtk2::VBox(0,10), 1, gtkpack_(new Gtk2::VBox(0,5), 1, gtkpack_(new Gtk2::VBox(0, 10), 1, create_scrolled_window($tree_catalog), 1, create_scrolled_window($list_bu_files), ), 0, gtkpack_(new Gtk2::HBox(1, 10), 1, gtksignal_connect(new Gtk2::Button(N("Restore Selected\nCatalog Entry")), clicked => sub { if ($cat_entry) { my $media_check = restore_catalog_entry($cat_entry, ()); if ($media_check) { destroy_widget(); # button_box_restore(); interactive_mode_box(); } } }), 1, gtksignal_connect(new Gtk2::Button(N("Restore Selected\nFiles")), clicked => sub { my $files = @restore_files; #- grab the array before the widget clears it my @passed_files = @restore_files; if ($cat_entry && $files) { my $media_check = restore_catalog_entry($cat_entry, @passed_files); if ($media_check) { destroy_widget(); # button_box_restore(); interactive_mode_box(); } } }), 1, gtkpack_(new Gtk2::VBox(0, 5), 0, new Gtk2::Label("Restore To Path"), 0, $restore_path_entry = new Gtk2::Entry(), ), 1, gtksignal_connect(new Gtk2::Button(N("Change\nRestore Path")), clicked => sub { filedialog_generic("Path To Restore To", \$restore_path_entry, \$restore_path); }), ), 0, new Gtk2::VBox(0,10), ), 0, new Gtk2::VBox(0,10), ), ); $restore_path_entry->set_text($restore_path); gtksignal_connect($restore_path_entry, changed => sub { $restore_path = $restore_path_entry->get_text() }); button_box_restore(); fonction_env(\$catalog_box, \&catalog_restore, \&restore_find_media_box, "restore", \&catalog_restore); $central_widget = \$catalog_box; $up_box->show_all(); } sub restore_catalog_entry { #FIXME # we're working from a catalog entry, which means we know the # the tar file wildcards and some info on where the backup was stored # if it's a local device (HD, tape, CD) - prompt for the media # for tape, find how many other catalog entries had the same # label and calculate the record offset # if it's remote storage, display what we know of the connection # parameters and get the user's verification, then connect restore_status(); my ($cat_entry, @restore_files) = @_; my $username; my $userpass = $passwd_user; my $restore_result = 1; my @line_data = split(':', $cat_entry); my $backup_time = $line_data[0]; #- use our own variables here so we don't trash a saved config accidentally my $media = $line_data[1]; #- can be a volume name or a host name my $vol_host = $line_data[2]; #- see if we have a username embedded in the host if (index($vol_host, "@")) { my @user_host = split("@", $vol_host); $username = $user_host[0]; $vol_host = $user_host[1]; } else { $username = $login_user; } #- create a restore work directory if we don't have one -d "$cfg_dir/restores" or mkdir_p "$cfg_dir/restores"; #- can be a device name or a path my $dev_path = $line_data[3]; if ($media eq 'HD') { #- shouldn't really happen, should have just browsed #- to the $save_path in the previous step - deal with it anyway my @restore_tar_files = glob("$dev_path/*$backup_time*$tar_ext"); my $matches = @restore_tar_files; if ($matches eq 0) { show_warning("f", N("Backup files not found at %s.", $dev_path)); return(0); } else { my $save_path_org = $save_path; $save_path = $dev_path; $restore_result = restore_hd_or_cd($cat_entry, $dev_path, @restore_files); $save_path = $save_path_org; } } if ($media eq 'CD') { #- we know the cdrecord device, and the label #- prompt the user for the right CD $in->ask_okcancel(N("Restore From CD"), N("Insert the CD with volume label %s\n in the CD drive under mount point /mnt/cdrom", $vol_host) ,1) ? ($vol_name = get_cd_volname()) : return 0; if ($vol_name ne $vol_host) { show_warning("f", N("Not the correct CD label. Disk is labelled %s.", $vol_name)); return(0); } else { $restore_result = restore_hd_or_cd($cat_entry, '/mnt/cdrom', @restore_files); } } if ($media eq 'Tape') { #- a little more complicated, we need to check if other backups #- were done on this tape, and try to find the offset to this one $in->ask_okcancel(N("Restore From Tape"), N("Insert the tape with volume label %s\n in the tape drive device %s", $vol_host, $dev_path) ,1) ? ($vol_name = get_tape_label($dev_path)) : return(0); if ($vol_name ne $vol_host) { show_warning("f", N("Not the correct tape label. Tape is labelled %s.", $vol_name)); return(0); } else { $restore_result = restore_tape($cat_entry, $dev_path, @restore_files); } } if ($media eq 'ftp' || $media eq 'webdav' || $media eq 'ssh' || $media eq 'rsync') { #- show the user what we know of the connection from the catalog #- and the config file, let them override if necessary #- the various protocols are going to have different requirements #- webdav - it should already be in sitecopyrc - compare it? #- ssh - the only method we have enabled at the moment is with keys #- - no passwd needed #- - if we use expect, it is needed #- - if we use drackbackup keys, then a different ssh call is needed #- rsync - uses a config file with username - rsync.user #- ftp needs all parameters entered $in->ask_from(N("Restore Via Network"), N("Restore Via Network Protocol: %s", $media), [ { label => N("Host Name"), val => \$vol_host }, { label => N("Host Path or Module"), val => \$dev_path }, { label => N("Username"), val => \$username }, { label => N("Password"), val => \$userpass, hidden => 1 }, ]) or goto return(0); if ($media eq 'ftp' || $media eq 'rsync') { if ($userpass eq '') { show_warning("f", N_("Password required")); return(0); } } if ($media eq 'ftp' || $media eq 'rsync' || $media eq 'ssh') { if ($username eq '') { show_warning("f", N_("Username required")); return(0); } elsif ($vol_host eq '') { show_warning("f", N_("Hostname required")); return(0); } } if ($dev_path eq '') { show_warning("f", N_("Path or Module required")); return(0); } $restore_result = restore_ftp($cat_entry, $vol_host, $dev_path, $username, $userpass, @restore_files) if $media eq 'ftp'; $restore_result = restore_rsync_ssh_webdav($cat_entry, $vol_host, $dev_path, $username, $media, @restore_files) if $media eq 'rsync' || $media eq 'ssh' || $media eq 'webdav'; } # cleanup our restore dir - unlink fails here? system("rm -f $cfg_dir/restores/*"); if (!$restore_result) { show_warning("i", N_("Files Restored...")); return(0); } else { show_warning("f", N_("Restore Failed...")); return(1); } } sub restore_hd_or_cd { my ($cat_entry, $tarfile_dir, @restore_files) = @_; my $indv_files = @restore_files; my $command; my $wild_card = catalog_to_wildcard($cat_entry); if ($indv_files eq 0) { #- full catalog specified foreach (wildcard_to_tarfile($wild_card)) { $command = "tar -C $restore_path -xzf $tarfile_dir/$_"; spawn_progress($command, "Untarring from \n$_ \nto $restore_path."); } } else { #- individual files - pull from appropriate catalog foreach (@restore_files) { my $tarfile = file_to_tarfile($_, $wild_card); $_ = substr($_, 1); $command = "tar -C $restore_path -xzf $tarfile_dir/$tarfile $_"; spawn_progress($command, "Untarring \n$_ from \n$tarfile \nto $restore_path."); } } return(0); } sub restore_tape { my ($cat_entry, $dev_path, @restore_files) = @_; my $indv_files = @restore_files; my $command; my $wild_card = catalog_to_wildcard($cat_entry); $dev_path =~ s/\/st/\/nst/; if ($indv_files eq 0) { #- full catalog specified foreach (wildcard_to_tarfile($wild_card)) { my $offset = find_tape_offset($cat_entry); $command = "mt -f $dev_path rewind"; spawn_progress($command, "Rewinding tape on $dev_path."); $command = "mt -f $dev_path fsf $offset"; spawn_progress($command, "Moving forward $offset file records."); $command = "tar -C cfg_dir/restores -xf $dev_path"; spawn_progress($command, "Untarring from $dev_path to work directory."); if (-e "$cfg_dir/restores/$_") { $command = "tar -C $restore_path -xzf $cfg_dir/restores/$_"; spawn_progress($command, "Untarring \n$_ \nto $restore_path."); } else { return(1); } } } else { #- individual files - pull from appropriate catalog foreach (@restore_files) { my $tarfile = file_to_tarfile($_, $wild_card); $_ = substr($_, 1); if (!-e "$cfg_dir/restores/$tarfile") { my $offset = find_tape_offset($cat_entry); $command = "mt -f $dev_path rewind"; spawn_progress($command, "Rewinding tape on $dev_path."); $command = "mt -f $dev_path fsf $offset"; spawn_progress($command, "Moving forward $offset file records."); $command = "tar -C cfg_dir/restores -xf $dev_path"; spawn_progress($command, "Untarring from $dev_path to work directory."); } if (-e "$cfg_dir/restores/$tarfile") { $command = "tar -C $restore_path -xzf $cfg_dir/restores/$tarfile $_"; spawn_progress($command, "Untarring \n$_ from \n$tarfile \nto $restore_path."); } else { return(1); } } } return(0); } sub restore_ftp { use Net::FTP; my $ftp; my ($cat_entry, $hostname, $hostpath, $username, $userpass, @restore_files) = @_; my $indv_files = @restore_files; my $command; $DEBUG and print "file list to retrieve: $cat_entry\n "; if ($DEBUG && $interactive) { $ftp = Net::FTP->new($hostname, Debug => 1) or return(1) } elsif ($interactive) { $ftp = Net::FTP->new($hostname, Debug => 0) or return(1) } else { $ftp = Net::FTP->new($hostname, Debug => 0) or return(1) } $ftp->login($username, $userpass); $ftp->cwd($hostpath); my $wild_card = catalog_to_wildcard($cat_entry); if ($indv_files eq 0) { #- full catalog specified foreach (wildcard_to_tarfile($wild_card)) { $ftp->get($_, "$cfg_dir/restores/$_"); $command = "tar -C $restore_path -xzf $cfg_dir/restores/$_"; spawn_progress($command, "Untarring \n$_ \nto $restore_path."); } } else { #- individual files - pull from appropriate catalog foreach (@restore_files) { my $tarfile = file_to_tarfile($_, $wild_card); $_ = substr($_, 1); if (!-e "$cfg_dir/restores/$tarfile") { $ftp->get($tarfile, "$cfg_dir/restores/$tarfile"); } $command = "tar -C $restore_path -xzf $cfg_dir/restores/$tarfile $_"; spawn_progress($command, "Untarring \n$_ from \n$tarfile \nto $restore_path."); } } $ftp->quit; return(0); } sub restore_rsync_ssh_webdav { my ($cat_entry, $hostname, $hostpath, $username, $mode, @restore_files) = @_; my $indv_files = @restore_files; my $command; my $wild_card = catalog_to_wildcard($cat_entry); if ($indv_files eq 0) { #- full catalog specified foreach (wildcard_to_tarfile($wild_card)) { if ($mode eq 'ssh') { $command = "scp $username\@$hostname:$hostpath/$_ $cfg_dir/restores/"; } elsif ($mode eq 'rsync') { $command = "rsync --password-file=$cfg_dir/rsync.user $username\@$hostname\:\:$hostpath/$_ $cfg_dir/restores/"; } else { $command = "wget http://$hostname/$hostpath/$_ -P $cfg_dir/restores/"; } spawn_progress($command, "Retrieving backup file \n$_ \nvia $mode."); if (-e "$cfg_dir/restores/$_") { $command = "tar -C $restore_path -xzf $cfg_dir/restores/$_"; spawn_progress($command, "Untarring \n$_ \nto $restore_path."); } else { return(1); } } } else { #- individual files - pull from appropriate catalog foreach (@restore_files) { my $tarfile = file_to_tarfile($_, $wild_card); $_ = substr($_, 1); if (!-e "$cfg_dir/restores/$tarfile") { if ($mode eq 'ssh') { $command = "scp $username\@$hostname:$hostpath/$tarfile $cfg_dir/restores/"; } elsif ($mode eq 'rsync') { $command = "rsync --password-file=$cfg_dir/rsync.user $username\@$hostname\:\:$hostpath/$tarfile $cfg_dir/restores/"; } else { $command = "wget http://$hostname/$hostpath/$tarfile -P $cfg_dir/restores/"; } spawn_progress($command, "Retrieving backup file \n$tarfile \nvia $mode."); } if (-e "$cfg_dir/restores/$tarfile") { $command = "tar -C $restore_path -xzf $cfg_dir/restores/$tarfile $_"; spawn_progress($command, "Untarring \n$_ from \n$tarfile \nto $restore_path."); } else { return(1); } } } return(0); } sub catalog_to_wildcard { my ($cat_entry) = @_; my @line_data = split(':', $cat_entry); my $wildcard = $line_data[0]; $wildcard; } sub wildcard_to_tarfile { my ($wildcard) = @_; my $tarfile = basename(glob("$save_path/*$wildcard.txt")); $tarfile =~ s/txt/$tar_ext/; $tarfile =~ s/list/backup/; $tarfile; } sub file_to_tarfile { my ($restore_file, $wildcard) = @_; my $tarfile = `grep -l $restore_file $save_path/*$wildcard.txt`; chop $tarfile; $tarfile = basename($tarfile); $tarfile =~ s/txt/$tar_ext/; $tarfile =~ s/list/backup/; $tarfile; } sub find_tape_offset { my ($cat_entry) = @_; my @line_data = split(':', $cat_entry); my $label = $line_data[2]; my @catalog = cat_("$cfg_dir/drakbackup_catalog"); # always off by 1 for tape label. my $offset = 1; foreach (@catalog) { if (index($_, $label)) { if (!index($_, $cat_entry)) { # tar seems to need 2 of these to get located $offset++; $offset++; } else { return($offset); } } } } sub restore_box { my $retore_box; if ($good_restore_path) { $path_to_find_restore = $save_path if $where_hd; $path_to_find_restore = "/mnt/cdrom" if $where_cd; } find_backup_to_restore(); button_box_restore_main(); if ($other_backuped || $sys_backuped || @user_backuped) { gtkpack($advanced_box, $retore_box = gtkpack_(new Gtk2::HBox(0,1), 1, new Gtk2::VBox(0,10), 1, gtkpack_(new Gtk2::VBox(0,10), 1, new Gtk2::VBox(0,10), 1, new Gtk2::VBox(0,10), 1, gtksignal_connect(new Gtk2::Button(N("Restore all backups")), clicked => sub { $retore_box->destroy(); button_box_restore(); @user_list_to_restore2 = sort @user_backuped; $restore_sys = 1; $restore_other = 1; $restore_user = 1; restore_do() }), 1, gtksignal_connect(new Gtk2::Button(N("Custom Restore")), clicked => sub { $retore_box->destroy(); button_box_restore(); restore_step2(); }), 1, new Gtk2::VBox(0,10), 1, new Gtk2::VBox(0,10), ), 1, new Gtk2::HBox(0,10), ), ); } else { destroy_widget(); restore_find_media_box(), } fonction_env(\$retore_box, \&restore_box, \&interactive_mode_box, "restore"); $central_widget = \$retore_box; $up_box->show_all(); } sub restore_find_media_box { my $mount_media = 1; $good_restore_path = 0; my $message = "Unable to find backups to restore...\n"; $message .= "Verify that $path_to_find_restore is the correct path" if $where_hd && $where_cd; $message .= " and the CD is in the drive" if $where_cd; if ($where_tape || $net_proto) { $message .= "Backups on unmountable media - Use Catalog to restore"; $mount_media = 0; } $message .= "."; gtkpack($advanced_box, $box2 = gtkpack_(new Gtk2::VBox(0, 5), 1, gtkpack(new Gtk2::HBox(0, 15), new Gtk2::VBox(0, 5), gtkcreate_img('warning'), translate($message), new Gtk2::VBox(0, 5), ), 1, gtkpack(new Gtk2::HBox(0, 15), new Gtk2::VBox(0, 5), gtkpack(new Gtk2::VBox(0, 10), gtkset_sensitive(gtksignal_connect(new Gtk2::Button(N("CD in place - continue.")), clicked => sub { $good_restore_path = 1; $box2->destroy(); interactive_mode_box("restore"); }), $mount_media), $new_path_entry = gtkset_sensitive(new Gtk2::Entry(), $mount_media), gtkset_sensitive(gtksignal_connect(new Gtk2::Button(N("Browse to new restore repository.")), clicked => sub { filedialog_generic("Directory To Restore From", \$new_path_entry, \$path_to_find_restore); }), $mount_media), gtksignal_connect(new Gtk2::Button(N("Restore From Catalog")), clicked => sub { $box2->destroy(); catalog_restore(); }), ), new Gtk2::VBox(0, 5), ), 1, new Gtk2::VBox(0, 5), ), ); $new_path_entry->set_text($path_to_find_restore); button_box_find_media($mount_media); $up_box->show_all(); } sub restore_status { destroy_widget(); $pbar3 = new Gtk2::ProgressBar; $stext = new Gtk2::Label(""); gtkpack($advanced_box, $table = gtkpack(new Gtk2::VBox(0, 5), new Gtk2::HBox(0,5), create_packtable({ col_spacings => 10, row_spacings => 5 }, [""], [""], [""], [""], [N("Restore Progress")], [""], [""], [$pbar3], [""], [""], [$pbar3->{label} = new Gtk2::Label(' ')], [""], ), $stext, ), ); $custom_help = "options"; $central_widget = \$table; $up_box->show_all(); gtkflush(); } ################################################ BUTTON_BOX ################################################ sub button_box_adv { $button_box_tmp->destroy(); gtkpack($button_box, $button_box_tmp = gtkpack_(new Gtk2::HButtonBox, 0, gtksignal_connect(new Gtk2::Button(N("Cancel")), clicked => sub { interactive_mode_box(); }), 0, gtksignal_connect(new Gtk2::Button(N("Help")), clicked => sub { adv_help(\&$current_widget, $custom_help); }), 1, new Gtk2::HBox(0, 1), 0, gtksignal_connect(new Gtk2::Button(N("Previous")), clicked => sub { destroy_widget(); $previous_widget->(); }), 0, gtksignal_connect(new Gtk2::Button(N("Save")), clicked => sub { destroy_widget(); unless (check_pkg_needs()) { save_conf_file(); $previous_widget->(); } }), ), ); } sub button_box_restore_main { $button_box_tmp->destroy(); gtkpack($button_box, $button_box_tmp = gtkpack_(gtkpack_(new Gtk2::HButtonBox, 0, gtksignal_connect(new Gtk2::Button(N("Cancel")), clicked => sub { destroy_widget(); interactive_mode_box(); }), 0, gtksignal_connect(new Gtk2::Button(N("Help")), clicked => sub { adv_help(\&$current_widget, $custom_help); }), 1, new Gtk2::HBox(0, 1), 0, gtksignal_connect(new Gtk2::Button(N("Previous")), clicked => sub { destroy_widget(); interactive_mode_box() }), 0, gtksignal_connect(new Gtk2::Button(N("Ok")), clicked => sub { destroy_widget(); interactive_mode_box() }), ), ), ); } sub button_box_backup_end { $button_box_tmp->destroy(); gtkpack($button_box, $button_box_tmp = gtkpack_(new Gtk2::HButtonBox, 0, gtksignal_connect(new Gtk2::Button(N("Cancel")), clicked => sub { destroy_widget(); interactive_mode_box() }), 0, gtksignal_connect(new Gtk2::Button(N("Help")), clicked => sub { adv_help(\&$current_widget, $custom_help) }), 1, new Gtk2::HBox(0, 1), 0, gtksignal_connect(new Gtk2::Button(N("Previous")), clicked => sub { destroy_widget(); $previous_widget->() }), 0, gtksignal_connect(new Gtk2::Button(N("Build Backup")), clicked => sub { destroy_widget(); build_backup_status(); build_backup_files(); }), ), ); } sub button_box_wizard_end { $button_box_tmp->destroy(); gtkpack($button_box, $button_box_tmp = gtkpack_(new Gtk2::HButtonBox, 0, gtksignal_connect(new Gtk2::Button(N("Cancel")), clicked => sub { destroy_widget(); interactive_mode_box(); }), 0, gtksignal_connect(new Gtk2::Button(N("Help")), clicked => sub { adv_help(\&$current_widget, $custom_help); }), 1, new Gtk2::HBox(0, 1), 0, gtksignal_connect(new Gtk2::Button(N("Previous")), clicked => sub { destroy_widget(); $previous_widget->(); }), 0, gtksignal_connect(new Gtk2::Button(N("Save")), clicked => sub { destroy_widget(); save_conf_file(); interactive_mode_box(); }), ), ); } sub button_box_restore_end { $button_box_tmp->destroy(); gtkpack($button_box, $button_box_tmp = gtkpack_(new Gtk2::HButtonBox, 0, gtksignal_connect(new Gtk2::Button(N("Cancel")), clicked => sub { destroy_widget(); interactive_mode_box(); }), 0, gtksignal_connect(new Gtk2::Button(N("Help")), clicked => sub { adv_help(\&$current_widget, $custom_help); }), 1, new Gtk2::HBox(0, 1), 0, gtksignal_connect(new Gtk2::Button(N("Previous")), clicked => sub { destroy_widget(); $previous_widget->(); }), 0, gtksignal_connect(new Gtk2::Button(N("Restore")), clicked => sub { destroy_widget(); restore_backend(); }), ), ); } sub button_box_build_backup_end { $button_box_tmp->destroy(); gtkpack($button_box, $button_box_tmp = gtkpack_(new Gtk2::HButtonBox, 1, new Gtk2::HBox(0, 5), 1, new Gtk2::HBox(0, 5), 0, gtksignal_connect(new Gtk2::Button(N("Ok")), clicked => sub { # destroy_widget(); interactive_mode_box(); }), ), ); } sub button_box_restore_pbs_end { $button_box_tmp->destroy(); gtkpack($button_box, $button_box_tmp = gtkpack_(new Gtk2::HButtonBox, 1, new Gtk2::HBox(0, 5), 1, new Gtk2::HBox(0, 5), 1, gtksignal_connect(new Gtk2::Button(N("Help")), clicked => sub { adv_help(\&$current_widget, $custom_help); }), 0, gtksignal_connect(new Gtk2::Button(N("Ok")), clicked => sub { destroy_widget(); interactive_mode_box(); }), ), ); } sub button_box_build_backup { $button_box_tmp->destroy(); gtkpack($button_box, $button_box_tmp = gtkpack_(new Gtk2::HButtonBox, 1, gtksignal_connect(new Gtk2::Button(N("Cancel")), clicked => sub { destroy_widget(); interactive_mode_box(); }), 1, gtksignal_connect(new Gtk2::Button(N("Help")), clicked => sub { adv_help(\&$current_widget, $custom_help); }), 1, new Gtk2::HBox(0, 0), 0, gtksignal_connect(new Gtk2::Button(N("Previous")), clicked => sub { destroy_widget(); $previous_widget->(); }), 1, gtksignal_connect(new Gtk2::Button(N("Next")), clicked => sub { destroy_widget(); $next_widget->(); }), ), ); } sub button_box_restore { $button_box_tmp->destroy(); gtkpack($button_box, $button_box_tmp = gtkpack_(new Gtk2::HButtonBox, 1, gtksignal_connect(new Gtk2::Button(N("Cancel")), clicked => sub { destroy_widget(); interactive_mode_box(); }), 1, gtksignal_connect(new Gtk2::Button(N("Help")), clicked => sub { adv_help(\&$current_widget, $custom_help); }), 1, new Gtk2::HBox(0, 0), 0, gtksignal_connect(new Gtk2::Button(N("Previous")), clicked => sub { destroy_widget(); $previous_widget->(); }), 1, gtksignal_connect(new Gtk2::Button(N("Next")), clicked => sub { destroy_widget(); $next_widget->(); }), ), ); } sub button_box_find_media { my ($mount_media) = @_; #- $central_widget is not known yet? $button_box_tmp->destroy(); gtkpack($button_box, $button_box_tmp = gtkpack_(new Gtk2::HButtonBox, 1, gtksignal_connect(new Gtk2::Button(N("Cancel")), clicked => sub { $box2->destroy(); interactive_mode_box(); }), 1, gtksignal_connect(new Gtk2::Button(N("Help")), clicked => sub { $box2->destroy(); adv_help(\&$current_widget, $custom_help); }), 1, new Gtk2::HBox(0, 0), 0, gtksignal_connect(new Gtk2::Button(N("Previous")), clicked => sub { $box2->destroy(); interactive_mode_box(); }), 1, gtkset_sensitive(gtksignal_connect(new Gtk2::Button(N("Next")), clicked => sub { $box2->destroy(); interactive_mode_box("restore"); }), $mount_media), ), ); } sub button_box_wizard { $button_box_tmp->destroy(); gtkpack($button_box, $button_box_tmp = gtkpack_(new Gtk2::HButtonBox, 1, gtksignal_connect(new Gtk2::Button(N("Cancel")), clicked => sub { destroy_widget(); interactive_mode_box() }), 1, gtksignal_connect(new Gtk2::Button(N("Help")), clicked => sub { adv_help(\&$current_widget, $custom_help) }), 1, new Gtk2::HBox(0, 0), 0, gtksignal_connect(new Gtk2::Button($next_widget ? N("Previous") : N("OK")), clicked => sub { destroy_widget(); $previous_widget ? $previous_widget->() : $next_widget->(); }), if_($next_widget, 1, gtksignal_connect(new Gtk2::Button(N("Next")), clicked => sub { destroy_widget(); $next_widget ? $next_widget->() : $previous_widget->(); })), ), ); } sub button_box_main { $button_box_tmp->destroy(); gtkpack($button_box, $button_box_tmp = gtkpack(gtkset_layout(new Gtk2::HButtonBox, 'start'), gtksignal_connect(new Gtk2::Button(N("Close")), clicked => sub { ugtk2->exit(0) }), gtksignal_connect(new Gtk2::Button(N("Help")), clicked => sub { adv_help(\&interactive_mode_box, $custom_help) }), ), ); } ################################################ MESSAGES ################################################ sub dialog_one { $table->destroy(); my ($label) = @_; gtkadd($advanced_box, $box2 = gtkpack_(new Gtk2::HBox(0, 15), 1, new Gtk2::VBox(0, 5), 0, gtkpack_(new Gtk2::HBox(0, 15), 0, new Gtk2::VBox(0, 5), 0, gtkcreate_img('warning'), 0, $label), 0, new Gtk2::VBox(0, 5), 1, new Gtk2::VBox(0, 5), ), ); button_box_restore_main(); $custom_help = "mail_pb"; $central_widget = \$box2; $up_box->show_all(); } sub send_mail_pb { dialog_one(N("Error during sendmail. Your report mail was not sent. Please configure sendmail")); } sub client_ftp_pb { dialog_one(N("Error during sending file via FTP. Please correct your FTP configuration.")); } sub install_rpm { my ($previous_function) = @_; #- catch a crash when calling help #- this GUI control technique is kind of funky if ($previous_function eq '') { $previous_function = \&advanced_where; } my $box_what_user; gtkpack($advanced_box, $box_what_user = gtkpack_(new Gtk2::VBox(0, 15), 0, N("The following packages need to be installed:\n") . join(' ', @list_of_rpm_to_install), 0, new Gtk2::HSeparator, 0, gtksignal_connect(new Gtk2::Button(N("Install")), clicked => sub { system("/usr/sbin/urpmi --X @list_of_rpm_to_install"); destroy_widget(); $previous_widget->(); }), ), ); fonction_env(\$box_what_user, \&install_rpm, \&$previous_function, "what"); $up_box->show_all(); } sub message_norestore_box { $box2->destroy(); gtkadd($advanced_box, $box2 = gtkpack_(new Gtk2::HBox(0, 15), 1, new Gtk2::VBox(0, 5), 1, gtkpack(new Gtk2::HBox(0, 15), new Gtk2::VBox(0, 5), gtkcreate_img('warning'), N("Please select data to restore..."), new Gtk2::VBox(0, 5), ), 1, new Gtk2::VBox(0, 5), ), ); button_box_restore_main(); $central_widget = \$box2; $up_box->show_all(); } sub message_common_box { $box2->destroy(); my ($label) = @_; gtkadd($advanced_box, $box2 = gtkpack_(new Gtk2::HBox(0, 15), 1, new Gtk2::VBox(0, 5), 1, gtkpack(new Gtk2::HBox(0, 15), new Gtk2::VBox(0, 5), gtkcreate_img('warning'), $label, new Gtk2::VBox(0, 5), ), 1, new Gtk2::VBox(0, 5), ), ); $previous_widget = \&wizard; $next_widget = \&wizard; $central_widget = \$box2; $up_box->show_all(); } sub message_noselect_box { message_common_box(N("Please select media for backup...")); $previous_widget = \&wizard_step2; $next_widget = \&wizard_step2; $central_widget = \$box2; $up_box->show_all(); } sub message_noselect_what_box { message_common_box(N("Please select data to backup...")); $previous_widget = \&wizard; $next_widget = \&wizard; $central_widget = \$box2; $up_box->show_all(); } sub message_common_box_2 { my ($label, $restore_main) = @_; $box2->destroy(); gtkadd($advanced_box, $box2 = gtkpack_(new Gtk2::HBox(0, 15), 1, new Gtk2::VBox(0, 5), 1, gtkpack(new Gtk2::HBox(0, 15), new Gtk2::VBox(0, 5), gtkcreate_img('warning'), N("%s", $label), new Gtk2::VBox(0, 5), ), 1, new Gtk2::VBox(0, 5), ), ); button_box_restore_main() if $restore_main; $central_widget = \$box2; $up_box->show_all(); } sub message_noconf_box { message_common_box_2(N("No configuration file found \nplease click Wizard or Advanced."), 1); } sub message_underdevel { message_common_box_2(N("Under Devel ... please wait.")); } ################################################ BUILD_BACKUP ################################################ sub progress { my ($progressbar, $plabel, $incr, $label_text) = @_; my ($new_val) = $progressbar->fraction; $new_val += $incr; if ($new_val > 1) { $new_val = 1 } $progressbar->fraction($new_val); $plabel->set_text($label_text); gtkflush(); } sub find_backup_to_put_on_cd { @data_backuped = (); local $_; -d $save_path and my @list_backup = all($save_path); foreach (grep /^backup_other/, @list_backup) { $other_backuped = 1; chomp; my $tail = (split(' ', `du $save_path/$_`))[0]; s/^backup_other//gi; s/.tar.gz$//gi; s/.tar.bz2$//gi; my @user_date = split /\_20/; my @user_date2 = split(/\_/, $user_date[1]); my $to_put = " other_data, (tail: $tail ko, date: 20$user_date2[0], hour: $user_date2[1])"; push @data_backuped , $to_put; } foreach (grep /_sys_/, @list_backup) { $sys_backuped = 1; chomp; my $tail = (split(' ', `du $save_path/$_`))[0]; s/^backup_other//gi; s/.tar.gz$//gi; s/.tar.bz2$//gi; my @user_date = split /\_20/; my @user_date2 = split(/\_/, $user_date[1]); my $to_put = " system, (tail: $tail ko, date: 20$user_date2[0], hour: $user_date2[1])"; push @data_backuped , $to_put; } foreach (grep /user_/, @list_backup) { chomp; my $tail = (split(' ', `du $save_path/$_`))[0]; s/^backup_user_//gi; s/.tar.gz$//gi; s/.tar.bz2$//gi; my @user_date = split /\_20/; my @user_date2 = split(/\_/, $user_date[1]); my $to_put = " $user_date[0], (tail: $tail ko, date: 20$user_date2[0], hour: $user_date2[1])"; push @data_backuped , $to_put; } } sub build_backup_status { $pbar = new Gtk2::ProgressBar; $pbar1 = new Gtk2::ProgressBar; $pbar2 = new Gtk2::ProgressBar; $pbar3 = new Gtk2::ProgressBar; $plabel = new Gtk2::Label(" "); $plabel1 = new Gtk2::Label(" "); $plabel2 = new Gtk2::Label(" "); $plabel3 = new Gtk2::Label(" "); $stext = new Gtk2::Label(""); button_box_build_backup_end(); my $table = Gtk2::Table->new(10, 2, 1); $table->set_row_spacings(5); $table->set_col_spacings(10); $table->attach_defaults(new Gtk2::Label(N("Backup system files")), 0, 1, 0, 1); $table->attach_defaults($pbar, 0, 1, 1, 2); $table->attach_defaults($plabel, 1, 2, 1, 2); $table->attach_defaults(new Gtk2::Label(N("Backup user files")), 0, 1, 2, 3); $table->attach_defaults($pbar1, 0, 1, 3, 4); $table->attach_defaults($plabel1, 1, 2, 3, 4); $table->attach_defaults(new Gtk2::Label(N("Backup other files")), 0, 1, 4, 5); $table->attach_defaults($pbar2, 0, 1, 5, 6); $table->attach_defaults($plabel2, 1, 2, 5, 6); $table->attach_defaults(new Gtk2::Label(N("Total Progress")), 0, 1, 6, 7); $table->attach_defaults($pbar3, 0, 1, 7, 8); $table->attach_defaults($plabel3, 1, 2, 7, 8); gtkpack($advanced_box, my $tbox = gtkpack(new Gtk2::VBox(0, 5), $table, $stext, ), ); $custom_help = "options"; $central_widget = \$tbox; $up_box->show_all(); gtkflush(); } sub build_backup_ftp_status { $pbar = new Gtk2::ProgressBar; $pbar3 = new Gtk2::ProgressBar; $table->destroy(); button_box_build_backup_end(); $pbar->set_fraction(0); $pbar3->set_fraction(0); gtkpack($advanced_box, $table = gtkpack_(new Gtk2::VBox(0, 15), 1, N("files sending by FTP"), 1, new Gtk2::VBox(0, 15), 1, create_packtable ({ col_spacings => 10, row_spacings => 5 }, # [ $pbar->set_show_text( $show_text); [N("Sending files...")], [""], [ $plabel = new Gtk2::Label(' ') ], [ $pbar ], [""], [N("Total Progress")], [ $plabel3 = new Gtk2::Label(' ') ], [$pbar3], ), 1, new Gtk2::VBox(0, 15), ), ); $custom_help = "options"; $central_widget = \$table; $up_box->show_all(); gtkflush(); } sub build_backup_box_see_conf { my $box2; my $text = new Gtk2::TextView; system_state(); gtktext_insert($text, [ [ $system_state ] ]); button_box_restore_main(); gtkpack($advanced_box, $box2 = gtkpack_(new Gtk2::HBox(0, 15), 1, gtkpack_(new Gtk2::VBox(0,10), 0, N("Drakbackup Configuration"), 1, create_scrolled_window($text), ), ), ); button_box_backup_end(); $custom_help = ""; $central_widget = \$box2; $current_widget = \&build_backup_box_see_conf; $previous_widget = \&build_backup_box; $up_box->show_all(); } sub build_backup_box_progress { # build_backup_files(); } sub aff_total_tail { my @toto; my $total = 0; push @toto, (split(",", $_))[1] foreach @list_to_build_on_cd; foreach (@toto) { s/\s+\(tail://gi; s/\s+//gi; s/ko//gi; $total += $_; } $label_tail->set("total tail: $total ko"); } sub build_backup_box { $box2->destroy(); # my ($pix_cd_map, $pix_cd_mask) = gtkcreate_img("ic82-CD-40"); gtkadd($advanced_box, $box2 = gtkpack_(new Gtk2::HBox(0, 15), 1, new Gtk2::VBox(0, 5), 1, gtkpack_(new Gtk2::VBox(0, 15), 1, new Gtk2::VBox(0, 5), 1, gtksignal_connect(my $button_from_conf_file = new Gtk2::Button(), clicked => sub { destroy_widget(); build_backup_box_see_conf(); }), 0, new Gtk2::VBox(0, 5), 1, gtksignal_connect(my $button_see_conf = new Gtk2::Button(), clicked => sub { destroy_widget(); build_backup_box_see_conf(); }), 1, new Gtk2::VBox(0, 5), ), 1, new Gtk2::VBox(0, 5), ), ); $button_from_conf_file->add(gtkpack(new Gtk2::HBox(0,10), gtkcreate_img("ic82-discdurwhat-40"), new Gtk2::Label(N("Backup Now from configuration file")), new Gtk2::HBox(0, 5) )); $button_see_conf->add(gtkpack(new Gtk2::HBox(0,10), gtkcreate_img("ic82-moreoption-40"), new Gtk2::Label(N("View Backup Configuration.")), new Gtk2::HBox(0, 5) )); button_box_restore_main(); fonction_env(\$box2, \&build_backup_box, \&interactive_mode_box, "options"); $up_box->show_all(); } ################################################ INTERACTIVE ################################################ sub interactive_mode_box { destroy_widget(); my ($mode) = @_; # read_conf_file(); gtkadd($advanced_box, $box2 = gtkpack_(new Gtk2::HBox(0, 15), 1, new Gtk2::VBox(0, 5), 1, gtkpack_(new Gtk2::VBox(0, 15), 1, new Gtk2::VBox(0, 5), 1, gtksignal_connect(new Gtk2::Button(N("Wizard Configuration")), clicked => sub { destroy_widget(); read_conf_file(); wizard(); }), 1, gtksignal_connect(new Gtk2::Button(N("Advanced Configuration")), clicked => sub { button_box_adv(); destroy_widget(); advanced_box(); }), 1, gtksignal_connect(new Gtk2::Button(N("Backup Now")), clicked => sub { # destroy_widget(); if ($cfg_file_exist) { build_backup_box(); } else { message_noconf_box(); } }), 1, gtksignal_connect(new Gtk2::Button(N("Restore")), clicked => sub { destroy_widget(); restore_box(); }), 1, new Gtk2::VBox(0, 5), ), 1, new Gtk2::VBox(0, 5), ), ); button_box_main(); $custom_help = "main"; $central_widget = \$box2; $up_box->show_all(); if ($mode eq "restore") { destroy_widget(); restore_box(); } } sub interactive_mode { $interactive = 1; eval { require ugtk2 }; die "Can't load ugtk2...\n" if $@; ugtk2->import(qw(:helpers :wrappers :create)); $in = 'interactive'->vnew; my $box; $my_win = ugtk2->new('drakbackup'); $window1 = $my_win->{window}; unless ($::isEmbedded) { $my_win->{rwindow}->set_position('center'); $my_win->{rwindow}->set_title(N("Drakbackup")); } $my_win->{rwindow}->signal_connect(delete_event => sub { ugtk2->exit(0) }); read_conf_file(); gtkadd($window1, gtkpack(new Gtk2::VBox(0,0), gtkpack(gtkset_size_request($up_box = new Gtk2::VBox(0, 5), 540, 400), $box = gtkpack_(new Gtk2::VBox(0, 3), if_(!$::isEmbedded, 0, gtkcreate_img("drakbackup.540x57")), 1, gtkpack_(new Gtk2::HBox(0, 3), 1, gtkpack_(new Gtk2::HBox(0, 15), 0, new Gtk2::HBox(0, 5), 1, $advanced_box = gtkpack_(new Gtk2::HBox(0, 15), # 1, $box2 = gtkpack_(new Gtk2::VBox(0, 15),), ), 0, new Gtk2::HBox(0, 5), ), ), 0, new Gtk2::HSeparator, 0, $button_box = gtkpack(new Gtk2::VBox(0, 15), $button_box_tmp = gtkpack(new Gtk2::VBox(0, 0),), ), ), ), ), ); interactive_mode_box(); $custom_help = "main"; button_box_main(); $central_widget = \$box2; $window1->show_all; $window1->realize; $window1->show_all(); $my_win->main; $my_win->exit(0); } ################################################ HELP & ABOUT ################################################ sub adv_help { my ($function, $custom_help) = @_, ################################################ help definition ############################################## my %custom_helps = ( "options" => N("options description: In this step Drakbackup allow you to change: - The compression mode: If you check bzip2 compression, you will compress your data better than gzip (about 2-10 %%). This option is not checked by default because this compression mode needs more time (about 1000%% more). - The update mode: This option will update your backup, but this option is not really useful because you need to decompress your backup before you can update it. - the .backupignore mode: Like with cvs, Drakbackup will ignore all references included in .backupignore files in each directories. ex: #> cat .backupignore *.o *~ ... "), "mail_pb" => N(" Some errors during sendmail are caused by a bad configuration of postfix. To solve it you have to set myhostname or mydomain in /etc/postfix/main.cf "), "what" => N("options description: - Backup system files: This option allows you to backup your /etc directory, which contains all configuration files. Please be careful during the restore step to not overwrite: /etc/passwd /etc/group /etc/fstab - Backup User files: This option allows you select all users that you want to backup. To preserve disk space, it is recommended that you do not include the web browser's cache. - Backup Other files: This option allows you to add more data to save. With the other backup it's not possible at the moment to select incremental backup. - Incremental Backups: The incremental backup is the most powerful option for backup. This option allows you to backup all your data the first time, and only the changed data afterward. Then you will be able, during the restore step, to restore your data from a specified date. If you have not selected this option all old backups are deleted before each backup. "), "restore" => N("restore description: Only the most recent date will be used, because with incremental backups it is necessary to restore one by one each older backup. So if you don't want to restore a user please unselect all their check boxes. Otherwise, you are able to select only one of these. - Incremental Backups: The incremental backup is the most powerful option to use. This option allows you to backup all of your data the first time, and only the changed data after. So you will be able, during the restore step, to restore your data from a specified date. If you have not selected this option all old backups are deleted before each backup. "), "main" => N(" Copyright (C) 2001-2002 MandrakeSoft by DUPONT Sebastien <dupont_s\@epita.fr>") . "\n" . N(" updates 2002 MandrakeSoft by Stew Benedict <sbenedict\@mandrakesoft.com>") . "\n\n" . $::license . "\n\n _____________________\n" . N("Description: Drakbackup is used to backup your system. During the configuration you can select: - System files, - Users files, - Other files. or All your system ... and Other (like Windows Partitions) Drakbackup allows you to backup your system on: - Harddrive. - NFS. - CDROM (CDRW), DVDROM (with autoboot, rescue and autoinstall.). - FTP. - Rsync. - Webdav. - Tape. Drakbackup allows you to restore your system to a user selected directory. Per default all backups will be stored on your /var/lib/drakbackup directory Configuration file: /etc/drakconf/drakbackup/drakbackup.conf Restore Step: During the restore step, DrakBackup will remove your original directory and verify that all backup files are not corrupted. It is recommended you do a last backup before restoring. "), "ftp" => N("options description: Please be careful when you are using ftp backup, because only backups that are already built are sent to the server. So at the moment, you need to build the backup on your hard drive before sending it to the server. "), "restore_pbs" => N(" Restore Backup Problems: During the restore step, Drakbackup will verify all your backup files before restoring them. Before the restore, Drakbackup will remove your original directory, and you will loose all your data. It is important to be careful and not modify the backup data files by hand. ") ); ################################################ help function ############################################## destroy_widget(); my $text = new Gtk2::TextView; gtktext_insert($text, $custom_helps{$custom_help} || $custom_helps{main}); gtkpack($advanced_box, my $advanced_box_help = gtkpack_(new Gtk2::VBox(0,10), 1, create_scrolled_window($text), 0, gtkadd(gtkset_layout(new Gtk2::HButtonBox, 'spread'), gtksignal_connect(new Gtk2::Button(N("OK")), clicked => sub { destroy_widget(); $function->(); }), ), ) ); $central_widget = \$advanced_box_help; $up_box->show_all(); } sub to_ok { $sav_next_widget = $next_widget; $next_widget = undef; button_box_wizard(); } sub to_normal { $next_widget = $sav_next_widget; } sub destroy_widget { if ($central_widget ne '') { ${$central_widget}->destroy; $central_widget = ''; } }