added findoid tool
This commit is contained in:
parent
8a6048635a
commit
c0f1131fa6
|
@ -1,3 +1,5 @@
|
|||
1.4.0 added findoid tool - find and list all versions of a given file in all available ZFS snapshots. use: findoid /path/to/file
|
||||
|
||||
1.3.1 whoops - prevent process_children_only from getting set from blank value in defaults
|
||||
|
||||
1.3.0 changed monitor_children_only to process_children_only. which keeps sanoid from messing around with empty parent datasets at all.
|
||||
|
|
|
@ -0,0 +1,180 @@
|
|||
#!/usr/bin/perl
|
||||
|
||||
# this software is licensed for use under the Free Software Foundation's GPL v3.0 license, as retrieved
|
||||
# from http://www.gnu.org/licenses/gpl-3.0.html on 2014-11-17. A copy should also be available in this
|
||||
# project's Git repository at https://github.com/jimsalterjrs/sanoid/blob/master/LICENSE.
|
||||
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
my $zfs = '/sbin/zfs';
|
||||
my %args = getargs(@ARGV);
|
||||
|
||||
my $progversion = '1.4.0';
|
||||
|
||||
if ($args{'version'}) { print "$progversion\n"; exit 0; }
|
||||
|
||||
my $dataset = getdataset($args{'path'});
|
||||
|
||||
my %versions = getversions($args{'path'}, $dataset);
|
||||
|
||||
foreach my $version (sort { $versions{$a}{'mtime'} <=> $versions{$b}{'mtime'} } keys %versions) {
|
||||
my $disptime = localtime($versions{$version}{'mtime'});
|
||||
my $dispsize = humansize($versions{$version}{'size'});
|
||||
|
||||
print "$disptime\t$dispsize\t$version\n";
|
||||
}
|
||||
|
||||
exit 0;
|
||||
|
||||
###################################################################
|
||||
###################################################################
|
||||
###################################################################
|
||||
|
||||
sub humansize {
|
||||
|
||||
my ($rawsize) = @_;
|
||||
my $humansize;
|
||||
|
||||
if ($rawsize > 1024*1024*1024) {
|
||||
$humansize = sprintf("%.1f",$rawsize/1024/1024/1024) . ' GB';
|
||||
} elsif ($rawsize > 1024*1024) {
|
||||
$humansize = sprintf("%.1f",$rawsize/1024/1024) . ' MB';
|
||||
} elsif ($rawsize > 255) {
|
||||
$humansize = sprintf("%.1f",$rawsize/1024) . ' KB';
|
||||
} else {
|
||||
$humansize = $rawsize . ' Bytes';
|
||||
}
|
||||
|
||||
return $humansize;
|
||||
}
|
||||
|
||||
sub getversions {
|
||||
my ($path, $dataset) = @_;
|
||||
my @snaps = findsnaps($dataset, $args{'path'});
|
||||
|
||||
my $snappath = '.zfs/snapshot';
|
||||
my $relpath = $path;
|
||||
$relpath =~ s/^$dataset\///;
|
||||
|
||||
my %versions;
|
||||
|
||||
foreach my $snap (@snaps) {
|
||||
my $filename = "$dataset/$snappath/$snap/$relpath";
|
||||
my ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime,$blksize,$blocks) = stat($filename);
|
||||
|
||||
# only push to the $versions hash if this size and mtime aren't already present (simple dedupe)
|
||||
my $duplicate = 0;
|
||||
foreach my $version (keys %versions) {
|
||||
if ($versions{$version}{'size'} eq $size && $versions{$version}{'mtime'} eq $mtime) {
|
||||
$duplicate = 1;
|
||||
}
|
||||
}
|
||||
if (! $duplicate) {
|
||||
$versions{$filename}{'size'} = $size;
|
||||
$versions{$filename}{'mtime'} = $mtime;
|
||||
}
|
||||
}
|
||||
|
||||
return %versions;
|
||||
}
|
||||
|
||||
sub findsnaps {
|
||||
my ($dataset, $path) = @_;
|
||||
|
||||
my $snappath = '.zfs/snapshot';
|
||||
|
||||
my $relpath = $path;
|
||||
$relpath =~ s/^$dataset//;
|
||||
|
||||
my @snaps;
|
||||
opendir (my $dh, "$dataset/$snappath");
|
||||
while (my $dir=(readdir $dh)) {
|
||||
if ($dir ne '.' && $dir ne '..') { push @snaps, $dir; }
|
||||
}
|
||||
closedir $dh;
|
||||
|
||||
return @snaps;
|
||||
}
|
||||
|
||||
sub getdataset {
|
||||
|
||||
my ($path) = @_;
|
||||
|
||||
open FH, "$zfs list -Ho mountpoint |";
|
||||
my @datasets = <FH>;
|
||||
close FH;
|
||||
|
||||
my @matchingdatasets;
|
||||
foreach my $dataset (@datasets) {
|
||||
chomp $dataset;
|
||||
if ( $path =~ /^$dataset/ ) { push @matchingdatasets, $dataset; }
|
||||
}
|
||||
|
||||
my $bestmatch = '';
|
||||
foreach my $dataset (@matchingdatasets) {
|
||||
if ( length $dataset > length $bestmatch ) { $bestmatch = $dataset; }
|
||||
}
|
||||
return $bestmatch;
|
||||
}
|
||||
|
||||
sub getargs {
|
||||
my @args = @_;
|
||||
my %args;
|
||||
|
||||
my %novaluearg;
|
||||
my %validarg;
|
||||
push my @validargs, ('debug','version');
|
||||
foreach my $item (@validargs) { $validarg{$item} = 1; }
|
||||
push my @novalueargs, ('debug','version');
|
||||
foreach my $item (@novalueargs) { $novaluearg{$item} = 1; }
|
||||
|
||||
while (my $rawarg = shift(@args)) {
|
||||
my $arg = $rawarg;
|
||||
my $argvalue;
|
||||
if ($rawarg =~ /=/) {
|
||||
# user specified the value for a CLI argument with =
|
||||
# instead of with blank space. separate appropriately.
|
||||
$argvalue = $arg;
|
||||
$arg =~ s/=.*$//;
|
||||
$argvalue =~ s/^.*=//;
|
||||
}
|
||||
if ($rawarg =~ /^--/) {
|
||||
# doubledash arg
|
||||
$arg =~ s/^--//;
|
||||
if (! $validarg{$arg}) { die "ERROR: don't understand argument $rawarg.\n"; }
|
||||
if ($novaluearg{$arg}) {
|
||||
$args{$arg} = 1;
|
||||
} else {
|
||||
# if this CLI arg takes a user-specified value and
|
||||
# we don't already have it, then the user must have
|
||||
# specified with a space, so pull in the next value
|
||||
# from the array as this value rather than as the
|
||||
# next argument.
|
||||
if ($argvalue eq '') { $argvalue = shift(@args); }
|
||||
$args{$arg} = $argvalue;
|
||||
}
|
||||
} elsif ($arg =~ /^-/) {
|
||||
# singledash arg
|
||||
$arg =~ s/^-//;
|
||||
if (! $validarg{$arg}) { die "ERROR: don't understand argument $rawarg.\n"; }
|
||||
if ($novaluearg{$arg}) {
|
||||
$args{$arg} = 1;
|
||||
} else {
|
||||
# if this CLI arg takes a user-specified value and
|
||||
# we don't already have it, then the user must have
|
||||
# specified with a space, so pull in the next value
|
||||
# from the array as this value rather than as the
|
||||
# next argument.
|
||||
if ($argvalue eq '') { $argvalue = shift(@args); }
|
||||
$args{$arg} = $argvalue;
|
||||
}
|
||||
} else {
|
||||
# bare arg
|
||||
$args{'path'} = $arg;
|
||||
}
|
||||
}
|
||||
|
||||
return %args;
|
||||
}
|
2
sanoid
2
sanoid
|
@ -4,7 +4,7 @@
|
|||
# from http://www.gnu.org/licenses/gpl-3.0.html on 2014-11-17. A copy should also be available in this
|
||||
# project's Git repository at https://github.com/jimsalterjrs/sanoid/blob/master/LICENSE.
|
||||
|
||||
my $version = '1.3.1';
|
||||
my $version = '1.4.0';
|
||||
|
||||
use strict;
|
||||
use Config::IniFiles; # read samba-style conf file
|
||||
|
|
2
syncoid
2
syncoid
|
@ -4,7 +4,7 @@
|
|||
# from http://www.gnu.org/licenses/gpl-3.0.html on 2014-11-17. A copy should also be available in this
|
||||
# project's Git repository at https://github.com/jimsalterjrs/sanoid/blob/master/LICENSE.
|
||||
|
||||
my $version = '1.3.1';
|
||||
my $version = '1.4.0';
|
||||
|
||||
use strict;
|
||||
use Data::Dumper;
|
||||
|
|
Loading…
Reference in New Issue