File Coverage

blib/lib/Filesys/Btrfs.pm
Criterion Covered Total %
statement 21 73 28.7
branch 0 28 0.0
condition 0 6 0.0
subroutine 7 19 36.8
pod 10 10 100.0
total 38 136 27.9


line stmt bran cond sub pod time code
1             package Filesys::Btrfs;
2              
3 2     2   283410 use 5.10.1;
  2         6  
  2         86  
4 2     2   12 use strict;
  2         3  
  2         63  
5 2     2   10 use warnings;
  2         8  
  2         52  
6 2     2   15 use Carp;
  2         4  
  2         135  
7 2     2   2368 use IPC::Cmd;
  2         17680609  
  2         142  
8 2     2   2494 use Path::Class qw();
  2         272525  
  2         92  
9              
10             =head1 NAME
11              
12             Filesys::Btrfs - Simple wrapper around Linux L util.
13              
14             =head1 VERSION
15              
16             Version 0.01
17              
18             =cut
19              
20             our $VERSION = '0.03';
21              
22             =head1 SYNOPSIS
23              
24             Simple wrapper around Linux C util. Btrfs util is used to
25             manage btrfs filesystem: manage snapshots, subvolumes and etc. Only
26             subset of C options is supported (hopefuly it is useful
27             subset).
28              
29             For more information about C util please see L manpage.
30              
31             B This module is hightly experimental (as btrfs itself). API
32             can change in the future.
33              
34             Example:
35              
36             use Filesys::Btrfs;
37              
38             my $btrfs = Filesys::Btrfs->new($mount_point);
39             $btrfs->subvolume_create('subvolume');
40             ...
41              
42             Note: all methods croak if error occures.
43              
44             =head1 CONSTANTS
45              
46             =head2 Filesys::Btrfs::BTRFS_CMD
47              
48             Default path to look for btrfs program: C.
49              
50             =cut
51              
52 2     2   17 use constant BTRFS_CMD => '/sbin/btrfs';
  2         4  
  2         1792  
53              
54             =head1 METHODS
55              
56             =head2 Filesys::Btrfs->new($mount_point, %options);
57              
58             Create new C object.
59              
60             my $btrfs = Filesys::Btrfs->new('/mnt/disk');
61              
62             =over
63              
64             =item $mount_point
65              
66             Mount point of C filesystem. Filesystem has to be mounted before
67             this module can be used. All methods of C object operate
68             with paths absolute or relative to mount point.
69              
70             =item %options
71              
72             Additional options. Currently only one option is supported:
73             C - specifies different path to btrfs util.
74              
75             =back
76              
77             =cut
78              
79             sub new {
80 0     0 1   my ($class, $mount_point) = (shift, shift);
81 0 0         croak('Mount point is required') unless($mount_point);
82 0           my %options;
83 0 0         if(@_ % 2 == 0) {
84 0           %options = @_;
85             } else {
86 0 0         croak('Unexpected options: '.join(', ', @_)) if(@_);
87             }
88 0           my $btrfs_cmd = delete($options{btrfs_cmd});
89 0 0         croak('Unexpected options: '.join(', ', keys(%options))) if(%options);
90              
91 0 0         my $self = bless({
92             btrfs_cmd => $btrfs_cmd ? $btrfs_cmd : BTRFS_CMD(),
93             mount_point => Path::Class::dir($mount_point)
94             }, $class);
95              
96 0           return $self;
97             }
98              
99             =head2 $btrfs->btrfs_cmd();
100              
101             Returns path to C util being used.
102              
103             =cut
104              
105             sub btrfs_cmd {
106 0     0 1   return $_[0]->{btrfs_cmd};
107             }
108              
109             =head2 $btrfs->mount_point();
110              
111             Returns mount point being used.
112              
113             =cut
114              
115             sub mount_point {
116 0     0 1   return $_[0]->{mount_point};
117             }
118              
119             =head2 $btrfs->version();
120              
121             Returns version of btrfs util being used.
122              
123             =cut
124              
125             sub version {
126 0     0 1   my ($self) = @_;
127             #look at the last line of help output
128 0           my $stdout = $self->_run('help');
129 0           my ($version) = ($stdout->[-1] =~ /^Btrfs Btrfs v([0-9\.]+)$/m);
130 0 0         unless($version) {
131 0           warn('Cannot determine btrfs version');
132             }
133 0           return $version;
134             }
135              
136             =head2 $btrfs->subvolume_list($dir);
137              
138             Get list of all subvolumes. Returns hashref of (subvolume_name => id).
139              
140             =over
141              
142             =item $dir
143              
144             If C<$dir> is specified then only subvolumes located in this directory
145             are returned.
146              
147             =back
148              
149             =cut
150              
151             sub subvolume_list {
152 0     0 1   my ($self, $dir) = @_;
153 0 0         $dir = $self->_absolute_path($dir) if($dir);
154 0           my $stdout = $self->_run('subvolume', 'list', $self->{mount_point});
155 0           my %subvolumes;
156 0           foreach (@$stdout) {
157 0 0         if(my ($id, $path) = /^ID\s+(\d+)\s+.*\s+path\s+(.+)$/) {
158 0           my $absolute_path = $self->_absolute_path($path);
159 0 0 0       if(!$dir
      0        
160             || ($absolute_path ne $dir && $dir->subsumes($absolute_path))) {
161 0           $subvolumes{$path} = $id;
162             }
163             }
164             else {
165 0           warn('Cannot parse subvolume list result line: '.$_);
166             }
167             }
168 0           return \%subvolumes;
169             }
170              
171             =head2 $btrfs->subvolume_create($dir);
172              
173             Create new subvolume in C<$dir>.
174              
175             =cut
176              
177             sub subvolume_create {
178 0     0 1   my ($self, $dir) = @_;
179 0 0         croak('Dir is required') unless($dir);
180 0           $self->_run('subvolume', 'create', $self->_absolute_path($dir));
181             }
182              
183             =head2 $btrfs->subvolume_delete($dir);
184              
185             Delete subvolume in C<$dir>.
186              
187             =cut
188              
189             sub subvolume_delete {
190 0     0 1   my ($self, $dir) = @_;
191 0 0         croak('Dir is required') unless($dir);
192 0           $self->_run('subvolume', 'delete', $self->_absolute_path($dir));
193             }
194              
195             =head2 $btrfs->subvolume_set_default($id);
196              
197             Set subvolume with C<$id> to be mounted by default.
198              
199             =cut
200              
201             sub subvolume_set_default {
202 0     0 1   my ($self, $id) = @_;
203 0 0         croak('Subvolume id is required') unless(defined($id));
204 0           $self->_run('subvolume', 'set-default', $id, $self->{mount_point});
205             }
206              
207             =head2 $btrfs->filesystem_sync();
208              
209             Force a sync on filesystem.
210              
211             =cut
212              
213             sub filesystem_sync {
214 0     0 1   my ($self) = @_;
215 0           $self->_run('filesystem', 'sync', $self->{mount_point});
216             }
217              
218             =head2 $btrfs->filesystem_balance();
219              
220             Balance the chunks across the device.
221              
222             =cut
223              
224             sub filesystem_balance {
225 0     0 1   my ($self) = @_;
226 0           $self->_run('filesystem', 'balance', $self->{mount_point});
227             }
228              
229             # Private method. Calls btrfs util and performs simple processing.
230             # Returns arrayref with command output split by newlines.
231             sub _run {
232 0     0     my $self = shift;
233 0           my @cmd = ($self->{btrfs_cmd}, @_);
234 0           my ($success, $error_code, undef, $stdout, $stderr)
235             = IPC::Cmd::run(command => \@cmd, verbose => 0);
236 0 0         if($success) {
237 0 0         if(@$stderr) {
238 0           warn('Btrfs reported warnings to stderr: '.join('', @$stderr));
239             }
240 0           return [split('\n', join('', @$stdout))];
241             }
242             else {
243 0           croak("Error running btrfs command ($error_code): ".join('', @$stderr));
244             }
245             }
246              
247             #Private method. Makes path absolute using mount point as base dir.
248             sub _absolute_path {
249 0     0     my ($self, $path) = @_;
250 0           return Path::Class::dir($path)->absolute($self->{mount_point});
251             }
252              
253             =head1 AUTHOR
254              
255             Nikolay Martynov, C<< >>
256              
257             =head1 BUGS
258              
259             Please report any bugs or feature requests to C
260             rt.cpan.org>, or through the web interface at
261             L. I
262             will be notified, and then you'll automatically be notified of
263             progress on your bug as I make changes.
264              
265              
266              
267              
268             =head1 SUPPORT
269              
270             You can find documentation for this module with the perldoc command.
271              
272             perldoc Filesys::Btrfs
273              
274              
275             You can also look for information at:
276              
277             =over 4
278              
279             =item * RT: CPAN's request tracker (report bugs here)
280              
281             L
282              
283             =item * AnnoCPAN: Annotated CPAN documentation
284              
285             L
286              
287             =item * CPAN Ratings
288              
289             L
290              
291             =item * Search CPAN
292              
293             L
294              
295             =back
296              
297              
298             =head1 ACKNOWLEDGEMENTS
299              
300              
301             =head1 LICENSE AND COPYRIGHT
302              
303             Copyright 2011 Nikolay Martynov.
304              
305             This program is free software; you can redistribute it and/or modify it
306             under the terms of either: the GNU General Public License as published
307             by the Free Software Foundation; or the Artistic License.
308              
309             See http://dev.perl.org/licenses/ for more information.
310              
311              
312             =cut
313              
314             1; # End of Filesys::Btrfs