mirror of
https://github.com/rclone/rclone.git
synced 2025-12-11 22:14:05 +01:00
Fix zombie SSH processes with --sftp-ssh by ensuring Wait() is called only once
The issue was that cmd.Wait() was being called multiple times on the same process - once in the background goroutine and once in Close(). This could lead to zombie processes because only the first call to Wait() properly reaps the process. The fix uses sync.Once to ensure Wait() is only called once per SSH process, storing and returning the result on subsequent calls. Added tests to verify the fix works correctly. Co-authored-by: ncw <536803+ncw@users.noreply.github.com>
This commit is contained in:
@@ -10,6 +10,7 @@ import (
|
||||
"os/exec"
|
||||
"slices"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/rclone/rclone/fs"
|
||||
@@ -76,6 +77,8 @@ type sshSessionExternal struct {
|
||||
cancel func()
|
||||
startCalled bool
|
||||
runningSFTP bool
|
||||
waitOnce sync.Once // ensure Wait() is only called once
|
||||
waitErr error // result of the Wait() call
|
||||
}
|
||||
|
||||
func (f *Fs) newSSHSessionExternal() *sshSessionExternal {
|
||||
@@ -175,16 +178,21 @@ func (s *sshSessionExternal) exited() bool {
|
||||
|
||||
// Wait for the command to exit
|
||||
func (s *sshSessionExternal) Wait() error {
|
||||
if s.exited() {
|
||||
return nil
|
||||
}
|
||||
err := s.cmd.Wait()
|
||||
if err == nil {
|
||||
fs.Debugf(s.f, "ssh external: command exited OK")
|
||||
} else {
|
||||
fs.Debugf(s.f, "ssh external: command exited with error: %v", err)
|
||||
}
|
||||
return err
|
||||
// Use sync.Once to ensure we only wait for the process once
|
||||
// This prevents zombie processes that occur when Wait() is called multiple times
|
||||
s.waitOnce.Do(func() {
|
||||
if s.exited() {
|
||||
s.waitErr = nil
|
||||
return
|
||||
}
|
||||
s.waitErr = s.cmd.Wait()
|
||||
if s.waitErr == nil {
|
||||
fs.Debugf(s.f, "ssh external: command exited OK")
|
||||
} else {
|
||||
fs.Debugf(s.f, "ssh external: command exited with error: %v", s.waitErr)
|
||||
}
|
||||
})
|
||||
return s.waitErr
|
||||
}
|
||||
|
||||
// Run runs cmd on the remote host. Typically, the remote
|
||||
|
||||
Reference in New Issue
Block a user