+sub _validate() {
+ my $self = shift;
+ my $dir = $self->{'dir'};
+
+ unless (-d $dir) {
+ return $self->make_error("fatal", undef,
+ message => "directory '$dir' does not exist");
+ }
+
+ if ($self->{'removable'}) {
+ my ($dev, $ino) = stat $dir;
+ my $parentdir = dirname $dir;
+ my ($pdev, $pino) = stat $parentdir;
+ if ($dev == $pdev) {
+ if ($self->{'mount'}) {
+ system $Amanda::Constants::MOUNT, $dir;
+ ($dev, $ino) = stat $dir;
+ }
+ }
+ if ($dev == $pdev) {
+ return $self->make_error("failed", undef,
+ reason => "notfound",
+ message => "No removable disk mounted on '$dir'");
+ }
+ }
+
+ if ($self->{'num-slot'}) {
+ for my $i (1..$self->{'num-slot'}) {
+ my $slot_dir = "$dir/slot$i";
+ if (!-e $slot_dir) {
+ if ($self->{'auto-create-slot'}) {
+ if (!mkdir ($slot_dir)) {
+ return $self->make_error("fatal", undef,
+ message => "Can't create '$slot_dir': $!");
+ }
+ } else {
+ return $self->make_error("fatal", undef,
+ message => "slot $i doesn't exists '$slot_dir'");
+ }
+ }
+ }
+ } else {
+ if ($self->{'auto-create-slot'}) {
+ return $self->make_error("fatal", undef,
+ message => "property 'auto-create-slot' set but property 'num-slot' is not set");
+ }
+ }
+ return undef;
+}
+
+sub try_lock {
+ my $self = shift;
+ my $cb = shift;
+ my $poll = 0; # first delay will be 0.1s; see below
+
+ my $steps = define_steps
+ cb_ref => \$cb;
+
+ step init => sub {
+ if ($self->{'mount'} && defined $self->{'fl'} &&
+ !$self->{'fl'}->locked()) {
+ return $steps->{'lock'}->();
+ }
+ $steps->{'lock_done'}->();
+ };
+
+ step lock => sub {
+ my $rv = $self->{'fl'}->lock_rd();
+ if ($rv == 1) {
+ # loop until we get the lock, increasing $poll to 10s
+ $poll += 100 unless $poll >= 10000;
+ return Amanda::MainLoop::call_after($poll, $steps->{'lock'});
+ } elsif ($rv == -1) {
+ return $self->make_error("fatal", $cb,
+ message => "Error locking '$self->{'umount_lockfile'}'");
+ } elsif ($rv == 0) {
+ if (defined $self->{'umount_src'}) {
+ $self->{'umount_src'}->remove();
+ $self->{'umount_src'} = undef;
+ }
+ return $steps->{'lock_done'}->();
+ }
+ };
+
+ step lock_done => sub {
+ my $err = $self->_validate();
+ $cb->($err);
+ };
+}
+
+sub try_umount {
+ my $self = shift;
+
+ my $dir = $self->{'dir'};
+ if ($self->{'removable'} && $self->{'umount'}) {
+ my ($dev, $ino) = stat $dir;
+ my $parentdir = dirname $dir;
+ my ($pdev, $pino) = stat $parentdir;
+ if ($dev != $pdev) {
+ system $Amanda::Constants::UMOUNT, $dir;
+ }
+ }
+}
+
+sub force_unlock {
+ my $self = shift;
+
+ if (keys( %{$self->{'reservation'}}) == 0 ) {
+ if ($self->{'fl'}) {
+ if ($self->{'fl'}->locked()) {
+ $self->{'fl'}->unlock();
+ }
+ if ($self->{'umount'}) {
+ if (defined $self->{'umount_src'}) {
+ $self->{'umount_src'}->remove();
+ $self->{'umount_src'} = undef;
+ }
+ if ($self->{'fl'}->lock_wr() == 0) {
+ $self->try_umount();
+ $self->{'fl'}->unlock();
+ }
+ }
+ }
+ }
+}
+
+sub try_unlock {
+ my $self = shift;
+
+ my $do_umount = sub {
+ local $?;
+
+ $self->{'umount_src'} = undef;
+ if ($self->{'fl'}->lock_wr() == 0) {
+ $self->try_umount();
+ $self->{'fl'}->unlock();
+ }
+ };
+
+ if (defined $self->{'umount_idle'}) {
+ if ($self->{'umount_idle'} == 0) {
+ return $self->force_unlock();
+ }
+ if (defined $self->{'fl'}) {
+ if (keys( %{$self->{'reservation'}}) == 0 ) {
+ if ($self->{'fl'}->locked()) {
+ $self->{'fl'}->unlock();
+ }
+ if ($self->{'umount'}) {
+ if (defined $self->{'umount_src'}) {
+ $self->{'umount_src'}->remove();
+ $self->{'umount_src'} = undef;
+ }
+ $self->{'umount_src'} = Amanda::MainLoop::call_after(
+ 0+$self->{'umount_idle'},
+ $do_umount);
+ }
+ }
+ }
+ }
+}
+