1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104
|
// License: GPLv3 Copyright: 2023, Kovid Goyal, <kovid at kovidgoyal.net>
package tui
import (
"errors"
"fmt"
"os"
"os/exec"
"path/filepath"
"strconv"
"strings"
"sync"
"time"
"github.com/shirou/gopsutil/process"
"golang.org/x/sys/unix"
"github.com/kovidgoyal/kitty/tools/utils"
)
var _ = fmt.Print
var TmuxExe = sync.OnceValue(func() string {
return utils.FindExe("tmux")
})
func tmux_socket_address() (socket string) {
socket = os.Getenv("TMUX")
if socket == "" {
return ""
}
addr, pid_str, found := strings.Cut(socket, ",")
if !found {
return ""
}
if unix.Access(addr, unix.R_OK|unix.W_OK) != nil {
return ""
}
pid_str, _, _ = strings.Cut(pid_str, ",")
pid, err := strconv.ParseInt(pid_str, 10, 32)
if err != nil {
return ""
}
p, err := process.NewProcess(int32(pid))
if err != nil {
return ""
}
cmd, err := p.CmdlineSlice()
if err != nil {
return ""
}
if len(cmd) > 0 && strings.ToLower(filepath.Base(cmd[0])) != "tmux" {
return ""
}
return socket
}
var TmuxSocketAddress = sync.OnceValue(tmux_socket_address)
func tmux_command(args ...string) (c *exec.Cmd, stderr *strings.Builder) {
c = exec.Command(TmuxExe(), args...)
stderr = &strings.Builder{}
c.Stderr = stderr
return c, stderr
}
func tmux_allow_passthrough() error {
c, stderr := tmux_command("show", "-Ap", "allow-passthrough")
allowed, not_allowed := errors.New("allowed"), errors.New("not allowed")
get_result := make(chan error)
go func() {
output, err := c.Output()
if err != nil {
get_result <- fmt.Errorf("Running %#v failed with error: %w. STDERR: %s", c.Args, err, stderr.String())
} else {
q := strings.TrimSpace(utils.UnsafeBytesToString(output))
if strings.HasSuffix(q, " on") || strings.HasSuffix(q, " all") {
get_result <- allowed
} else {
get_result <- not_allowed
}
}
}()
select {
case r := <-get_result:
if r == allowed {
return nil
}
if r != not_allowed {
return r
}
c, stderr = tmux_command("set", "-p", "allow-passthrough", "on")
err := c.Run()
if err != nil {
err = fmt.Errorf("Running %#v failed with error: %w. STDERR: %s", c.Args, err, stderr.String())
}
return err
case <-time.After(2 * time.Second):
return fmt.Errorf("Tmux command timed out. This often happens when the version of tmux on your PATH is older than the version of the running tmux server")
}
}
var TmuxAllowPassthrough = sync.OnceValue(tmux_allow_passthrough)
|