|
|
|
package terminal
|
|
|
|
|
|
|
|
import (
|
|
|
|
"os"
|
|
|
|
"os/exec"
|
|
|
|
"syscall"
|
|
|
|
"time"
|
|
|
|
"unsafe"
|
|
|
|
|
|
|
|
"github.com/1Panel-dev/1Panel/backend/global"
|
|
|
|
"github.com/creack/pty"
|
|
|
|
"github.com/pkg/errors"
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
DefaultCloseSignal = syscall.SIGINT
|
|
|
|
DefaultCloseTimeout = 10 * time.Second
|
|
|
|
)
|
|
|
|
|
|
|
|
type LocalCommand struct {
|
|
|
|
closeSignal syscall.Signal
|
|
|
|
closeTimeout time.Duration
|
|
|
|
|
|
|
|
cmd *exec.Cmd
|
|
|
|
pty *os.File
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewCommand(commands string) (*LocalCommand, error) {
|
|
|
|
cmd := exec.Command("sh", "-c", commands)
|
|
|
|
|
|
|
|
pty, err := pty.Start(cmd)
|
|
|
|
if err != nil {
|
|
|
|
return nil, errors.Wrapf(err, "failed to start command")
|
|
|
|
}
|
|
|
|
|
|
|
|
lcmd := &LocalCommand{
|
|
|
|
closeSignal: DefaultCloseSignal,
|
|
|
|
closeTimeout: DefaultCloseTimeout,
|
|
|
|
|
|
|
|
cmd: cmd,
|
|
|
|
pty: pty,
|
|
|
|
}
|
|
|
|
|
|
|
|
return lcmd, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (lcmd *LocalCommand) Read(p []byte) (n int, err error) {
|
|
|
|
return lcmd.pty.Read(p)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (lcmd *LocalCommand) Write(p []byte) (n int, err error) {
|
|
|
|
return lcmd.pty.Write(p)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (lcmd *LocalCommand) Close() error {
|
|
|
|
if lcmd.cmd != nil && lcmd.cmd.Process != nil {
|
|
|
|
_ = lcmd.cmd.Process.Kill()
|
|
|
|
}
|
|
|
|
_ = lcmd.pty.Close()
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (lcmd *LocalCommand) ResizeTerminal(width int, height int) error {
|
|
|
|
window := struct {
|
|
|
|
row uint16
|
|
|
|
col uint16
|
|
|
|
x uint16
|
|
|
|
y uint16
|
|
|
|
}{
|
|
|
|
uint16(height),
|
|
|
|
uint16(width),
|
|
|
|
0,
|
|
|
|
0,
|
|
|
|
}
|
|
|
|
_, _, errno := syscall.Syscall(
|
|
|
|
syscall.SYS_IOCTL,
|
|
|
|
lcmd.pty.Fd(),
|
|
|
|
syscall.TIOCSWINSZ,
|
|
|
|
uintptr(unsafe.Pointer(&window)),
|
|
|
|
)
|
|
|
|
if errno != 0 {
|
|
|
|
return errno
|
|
|
|
} else {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (lcmd *LocalCommand) Wait(quitChan chan bool) {
|
|
|
|
if err := lcmd.cmd.Wait(); err != nil {
|
|
|
|
global.LOG.Errorf("ssh session wait failed, err: %v", err)
|
|
|
|
setQuit(quitChan)
|
|
|
|
}
|
|
|
|
}
|