# Usage: # perl -MMyHDD -e 'MyHDD::hdd_report(qw[size brand])' # HDD data: 2006.07.20 # Owner: altblue@n0i.net package MyHDD; use strict; use warnings; our $VERSION = sprintf '0.%d.%d', '\$Revision: 1.9 $' =~ /(\d+)\.(\d+)/xm; use List::Util qw(sum max); use Data::Dumper; # size - in GiB # uptime - in Hours my $HDD = [ { serial => 'WD-WCAL81373552', brand => 'Western Digital', type => 'WD2000JB-00GVA0', fwrev => '08.02D08', dev => 'hdc', place => 'neo AT neomedia', size => 200, uptime => 10_749, cycles => 37, }, { serial => 'WD-WCAL81526954', brand => 'Western Digital', type => 'WD2000JB-00GVA0', fwrev => '08.02D08', dev => 'hdd', place => 'neo AT neomedia', size => 200, uptime => 10_781, cycles => 37, }, { serial => '3JS22FB4', brand => 'Seagate', type => 'ST3160023A', fwrev => '3.06', dev => 'hde', place => 'neo AT neomedia', size => 160, uptime => 22_751, cycles => 60, }, { serial => '3JS22G7F', brand => 'Seagate', type => 'ST3160023A', fwrev => '3.06', dev => 'hdf', place => 'neo AT neomedia', size => 160, uptime => 22_672, cycles => 59, }, { serial => '3KA1DWN8', brand => 'Seagate', type => 'ST3120023A', fwrev => '3.33', dev => 'hdc', place => 'n0i AT neomedia', size => 120, uptime => 28_687, cycles => 86, }, { serial => '3KA1CBJP', brand => 'Seagate', type => 'ST3120023A', fwrev => '3.33', dev => 'hdd', place => 'n0i AT neomedia', size => 120, uptime => 28_565, cycles => 89, }, { serial => '3HV3JZFK', brand => 'Seagate', type => 'ST380021A', fwrev => '3.75', dev => 'hda', place => 'n0i AT neomedia', size => 80, uptime => 25_730, cycles => 91, }, { serial => '5JT034DH', brand => 'Seagate', type => 'ST3120022A', fwrev => '3.06', dev => 'hdb', place => 'n0i AT neomedia', size => 120, uptime => 24_781, cycles => 58, }, { serial => 'L61QJTPH', brand => 'Maxtor', type => '6L250R0', fwrev => 'BAJ41G20', dev => 'hdb', place => 'webdev AT itfits', size => 250, uptime => 343, cycles => 3, }, { serial => '3HSBEJE1', brand => 'Seagate', type => 'ST340016A', fwrev => '3.75', dev => 'hda', place => 'nul AT home', size => 40, uptime => 27_406, cycles => 232, }, { serial => 'WD-WCAL72112632', brand => 'Western Digital', type => 'WD2000JB-00GVA0', fwrev => '08.02D08', dev => 'hdb', place => 'nul AT home', size => 200, uptime => 13_168, cycles => 125, }, { serial => 'WD-WXE405279726', brand => 'Western Digital', type => 'WDC WD400VE-00HDT0', fwrev => '09.07D09', dev => 'hda', place => 'nop AT home', size => 40, uptime => 8_894, cycles => 175, }, { serial => '3PM08QF1', brand => 'Seagate', type => 'ST3500841A', fwrev => '3.AAE', dev => 'hdb', place => 'neo AT neomedia', size => 500, uptime => 320, cycles => 5, }, { serial => 'WCAEK1702371', brand => 'Western Digital', type => 'WD1600JB-00EVA0', fwrev => undef, dev => undef, place => undef, size => 160, uptime => 0, cycles => 0, }, ]; my $reports = { size => sub { my %sz; foreach ( @{$HDD} ) { $sz{ $_->{size} }++; } my @sz; foreach ( sort { $b <=> $a } keys %sz ) { push @sz, [ $_, $sz{$_}, $sz{$_} * $_ ]; } return [ [ 'Type', 'Cnt', 'Size' ], @sz, [ 'TOTAL', scalar @{$HDD}, sum map { $_->{size} } @{$HDD} ], ]; }, brand => sub { my %brands; foreach ( @{$HDD} ) { $brands{ $_->{brand} }{count}++; $brands{ $_->{brand} }{size} += $_->{size}; $brands{ $_->{brand} }{uptime} += $_->{uptime}; } my @sz; foreach ( sort { $brands{$b}{size} <=> $brands{$a}{size} } keys %brands ) { push @sz, [ $_, $brands{$_}{count}, $brands{$_}{size}, $brands{$_}{uptime}, int $brands{$_}{uptime} / $brands{$_}{count} ]; } return [ [ 'Brand', 'Cnt', 'Size', 'Uptime(H)', 'Uptime(AvgH)' ], @sz, [ 'TOTAL', sum( map { $brands{$_}{count} } keys %brands ), sum( map { $brands{$_}{size} } keys %brands ), sum( map { $brands{$_}{uptime} } keys %brands ), int sum( map { $brands{$_}{uptime} } keys %brands ) / sum( map { $brands{$_}{count} } keys %brands ) ], ]; }, }; sub hdd_report { return print join "\n", 'No report type selected. Choose one (or more) of: ', keys %{$reports}, "\n" if !@_; foreach my $type (@_) { draw_report( "HDD Report: $type", $reports->{$type}->() ); } return; } sub draw_report { my $caption = shift || return; my $data = shift || return; return if !@{$data}; my @len = (); foreach my $col ( 0 .. @{ $data->[0] } - 1 ) { push @len, max map { length $_->[$col] } @{$data}; } my $template = join q{ | }, map { "%${_}s" } @len; my $splitter = join( q{--|--}, map { q{-} x $_ } @len ) . "\n"; my $rlen = sum(@len) + @len * 4; if ( length $caption < $rlen ) { print q{ } x ( ( $rlen - length $caption ) / 2 ); } print $caption, "\n", q{=} x $rlen, "\n"; my $idx = 0; foreach ( @{$data} ) { $idx++; if ( $idx == 2 ) { print $splitter; } printf "$template\n", @{$_}; if ( $idx == @{$data} - 1 ) { print $splitter; } } print q{=} x $rlen, "\n" x 2; return; } 1;