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?
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.
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.