2014-04-28 00:00:15 +02:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
2017-05-01 10:09:24 +02:00
|
|
|
"bufio"
|
|
|
|
"bytes"
|
2024-03-29 23:58:48 +01:00
|
|
|
"context"
|
2015-07-12 22:10:01 +02:00
|
|
|
"fmt"
|
2017-05-01 10:09:24 +02:00
|
|
|
"log"
|
2016-08-03 20:29:08 +02:00
|
|
|
"os"
|
2017-06-11 14:17:44 +02:00
|
|
|
"runtime"
|
2023-06-02 21:51:50 +02:00
|
|
|
godebug "runtime/debug"
|
2016-08-21 17:46:23 +02:00
|
|
|
|
2016-09-17 12:36:05 +02:00
|
|
|
"github.com/spf13/cobra"
|
2023-10-22 16:59:45 +02:00
|
|
|
"go.uber.org/automaxprocs/maxprocs"
|
2016-09-01 22:17:37 +02:00
|
|
|
|
2023-09-28 19:45:58 +02:00
|
|
|
"github.com/restic/restic/internal/debug"
|
2017-07-23 14:21:03 +02:00
|
|
|
"github.com/restic/restic/internal/errors"
|
2024-01-28 16:21:22 +01:00
|
|
|
"github.com/restic/restic/internal/feature"
|
2023-09-28 19:45:58 +02:00
|
|
|
"github.com/restic/restic/internal/options"
|
|
|
|
"github.com/restic/restic/internal/restic"
|
2014-04-28 00:00:15 +02:00
|
|
|
)
|
|
|
|
|
2023-10-22 16:59:45 +02:00
|
|
|
func init() {
|
|
|
|
// don't import `go.uber.org/automaxprocs` to disable the log output
|
|
|
|
_, _ = maxprocs.Set()
|
|
|
|
}
|
|
|
|
|
2024-04-05 22:23:08 +02:00
|
|
|
var ErrOK = errors.New("ok")
|
|
|
|
|
2023-07-23 12:09:01 +02:00
|
|
|
// cmdRoot is the base command when no other command has been specified.
|
|
|
|
var cmdRoot = &cobra.Command{
|
|
|
|
Use: "restic",
|
|
|
|
Short: "Backup and restore files",
|
|
|
|
Long: `
|
2016-09-17 12:36:05 +02:00
|
|
|
restic is a backup program which allows saving multiple revisions of files and
|
|
|
|
directories in an encrypted repository stored on different backends.
|
2021-01-11 11:50:02 +08:00
|
|
|
|
2023-07-23 12:09:01 +02:00
|
|
|
The full documentation can be found at https://restic.readthedocs.io/ .
|
|
|
|
`,
|
2017-08-06 21:02:16 +02:00
|
|
|
SilenceErrors: true,
|
|
|
|
SilenceUsage: true,
|
|
|
|
DisableAutoGenTag: true,
|
2017-01-22 19:10:32 +01:00
|
|
|
|
2024-02-10 22:58:10 +01:00
|
|
|
PersistentPreRunE: func(c *cobra.Command, _ []string) error {
|
2018-04-22 11:57:20 +02:00
|
|
|
// set verbosity, default is one
|
2018-04-21 22:07:14 +02:00
|
|
|
globalOptions.verbosity = 1
|
2020-12-30 21:24:18 +01:00
|
|
|
if globalOptions.Quiet && globalOptions.Verbose > 0 {
|
2018-04-22 11:57:20 +02:00
|
|
|
return errors.Fatal("--quiet and --verbose cannot be specified at the same time")
|
2018-04-21 22:07:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
switch {
|
2018-04-22 11:57:20 +02:00
|
|
|
case globalOptions.Verbose >= 2:
|
|
|
|
globalOptions.verbosity = 3
|
|
|
|
case globalOptions.Verbose > 0:
|
|
|
|
globalOptions.verbosity = 2
|
2018-04-21 22:07:14 +02:00
|
|
|
case globalOptions.Quiet:
|
|
|
|
globalOptions.verbosity = 0
|
|
|
|
}
|
|
|
|
|
2017-03-25 15:33:52 +01:00
|
|
|
// parse extended options
|
|
|
|
opts, err := options.Parse(globalOptions.Options)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
globalOptions.extended = opts
|
2020-10-05 16:03:51 +02:00
|
|
|
if !needsPassword(c.Name()) {
|
2018-03-08 17:55:03 -04:00
|
|
|
return nil
|
|
|
|
}
|
2019-08-13 18:27:20 +02:00
|
|
|
pwd, err := resolvePassword(globalOptions, "RESTIC_PASSWORD")
|
2017-07-24 23:01:16 +02:00
|
|
|
if err != nil {
|
|
|
|
fmt.Fprintf(os.Stderr, "Resolving password failed: %v\n", err)
|
|
|
|
Exit(1)
|
|
|
|
}
|
|
|
|
globalOptions.password = pwd
|
|
|
|
|
2017-03-25 15:33:52 +01:00
|
|
|
// run the debug functions for all subcommands (if build tag "debug" is
|
|
|
|
// enabled)
|
2023-05-18 18:07:19 +02:00
|
|
|
return runDebug()
|
2017-01-23 17:52:26 +01:00
|
|
|
},
|
2024-04-05 23:16:15 +02:00
|
|
|
PersistentPostRun: func(_ *cobra.Command, _ []string) {
|
|
|
|
stopDebug()
|
|
|
|
},
|
2016-09-17 12:36:05 +02:00
|
|
|
}
|
|
|
|
|
2020-10-05 16:03:51 +02:00
|
|
|
// Distinguish commands that need the password from those that work without,
|
|
|
|
// so we don't run $RESTIC_PASSWORD_COMMAND for no reason (it might prompt the
|
|
|
|
// user for authentication).
|
|
|
|
func needsPassword(cmd string) bool {
|
|
|
|
switch cmd {
|
2023-10-19 22:35:24 +02:00
|
|
|
case "cache", "generate", "help", "options", "self-update", "version", "__complete":
|
2020-10-05 16:03:51 +02:00
|
|
|
return false
|
|
|
|
default:
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-06-02 21:51:50 +02:00
|
|
|
func tweakGoGC() {
|
|
|
|
// lower GOGC from 100 to 50, unless it was manually overwritten by the user
|
|
|
|
oldValue := godebug.SetGCPercent(50)
|
|
|
|
if oldValue != 100 {
|
|
|
|
godebug.SetGCPercent(oldValue)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-12-10 16:08:27 +01:00
|
|
|
func main() {
|
2023-06-02 21:51:50 +02:00
|
|
|
tweakGoGC()
|
2017-05-01 10:09:24 +02:00
|
|
|
// install custom global logger into a buffer, if an error occurs
|
|
|
|
// we can show the logs
|
2024-03-30 14:28:59 +01:00
|
|
|
logBuffer := bytes.NewBuffer(nil)
|
2017-05-01 10:09:24 +02:00
|
|
|
log.SetOutput(logBuffer)
|
|
|
|
|
2024-02-17 21:50:25 +01:00
|
|
|
err := feature.Flag.Apply(os.Getenv("RESTIC_FEATURES"), func(s string) {
|
|
|
|
fmt.Fprintln(os.Stderr, s)
|
|
|
|
})
|
2024-01-28 16:21:22 +01:00
|
|
|
if err != nil {
|
|
|
|
fmt.Fprintln(os.Stderr, err)
|
|
|
|
Exit(1)
|
|
|
|
}
|
|
|
|
|
2016-09-27 22:35:08 +02:00
|
|
|
debug.Log("main %#v", os.Args)
|
2018-03-21 21:49:03 +01:00
|
|
|
debug.Log("restic %s compiled with %v on %v/%v",
|
2017-06-11 14:17:44 +02:00
|
|
|
version, runtime.Version(), runtime.GOOS, runtime.GOARCH)
|
2024-03-29 23:58:48 +01:00
|
|
|
|
|
|
|
ctx := createGlobalContext()
|
|
|
|
err = cmdRoot.ExecuteContext(ctx)
|
|
|
|
|
|
|
|
if err == nil {
|
|
|
|
err = ctx.Err()
|
2024-04-05 22:23:08 +02:00
|
|
|
} else if err == ErrOK {
|
|
|
|
// ErrOK overwrites context cancelation errors
|
|
|
|
err = nil
|
2024-03-29 23:58:48 +01:00
|
|
|
}
|
2016-08-28 22:19:48 +02:00
|
|
|
|
|
|
|
switch {
|
2022-06-13 20:35:37 +02:00
|
|
|
case restic.IsAlreadyLocked(err):
|
2016-08-28 22:19:48 +02:00
|
|
|
fmt.Fprintf(os.Stderr, "%v\nthe `unlock` command can be used to remove stale locks\n", err)
|
2020-07-28 22:57:40 +02:00
|
|
|
case err == ErrInvalidSourceData:
|
|
|
|
fmt.Fprintf(os.Stderr, "Warning: %v\n", err)
|
2022-02-12 23:31:31 +01:00
|
|
|
case errors.IsFatal(err):
|
2016-08-28 22:19:48 +02:00
|
|
|
fmt.Fprintf(os.Stderr, "%v\n", err)
|
|
|
|
case err != nil:
|
2016-08-21 18:07:13 +02:00
|
|
|
fmt.Fprintf(os.Stderr, "%+v\n", err)
|
2017-05-01 10:09:24 +02:00
|
|
|
|
|
|
|
if logBuffer.Len() > 0 {
|
|
|
|
fmt.Fprintf(os.Stderr, "also, the following messages were logged by a library:\n")
|
|
|
|
sc := bufio.NewScanner(logBuffer)
|
|
|
|
for sc.Scan() {
|
|
|
|
fmt.Fprintln(os.Stderr, sc.Text())
|
|
|
|
}
|
|
|
|
}
|
2016-01-17 16:59:03 +01:00
|
|
|
}
|
|
|
|
|
2016-12-28 10:53:31 +01:00
|
|
|
var exitCode int
|
2024-03-29 23:58:48 +01:00
|
|
|
switch {
|
|
|
|
case err == nil:
|
2020-01-12 16:21:17 +01:00
|
|
|
exitCode = 0
|
2024-03-29 23:58:48 +01:00
|
|
|
case err == ErrInvalidSourceData:
|
2020-01-12 16:21:17 +01:00
|
|
|
exitCode = 3
|
2024-03-29 23:58:48 +01:00
|
|
|
case errors.Is(err, context.Canceled):
|
|
|
|
exitCode = 130
|
2020-01-12 16:21:17 +01:00
|
|
|
default:
|
2016-12-28 10:53:31 +01:00
|
|
|
exitCode = 1
|
2014-04-28 00:00:15 +02:00
|
|
|
}
|
2016-12-28 10:53:31 +01:00
|
|
|
Exit(exitCode)
|
2014-04-28 00:00:15 +02:00
|
|
|
}
|