2020-02-18 10:47:19 -07:00
|
|
|
// Copyright 2020 The Go Authors. All rights reserved.
|
|
|
|
// Use of this source code is governed by a BSD-style
|
|
|
|
// license that can be found in the LICENSE file.
|
|
|
|
|
2020-03-05 15:54:57 -07:00
|
|
|
// +build darwin dragonfly freebsd linux netbsd openbsd solaris
|
2020-02-18 10:47:19 -07:00
|
|
|
|
|
|
|
package lsprpc
|
|
|
|
|
|
|
|
import (
|
2020-07-28 16:00:54 -06:00
|
|
|
"crypto/sha256"
|
2020-03-05 15:54:57 -07:00
|
|
|
"errors"
|
2020-02-18 10:47:19 -07:00
|
|
|
"fmt"
|
|
|
|
"log"
|
|
|
|
"os"
|
|
|
|
"os/exec"
|
2020-03-05 15:54:57 -07:00
|
|
|
"os/user"
|
2020-02-18 10:47:19 -07:00
|
|
|
"path/filepath"
|
2020-03-05 15:54:57 -07:00
|
|
|
"strconv"
|
2020-02-26 14:22:54 -07:00
|
|
|
"syscall"
|
2020-08-26 15:41:45 -06:00
|
|
|
|
|
|
|
"golang.org/x/xerrors"
|
2020-02-18 10:47:19 -07:00
|
|
|
)
|
|
|
|
|
2020-02-26 14:22:54 -07:00
|
|
|
func init() {
|
|
|
|
startRemote = startRemotePosix
|
|
|
|
autoNetworkAddress = autoNetworkAddressPosix
|
2020-03-05 15:54:57 -07:00
|
|
|
verifyRemoteOwnership = verifyRemoteOwnershipPosix
|
2020-02-26 14:22:54 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
func startRemotePosix(goplsPath string, args ...string) error {
|
|
|
|
cmd := exec.Command(goplsPath, args...)
|
|
|
|
cmd.SysProcAttr = &syscall.SysProcAttr{
|
|
|
|
Setsid: true,
|
|
|
|
}
|
|
|
|
if err := cmd.Start(); err != nil {
|
2020-08-26 15:41:45 -06:00
|
|
|
return xerrors.Errorf("starting remote gopls: %w", err)
|
2020-02-26 14:22:54 -07:00
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2020-02-18 10:47:19 -07:00
|
|
|
// autoNetworkAddress resolves an id on the 'auto' pseduo-network to a
|
|
|
|
// real network and address. On unix, this uses unix domain sockets.
|
2020-02-26 14:22:54 -07:00
|
|
|
func autoNetworkAddressPosix(goplsPath, id string) (network string, address string) {
|
2020-02-18 10:47:19 -07:00
|
|
|
// Especially when doing local development or testing, it's important that
|
|
|
|
// the remote gopls instance we connect to is running the same binary as our
|
|
|
|
// forwarder. So we encode a short hash of the binary path into the daemon
|
|
|
|
// socket name. If possible, we also include the buildid in this hash, to
|
|
|
|
// account for long-running processes where the binary has been subsequently
|
|
|
|
// rebuilt.
|
2020-07-28 16:00:54 -06:00
|
|
|
h := sha256.New()
|
2020-02-18 10:47:19 -07:00
|
|
|
cmd := exec.Command("go", "tool", "buildid", goplsPath)
|
|
|
|
cmd.Stdout = h
|
|
|
|
var pathHash []byte
|
|
|
|
if err := cmd.Run(); err == nil {
|
|
|
|
pathHash = h.Sum(nil)
|
|
|
|
} else {
|
|
|
|
log.Printf("error getting current buildid: %v", err)
|
2020-07-28 16:00:54 -06:00
|
|
|
sum := sha256.Sum256([]byte(goplsPath))
|
2020-02-18 10:47:19 -07:00
|
|
|
pathHash = sum[:]
|
|
|
|
}
|
|
|
|
shortHash := fmt.Sprintf("%x", pathHash)[:6]
|
|
|
|
user := os.Getenv("USER")
|
|
|
|
if user == "" {
|
|
|
|
user = "shared"
|
|
|
|
}
|
|
|
|
basename := filepath.Base(goplsPath)
|
|
|
|
idComponent := ""
|
|
|
|
if id != "" {
|
|
|
|
idComponent = "-" + id
|
|
|
|
}
|
|
|
|
return "unix", filepath.Join(os.TempDir(), fmt.Sprintf("%s-%s-daemon.%s%s", basename, shortHash, user, idComponent))
|
|
|
|
}
|
2020-03-05 15:54:57 -07:00
|
|
|
|
|
|
|
func verifyRemoteOwnershipPosix(network, address string) (bool, error) {
|
|
|
|
if network != "unix" {
|
|
|
|
return true, nil
|
|
|
|
}
|
|
|
|
fi, err := os.Stat(address)
|
|
|
|
if err != nil {
|
|
|
|
if os.IsNotExist(err) {
|
|
|
|
return true, nil
|
|
|
|
}
|
2020-08-26 15:41:45 -06:00
|
|
|
return false, xerrors.Errorf("checking socket owner: %w", err)
|
2020-03-05 15:54:57 -07:00
|
|
|
}
|
|
|
|
stat, ok := fi.Sys().(*syscall.Stat_t)
|
|
|
|
if !ok {
|
|
|
|
return false, errors.New("fi.Sys() is not a Stat_t")
|
|
|
|
}
|
|
|
|
user, err := user.Current()
|
|
|
|
if err != nil {
|
2020-08-26 15:41:45 -06:00
|
|
|
return false, xerrors.Errorf("checking current user: %w", err)
|
2020-03-05 15:54:57 -07:00
|
|
|
}
|
|
|
|
uid, err := strconv.ParseUint(user.Uid, 10, 32)
|
|
|
|
if err != nil {
|
2020-08-26 15:41:45 -06:00
|
|
|
return false, xerrors.Errorf("parsing current UID: %w", err)
|
2020-03-05 15:54:57 -07:00
|
|
|
}
|
|
|
|
return stat.Uid == uint32(uid), nil
|
|
|
|
}
|