web-dev-qa-db-ja.com

Linuxシェルコマンドを使用してファイル記述子を閉じる方法

/proc/pid/fd/、ファイル記述子が多すぎます。 Shellコマンドを使用してこれらのファイル記述子を閉じることはできますか?

13
Eric

実行中の他のプロセスのfdは、そうする権限がある限り、確実に閉じることができます。

まず、PIDを見つけます。

次に、gdbを起動し、プロセスにアタッチします。

gdb -p 1598

次に、閉じたいfdでcloseシステムコールを呼び出します。

(gdb) call close(999)
$1 = 0

ファイル記述子がリークされた場合、プログラムはとにかくそれを再び使用しようとはせず、問題を引き起こすことはありません。ただし、プログラムにはバグがある可能性があります。

次のように、bashで現在のプロセスのFD nを閉じることができます。

exec n<&-

私は同様の状況で実行しましたが、gdbはアプリケーションのリアルタイムの制約を混乱させ、テストを歪めたため、オプションではありませんでした。

そこで、私は簡単なiptablesルールを思いつきました。 角かっこで囲まれたオプションの引数([ opt ]

  1. 宛先アドレスとポートを検索

    netstat --program [ --numeric-Host --numeric-ports ] | grep [<pid>]/[<appname>]

    $ netstat --program --numeric-ports | grep 8812/
    tcp        0      0 ysc.xxx:54055          10.56.1.152:30000           ESTABLISHED 8812/my-application
    tcp        0      0 ysc.xxx:46786          postgres.xxx:5432           ESTABLISHED 8812/my-application
    tcp        0      0 ysc.xxx:36090          10.56.4.79:57000            ESTABLISHED 8812/my-application
                                          ...
    unix  2      [ ]         DGRAM                    7177020 8812/my-application
    

    ここで、カットしたい10.56.4.79:57000

  2. ソケットをカットするためのiptablesルールを作成します

    iptables -A OUTPUT [ --out-interface <if> --protocol <tcp|udp|unix> ] --destination <addr> --dport <port> --jump DROP

    $ iptables -A OUTPUT --destination 10.56.4.79 --dport 57000 --jump DROP
    $
    
  3. この段階で、プログラムは離れたホストにパケットを送信できません。ほとんどの場合、TCP接続は閉じられています。いくつかある場合は、テストを続行できます。

    $ netstat --program --numeric-ports | grep 8812/
    tcp        0      0 ysc.xxx:54055          10.56.1.152:30000           ESTABLISHED 8812/my-application
    tcp        0      0 ysc.xxx:46786          postgres.xxx:5432           ESTABLISHED 8812/my-application
                                          ...
    unix  2      [ ]         DGRAM                    7177020 8812/my-application
    
  4. iptablesルールを削除します

    同じiptablesルールを入力するだけで、ADに置き換えます。

    $ iptables -D OUTPUT --destination 10.56.4.79 --dport 57000 --jump DROP
    $
    
2
YSC

@Thomasの回答は、close()呼び出しのデバッグ情報がインストールされている場合にのみ有効です。

デバッグ情報がインストールされていない場合、gdbはclose()の呼び出しを拒否します。

_(gdb) call close(3)
'close' has unknown return type; cast the call to its declared return type
_

この場合、gdbでclose()を呼び出す最も簡単な方法は、呼び出しをclose()の戻り値の型にキャストすることです。

_(gdb) call (int)close(3)
$1 = 0
_

Gdb ドキュメント を参照してください:

呼び出したい関数にデバッグ情報がない場合があります。このような場合、GDBは、関数のパラメーターのタイプを含め、関数のタイプを認識しません。呼び出された関数が誤って機能し、クラッシュする可能性がある下位関数の誤った呼び出しを回避するために、GDBは、関数のタイプを指定しない限り、関数の呼び出しを拒否します。

プロトタイプ(つまり、ANSI/ISOスタイル)の関数の場合、これを行うには2つの方法があります。最も簡単なのは、関数の宣言された戻り値の型に呼び出しをキャストすることです。

0
ks1322