5 use File::Temp qw/ tempfile tempdir /;
7 my $SSLPATH = '/usr/bin/openssl';
11 print "ZFS Snapshot diff\n";
12 print "\t$0 [-dhirv] <zfs shapshot name> [filename]\n\n";
13 print " -d Display the lines that are different (diff output)\n";
14 print " -h Display this usage\n";
15 print " -i Ignore files that don't exist in the snapshot (only necessary for recursing)\n";
16 print " -r Recursively diff every file in the snapshot (filename not required)\n";
17 print " -v Verbose mode\n\n";
19 print " [filename] is the filename RELATIVE to the ZFS snapshot root. For example, if\n";
20 print " I had a filesystem snapshot called pool/data/zone\@initial. The filename '/etc/passwd'\n";
21 print " would refer to the filename /pool/data/zone/etc/passwd in the filesystem and filename\n";
22 print " /pool/data/zone/.zfs/snapshot/initial/etc/passwd in the snapshot.\n\n";
24 print " A couple of examples:\n";
25 print "\t$0 -v -r -i pool/zones/lava2019\@Fri\n";
26 print "\t\tChecks the current pool/zones/lava2019 filesystem against the snapshot\n";
27 print "\t\treturning the md5sum difference of any files (ignore files that don't\n";
28 print "\t\texist in the snapshot). With verbose mode\n\n";
30 print "\t$0 -d pool/zones/lava2019\@Mon /root/etc/passwd\n";
31 print "\t\tCheck the md5sum for /pool/zones/lava2019/root/etc/passwd and compare\n";
32 print "\t\tit to /pool/zones/lava2019/.zfs/snapshot/Mon/root/etc/passwd. Display\n";
33 print "\t\tthe lines that are different also.\n\n";
42 GetOptions("h" => \$options{help},
43 "r!" => \$options{recurse},
44 "d!" => \$options{diff},
45 "i!" => \$options{ignore},
53 if ($options{recurse}) {
54 recurse_diff(shift || die "Need a ZFS snapshot name\n");
56 my $zfsname = shift || die "Need a ZFS snapshot name\n";
57 my $file = shift || die "Need a filename\n";
58 diff_single_file($zfsname,$file);
65 print "Recursive diff on $zfssnap\n" if $verbose;
67 $zfssnap =~ /(.+)\@(.+)/i;
68 my $fsname = "/" . $1;
70 if(! -d $fsname && $fsname =~ /\/\S+?(\/.*)/) { $fsname = $1; }
71 elsif(! -d $fsname && $fsname =~ /\/\S+?/) { $fsname = "/"; }
72 print "Filesystem: $fsname, Snapshot: $snapname\n" if $verbose;
74 my $snappath = $fsname . "/.zfs/snapshot/" . $snapname . "/";
75 my $fspath = $fsname . "/";
76 $fspath =~ s/\/\//\//gi;
77 $snappath =~ s/\/\//\//gi;
78 print "Comparing: $fspath\nto: $snappath\n" if $verbose;
80 my $dir = tempdir( CLEANUP => 0 );
81 my ($fh, $filename) = tempfile( DIR => $dir );
83 `find $fspath -name "*" -type f > $filename`;
85 foreach my $file (<$fh>) {
87 $file =~ /(.*)\/(.*)/;
89 $file =~ /$fspath(.*)/;
90 my $diff = $snappath . $1;
92 print "$file does not exist in snapshot\n" if !$options{ignore};
97 my $orig = `$SSLPATH md5 $file`;
98 my $snap = `$SSLPATH md5 $diff`;
99 $orig =~ /[\s\S]+= (.+)/;
101 $snap =~ /[\s\S]+= (.+)/;
103 if ($sum1 ne $sum2) {
104 print "** $file is different\n";
105 print "** $orig** $snap" if $verbose;
107 if ($options{diff}) {
108 system("diff $file $diff");
113 sub diff_single_file {
115 my $filename = shift;
116 print "Single-file diff on $zfssnap, file: $filename\n" if $verbose;
118 $zfssnap =~ /(.+)\@(.+)/i;
119 my $fsname = "/" . $1 . "/";
121 if(! -d $fsname && $fsname =~ /\/\S+?(\/.*)/) { $fsname = $1; }
122 print "Filesystem: $fsname, Snapshot: $snapname\n" if $verbose;
125 if($filename !~ /^\//) { $fspath = $ENV{'PWD'} . "/" . $filename; }
126 else { $fspath = $filename; }
128 my $snapfspath = $fspath;
129 $snapfspath =~ s/$fsname//g;
130 my $snappath = $fsname . "/.zfs/snapshot/" . $snapname . "/" . $snapfspath;
131 $fspath =~ s/\/\//\//gi;
132 $snappath =~ s/\/\//\//gi;
133 print "Comparing: $fspath\nto: $snappath\n" if $verbose;
134 if(! -f $fspath) { print "-E- Cannot find source file: $fspath\n"; exit 1; }
135 if(! -f $snappath) { print "-E- Cannot find source file: $snappath\n"; exit 1; }
137 my $orig = `$SSLPATH md5 $fspath`;
138 my $snap = `$SSLPATH md5 $snappath`;
139 $orig =~ /[\s\S]+= (.+)/;
141 $snap =~ /[\s\S]+= (.+)/;
143 if ($sum1 ne $sum2) {
144 print "** Files are different\n";
145 print "** $orig** $snap" if $verbose;
147 if ($options{diff}) {
148 system("diff $fspath $snappath");