mirror of
https://github.com/tailscale/tailscale.git
synced 2025-04-21 14:11:56 +00:00
cmd/tailscaled: add subcommand on darwin to install+start tailscaled under launchd
Tangentially related to #987, #177, #594, #925.
This commit is contained in:
parent
54e108ff4e
commit
29b028b9c4
104
cmd/tailscaled/install_darwin.go
Normal file
104
cmd/tailscaled/install_darwin.go
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
// Copyright (c) 2021 Tailscale Inc & AUTHORS All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
installSystemDaemon = installSystemDaemonDarwin
|
||||||
|
}
|
||||||
|
|
||||||
|
// darwinLaunchdPlist is the launchd.plist that's written to
|
||||||
|
// /Library/LaunchDaemons/com.tailscale.tailscaled.plist or (in the
|
||||||
|
// future) a user-specific location.
|
||||||
|
//
|
||||||
|
// See man launchd.plist.
|
||||||
|
const darwinLaunchdPlist = `
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
|
||||||
|
<key>Label</key>
|
||||||
|
<string>com.tailscale.tailscaled</string>
|
||||||
|
|
||||||
|
<key>ProgramArguments</key>
|
||||||
|
<array>
|
||||||
|
<string>/usr/local/bin/tailscaled</string>
|
||||||
|
</array>
|
||||||
|
|
||||||
|
<key>RunAtLoad</key>
|
||||||
|
<true/>
|
||||||
|
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
|
`
|
||||||
|
|
||||||
|
const sysPlist = "/Library/LaunchDaemons/com.tailscale.tailscaled.plist"
|
||||||
|
const targetBin = "/usr/local/bin/tailscaled"
|
||||||
|
const service = "system/com.tailscale.tailscaled"
|
||||||
|
|
||||||
|
func installSystemDaemonDarwin() (err error) {
|
||||||
|
defer func() {
|
||||||
|
if err != nil && os.Getuid() != 0 {
|
||||||
|
err = fmt.Errorf("%w; try running tailscaled with sudo", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
// Copy ourselves to /usr/local/bin/tailscaled.
|
||||||
|
exe, err := os.Executable()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to find our own executable path: %w", err)
|
||||||
|
}
|
||||||
|
tmpBin := targetBin + ".tmp"
|
||||||
|
f, err := os.Create(tmpBin)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
self, err := os.Open(exe)
|
||||||
|
if err != nil {
|
||||||
|
f.Close()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_, err = io.Copy(f, self)
|
||||||
|
self.Close()
|
||||||
|
if err != nil {
|
||||||
|
f.Close()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := f.Close(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := os.Chmod(tmpBin, 0755); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := os.Rename(tmpBin, targetBin); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Two best effort commands to stop a previous run.
|
||||||
|
exec.Command("launchctl", "stop", "system/com.tailscale.tailscaled").Run()
|
||||||
|
exec.Command("launchctl", "unload", sysPlist).Run()
|
||||||
|
|
||||||
|
if err := ioutil.WriteFile(sysPlist, []byte(darwinLaunchdPlist), 0700); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if out, err := exec.Command("launchctl", "load", sysPlist).CombinedOutput(); err != nil {
|
||||||
|
return fmt.Errorf("error running launchctl load %s: %v, %s", sysPlist, err, out)
|
||||||
|
}
|
||||||
|
|
||||||
|
if out, err := exec.Command("launchctl", "start", service).CombinedOutput(); err != nil {
|
||||||
|
return fmt.Errorf("error running launchctl start %s: %v, %s", service, err, out)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
@ -71,6 +71,8 @@ var args struct {
|
|||||||
verbose int
|
verbose int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var installSystemDaemon func() error // non-nil on some platforms
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
// We aren't very performance sensitive, and the parts that are
|
// We aren't very performance sensitive, and the parts that are
|
||||||
// performance sensitive (wireguard) try hard not to do any memory
|
// performance sensitive (wireguard) try hard not to do any memory
|
||||||
@ -91,11 +93,23 @@ func main() {
|
|||||||
flag.StringVar(&args.socketpath, "socket", paths.DefaultTailscaledSocket(), "path of the service unix socket")
|
flag.StringVar(&args.socketpath, "socket", paths.DefaultTailscaledSocket(), "path of the service unix socket")
|
||||||
flag.BoolVar(&printVersion, "version", false, "print version information and exit")
|
flag.BoolVar(&printVersion, "version", false, "print version information and exit")
|
||||||
|
|
||||||
if len(os.Args) > 1 && os.Args[1] == "debug" {
|
if len(os.Args) > 1 {
|
||||||
|
switch os.Args[1] {
|
||||||
|
case "debug":
|
||||||
if err := debugMode(os.Args[2:]); err != nil {
|
if err := debugMode(os.Args[2:]); err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
|
case "install-system-daemon":
|
||||||
|
if f := installSystemDaemon; f == nil {
|
||||||
|
log.SetFlags(0)
|
||||||
|
log.Fatalf("install-system-daemon not available on %v", runtime.GOOS)
|
||||||
|
} else if err := f(); err != nil {
|
||||||
|
log.SetFlags(0)
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if beWindowsSubprocess() {
|
if beWindowsSubprocess() {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user