@ -158,6 +158,10 @@ func Update(args UpdateArgs) error {
case haveExecutable ( "apk" ) :
up . update = up . updateAlpineLike
}
// If nothing matched, fall back to tarball updates.
if up . update == nil {
up . update = up . updateLinuxBinary
}
case "darwin" :
switch {
case ! args . AppStore && ! version . IsSandboxedMacOS ( ) :
@ -300,6 +304,14 @@ func parseSynoinfo(path string) (string, error) {
}
func ( up * updater ) updateDebLike ( ) error {
if err := requireRoot ( ) ; err != nil {
return err
}
if err := exec . Command ( "dpkg" , "--status" , "tailscale" ) . Run ( ) ; err != nil && isExitError ( err ) {
// Tailscale was not installed via apt, update via tarball download
// instead.
return up . updateLinuxBinary ( )
}
ver , err := requestedTailscaleVersion ( up . Version , up . track )
if err != nil {
return err
@ -308,10 +320,6 @@ func (up *updater) updateDebLike() error {
return nil
}
if err := requireRoot ( ) ; err != nil {
return err
}
if updated , err := updateDebianAptSourcesList ( up . track ) ; err != nil {
return err
} else if updated {
@ -402,6 +410,11 @@ func updateDebianAptSourcesListBytes(was []byte, dstTrack string) (newContent []
}
func ( up * updater ) updateArchLike ( ) error {
if err := exec . Command ( "pacman" , "--query" , "tailscale" ) . Run ( ) ; err != nil && isExitError ( err ) {
// Tailscale was not installed via pacman, update via tarball download
// instead.
return up . updateLinuxBinary ( )
}
// Arch maintainer asked us not to implement "tailscale update" or
// auto-updates on Arch-based distros:
// https://github.com/tailscale/tailscale/issues/6995#issuecomment-1687080106
@ -419,6 +432,11 @@ func (up *updater) updateFedoraLike(packageManager string) func() error {
if err := requireRoot ( ) ; err != nil {
return err
}
if err := exec . Command ( packageManager , "info" , "--installed" , "tailscale" ) . Run ( ) ; err != nil && isExitError ( err ) {
// Tailscale was not installed via yum/dnf, update via tarball
// download instead.
return up . updateLinuxBinary ( )
}
defer func ( ) {
if err != nil {
err = fmt . Errorf ( ` %w; you can try updating using "%s upgrade tailscale" ` , err , packageManager )
@ -497,6 +515,11 @@ func (up *updater) updateAlpineLike() (err error) {
if err := requireRoot ( ) ; err != nil {
return err
}
if err := exec . Command ( "apk" , "info" , "--installed" , "tailscale" ) . Run ( ) ; err != nil && isExitError ( err ) {
// Tailscale was not installed via apk, update via tarball download
// instead.
return up . updateLinuxBinary ( )
}
defer func ( ) {
if err != nil {
@ -764,6 +787,11 @@ func (up *updater) updateFreeBSD() (err error) {
if err := requireRoot ( ) ; err != nil {
return err
}
if err := exec . Command ( "pkg" , "query" , "%n" , "tailscale" ) . Run ( ) ; err != nil && isExitError ( err ) {
// Tailscale was not installed via pkg and we don't pre-compile
// binaries for it.
return errors . New ( "Tailscale was not installed via pkg, binary updates on FreeBSD are not supported; please reinstall Tailscale using pkg or update manually" )
}
defer func ( ) {
if err != nil {
@ -793,6 +821,10 @@ func (up *updater) updateFreeBSD() (err error) {
return nil
}
func ( up * updater ) updateLinuxBinary ( ) error {
return errors . New ( "Linux binary updates without a package manager are not supported yet" )
}
func haveExecutable ( name string ) bool {
path , err := exec . LookPath ( name )
return err == nil && path != ""
@ -867,3 +899,8 @@ func requireRoot() error {
return errors . New ( "must be root" )
}
}
func isExitError ( err error ) bool {
var exitErr * exec . ExitError
return errors . As ( err , & exitErr )
}