mirror of
https://github.com/tailscale/tailscale.git
synced 2024-11-29 04:55:31 +00:00
cmd/tailscaled: change Windows implementation to shut down subprocess via closing its stdin
We've been doing a hard kill of the subprocess, which is only safe as long as both the cli and gui are not running and the subprocess has had the opportunity to clean up DNS settings etc. If unattended mode is turned on, this is definitely unsafe. I changed babysitProc to close the subprocess's stdin to make it shut down, and then I plumbed a cancel function into the stdin reader on the subprocess side. Fixes https://github.com/tailscale/corp/issues/5621 Signed-off-by: Aaron Klotz <aaron@tailscale.com>
This commit is contained in:
parent
9c67395334
commit
53e2010b8a
@ -25,6 +25,7 @@
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"net/netip"
|
||||
"os"
|
||||
@ -273,17 +274,24 @@ func beWindowsSubprocess() bool {
|
||||
log.Printf("Error reading environment config: %v", err)
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
go func() {
|
||||
b := make([]byte, 16)
|
||||
for {
|
||||
_, err := os.Stdin.Read(b)
|
||||
if err == io.EOF {
|
||||
// Parent wants us to shut down gracefully.
|
||||
log.Printf("subproc received EOF from stdin")
|
||||
cancel()
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
log.Fatalf("stdin err (parent process died): %v", err)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
err := startIPNServer(context.Background(), log.Printf, logid)
|
||||
err := startIPNServer(ctx, log.Printf, logid)
|
||||
if err != nil {
|
||||
log.Fatalf("ipnserver: %v", err)
|
||||
}
|
||||
@ -365,8 +373,9 @@ func babysitProc(ctx context.Context, args []string, logf logger.Logf) {
|
||||
}
|
||||
|
||||
var proc struct {
|
||||
mu sync.Mutex
|
||||
p *os.Process
|
||||
mu sync.Mutex
|
||||
p *os.Process
|
||||
wStdin *os.File
|
||||
}
|
||||
|
||||
done := make(chan struct{})
|
||||
@ -378,15 +387,18 @@ func babysitProc(ctx context.Context, args []string, logf logger.Logf) {
|
||||
case sig = <-interrupt:
|
||||
logf("babysitProc: got signal: %v", sig)
|
||||
close(done)
|
||||
proc.mu.Lock()
|
||||
proc.p.Signal(sig)
|
||||
proc.mu.Unlock()
|
||||
case <-ctx.Done():
|
||||
logf("babysitProc: context done")
|
||||
sig = os.Kill
|
||||
close(done)
|
||||
proc.mu.Lock()
|
||||
// Closing wStdin gives the subprocess a chance to shut down cleanly,
|
||||
// which is important for cleaning up DNS settings etc.
|
||||
proc.wStdin.Close()
|
||||
proc.mu.Unlock()
|
||||
}
|
||||
|
||||
proc.mu.Lock()
|
||||
proc.p.Signal(sig)
|
||||
proc.mu.Unlock()
|
||||
}()
|
||||
|
||||
bo := backoff.NewBackoff("babysitProc", logf, 30*time.Second)
|
||||
@ -448,6 +460,7 @@ func babysitProc(ctx context.Context, args []string, logf logger.Logf) {
|
||||
} else {
|
||||
proc.mu.Lock()
|
||||
proc.p = cmd.Process
|
||||
proc.wStdin = wStdin
|
||||
proc.mu.Unlock()
|
||||
|
||||
err = cmd.Wait()
|
||||
|
Loading…
Reference in New Issue
Block a user