go-cmd / cmd

Non-blocking external commands in Go with streaming output
MIT License
918 stars 128 forks source link

wrong description of Status for receiving a signal of interrupt #100

Closed FLAGLORD closed 3 months ago

FLAGLORD commented 11 months ago

https://github.com/go-cmd/cmd/blob/500562c204744af1802ae24316a7e0bf88dcc545/cmd.go#L108-L134 Its description mentions that Complete should be false and Error should not be nil if signaled. But if the underlying cmd receives a os.Interrupt signal, the returned status will have a true value in Complete and a nil value in Error

Reproduce:

test script count_sec.sh

#!/bin/sh

exit_fn () {
    # https://unix.stackexchange.com/questions/447229/how-can-we-set-up-a-signal-trap-to-be-sig-ign-and-sig-dfl-in-bash
    trap - INT              # Restore signal handling for SIGINT
    echo; echo 'Catch it! Interrupt!'    # Growl at user,
    # Mock
    # https://unix.stackexchange.com/a/99117
    exit 130                    # then exit script.
}

trap "exit_fn" INT   # Set up SIGINT trap to call function.

count=0
while [ "$1" -ne "$count" ]
do
    sleep 1
    count=$((count + 1))
    echo $count
done

trap - INT  # Restore signal handling to previous before exit.

main function:

cmd := cmd.NewCmd("sh", "count_sec.sh", "5")

time.AfterFunc(time.Second*2, func() {
    p, err := os.FindProcess(cmd.Status().PID)
    if err != nil {
        fmt.Println(err)
        return
    }
    err = p.Signal(os.Interrupt)
    if err != nil {
        fmt.Println(err)
        return
    }
})
status := <-cmd.Start()
fmt.Println(status.Stdout)
fmt.Println(status.Complete)
fmt.Println(status.Error)
daniel-nichter commented 3 months ago

Thanks for the report. I'll look into it.

daniel-nichter commented 3 months ago

Ah, SIGINT: it doesn't terminate a problem, just interrupts it. https://www.gnu.org/software/bash/manual/html_node/Signals.html

In this case, the shell script above catches that and ends the program. So the go-cmd result is correct: no error, no (handled) signal, completed, and exit status = 130.

The docs mention,

but was terminated unexpectedly (probably signaled)

The subtleness there is "unexpectedly". Catching SIGINT and terminating is not unexpected. (For example, the program could catch and keep running, instead.)

I added https://github.com/go-cmd/cmd/commit/0986371b94ede55e7b15935095bf7c60c15b50c7 to address this for future users.