From 128f2d3e20c5740e8375c5a9cd5944669034f845 Mon Sep 17 00:00:00 2001 From: Alessandro Ros Date: Sat, 27 May 2023 19:28:07 +0200 Subject: [PATCH] print error that caused an external command to exit (#1869) --- internal/core/path.go | 12 ++++---- internal/core/rtmp_conn.go | 8 +++--- internal/core/rtsp_conn.go | 4 +-- internal/core/rtsp_session.go | 4 +-- internal/externalcmd/cmd.go | 47 ++++++++++++++------------------ internal/externalcmd/cmd_unix.go | 11 ++++---- internal/externalcmd/cmd_win.go | 11 ++++---- 7 files changed, 47 insertions(+), 50 deletions(-) diff --git a/internal/core/path.go b/internal/core/path.go index 2de00f0a..948276c4 100644 --- a/internal/core/path.go +++ b/internal/core/path.go @@ -333,8 +333,8 @@ func (pa *path) run() { pa.conf.RunOnInit, pa.conf.RunOnInitRestart, pa.externalCmdEnv(), - func(co int) { - pa.Log(logger.Info, "runOnInit command exited with code %d", co) + func(err error) { + pa.Log(logger.Info, "runOnInit command exited: %v", err) }) } @@ -588,8 +588,8 @@ func (pa *path) onDemandPublisherStart() { pa.conf.RunOnDemand, pa.conf.RunOnDemandRestart, pa.externalCmdEnv(), - func(co int) { - pa.Log(logger.Info, "runOnDemand command exited with code %d", co) + func(err error) { + pa.Log(logger.Info, "runOnDemand command exited: %v", err) }) pa.onDemandPublisherReadyTimer.Stop() @@ -647,8 +647,8 @@ func (pa *path) sourceSetReady(medias media.Medias, allocateEncoder bool) error pa.conf.RunOnReady, pa.conf.RunOnReadyRestart, pa.externalCmdEnv(), - func(co int) { - pa.Log(logger.Info, "runOnReady command exited with code %d", co) + func(err error) { + pa.Log(logger.Info, "runOnReady command exited: %v", err) }) } diff --git a/internal/core/rtmp_conn.go b/internal/core/rtmp_conn.go index cc630c3f..807024ce 100644 --- a/internal/core/rtmp_conn.go +++ b/internal/core/rtmp_conn.go @@ -299,8 +299,8 @@ func (c *rtmpConn) run() { "RTSP_PATH": "", "RTSP_PORT": port, }, - func(co int) { - c.Log(logger.Info, "runOnConnect command exited with code %d", co) + func(err error) { + c.Log(logger.Info, "runOnConnect command exited: %v", err) }) defer func() { @@ -424,8 +424,8 @@ func (c *rtmpConn) runRead(ctx context.Context, u *url.URL) error { pathConf.RunOnRead, pathConf.RunOnReadRestart, res.path.externalCmdEnv(), - func(co int) { - c.Log(logger.Info, "runOnRead command exited with code %d", co) + func(err error) { + c.Log(logger.Info, "runOnRead command exited: %v", err) }) defer func() { onReadCmd.Close() diff --git a/internal/core/rtsp_conn.go b/internal/core/rtsp_conn.go index f90519af..71cd1c63 100644 --- a/internal/core/rtsp_conn.go +++ b/internal/core/rtsp_conn.go @@ -80,8 +80,8 @@ func newRTSPConn( "RTSP_PATH": "", "RTSP_PORT": port, }, - func(co int) { - c.Log(logger.Info, "runOnInit command exited with code %d", co) + func(err error) { + c.Log(logger.Info, "runOnInit command exited: %v", err) }) } diff --git a/internal/core/rtsp_session.go b/internal/core/rtsp_session.go index ad51901e..f2ce81e6 100644 --- a/internal/core/rtsp_session.go +++ b/internal/core/rtsp_session.go @@ -276,8 +276,8 @@ func (s *rtspSession) onPlay(ctx *gortsplib.ServerHandlerOnPlayCtx) (*base.Respo pathConf.RunOnRead, pathConf.RunOnReadRestart, s.path.externalCmdEnv(), - func(co int) { - s.Log(logger.Info, "runOnRead command exited with code %d", co) + func(err error) { + s.Log(logger.Info, "runOnRead command exited: %v", err) }) } diff --git a/internal/externalcmd/cmd.go b/internal/externalcmd/cmd.go index 0d4d8da4..7a50bd41 100644 --- a/internal/externalcmd/cmd.go +++ b/internal/externalcmd/cmd.go @@ -2,6 +2,7 @@ package externalcmd import ( + "errors" "strings" "time" ) @@ -10,6 +11,8 @@ const ( restartPause = 5 * time.Second ) +var errTerminated = errors.New("terminated") + // Environment is a Cmd environment. type Environment map[string]string @@ -19,7 +22,7 @@ type Cmd struct { cmdstr string restart bool env Environment - onExit func(int) + onExit func(error) // in terminate chan struct{} @@ -31,7 +34,7 @@ func NewCmd( cmdstr string, restart bool, env Environment, - onExit func(int), + onExit func(error), ) *Cmd { // replace variables in both Linux and Windows, in order to allow using the // same commands on both of them. @@ -64,30 +67,22 @@ func (e *Cmd) run() { defer e.pool.wg.Done() for { - ok := e.runInner() - if !ok { - break + err := e.runOSSpecific() + if err == errTerminated { + return + } + + e.onExit(err) + + if !e.restart { + <-e.terminate + return + } + + select { + case <-time.After(restartPause): + case <-e.terminate: + return } } } - -func (e *Cmd) runInner() bool { - c, ok := e.runOSSpecific() - if !ok { - return false - } - - e.onExit(c) - - if !e.restart { - <-e.terminate - return false - } - - select { - case <-time.After(restartPause): - return true - case <-e.terminate: - return false - } -} diff --git a/internal/externalcmd/cmd_unix.go b/internal/externalcmd/cmd_unix.go index f3691473..fb36a59e 100644 --- a/internal/externalcmd/cmd_unix.go +++ b/internal/externalcmd/cmd_unix.go @@ -4,6 +4,7 @@ package externalcmd import ( + "fmt" "os" "os/exec" "syscall" @@ -11,10 +12,10 @@ import ( "github.com/kballard/go-shellquote" ) -func (e *Cmd) runOSSpecific() (int, bool) { +func (e *Cmd) runOSSpecific() error { cmdParts, err := shellquote.Split(e.cmdstr) if err != nil { - return 0, true + return err } cmd := exec.Command(cmdParts[0], cmdParts[1:]...) @@ -29,7 +30,7 @@ func (e *Cmd) runOSSpecific() (int, bool) { err = cmd.Start() if err != nil { - return 0, true + return err } cmdDone := make(chan int) @@ -51,9 +52,9 @@ func (e *Cmd) runOSSpecific() (int, bool) { case <-e.terminate: syscall.Kill(cmd.Process.Pid, syscall.SIGINT) <-cmdDone - return 0, false + return errTerminated case c := <-cmdDone: - return c, true + return fmt.Errorf("command returned code %d", c) } } diff --git a/internal/externalcmd/cmd_win.go b/internal/externalcmd/cmd_win.go index bf3013d9..fb4d7764 100644 --- a/internal/externalcmd/cmd_win.go +++ b/internal/externalcmd/cmd_win.go @@ -4,6 +4,7 @@ package externalcmd import ( + "fmt" "os" "os/exec" "strings" @@ -12,7 +13,7 @@ import ( "github.com/kballard/go-shellquote" ) -func (e *Cmd) runOSSpecific() (int, bool) { +func (e *Cmd) runOSSpecific() error { var cmd *exec.Cmd // from Golang documentation: @@ -32,7 +33,7 @@ func (e *Cmd) runOSSpecific() (int, bool) { } else { cmdParts, err := shellquote.Split(e.cmdstr) if err != nil { - return 0, true + return err } cmd = exec.Command(cmdParts[0], cmdParts[1:]...) @@ -48,7 +49,7 @@ func (e *Cmd) runOSSpecific() (int, bool) { err := cmd.Start() if err != nil { - return 0, true + return err } cmdDone := make(chan int) @@ -72,9 +73,9 @@ func (e *Cmd) runOSSpecific() (int, bool) { // Kill() is the only supported way. cmd.Process.Kill() <-cmdDone - return 0, false + return errTerminated case c := <-cmdDone: - return c, true + return fmt.Errorf("command returned code %d", c) } }