Hi Vadim, your suggestion worked.

I was able to simplify the code a bit, but thanks to this I can remove the 
handshake while detecting immediately crashing executable. Fo the records, here 
is the code and the test:

// startAndCheck
func startAndCheck(cmd *exec.Cmd) error {
        //fmt.Println(cmd.Path)
        err := cmd.Start()
        if err != nil {
                return err
        }
        ch := make(chan error)
        go func() { ch <- cmd.Wait() }()
        select {
        case <-ch:
                return fmt.Errorf("command exited")
        case <-time.After(100 * time.Millisecond):
                return nil
        }
}

func Example_startAndCheck() {
        // err
        cmd := exec.Command("/does/not/exists")
        cmd.StdinPipe()
        cmd.StdoutPipe()
        fmt.Println(startAndCheck(cmd))
        // immediate exit
        cmd = exec.Command("/bin/true")
        cmd.StdinPipe()
        cmd.StdoutPipe()
        fmt.Println(startAndCheck(cmd))
        // immediate exit with output
        cmd = exec.Command("/bin/pwd")
        cmd.StdinPipe()
        cmd.StdoutPipe()
        fmt.Println(startAndCheck(cmd))
        // unwanted banner
        cmd = exec.Command("/usr/bin/bc")
        cmd.StdinPipe()
        cmd.StderrPipe()
        fmt.Println(startAndCheck(cmd))
        // pipe loop
        cmd = exec.Command("/bin/cat")
        cmd.StdinPipe()
        cmd.StderrPipe()
        fmt.Println(startAndCheck(cmd))
        // Output:
        // fork/exec /does/not/exists: no such file or directory
        // command exited
        // command exited
        // <nil>
        // <nil>
}



-- 
  Michele Sciabarra
  [email protected]

On Sat, Mar 10, 2018, at 9:47 PM, Vadim Raskin wrote:
> >> So, how can I check the process is actually terminated ?
> 
> Hi Michele,
> 
> what about using cmd.Wait() to check whether the process exited after you
> started a go action? It will return a non-nil in case of error, otherwise
> blocks forever waiting the process to finish. Waiting for a reasonable
> amount of time to make sure that process doesn't exit and close the /init
> call afterwards, would it cover the case you mentioned?
> 
> Just to make sure we talk about the same thing:
> 
> errorChan := chan string
> 
> cmd := exec.Command("userBinary")
> cmd.Start()
> // wait for failure to happen
> go func(){
> err := cmd.Wait()
> if(err != nil){
> errorChan <- "exited with failure"
> }
> else {
> close(errorChan)
> }
> }()
> // wait at most 10ms for an error to happen
> go func(){
> time.Sleep(10 * time.Millisecond)
> errorChan <- "happy"
> }
> runResult <- errorChan
> // further processing.
> 
> I haven't tested this code, it also needs to do some clean up of the Wait
> go routine, but hopefully the logic is clear.
> 
> regards,
> Vadim.
> 
> On Fri, Mar 9, 2018 at 3:18 PM Michele Sciabarra <[email protected]>
> wrote:
> 
> > > I would prefer it not be there, but can see the convenience of detecting
> > > that an app has immediately crashed. If we can find another way to do
> > > that via process inspection, that would be better in my view.
> > >
> > The problem can be summarised into this code:
> >
> >         // this command exits
> >         cmd := exec.Command("true")
> >         out, err := cmd.StdoutPipe()
> >
> >         err = cmd.Start()
> >         fmt.Println(err)
> >        // this is nil! no error!
> >
> >         // even worse! attempted to detect
> >         err = cmd.Process.Signal(syscall.Signal(0))
> >         // this is nil too! no error!
> >         fmt.Println(err)
> >
> > So, how can I check the process is actually terminated ?
> >

Reply via email to