# # (c) Jan Gehring <jan.gehring@gmail.com> # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Inventory::Hal; use strict; use warnings; use Rex::Inventory::Hal::Object; use Rex::Commands::Run; use Rex::Helper::Run; use Rex::Commands::Gather; use Rex::Logger; our $VERSION = '1.7.0'; # VERSION use Data::Dumper; sub new { my $that = shift; my $proto = ref($that) || $that; my $self = {@_}; bless( $self, $proto ); $self->_read_lshal(); return $self; } # get devices of $category # like net or storage sub get_devices_of { my ( $self, $cat, $rex_class ) = @_; my @ret; for my $dev ( keys %{ $self->{'__hal'}->{$cat} } ) { push( @ret, $self->get_object_by_cat_and_udi( $cat, $dev, $rex_class ) ); } return @ret; } # get network devices sub get_network_devices { my ($self) = @_; return $self->get_devices_of('net'); } # get storage devices sub get_storage_devices { my ($self) = @_; my $os = get_operating_system(); if ( $os =~ m/BSD/ ) { return grep { !$_->is_cdrom && !$_->is_volume && !$_->is_floppy } $self->get_devices_of( 'block', 'storage' ); } else { # default linux return grep { !$_->is_cdrom && !$_->is_floppy } $self->get_devices_of('storage'); } } # get storage volumes sub get_storage_volumes { my ($self) = @_; my $os = get_operating_system(); if ( $os =~ m/BSD/ ) { return grep { !$_->is_cdrom && $_->is_volume && !$_->is_floppy } $self->get_devices_of( 'block', 'volume' ); } else { # default linux return $self->get_devices_of('volume'); } } # get a hal object from category and udi sub get_object_by_cat_and_udi { my ( $self, $cat, $udi, $rex_class ) = @_; $rex_class ||= $cat; my $class_name = "Rex::Inventory::Hal::Object::\u$rex_class"; eval "use $class_name"; if ($@) { Rex::Logger::debug( "This Hal Object isn't supported yet. Falling back to Base Object."); $class_name = "Rex::Inventory::Hal::Object"; } return $class_name->new( %{ $self->{'__hal'}->{$cat}->{$udi} }, hal => $self ); } # get object by udi sub get_object_by_udi { my ( $self, $udi ) = @_; for my $cat ( keys %{ $self->{'__hal'} } ) { for my $dev ( keys %{ $self->{'__hal'}->{$cat} } ) { if ( $dev eq $udi ) { return $self->get_object_by_cat_and_udi( $cat, $dev ); } } } } # private method to read lshal output # you don't see that... sub _read_lshal { my ($self) = @_; unless ( can_run "lshal" ) { Rex::Logger::info("No lshal available"); die; } my @lines = i_run "lshal", fail_ok => 1; my %devices; my %tmp_devices; my $in_dev = 0; my %data; my $dev_name; for my $l (@lines) { chomp $l; if ( $l =~ m/^udi = '(.*?)'/ ) { $in_dev = 1; $dev_name = $1; } if ( $l =~ m/^$/ ) { $in_dev = 0; unless ($dev_name) { %data = (); next; } $tmp_devices{$dev_name} = {%data}; %data = (); } if ($in_dev) { my ( $key, $val ) = split( / = /, $l, 2 ); $key =~ s/^\s+//; $key =~ s/^'|'$//g; $val =~ s/\(.*?\)$//; $val =~ s/^\s+//; $val =~ s/\s+$//; $val =~ s/^'|'$//g; $data{$key} = $self->_parse_hal_string($val); } } for my $dev ( keys %tmp_devices ) { my $s_key = $tmp_devices{$dev}->{"info.subsystem"} || $tmp_devices{$dev}->{"linux.subsystem"}; $s_key ||= $tmp_devices{$dev}->{"info.category"}; if ( !$s_key ) { #print Dumper($tmp_devices{$dev}); next; } if ( $s_key =~ m/\./ ) { ($s_key) = split( /\./, $s_key ); } if ( !exists $devices{$s_key} ) { $devices{$s_key} = {}; } $devices{$s_key}->{$dev} = $tmp_devices{$dev}; } $self->{'__hal'} = \%devices; } sub _parse_hal_string { my ( $self, $line ) = @_; if ( $line =~ m/^\{.*\}$/ ) { $line =~ s/^\{/[/; $line =~ s/\}$/]/; return eval $line; } return $line; } 1;