@@ -11,6 +11,7 @@ import (
1111 "os/signal"
1212 "path/filepath"
1313 "strconv"
14+ "syscall"
1415 "strings"
1516 "time"
1617
@@ -57,32 +58,36 @@ func sshCode(host, dir string, o options) error {
5758
5859 // Start SSH master connection socket. This prevents multiple password prompts from appearing as authentication
5960 // only happens on the initial connection.
60- var sshMasterCmd * exec.Cmd
6161 if ! o .noReuseConnection {
6262 newSSHFlags := fmt .Sprintf (`%v -o "ControlPath=%v"` , o .sshFlags , sshControlPath )
6363
6464 // -MN means "start a master socket and don't open a session, just connect".
65- sshMasterCmdStr := fmt .Sprintf (`ssh %v -MN %v` , newSSHFlags , host )
66- sshMasterCmd = exec .Command ("sh" , "-c" , sshMasterCmdStr )
65+ sshCmdStr := fmt .Sprintf (`exec ssh %v -MN %v` , newSSHFlags , host )
66+ sshMasterCmd : = exec .Command ("sh" , "-c" , sshCmdStr )
6767 sshMasterCmd .Stdin = os .Stdin
6868 sshMasterCmd .Stdout = os .Stdout
6969 sshMasterCmd .Stderr = os .Stderr
70+ stopSSHMaster := func () {
71+ if sshMasterCmd .Process != nil {
72+ err := sshMasterCmd .Process .Signal (syscall .SIGTERM )
73+ if err != nil {
74+ flog .Error ("failed to send SIGTERM to SSH master process: %v" , err )
75+ }
76+ }
77+ }
78+ defer stopSSHMaster ()
79+
7080 err = sshMasterCmd .Start ()
7181 if err != nil {
7282 flog .Error ("failed to start SSH master connection, disabling connection reuse feature: %v" , err )
7383 o .noReuseConnection = true
84+ stopSSHMaster ()
7485 } else {
75- // Wait for master to be ready.
7686 err = checkSSHMaster (newSSHFlags , host )
7787 if err != nil {
78- flog .Error ("SSH master failed to start in time, disabling connection reuse feature: %v" , err )
88+ flog .Error ("SSH master failed to be ready in time, disabling connection reuse feature: %v" , err )
7989 o .noReuseConnection = true
80- if sshMasterCmd .Process != nil {
81- err = sshMasterCmd .Process .Kill ()
82- if err != nil {
83- flog .Error ("failed to kill SSH master connection, ignoring: %v" , err )
84- }
85- }
90+ stopSSHMaster ()
8691 } else {
8792 sshMasterCmd .Stdin = nil
8893 o .sshFlags = newSSHFlags
@@ -183,39 +188,22 @@ func sshCode(host, dir string, o options) error {
183188 case <- ctx .Done ():
184189 case <- c :
185190 }
186- flog .Info ("exiting" )
187191
188- if o .syncBack && ! o .skipSync {
189- flog .Info ("synchronizing VS Code back to local" )
192+ flog .Info ("shutting down" )
193+ if ! o .syncBack || o .skipSync {
194+ return nil
195+ }
190196
191- err = syncExtensions (o .sshFlags , host , true )
192- if err != nil {
193- flog .Error ("failed to sync extensions back: %v" , err )
194- }
197+ flog .Info ("synchronizing VS Code back to local" )
195198
196- err = syncUserSettings (o .sshFlags , host , true )
197- if err != nil {
198- flog .Error ("failed to sync user settings settings back: %v" , err )
199- }
199+ err = syncExtensions (o .sshFlags , host , true )
200+ if err != nil {
201+ return xerrors .Errorf ("failed to sync extensions back: %v" , err )
200202 }
201203
202- // Kill the master connection if we made one.
203- if ! o .noReuseConnection {
204- // Try using the -O exit syntax first before killing the master.
205- sshCmdStr = fmt .Sprintf (`ssh %v -O exit %v` , o .sshFlags , host )
206- sshCmd = exec .Command ("sh" , "-c" , sshCmdStr )
207- sshCmd .Stdout = os .Stdout
208- sshCmd .Stderr = os .Stderr
209- err = sshCmd .Run ()
210- if err != nil {
211- flog .Error ("failed to gracefully stop SSH master connection, killing: %v" , err )
212- if sshMasterCmd .Process != nil {
213- err = sshMasterCmd .Process .Kill ()
214- if err != nil {
215- flog .Error ("failed to kill SSH master connection, ignoring: %v" , err )
216- }
217- }
218- }
204+ err = syncUserSettings (o .sshFlags , host , true )
205+ if err != nil {
206+ return xerrors .Errorf ("failed to sync user settings settings back: %v" , err )
219207 }
220208
221209 return nil
0 commit comments