linuxshellexeczombie-processdefunct

why defunct process generate when call exec in shell script?


why defunct process generate when call exec in shell script?

Because some extra configure and sharelib should be set and preload before starting snmpd,

so I use shell script like bellow, but the problem is that a zombie process was generated every time when start the shell script.

as far as I know, exec will replace the original shell process 26452, why a child process 26453 generate and become zombie?

$# ps -ef | grep snmpd
root     26452 12652  0 10:24 pts/4    00:00:00 snmpd udp:161,udp6:161 -f -Ln -I -system_mib ifTable -c /opt/snmp/config/snmpd.conf
root     26453 26452  0 10:24 pts/4    00:00:00 [snmpd_wapper.sh] <defunct>

how to avoid the zombie process, pls help!

cat /home/xpeng/snmpd_wapper.sh
#!/bin/bash

 ( sleep 2;/opt/snmp/bin/snmpusm -v 3 -u myuser -l authNoPriv -a MD5 -A xpeng localhost create top myuser >/dev/null 2>&1; \
 /opt/snmp/bin/snmpvacm -v 3 -u myuser -l authNoPriv -a MD5 -A xpeng localhost createSec2Group 3 top RWGroup >/dev/null 2>&1; \
 /opt/snmp/bin/snmpvacm -v 3 -u myuser -l authNoPriv -a MD5 -A xpeng localhost createView all .1 80 >/dev/null 2>&1; \
 /opt/snmp/bin/snmpvacm -v 3 -u myuser -l authNoPriv -a MD5 -A xpeng localhost createAccess RWGroup 3 1 1 all all none >/dev/null 2>&1 ) &

 LIBRT=/usr/lib64
 if [ "$(. /etc/os-release; echo $NAME)" = "Ubuntu" ]; then
    LIBRT=/usr/lib/x86_64-linux-gnu
 fi
 echo $$>/tmp/snmpd.pid
 export LD_PRELOAD=$LD_PRELOAD:$LIBRT/librt.so:/opt/xpeng/lib/libxpengsnmp.so
 exec -a "snmpd" /opt/snmp/sbin/snmpd udp:161,udp6:161 -f -Ln -I -system_mib,ifTable -c /opt/snmp/config/snmpd.conf

Solution

  • It's a parent process' responsibility to wait for any child processes. The child process will be a zombie from the time it dies until the parent waits for it.

    You started a child process, but then you used exec to replace the parent process. The new program doesn't know that it has children, so it doesn't wait. The child therefore becomes a zombie until the parent process dies.

    Here's a MCVE:

    #!/bin/sh
    sleep 1 &      # This process will become a zombie
    exec sleep 30  # Because this executable won't `wait`
    

    You can instead do a double fork:

    #!/bin/sh
    (             # Start a child shell
      sleep 1 &   # Start a grandchild process
    )             # Child shell dies, grandchild is given to `init`
    exec sleep 30 # This process now has no direct children