From 936c783c0f23ffbb3fdf51506f4e91dc087ff147 Mon Sep 17 00:00:00 2001 From: Srigovind Nayak <5201843+konidev20@users.noreply.github.com> Date: Sun, 30 Mar 2025 14:11:32 +0530 Subject: [PATCH 1/2] forget: exit code 3 for snapshot removal failures --- cmd/restic/cmd_forget.go | 9 +++++++++ cmd/restic/main.go | 2 ++ 2 files changed, 11 insertions(+) diff --git a/cmd/restic/cmd_forget.go b/cmd/restic/cmd_forget.go index 2bfacc4de..bea585ca9 100644 --- a/cmd/restic/cmd_forget.go +++ b/cmd/restic/cmd_forget.go @@ -41,6 +41,7 @@ EXIT STATUS Exit status is 0 if the command was successful. Exit status is 1 if there was any error. +Exit status is 3 if there was an error removing one or more snapshots. Exit status is 10 if the repository does not exist. Exit status is 11 if the repository is already locked. Exit status is 12 if the password is incorrect. @@ -62,6 +63,7 @@ Exit status is 12 if the password is incorrect. type ForgetPolicyCount int var ErrNegativePolicyCount = errors.New("negative values not allowed, use 'unlimited' instead") +var ErrFailedToRemoveOneOrMoreSnapshots = errors.New("failed to remove one or more snapshots") func (c *ForgetPolicyCount) Set(s string) error { switch s { @@ -304,12 +306,15 @@ func runForget(ctx context.Context, opts ForgetOptions, pruneOptions PruneOption return ctx.Err() } + // these are the snapshots that failed to be removed + failedSnIDs := restic.NewIDSet() if len(removeSnIDs) > 0 { if !opts.DryRun { bar := printer.NewCounter("files deleted") err := restic.ParallelRemove(ctx, repo, removeSnIDs, restic.WriteableSnapshotFile, func(id restic.ID, err error) error { if err != nil { printer.E("unable to remove %v/%v from the repository\n", restic.SnapshotFile, id) + failedSnIDs.Insert(id) } else { printer.VV("removed %v/%v\n", restic.SnapshotFile, id) } @@ -331,6 +336,10 @@ func runForget(ctx context.Context, opts ForgetOptions, pruneOptions PruneOption } } + if len(failedSnIDs) > 0 { + return ErrFailedToRemoveOneOrMoreSnapshots + } + if len(removeSnIDs) > 0 && opts.Prune { if opts.DryRun { printer.P("%d snapshots would be removed, running prune dry run\n", len(removeSnIDs)) diff --git a/cmd/restic/main.go b/cmd/restic/main.go index b04b3b9ab..f4b17aa92 100644 --- a/cmd/restic/main.go +++ b/cmd/restic/main.go @@ -206,6 +206,8 @@ func main() { exitCode = 0 case err == ErrInvalidSourceData: exitCode = 3 + case errors.Is(err, ErrFailedToRemoveOneOrMoreSnapshots): + exitCode = 3 case errors.Is(err, ErrNoRepository): exitCode = 10 case restic.IsAlreadyLocked(err): From d1649affb2ae12996d8bc7bc716517a651039019 Mon Sep 17 00:00:00 2001 From: Srigovind Nayak <5201843+konidev20@users.noreply.github.com> Date: Sun, 30 Mar 2025 14:12:06 +0530 Subject: [PATCH 2/2] chore: update changelog for issue-5233 --- changelog/unreleased/issue-5233 | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 changelog/unreleased/issue-5233 diff --git a/changelog/unreleased/issue-5233 b/changelog/unreleased/issue-5233 new file mode 100644 index 000000000..14ff2b249 --- /dev/null +++ b/changelog/unreleased/issue-5233 @@ -0,0 +1,8 @@ +Bugfix: forget command returns exit code 3 on partial removal of snapshots + +The `forget` command now returns exit code 3 when it fails to remove one or +more snapshots. Previously, it returned exit code 0, which could lead to +confusion if the command was used in a script. + +https://github.com/restic/restic/issues/5233 +https://github.com/restic/restic/pull/5322