Is reparenting from the shell possible?

This question is closely related to How to "correctly" start an application from a shell but tries to tackle a more specific problem. How can I spawn an application from a shell and thereby making it a child of another process. Here is what I mean exemplified with two graphics:

systemd-+-acpid
        |-bash---chromium-+-chrome-sandbox---chromium-+-chrome-sandbox---nacl_helper
        |                 |                           `-chromium---5*[chromium-+-{Chrome_ChildIOT}]
        |                 |                                                    |-{Compositor}]
        |                 |                                                    |-{HTMLParserThrea}]
        |                 |                                                    |-{OptimizingCompi}]
        |                 |                                                    `-3*[{v8:SweeperThrea}]]
        |                 |-chromium
        |                 |-chromium-+-chromium
        |                 |          |-{Chrome_ChildIOT}
        |                 |          `-{Watchdog}
        |                 |-{AudioThread}
        |                 |-3*[{BrowserBlocking}]
        |                 |-{BrowserWatchdog}
        |                 |-5*[{CachePoolWorker}]
        |                 |-{Chrome_CacheThr}
        |                 |-{Chrome_DBThread}
        |                 |-{Chrome_FileThre}
        |                 |-{Chrome_FileUser}
        |                 |-{Chrome_HistoryT}
        |                 |-{Chrome_IOThread}
        |                 |-{Chrome_ProcessL}
        |                 |-{Chrome_SafeBrow}
        |                 |-{CrShutdownDetec}
        |                 |-{IndexedDB}
        |                 |-{LevelDBEnv}
        |                 |-{NSS SSL ThreadW}
        |                 |-{NetworkChangeNo}
        |                 |-2*[{Proxy resolver}]
        |                 |-{WorkerPool/1201}
        |                 |-{WorkerPool/2059}
        |                 |-{WorkerPool/2579}
        |                 |-{WorkerPool/2590}
        |                 |-{WorkerPool/2592}
        |                 |-{WorkerPool/2608}
        |                 |-{WorkerPool/2973}
        |                 |-{WorkerPool/2974}
        |                 |-{chromium}
        |                 |-{extension_crash}
        |                 |-{gpu-process_cra}
        |                 |-{handle-watcher-}
        |                 |-{inotify_reader}
        |                 |-{ppapi_crash_upl}
        |                 `-{renderer_crash_}
        |-2*[dbus-daemon]
        |-dbus-launch
        |-dhcpcd
        |-firefox-+-4*[{Analysis Helper}]
        |         |-{Cache I/O}
        |         |-{Cache2 I/O}
        |         |-{Cert Verify}
        |         |-3*[{DOM Worker}]
        |         |-{Gecko_IOThread}
        |         |-{HTML5 Parser}
        |         |-{Hang Monitor}
        |         |-{Image Scaler}
        |         |-{JS GC Helper}
        |         |-{JS Watchdog}
        |         |-{Proxy R~olution}
        |         |-{Socket Thread}
        |         |-{Timer}
        |         |-{URL Classifier}
        |         |-{gmain}
        |         |-{localStorage DB}
        |         |-{mozStorage #1}
        |         |-{mozStorage #2}
        |         |-{mozStorage #3}
        |         |-{mozStorage #4}
        |         `-{mozStorage #5}
        |-gpg-agent
        |-login---bash---startx---xinit-+-Xorg.bin-+-xf86-video-inte
        |                               |          `-{Xorg.bin}
        |                               `-dwm-+-dwmstatus
        |                                     `-xterm---bash-+-bash
        |                                                    `-pstree
        |-systemd---(sd-pam)
        |-systemd-journal
        |-systemd-logind
        |-systemd-udevd
        |-wpa_actiond
        `-wpa_supplicant

The process tree shows chromium and firefox as children of the init process that starts at boot and has PID 1. But what I want to achieve is to start firefox and chromium as children of dwm. Hence, I want a similar behaviour to what you can see under the weston part of the following process tree where firefox has weston-desktop as its parent:

systemd-+-acpid
        |-bash---chromium-+-chrome-sandbox---chromium-+-chrome-sandbox---nacl_helper
        |                 |                           `-chromium-+-3*[chromium-+-{Chrome_ChildIOT}]
        |                 |                                      |             |-{Compositor}]
        |                 |                                      |             |-{HTMLParserThrea}]
        |                 |                                      |             |-{OptimizingCompi}]
        |                 |                                      |             `-3*[{v8:SweeperThrea}]]
        |                 |                                      `-4*[chromium-+-{Chrome_ChildIOT}]
        |                 |                                                    |-{CompositorRaste}]
        |                 |                                                    |-{Compositor}]
        |                 |                                                    |-{HTMLParserThrea}]
        |                 |                                                    |-{OptimizingCompi}]
        |                 |                                                    `-3*[{v8:SweeperThrea}]]
        |                 |-{AudioThread}
        |                 |-3*[{BrowserBlocking}]
        |                 |-{BrowserWatchdog}
        |                 |-5*[{CachePoolWorker}]
        |                 |-{Chrome_CacheThr}
        |                 |-{Chrome_DBThread}
        |                 |-{Chrome_FileThre}
        |                 |-{Chrome_FileUser}
        |                 |-{Chrome_HistoryT}
        |                 |-{Chrome_IOThread}
        |                 |-{Chrome_ProcessL}
        |                 |-{Chrome_SafeBrow}
        |                 |-{Chrome_SyncThre}
        |                 |-{CrShutdownDetec}
        |                 |-{IndexedDB}
        |                 |-{NSS SSL ThreadW}
        |                 |-{NetworkChangeNo}
        |                 |-2*[{Proxy resolver}]
        |                 |-{WorkerPool/2315}
        |                 |-{WorkerPool/2316}
        |                 |-{WorkerPool/2481}
        |                 |-{chromium}
        |                 |-{extension_crash}
        |                 |-{gpu-process_cra}
        |                 |-{handle-watcher-}
        |                 |-{inotify_reader}
        |                 |-{renderer_crash_}
        |                 `-{sandbox_ipc_thr}
        |-2*[dbus-daemon]
        |-dbus-launch
        |-dhcpcd
        |-gpg-agent
        |-login---bash---startx---xinit-+-Xorg.bin-+-xf86-video-inte
        |                               |          `-{Xorg.bin}
        |                               `-dwm-+-dwmstatus
        |                                     `-xterm---bash
        |-login---bash---weston-launch---weston-+-Xwayland---4*[{Xwayland}]
        |                                       |-weston-desktop--+-firefox-+-firefox
        |                                       |                 |         |-4*[{Analysis Helper}]
        |                                       |                 |         |-{Cache2 I/O}
        |                                       |                 |         |-{Cert Verify}
        |                                       |                 |         |-{DNS Resolver #1}
        |                                       |                 |         |-{DNS Resolver #2}
        |                                       |                 |         |-2*[{DOM Worker}]
        |                                       |                 |         |-{Gecko_IOThread}
        |                                       |                 |         |-{HTML5 Parser}
        |                                       |                 |         |-{Hang Monitor}
        |                                       |                 |         |-{Image Scaler}
        |                                       |                 |         |-{ImageDecoder #1}
        |                                       |                 |         |-{ImageDecoder #2}
        |                                       |                 |         |-{ImageDecoder #3}
        |                                       |                 |         |-{JS GC Helper}
        |                                       |                 |         |-{JS Watchdog}
        |                                       |                 |         |-{Socket Thread}
        |                                       |                 |         |-{Timer}
        |                                       |                 |         |-{URL Classifier}
        |                                       |                 |         |-{gmain}
        |                                       |                 |         |-{localStorage DB}
        |                                       |                 |         |-{mozStorage #1}
        |                                       |                 |         |-{mozStorage #2}
        |                                       |                 |         |-{mozStorage #3}
        |                                       |                 |         |-{mozStorage #4}
        |                                       |                 |         `-{mozStorage #5}
        |                                       |                 `-weston-terminal---bash---pstree
        |                                       `-weston-keyboard
        |-systemd---(sd-pam)
        |-systemd-journal
        |-systemd-logind
        |-systemd-udevd
        |-tmux---bash
        |-wpa_actiond
        `-wpa_supplicant

One possible solution would be to use nsenter from util-linux. I could enter the namespace of the dwm process and fork a new firefox process which would then be the child of dwm. However, that seems like a lot of work. Is there some easier way to do this?

Asked By: lord.garbage

||

You can not start a process as the child of the shell, and then “reparent” it so another process becomes it’s parent.

So you need to use a parent process that explicitly starts the children.

init with PID 1 is an exception, processes can become it’s child as it collects processes that lost their original parent process.

(With upstart, there can be multiple init processes, they do not share the PID 1, but otherwise the roles are very similar.)
(See also PR_SET_CHILD_SUBREAPER in man 2 prctl)

Answered By: Volker Siegel

What you ask for is simply impossible. By the design of the Unix and Linux internal process management init becomes the parent of all processes whose parents die. This is because processes must have parents (also by design), and init is always there, for if init dies, the system shuts down. But beyond that there is no such thing as “re-parenting” processes.

EDIT

However: As lord.garbage pointed out, there’s the arcane prctl() system call which is wicked cool and makes any program that uses it unportable. Suppose we don’t care. Using the PR_SET_CHILD_SUBREAPER option it can wait() not only for its own children (as before) but also for all of their descendants, should their parents die prematurely. Thus a process using this feature can assume the role of init for its descendants. The following code is a proof of concept:

#include        <sys/prctl.h>
#include        <sys/wait.h>
#include        <unistd.h>
#include        <stdio.h>

int
main (int argc, const char* const argv[], char* const envp[])
{
        pid_t   pid;

        if (prctl(PR_SET_CHILD_SUBREAPER, 1, 0, 0, 0) < 0) {
                perror("prctl");
                return 4;
        }
        pid = fork();
        if (pid < 0) {
                perror("fork");
                return 4;
        }
        if (pid == 0) {
                // child
                char* const argv[] = { "/usr/bin/konsole", "-e", "/bin/bash", NULL };
                if (execve("/usr/bin/konsole", argv, envp) < 0) {
                        perror("execve");
                }
        }

        // parent
        while (1) {
                pid_t   wpid;
                int     s;

                wpid = waitpid(-1, &s, 0);
                if (wpid > 0) {
                        printf("child with pid %u has exitedn", wpid);
                }
        }

        return 0;
}

Run some programs in the background that does not need shell attendance, exit konsole, run ps, exit the programs, and see what happens. Replace konsole by anything your heart desires.

Now, in order to achieve what you want, use the prctl() call as in the PoC and then execve() to dwm. And hope that dwm wait()s for unspecific children lest they end up as zombies.

Final note: There’s still no such thing as re-parenting. I.e. you still cannot arbitrarily assign a parent to a process.

Answered By: countermode

I do not believe you can send a process to the dwm process as parent. But if you could start a screen or shell as a child process of dwm, then you could reparent your desired processes into that. See this link for details: http://monkeypatch.me/blog/move-a-running-process-to-a-new-screen-shell.html

Answered By: robertoldham

With reptyr, you can reparent a running program to a new terminal. Here is a longer explanation how it works.

Answered By: Albert
Categories: Answers Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.