From c72f6bb34636af4aac4493c6446ad0a96ebbf01c Mon Sep 17 00:00:00 2001 From: Davy Landman Date: Fri, 19 Apr 2024 11:35:30 +0200 Subject: [PATCH] Improved error handling --- cmd/backup/main.go | 39 +++++++++++++++++++-------------------- internal/ssh/ssh.go | 38 ++++++++++++++++++++++++-------------- 2 files changed, 43 insertions(+), 34 deletions(-) diff --git a/cmd/backup/main.go b/cmd/backup/main.go index 0b88baf..de2448d 100644 --- a/cmd/backup/main.go +++ b/cmd/backup/main.go @@ -61,14 +61,14 @@ func main() { } if d.Output != nil { os.Stdout.WriteString("Output of " + d.Name + ":\n") - io.Copy(os.Stdout, d.Output) + if _, err := io.Copy(os.Stdout, d.Output); err != nil { + log.WithError(err).Error("Could not copy output of backup process to our stdout") + } } } if anyError { os.Exit(1) } - - log.Info("Backups are done, now starting pruning") } func getBackupRawKey(bc config.BorgConfig) *interface{} { @@ -136,7 +136,9 @@ func (b *borg) exec(cmd string) error { return fmt.Errorf("couldn't set remote BORG_RSH: %w", err) } - b.keyring.RemoveAll() + if err = b.keyring.RemoveAll(); err != nil { + log.WithError(err).Error("Could not clear keyring before adding a new key") + } // we load the key for backup very shortly in the KeyRing, so that there is a very short window to catch it. err = b.keyring.Add(agent.AddedKey{ PrivateKey: *getBackupRawKey(b.mainConfig), @@ -152,12 +154,16 @@ func (b *borg) exec(cmd string) error { return fmt.Errorf("in pipe: %w", err) } defer inPipe.Close() - b.output.Write([]byte("remote> " + cmd + "\n")) + if _, err = b.output.Write([]byte("remote> " + cmd + "\n")); err != nil { + log.WithError(err).Error("Unexpected failure to write to output") + } if err := ses.Start(cmd); err != nil { return fmt.Errorf("starting command: %w", err) } time.Sleep(3 * time.Second) // give the password prompt time to show up - inPipe.Write([]byte(stdin)) + if _, err = inPipe.Write([]byte(stdin)); err != nil { + log.WithError(err).Error("Could not write the passphrase to stdin") + } return ses.Wait() } @@ -182,18 +188,7 @@ func forwardSingleConnection(localSSH net.Listener, con *ssh.Client, address str } defer remote.Close() - done := make(chan bool, 2) - go func() { - io.Copy(local, remote) - done <- true - }() - go func() { - io.Copy(remote, local) - done <- true - }() - - // now we wait until either side is done - <-done + specialSSH.Proxy(local, remote) // end of this function will execute the deferred closes } @@ -277,7 +272,9 @@ func (b *borg) execLocalForwarded(cmd string, key *interface{}) error { return err } - b.keyring.RemoveAll() + if err = b.keyring.RemoveAll(); err != nil { + return fmt.Errorf("Could not clear keyring: %w", err) + } err = b.keyring.Add(agent.AddedKey{ PrivateKey: *key, LifetimeSecs: 2, @@ -288,7 +285,9 @@ func (b *borg) execLocalForwarded(cmd string, key *interface{}) error { log.WithField("borgCommand", borgCommand).WithField("env", borgCommand.Env).Info("setup completed, starting borg on local machine") - b.output.Write([]byte("local> " + cmd + "\n")) + if _, err := b.output.Write([]byte("local> " + cmd + "\n")); err != nil { + log.WithError(err).Error("Could not write to output buffer") + } return borgCommand.Run() } diff --git a/internal/ssh/ssh.go b/internal/ssh/ssh.go index 988dc3a..f9f3a4c 100644 --- a/internal/ssh/ssh.go +++ b/internal/ssh/ssh.go @@ -15,6 +15,27 @@ import ( "github.com/swat-engineering/borg-backup-remotely/internal/config" ) +func copyIgnoreError(dst io.Writer, src io.Reader) { + if _, err := io.Copy(dst, src); err != nil { + log.WithError(err).Debug("We intentionally ignore this error in copying") + } +} + +func Proxy(a io.ReadWriter, b io.ReadWriter) { + done := make(chan bool, 2) + go func() { + copyIgnoreError(a, b) + done <- true + }() + go func() { + copyIgnoreError(b, a) + done <- true + }() + + // now we wait until either side is done + <-done +} + func ForwardSingleConnection(localSSH net.Listener, con *ssh.Client, address string) { local, err := localSSH.Accept() if err != nil { @@ -30,18 +51,7 @@ func ForwardSingleConnection(localSSH net.Listener, con *ssh.Client, address str } defer remote.Close() - done := make(chan bool, 2) - go func() { - io.Copy(local, remote) - done <- true - }() - go func() { - io.Copy(remote, local) - done <- true - }() - - // now we wait until either side is done - <-done + Proxy(local, remote) // end of this function will execute the deferred closes } @@ -225,7 +235,7 @@ func pipeStreamsActual(outPipe io.Reader, errPipe io.Reader, outError error, err return fmt.Errorf("opening err pipe: %w", errError) } - go io.Copy(target, outPipe) - go io.Copy(target, errPipe) + go copyIgnoreError(target, outPipe) + go copyIgnoreError(target, errPipe) return nil }