Detach child process from parent
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
$a &
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:
I'm astonished. Thanks James!
Tags: easy