55 lines
1.2 KiB
Go
55 lines
1.2 KiB
Go
package agent
|
|
|
|
import (
|
|
"os"
|
|
"os/exec"
|
|
|
|
"github.com/creack/pty"
|
|
)
|
|
|
|
// PTY is a pseudo-terminal running an interactive login shell.
|
|
type PTY struct {
|
|
cmd *exec.Cmd
|
|
f *os.File
|
|
}
|
|
|
|
// StartPTY launches the shell attached to a new PTY. The agent runs as root
|
|
// (systemd User=root), so this is a root shell by design.
|
|
func StartPTY() (*PTY, error) {
|
|
shell := "/bin/bash"
|
|
if _, err := os.Stat(shell); err != nil {
|
|
shell = "/bin/sh"
|
|
}
|
|
cmd := exec.Command(shell, "-l")
|
|
cmd.Env = append(os.Environ(), "TERM=xterm-256color")
|
|
f, err := pty.Start(cmd)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &PTY{cmd: cmd, f: f}, nil
|
|
}
|
|
|
|
// Read reads terminal output.
|
|
func (p *PTY) Read(b []byte) (int, error) { return p.f.Read(b) }
|
|
|
|
// Write writes keystrokes to the terminal.
|
|
func (p *PTY) Write(b []byte) (int, error) { return p.f.Write(b) }
|
|
|
|
// Resize changes the terminal window size.
|
|
func (p *PTY) Resize(cols, rows uint16) {
|
|
if cols == 0 || rows == 0 {
|
|
return
|
|
}
|
|
_ = pty.Setsize(p.f, &pty.Winsize{Rows: rows, Cols: cols})
|
|
}
|
|
|
|
// Close terminates the shell and releases the PTY.
|
|
func (p *PTY) Close() error {
|
|
err := p.f.Close()
|
|
if p.cmd.Process != nil {
|
|
_ = p.cmd.Process.Kill()
|
|
}
|
|
_ = p.cmd.Wait()
|
|
return err
|
|
}
|