Update dependencies
This commit is contained in:
10
vendor/tailscale.com/version/.gitignore
generated
vendored
Normal file
10
vendor/tailscale.com/version/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
describe.txt
|
||||
long.txt
|
||||
short.txt
|
||||
gitcommit.txt
|
||||
extragitcommit.txt
|
||||
version-info.sh
|
||||
version.h
|
||||
version.xcconfig
|
||||
ver.go
|
||||
version
|
||||
139
vendor/tailscale.com/version/cmdname.go
generated
vendored
Normal file
139
vendor/tailscale.com/version/cmdname.go
generated
vendored
Normal file
@@ -0,0 +1,139 @@
|
||||
// Copyright (c) Tailscale Inc & AUTHORS
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
//go:build !ios
|
||||
|
||||
package version
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"io"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// CmdName returns either the base name of the current binary
|
||||
// using os.Executable. If os.Executable fails (it shouldn't), then
|
||||
// "cmd" is returned.
|
||||
func CmdName() string {
|
||||
e, err := os.Executable()
|
||||
if err != nil {
|
||||
return "cmd"
|
||||
}
|
||||
return cmdName(e)
|
||||
}
|
||||
|
||||
func cmdName(exe string) string {
|
||||
// fallbackName, the lowercase basename of the executable, is what we return if
|
||||
// we can't find the Go module metadata embedded in the file.
|
||||
fallbackName := filepath.Base(strings.TrimSuffix(strings.ToLower(exe), ".exe"))
|
||||
|
||||
var ret string
|
||||
info, err := findModuleInfo(exe)
|
||||
if err != nil {
|
||||
return fallbackName
|
||||
}
|
||||
// v is like:
|
||||
// "path\ttailscale.com/cmd/tailscale\nmod\ttailscale.com\t(devel)\t\ndep\tgithub.com/apenwarr/fixconsole\tv0.0.0-20191012055117-5a9f6489cc29\th1:muXWUcay7DDy1/hEQWrYlBy+g0EuwT70sBHg65SeUc4=\ndep\tgithub....
|
||||
for _, line := range strings.Split(info, "\n") {
|
||||
if goPkg, ok := strings.CutPrefix(line, "path\t"); ok { // like "tailscale.com/cmd/tailscale"
|
||||
ret = path.Base(goPkg) // goPkg is always forward slashes; use path, not filepath
|
||||
break
|
||||
}
|
||||
}
|
||||
if strings.HasPrefix(ret, "wg") && fallbackName == "tailscale-ipn" {
|
||||
// The tailscale-ipn.exe binary for internal build system packaging reasons
|
||||
// has a path of "tailscale.io/win/wg64", "tailscale.io/win/wg32", etc.
|
||||
// Ignore that name and use "tailscale-ipn" instead.
|
||||
return fallbackName
|
||||
}
|
||||
if ret == "" {
|
||||
return fallbackName
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
// findModuleInfo returns the Go module info from the executable file.
|
||||
func findModuleInfo(file string) (s string, err error) {
|
||||
f, err := os.Open(file)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer f.Close()
|
||||
// Scan through f until we find infoStart.
|
||||
buf := make([]byte, 65536)
|
||||
start, err := findOffset(f, buf, infoStart)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
start += int64(len(infoStart))
|
||||
// Seek to the end of infoStart and scan for infoEnd.
|
||||
_, err = f.Seek(start, io.SeekStart)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
end, err := findOffset(f, buf, infoEnd)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
length := end - start
|
||||
// As of Aug 2021, tailscaled's mod info was about 2k.
|
||||
if length > int64(len(buf)) {
|
||||
return "", errors.New("mod info too large")
|
||||
}
|
||||
// We have located modinfo. Read it into buf.
|
||||
buf = buf[:length]
|
||||
_, err = f.Seek(start, io.SeekStart)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
_, err = io.ReadFull(f, buf)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return string(buf), nil
|
||||
}
|
||||
|
||||
// findOffset finds the absolute offset of needle in f,
|
||||
// starting at f's current read position,
|
||||
// using temporary buffer buf.
|
||||
func findOffset(f *os.File, buf, needle []byte) (int64, error) {
|
||||
for {
|
||||
// Fill buf and look within it.
|
||||
n, err := f.Read(buf)
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
i := bytes.Index(buf[:n], needle)
|
||||
if i < 0 {
|
||||
// Not found. Rewind a little bit in case we happened to end halfway through needle.
|
||||
rewind, err := f.Seek(int64(-len(needle)), io.SeekCurrent)
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
// If we're at EOF and rewound exactly len(needle) bytes, return io.EOF.
|
||||
_, err = f.ReadAt(buf[:1], rewind+int64(len(needle)))
|
||||
if err == io.EOF {
|
||||
return -1, err
|
||||
}
|
||||
continue
|
||||
}
|
||||
// Found! Figure out exactly where.
|
||||
cur, err := f.Seek(0, io.SeekCurrent)
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
return cur - int64(n) + int64(i), nil
|
||||
}
|
||||
}
|
||||
|
||||
// These constants are taken from rsc.io/goversion.
|
||||
|
||||
var (
|
||||
infoStart, _ = hex.DecodeString("3077af0c9274080241e1c107e6d618e6")
|
||||
infoEnd, _ = hex.DecodeString("f932433186182072008242104116d8f2")
|
||||
)
|
||||
18
vendor/tailscale.com/version/cmdname_ios.go
generated
vendored
Normal file
18
vendor/tailscale.com/version/cmdname_ios.go
generated
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
// Copyright (c) Tailscale Inc & AUTHORS
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
//go:build ios
|
||||
|
||||
package version
|
||||
|
||||
import (
|
||||
"os"
|
||||
)
|
||||
|
||||
func CmdName() string {
|
||||
e, err := os.Executable()
|
||||
if err != nil {
|
||||
return "cmd"
|
||||
}
|
||||
return e
|
||||
}
|
||||
193
vendor/tailscale.com/version/cmp.go
generated
vendored
Normal file
193
vendor/tailscale.com/version/cmp.go
generated
vendored
Normal file
@@ -0,0 +1,193 @@
|
||||
// Copyright (c) Tailscale Inc & AUTHORS
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
package version
|
||||
|
||||
import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
// AtLeast returns whether version is at least the specified minimum
|
||||
// version.
|
||||
//
|
||||
// Version comparison in Tailscale is a little complex, because we
|
||||
// switched "styles" a few times, and additionally have a completely
|
||||
// separate track of version numbers for OSS-only builds.
|
||||
//
|
||||
// AtLeast acts conservatively, returning true only if it's certain
|
||||
// that version is at least minimum. As a result, it can produce false
|
||||
// negatives, for example when an OSS build supports a given feature,
|
||||
// but AtLeast is called with an official release number as the
|
||||
// minimum
|
||||
//
|
||||
// version and minimum can both be either an official Tailscale
|
||||
// version numbers (major.minor.patch-extracommits-extrastring), or an
|
||||
// OSS build datestamp (date.YYYYMMDD). For Tailscale version numbers,
|
||||
// AtLeast also accepts a prefix of a full version, in which case all
|
||||
// missing fields are assumed to be zero.
|
||||
func AtLeast(version string, minimum string) bool {
|
||||
v, ok := parse(version)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
m, ok := parse(minimum)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
switch {
|
||||
case v.Datestamp != 0 && m.Datestamp == 0:
|
||||
// OSS version vs. Tailscale version
|
||||
return false
|
||||
case v.Datestamp == 0 && m.Datestamp != 0:
|
||||
// Tailscale version vs. OSS version
|
||||
return false
|
||||
case v.Datestamp != 0:
|
||||
// OSS version vs. OSS version
|
||||
return v.Datestamp >= m.Datestamp
|
||||
case v.Major == m.Major && v.Minor == m.Minor && v.Patch == m.Patch && v.ExtraCommits == m.ExtraCommits:
|
||||
// Exactly equal Tailscale versions
|
||||
return true
|
||||
case v.Major != m.Major:
|
||||
return v.Major > m.Major
|
||||
case v.Minor != m.Minor:
|
||||
return v.Minor > m.Minor
|
||||
case v.Patch != m.Patch:
|
||||
return v.Patch > m.Patch
|
||||
default:
|
||||
return v.ExtraCommits > m.ExtraCommits
|
||||
}
|
||||
}
|
||||
|
||||
type parsed struct {
|
||||
Major, Minor, Patch, ExtraCommits int // for Tailscale version e.g. e.g. "0.99.1-20"
|
||||
Datestamp int // for OSS version e.g. "date.20200612"
|
||||
}
|
||||
|
||||
func parse(version string) (parsed, bool) {
|
||||
if strings.HasPrefix(version, "date.") {
|
||||
stamp, ok := atoi(version[5:])
|
||||
if !ok {
|
||||
return parsed{}, false
|
||||
}
|
||||
return parsed{Datestamp: stamp}, true
|
||||
}
|
||||
|
||||
var ret parsed
|
||||
|
||||
major, rest, ok := splitNumericPrefix(version)
|
||||
if !ok {
|
||||
return parsed{}, false
|
||||
}
|
||||
ret.Major = major
|
||||
if len(rest) == 0 {
|
||||
return ret, true
|
||||
}
|
||||
|
||||
ret.Minor, rest, ok = splitNumericPrefix(rest[1:])
|
||||
if !ok {
|
||||
return parsed{}, false
|
||||
}
|
||||
if len(rest) == 0 {
|
||||
return ret, true
|
||||
}
|
||||
|
||||
// Optional patch version, if the next separator is a dot.
|
||||
if rest[0] == '.' {
|
||||
ret.Patch, rest, ok = splitNumericPrefix(rest[1:])
|
||||
if !ok {
|
||||
return parsed{}, false
|
||||
}
|
||||
if len(rest) == 0 {
|
||||
return ret, true
|
||||
}
|
||||
}
|
||||
|
||||
// Optional extraCommits, if the next bit can be completely
|
||||
// consumed as an integer.
|
||||
if rest[0] != '-' {
|
||||
return parsed{}, false
|
||||
}
|
||||
|
||||
var trailer string
|
||||
ret.ExtraCommits, trailer, ok = splitNumericPrefix(rest[1:])
|
||||
if !ok || (len(trailer) > 0 && trailer[0] != '-') {
|
||||
// rest was probably the string trailer, ignore it.
|
||||
ret.ExtraCommits = 0
|
||||
}
|
||||
return ret, true
|
||||
}
|
||||
|
||||
func splitNumericPrefix(s string) (n int, rest string, ok bool) {
|
||||
for i, r := range s {
|
||||
if r >= '0' && r <= '9' {
|
||||
continue
|
||||
}
|
||||
ret, ok := atoi(s[:i])
|
||||
if !ok {
|
||||
return 0, "", false
|
||||
}
|
||||
return ret, s[i:], true
|
||||
}
|
||||
|
||||
ret, ok := atoi(s)
|
||||
if !ok {
|
||||
return 0, "", false
|
||||
}
|
||||
return ret, "", true
|
||||
}
|
||||
|
||||
const (
|
||||
maxUint = ^uint(0)
|
||||
maxInt = int(maxUint >> 1)
|
||||
)
|
||||
|
||||
// atoi parses an int from a string s.
|
||||
// The bool result reports whether s is a number
|
||||
// representable by a value of type int.
|
||||
//
|
||||
// From Go's runtime/string.go.
|
||||
func atoi(s string) (int, bool) {
|
||||
if s == "" {
|
||||
return 0, false
|
||||
}
|
||||
|
||||
neg := false
|
||||
if s[0] == '-' {
|
||||
neg = true
|
||||
s = s[1:]
|
||||
}
|
||||
|
||||
un := uint(0)
|
||||
for i := range len(s) {
|
||||
c := s[i]
|
||||
if c < '0' || c > '9' {
|
||||
return 0, false
|
||||
}
|
||||
if un > maxUint/10 {
|
||||
// overflow
|
||||
return 0, false
|
||||
}
|
||||
un *= 10
|
||||
un1 := un + uint(c) - '0'
|
||||
if un1 < un {
|
||||
// overflow
|
||||
return 0, false
|
||||
}
|
||||
un = un1
|
||||
}
|
||||
|
||||
if !neg && un > uint(maxInt) {
|
||||
return 0, false
|
||||
}
|
||||
if neg && un > uint(maxInt)+1 {
|
||||
return 0, false
|
||||
}
|
||||
|
||||
n := int(un)
|
||||
if neg {
|
||||
n = -n
|
||||
}
|
||||
|
||||
return n, true
|
||||
}
|
||||
149
vendor/tailscale.com/version/distro/distro.go
generated
vendored
Normal file
149
vendor/tailscale.com/version/distro/distro.go
generated
vendored
Normal file
@@ -0,0 +1,149 @@
|
||||
// Copyright (c) Tailscale Inc & AUTHORS
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
// Package distro reports which distro we're running on.
|
||||
package distro
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"os"
|
||||
"runtime"
|
||||
"strconv"
|
||||
|
||||
"tailscale.com/types/lazy"
|
||||
"tailscale.com/util/lineread"
|
||||
)
|
||||
|
||||
type Distro string
|
||||
|
||||
const (
|
||||
Debian = Distro("debian")
|
||||
Arch = Distro("arch")
|
||||
Synology = Distro("synology")
|
||||
OpenWrt = Distro("openwrt")
|
||||
NixOS = Distro("nixos")
|
||||
QNAP = Distro("qnap")
|
||||
Pfsense = Distro("pfsense")
|
||||
OPNsense = Distro("opnsense")
|
||||
TrueNAS = Distro("truenas")
|
||||
Gokrazy = Distro("gokrazy")
|
||||
WDMyCloud = Distro("wdmycloud")
|
||||
Unraid = Distro("unraid")
|
||||
Alpine = Distro("alpine")
|
||||
)
|
||||
|
||||
var distro lazy.SyncValue[Distro]
|
||||
var isWSL lazy.SyncValue[bool]
|
||||
|
||||
// Get returns the current distro, or the empty string if unknown.
|
||||
func Get() Distro {
|
||||
return distro.Get(func() Distro {
|
||||
switch runtime.GOOS {
|
||||
case "linux":
|
||||
return linuxDistro()
|
||||
case "freebsd":
|
||||
return freebsdDistro()
|
||||
default:
|
||||
return Distro("")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// IsWSL reports whether we're running in the Windows Subsystem for Linux.
|
||||
func IsWSL() bool {
|
||||
return runtime.GOOS == "linux" && isWSL.Get(func() bool {
|
||||
// We could look for $WSL_INTEROP instead, however that may be missing if
|
||||
// the user has started to use systemd in WSL2.
|
||||
return have("/proc/sys/fs/binfmt_misc/WSLInterop") || have("/mnt/wsl")
|
||||
})
|
||||
}
|
||||
|
||||
func have(file string) bool {
|
||||
_, err := os.Stat(file)
|
||||
return err == nil
|
||||
}
|
||||
|
||||
func haveDir(file string) bool {
|
||||
fi, err := os.Stat(file)
|
||||
return err == nil && fi.IsDir()
|
||||
}
|
||||
|
||||
func linuxDistro() Distro {
|
||||
switch {
|
||||
case haveDir("/usr/syno"):
|
||||
return Synology
|
||||
case have("/usr/local/bin/freenas-debug"):
|
||||
// TrueNAS Scale runs on debian
|
||||
return TrueNAS
|
||||
case have("/etc/debian_version"):
|
||||
return Debian
|
||||
case have("/etc/arch-release"):
|
||||
return Arch
|
||||
case have("/etc/openwrt_version"):
|
||||
return OpenWrt
|
||||
case have("/run/current-system/sw/bin/nixos-version"):
|
||||
return NixOS
|
||||
case have("/etc/config/uLinux.conf"):
|
||||
return QNAP
|
||||
case haveDir("/gokrazy"):
|
||||
return Gokrazy
|
||||
case have("/usr/local/wdmcserver/bin/wdmc.xml"): // Western Digital MyCloud OS3
|
||||
return WDMyCloud
|
||||
case have("/usr/sbin/wd_crontab.sh"): // Western Digital MyCloud OS5
|
||||
return WDMyCloud
|
||||
case have("/etc/unraid-version"):
|
||||
return Unraid
|
||||
case have("/etc/alpine-release"):
|
||||
return Alpine
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func freebsdDistro() Distro {
|
||||
switch {
|
||||
case have("/etc/pfSense-rc"):
|
||||
return Pfsense
|
||||
case have("/usr/local/sbin/opnsense-shell"):
|
||||
return OPNsense
|
||||
case have("/usr/local/bin/freenas-debug"):
|
||||
// TrueNAS Core runs on FreeBSD
|
||||
return TrueNAS
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
var dsmVersion lazy.SyncValue[int]
|
||||
|
||||
// DSMVersion reports the Synology DSM major version.
|
||||
//
|
||||
// If not Synology, it reports 0.
|
||||
func DSMVersion() int {
|
||||
if runtime.GOOS != "linux" {
|
||||
return 0
|
||||
}
|
||||
return dsmVersion.Get(func() int {
|
||||
if Get() != Synology {
|
||||
return 0
|
||||
}
|
||||
// This is set when running as a package:
|
||||
v, _ := strconv.Atoi(os.Getenv("SYNOPKG_DSM_VERSION_MAJOR"))
|
||||
if v != 0 {
|
||||
return v
|
||||
}
|
||||
// But when run from the command line, we have to read it from the file:
|
||||
lineread.File("/etc/VERSION", func(line []byte) error {
|
||||
line = bytes.TrimSpace(line)
|
||||
if string(line) == `majorversion="7"` {
|
||||
v = 7
|
||||
return io.EOF
|
||||
}
|
||||
if string(line) == `majorversion="6"` {
|
||||
v = 6
|
||||
return io.EOF
|
||||
}
|
||||
return nil
|
||||
})
|
||||
return v
|
||||
})
|
||||
}
|
||||
33
vendor/tailscale.com/version/print.go
generated
vendored
Normal file
33
vendor/tailscale.com/version/print.go
generated
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
// Copyright (c) Tailscale Inc & AUTHORS
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
package version
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"tailscale.com/types/lazy"
|
||||
)
|
||||
|
||||
var stringLazy = lazy.SyncFunc(func() string {
|
||||
var ret strings.Builder
|
||||
ret.WriteString(Short())
|
||||
ret.WriteByte('\n')
|
||||
if IsUnstableBuild() {
|
||||
fmt.Fprintf(&ret, " track: unstable (dev); frequent updates and bugs are likely\n")
|
||||
}
|
||||
if gitCommit() != "" {
|
||||
fmt.Fprintf(&ret, " tailscale commit: %s%s\n", gitCommit(), dirtyString())
|
||||
}
|
||||
if extraGitCommitStamp != "" {
|
||||
fmt.Fprintf(&ret, " other commit: %s\n", extraGitCommitStamp)
|
||||
}
|
||||
fmt.Fprintf(&ret, " go version: %s\n", runtime.Version())
|
||||
return strings.TrimSpace(ret.String())
|
||||
})
|
||||
|
||||
func String() string {
|
||||
return stringLazy()
|
||||
}
|
||||
260
vendor/tailscale.com/version/prop.go
generated
vendored
Normal file
260
vendor/tailscale.com/version/prop.go
generated
vendored
Normal file
@@ -0,0 +1,260 @@
|
||||
// Copyright (c) Tailscale Inc & AUTHORS
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
package version
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"tailscale.com/tailcfg"
|
||||
"tailscale.com/types/lazy"
|
||||
)
|
||||
|
||||
// IsMobile reports whether this is a mobile client build.
|
||||
func IsMobile() bool {
|
||||
return runtime.GOOS == "android" || runtime.GOOS == "ios"
|
||||
}
|
||||
|
||||
// OS returns runtime.GOOS, except instead of returning "darwin" it returns
|
||||
// "iOS" or "macOS".
|
||||
func OS() string {
|
||||
// If you're wondering why we have this function that just returns
|
||||
// runtime.GOOS written differently: in the old days, Go reported
|
||||
// GOOS=darwin for both iOS and macOS, so we needed this function to
|
||||
// differentiate them. Then a later Go release added GOOS=ios as a separate
|
||||
// platform, but by then the "iOS" and "macOS" values we'd picked, with that
|
||||
// exact capitalization, were already baked into databases.
|
||||
if IsAppleTV() {
|
||||
return "tvOS"
|
||||
}
|
||||
if runtime.GOOS == "ios" {
|
||||
return "iOS"
|
||||
}
|
||||
if runtime.GOOS == "darwin" {
|
||||
return "macOS"
|
||||
}
|
||||
return runtime.GOOS
|
||||
}
|
||||
|
||||
// IsMacGUIVariant reports whether runtime.GOOS=="darwin" and this one of the
|
||||
// two GUI variants (that is, not tailscaled-on-macOS).
|
||||
// This predicate should not be used to determine sandboxing properties. It's
|
||||
// meant for callers to determine whether the NetworkExtension-like auto-netns
|
||||
// is in effect.
|
||||
func IsMacGUIVariant() bool {
|
||||
return IsMacAppStore() || IsMacSysExt()
|
||||
}
|
||||
|
||||
// IsSandboxedMacOS reports whether this process is a sandboxed macOS
|
||||
// process (either the app or the extension). It is true for the Mac App Store
|
||||
// and macsys (System Extension) version on macOS, and false for
|
||||
// tailscaled-on-macOS.
|
||||
func IsSandboxedMacOS() bool {
|
||||
return IsMacAppStore() || IsMacSysExt()
|
||||
}
|
||||
|
||||
// IsMacSys reports whether this process is part of the Standalone variant of
|
||||
// Tailscale for macOS, either the main GUI process (non-sandboxed) or the
|
||||
// system extension (sandboxed).
|
||||
func IsMacSys() bool {
|
||||
return IsMacSysExt() || IsMacSysApp()
|
||||
}
|
||||
|
||||
var isMacSysApp lazy.SyncValue[bool]
|
||||
|
||||
// IsMacSysApp reports whether this process is the main, non-sandboxed GUI process
|
||||
// that ships with the Standalone variant of Tailscale for macOS.
|
||||
func IsMacSysApp() bool {
|
||||
if runtime.GOOS != "darwin" {
|
||||
return false
|
||||
}
|
||||
|
||||
return isMacSysApp.Get(func() bool {
|
||||
exe, err := os.Executable()
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
// Check that this is the GUI binary, and it is not sandboxed. The GUI binary
|
||||
// shipped in the App Store will always have the App Sandbox enabled.
|
||||
return strings.HasSuffix(exe, "/Contents/MacOS/Tailscale") && !IsMacAppStore()
|
||||
})
|
||||
}
|
||||
|
||||
var isMacSysExt lazy.SyncValue[bool]
|
||||
|
||||
// IsMacSysExt reports whether this binary is the system extension shipped as part of
|
||||
// the standalone "System Extension" (a.k.a. "macsys") version of Tailscale
|
||||
// for macOS.
|
||||
func IsMacSysExt() bool {
|
||||
if runtime.GOOS != "darwin" {
|
||||
return false
|
||||
}
|
||||
return isMacSysExt.Get(func() bool {
|
||||
if strings.Contains(os.Getenv("HOME"), "/Containers/io.tailscale.ipn.macsys/") ||
|
||||
strings.Contains(os.Getenv("XPC_SERVICE_NAME"), "io.tailscale.ipn.macsys") {
|
||||
return true
|
||||
}
|
||||
exe, err := os.Executable()
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return filepath.Base(exe) == "io.tailscale.ipn.macsys.network-extension"
|
||||
})
|
||||
}
|
||||
|
||||
var isMacAppStore lazy.SyncValue[bool]
|
||||
|
||||
// IsMacAppStore whether this binary is from the App Store version of Tailscale
|
||||
// for macOS.
|
||||
func IsMacAppStore() bool {
|
||||
if runtime.GOOS != "darwin" {
|
||||
return false
|
||||
}
|
||||
return isMacAppStore.Get(func() bool {
|
||||
// Both macsys and app store versions can run CLI executable with
|
||||
// suffix /Contents/MacOS/Tailscale. Check $HOME to filter out running
|
||||
// as macsys.
|
||||
return strings.Contains(os.Getenv("HOME"), "/Containers/io.tailscale.ipn.macos/") ||
|
||||
strings.Contains(os.Getenv("XPC_SERVICE_NAME"), "io.tailscale.ipn.macos")
|
||||
})
|
||||
}
|
||||
|
||||
var isAppleTV lazy.SyncValue[bool]
|
||||
|
||||
// IsAppleTV reports whether this binary is part of the Tailscale network extension for tvOS.
|
||||
// Needed because runtime.GOOS returns "ios" otherwise.
|
||||
func IsAppleTV() bool {
|
||||
if runtime.GOOS != "ios" {
|
||||
return false
|
||||
}
|
||||
return isAppleTV.Get(func() bool {
|
||||
return strings.EqualFold(os.Getenv("XPC_SERVICE_NAME"), "io.tailscale.ipn.ios.network-extension-tvos")
|
||||
})
|
||||
}
|
||||
|
||||
var isWindowsGUI lazy.SyncValue[bool]
|
||||
|
||||
// IsWindowsGUI reports whether the current process is the Windows GUI.
|
||||
func IsWindowsGUI() bool {
|
||||
if runtime.GOOS != "windows" {
|
||||
return false
|
||||
}
|
||||
return isWindowsGUI.Get(func() bool {
|
||||
exe, err := os.Executable()
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return strings.EqualFold(exe, "tailscale-ipn.exe") || strings.EqualFold(exe, "tailscale-ipn")
|
||||
})
|
||||
}
|
||||
|
||||
var isUnstableBuild lazy.SyncValue[bool]
|
||||
|
||||
// IsUnstableBuild reports whether this is an unstable build.
|
||||
// That is, whether its minor version number is odd.
|
||||
func IsUnstableBuild() bool {
|
||||
return isUnstableBuild.Get(func() bool {
|
||||
_, rest, ok := strings.Cut(Short(), ".")
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
minorStr, _, ok := strings.Cut(rest, ".")
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
minor, err := strconv.Atoi(minorStr)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return minor%2 == 1
|
||||
})
|
||||
}
|
||||
|
||||
var isDev = lazy.SyncFunc(func() bool {
|
||||
return strings.Contains(Short(), "-dev")
|
||||
})
|
||||
|
||||
// Meta is a JSON-serializable type that contains all the version
|
||||
// information.
|
||||
type Meta struct {
|
||||
// MajorMinorPatch is the "major.minor.patch" version string, without
|
||||
// any hyphenated suffix.
|
||||
MajorMinorPatch string `json:"majorMinorPatch"`
|
||||
|
||||
// IsDev is whether Short contains a -dev suffix. This is whether the build
|
||||
// is a development build (as opposed to an official stable or unstable
|
||||
// build stamped in the usual ways). If you just run "go install" or "go
|
||||
// build" on a dev branch, this will be true.
|
||||
IsDev bool `json:"isDev,omitempty"`
|
||||
|
||||
// Short is MajorMinorPatch but optionally adding "-dev" or "-devYYYYMMDD"
|
||||
// for dev builds, depending on how it was build.
|
||||
Short string `json:"short"`
|
||||
|
||||
// Long is the full version string, including git commit hash(es) as the
|
||||
// suffix.
|
||||
Long string `json:"long"`
|
||||
|
||||
// UnstableBranch is whether the build is from an unstable (development)
|
||||
// branch. That is, it reports whether the minor version is odd.
|
||||
UnstableBranch bool `json:"unstableBranch,omitempty"`
|
||||
|
||||
// GitCommit, if non-empty, is the git commit of the
|
||||
// github.com/tailscale/tailscale repository at which Tailscale was
|
||||
// built. Its format is the one returned by `git describe --always
|
||||
// --exclude "*" --dirty --abbrev=200`.
|
||||
GitCommit string `json:"gitCommit,omitempty"`
|
||||
|
||||
// GitDirty is whether Go stamped the binary as having dirty version
|
||||
// control changes in the working directory (debug.ReadBuildInfo
|
||||
// setting "vcs.modified" was true).
|
||||
GitDirty bool `json:"gitDirty,omitempty"`
|
||||
|
||||
// ExtraGitCommit, if non-empty, is the git commit of a "supplemental"
|
||||
// repository at which Tailscale was built. Its format is the same as
|
||||
// gitCommit.
|
||||
//
|
||||
// ExtraGitCommit is used to track the source revision when the main
|
||||
// Tailscale repository is integrated into and built from another
|
||||
// repository (for example, Tailscale's proprietary code, or the
|
||||
// Android OSS repository). Together, GitCommit and ExtraGitCommit
|
||||
// exactly describe what repositories and commits were used in a
|
||||
// build.
|
||||
ExtraGitCommit string `json:"extraGitCommit,omitempty"`
|
||||
|
||||
// DaemonLong is the version number from the tailscaled
|
||||
// daemon, if requested.
|
||||
DaemonLong string `json:"daemonLong,omitempty"`
|
||||
|
||||
// GitCommitTime is the commit time of the git commit in GitCommit.
|
||||
GitCommitTime string `json:"gitCommitTime,omitempty"`
|
||||
|
||||
// Cap is the current Tailscale capability version. It's a monotonically
|
||||
// incrementing integer that's incremented whenever a new capability is
|
||||
// added.
|
||||
Cap int `json:"cap"`
|
||||
}
|
||||
|
||||
var getMeta lazy.SyncValue[Meta]
|
||||
|
||||
// GetMeta returns version metadata about the current build.
|
||||
func GetMeta() Meta {
|
||||
return getMeta.Get(func() Meta {
|
||||
return Meta{
|
||||
MajorMinorPatch: majorMinorPatch(),
|
||||
Short: Short(),
|
||||
Long: Long(),
|
||||
GitCommitTime: getEmbeddedInfo().commitTime,
|
||||
GitCommit: gitCommit(),
|
||||
GitDirty: gitDirty(),
|
||||
ExtraGitCommit: extraGitCommitStamp,
|
||||
IsDev: isDev(),
|
||||
UnstableBranch: IsUnstableBuild(),
|
||||
Cap: int(tailcfg.CurrentCapabilityVersion),
|
||||
}
|
||||
})
|
||||
}
|
||||
10
vendor/tailscale.com/version/race.go
generated
vendored
Normal file
10
vendor/tailscale.com/version/race.go
generated
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
// Copyright (c) Tailscale Inc & AUTHORS
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
//go:build race
|
||||
|
||||
package version
|
||||
|
||||
// IsRace reports whether the current binary was built with the Go
|
||||
// race detector enabled.
|
||||
func IsRace() bool { return true }
|
||||
10
vendor/tailscale.com/version/race_off.go
generated
vendored
Normal file
10
vendor/tailscale.com/version/race_off.go
generated
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
// Copyright (c) Tailscale Inc & AUTHORS
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
//go:build !race
|
||||
|
||||
package version
|
||||
|
||||
// IsRace reports whether the current binary was built with the Go
|
||||
// race detector enabled.
|
||||
func IsRace() bool { return false }
|
||||
171
vendor/tailscale.com/version/version.go
generated
vendored
Normal file
171
vendor/tailscale.com/version/version.go
generated
vendored
Normal file
@@ -0,0 +1,171 @@
|
||||
// Copyright (c) Tailscale Inc & AUTHORS
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
// Package version provides the version that the binary was built at.
|
||||
package version
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime/debug"
|
||||
"strings"
|
||||
|
||||
tailscaleroot "tailscale.com"
|
||||
"tailscale.com/types/lazy"
|
||||
)
|
||||
|
||||
// Stamp vars can have their value set at build time by linker flags (see
|
||||
// build_dist.sh for an example). When set, these stamps serve as additional
|
||||
// inputs to computing the binary's version as returned by the functions in this
|
||||
// package.
|
||||
//
|
||||
// All stamps are optional.
|
||||
var (
|
||||
// longStamp is the full version identifier of the build. If set, it is
|
||||
// returned verbatim by Long() and other functions that return Long()'s
|
||||
// output.
|
||||
longStamp string
|
||||
|
||||
// shortStamp is the short version identifier of the build. If set, it
|
||||
// is returned verbatim by Short() and other functions that return Short()'s
|
||||
// output.
|
||||
shortStamp string
|
||||
|
||||
// gitCommitStamp is the git commit of the github.com/tailscale/tailscale
|
||||
// repository at which Tailscale was built. Its format is the one returned
|
||||
// by `git rev-parse <commit>`. If set, it is used instead of any git commit
|
||||
// information embedded by the Go tool.
|
||||
gitCommitStamp string
|
||||
|
||||
// gitDirtyStamp is whether the git checkout from which the code was built
|
||||
// was dirty. Its value is ORed with the dirty bit embedded by the Go tool.
|
||||
//
|
||||
// We need this because when we build binaries from another repo that
|
||||
// imports tailscale.com, the Go tool doesn't stamp any dirtiness info into
|
||||
// the binary. Instead, we have to inject the dirty bit ourselves here.
|
||||
gitDirtyStamp bool
|
||||
|
||||
// extraGitCommit, is the git commit of a "supplemental" repository at which
|
||||
// Tailscale was built. Its format is the same as gitCommit.
|
||||
//
|
||||
// extraGitCommit is used to track the source revision when the main
|
||||
// Tailscale repository is integrated into and built from another repository
|
||||
// (for example, Tailscale's proprietary code, or the Android OSS
|
||||
// repository). Together, gitCommit and extraGitCommit exactly describe what
|
||||
// repositories and commits were used in a build.
|
||||
extraGitCommitStamp string
|
||||
)
|
||||
|
||||
var long lazy.SyncValue[string]
|
||||
|
||||
// Long returns a full version number for this build, of one of the forms:
|
||||
//
|
||||
// - "x.y.z-commithash-otherhash" for release builds distributed by Tailscale
|
||||
// - "x.y.z-commithash" for release builds built with build_dist.sh
|
||||
// - "x.y.z-changecount-commithash-otherhash" for untagged release branch
|
||||
// builds by Tailscale (these are not distributed).
|
||||
// - "x.y.z-changecount-commithash" for untagged release branch builds
|
||||
// built with build_dist.sh
|
||||
// - "x.y.z-devYYYYMMDD-commithash{,-dirty}" for builds made with plain "go
|
||||
// build" or "go install"
|
||||
// - "x.y.z-ERR-BuildInfo" for builds made by plain "go run"
|
||||
func Long() string {
|
||||
return long.Get(func() string {
|
||||
if longStamp != "" {
|
||||
return longStamp
|
||||
}
|
||||
bi := getEmbeddedInfo()
|
||||
if !bi.valid {
|
||||
return strings.TrimSpace(tailscaleroot.VersionDotTxt) + "-ERR-BuildInfo"
|
||||
}
|
||||
return fmt.Sprintf("%s-dev%s-t%s%s", strings.TrimSpace(tailscaleroot.VersionDotTxt), bi.commitDate, bi.commitAbbrev(), dirtyString())
|
||||
})
|
||||
}
|
||||
|
||||
var short lazy.SyncValue[string]
|
||||
|
||||
// Short returns a short version number for this build, of the forms:
|
||||
//
|
||||
// - "x.y.z" for builds distributed by Tailscale or built with build_dist.sh
|
||||
// - "x.y.z-devYYYYMMDD" for builds made with plain "go build" or "go install"
|
||||
// - "x.y.z-ERR-BuildInfo" for builds made by plain "go run"
|
||||
func Short() string {
|
||||
return short.Get(func() string {
|
||||
if shortStamp != "" {
|
||||
return shortStamp
|
||||
}
|
||||
bi := getEmbeddedInfo()
|
||||
if !bi.valid {
|
||||
return strings.TrimSpace(tailscaleroot.VersionDotTxt) + "-ERR-BuildInfo"
|
||||
}
|
||||
return strings.TrimSpace(tailscaleroot.VersionDotTxt) + "-dev" + bi.commitDate
|
||||
})
|
||||
}
|
||||
|
||||
type embeddedInfo struct {
|
||||
valid bool
|
||||
commit string
|
||||
commitDate string
|
||||
commitTime string
|
||||
dirty bool
|
||||
}
|
||||
|
||||
func (i embeddedInfo) commitAbbrev() string {
|
||||
if len(i.commit) >= 9 {
|
||||
return i.commit[:9]
|
||||
}
|
||||
return i.commit
|
||||
}
|
||||
|
||||
var getEmbeddedInfo = lazy.SyncFunc(func() embeddedInfo {
|
||||
bi, ok := debug.ReadBuildInfo()
|
||||
if !ok {
|
||||
return embeddedInfo{}
|
||||
}
|
||||
ret := embeddedInfo{valid: true}
|
||||
for _, s := range bi.Settings {
|
||||
switch s.Key {
|
||||
case "vcs.revision":
|
||||
ret.commit = s.Value
|
||||
case "vcs.time":
|
||||
ret.commitTime = s.Value
|
||||
if len(s.Value) >= len("yyyy-mm-dd") {
|
||||
ret.commitDate = s.Value[:len("yyyy-mm-dd")]
|
||||
ret.commitDate = strings.ReplaceAll(ret.commitDate, "-", "")
|
||||
}
|
||||
case "vcs.modified":
|
||||
ret.dirty = s.Value == "true"
|
||||
}
|
||||
}
|
||||
if ret.commit == "" || ret.commitDate == "" {
|
||||
// Build info is present in the binary, but has no useful data. Act as
|
||||
// if it's missing.
|
||||
return embeddedInfo{}
|
||||
}
|
||||
return ret
|
||||
})
|
||||
|
||||
func gitCommit() string {
|
||||
if gitCommitStamp != "" {
|
||||
return gitCommitStamp
|
||||
}
|
||||
return getEmbeddedInfo().commit
|
||||
}
|
||||
|
||||
func gitDirty() bool {
|
||||
if gitDirtyStamp {
|
||||
return true
|
||||
}
|
||||
return getEmbeddedInfo().dirty
|
||||
}
|
||||
|
||||
func dirtyString() string {
|
||||
if gitDirty() {
|
||||
return "-dirty"
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func majorMinorPatch() string {
|
||||
ret, _, _ := strings.Cut(Short(), "-")
|
||||
return ret
|
||||
}
|
||||
Reference in New Issue
Block a user