tailscale/paths/paths_unix.go

87 lines
1.7 KiB
Go

// Copyright (c) Tailscale Inc & AUTHORS
// SPDX-License-Identifier: BSD-3-Clause
//go:build !windows && !wasm && !plan9 && !tamago
package paths
import (
"fmt"
"os"
"path/filepath"
"runtime"
"golang.org/x/sys/unix"
"tailscale.com/version/distro"
)
func init() {
stateFileFunc = stateFileUnix
ensureStateDirPerms = ensureStateDirPermsUnix
}
func statePath() string {
switch runtime.GOOS {
case "linux":
return "/var/lib/tailscale/tailscaled.state"
case "freebsd", "openbsd":
return "/var/db/tailscale/tailscaled.state"
case "darwin":
return "/Library/Tailscale/tailscaled.state"
default:
return ""
}
}
func stateFileUnix() string {
if distro.Get() == distro.Gokrazy {
return "/perm/tailscaled/tailscaled.state"
}
path := statePath()
if path == "" {
return ""
}
try := path
for i := 0; i < 3; i++ { // check writability of the file, /var/lib/tailscale, and /var/lib
err := unix.Access(try, unix.O_RDWR)
if err == nil {
return path
}
try = filepath.Dir(try)
}
if os.Getuid() == 0 {
return ""
}
// For non-root users, fall back to $XDG_DATA_HOME/tailscale/*.
return filepath.Join(xdgDataHome(), "tailscale", "tailscaled.state")
}
func xdgDataHome() string {
if e := os.Getenv("XDG_DATA_HOME"); e != "" {
return e
}
return filepath.Join(os.Getenv("HOME"), ".local/share")
}
func ensureStateDirPermsUnix(dir string) error {
if filepath.Base(dir) != "tailscale" {
return nil
}
fi, err := os.Stat(dir)
if err != nil {
return err
}
if !fi.IsDir() {
return fmt.Errorf("expected %q to be a directory; is %v", dir, fi.Mode())
}
const perm = 0700
if fi.Mode().Perm() == perm {
// Already correct.
return nil
}
return os.Chmod(dir, perm)
}