mirror of
https://github.com/wavetermdev/backup.git
synced 2026-08-05 13:57:07 -07:00
use cirfile for detached commands
This commit is contained in:
@@ -377,6 +377,9 @@ func handleClient() (int, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return 1, err
|
return 1, err
|
||||||
}
|
}
|
||||||
|
if runPacket.Detached {
|
||||||
|
return 1, fmt.Errorf("cannot run detached command from command line client")
|
||||||
|
}
|
||||||
donePacket, err := shexec.RunClientSSHCommandAndWait(runPacket, shexec.StdContext{}, opts.SSHOpts, nil, opts.Debug)
|
donePacket, err := shexec.RunClientSSHCommandAndWait(runPacket, shexec.StdContext{}, opts.SSHOpts, nil, opts.Debug)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 1, err
|
return 1, err
|
||||||
|
|||||||
@@ -118,22 +118,6 @@ func GetMShellHomeDir() string {
|
|||||||
return ExpandHomeDir(DefaultMShellHome)
|
return ExpandHomeDir(DefaultMShellHome)
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetPtyOutFile(ck CommandKey, seqNum int) (string, error) {
|
|
||||||
if err := ck.Validate("ck"); err != nil {
|
|
||||||
return "", fmt.Errorf("cannot get command files: %w", err)
|
|
||||||
}
|
|
||||||
if seqNum < 0 {
|
|
||||||
return "", fmt.Errorf("invalid seqnum, cannot be negative")
|
|
||||||
}
|
|
||||||
sessionId, cmdId := ck.Split()
|
|
||||||
sdir, err := EnsureSessionDir(sessionId)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
base := path.Join(sdir, cmdId)
|
|
||||||
return fmt.Sprintf("%s.%d.ptyout", base, seqNum), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetCommandFileNames(ck CommandKey) (*CommandFileNames, error) {
|
func GetCommandFileNames(ck CommandKey) (*CommandFileNames, error) {
|
||||||
if err := ck.Validate("ck"); err != nil {
|
if err := ck.Validate("ck"); err != nil {
|
||||||
return nil, fmt.Errorf("cannot get command files: %w", err)
|
return nil, fmt.Errorf("cannot get command files: %w", err)
|
||||||
@@ -151,15 +135,6 @@ func GetCommandFileNames(ck CommandKey) (*CommandFileNames, error) {
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func MakeCommandFileNamesWithHome(mhome string, ck CommandKey) *CommandFileNames {
|
|
||||||
base := path.Join(mhome, SessionsDirBaseName, ck.GetSessionId(), ck.GetCmdId())
|
|
||||||
return &CommandFileNames{
|
|
||||||
PtyOutFile: base + ".ptyout",
|
|
||||||
StdinFifo: base + ".stdin",
|
|
||||||
RunnerOutFile: base + ".runout",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func CleanUpCmdFiles(sessionId string, cmdId string) error {
|
func CleanUpCmdFiles(sessionId string, cmdId string) error {
|
||||||
if cmdId == "" {
|
if cmdId == "" {
|
||||||
return fmt.Errorf("bad cmdid, cannot clean up")
|
return fmt.Errorf("bad cmdid, cannot clean up")
|
||||||
|
|||||||
+11
-4
@@ -378,6 +378,13 @@ func (p *ResponsePacketType) Err() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *ResponsePacketType) String() string {
|
||||||
|
if p.Success {
|
||||||
|
return "response[success]"
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("response[error:%s]", p.Error)
|
||||||
|
}
|
||||||
|
|
||||||
func MakeErrorResponsePacket(reqId string, err error) *ResponsePacketType {
|
func MakeErrorResponsePacket(reqId string, err error) *ResponsePacketType {
|
||||||
return &ResponsePacketType{Type: ResponsePacketStr, RespId: reqId, Error: err.Error()}
|
return &ResponsePacketType{Type: ResponsePacketStr, RespId: reqId, Error: err.Error()}
|
||||||
}
|
}
|
||||||
@@ -504,10 +511,10 @@ func MakeCmdStartPacket(reqId string) *CmdStartPacketType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type TermOpts struct {
|
type TermOpts struct {
|
||||||
Rows int `json:"rows"`
|
Rows int `json:"rows"`
|
||||||
Cols int `json:"cols"`
|
Cols int `json:"cols"`
|
||||||
Term string `json:"term"`
|
Term string `json:"term"`
|
||||||
CmdSize int64 `json:"cmdsize,omitempty"`
|
MaxPtySize int64 `json:"maxptysize,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type RemoteFd struct {
|
type RemoteFd struct {
|
||||||
|
|||||||
+31
-3
@@ -23,6 +23,7 @@ import (
|
|||||||
"github.com/alessio/shellescape"
|
"github.com/alessio/shellescape"
|
||||||
"github.com/creack/pty"
|
"github.com/creack/pty"
|
||||||
"github.com/scripthaus-dev/mshell/pkg/base"
|
"github.com/scripthaus-dev/mshell/pkg/base"
|
||||||
|
"github.com/scripthaus-dev/mshell/pkg/cirfile"
|
||||||
"github.com/scripthaus-dev/mshell/pkg/mpio"
|
"github.com/scripthaus-dev/mshell/pkg/mpio"
|
||||||
"github.com/scripthaus-dev/mshell/pkg/packet"
|
"github.com/scripthaus-dev/mshell/pkg/packet"
|
||||||
"golang.org/x/sys/unix"
|
"golang.org/x/sys/unix"
|
||||||
@@ -35,6 +36,7 @@ const MaxCols = 1024
|
|||||||
const MaxFdNum = 1023
|
const MaxFdNum = 1023
|
||||||
const FirstExtraFilesFdNum = 3
|
const FirstExtraFilesFdNum = 3
|
||||||
const DefaultTermType = "xterm-256color"
|
const DefaultTermType = "xterm-256color"
|
||||||
|
const DefaultMaxPtySize = 1024 * 1024
|
||||||
|
|
||||||
const ClientCommand = `
|
const ClientCommand = `
|
||||||
PATH=$PATH:~/.mshell;
|
PATH=$PATH:~/.mshell;
|
||||||
@@ -67,6 +69,7 @@ type ShExecType struct {
|
|||||||
FileNames *base.CommandFileNames
|
FileNames *base.CommandFileNames
|
||||||
Cmd *exec.Cmd
|
Cmd *exec.Cmd
|
||||||
CmdPty *os.File
|
CmdPty *os.File
|
||||||
|
MaxPtySize int64
|
||||||
Multiplexer *mpio.Multiplexer
|
Multiplexer *mpio.Multiplexer
|
||||||
Detached bool
|
Detached bool
|
||||||
DetachedOutput *packet.PacketSender
|
DetachedOutput *packet.PacketSender
|
||||||
@@ -933,6 +936,26 @@ func SetupSignalsForDetach() {
|
|||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func copyToCirFile(dest *cirfile.File, src io.Reader) error {
|
||||||
|
buf := make([]byte, 64*1024)
|
||||||
|
for {
|
||||||
|
var appendErr error
|
||||||
|
nr, readErr := src.Read(buf)
|
||||||
|
if nr > 0 {
|
||||||
|
appendErr = dest.AppendData(context.Background(), buf[0:nr])
|
||||||
|
}
|
||||||
|
if readErr != nil && readErr != io.EOF {
|
||||||
|
return readErr
|
||||||
|
}
|
||||||
|
if appendErr != nil {
|
||||||
|
return appendErr
|
||||||
|
}
|
||||||
|
if readErr == io.EOF {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (cmd *ShExecType) DetachedWait(startPacket *packet.CmdStartPacketType) {
|
func (cmd *ShExecType) DetachedWait(startPacket *packet.CmdStartPacketType) {
|
||||||
// after Start(), any output/errors must go to DetachedOutput
|
// after Start(), any output/errors must go to DetachedOutput
|
||||||
// close stdin, redirect stdout/stderr to /dev/null, but wait for cmdstart packet to get sent
|
// close stdin, redirect stdout/stderr to /dev/null, but wait for cmdstart packet to get sent
|
||||||
@@ -949,7 +972,7 @@ func (cmd *ShExecType) DetachedWait(startPacket *packet.CmdStartPacketType) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
cmd.DetachedOutput.SendCmdError(cmd.CK, fmt.Errorf("cannot dup2 stdin to runout: %w", err))
|
cmd.DetachedOutput.SendCmdError(cmd.CK, fmt.Errorf("cannot dup2 stdin to runout: %w", err))
|
||||||
}
|
}
|
||||||
ptyOutFd, err := os.OpenFile(cmd.FileNames.PtyOutFile, os.O_TRUNC|os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0600)
|
ptyOutFile, err := cirfile.CreateCirFile(cmd.FileNames.PtyOutFile, cmd.MaxPtySize)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
cmd.DetachedOutput.SendCmdError(cmd.CK, fmt.Errorf("cannot open ptyout file '%s': %w", cmd.FileNames.PtyOutFile, err))
|
cmd.DetachedOutput.SendCmdError(cmd.CK, fmt.Errorf("cannot open ptyout file '%s': %w", cmd.FileNames.PtyOutFile, err))
|
||||||
// don't return (command is already running)
|
// don't return (command is already running)
|
||||||
@@ -958,8 +981,8 @@ func (cmd *ShExecType) DetachedWait(startPacket *packet.CmdStartPacketType) {
|
|||||||
go func() {
|
go func() {
|
||||||
// copy pty output to .ptyout file
|
// copy pty output to .ptyout file
|
||||||
defer close(ptyCopyDone)
|
defer close(ptyCopyDone)
|
||||||
defer ptyOutFd.Close()
|
defer ptyOutFile.Close()
|
||||||
_, copyErr := io.Copy(ptyOutFd, cmd.CmdPty)
|
copyErr := copyToCirFile(ptyOutFile, cmd.CmdPty)
|
||||||
if copyErr != nil {
|
if copyErr != nil {
|
||||||
cmd.DetachedOutput.SendCmdError(cmd.CK, fmt.Errorf("copying pty output to ptyout file: %w", copyErr))
|
cmd.DetachedOutput.SendCmdError(cmd.CK, fmt.Errorf("copying pty output to ptyout file: %w", copyErr))
|
||||||
}
|
}
|
||||||
@@ -1002,6 +1025,11 @@ func RunCommandDetached(pk *packet.RunPacketType, sender *packet.PacketSender) (
|
|||||||
cmd.FileNames = fileNames
|
cmd.FileNames = fileNames
|
||||||
cmd.CmdPty = cmdPty
|
cmd.CmdPty = cmdPty
|
||||||
cmd.Detached = true
|
cmd.Detached = true
|
||||||
|
if pk.TermOpts != nil && pk.TermOpts.MaxPtySize != 0 {
|
||||||
|
cmd.MaxPtySize = pk.TermOpts.MaxPtySize
|
||||||
|
} else {
|
||||||
|
cmd.MaxPtySize = DefaultMaxPtySize
|
||||||
|
}
|
||||||
cmd.RunnerOutFd, err = os.OpenFile(fileNames.RunnerOutFile, os.O_TRUNC|os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0600)
|
cmd.RunnerOutFd, err = os.OpenFile(fileNames.RunnerOutFile, os.O_TRUNC|os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0600)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, fmt.Errorf("cannot open runout file '%s': %w", fileNames.RunnerOutFile, err)
|
return nil, nil, fmt.Errorf("cannot open runout file '%s': %w", fileNames.RunnerOutFile, err)
|
||||||
|
|||||||
Reference in New Issue
Block a user