Killing a command tree

Hi there!

I currently have a problem with a program of mine where I spawn a sh -c "<...>" command.

Basically I want to be able to run this command asynchronously and kill it in specific conditions. So I create a Command that I .spawn() and store the Child handle somewhere in the application's state.

But when I call .kill() on it, nothing happens. If I get the child's ID and kill it with my shell's kill command then it stops.

This is the first problem, but I have another: even when manually killing the shell process, the underlying command isn't killed. So for instance, if I spawn a Command with sh -c "sleep 100" and I kill the sh process, the sleep command keeps running. How can I avoid that and kill both at the same time?

Thanks in advance for your help!

Kill the "process group". In Unix you have process groups. Typically, when you have a sh -c <command>, then the <command> and the sh should be in the same process group. You kill a process group by sending the negative of the PGID. Thus if the PGID is 100, then you should do kill -s SIGTERM -100.

This happens because the way shells work. When a shell spawns a child (in this case the <command> the sh is spawning), it makes the child the foreground process. Thus sending SIGTERM signals to the parent process (which is the shell, and now is a background process) will not help. You need to send the signal to the child process.

1 Like

Interesting!

So there's no "native Rust" way of doing that? I need to deal with the system's signals myself?

Also, is it guaranteed that (on unix systems at least) the child's .id() will return me the PID to kill?

There is. If you directly spawn the <command> without going through the sh, then this problem won't arise and kill behaves the way you expect it to.

1 Like

I ran some tests and the problem is that the command itself can spawn other children, which would need to be killed to.

So I finally found out that running pkill -P <child ID> solved the problem. It termines all the processes properly and is correctly reported as a failed Command in Rust.

Thanks for your help!

A quick search for "process group" on lib.rs found command-group — Rust OS-specific library // Lib.rs which seems to do what you want.

1 Like