site  contact  subhomenews

Detach child process from parent

September 08, 2020 — BarryK

EasyOS uses the traditional Puppy Linux method of launching the tray applets, such as the volume control, NetworkManager applet and CPU-temperature applet. These applets are found in /root/Startup and are executed by /usr/sbin/delayedrun, which in turn is launched from /root/.xinitrc when Xorg starts.

I think that this method is still supported in Puppy, but deprecated in favour of the applets being in /etc/xdg/autostart and /root/.config/autostart.

/usr/sbin/delayedrun has this code near the end of the script:

if [ -d /root/Startup ];then
for a in /root/Startup/*
do
[ -x "$a" ] && $a &
sleep 0.2
done
fi

This is OK, except over the years it has bothered me that 'ps' shows 'delayedrun' as still running, after it has finished. Executing 'pstree' shows the situation, here is part of the output:

     |-delayedrun---blueman-applet-+-{dconf worker}
| |-{gdbus}
| |-{gmain}
| `-{python3:disk$0}
|-delayedrun---yad
|-delayedrun---freememapplet_t
|-delayedrun---nm-applet-+-{dconf worker}
| |-{gdbus}
| `-{gmain}
|-delayedrun---pmcputemp
|-delayedrun---pnmixer

Those applets are children of 'delayedrun', so 'delayedrun' is still shown as "running". There is nothing wrong with that, but aesthetically it would seem nice if 'delayedrun' could be completely dismissed.

After an Internet search, I implemented this in delayedrun:

if [ -d /root/Startup ];then
for a in /root/Startup/*
do
if [ -x "$a" ];then
disown -h $! #note, -h will disable forwarding SIGHUP.
fi
sleep 0.2
done
fi

Now, 'pstree' shows that 'delayedrun' has gone, each applet is a child of 'init', for example:

     |-blueman-applet-+-{dconf worker}
| |-{gdbus}
| |-{gmain}
| `-{python3:disk$0}

The applets still work, terminate and startup as expected. The "-h" doesn't seem to do anything, works just as well without it.

The problem is that 'disown' is a bash builtin, not available in busybox ash, nor even with /bin/sh if it is symlinked to bash. However, I found that this works the same:

if [ -d /root/Startup ];then
for a in /root/Startup/*
do
if [ -x "$a" ];then
setsid --fork $a
fi
sleep 0.2
done
fi

I wrote about 'setsid' recently, used in the 'initrd':

https://bkhome.org/news/202008/fix-for-devtty-in-initrd.html

'setsid' is a busybox utility, also in 'util-linux' package.

I will implement the 'setsid' method in 'delayedrun'. Not that it really needs to be done, just, as I stated, aesthetically pleasing. 

Here are some relevant discussions:

https://unix.stackexchange.com/questions/269805/how-can-i-detach-a-process-from-a-bash-script

https://superuser.com/questions/178587/how-do-i-detach-a-process-from-terminal-entirely

...though, I don't want to detach from the controlling terminal, just from the parent script. If anyone knows of a potential downside to doing this, let me know!

EDIT 2020-09-09:
James (jamesbond in the forums) sent me an email, quoting:

The solution is quite simple, no setsid or bash hackery needed.

Instead of the original code

if [ -d /root/Startup ];then
 for a in /root/Startup/*
 do
  [ -x "$a" ] && $a &
  sleep 0.2
 done
fi

Do it like this:

if [ -d /root/Startup ];then
 for a in /root/Startup/*
 do
  if [ -x "$a" ]; then
     $a &
     sleep 0.2
  fi
 done
fi

Changing the short form to proper if/then block is what fixes it.

Gosh, that works! My understanding has always been that there is no underlying difference between the two forms. Which seems to be the general understanding, for example this discussion:

https://unix.stackexchange.com/questions/472137/whats-the-difference-between-using-if-condition-then-and-just-condition

I'm astonished. Thanks James!   



 

Tags: easy