時々、ファイルシステムをアンマウントしたり、ループデバイスを切り離したりする必要がありますが、それはbusy
です。これは、ファイル記述子が開いているため、おそらくsmb
サーバープロセスが原因です。
強制的にアンマウントするには、問題のあるプロセスを強制終了します(または_kill -SIGTERM
_を試します)が、smb
接続を閉じます(開いているファイルの一部を閉じる必要がない場合でも)。 。
プロセスに特定のファイル記述子を強制的に強制するハックな方法について説明します heregdb
を使用してclose(fd)
を呼び出します。しかし、これは危険なようです。閉じた記述子がリサイクルされるとどうなりますか?プロセスは、完全に異なるファイルを参照するようになったことに気づかずに、古い格納された記述子を使用する場合があります。
私はアイデアを持っていますが、どのような欠陥があるのかわかりません:gdb
を使用し、_/dev/null
_で_O_WRONLY
_を開きます(編集:_O_PATH
_として提案されたコメントより良い代替手段)、次に_dup2
_を使用して問題のファイル記述子を閉じ、その記述子を_/dev/null
_に再利用します。この方法では、ファイル記述子への読み取りまたは書き込みは失敗します。
このような:
_Sudo gdb -p 234532
(gdb) set $dummy_fd = open("/dev/null", 0x200000) // O_PATH
(gdb) p dup2($dummy_fd, offending_fd)
(gdb) p close($dummy_fd)
(gdb) detach
(gdb) quit
_
何がうまくいかないのでしょうか?
gdb
を使用してプロセスをいじるのはほとんど安全ではありませんが、緊急事態が発生し、プロセスを開いたままにし、関係するすべてのリスクとコードを理解する必要がある場合に必要になることがあります。
ほとんどの場合、私は単にプロセスを終了しますが、場合によっては異なり、関連するシステムとプロセスを所有する環境、プロセスの実行状況、「強制終了してもよい」または「いいえ、まず最初に連絡してください」など。これらの詳細は、ほこりが落ち着いたら、検視会議で解決する必要がある場合があります。移行が計画されている場合は、問題のあるファイル記述子を開いているプロセスがあるかどうかを事前に確認して、緊急でない設定(移行の時間帯にのみ実行されるcronジョブまたはその他のスケジュールされたタスク)で処理できるようにすることをお勧めします。昼間のみチェックした場合、簡単に見逃される可能性があります)。
すべてのファイル記述子が書き込み専用ではないため、ファイル記述子O_WRONLY
を再度開くという考えには問題があります。 John ViegaとMatt Messierは、「Secure Programming Cookbook for C and C++」の本でより微妙なアプローチをとり、標準入力や標準エラーとは異なる方法で標準入力を処理します(p。25、「ファイル記述子の安全な管理」)。
static int open_devnull(int fd) {
FILE *f = 0;
if (!fd) f = freopen(_PATH_DEVNULL, "rb", stdin);
else if (fd == 1) f = freopen(_PATH_DEVNULL, "wb", stdout);
else if (fd == 2) f = freopen(_PATH_DEVNULL, "wb", stderr);
return (f && fileno(f) == fd);
}
gdb
の場合、記述子(またはFILE *
ハンドル)が読み取り専用か、読み取り専用か書き込み専用か、および/dev/null
で適切な置換が開かれているかどうかを確認する必要があります。そうでない場合、書き込み専用になった一度読み取り専用のハンドルは、プロセスがそこから読み取ろうとすると、不要なエラーを引き起こします。
ファイル記述子(およびおそらくFILE *
ハンドルも)が背後でいじられるときにプロセスがどのように正確に動作するかはプロセスに依存し、その記述子が現在使用されていない「悪夢モード」に使用されない場合の「大した問題」から変化しますフラッシュされていないデータ、ファイルが適切に閉じられていなかったことを示すインジケータ、またはその他の予期しない問題が原因で、どこかで破損したファイル。
FILE *
ハンドルの場合、ハンドルを閉じる前にfflush(3)
呼び出しを追加すると役立つ場合や、ダブルバッファリングやその他の問題が発生する場合があります。これは、ソースコードが何を期待しているのかを正確に知らなくても、gdb
でランダムな呼び出しを行う際のいくつかの危険の1つです。ソフトウェアには、fd
記述子または処理する必要があるFILE *
ハンドルに加えて、さらに複雑なレイヤーが組み込まれている場合があります。コードにパッチを当てるモンキーは、簡単にモンキーレンチになる可能性があります。
標準の終了シグナルをプロセスに送信すると、システムが正常にシャットダウンするときと同じように、リソースを適切に閉じる機会が与えられます。 gdb
を使用してプロセスをいじると、適切に処理が完了せず、状況がさらに悪化する可能性があります。
o_WRONLYで/ dev/nullを開き、次にdup2で問題のファイル記述子を閉じて、その記述子を/ dev/nullに再利用します。この方法では、ファイル記述子への読み取りまたは書き込みは失敗します。
記述子を/dev/null
に複製すると、書き込みはfailではなくsucceed、読み取りは成功し、0(eof)を返します。
これは必要な場合とそうでない場合があります。
Linuxでは、フラグ= 3(O_WRONLY|O_RDWR
aka O_NOACCESS
)でファイルを開くこともできます。これにより、読み取りまたは書き込みがEBADF
で失敗します。
このファイルはioctlでのみ使用できます-これは、他の回答やコメントでは触れられていない危険をもたらします。ファイル記述子で実行される操作は読み取りと書き込みだけではありません。 (lseek
またはftruncate
はどうですか?).
更新:
ドキュメントに記載されていないO_WRONLY|O_RDWR
:O_PATH = 010000000 / 0x200000
よりも良いものを見つけました。 open(2)マンページによると:
O_PATH (since Linux 2.6.39) Obtain a file descriptor that can be used for two purposes: to indicate a location in the filesystem tree and to perform opera- tions that act purely at the file descriptor level. The file itself is not opened, and other file operations (e.g., read(2), write(2), fchmod(2), fchown(2), fgetxattr(2), mmap(2)) fail with the error EBADF. The following operations can be performed on the resulting file descriptor: * close(2); fchdir(2) (since Linux 3.5); fstat(2) (since Linux 3.6). * Duplicating the file descriptor (dup(2), fcntl(2) F_DUPFD, etc.).