From c41ff5335b1bcf111faa88039ba0189bc4912424 Mon Sep 17 00:00:00 2001 From: Maarten Vanraes Date: Sun, 5 Jun 2016 09:52:13 +0200 Subject: Mount: adjust to new PartLink system --- lib/ManaTools/Shared/disk_backend/Plugin/Mount.pm | 314 ++++++++++++++++++++-- 1 file changed, 299 insertions(+), 15 deletions(-) diff --git a/lib/ManaTools/Shared/disk_backend/Plugin/Mount.pm b/lib/ManaTools/Shared/disk_backend/Plugin/Mount.pm index 7817148c..b0e02e5c 100644 --- a/lib/ManaTools/Shared/disk_backend/Plugin/Mount.pm +++ b/lib/ManaTools/Shared/disk_backend/Plugin/Mount.pm @@ -66,6 +66,97 @@ has '+dependencies' => ( #============================================================= +=head2 changedpart + +=head3 INPUT + + $part: ManaTools::Shared::disk_backend::Part + $partstate: PartState + +=head3 OUTPUT + + 0 if failed, 1 if success or unneeded + +=head3 DESCRIPTION + + this overridden method will load/probe/save a mount point when it's called + +=cut + +#============================================================= +override ('changedpart', sub { + my $self = shift; + my $part = shift; + my $partstate = shift; + $self->D("$self: called changepart for mount: $part, $partstate"); + + ## LOAD + # read the partition table + if ($partstate == ManaTools::Shared::disk_backend::Part->LoadedState) { + # only BlockDevices for loading + } + + ## PROBE + # check in the kernel partition table by reading /sys + if ($partstate == ManaTools::Shared::disk_backend::Part->CurrentState) { + $self->D("$self: called changepart for probing partitiontable on $part"); + # only BlockDevices for loading + return 1 if (!$part->does('ManaTools::Shared::disk_backend::Mountable')); + + # TODO: we should look for changes wrt mounts + # we should check if this part is mounted or not and change accordingly + + # keep in mind that the probe will have done all mounts already, and made a link to the original device if not the filesystem itself + # a filesystem could be mounted several times to different paths + # NOTE: this may not be necessary and probe could've already done everything + + # there is no way to differentiate between an in-kernel empty partition table and no partition table + # so, we're not making an empty partition table entry for probed state + # since there is none, it'll just recreate the partition table (probably with the loaded state settings) anyway + # + # in any case, if there are no partition entries (in-kernel), we exit early. + my @devices = map { $_ =~ s'/size$''r } glob($part->devicepath(). "/*/size"); + return 1 if (!scalar(@devices)); + + # look or make the PartitionTable as a child of the BlockDevice + my $parttable = $part->trychild($partstate, undef, 'PartitionTable', {plugin => $self, loaded => undef, saved => undef}); + my @changedparts = ($parttable); + + # find subdevices in /sys/ + my $prevchild = undef; + for my $pf (@devices) { + # look or create the child with id based on the filename + my $child = $parttable->trychild($partstate, sub { + my $self = shift; + my $parameters = shift; + return ($self->devicepath() =~ s'^.+/''r eq $parameters->{devicepath} =~ s'^.+/''r); + },'PartitionElement', {plugin => $self, devicepath => $pf, loaded => undef, saved => undef}); + + # add the child to the changedparts + push @changedparts, $child; + } + + # trigger changedpart on all children for other plugins to load further + for my $p (@changedparts) { + $p->changedpart($partstate); + } + } + + ## SAVE + # save the partition table + if ($partstate == ManaTools::Shared::disk_backend::Part->FutureState) { + # in all child parts, find PartitionTable entries and trigger ->save(); + for my $p ($part->find_parts(undef, 'child')) { + # TODO: need to be able to abort during save!!! + $p->save(); + } + } + + return 1; +}); + +#============================================================= + =head2 probe =head3 OUTPUT @@ -86,17 +177,77 @@ override ('probe', sub { open F, ') { my @fields = split(/ /, $line); - my $part = $self->parent->mkpart('Mount', {path => $fields[4], plugin => $self}); - $part->prop('options', $fields[5]); - $part->prop('dev', $fields[2]); - $part->prop('id', $fields[0]); - $part->prop('parent', $fields[1]); - $part->prop('srcdevpath', $fields[3]); - $part->prop('fstype', $fields[8]); - $part->prop('srcmount', $fields[9]); + ## try to find the filesystem + # + ## try to find device + # if not found, create an UnknownBlockDevice for it + my $bd = $self->parent(); + my $devpart = undef; + # TODO: what about --bind mount points + # TODO: keep in mind loopbacked files! + my @parts = grep { $_->type() ne 'Mount' } $bd->findpartprop(undef, 'dev', $fields[2]); + if (scalar(@parts) == 0) { + $devpart = $bd->mkpart('UnknownBlockDevice', {plugin => $self, devicepath => $fields[4], loaded => undef, saved => undef}); + $devpart->prop('dev', $fields[2]); + } + else { + $devpart = $parts[0]; + } + + ## try to find filesystem + # if not found, create an UnknownFS for it + $self->D('find dev %s with fstype %s (srcmount %s)', $fields[2], $fields[8], $fields[9]); + my $fs = $devpart->trychild(ManaTools::Shared::disk_backend::Part->CurrentState, sub { + my $self = shift; + my $parameters = shift; + my $dev = shift; + my $fstype = shift; + + # only filesystems + return 0 if !$self->does('ManaTools::Shared::disk_backend::FileSystem'); + $self->plugin()->D('part is a FileSystem with type %s', $self->prop('fstype')); + + # needs to be this fstype + return 0 if ($self->prop('fstype') ne $fields[8]); + + # TODO: need to check srcmount $fields[9] as well + + # if one of the parent matches dev $field[2], then it's ok + my @parents = $self->find_parts(undef, 'parent'); + $self->plugin()->D('FileSystem part has %d parents', scalar(@parents)); + for my $parent (@parents) { + # check state + next if !$parent->is_state(ManaTools::Shared::disk_backend::Part->CurrentState); + # check dev + $self->plugin()->D('parent of part has dev %s', $parent->prop('dev')); + return 1 if $parent->prop('dev') eq $fields[2]; + } + + # not found + return 0; + }, 'UnknownFS', {plugin => $self, loaded => undef, saved => undef}); + $fs->prop('fstype', $fields[8]); + + ## TODO: check filesystem and sourcepath options to select the actual parent + # + ## from this parent, create the mount point + # look or create the child with id based on the path + my $child = $fs->trychild(ManaTools::Shared::disk_backend::Part->CurrentState, sub { + my $self = shift; + my $parameters = shift; + return ($self->path() eq $parameters->{path}); + },'Mount', {plugin => $self, path => $fields[4], loaded => undef, saved => undef}); + + $child->prop('options', $fields[5]); + $child->prop('dev', $fields[2]); + $child->prop('id', $fields[0]); + $child->prop('parent', $fields[1]); + $child->prop('srcdevpath', $fields[3]); + $child->prop('fstype', $fields[8]); + $child->prop('srcmount', $fields[9]); # add an unmount action - $part->add_action('unmount', 'Unmount', undef, sub { + $child->add_action('unmount', 'Unmount', undef, sub { my $self = shift; print STDERR "Unmount is not implemented...\n"; return 1; @@ -107,13 +258,13 @@ override ('probe', sub { if ($fields[1] != $fields[0]) { # find parent and put into parentmount field my @parts = $self->parent->findpartprop('Mount', 'id', $fields[1]); - $part->parentmount($parts[0]) if scalar(@parts) > 0; + $child->parentmount($parts[0]) if scalar(@parts) > 0; } # find missing children Mount Part - my @parts = $self->parent->findpartprop('Mount', 'parent', $fields[0]); + @parts = $self->parent->findpartprop('Mount', 'parent', $fields[0]); for my $p (@parts) { my $pm = $p->parentmount(); - $p->parentmount($part) if (!defined $pm); + $p->parentmount($child) if (!defined $pm); } ## get the in IO @@ -141,13 +292,13 @@ override ('probe', sub { my $in = shift; my $mount = shift; return ($plugin->does('ManaTools::Shared::disk_backend::FileSystem') and $plugin->has_type($type) and $plugin->fsprobe($in, $mount)); - }, $fields[8], $in, $part); + }, $fields[8], $in, $child); if (defined $out) { - my $res = $part->in_add($out); + my $res = $child->in_add($out); } else { - $part->in_add($in); + $child->in_add($in); } # TODO: look up device with this @@ -249,4 +400,137 @@ class_has '+out_restriction' => ( } ); +class_has '+restrictions' => ( + default => sub { + return { + sibling => sub { + my $self = shift; + my $part = shift; + return 0; + }, + parentmount => sub { + my $self = shift; + my $part = shift; + return $part->isa('ManaTools::Shared::disk_backend::Part::Mount'); + }, + childmount => sub { + my $self = shift; + my $part = shift; + return $part->isa('ManaTools::Shared::disk_backend::Part::Mount'); + }, + parent => sub { + my $self = shift; + my $part = shift; + return $part->does('ManaTools::Shared::disk_backend::FileSystem'); + }, + child => sub { + my $self = shift; + my $part = shift; + return $part->does('ManaTools::Shared::disk_backend::FileRole') || $part->does('ManaTools::Shared::disk_backend::DirectoryRole'); + }, + } + } +); + +override('_reverse_tag', sub { + my $tag = shift; + return 'childmount' if ($tag eq 'parentmount'); + return 'parentmount' if ($tag eq 'childmount'); + return super; +}); + +package ManaTools::Shared::disk_backend::Part::UnknownBlockDevice; + +use Moose; + +extends 'ManaTools::Shared::disk_backend::Part'; + +use MooseX::ClassAttribute; + +with 'ManaTools::Shared::disk_backend::BlockDevice'; + +class_has '+type' => ( + default => 'UnknownBlockDevice' +); + +class_has '+restrictions' => ( + default => sub { + return { + sibling => sub { + my $self = shift; + my $part = shift; + return 0; + }, + parent => sub { + my $self = shift; + my $part = shift; + return 0; + }, + } + } +); + +package ManaTools::Shared::disk_backend::Part::UnknownFS; + +use Moose; + +extends 'ManaTools::Shared::disk_backend::Part'; + +use MooseX::ClassAttribute; + +with 'ManaTools::Shared::disk_backend::FileSystem'; + +class_has '+type' => ( + default => 'UnknownFS' +); + +class_has '+restrictions' => ( + default => sub { + return { + sibling => sub { + my $self = shift; + my $part = shift; + return 0; + }, + parent => sub { + my $self = shift; + my $part = shift; + return $part->does('ManaTools::Shared::disk_backend::BlockDevice'); + }, + } + } +); + +#============================================================= + +=head2 fsprobe + +=head3 INPUT + + $io: ManaTools::Shared::disk_backend::IO | Str + $mount: ManaTools::Shared::disk_backend::Part::Mount + +=head3 OUTPUT + + ManaTools::Shared::disk_backend::IO or undef + +=head3 DESCRIPTION + + this method probes the IO to see if it fits for this + filesystem, if it does, create a new Part with this IO as in. + also create an IO (linked as the out) and return that one. + The resulting one can then be used as an in to eg: a Mount Part. + +=cut + +#============================================================= +sub fsprobe { + my $self = shift; + my $io = shift; + my $mount = shift; + + # return $fs to be link as an in IO into $mount Part + return undef; +} + 1; -- cgit v1.2.1