Bash、CLOEXEC でフォーク

Bash、CLOEXEC でフォーク

Bash は、サブプロセスがファイル記述子を継承するのを防ぎながらサブプロセスを実行できますか?

if flock -nx 9
then
  # If begin program runs away, it will keep the lock.
  begin program
else
  echo "Lock held :/)" >&2
fi 9> /tmp/lk

答え1

私の知る限り、いいえ。手動で閉じる必要があります。

if flock 9 -nx
then
   program 9>&- #<= manual close of fd 9 after `program` has forked but before it execs
else
  echo "Lock held :/)" >&2
fi 9> /tmp/lk

さらにハックしたい場合は、関数をfcntl直接呼び出してフラグを設定することができます。ctypes.sh:

#!/bin/bash

echo initial
ls /proc/$$/fd/

echo with 9
{

ls /proc/$$/fd/

echo with 9 in an execced child
bash -c ' ls /proc/$$/fd/'

} 9</etc/passwd


echo
echo BEGIN MAGIC
FD_CLOEXEC=1
FD_SETFD=2

. ctypes.sh
echo initial
ls /proc/$$/fd/

echo with 9
{

dlcall fcntl int:9 int:$FD_SETFD int:$FD_CLOEXEC

ls /proc/$$/fd/

echo with 9 in an execced child
bash -c ' ls /proc/$$/fd/'

} 9</etc/passwd

出力:

initial
0
1
2
255
with 9
0
1
2
255
9
with 9 in an execced child
0
1
2
3
9

BEGIN MAGIC
initial
0
1
2
255
with 9
0
1
2
255
9
with 9 in an execced child
0
1
2
3

(貼り付け時のタイプミスではありません。子 bash が実行されたときに 9 は実際に閉じられました)。

答え2

bash 5.0 以降とサンプルのロード可能モジュール (Debian ではパッケージもインストールする必要がありますbash-builtins) を使用すると、fdflags ロード可能モジュールを使用できます。

if flock -nx 9
then
  enable -f /usr/lib/bash/fdflags fdflags
  fdflags -s+cloexec 9
  begin program
else
  echo "Lock held :/)" >&2
fi 9> /tmp/lk

関連情報