#!/usr/bin/env perl use strict; use warnings; my $usage = "Usage: $0 [-r] pool/dataset\n -r include snapshots of child datasets (recursive)\n"; my $recurse = 0; my $dataset; while (@ARGV) { my $a = shift @ARGV; if ($a eq '-r') { $recurse = 1; next } if (defined $dataset) { die $usage } $dataset = $a; } die $usage unless defined $dataset; my @cmd = ('zfs','list','-t','snapshot','-o','name,used','-H'); push @cmd, '-r' if $recurse; push @cmd, $dataset; open my $fh, "-|", @cmd or die "Failed to run zfs: $!\n"; sub parse_size { my ($s) = @_; return 0 unless defined $s && length $s; $s =~ s/,//g; if ($s =~ /([0-9.]+)\s*([BKMGTP]?)$/i) { my ($n,$u) = ($1, uc $2); my %m = ('B' => 1, ''=>1, 'K'=>1024, 'M'=>1024**2, 'G'=>1024**3, 'T'=>1024**4, 'P'=>1024**5); return int($n * $m{$u}); } # fallback: try to interpret as integer bytes return int($s); } sub human { my ($n) = @_; return "0 B" if $n == 0; my @units = qw(B K M G T P); my $i = 0; while ($n >= 1024 && $i < @units-1) { $n /= 1024; $i++ } return sprintf("%.2f %s", $n, $units[$i]); } my $sum = 0; while (my $line = <$fh>) { chomp $line; next unless $line =~ /\S/; my ($name, $used) = split /\s+/, $line, 2; $used =~ s/^\s+|\s+$//g if defined $used; $sum += parse_size($used); } close $fh; printf "%s (%d bytes)\n", human($sum), $sum; exit 0