#!/bin/perl use Tree::Simple; use Getopt::Std; #Get command line options getopt("m:"); $verbose ="true" if $opt_m eq "verbose"; $verbose ="false" if $opt_m eq "basic"; print "$verbose\n"; #Initialisation my @metadata; $zfslist_command = "zfs list -H -t all -o name,origin,type"; my $tree = Tree::Simple->new("root"); open(OUT,">out.dot"); #Gathering filesystemnames and basic informations for further processing open(ZFS,"$zfslist_command|"); while() { $line=$_; next if $line=~/^$/; chomp($line); ($objectname,$origin,$type) = $line =~ /^(\S*)\s*(\S*)\s*(\S*)$/; $filesystemdata{$objectname} = { origin => "$origin", type => "$type"} } #Processing of the data and gathering further filesystem informations foreach $i (sort keys %filesystemdata) { my $metadataindex = $i; $metadataindex =~ s/\//\|\|/gi; $metadataindex =~ s/\@/\|\|/gi; $metadataindex = $metadataindex . "\|\|"; if ($filesystemdata{$i}{type} eq "snapshot") { ($rest,$snapshotname) = split(/\@/,$i); $snapshotname = "$snapshotname"; @directorystructure = split(/\//,$rest); tinsert($tree,@directorystructure,$snapshotname); } if ($filesystemdata{$i}{type} eq "filesystem") { @directorystructure = split(/\//,$i); tinsert($tree,@directorystructure); } if ($filesystemdata{$i}{type} eq "volume") { @directorystructure = split(/\//,$i); tinsert($tree,@directorystructure); } open(ZFSGET,"zfs get -H -o property,value all $i |"); while() { $zfsgetline=$_; chomp($zfsgetline); (my $property,my $valueofproperty) = $zfsgetline =~ /(\S*?)\s(.*)/; $property=lc($property); $metadata{$metadataindex}{$property} = "$valueofproperty"; } close(ZFSGET); } print OUT "digraph ZFS \{\n"; tprint($tree); print OUT "}\n"; # Insert a list into a tree sub tinsert { my $tree = shift; return $tree unless scalar @_; my $el = shift; my @rest = @_; my @match = grep { $_->getNodeValue() eq $el} $tree->getAllChildren(); if (scalar @match) { my $t = $match[0]; tinsert($t, @rest); } else { tinsert($tree->addChild(Tree::Simple->new($el)), $el, @rest); } } # Print tree node sub print_nodeobjects { my $tree = shift; my $nodedepth; my $nodevalue; my $type; my $nodeobjectname; my $colorofnode; $nodevalue = $tree->getNodeValue(); $nodedepth = $tree->getDepth(); $curnode[$nodedepth] = $nodevalue; for ($currentpos_iterator=0; $currentpos_iterator <= $nodedepth; $currentpos_iterator++) { $currentposition= $currentposition . $curnode[$currentpos_iterator] ."\|\|"; } $colorofnode="blue" if $metadata{$currentposition}{type} eq "snapshot"; $colorofnode="black" if $metadata{$currentposition}{type} eq "filesystem"; $colorofnode="green" if $metadata{$currentposition}{type} eq "volume"; $shapeofnode="ellipse" if $metadata{$currentposition}{type} eq "snapshot"; $shapeofnode="box" if $metadata{$currentposition}{type} eq "filesystem"; $shapeofnode="hexagon" if $metadata{$currentposition}{type} eq "volume"; if ($verbose eq "true") { print OUT " \"" . $currentposition . "\"[color=$colorofnode,shape=record,label=\"\{$nodevalue\|\{creation\|$metadata{$currentposition}{creation}\}\}\"] \n"; } else { print OUT " \"" . $currentposition . "\"[color=$colorofnode,shape=$shapeofnode,label=\"$nodevalue\"] \n" } $currentposition=""; } sub print_edges { my $tree = shift; my $nodevalue; my $type; my $nodeobjectname; $nodevalue = $tree->getNodeValue(); my $parent = $tree->getParent; my $parentvalue = $parent->getNodeValue(); $nodedepth = $tree->getDepth(); $curnode[$nodedepth] = $nodevalue; for ($currentpos_iterator=0; $currentpos_iterator <= $nodedepth; $currentpos_iterator++) { $currentposition= $currentposition . $curnode[$currentpos_iterator] ."\|\|"; } for ($parentpos_iterator=0; $parentpos_iterator < $nodedepth; $parentpos_iterator++) { $parentposition = $parentposition . $curnode[$parentpos_iterator] ."\|\|"; } print OUT " \"" . $parentposition . "\"-\>\"" . $currentposition . "\"\n"; if ($metadata{$currentposition}{origin} ne "") { $clonemaster = $metadata{$currentposition}{origin}; $clonemaster =~ s/\//\|\|/gi; $clonemaster =~ s/\@/\|\|/gi; $clonemaster = $clonemaster . "\|\|"; print OUT " \"" . $currentposition . "\"-\>\"" . $clonemaster . "\"[color=red,label=\"is a clone\\n based on\"]\n"; } $currentposition=""; $parentposition=""; $clonemaster=""; } # Print the whole tree sub tprint { my $tree = shift; $tree->traverse(\&print_nodeobjects); $tree->traverse(\&print_edges); }