📑

[SadServers] 解説 "Oaxaca": Close an Open File

2023/01/11に公開

"Oaxaca": Close an Open File

SadServersの "Oaxaca": Close an Open File の解説です。

SadServers って何? って人は、 SadServers解説 を見てください。
一言でいうと、LeetCode (コーディング問題集) の Linuxサーバ設定版のようなものです。

問題

問題を見ていきます。 > の箇所は DeepLでの翻訳です。

Scenario: "Oaxaca": Close an Open File

Level: Medium

Description: The file /home/admin/somefile is open for writing by some process. Close this file without killing the process.
> home/admin/somefile ファイルは、あるプロセスによって書き込み可能な状態で開かれています。プロセスを停止させずに、このファイルを閉じてください。

Test: lsof /home/admin/somefile returns nothing.
> lsof /home/admin/somefile は何も返しません。

Time to Solve: 15 minutes.

OS: Debian 11

プロセスを殺さずに、そのプロセスが書き込み可能状態でオープンしているファイルを閉じろということです。

解説

まずは、 /home/admin/somefile の存在確認をします。

admin@ip-172-31-45-138:/$ cd /home/admin
admin@ip-172-31-45-138:~$ ls
agent  openfile.sh  somefile

ありますね。 lsofを使って、このファイルがどのプロセスから利用されているか調べます。
lsofはオープンしているファイルやポートが、どのプロセスからのものか調べる時に重宝するコマンドです。

admin@ip-172-31-45-138:~$ lsof somefile 
COMMAND PID  USER   FD   TYPE DEVICE SIZE/OFF   NODE NAME
bash    818 admin   77w   REG  259,1        0 272875 somefile

PID=818bashコマンドが このファイルをオープンしていることがわかります。 また、FD=77wから、ファイルディスクリプタ(fd)は77で、 書き込み可能状態ということがわかります。
ファイルディスクリプタというのは、オープンしたファイルを操作するときのLinuxカーネルが利用する識別子です。

procファイルシステムで、PID=818のファイルディスクリプタ情報を確認します。

admin@ip-172-31-45-138:~$ cat /proc/818/fd/
0    1    2    255  3    77   

きちんと 77 があります。
これを消したいので、 rmを試してみます。

admin@ip-172-31-45-138:~$ rm /proc/818/fd/77
rm: cannot remove '/proc/818/fd/77': Permission denied
admin@ip-172-31-45-138:~$ sudo rm /proc/818/fd/77
rm: cannot remove '/proc/818/fd/77': Operation not permitted

駄目ですね。。。
ググると、gdbを使って ファイルディスクリプタをクローズする方法がありました。

admin@ip-172-31-45-138:~$ gdb
bash: gdb: command not found

が、 gdbは無いようです。

もう少し調べると、execを使う方法が見つかりました。

書き込み可能なファイルをクローズするには、 exec [ファイルディスクリプタ]>&- のようです。

## ファイルディスクリプタ 77 をクローズ
admin@ip-172-31-45-138:/proc/818/fd$ exec 77<&-

## 77が無いことを確認
admin@ip-172-31-45-138:/proc/818/fd$ ls
0  1  2  255

最後に、testを実行します。 lsofが何も返さないのでOKです。

admin@ip-172-31-45-138:/proc/818/fd$ lsof /home/admin/somefile
admin@ip-172-31-45-138:/proc/818/fd$ 

Discussion