File Coverage

blib/lib/Device/Moose/SCSI.pm
Criterion Covered Total %
statement 1 3 33.3
branch n/a
condition n/a
subroutine 1 1 100.0
pod n/a
total 2 4 50.0


line stmt bran cond sub pod time code
1             #!/usr/bin/perl -c
2              
3             package Device::Moose::SCSI;
4             {
5             $Device::Moose::SCSI::AUTHORITY = "cpan:potatogim";
6             $Device::Moose::SCSI::VERSION = "0.11";
7             };
8              
9 1     1   15983 use Moose;
  0            
  0            
10             use namespace::clean -except => "meta";
11              
12             use Carp;
13             use IO::File;
14              
15              
16             #-----------------------------------------------------------------------------
17             # Attributes
18             #-----------------------------------------------------------------------------
19             has "fh" =>
20             (
21             is => "ro",
22             isa => "FileHandle",
23             writer => "_set_fh",
24             clearer => "close",
25             );
26              
27             has "name" =>
28             (
29             is => "ro",
30             isa => "Str",
31             writer => "_set_name",
32             );
33              
34              
35             #-----------------------------------------------------------------------------
36             # Methods
37             #-----------------------------------------------------------------------------
38             sub enumerate
39             {
40             my $self = shift;
41             my %args = @_;
42              
43             opendir (my $dh, "/dev") || confess "Cannot read /dev: $!";
44              
45             my %devs;
46              
47             foreach my $file (readdir($dh))
48             {
49             my @stat = lstat("/dev/$file");
50              
51             next unless (scalar(@stat)); # next if stat() failed
52             next unless (S_ISCHR($stat[2])); # next if file isn't character special
53              
54             my $major = int($stat[6] / 256);
55              
56             next unless ($major == 21); # major number of /dev/sg* is 21
57              
58             my $minor = $stat[6] % 256;
59              
60             next if (exists($devs{$minor}));
61              
62             $devs{$minor} = $file;
63             }
64              
65             return map { $devs{$_}; } sort { $a <=> $b; } keys %devs;
66             }
67              
68             sub open
69             {
70             my $self = shift;
71             my %args = @_;
72              
73             $self->close() if (defined($self->fh));
74              
75             if (defined($args{sg}))
76             {
77             my $fh = IO::File->new("+<$args{sg}");
78              
79             if (!defined($fh))
80             {
81             confess "Cannot open $args{sg}: $!";
82             return -1;
83             }
84              
85             $self->_set_fh($fh);
86             $self->_set_name($args{sg});
87             }
88              
89             return 0;
90             }
91              
92             sub execute
93             {
94             my $self = shift;
95             my %args = @_;
96              
97             my ($command, $wanted, $data) = @args{qw/command wanted data/};
98              
99             $data = "" unless(defined($data));
100              
101             my $header = pack ("i4 I x16"
102             , 36 + length($command) + length($data) # int pack_len
103             , 36 + $wanted # int reply_len
104             , 0 # int pack_id
105             , 0 # int result
106             , length($command) == 12 ? 1 : 0); # unsigned int twelve_byte:1
107              
108             my $iobuf = $header . $command . $data;
109              
110             my $ret = syswrite($self->fh, $iobuf, length($iobuf));
111              
112             confess "Cannot write to " . $self->name . ": $!" unless (defined($ret));
113              
114             $ret = sysread($self->fh, $iobuf, length($header) + $wanted);
115              
116             confess "Cannot read from " . $self->name . ": $!" unless (defined($ret));
117              
118             my @data = unpack("i4 I C16", substr($iobuf, 0, 36));
119              
120             confess "SCSI I/O error $data[3] on " . $self->name if ($data[3]);
121              
122             return (substr($iobuf, 36), [@data[5..20]]);
123             }
124              
125             sub inquiry
126             {
127             my $self = shift;
128              
129             my ($data, undef) = $self->execute(command => pack("C x3 C x1", 0x12, 96)
130             , wanted => 96);
131              
132             my %enq;
133              
134             @enq{qw/DEVICE VENDOR PRODUCT REVISION/} = unpack("C x7 A8 A16 A4", $data);
135              
136             return \%enq;
137             }
138              
139              
140             #-----------------------------------------------------------------------------
141             # Life Cycle
142             #-----------------------------------------------------------------------------
143             sub BUILD
144             {
145             my $self = shift;
146             my $args = shift;
147              
148             if (defined($args->{sg}))
149             {
150             $self->open(sg => $args->{sg});
151             }
152             }
153              
154             1;
155              
156             __END__
157              
158             =encoding utf8
159              
160             =head1 NAME
161              
162             Device::Moose::SCSI - Reimplementation of Device::SCSI with Moose.
163              
164             =head1 SYNOPSIS
165              
166             use Device::Moose::SCSI;
167              
168             my $device = Device::Moose::SCSI->new(sg => "/dev/sg0");
169              
170             # INQUIRY
171             my $inquiry = $device->inquiry();
172              
173             # TESTUNITREADY
174             my ($result, $sense) = $device->execute (
175             command => pack("C x5", 0x00)
176             , wanted => 32
177             );
178              
179             =head1 DESCRIPTION
180              
181             C<Device::Moose::SCSI> reimplementation of Device::SCSI using Moose.
182              
183             See L<Device::SCSI> for detail information.
184              
185             Refer to L<http://www.tldp.org/HOWTO/archived/SCSI-Programming-HOWTO>
186             if you need to know how to SCSI programming with Linux.
187              
188             =head1 ATTRIBUTES
189              
190             =over
191              
192             =item B<fh>
193              
194             =item B<name>
195              
196             =back
197              
198             =head1 METHODS
199              
200             =over
201              
202             =item B<enumerate>
203              
204             =item B<open>
205              
206             =item B<close>
207              
208             =item B<execute>
209              
210             =item B<inquiry>
211              
212             =back
213              
214             =head2 Lifecycle methods
215              
216             =over
217              
218             =item B<BUILD>
219              
220             =back
221              
222             =head1 AUTHOR
223              
224             Ji-Hyeon Gim <potatogim@potatogim.net>
225              
226             =head1 CONTRIBUTORS
227              
228             =head1 COPYRIGHT AND LICENSE
229              
230             Copyright(c) 2015, by Ji-Hyeon Gim <potatogim@potatogim.net>
231              
232             This is free software; you can redistribute it and/or modify it
233             under the same terms as Perl 5 itself at:
234              
235             L<http://www.perlfoundation.org/artistic_license_2_0>
236              
237             You may obtain a copy of the full license at:
238              
239             L<http://www.perl.com/perl/misc/Artistic.html>
240              
241             =head1 SEE ALSO
242              
243             L<Device::SCSI>, L<Moose>
244              
245             =cut