From fd71e794ad4e56afa54784516fd2c2e709d1723f Mon Sep 17 00:00:00 2001 From: Michael Schout Date: Thu, 16 May 2019 11:38:39 -0500 Subject: [PATCH 1/3] Gracefully handle error when source dataset disappeared If the source dataset dissappeared before we were able to get the sanoid:sync property, do not set an error exit code. Handle this gracefully as this should not be considered an error. Fixes #380 --- syncoid | 36 +++++++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/syncoid b/syncoid index 21e9d1e..98403ec 100755 --- a/syncoid +++ b/syncoid @@ -290,7 +290,10 @@ sub syncdataset { if (!defined $sync) { # zfs already printed the corresponding error - if ($exitcode < 2) { $exitcode = 2; } + if (dataset_exists($sourcehost, $sourcefs, $sourceisroot) and $exitcode < 2) { + $exitcode = 2; + } + return 0; } @@ -1147,6 +1150,37 @@ sub getzfsvalue { return $value; } +sub dataset_exists { + my ($rhost, $fs, $isroot) = @_; + + my $fsescaped = escapeshellparam($fs); + + my $mysudocmd; + if ($isroot) { + $mysudocmd = ''; + } + else { + $mysudocmd = $sudocmd; + } + + my $command = "$rhost $mysudocmd $zfscmd get -H creation $fsescaped"; + + if ($debug) { + print "$command\n"; + } + + open my $fh, '-|', "$command 2>&1"; + my $result = <$fh>; + close $fh; + + if ($result =~ /dataset does not exist/) { + warn "$fsescaped does not exist...\n"; + return 0; + } + + return 1; +} + sub readablebytes { my $bytes = shift; my $disp; From 784efe2d85f05e4bb3ca8f060ec1cfefc902b48c Mon Sep 17 00:00:00 2001 From: Michael Schout Date: Thu, 16 May 2019 11:57:08 -0500 Subject: [PATCH 2/3] Remove debug warning --- syncoid | 1 - 1 file changed, 1 deletion(-) diff --git a/syncoid b/syncoid index 98403ec..c443b84 100755 --- a/syncoid +++ b/syncoid @@ -1174,7 +1174,6 @@ sub dataset_exists { close $fh; if ($result =~ /dataset does not exist/) { - warn "$fsescaped does not exist...\n"; return 0; } From 3892d73594c1e9faf14d65f5d0008095a005d98d Mon Sep 17 00:00:00 2001 From: Michael Schout Date: Wed, 29 May 2019 17:13:31 -0500 Subject: [PATCH 3/3] Capture output in getzfsvalue and handle datasets that disappeared Change getzfsvalue() so that if called in array context, returns the value and the error as a two element list. This allows the caller to recieve the error from the zfs command. If the dataset went away before fetching the sanoid:sync property, just issue a warning and skip it. --- syncoid | 55 ++++++++++++++++++------------------------------------- 1 file changed, 18 insertions(+), 37 deletions(-) diff --git a/syncoid b/syncoid index c443b84..f7a4b66 100755 --- a/syncoid +++ b/syncoid @@ -286,12 +286,18 @@ sub syncdataset { if ($debug) { print "DEBUG: syncing source $sourcefs to target $targetfs.\n"; } - my $sync = getzfsvalue($sourcehost,$sourcefs,$sourceisroot,'syncoid:sync'); + my ($sync, $error) = getzfsvalue($sourcehost,$sourcefs,$sourceisroot,'syncoid:sync'); if (!defined $sync) { # zfs already printed the corresponding error - if (dataset_exists($sourcehost, $sourcefs, $sourceisroot) and $exitcode < 2) { - $exitcode = 2; + if ($error =~ /\bdataset does not exist\b/) { + if (!$quiet) { print "WARN Skipping dataset (dataset no longer exists): $sourcefs...\n"; } + return 0; + } + else { + # print the error out and set exit code + print "ERROR: $error\n"; + if ($exitcode < 2) { $exitcode = 2 } } return 0; @@ -1137,47 +1143,22 @@ sub getzfsvalue { my $mysudocmd; if ($isroot) { $mysudocmd = ''; } else { $mysudocmd = $sudocmd; } if ($debug) { print "$rhost $mysudocmd $zfscmd get -H $property $fsescaped\n"; } - open FH, "$rhost $mysudocmd $zfscmd get -H $property $fsescaped |"; - my $value = ; - close FH; - - if (!defined $value) { - return undef; - } + my ($value, $error, $exit) = capture { + system("$rhost $mysudocmd $zfscmd get -H $property $fsescaped"); + }; my @values = split(/\t/,$value); $value = $values[2]; - return $value; -} -sub dataset_exists { - my ($rhost, $fs, $isroot) = @_; + my $wantarray = wantarray || 0; - my $fsescaped = escapeshellparam($fs); - - my $mysudocmd; - if ($isroot) { - $mysudocmd = ''; - } - else { - $mysudocmd = $sudocmd; + # If we are in scalar context and there is an error, print it out. + # Otherwise we assume the caller will deal with it. + if (!$wantarray and $error) { + print "ERROR getzfsvalue $fs $property: $error\n"; } - my $command = "$rhost $mysudocmd $zfscmd get -H creation $fsescaped"; - - if ($debug) { - print "$command\n"; - } - - open my $fh, '-|', "$command 2>&1"; - my $result = <$fh>; - close $fh; - - if ($result =~ /dataset does not exist/) { - return 0; - } - - return 1; + return $wantarray ? ($value, $error) : $value; } sub readablebytes {