0

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?

  • If you launch firefox from a dwm keybind (using the spawn function), it will parent the process... – jasonwryan Aug 27 '14 at 9:07
  • Basically I would like to do this for every application. Hence, this would involve setting keybinds for every relevant application in dwm's config.h. I'd prefer to avoid this. – lord.garbage Aug 27 '14 at 9:09
5

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)

  • 2
    Cheers. As far as I know you can actually do this since Linux kernel 3.4 by setting PR_SET_CHILD_SUBREAPER which circumvents init picking up orphan processes. But I think it's just to complicated for my case. (cf. man prctl). – lord.garbage Aug 27 '14 at 12:17
  • 1
    Scary! shudder ...in many ways... – Volker Siegel Aug 27 '14 at 12:18
  • init with other PIDs as well. Upstart creates an init for each user session, IIRC, which serves as the parent for that session's orphaned processes. – muru Aug 27 '14 at 12:35
  • The question for me is: How can is it possible to get the following process tree from the shell: systemd--bash--firefox. All methods I try will ultimately lead to a process tree of the following form systemd--firefox when I spawn firefox from the shell. – lord.garbage Aug 27 '14 at 13:28
  • That looks like you did an exec, replacing the bash process by the firefox process? – Volker Siegel Aug 27 '14 at 13:30
4

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 exited\n", 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.

  • Cheers. See comments/discussion above to @Volker's answer. – lord.garbage Aug 27 '14 at 21:14
  • I did not get notified about your edit so I just read this now. Thank you, @countermode. – lord.garbage Sep 1 '14 at 10:25
0

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

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.