@ -30,11 +30,6 @@ const (
// tailscale.exe process from running before the msiexec process runs and
// tailscale.exe process from running before the msiexec process runs and
// tries to overwrite ourselves.
// tries to overwrite ourselves.
winMSIEnv = "TS_UPDATE_WIN_MSI"
winMSIEnv = "TS_UPDATE_WIN_MSI"
// winExePathEnv is the environment variable that is set along with
// winMSIEnv and carries the full path of the calling tailscale.exe binary.
// It is used to re-launch the GUI process (tailscale-ipn.exe) after
// install is complete.
winExePathEnv = "TS_UPDATE_WIN_EXE_PATH"
// winVersionEnv is the environment variable that is set along with
// winVersionEnv is the environment variable that is set along with
// winMSIEnv and carries the version of tailscale that is being installed.
// winMSIEnv and carries the version of tailscale that is being installed.
// It is used for logging purposes.
// It is used for logging purposes.
@ -78,6 +73,17 @@ func verifyAuthenticode(path string) error {
return authenticode . Verify ( path , certSubjectTailscale )
return authenticode . Verify ( path , certSubjectTailscale )
}
}
func isTSGUIPresent ( ) bool {
us , err := os . Executable ( )
if err != nil {
return false
}
tsgui := filepath . Join ( filepath . Dir ( us ) , "tsgui.dll" )
_ , err = os . Stat ( tsgui )
return err == nil
}
func ( up * Updater ) updateWindows ( ) error {
func ( up * Updater ) updateWindows ( ) error {
if msi := os . Getenv ( winMSIEnv ) ; msi != "" {
if msi := os . Getenv ( winMSIEnv ) ; msi != "" {
// stdout/stderr from this part of the install could be lost since the
// stdout/stderr from this part of the install could be lost since the
@ -131,7 +137,15 @@ you can run the command prompt as Administrator one of these ways:
return err
return err
}
}
up . cleanupOldDownloads ( filepath . Join ( msiDir , "*.msi" ) )
up . cleanupOldDownloads ( filepath . Join ( msiDir , "*.msi" ) )
pkgsPath := fmt . Sprintf ( "%s/tailscale-setup-%s-%s.msi" , up . Track , ver , arch )
qualifiers := [ ] string { ver , arch }
// TODO(aaron): Temporary hack so autoupdate still works on winui builds;
// remove when we enable winui by default on the unstable track.
if isTSGUIPresent ( ) {
qualifiers = append ( qualifiers , "winui" )
}
pkgsPath := fmt . Sprintf ( "%s/tailscale-setup-%s.msi" , up . Track , strings . Join ( qualifiers , "-" ) )
msiTarget := filepath . Join ( msiDir , path . Base ( pkgsPath ) )
msiTarget := filepath . Join ( msiDir , path . Base ( pkgsPath ) )
if err := up . downloadURLToFile ( pkgsPath , msiTarget ) ; err != nil {
if err := up . downloadURLToFile ( pkgsPath , msiTarget ) ; err != nil {
return err
return err
@ -145,7 +159,7 @@ you can run the command prompt as Administrator one of these ways:
up . Logf ( "making tailscale.exe copy to switch to..." )
up . Logf ( "making tailscale.exe copy to switch to..." )
up . cleanupOldDownloads ( filepath . Join ( os . TempDir ( ) , updaterPrefix + "-*.exe" ) )
up . cleanupOldDownloads ( filepath . Join ( os . TempDir ( ) , updaterPrefix + "-*.exe" ) )
selfOrig , selfCopy , err := makeSelfCopy ( )
_ , selfCopy , err := makeSelfCopy ( )
if err != nil {
if err != nil {
return err
return err
}
}
@ -153,7 +167,7 @@ you can run the command prompt as Administrator one of these ways:
up . Logf ( "running tailscale.exe copy for final install..." )
up . Logf ( "running tailscale.exe copy for final install..." )
cmd := exec . Command ( selfCopy , "update" )
cmd := exec . Command ( selfCopy , "update" )
cmd . Env = append ( os . Environ ( ) , winMSIEnv + "=" + msiTarget , win ExePathEnv+ "=" + selfOrig , win VersionEnv+ "=" + ver )
cmd . Env = append ( os . Environ ( ) , winMSIEnv + "=" + msiTarget , win VersionEnv+ "=" + ver )
cmd . Stdout = up . Stderr
cmd . Stdout = up . Stderr
cmd . Stderr = up . Stderr
cmd . Stderr = up . Stderr
cmd . Stdin = os . Stdin
cmd . Stdin = os . Stdin
@ -189,7 +203,7 @@ func (up *Updater) installMSI(msi string) error {
case windows . ERROR_SUCCESS_REBOOT_REQUIRED :
case windows . ERROR_SUCCESS_REBOOT_REQUIRED :
// In most cases, updating Tailscale should not require a reboot.
// In most cases, updating Tailscale should not require a reboot.
// If it does, it might be because we failed to close the GUI
// If it does, it might be because we failed to close the GUI
// and the installer couldn't replace tail scale-ipn.ex e.
// and the installer couldn't replace i ts exe cut ab le.
// The old GUI will continue to run until the next reboot.
// The old GUI will continue to run until the next reboot.
// Not ideal, but also not a retryable error.
// Not ideal, but also not a retryable error.
up . Logf ( "[unexpected] reboot required" )
up . Logf ( "[unexpected] reboot required" )