diff --git a/changelog/unreleased/pull-4884 b/changelog/unreleased/pull-4884 new file mode 100644 index 000000000..ff2bff967 --- /dev/null +++ b/changelog/unreleased/pull-4884 @@ -0,0 +1,11 @@ +Change: return exit code 10 or 11 if repository does not exist or is locked + +If a repository does not exist or cannot be locked, then restic always returned +exit code 1. This made it difficult to distinguish these cases from other +errors. + +Now, restic returns exit code 10 if the repository does not exist and exit code +11 if the repository could be not locked due to a conflicting lock. + +https://github.com/restic/restic/issues/956 +https://github.com/restic/restic/pull/4884 diff --git a/cmd/restic/cmd_backup.go b/cmd/restic/cmd_backup.go index 434469683..9957b5784 100644 --- a/cmd/restic/cmd_backup.go +++ b/cmd/restic/cmd_backup.go @@ -41,6 +41,8 @@ EXIT STATUS Exit status is 0 if the command was successful. Exit status is 1 if there was a fatal error (no snapshot created). Exit status is 3 if some source data could not be read (incomplete snapshot created). +Exit status is 10 if the repository does not exist. +Exit status is 11 if the repository is already locked. `, PreRun: func(_ *cobra.Command, _ []string) { if backupOptions.Host == "" { diff --git a/cmd/restic/cmd_cache.go b/cmd/restic/cmd_cache.go index 651c65fcf..e71d38365 100644 --- a/cmd/restic/cmd_cache.go +++ b/cmd/restic/cmd_cache.go @@ -25,7 +25,8 @@ The "cache" command allows listing and cleaning local cache directories. EXIT STATUS =========== -Exit status is 0 if the command was successful, and non-zero if there was any error. +Exit status is 0 if the command was successful. +Exit status is 1 if there was any error. `, DisableAutoGenTag: true, RunE: func(_ *cobra.Command, args []string) error { diff --git a/cmd/restic/cmd_cat.go b/cmd/restic/cmd_cat.go index 23205771a..693c26790 100644 --- a/cmd/restic/cmd_cat.go +++ b/cmd/restic/cmd_cat.go @@ -21,7 +21,10 @@ The "cat" command is used to print internal objects to stdout. EXIT STATUS =========== -Exit status is 0 if the command was successful, and non-zero if there was any error. +Exit status is 0 if the command was successful. +Exit status is 1 if there was any error. +Exit status is 10 if the repository does not exist. +Exit status is 11 if the repository is already locked. `, DisableAutoGenTag: true, RunE: func(cmd *cobra.Command, args []string) error { diff --git a/cmd/restic/cmd_check.go b/cmd/restic/cmd_check.go index f416c9269..9cccc0609 100644 --- a/cmd/restic/cmd_check.go +++ b/cmd/restic/cmd_check.go @@ -35,7 +35,10 @@ repository and not use a local cache. EXIT STATUS =========== -Exit status is 0 if the command was successful, and non-zero if there was any error. +Exit status is 0 if the command was successful. +Exit status is 1 if there was any error. +Exit status is 10 if the repository does not exist. +Exit status is 11 if the repository is already locked. `, DisableAutoGenTag: true, RunE: func(cmd *cobra.Command, args []string) error { diff --git a/cmd/restic/cmd_copy.go b/cmd/restic/cmd_copy.go index d12501dd9..d7761174a 100644 --- a/cmd/restic/cmd_copy.go +++ b/cmd/restic/cmd_copy.go @@ -30,6 +30,14 @@ This means that copied files, which existed in both the source and destination repository, /may occupy up to twice their space/ in the destination repository. This can be mitigated by the "--copy-chunker-params" option when initializing a new destination repository using the "init" command. + +EXIT STATUS +=========== + +Exit status is 0 if the command was successful. +Exit status is 1 if there was any error. +Exit status is 10 if the repository does not exist. +Exit status is 11 if the repository is already locked. `, RunE: func(cmd *cobra.Command, args []string) error { return runCopy(cmd.Context(), copyOptions, globalOptions, args) diff --git a/cmd/restic/cmd_debug.go b/cmd/restic/cmd_debug.go index 1a42995fd..74c21df24 100644 --- a/cmd/restic/cmd_debug.go +++ b/cmd/restic/cmd_debug.go @@ -43,7 +43,10 @@ is used for debugging purposes only. EXIT STATUS =========== -Exit status is 0 if the command was successful, and non-zero if there was any error. +Exit status is 0 if the command was successful. +Exit status is 1 if there was any error. +Exit status is 10 if the repository does not exist. +Exit status is 11 if the repository is already locked. `, DisableAutoGenTag: true, RunE: func(cmd *cobra.Command, args []string) error { diff --git a/cmd/restic/cmd_diff.go b/cmd/restic/cmd_diff.go index fd54897f1..6488a7c35 100644 --- a/cmd/restic/cmd_diff.go +++ b/cmd/restic/cmd_diff.go @@ -39,7 +39,10 @@ snapshot. EXIT STATUS =========== -Exit status is 0 if the command was successful, and non-zero if there was any error. +Exit status is 0 if the command was successful. +Exit status is 1 if there was any error. +Exit status is 10 if the repository does not exist. +Exit status is 11 if the repository is already locked. `, DisableAutoGenTag: true, RunE: func(cmd *cobra.Command, args []string) error { diff --git a/cmd/restic/cmd_dump.go b/cmd/restic/cmd_dump.go index 2a98a8ae8..7e1efa3ae 100644 --- a/cmd/restic/cmd_dump.go +++ b/cmd/restic/cmd_dump.go @@ -34,7 +34,10 @@ snapshot. EXIT STATUS =========== -Exit status is 0 if the command was successful, and non-zero if there was any error. +Exit status is 0 if the command was successful. +Exit status is 1 if there was any error. +Exit status is 10 if the repository does not exist. +Exit status is 11 if the repository is already locked. `, DisableAutoGenTag: true, RunE: func(cmd *cobra.Command, args []string) error { diff --git a/cmd/restic/cmd_features.go b/cmd/restic/cmd_features.go index 8125d3e26..497013696 100644 --- a/cmd/restic/cmd_features.go +++ b/cmd/restic/cmd_features.go @@ -28,7 +28,8 @@ A _deprecated_ feature is always disabled and cannot be enabled. The flag will b EXIT STATUS =========== -Exit status is 0 if the command was successful, and non-zero if there was any error. +Exit status is 0 if the command was successful. +Exit status is 1 if there was any error. `, Hidden: true, DisableAutoGenTag: true, diff --git a/cmd/restic/cmd_find.go b/cmd/restic/cmd_find.go index 59e34c468..4f9549ca4 100644 --- a/cmd/restic/cmd_find.go +++ b/cmd/restic/cmd_find.go @@ -33,7 +33,10 @@ restic find --pack 025c1d06 EXIT STATUS =========== -Exit status is 0 if the command was successful, and non-zero if there was any error. +Exit status is 0 if the command was successful. +Exit status is 1 if there was any error. +Exit status is 10 if the repository does not exist. +Exit status is 11 if the repository is already locked. `, DisableAutoGenTag: true, RunE: func(cmd *cobra.Command, args []string) error { diff --git a/cmd/restic/cmd_forget.go b/cmd/restic/cmd_forget.go index 4fd931ff0..87738b518 100644 --- a/cmd/restic/cmd_forget.go +++ b/cmd/restic/cmd_forget.go @@ -35,7 +35,10 @@ security considerations. EXIT STATUS =========== -Exit status is 0 if the command was successful, and non-zero if there was any error. +Exit status is 0 if the command was successful. +Exit status is 1 if there was any error. +Exit status is 10 if the repository does not exist. +Exit status is 11 if the repository is already locked. `, DisableAutoGenTag: true, RunE: func(cmd *cobra.Command, args []string) error { diff --git a/cmd/restic/cmd_generate.go b/cmd/restic/cmd_generate.go index ba710e708..b5c7cecb5 100644 --- a/cmd/restic/cmd_generate.go +++ b/cmd/restic/cmd_generate.go @@ -18,7 +18,8 @@ and the auto-completion files for bash, fish and zsh). EXIT STATUS =========== -Exit status is 0 if the command was successful, and non-zero if there was any error. +Exit status is 0 if the command was successful. +Exit status is 1 if there was any error. `, DisableAutoGenTag: true, RunE: func(_ *cobra.Command, args []string) error { diff --git a/cmd/restic/cmd_init.go b/cmd/restic/cmd_init.go index e6ea69441..3c0319e55 100644 --- a/cmd/restic/cmd_init.go +++ b/cmd/restic/cmd_init.go @@ -23,7 +23,8 @@ The "init" command initializes a new repository. EXIT STATUS =========== -Exit status is 0 if the command was successful, and non-zero if there was any error. +Exit status is 0 if the command was successful. +Exit status is 1 if there was any error. `, DisableAutoGenTag: true, RunE: func(cmd *cobra.Command, args []string) error { diff --git a/cmd/restic/cmd_key_add.go b/cmd/restic/cmd_key_add.go index d38991f09..c9f0ef233 100644 --- a/cmd/restic/cmd_key_add.go +++ b/cmd/restic/cmd_key_add.go @@ -19,7 +19,10 @@ The "add" sub-command creates a new key and validates the key. Returns the new k EXIT STATUS =========== -Exit status is 0 if the command is successful, and non-zero if there was any error. +Exit status is 0 if the command was successful. +Exit status is 1 if there was any error. +Exit status is 10 if the repository does not exist. +Exit status is 11 if the repository is already locked. `, DisableAutoGenTag: true, } diff --git a/cmd/restic/cmd_key_list.go b/cmd/restic/cmd_key_list.go index fcca6055a..ae751a487 100644 --- a/cmd/restic/cmd_key_list.go +++ b/cmd/restic/cmd_key_list.go @@ -23,7 +23,10 @@ used to access the repository. EXIT STATUS =========== -Exit status is 0 if the command is successful, and non-zero if there was any error. +Exit status is 0 if the command was successful. +Exit status is 1 if there was any error. +Exit status is 10 if the repository does not exist. +Exit status is 11 if the repository is already locked. `, DisableAutoGenTag: true, RunE: func(cmd *cobra.Command, args []string) error { diff --git a/cmd/restic/cmd_key_passwd.go b/cmd/restic/cmd_key_passwd.go index 1a1200109..723acaaab 100644 --- a/cmd/restic/cmd_key_passwd.go +++ b/cmd/restic/cmd_key_passwd.go @@ -19,7 +19,10 @@ Returns the new key ID. EXIT STATUS =========== -Exit status is 0 if the command is successful, and non-zero if there was any error. +Exit status is 0 if the command was successful. +Exit status is 1 if there was any error. +Exit status is 10 if the repository does not exist. +Exit status is 11 if the repository is already locked. `, DisableAutoGenTag: true, } diff --git a/cmd/restic/cmd_key_remove.go b/cmd/restic/cmd_key_remove.go index 93babb4f3..c4c24fdb7 100644 --- a/cmd/restic/cmd_key_remove.go +++ b/cmd/restic/cmd_key_remove.go @@ -20,7 +20,10 @@ removing the current key being used to access the repository. EXIT STATUS =========== -Exit status is 0 if the command is successful, and non-zero if there was any error. +Exit status is 0 if the command was successful. +Exit status is 1 if there was any error. +Exit status is 10 if the repository does not exist. +Exit status is 11 if the repository is already locked. `, DisableAutoGenTag: true, RunE: func(cmd *cobra.Command, args []string) error { diff --git a/cmd/restic/cmd_list.go b/cmd/restic/cmd_list.go index 6f4430420..060bca871 100644 --- a/cmd/restic/cmd_list.go +++ b/cmd/restic/cmd_list.go @@ -19,7 +19,10 @@ The "list" command allows listing objects in the repository based on type. EXIT STATUS =========== -Exit status is 0 if the command was successful, and non-zero if there was any error. +Exit status is 0 if the command was successful. +Exit status is 1 if there was any error. +Exit status is 10 if the repository does not exist. +Exit status is 11 if the repository is already locked. `, DisableAutoGenTag: true, RunE: func(cmd *cobra.Command, args []string) error { diff --git a/cmd/restic/cmd_ls.go b/cmd/restic/cmd_ls.go index 6e48b010f..d9a3b0fb8 100644 --- a/cmd/restic/cmd_ls.go +++ b/cmd/restic/cmd_ls.go @@ -39,7 +39,10 @@ a path separator); paths use the forward slash '/' as separator. EXIT STATUS =========== -Exit status is 0 if the command was successful, and non-zero if there was any error. +Exit status is 0 if the command was successful. +Exit status is 1 if there was any error. +Exit status is 10 if the repository does not exist. +Exit status is 11 if the repository is already locked. `, DisableAutoGenTag: true, RunE: func(cmd *cobra.Command, args []string) error { diff --git a/cmd/restic/cmd_migrate.go b/cmd/restic/cmd_migrate.go index 0f9bdde1a..e89980050 100644 --- a/cmd/restic/cmd_migrate.go +++ b/cmd/restic/cmd_migrate.go @@ -22,7 +22,10 @@ names are specified, these migrations are applied. EXIT STATUS =========== -Exit status is 0 if the command was successful, and non-zero if there was any error. +Exit status is 0 if the command was successful. +Exit status is 1 if there was any error. +Exit status is 10 if the repository does not exist. +Exit status is 11 if the repository is already locked. `, DisableAutoGenTag: true, RunE: func(cmd *cobra.Command, args []string) error { diff --git a/cmd/restic/cmd_mount.go b/cmd/restic/cmd_mount.go index 5a10447f3..3e0b159be 100644 --- a/cmd/restic/cmd_mount.go +++ b/cmd/restic/cmd_mount.go @@ -64,7 +64,10 @@ The default path templates are: EXIT STATUS =========== -Exit status is 0 if the command was successful, and non-zero if there was any error. +Exit status is 0 if the command was successful. +Exit status is 1 if there was any error. +Exit status is 10 if the repository does not exist. +Exit status is 11 if the repository is already locked. `, DisableAutoGenTag: true, RunE: func(cmd *cobra.Command, args []string) error { diff --git a/cmd/restic/cmd_options.go b/cmd/restic/cmd_options.go index 85e062220..4cd574b68 100644 --- a/cmd/restic/cmd_options.go +++ b/cmd/restic/cmd_options.go @@ -17,7 +17,8 @@ The "options" command prints a list of extended options. EXIT STATUS =========== -Exit status is 0 if the command was successful, and non-zero if there was any error. +Exit status is 0 if the command was successful. +Exit status is 1 if there was any error. `, Hidden: true, DisableAutoGenTag: true, diff --git a/cmd/restic/cmd_prune.go b/cmd/restic/cmd_prune.go index f0bfa2b94..7e706ccf8 100644 --- a/cmd/restic/cmd_prune.go +++ b/cmd/restic/cmd_prune.go @@ -28,7 +28,10 @@ referenced and therefore not needed any more. EXIT STATUS =========== -Exit status is 0 if the command was successful, and non-zero if there was any error. +Exit status is 0 if the command was successful. +Exit status is 1 if there was any error. +Exit status is 10 if the repository does not exist. +Exit status is 11 if the repository is already locked. `, DisableAutoGenTag: true, RunE: func(cmd *cobra.Command, _ []string) error { diff --git a/cmd/restic/cmd_recover.go b/cmd/restic/cmd_recover.go index 726f1bf65..5e4744bb6 100644 --- a/cmd/restic/cmd_recover.go +++ b/cmd/restic/cmd_recover.go @@ -22,7 +22,10 @@ It can be used if, for example, a snapshot has been removed by accident with "fo EXIT STATUS =========== -Exit status is 0 if the command was successful, and non-zero if there was any error. +Exit status is 0 if the command was successful. +Exit status is 1 if there was any error. +Exit status is 10 if the repository does not exist. +Exit status is 11 if the repository is already locked. `, DisableAutoGenTag: true, RunE: func(cmd *cobra.Command, _ []string) error { diff --git a/cmd/restic/cmd_repair_index.go b/cmd/restic/cmd_repair_index.go index 50ba16e33..e6b6e9fa5 100644 --- a/cmd/restic/cmd_repair_index.go +++ b/cmd/restic/cmd_repair_index.go @@ -19,7 +19,10 @@ repository. EXIT STATUS =========== -Exit status is 0 if the command was successful, and non-zero if there was any error. +Exit status is 0 if the command was successful. +Exit status is 1 if there was any error. +Exit status is 10 if the repository does not exist. +Exit status is 11 if the repository is already locked. `, DisableAutoGenTag: true, RunE: func(cmd *cobra.Command, _ []string) error { diff --git a/cmd/restic/cmd_repair_packs.go b/cmd/restic/cmd_repair_packs.go index ab8c7f475..b0afefb2d 100644 --- a/cmd/restic/cmd_repair_packs.go +++ b/cmd/restic/cmd_repair_packs.go @@ -23,7 +23,10 @@ the index to remove the damaged pack files and removes the pack files from the r EXIT STATUS =========== -Exit status is 0 if the command was successful, and non-zero if there was any error. +Exit status is 0 if the command was successful. +Exit status is 1 if there was any error. +Exit status is 10 if the repository does not exist. +Exit status is 11 if the repository is already locked. `, DisableAutoGenTag: true, RunE: func(cmd *cobra.Command, args []string) error { diff --git a/cmd/restic/cmd_repair_snapshots.go b/cmd/restic/cmd_repair_snapshots.go index be5ef4ad9..fc221ebea 100644 --- a/cmd/restic/cmd_repair_snapshots.go +++ b/cmd/restic/cmd_repair_snapshots.go @@ -37,7 +37,10 @@ snapshot! EXIT STATUS =========== -Exit status is 0 if the command was successful, and non-zero if there was any error. +Exit status is 0 if the command was successful. +Exit status is 1 if there was any error. +Exit status is 10 if the repository does not exist. +Exit status is 11 if the repository is already locked. `, DisableAutoGenTag: true, RunE: func(cmd *cobra.Command, args []string) error { diff --git a/cmd/restic/cmd_restore.go b/cmd/restic/cmd_restore.go index e21d0bd94..89942f4cf 100644 --- a/cmd/restic/cmd_restore.go +++ b/cmd/restic/cmd_restore.go @@ -32,7 +32,10 @@ syntax, where "subfolder" is a path within the snapshot. EXIT STATUS =========== -Exit status is 0 if the command was successful, and non-zero if there was any error. +Exit status is 0 if the command was successful. +Exit status is 1 if there was any error. +Exit status is 10 if the repository does not exist. +Exit status is 11 if the repository is already locked. `, DisableAutoGenTag: true, RunE: func(cmd *cobra.Command, args []string) error { diff --git a/cmd/restic/cmd_rewrite.go b/cmd/restic/cmd_rewrite.go index 83ace7a11..73bc32f6f 100644 --- a/cmd/restic/cmd_rewrite.go +++ b/cmd/restic/cmd_rewrite.go @@ -38,7 +38,10 @@ use the "prune" command. EXIT STATUS =========== -Exit status is 0 if the command was successful, and non-zero if there was any error. +Exit status is 0 if the command was successful. +Exit status is 1 if there was any error. +Exit status is 10 if the repository does not exist. +Exit status is 11 if the repository is already locked. `, DisableAutoGenTag: true, RunE: func(cmd *cobra.Command, args []string) error { diff --git a/cmd/restic/cmd_self_update.go b/cmd/restic/cmd_self_update.go index 4b86c416f..0fce41241 100644 --- a/cmd/restic/cmd_self_update.go +++ b/cmd/restic/cmd_self_update.go @@ -24,7 +24,10 @@ files. EXIT STATUS =========== -Exit status is 0 if the command was successful, and non-zero if there was any error. +Exit status is 0 if the command was successful. +Exit status is 1 if there was any error. +Exit status is 10 if the repository does not exist. +Exit status is 11 if the repository is already locked. `, DisableAutoGenTag: true, RunE: func(cmd *cobra.Command, args []string) error { diff --git a/cmd/restic/cmd_snapshots.go b/cmd/restic/cmd_snapshots.go index ea15af019..9112e1b95 100644 --- a/cmd/restic/cmd_snapshots.go +++ b/cmd/restic/cmd_snapshots.go @@ -23,7 +23,10 @@ The "snapshots" command lists all snapshots stored in the repository. EXIT STATUS =========== -Exit status is 0 if the command was successful, and non-zero if there was any error. +Exit status is 0 if the command was successful. +Exit status is 1 if there was any error. +Exit status is 10 if the repository does not exist. +Exit status is 11 if the repository is already locked. `, DisableAutoGenTag: true, RunE: func(cmd *cobra.Command, args []string) error { diff --git a/cmd/restic/cmd_stats.go b/cmd/restic/cmd_stats.go index 0f8e45f36..8a78d57f7 100644 --- a/cmd/restic/cmd_stats.go +++ b/cmd/restic/cmd_stats.go @@ -49,7 +49,10 @@ Refer to the online manual for more details about each mode. EXIT STATUS =========== -Exit status is 0 if the command was successful, and non-zero if there was any error. +Exit status is 0 if the command was successful. +Exit status is 1 if there was any error. +Exit status is 10 if the repository does not exist. +Exit status is 11 if the repository is already locked. `, DisableAutoGenTag: true, RunE: func(cmd *cobra.Command, args []string) error { diff --git a/cmd/restic/cmd_tag.go b/cmd/restic/cmd_tag.go index 033dc5ebe..ea73955f0 100644 --- a/cmd/restic/cmd_tag.go +++ b/cmd/restic/cmd_tag.go @@ -25,7 +25,10 @@ When no snapshotID is given, all snapshots matching the host, tag and path filte EXIT STATUS =========== -Exit status is 0 if the command was successful, and non-zero if there was any error. +Exit status is 0 if the command was successful. +Exit status is 1 if there was any error. +Exit status is 10 if the repository does not exist. +Exit status is 11 if the repository is already locked. `, DisableAutoGenTag: true, RunE: func(cmd *cobra.Command, args []string) error { diff --git a/cmd/restic/cmd_unlock.go b/cmd/restic/cmd_unlock.go index 6893f3365..96eef7e02 100644 --- a/cmd/restic/cmd_unlock.go +++ b/cmd/restic/cmd_unlock.go @@ -16,7 +16,8 @@ The "unlock" command removes stale locks that have been created by other restic EXIT STATUS =========== -Exit status is 0 if the command was successful, and non-zero if there was any error. +Exit status is 0 if the command was successful. +Exit status is 1 if there was any error. `, DisableAutoGenTag: true, RunE: func(cmd *cobra.Command, _ []string) error { diff --git a/cmd/restic/cmd_version.go b/cmd/restic/cmd_version.go index e3f9b3010..cd32e2470 100644 --- a/cmd/restic/cmd_version.go +++ b/cmd/restic/cmd_version.go @@ -18,7 +18,8 @@ and the version of this software. EXIT STATUS =========== -Exit status is 0 if the command was successful, and non-zero if there was any error. +Exit status is 0 if the command was successful. +Exit status is 1 if there was any error. `, DisableAutoGenTag: true, Run: func(_ *cobra.Command, _ []string) { diff --git a/cmd/restic/global.go b/cmd/restic/global.go index cd6a683bf..be485dc3b 100644 --- a/cmd/restic/global.go +++ b/cmd/restic/global.go @@ -43,6 +43,10 @@ import ( "golang.org/x/term" ) +// ErrNoRepository is used to report if opening a repsitory failed due +// to a missing backend storage location or config file +var ErrNoRepository = errors.New("repository does not exist") + var version = "0.16.5-dev (compiled manually)" // TimeFormat is the format used for all timestamps printed by restic. @@ -607,6 +611,9 @@ func innerOpen(ctx context.Context, s string, gopts GlobalOptions, opts options. be, err = factory.Open(ctx, cfg, rt, lim) } + if errors.Is(err, backend.ErrNoRepository) { + return nil, fmt.Errorf("Fatal: %w at %v: %v", ErrNoRepository, location.StripPassword(gopts.backends, s), err) + } if err != nil { return nil, errors.Fatalf("unable to open repository at %v: %v", location.StripPassword(gopts.backends, s), err) } @@ -635,6 +642,9 @@ func open(ctx context.Context, s string, gopts GlobalOptions, opts options.Optio // check if config is there fi, err := be.Stat(ctx, backend.Handle{Type: restic.ConfigFile}) + if be.IsNotExist(err) { + return nil, fmt.Errorf("Fatal: %w: unable to open config file: %v\nIs there a repository at the following location?\n%v", ErrNoRepository, err, location.StripPassword(gopts.backends, s)) + } if err != nil { return nil, errors.Fatalf("unable to open config file: %v\nIs there a repository at the following location?\n%v", err, location.StripPassword(gopts.backends, s)) } diff --git a/cmd/restic/main.go b/cmd/restic/main.go index e847b8156..5818221a5 100644 --- a/cmd/restic/main.go +++ b/cmd/restic/main.go @@ -156,6 +156,10 @@ func main() { exitCode = 0 case err == ErrInvalidSourceData: exitCode = 3 + case errors.Is(err, ErrNoRepository): + exitCode = 10 + case restic.IsAlreadyLocked(err): + exitCode = 11 case errors.Is(err, context.Canceled): exitCode = 130 default: diff --git a/doc/075_scripting.rst b/doc/075_scripting.rst index e11f280db..87ae4fcf4 100644 --- a/doc/075_scripting.rst +++ b/doc/075_scripting.rst @@ -21,23 +21,51 @@ Check if a repository is already initialized ******************************************** You may find a need to check if a repository is already initialized, -perhaps to prevent your script from initializing a repository multiple -times. The command ``cat config`` may be used for this purpose: +perhaps to prevent your script from trying to initialize a repository multiple +times (the ``init`` command contains a check to prevent overwriting existing +repositories). The command ``cat config`` may be used for this purpose: .. code-block:: console $ restic -r /srv/restic-repo cat config - Fatal: unable to open config file: stat /srv/restic-repo/config: no such file or directory + Fatal: repository does not exist: unable to open config file: stat /srv/restic-repo/config: no such file or directory Is there a repository at the following location? /srv/restic-repo -If a repository does not exist, restic will return a non-zero exit code -and print an error message. Note that restic will also return a non-zero -exit code if a different error is encountered (e.g.: incorrect password -to ``cat config``) and it may print a different error message. If there -are no errors, restic will return a zero exit code and print the repository +If a repository does not exist, restic (since 0.17.0) will return exit code ``10`` +and print a corresponding error message. Older versions return exit code ``1``. +Note that restic will also return exit code ``1`` if a different error is encountered +(e.g.: incorrect password to ``cat config``) and it may print a different error message. +If there are no errors, restic will return a zero exit code and print the repository metadata. +Exit codes +********** + +Restic commands return an exit code that signals whether the command was successful. +The following table provides a general description, see the help of each command for +a more specific description. + +.. warning:: + New exit codes will be added over time. If an unknown exit code is returned, then it + MUST be treated as a command failure. + ++-----+----------------------------------------------------+ +| 0 | Command was successful | ++-----+----------------------------------------------------+ +| 1 | Command failed, see command help for more details | ++-----+----------------------------------------------------+ +| 2 | Go runtime error | ++-----+----------------------------------------------------+ +| 3 | ``backup`` command could not read some source data | ++-----+----------------------------------------------------+ +| 10 | Repository does not exist (since restic 0.17.0) | ++-----+----------------------------------------------------+ +| 11 | Failed to lock repository (since restic 0.17.0) | ++-----+----------------------------------------------------+ +| 130 | Restic was interrupted using SIGINT or SIGSTOP | ++-----+----------------------------------------------------+ + JSON output *********** diff --git a/internal/backend/b2/b2.go b/internal/backend/b2/b2.go index 1a5e72aaa..9717cdd0e 100644 --- a/internal/backend/b2/b2.go +++ b/internal/backend/b2/b2.go @@ -100,7 +100,9 @@ func Open(ctx context.Context, cfg Config, rt http.RoundTripper) (backend.Backen } bucket, err := client.Bucket(ctx, cfg.Bucket) - if err != nil { + if b2.IsNotExist(err) { + return nil, backend.ErrNoRepository + } else if err != nil { return nil, errors.Wrap(err, "Bucket") } diff --git a/internal/backend/backend.go b/internal/backend/backend.go index 3b0599c30..f606e1123 100644 --- a/internal/backend/backend.go +++ b/internal/backend/backend.go @@ -2,10 +2,13 @@ package backend import ( "context" + "fmt" "hash" "io" ) +var ErrNoRepository = fmt.Errorf("repository does not exist") + // Backend is used to store and access data. // // Backend operations that return an error will be retried when a Backend is