0

I'd like to set the parent of a newly started process, is that possible?

Example, let us assume that we start a new desktop environment session via a login manager, so our process tree would look something like this:

init
 \- login-manager
     \- de-session

Now I do have a script to launch my most essential applications which should start with the session, for various reasons I'd like to keep these as a script and not migrate them to the autostart manager of any DE. It looks something like this:

#!/usr/bin/env

application1 &
application2 &
application3 &

After running this automatically at the start of the session, our process tree looks like this:

init
 |- application1
 |- application2
 |- application3
 \- login-manager
     \- de-session

But what I'd actually like is to "reparent" these processes under the session, like this:

init
 \- login-manager
     \- de-session
         |- application1
         |- application2
         \- application3

So, is there any way to "reparent" a process under another one?

2

On a few systems, you can mark a process as a child subreaper, which makes it take init's role of adopting orphan processes for all its descendants.

On Linux, that's done with the PR_SET_CHILD_SUBREAPER prctl().

So, you could start your de-session as (here hardcoding the value of PR_SET_CHILD_SUBREAPER for Linux):

perl -e 'require "syscall.ph";
         syscall(&SYS_prctl,36,1) >= 0 or die "cannot set subreaper: $!";
         exec("de-session");'

But de-session might get confused when it receives SIGCHLD signals for processes it has never spawned. Your init has been designed to deal with those, but probably not your de-session, so you may find that you get an army of zombies as de-session never acknowledges the death of those processes it never wanted to inherit.

2

I actually did this with TrueOS (formerly known as PC-BSD) just under a year ago.

vanilla TrueOS

On vanilla TrueOS, the pcdm service runs the graphical user interface.

  • The Mewburn rc system runs the /usr/local/etc/rc.d/pcdm script, which is not long-lived.
  • An infinitely-looping and quite convoluted shell script named PCDMd spawns xinit telling it to run a program named PCDM-session.
  • PCDM-session is a desktop chooser and login program that writes out a nonce shell script in /tmp. It spawns /usr/local/share/PCDM/pcdm-session. It also spins off and orphans a dbus-daemon, run as the superuser, on the side if it isn't passed information about a Desktop Bus to talk to.
  • /usr/local/share/PCDM/pcdm-session chains to sh /tmp/PCDM-session.blah, the script written out earlier.
  • Said shell script in its turn runs everything in $HOME/.xprofile, which is where all of the things such as gpg-agent are forked off, and finally runs the chosen desktop's session via dbus-launch (run as the logged-in user and spinning off another dbus-daemon process).

This results in a fairly messy process tree, both for anything forked off by $HOME/.xprofile (which runs everything from /usr/local/share/pcbsd/xstartup/) and for anything started under the desktop session process and later orphaned via fork-and-exit-parent (like, alas, thunderbird). All of the D-Bus brokers are not pretty, either; a lot of stuff ends up with process #1 as its parent process ID. The naming does not help make this straighforward, either. pcdm invokes PCDMd invokes PCDM-session invokes pcdm-session invokes PCDM-session.blah.

(I tried to let the TrueOS people know that this was unnecessarily complex, especially the wholly unnecessary hidden extra, and broken, service manager inside the PCDM-session program that I have left out of the above description.)

local-reaper and userenv from the nosh toolset

In the nosh toolset there is a little chain-loading utility named local-reaper. Its sole task is to mark (or un-mark) itself as a subreaper and then chain-load another program image in the same process.

There's nothing Linux-specific about it, the subreaper mechanism being available on several operating systems. It works on Linux and FreeBSD/TrueOS/DragonFlySBD, and has no hard-wired system call numbers or anything of that sort. ☺

Also in the nosh tool set are the userenv and setuidgid tools. These actually do everything that the TrueOS pcdm-session program does, and more besides, including setting up the DBUS_SESSION_BUS_ADDRESS variable to point to the per-user Desktop Bus broker. The entire TrueOS pcdm-session program is in fact replaceable with

#!/bin/sh -
exec >>"$5" 2>&1 
chown -v -h -- "$1" "${XAUTHORITY}"
exec \
local-reaper true \
setuidgid --supplementary "$1" \
userenv --set-path --set-other --set-tools --set-timezone --set-locale --set-xdg \
sh "$4"

putting local-reaper to use

To use it, I had to find processes that satisfied three conditions:

  • They had to be an indirect parent of the processes that were getting orphaned.
  • They had to be long-lived.
  • They had to be amenable to suddenly gaining child processes that they weren't expecting.

Not all processes were suitable. I actually uncovered a bug in the TrueOS PCDM-session program, where it was waiting for the wrong process ID, whilst diagnosing whether the PCDM-session process was suitable to be a subreaper.

(I told the TrueOS people about this bug, too. It's actually a one character typing error.)

Fortunately, shell programs almost always are suitable to be reapers, and there were several shell processes in this tree. So also, it turned out, was xinit.

improved process tree

So what happens now is;

  • I run things under a proper service manager. The server manager process is itself a subreaper.
  • Service management spawns a significantly shorter shell script that spawns local-reaper true xinit …, making the xinit process a subreaper too.
  • xinit is told to run local-reaper true helper-script, making the shell interpreter that interprets helper-script a third subreaper.
  • helper-script runs dbus-launch --exit-with-session PCDM-session. It sticks around, running a shell interpreter, waiting for the PCDM-session process to finish. dbus-launch spins off two side-processes that it orphans.
  • PCDM-session cannot be made a subreaper. Its behaviour is unchanged: it writes out a nonce shell script in /tmp and spawns /usr/local/share/PCDM/pcdm-session. But the spinning off of the Desktop Bus side-processed has already been done for it.
  • The revised /usr/local/share/PCDM/pcdm-session marks itself as a subreaper and chains to sh /tmp/PCDM-session.blah, the script written out earlier.
  • Said shell script in its turn still runs everything in $HOME/.xprofile and thus everything in /usr/local/share/pcbsd/xstartup/, and finally runs the chosen desktop's session, but directly and no longer via dbus-launch. It sticks around, running a shell interpreter, waiting for the desktop's session process to finish.

The effects of this are as follows:

  • Stuff forked off from any of the scripts in /usr/local/share/pcbsd/xstartup/ is reparented to the process running sh /tmp/PCDM-session.blah.
  • Desktop applications such as thunderbird that are run via fork-and-exit-parent as grandchildren of the desktop session process are reparented to the process running sh /tmp/PCDM-session.blah.
  • The side processes forked off and orphaned by dbus-launch are re-parented to the helper-script process.
  • There is no user dbus-daemon side process forked off; as everything is pointed to a per-user Desktop Bus broker that is running in another part of the process tree, as a user-level service under proper service management.
  • Nothing gets as far as being reparented to xinit. Making it a subreaper turned out to be unnecessary.

The process tree, starting from process #1, looks like this:

/sbin/system-manager --
|-- cyclog --max-file-size 262144 --max-total-size 1048576 . (system-manager)
`-- service-manager (system-manager)
  …
  |-- per-user-manager
  | |-- cyclog --max-file-size 262144 --max-total-size 1048576 .
  | `-- service-manager
  |   |-- cyclog JdeBP/socket-servers/
  |   |-- cyclog JdeBP/dbus-servers/
  |   |-- dbus-daemon --config-file ./per-user.conf --nofork --address=unix:path=/run/user/JdeBP//bus
  …
  |-- /bin/sh - ./helper run
   `-- xinit /bin/exec local-reaper true ./helper session -- :0 -auth -retro
     |-- X :0 -auth -retro (Xorg)
     `-- /bin/sh - ./helper session
       |-- PCDM-session -once
       | `-- PCDM-session -once
       |   `-- sh /tmp/PCDM-session.ca1015
       |     |-- /usr/local/bin/gpg-agent …
       |     | `-- scdaemon --multi-server
       |     |-- /usr/local/bin/lxsession -s LXDE
       |     | |-- openbox --config-file …
       |     | |-- lxpanel --profile LXDE
       |     | |-- pcmanfm --desktop --profile LXDE
       |     | `-- xscreensaver -no-splash
       |     |-- /usr/local/bin/python2.7 /usr/local/share/system-config-printer/applet.py
       |     |-- life-preserver-tray
       |     |-- /usr/local/bin/pc-systemupdatertray
       |     |-- zeitgeist-datahub
       |     |-- pc-mixer
       |     |-- pc-mounttray
       |     |-- /usr/local/libexec/menu-cache/menu-cached …
       |     `-- thunderbird
       |-- dbus-launch --exit-with-session PCDM-session -once
       `-- /usr/local/bin/dbus-daemon --fork … --session

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.