Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a shell script equivalent of prctl (PR_SET_PDEATHSIG, SIGKILL) for handling zombie children?

Tags:

bash

sh

C and C++, I've been using prctl(PR_SET_PDEATHSIG, SIGKILL); and it works great.When I spawn child processes in shell scripts I use something like this:

    pid=$!
    
    trap "kill $pid" SIGHUP SIGINT SIGTERM
    
    wait

Which works in all cases except when the shell script gets a SIGKILL (which it can't catch). Then I end up with the children of the shell script being zombies.

Is there a way for shell scripts to have SIGKILL passed on to their children?

I'm pretty open to what shell this would apply to but ideally it'd be bash or sh.

UPDATE

So based on the comment below I'm gonna provide some background and see if perhaps I should be using a different approach entirely. Our setup is structured roughly along these lines:

+ systemd
 + a_c_process
   + a_c_process
   + a_c_process
     + a_leaf_c_process
   + shellscriptA
     + a_leaf_c_process
     + a_leaf_c_process

So while SIGTERM can be our starting signal (e.g. any non leaf c process could send SIGTERM to all its children when it received a SIGTERM), but if a process in the tree doesn't handle SIGTERM properly my understanding is I should expect systemd to deliver a SIGKILL. We've been using PR_SET_PDEATHSIG to ensure the entire process tree is cleared of zombies.

From what I can see this technique should be able to co-exist with SIGTERM handling. That is, I can install SIGTERM handlers, but also have PR_SET_DEATHSIG as a fallback if those handlers fail.

like image 603
mpr Avatar asked Jul 24 '18 15:07

mpr


1 Answers

As noted everywhere, Bash won't allow trapping of KILL, but you can spawn another process to monitor for that. There are several things you can do, such as a watchdog, but I like a solution based on this Unix & Linux answer which uses strace to monitor the parent process:

#!/bin/bash

function handlekill() {
        echo "I was KILLed!"
}

curpid=$$
( strace -p $curpid -e 'trace=!all' 2>&1 | grep -q SIGKILL && handlekill )&

sleep 60
echo done

If you then kill -9 that process, you'd get the output "I was KILLed!". The rest is just wiring.

Caveats:

  • Need strace installed.
  • Won't work on modern Linuxes unless the Kernel's YAMA ptrace_scope is disabled or you only run the script as root.
like image 91
Guss Avatar answered Nov 15 '22 08:11

Guss