]> www.wagner.pp.ru Git - oss/restore.git/blob - backup
Debugged matrix notifications
[oss/restore.git] / backup
1 #!/usr/bin/perl
2 # If we have rsnapshot, we have perl to run it
3
4 =head1 NAME
5
6 backup - manages multilevel rsnapshot backups
7
8 =head1 SYNOPSIS
9
10     backup
11
12 =head1 DESCRIPTION
13
14 This script is intended to make B<rsnapshot>(1) backups to removable
15 devices, which are performed by hand and with some irregularity.
16
17 It reads C</etc/rsnapshot.conf> and finds out snapshot root and
18 list of backup levels.
19
20 It expected that removable device is automounted.
21
22 It checks existing backups in the C<$snapshot_root>, and if oldest snapshot
23 of level n is newer that next level was done (as determined by
24 modification date of C<$snapshot_root/$level-stamp>) next level is
25 performed.
26
27 If all backups were successful, unmounts all partitions of device where
28 C<$snapshot_root> is located.
29
30 If there exists B</usr/local/sbin/notify-messenger> invokes it and
31 sends messaage about backup completion status to its stdin
32
33 =head1 FILES
34
35 /etc/rsnapshot.conf
36
37 /usr/local/sbin/notify-messenger
38
39 =head1 AUTHOR
40
41 Victor Wagner <vitus@wagner.pp.ru>
42
43 =cut
44
45 use Sys::Hostname;
46
47 # Read rsnapshot conf, find out snapshot_root and retain.
48 open $conf, "<","/etc/rsnapshot.conf" or die "/etc/rsnapshot.conf:$!\n";
49 my @levels=();
50 my $snapshot_root=undef;
51 LINE:
52 while (<$conf>) {
53         if (/^snapshot_root\t+(.*)$/) {
54                 $snapshot_root= $1;
55                 next LINE;
56         }       
57         if (/^retain\s+(\w+)\s+(\d+)/) {
58                 my $level = $1;
59                 my $number = $2;
60                 if (@levels) {
61                         push @{$levels[$#levels]},$level;
62                 }
63                 push @levels,[$level,$number];
64         }
65 }
66 # last level is incomplete, we don't need it.
67 pop @levels;
68
69 die "No backup media mounted on $snapshot_root\n" unless -d $snapshot_root;
70 # Now we have following triples:
71 # "level,number,nextlevel"
72 my $level;
73 LEVEL:
74 while (@levels) {
75         $triple = pop @levels;
76         $level=$triple->[0];
77         my $number=$triple->[1] -1;
78         my $nextlevel=$triple->[2];
79         if (! -d "$snapshot_root/$level.$number") {
80             #not enough retained backups of on this level
81                 next LEVEL;
82         }
83         if (-f "$snapshot_root/${nextlevel}-stamp" &&
84                 -M "$snapshot_root/${nextlevel}-stamp" < 
85                 -M "$snapshot_root/$level.$number") {
86                 # last backup on level nextlevel happen after oldest retanined
87                 # on level level
88                 next LEVEL;
89         }
90     run_rsnapshot($nextlevel);
91         # touch stamp file
92         open my $stamp, ">>","$snapshot_root/${nextlevel}-stamp";
93         close $stamp;
94 }
95 run_rsnapshot($level);  
96 notify("Backup completed successfully\n");
97 # Размонтируем файловую систему, содержащую snapshot_root
98 my @lines = `df $snapshot_root`;
99 my @line = split(/\s+/,pop @lines);
100 my $device = shift @line;
101 $device =~ s/\d$//; # remove partition number 
102 open my $mount,"mount|" or die "Cannot execute mount:$!";
103 my @to_umount=();
104 while (<$mount>) {
105         if (m!^($device\d) on !) {
106                 push @to_umount,$1;
107         }
108 }
109 close $mount;
110 my @baddevs=();
111 for $device (@to_umount) {
112     print STDERR  "umount $device\n";
113     if (system("umount",$device) !=0) {
114         push @baddevs, $device;
115     }
116 }
117
118 if (@baddevs) {
119   notify("Cannot unmount device(s) ".join(", ",@baddevs).".\n")
120 }
121 sub run_rsnapshot {
122     my $level = shift;
123     print STDERR "running rsnapshot $level\n";
124     my $status= system("rsnapshot",$level) >> 8;
125     if ($status) { 
126         notify("rsapshot $level finished with code $status\n");
127         exit $status;
128     }
129 }
130 sub notify {
131     my $msg = shift;    
132     print STDERR $msg;  
133     my $notifier = "/usr/local/sbin/notify-messenger";
134     if ( -x $notifier) {
135      $hostname = Sys::Hostname::hostname();
136          open my $pipe,"|$notifier";
137          print $pipe  "$hostname: $msg";
138          close $pipe; 
139     }
140 }