diff --git a/cmd/containerboot/tailscaled.go b/cmd/containerboot/tailscaled.go index 6f4ed77e7..379dd3eeb 100644 --- a/cmd/containerboot/tailscaled.go +++ b/cmd/containerboot/tailscaled.go @@ -150,7 +150,15 @@ func tailscaleUp(ctx context.Context, cfg *settings) error { cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr if err := cmd.Run(); err != nil { - return fmt.Errorf("tailscale up failed: %v", err) + if ctxErr := ctx.Err(); ctxErr != nil { + // A canceled context kills the command, and cmd.Run can + // report the subprocess's death ("signal: killed") rather + // than the context error that caused it. Return the + // context error so that callers (and ultimately main) can + // recognize a graceful shutdown with errors.Is. + return fmt.Errorf("tailscale up failed: %w", ctxErr) + } + return fmt.Errorf("tailscale up failed: %w", err) } return nil } @@ -180,7 +188,11 @@ func tailscaleSet(ctx context.Context, cfg *settings) error { cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr if err := cmd.Run(); err != nil { - return fmt.Errorf("tailscale set failed: %v", err) + if ctxErr := ctx.Err(); ctxErr != nil { + // See the equivalent check in tailscaleUp. + return fmt.Errorf("tailscale set failed: %w", ctxErr) + } + return fmt.Errorf("tailscale set failed: %w", err) } return nil }