2

I'd like to set the PR_SET_CHILD_SUBREAPER process flag for the Bash process running my script, so that I can reap the tree of child processes that gets created (and can get killed in a non-orderly way) during its lifetime. Basically, I'd like Bash to call prctl(PR_SET_CHILD_SUBREAPER, 1, 0, 0, 0); on itself, but I haven't found a way to achieve that. Any suggestion?

I'd be fine even with dodgy solutions that involve invoking libc.so.6 prctl() directly (a-la Python ctypes) using Bash builtins, if any exist.

2 Answers 2

1

Since you mention it's fine with you, I feel obliged to introduce bash's equivalent...

ctypes.sh, a foreign function interface for bash

It's a shared object plugin for bash that is loaded with bash's enable -f mechanism:

enable [-a] [-dnps] [-f filename] [name ...]

The -f option means to load the new builtin command name from shared object filename, on systems that support dynamic loading.

and implemented in C language. It works at least on most Linux distributions and on FreeBSD.

You'll have to compile and install it first. The main feature is the ability to use almost any library call or system call from the shell. Though calls requiring structures might become way more complex to use when the builtin struct fails to reconstruct them automatically.

Example typed in current bash shell, on amd64 (x86_64) architecture and Linux kernel 5.6 (in some cases constants depend on architecture and (more uncommonly) kernel version):

$ source /usr/local/bin/ctypes.sh $ dlcall -r int prctl int:36 ulong:1 ulong:0 ulong:0 ulong:0 int:0 $ echo $DLRETVAL # you can't use $() above to get the result since that would be a subshell int:0 $ echo $$; bash -c 'echo $$; sleep 99 & echo $!; disown -a' 14767 16761 16762 $ pstree -p $$ bash(14767)─┬─pstree(16778) └─sleep(16762) 

The sleep process having lost its parent process (bash pid 16761), has been inherited by the current shell instead of the init process: it worked.

Note that PR_SET_CHILD_SUBREAPER had to be replaced by its value (and type) as found in /usr/include/linux/prctl.h on this system:

#define PR_SET_CHILD_SUBREAPER 36 

You'll have to check the documentation to use it properly.

Also, the shell's standard wait might not work as expected for this: the shell didn't spawn that sleep command so the wait command won't do anything. You might have to invest into dlcalling wait(), waitpid() & co. This could be difficult, because bash itself alters settings and uses wait()-like calls each time it runs a command, so some unforeseen interactions to handle those inherited processes are likely.


Using gdb

This would achieve the same result as before (there must be some options to get it less verbose):

$ gdb -ex 'call (int)prctl((int)36,(long)1,(long)0,(long)0,(long)0)' -ex detach -ex quit -p $$ 
5
  • An other method would be to use gdb from the shell to inject a prctl() call to itself. Nothing to compile anymore Commented May 27, 2020 at 18:55
  • Something like: gdb --pid $$ -ex 'call prctl(36, 1, 0, 0, 0, 0)' -ex 'quit $1'? I'll test it and report, I actually like it more as it doesn't involve installing anything (which could be tricky in the environment I work in). Commented May 27, 2020 at 19:01
  • I was adding it. Yes. Just in case I specified all types. Commented May 27, 2020 at 19:04
  • Anyway my remark at the end of ctypes.sh stands true: attempting to handle processes from bash commands (somehow...) might interact with bash's own handling of them which happens at least for each external command run. Commented May 27, 2020 at 19:05
  • The gdb solution works like a charm and I accepted it as it just works out the box. Thanks! Commented May 27, 2020 at 19:08
0

Non-C-programmers can use some simple chain-loading tools. I wrote one such for the nosh toolset.

  • For a script invoked as sh ./wibble (or some other shell) simply run
    local-reaper true sh ./wibble
  • For a script invoked as ./wibble simply run
    local-reaper true ./wibble

This tool works the same on FreeBSD. It hides all of the system call differences.

Further reading

1
  • The problem with a local-reaper process solution is that it doesn't scale well, as one more process has to stay alive to deal with the reaping (in my case I have a swarm of thousands process trees per machine, rooted in the Bash script). This is why I was specifically asking how to prctl the very Bash process running the root script. Commented May 28, 2020 at 10:34

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.