How to force a program to run in the foreground

5,220

Solution 1

When a process daemonizes, it forks itself (at least once), the parent returns immediately, and the child does the job.

When that child dies, it no longer has a parent. Or rather, it has been adopted by init (the process of id 1). init will be able to get its exit status.

On Linux, and since kernel 3.4, you can change which process will adopt the orphan processes (for its children and descendants) using the PR_SET_CHILD_SUBREAPER prctl().

So like in this very similar Q&A, if on Linux 3.4+, you can start your daemon under a wrapper that claims itself a child subreaper and have it report the exit status of its orphan descendants:

Here using perl and hardcoding the value of the PR_SET_CHILD_SUBREAPER prctl():

perl -MPOSIX -le '
  require "syscall.ph";
  syscall(&SYS_prctl,36,1) >= 0 or die "cannot set subreaper: $!";
  if (!fork) {
    exec @ARGV;
    exit(127);
  }
  # now reporting on all children and grand-children:
  while (($pid = wait) > 0) {
   print "$pid: " . WEXITSTATUS($?)
  }' your-daemon here

Solution 2

Assuming this is just for the occasional debug, if you just want to capture the exit code, then if you know the process id of the final daemonised process, you can attach to it with strace -p and so trace through till its exit.

If, for example, you do not have time to get the pid before it exits you can run the command under strace -f and so follow the child process. I don't have any easy daemon demos, but you can see how it might work with the following example:

$ strace -f -e exit bash -c 'nohup bash -c "sleep 10; exit 2" &'
strace: Process 9688 attached
[pid  9687] +++ exited with 0 +++
nohup: appending output to 'nohup.out'
strace: Process 9689 attached
[pid  9689] +++ exited with 0 +++
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=9689, si_uid=127, si_status=0, si_utime=0, si_stime=0} ---
+++ exited with 2 +++

Here we can see we managed to gather the exit code of 2 from the inner "daemonised" bash command.


Alternatively, if you have systemd, you can run try running the command in a separate cgroup:

$ systemd-run --user --service-type=forking  bash -c '(sleep 99;exit 2)& exit 0'
Running as unit run-8772.service.

I don't know how to gather the resulting exit code except by polling. When done too soon the daemon is still active:

$ systemctl --user status run-8772
  ...
   Active: active (running) since Wed 2017-03-29 18:56:43 CEST; 14s ago
   CGroup: /user.slice/user-1000.slice/[email protected]/run-8772.service
       |-8774 /usr/bin/bash -c (sleep 99;exit 2)& exit 0
       `-8775 sleep 99

After a suitable delay, the process is dead and we have access to the wanted exit code:

$ systemctl --user status run-8772
   Active: failed (Result: exit-code) since Wed 2017-03-29 18:58:22 CEST; 3s ago
 Main PID: 8774 (code=exited, status=2)
Share:
5,220

Related videos on Youtube

LINUX G33NYUS
Author by

LINUX G33NYUS

Updated on September 18, 2022

Comments

  • LINUX G33NYUS
    LINUX G33NYUS almost 2 years

    There is a program that automatically daemonizes itself and runs in the background.

    Is there a way to force this program to run in the foreground? I want to put it in a script and then capture the return code to see whether or not it exited normally.