summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorkari-ts <135075563+kari-ts@users.noreply.github.com>2026-04-17 10:28:35 -0700
committerGitHub <noreply@github.com>2026-04-17 10:28:35 -0700
commit8dda62cc24692b17e9bec0156160d8e54046d762 (patch)
tree4d56ea23cca066158a0ba0f645a848d3d8ad44d4
parentb239e92eb65d7fe102d247a4f69838c5e5e12f17 (diff)
downloadtailscale-8dda62cc24692b17e9bec0156160d8e54046d762.tar.xz
tailscale-8dda62cc24692b17e9bec0156160d8e54046d762.zip
feature/clientupdate: windows update should use tailscale.exe update (#19438)
Currently, clientupdate.NewUpdater().Update() is called directly inside tailscaled, which fatals. There is also a failure that doesn't return, causing a panic. This fix allows us to use the same approach as startAutoUpdate, which is to find tailscale.exe and run tailscale.exe --update, though since it's calling the updater library directly, we get progress messages. Fixes tailscale/corp#40430s Signed-off-by: kari-ts <kari@tailscale.com>
-rw-r--r--clientupdate/clientupdate_windows.go32
-rw-r--r--feature/clientupdate/clientupdate.go1
2 files changed, 26 insertions, 7 deletions
diff --git a/clientupdate/clientupdate_windows.go b/clientupdate/clientupdate_windows.go
index 70a3c5091..50b77c38b 100644
--- a/clientupdate/clientupdate_windows.go
+++ b/clientupdate/clientupdate_windows.go
@@ -38,12 +38,12 @@ const (
updaterPrefix = "tailscale-updater"
)
-func makeSelfCopy() (origPathExe, tmpPathExe string, err error) {
- selfExe, err := os.Executable()
+func makeCmdTailscaleCopy() (origPathExe, tmpPathExe string, err error) {
+ srcExe, err := findCmdTailscale()
if err != nil {
return "", "", err
}
- f, err := os.Open(selfExe)
+ f, err := os.Open(srcExe)
if err != nil {
return "", "", err
}
@@ -59,7 +59,25 @@ func makeSelfCopy() (origPathExe, tmpPathExe string, err error) {
f2.Close()
return "", "", err
}
- return selfExe, f2.Name(), f2.Close()
+ return srcExe, f2.Name(), f2.Close()
+}
+
+// findCmdTailscale returns the path to the binary that should be copied for the update
+// re-execution. The copy is re-executed with "update" as a subcommand, so it must be
+// a binary that handles "update" (ie tailscale.exe, not tailscaled.exe)
+func findCmdTailscale() (string, error) {
+ selfExe, err := os.Executable()
+ if err != nil {
+ return "", err
+ }
+ if strings.EqualFold(filepath.Base(selfExe), "tailscale.exe") {
+ return selfExe, nil
+ }
+ ts := filepath.Join(filepath.Dir(selfExe), "tailscale.exe")
+ if _, err := os.Stat(ts); err != nil {
+ return "", fmt.Errorf("cannot find tailscale.exe alongside %s: %w", selfExe, err)
+ }
+ return ts, nil
}
func markTempFileWindows(name string) error {
@@ -159,14 +177,14 @@ you can run the command prompt as Administrator one of these ways:
up.Logf("making tailscale.exe copy to switch to...")
up.cleanupOldDownloads(filepath.Join(os.TempDir(), updaterPrefix+"-*.exe"))
- _, selfCopy, err := makeSelfCopy()
+ _, cmdTailscaleCopy, err := makeCmdTailscaleCopy()
if err != nil {
return err
}
- defer os.Remove(selfCopy)
+ defer os.Remove(cmdTailscaleCopy)
up.Logf("running tailscale.exe copy for final install...")
- cmd := exec.Command(selfCopy, "update")
+ cmd := exec.Command(cmdTailscaleCopy, "update")
cmd.Env = append(os.Environ(), winMSIEnv+"="+msiTarget, winVersionEnv+"="+ver)
cmd.Stdout = up.Stderr
cmd.Stderr = up.Stderr
diff --git a/feature/clientupdate/clientupdate.go b/feature/clientupdate/clientupdate.go
index d47d04815..999dd7920 100644
--- a/feature/clientupdate/clientupdate.go
+++ b/feature/clientupdate/clientupdate.go
@@ -163,6 +163,7 @@ func (e *extension) DoSelfUpdate() {
})
if err != nil {
e.pushSelfUpdateProgress(ipnstate.NewUpdateProgress(ipnstate.UpdateFailed, err.Error()))
+ return
}
err = up.Update()
if err != nil {