4

I am writing a wrapper application to bash scripts and want the application to keep a track of which tools/processes have been launched from user scripts. I would like to know what is the best way to determine the list of child processes that were spawned of this parent process.

I tried

  1. Periodically invoking ps command and building a process tree (like ps -ejH) but this misses out on processes that ran to completion very quickly.
  2. Using a tool like forkstat that uses the proc connector interface, but that would only run with elevated privileges. While this gives the correct data, running as sudo would not work in my case?

Any suggestions how this can be achieved?

5
  • What language are you writing in? Commented Nov 20, 2018 at 11:18
  • Do you want to include also the "grandchildren etc.", i.e. if your script spawns process A, would children of process A be included in your tracking? Commented Nov 22, 2018 at 9:29
  • Yes, I would need the grandchildren too. Basically the subtree rooted at my wrapper application process.
    – divyanshm
    Commented Nov 22, 2018 at 9:41
  • 1
    I hope you're aware that a) a process can get rid of its parent (escape the process tree) by fork + exit b) you can start a process inside another unrelated process of the same user with ptrace eg. gdb -p PID -batch -ex 'p system("command")'.
    – user313992
    Commented Nov 22, 2018 at 19:29
  • Yes, and that is why I was exploring #2 -> ability to listen to a process being forked right away.
    – divyanshm
    Commented Nov 23, 2018 at 8:57

4 Answers 4

11
+50

If you're using Linux, you can use strace to trace system calls used by a process. For example:

~ strace -e fork,vfork,clone,execve -fb execve -o log ./foo.sh
foo bar
~ cat log
4817  execve("./foo.sh", ["./foo.sh"], [/* 42 vars */]) = 0
4817  clone(child_stack=NULL, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f1bb563b9d0) = 4818
4818  execve("/bin/true", ["/bin/true"], [/* 42 vars */] <detached ...>
4817  --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=4818, si_uid=1000, si_status=0, si_utime=0, si_stime=0} ---
4817  clone(child_stack=NULL, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f1bb563b9d0) = 4819
4817  clone(child_stack=NULL, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f1bb563b9d0) = 4820
4820  execve("/bin/echo", ["/bin/echo", "foo", "bar"], [/* 42 vars */] <detached ...>
4817  --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=4820, si_uid=1000, si_status=0, si_utime=0, si_stime=0} ---
4817  +++ exited with 0 +++
4819  execve("/bin/sleep", ["sleep", "1"], [/* 42 vars */] <detached ...>

You can see that the script forked off three processes (PIDs 4818, 4819, 4820) using the clone(2) system call, and the execve(2) system calls in those forked off processes show the commands executed.

  • -e fork,vfork,clone,execve limits strace output to these system calls
  • -f follows child processes
  • -b execve detaches from a process when the execve is reached, so we don't see further tracing of child processes.
6
  • Is it advisable to rely on strace? From what I know it takes up quite a few resources.
    – divyanshm
    Commented Nov 23, 2018 at 8:59
  • 1
    @divyanshm it only takes much resources when you don't limit the set of system calls to trace. When you instead use -e with a handful of syscalls, it'll only slow down things for the processes which use these syscalls very heavily.
    – Ruslan
    Commented Nov 23, 2018 at 9:30
  • ptrace-ing a process and its children (which is what strace(1) is doing) will still slow them down considerably -- at least 1.8x slowdown for a simple strace -qfe trace=execve -o /dev/null -p PID on a shell running /.configure && make in the bash source directory. Then there's still the problem of parsing strace's output into a tree -- that doesn't sound like a piece of cake ;-)
    – user313992
    Commented Nov 23, 2018 at 18:00
  • 1
    @muru as opposed to typical bash scripts, which are very light in execs and forks ;-)
    – user313992
    Commented Nov 23, 2018 at 23:12
  • 1
    It's not that strace(1) is a resource hog (it isn't by any measure), but that it has to work in tandem with the processes it's tracing -- it's not doing its tracing asynchronously. The traced process stops while strace is doing its thing (peeking at arguments, etc).
    – user313992
    Commented Nov 23, 2018 at 23:17
7
pstree -p `pgrep NetworkManager`
NetworkManager(1638)─┬─dhclient(3594)
                     ├─{NetworkManager}(1645)
                     ├─{NetworkManager}(1647)
                     └─{NetworkManager}(7363)

I think this is what you were looking for.

use direct pid or pgrep with process name.

-p used to print pids of children.

2
  • 1
    This leaves me with the need to invoke this method periodically, which reduces to me missing out on processes that ran to completion very quickly.
    – divyanshm
    Commented Nov 23, 2018 at 8:58
  • Good answer though, better than my #1 :) But there was a reason why I moved to #2 - this would have the same problem
    – divyanshm
    Commented Nov 23, 2018 at 8:58
4

pgrep command will be helpful. Use these commands :

Print PIDs of each forked process from process($pid) :

pgrep -P $pid

For more detailed information about each forked process use this command :

ps -fp `pgrep -P $pid`

where $pid is your process ID.

0

I would like to know what is the best way to determine the list of child processes that were spawned of this parent process.

Assuming that you are writing in bash (you do not say). Then you can use job control. This is off by default, when running scripts.

The bash manual says:

set [--abefhkmnptuvxBCHP] [-o option] [arg ...]
...
-m Monitor mode.
Job control is enabled. This option is on by default for interactive shells on systems that support it (see JOB CONTROL above). Background processes run in a separate process group and a line containing their exit status is printed upon their completion.

So add to your script set -m, the you can start commands, with command &, then latter do jobs to list jobs.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .