次のイディオムは珍しくありません (これはMIMEDefangの C 部分から取られています)。
/* Number of file descriptors to close when forking */
#define CLOSEFDS 256
...
static void
closefiles(void)
{
int i;
for (i=0; i<CLOSEFDS; i++) {
(void) close(i);
}
}
(これは mimedefang-2.78 からのもので、後のリリースで実装がわずかに変更されています。)
これは一種のハックです (MIMEDefang コードが自由に認めているように)。多くの場合STDERR_FILENO+1
、0 ではなく FD 3 (または )から開始する方が便利です。 は無効な FD をclose()
返しますEBADF
が、これは通常問題を引き起こしません (少なくとも C ではそうではなく、他の言語では例外がスローされる可能性があります)。
次のように定義さgetrlimit(RLIMIT_NOFILE,...)
れているファイル記述子の上限を決定できるため:
RLIMIT_NOFILE
これは、システムが新しく作成された記述子に割り当てることができる最大値よりも 1 大きい数値です。この制限を超えると、ファイル記述子を割り当てる関数は失敗し、errno が [EMFILE] に設定されます。この制限により、プロセスが割り当てることができるファイル記述子の数が制限されます。
これを (1 を引いて) ループの上限として使用できます。上記とulimit -n
、getconf OPEN_MAX
およびsysconf(OPEN_MAX)
はすべて同意する必要があります。
は常に最小の空き FD を割り当てるためopen()
、開いているファイルの最大数と最大の FD+1 は同じ数になります。
fdが開いていない場合に戻るclose()
no-opを使用する代わりに、どのfdが開いているかを判断するには(ただし、条件付きを呼び出すことには明らかな利点はありません)。のループは 0 ..を呼び出して/を呼び出します。lseek(fd, 0, SEEK_CUR)
EBADF
lseek()
close()
socat
filan
FD_SETSIZE
fstat()
fstat64()
任意のプロセスをデーモン化するlibslackdaemon
ユーティリティも、このブルート フォース アプローチを使用します (ただし、 で使用する場合は、最初の 3 つの記述子を開いたままにしておく必要がありますinetd
)。
プログラムがファイル ハンドルを追跡できる場合は、追跡するか、可能な場合は使用することをお勧めしFD_CLOEXEC
ます。ただし、防御的にコーディングしたい場合は、親プロセスを信頼しないことを好むかもしれません。たとえば、このUnix プラットフォームの長期にわたる古い Mozilla バグのように、ブラウザによって開始された外部ハンドラー/ビューアー プロセスなどです。
偏執狂の場合 (キャッシュを含むすべての開いている Firefox FD を PDF ビューアーに継承させ、TCP 接続を開くようにしますか?):
#!/bin/bash
# you might want to use the value of "ulimit -n" instead of picking 255
for ((fd=3; fd<=255; fd++)); do
exec {fd}<&- # close
done
exec /usr/local/bin/xpdf "$@"
15 年後の更新この問題は、プロセスの作成が Netscape Portable Runtime (NSPR) API から LaunchApp を使用するように変更された Firefox 58 (2018) で解決されました。