feat: «Здесь» from a machine's file pane opens the terminal in that pane's folder (the agent starts the shell there; an older agent, or a folder gone, at home)

This commit is contained in:
redtea committed 2026-10-16 18:17:11 +03:00
1 parent 4fb26a9652
commit 57c2f1338f
10 files changed
+143 -12

No files matched your search

+22 -2
View File
@@ -4,6 +4,8 @@ import (
"fmt"
"os"
"os/exec"
"path/filepath"
"strings"
"sync"
"syscall"
"time"
@@ -41,8 +43,12 @@ func CloseTerminals() {
// StartPTY launches a login shell attached to a new PTY. With user empty (or
// equal to the agent's own user) it is the agent's shell - root by default,
// since the agent runs as a root systemd service. Any other user is entered via
// `su -l`, which only a root agent can do without a password.
func StartPTY(user string) (*PTY, error) {
// `su -l`, which only a root agent can do without a password. dir, when it
// is a folder, is where the shell starts instead of home.
func StartPTY(user, dir string) (*PTY, error) {
if dir != "" && (!filepath.IsAbs(dir) || strings.ContainsAny(dir, "\x00\r\n") || !isDir(dir)) {
dir = ""
}
var cmd *exec.Cmd
env := append(os.Environ(), "TERM=xterm-256color")
if user == "" || user == currentUser() {
@@ -54,6 +60,9 @@ func StartPTY(user string) (*PTY, error) {
cmd.Dir = home
env = append(env, "HOME="+home)
}
if dir != "" {
cmd.Dir = dir
}
} else {
if !validUserName(user) {
return nil, fmt.Errorf("недопустимое имя пользователя %q", user)
@@ -69,6 +78,11 @@ func StartPTY(user string) (*PTY, error) {
return nil, fmt.Errorf("su не найден: %w", err)
}
cmd = exec.Command(su, "-l", user)
// su -l always goes home; to start elsewhere, its shell changes
// directory first and becomes the login shell (sh and csh alike).
if dir != "" {
cmd = exec.Command(su, "-l", user, "-c", "cd "+shQuote(dir)+"; exec \"$SHELL\" -l")
}
// su -l goes to the user's home; starting there too keeps the shell
// out of "/" should it not.
if home := homeDir(user); isDir(home) {
@@ -126,3 +140,9 @@ func (p *PTY) Close() error {
})
return err
}
// shQuote puts s in single quotes for sh and csh alike, closing and
// reopening them around each quote inside.
func shQuote(s string) string {
return "'" + strings.ReplaceAll(s, "'", `'\''`) + "'"
}