File Coverage

blib/lib/Linux/Proc/Mountinfo.pm
Criterion Covered Total %
statement 51 87 58.6
branch 15 24 62.5
condition 5 10 50.0
subroutine 7 25 28.0
pod 3 3 100.0
total 81 149 54.3


line stmt bran cond sub pod time code
1             package Linux::Proc::Mountinfo;
2              
3             our $VERSION = '0.02';
4              
5 1     1   36422 use strict;
  1         2  
  1         42  
6 1     1   6 use warnings;
  1         1  
  1         30  
7 1     1   5 use Carp;
  1         5  
  1         1300  
8              
9             sub _key {
10 18     18   25 my $mnt = shift;
11 18         81 $mnt =~ s|/+|/|g;
12 18         57 $mnt =~ s|/?$|/|;
13 18         115 $mnt =~ s|([\0/])|\0$1|g;
14 18         137 $mnt;
15             }
16              
17             sub read {
18 1     1 1 16 my ($class, %opts) = @_;
19 1         3 my $mnt = delete $opts{mnt};
20 1         3 my $pid = delete $opts{pid};
21 1         3 my $file = delete $opts{file};
22 1 50       4 %opts and croak "Unknown option(s) ". join(", ", sort keys %opts);
23              
24 1 50       4 unless (defined $file) {
25 1 50       4 $mnt = "/proc" unless defined $mnt;
26 1 50 33     68 croak "'$mnt' is not a proc filesystem" unless -d $mnt and (stat _)[12] == 0;
27 1 50       8 $pid = $$ unless defined $pid;
28 1         5 $file = "$mnt/$pid/mountinfo";
29             }
30 1 50       66 open my $fh, '<', $file or croak "Unable to open '$file': $!";
31              
32 1         2 my @entries;
33             my %entry_by_id;
34 0         0 my %entry_by_mm;
35 1         138 OUT: while (<$fh>) {
36 17         29 chomp;
37 17         109 my @fields = split;
38 17         66 my ($dash_ix) = grep $fields[$_] eq '-', 6 .. $#fields;
39 17 50       37 unless ($dash_ix) {
40 0         0 warn "dash not found inside mountinfo";
41 0         0 next;
42             }
43              
44 17 50       44 if (@fields < $dash_ix + 4) {
45 0         0 warn "invalid number of fields";
46 0         0 next;
47             }
48              
49 17         94 s/\\([0-7]{1,3})/chr oct $1/g for @fields;
50              
51 17         74 my $entry = [ @fields[0 .. 5, $dash_ix+1 .. $#fields],
52             [ @fields[6 .. $dash_ix-1] ],
53             $., $_,
54             _key($fields[4]),
55             [] ];
56 17         54 push @entries, bless $entry, 'Linux::Proc::Mountinfo::Entry';
57 17         57 $entry_by_id{$entry->[0]} = $entry;
58              
59 17         32 my $old = $entry_by_mm{$entry->[2]};
60 17 100 100     96 if (not $old or length($entry->[3]) < length($old->[3])) {
61 10         58 $entry_by_mm{$entry->[2]} = $entry
62             }
63             }
64              
65 1         3 for my $entry (@entries) {
66 17         25 my $bind = $entry_by_mm{$entry->[2]};
67 17 100       47 $entry->[14] = ( $bind == $entry ? undef : $bind );
68              
69 17 50       42 if ($entry->[0] != $entry->[1]) {
70 17 100       43 if (my $parent = $entry_by_id{$entry->[1]}) {
71 16         17 push @{$parent->[13]}, $entry;
  16         39  
72             }
73             }
74              
75             }
76              
77 1         24 bless \@entries, $class;
78             }
79              
80             *new = \&read;
81              
82             sub at {
83 1     1 1 6 my ($self, $at) = @_;
84 1         6 my $key = _key $at;
85 1   50     11 $_->[12] eq $key and return $_ for @$self;
86             ()
87 0         0 }
88              
89             sub root {
90 0     0 1 0 my $self = shift;
91 0   0     0 $_->[4] eq '/' and return $_ for @$self;
92             ()
93 0         0 }
94              
95             package Linux::Proc::Mountinfo::Entry;
96              
97 0     0   0 sub mount_id { shift->[ 0] }
98 0     0   0 sub parent_id { shift->[ 1] }
99 0     0   0 sub major_minor { shift->[ 2] }
100 0     0   0 sub root { shift->[ 3] }
101 1     1   12 sub mount_point { shift->[ 4] }
102 0     0     sub mount_options { shift->[ 5] }
103 0     0     sub fs_type { shift->[ 6] }
104 0     0     sub mount_source { shift->[ 7] }
105 0     0     sub super_options { shift->[ 8] }
106              
107 0     0     sub optional_fields { [@{shift->[9]}] }
  0            
108              
109 0     0     sub line_number { shift->[10] }
110 0     0     sub line { shift->[11] }
111              
112 0     0     sub _key { shift->[12] }
113              
114 0     0     sub major { (split /:/, shift->[2])[0] }
115 0     0     sub minor { (split /:/, shift->[2])[1] }
116              
117 0     0     sub children { bless [@{shift->[13]}], 'Linux::Proc::Mountinfo' }
  0            
118              
119 0     0     sub bind_source { shift->[14] }
120              
121             sub flatten {
122 0     0     my $self = shift;
123 0           my @flatten;
124 0           my @queue = $self;
125 0           while (@queue) {
126 0           my $first = shift @queue;
127 0           push @flatten, $first;
128 0           push @queue, @{$first->[13]}
  0            
129             }
130 0           bless \@flatten, 'Linux::Proc::Mountinfo'
131             }
132              
133             1;
134              
135             __END__