Linux のファむル蚘述子ず䟋

か぀お、むンタビュヌで、ディスクの容量が䞍足したためにサヌビスが壊れおいるのを芋぀けたらどうしたすか、ず尋ねられたこずがありたす。

もちろん、私はこの堎所が䜕をしおいるのか芋お、可胜であればその堎所を掃陀するず答えたした。
次にむンタビュアヌは、パヌティションに空き領域がなく、すべおの領域を占有するファむルも衚瀺されない堎合はどうなるのかず尋ねたした。

これに察しお、たずえば lsof コマンドを䜿甚しお、い぀でも開いおいるファむル蚘述子を確認でき、どのアプリケヌションが利甚可胜なスペヌスをすべお占有しおいるかを把握でき、デヌタが必芁かどうかに応じお状況に応じお行動できるず述べたした。 。

むンタビュアヌは最埌の蚀葉で私の話を遮り、さらに質問を加えたした。「デヌタは必芁ないずしたす。これは単なるデバッグ ログですが、デバッグを曞き蟌めないためアプリケヌションがダりンしおいたす。」

「わかりたした」ず私は答えたした。「アプリケヌション構成でデバッグをオフにしお、再起動できたす。」
面接官は「いいえ、アプリケヌションを再起動するこずはできたせん。メモリには重芁なデヌタがただあり、重芁なクラむアントはサヌビス自䜓に接続されおいるため、匷制的に再接続するこずはできたせん。」ず反論したした。

「わかりたした」ず私は蚀いたした。「アプリケヌションを再起動できず、デヌタを気にしない堎合は、ls にファむルが衚瀺されなくおも、ファむル蚘述子を介しおこの開いおいるファむルをクリアできたす。」ファむル システム䞊のコマンドです。」

面接官は満足しおいたしたが、私はそうではありたせんでした。

そこで私は、なぜ私の知識をテストする人はさらに深く調べようずしないのかず考えたした。 しかし、結局のずころデヌタが重芁である堎合はどうなるでしょうか? プロセスを再起動できず、同時にこのプロセスが空き領域のないパヌティション䞊のファむル システムに曞き蟌みを行った堎合はどうなるでしょうか? すでに曞き蟌たれたデヌタだけでなく、このプロセスが曞き蟌んでいる、たたは曞き蟌もうずしおいるデヌタも倱われないずしたらどうなるでしょうか?

トゥゞク

私のキャリアの初めに、私はナヌザヌに関する情報を保存する必芁がある小さなアプリケヌションを䜜成しようずしおいたした。 そこで私は、どうすればナヌザヌずそのデヌタを照合できるだろうかず考えたした。 たずえば、私にはむワノフ・むワン・むワノビッチがい​​お、圌はいく぀かのデヌタを持っおいたすが、どうすれば圌らず友達になるこずができたすか 「トゥゞク」ずいう名前の犬がこの同じむワンのものであるこずを盎接指摘できたす。 しかし、もし圌が名前を倉えお、むワンではなく、䟋えばオヌリダになったらどうなるでしょうか その埌、私たちのオリダ・むワノフナ・むワノワはもう犬を飌っおいないこずが刀明し、私たちのトゥゞクは䟝然ずしお存圚しないむワンに属したす。 デヌタベヌスはこの問題の解決に圹立ち、各ナヌザヌに䞀意の識別子 (ID) が䞎えられ、私の Tuzik はこの ID (実際には単なるシリアル番号) に関連付けられおいたした。 したがっお、tuzik の所有者は ID 番号 2 を持ち、ある時点で Ivan がこの ID の䞋にあり、その埌 Olya も同じ ID の䞋になりたした。 人類ず畜産の問題は実質的に解決されたした。

ファむル蚘述子

ファむルずそのファむルを操䜜するプログラムの問題は、犬ず人間の問題ずほが同じです。 ivan.txt ずいう名前のファむルを開いお、tuzik ずいう単語を曞き始めたものの、最初の文字「t」だけをファむルに曞き蟌むこずができ、このファむルの名前が誰かによっお、たずえば olya.txt に倉曎されたずしたす。 しかし、ファむルは同じなので、゚ヌスをそこに曞き蟌みたいず思っおいたす。 システムコヌルでファむルを開くたびに 開いた どのプログラミング蚀語でも、ファむルを指す䞀意の ID を取埗したす。この ID がファむル蚘述子です。 そしお、このファむルを次に誰が䜕をするかはたったく問題ではありたせん。削陀するこずも、名前を倉曎するこずも、所有者を倉曎するこずも、読み取りず曞き蟌みの暩利を剥奪するこずもできたす。私は匕き続きそのファむルにアクセスできたす。なぜなら、ファむルを開いた時点で、私はそのファむルを読み曞きする暩利を持っおいお、なんずかそのファむルで䜜業を開始できたので、それを続けなければならないこずを意味したす。

Linux では、libc ラむブラリは、実行䞭のアプリケヌション (プロセス) ごずに、番号 3、0,1,2、XNUMX の XNUMX ぀の蚘述子ファむルを開きたす。 詳现に぀いおはリンクをご芧ください 男暙準 О 男の暙準出力

  • ファむル蚘述子 0 は STDIN ず呌ばれ、アプリケヌション入力に関連付けられたす。
  • ファむル蚘述子 1 は STDOUT ず呌ばれ、印刷コマンドなどの出力アプリケヌションによっお䜿甚されたす。
  • ファむル蚘述子 2 は STDERR ずいう名前で、アプリケヌションが゚ラヌ メッセヌゞを出力するために䜿甚したす。

プログラム内で読み取りたたは曞き蟌みのためにファむルを開いた堎合、おそらく最初の無料 ID が取埗され、これが 3 番目になりたす。

PID がわかっおいる堎合は、プロセスのファむル蚘述子のリストを衚瀺できたす。

たずえば、bash でコン゜ヌルを開いおプロセスの PID を確認しおみたしょう。

[user@localhost ]$ echo $$
15771

XNUMX 番目のコン゜ヌルで次を実行したす。

[user@localhost ]$ ls -lah /proc/15771/fd/
total 0
dr-x------ 2 user user  0 Oct  7 15:42 .
dr-xr-xr-x 9 user user  0 Oct  7 15:42 ..
lrwx------ 1 user user 64 Oct  7 15:42 0 -> /dev/pts/21
lrwx------ 1 user user 64 Oct  7 15:42 1 -> /dev/pts/21
lrwx------ 1 user user 64 Oct  7 15:42 2 -> /dev/pts/21
lrwx------ 1 user user 64 Oct  7 15:42 255 -> /dev/pts/21

この蚘事の枠組み内では、番号 255 のファむル蚘述子は無芖しおも問題ありたせん。これは、リンクされたラむブラリではなく、bash 自䜓によっお必芁に応じお開かれたものです。

これで、3 ぀の蚘述子ファむルすべおが擬䌌端末デバむスに関連付けられたした。 / dev / ptsただし、たずえば XNUMX 番目のコン゜ヌルで実行するなど、匕き続き操䜜できたす。

[user@localhost ]$ echo "hello world" > /proc/15771/fd/0

そしお最初のコン゜ヌルに衚瀺されるのは、

[user@localhost ]$ hello world

リダむレクトずパむプ

これら 3 ぀の蚘述子ファむルは、bash を含む任意のプロセスで、たずえば XNUMX ぀のプロセスを接続するパむプ (パむプ) を通じお簡単にオヌバヌラむドできたす。

[user@localhost ]$ cat /dev/zero | sleep 10000

このコマンドは自分で実行できたす strace -f 内郚で䜕が起こっおいるのか芋おみたしょう。しかし、それは手短にしたす。

PID 15771 の芪 bash プロセスはコマンドを解析し、実行するコマンドの数を正確に理解したす。この堎合、そのうちの 2 ぀は cat ず sleep です。 Bash は、XNUMX ぀の子プロセスを䜜成し、それらを XNUMX ぀のパむプにマヌゞする必芁があるこずを認識しおいたす。 合蚈するず、bash には XNUMX ぀の子プロセスず XNUMX ぀のパむプが必芁になりたす。

子プロセスを䜜成する前に、bash はシステム コヌルを実行したす。 パむプ そしお、䞀時パむプバッファヌで新しいファむル蚘述子を受け取りたすが、このバッファヌはただ XNUMX ぀の子プロセスをいかなる方法でも接続しおいたせん。

芪プロセスの堎合、パむプはすでに存圚しおいるように芋えたすが、子プロセスはただありたせん。

PID    command
15771  bash
lrwx------ 1 user user 64 Oct  7 15:42 0 -> /dev/pts/21
lrwx------ 1 user user 64 Oct  7 15:42 1 -> /dev/pts/21
lrwx------ 1 user user 64 Oct  7 15:42 2 -> /dev/pts/21
lrwx------ 1 user user 64 Oct  7 15:42 3 -> pipe:[253543032]
lrwx------ 1 user user 64 Oct  7 15:42 4 -> pipe:[253543032]
lrwx------ 1 user user 64 Oct  7 15:42 255 -> /dev/pts/21

次に、システムコヌルを䜿甚しお、 bash は XNUMX ぀の子プロセスを䜜成したす。XNUMX ぀のプロセスは次のようになりたす。

PID    command
15771  bash
lrwx------ 1 user user 64 Oct  7 15:42 0 -> /dev/pts/21
lrwx------ 1 user user 64 Oct  7 15:42 1 -> /dev/pts/21
lrwx------ 1 user user 64 Oct  7 15:42 2 -> /dev/pts/21
lrwx------ 1 user user 64 Oct  7 15:42 3 -> pipe:[253543032]
lrwx------ 1 user user 64 Oct  7 15:42 4 -> pipe:[253543032]
lrwx------ 1 user user 64 Oct  7 15:42 255 -> /dev/pts/21
PID    command
9004  bash
lrwx------ 1 user user 64 Oct  7 15:57 0 -> /dev/pts/21
lrwx------ 1 user user 64 Oct  7 15:57 1 -> /dev/pts/21
lrwx------ 1 user user 64 Oct  7 15:57 2 -> /dev/pts/21
lrwx------ 1 user user 64 Oct  7 15:57 3 -> pipe:[253543032]
lrwx------ 1 user user 64 Oct  7 15:57 4 -> pipe:[253543032]
lrwx------ 1 user user 64 Oct  7 15:57 255 -> /dev/pts/21
PID    command
9005  bash
lrwx------ 1 user user 64 Oct  7 15:57 0 -> /dev/pts/21
lrwx------ 1 user user 64 Oct  7 15:57 1 -> /dev/pts/21
lrwx------ 1 user user 64 Oct  7 15:57 2 -> /dev/pts/21
lrwx------ 1 user user 64 Oct  7 15:57 3 -> pipe:[253543032]
lrwx------ 1 user user 64 Oct  7 15:57 4 -> pipe:[253543032]
lrwx------ 1 user user 64 Oct  7 15:57 255 -> /dev/pts/21

clone はすべおのファむル蚘述子ずずもにプロセスを耇補するため、それらは芪プロセスず子プロセスで同じになるこずを忘れないでください。 PID 15771 の芪プロセスのタスクは子プロセスを監芖するこずなので、子プロセスからの応答を埅぀だけです。

したがっお、パむプは必芁なく、番号 3 ず 4 でファむル蚘述子を閉じたす。

PID 9004 の最初の bash 子プロセスでは、システム コヌル dup2は、STDOUT ファむル蚘述子の番号 1 を、パむプを指すファむル蚘述子に倉曎したす。この堎合は番号 3 です。したがっお、PID 9004 の最初の子プロセスが STDOUT に曞き蟌むものはすべお、自動的にパむプ バッファヌに入りたす。

PID 9005 の 2 番目の子プロセスでは、ファむルを STDIN 蚘述子番号 0 に bash dup9005s したす。これで、PID XNUMX の XNUMX 番目の bash が読み取るものはすべおパむプから読み取られたす。

その埌、番号 3 ず 4 のファむル蚘述子も䜿甚されなくなったため、子プロセスで閉じられたす。

ファむル蚘述子 255 は意図的に無芖したす。これは bash 自䜓によっお内郚的に䜿甚され、子プロセスでも閉じられたす。

次に、PID 9004 の最初の子プロセスで、bash がシステム コヌルで開始されたす。 exec コマンドラむンで指定した実行可胜ファむル。この堎合は /usr/bin/cat です。

PID 9005 の XNUMX 番目の子プロセスでは、bash は指定した XNUMX 番目の実行可胜ファむル (この堎合は /usr/bin/sleep) を実行したす。

exec システム コヌルは、open 呌び出しの実行時に O_CLOEXEC フラグを䜿甚しおファむル蚘述子が開かれおいない限り、ファむル蚘述子を閉じたせん。 この䟋では、実行可胜ファむルを実行した埌、珟圚のファむル蚘述子がすべお保存されたす。

コン゜ヌルでチェックむンするず、次のようになりたす。

[user@localhost ]$ pgrep -P 15771
9004
9005
[user@localhost ]$ ls -lah /proc/15771/fd/
total 0
dr-x------ 2 user user  0 Oct  7 15:42 .
dr-xr-xr-x 9 user user  0 Oct  7 15:42 ..
lrwx------ 1 user user 64 Oct  7 15:42 0 -> /dev/pts/21
lrwx------ 1 user user 64 Oct  7 15:42 1 -> /dev/pts/21
lrwx------ 1 user user 64 Oct  7 15:42 2 -> /dev/pts/21
lrwx------ 1 user user 64 Oct  7 15:42 255 -> /dev/pts/21
[user@localhost ]$ ls -lah /proc/9004/fd
total 0
dr-x------ 2 user user  0 Oct  7 15:57 .
dr-xr-xr-x 9 user user  0 Oct  7 15:57 ..
lrwx------ 1 user user 64 Oct  7 15:57 0 -> /dev/pts/21
l-wx------ 1 user user 64 Oct  7 15:57 1 -> pipe:[253543032]
lrwx------ 1 user user 64 Oct  7 15:57 2 -> /dev/pts/21
lr-x------ 1 user user 64 Oct  7 15:57 3 -> /dev/zero
[user@localhost ]$ ls -lah /proc/9005/fd
total 0
dr-x------ 2 user user  0 Oct  7 15:57 .
dr-xr-xr-x 9 user user  0 Oct  7 15:57 ..
lr-x------ 1 user user 64 Oct  7 15:57 0 -> pipe:[253543032]
lrwx------ 1 user user 64 Oct  7 15:57 1 -> /dev/pts/21
lrwx------ 1 user user 64 Oct  7 15:57 2 -> /dev/pts/21
[user@localhost ]$ ps -up 9004
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
user  9004  0.0  0.0 107972   620 pts/21   S+   15:57   0:00 cat /dev/zero
[user@localhost ]$ ps -up 9005
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
user  9005  0.0  0.0 107952   360 pts/21   S+   15:57   0:00 sleep 10000

ご芧のずおり、パむプの䞀意の番号は䞡方のプロセスで同じです。 したがっお、同じ芪を持぀ XNUMX ぀の異なるプロセス間に接続が存圚したす。

bash が䜿甚するシステム コヌルに詳しくない人には、次のように strace を通じおコマンドを実行し、内郚で䜕が起こっおいるかを確認するこずを匷くお勧めしたす。

strace -s 1024 -f bash -c "ls | grep hello"

ディスク容量が䞍足し、プロセスを再起動せずにデヌタを保存しようずする問題に戻りたしょう。 1 秒あたり玄 XNUMX メガバむトの速床でディスクに曞き蟌む小さなプログラムを曞いおみたしょう。 さらに、䜕らかの理由でデヌタをディスクに曞き蟌めなかった堎合は、これを無芖しお、すぐに再床デヌタの曞き蟌みを詊みたす。 この䟋では Python を䜿甚しおいたすが、他のプログラミング蚀語を䜿甚するこずもできたす。

[user@localhost ]$ cat openforwrite.py 
import datetime
import time

mystr="a"*1024*1024+"n"
with open("123.txt", "w") as f:
    while True:
        try:
            f.write(str(datetime.datetime.now()))
            f.write(mystr)
            f.flush()
            time.sleep(1)
        except:
            pass

プログラムを実行しおファむル蚘述子を確認したす。

[user@localhost ]$ python openforwrite.py &
[1] 3762
[user@localhost ]$ ps axuf | grep [o]penforwrite
user  3762  0.0  0.0 128600  5744 pts/22   S+   16:28   0:00  |   _ python openforwrite.py
[user@localhost ]$ ls -la /proc/3762/fd
total 0
dr-x------ 2 user user  0 Oct  7 16:29 .
dr-xr-xr-x 9 user user  0 Oct  7 16:29 ..
lrwx------ 1 user user 64 Oct  7 16:29 0 -> /dev/pts/22
lrwx------ 1 user user 64 Oct  7 16:29 1 -> /dev/pts/22
lrwx------ 1 user user 64 Oct  7 16:29 2 -> /dev/pts/22
l-wx------ 1 user user 64 Oct  7 16:29 3 -> /home/user/123.txt

ご芧のずおり、3 ぀の暙準ファむル蚘述子ず、開いたもう XNUMX ぀のファむル蚘述子がありたす。 ファむルサむズを確認しおみたしょう。

[user@localhost ]$ ls -lah 123.txt 
-rw-rw-r-- 1 user user 117M Oct  7 16:30 123.txt

デヌタが曞き蟌たれた埌、ファむルに察する暩限を倉曎しようずしたす。

[user@localhost ]$ sudo chown root: 123.txt
[user@localhost ]$ ls -lah 123.txt 
-rw-rw-r-- 1 root root 168M Oct  7 16:31 123.txt
[user@localhost ]$ ls -lah 123.txt 
-rw-rw-r-- 1 root root 172M Oct  7 16:31 123.txt

ナヌザヌにはファむルに曞き蟌む暩限がないにもかかわらず、デヌタがただ曞き蟌たれおいるこずがわかりたす。 それを削陀しおみたしょう:

[user@localhost ]$ sudo rm 123.txt 
[user@localhost ]$ ls 123.txt
ls: cannot access 123.txt: No such file or directory

デヌタはどこに曞き蟌たれたすか? そしお、そもそもそれらは曞かれおいたすか 私たちは以䞋をチェックしたす:

[user@localhost ]$ ls -la /proc/3762/fd
total 0
dr-x------ 2 user user  0 Oct  7 16:29 .
dr-xr-xr-x 9 user user  0 Oct  7 16:29 ..
lrwx------ 1 user user 64 Oct  7 16:29 0 -> /dev/pts/22
lrwx------ 1 user user 64 Oct  7 16:29 1 -> /dev/pts/22
lrwx------ 1 user user 64 Oct  7 16:29 2 -> /dev/pts/22
l-wx------ 1 user user 64 Oct  7 16:29 3 -> /home/user/123.txt (deleted)

はい、ファむル蚘述子はただ存圚しおおり、このファむル蚘述子を叀いファむルず同様に操䜜でき、読み取り、クリヌンアップ、コピヌできたす。

ファむルサむズを芋おください:

[user@localhost ]$ lsof | grep 123.txt
python    31083             user    3w      REG                8,5   19923457   2621522 /home/user/123.txt

ファむル サむズは 19923457 です。ファむルをクリアしようずしおいたす:

[user@localhost ]$ truncate -s 0 /proc/31083/fd/3
[user@localhost ]$ lsof | grep 123.txt
python    31083             user    3w      REG                8,5  136318390   2621522 /home/user/123.txt

ご芧のずおり、ファむル サむズは増加するだけで、トランクは機胜したせんでした。 システムコヌルに関するドキュメントに移りたしょう 開いた。 ファむルを開くずきに O_APPEND フラグを䜿甚するず、曞き蟌みのたびに、オペレヌティング システムがファむル サむズをチェックしおファむルの最埌にデヌタを曞き蟌み、それをアトミックに実行したす。 これにより、耇数のスレッドたたはプロセスが同じファむルに曞き蟌むこずができたす。 ただし、コヌドではこのフラグを䜿甚したせん。 ファむルを曞き蟌み甚に開いた堎合にのみ、trunk の埌の lsof で異なるファむル サむズが確認できたす。぀たり、コヌドでは、

with open("123.txt", "w") as f:

私たちは眮かなければなりたせん

with open("123.txt", "a") as f:

「w」フラグでチェックする

[user@localhost ]$ strace -e trace=open python openforwrite.py 2>&1| grep 123.txt
open("123.txt", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 3

そしお「a」フラグ付き

[user@localhost ]$ strace -e trace=open python openforwrite.py 2>&1| grep 123.txt
open("123.txt", O_WRONLY|O_CREAT|O_APPEND, 0666) = 3

すでに実行䞭のプロセスをプログラミングする

倚くの堎合、プログラマはプログラムを䜜成およびテストするずきに、デバッガ (GDB など) たたはアプリケヌションのさたざたなレベルのログを䜿甚したす。 Linux は、倉数の倀の倉曎、ブレヌクポむントの蚭定など、すでに実行䞭のプログラムを実際に䜜成および倉曎する機胜を提䟛したす。

ファむルを曞き蟌むためのディスク領域の䞍足に関する最初の質問に戻っお、問題をシミュレヌトしおみたしょう。

パヌティション甚のファむルを䜜成しお、別のドラむブずしおマりントしたしょう。

[user@localhost ~]$ dd if=/dev/zero of=~/tempfile_for_article.dd bs=1M count=10
10+0 records in
10+0 records out
10485760 bytes (10 MB) copied, 0.00525929 s, 2.0 GB/s
[user@localhost ~]$

ファむルシステムを䜜成しおみたしょう。

[user@localhost ~]$ mkfs.ext4 ~/tempfile_for_article.dd
mke2fs 1.42.9 (28-Dec-2013)
/home/user/tempfile_for_article.dd is not a block special device.
Proceed anyway? (y,n) y
...
Writing superblocks and filesystem accounting information: done
[user@localhost ~]$

ファむルシステムをマりントしおみたしょう。

[user@localhost ~]$ sudo mount ~/tempfile_for_article.dd /mnt/
[sudo] password for user: 
[user@localhost ~]$ df -h | grep mnt
/dev/loop0      8.7M  172K  7.9M   3% /mnt

所有者ず䞀緒にディレクトリを䜜成したす。

[user@localhost ~]$ sudo mkdir /mnt/logs
[user@localhost ~]$ sudo chown user: /mnt/logs

プログラム内でのみ曞き蟌み甚にファむルを開いおみたしょう。

with open("/mnt/logs/123.txt", "w") as f:

打ち䞊げ

[user@localhost ]$ python openforwrite.py 

数秒埅っおいたす

[user@localhost ~]$ df -h | grep mnt
/dev/loop0      8.7M  8.0M     0 100% /mnt

したがっお、この蚘事の冒頭で説明した問題が発生したした。 空き容量 0、占有率 100%。

問題の状況に応じお、倱うこずができない非垞に重芁なデヌタを蚘録しようずしおいるこずを思い出したす。 その際、プロセスを再起動せずにサヌビスを修正する必芁がありたす。

ただディスク領域があるが、別のパヌティション、たずえば /home にあるずしたす。

コヌドを「オンザフラむで再プログラム」しおみたしょう。

すべおのディスク容量を消費したプロセスの PID を確認したす。

[user@localhost ~]$ ps axuf | grep [o]penfor
user 10078 27.2  0.0 128600  5744 pts/22   R+   11:06   0:02  |   _ python openforwrite.py

gdb を䜿甚しおプロセスに接続する

[user@localhost ~]$ gdb -p 10078
...
(gdb) 

開いおいるファむル蚘述子を芋おみたしょう。

(gdb) shell ls -lah /proc/10078/fd/
total 0
dr-x------ 2 user user  0 Oct  8 11:06 .
dr-xr-xr-x 9 user user  0 Oct  8 11:06 ..
lrwx------ 1 user user 64 Oct  8 11:09 0 -> /dev/pts/22
lrwx------ 1 user user 64 Oct  8 11:09 1 -> /dev/pts/22
lrwx------ 1 user user 64 Oct  8 11:06 2 -> /dev/pts/22
l-wx------ 1 user user 64 Oct  8 11:09 3 -> /mnt/logs/123.txt

興味のある番号 3 のファむル蚘述子に関する情報を調べたす。

(gdb) shell cat /proc/10078/fdinfo/3
pos:    8189952
flags:  0100001
mnt_id: 482

Python がどのようなシステム コヌルを行うかを念頭に眮き (䞊蚘の strace を実行しおオヌプン コヌルを芋぀けたずころを参照)、コヌドを凊理しおファむルを開くずきに、プロセスに代わっお自分たちでも同じこずを行いたすが、O_WRONLY|O_CREAT| が必芁です。 O_TRUNC ビットは数倀に眮き換えられたす。 これを行うには、次のようなカヌネル ゜ヌスを開きたす。 ここで どのフラグが䜕を担圓しおいるかを確認したす

#define O_WRONLY 00000001
#define O_CREAT 00000100
#define O_TRUNC 00001000

すべおの倀を 00001101 ぀に結合するず、XNUMX が埗られたす

gdb から呌び出しを実行する

(gdb) call open("/home/user/123.txt", 00001101,0666)
$1 = 4

したがっお、番号 4 の新しいファむル蚘述子ず、別のパヌティションに新しい開いおいるファむルを取埗したした。次を確認しおください。

(gdb) shell ls -lah /proc/10078/fd/
total 0
dr-x------ 2 user user  0 Oct  8 11:06 .
dr-xr-xr-x 9 user user  0 Oct  8 11:06 ..
lrwx------ 1 user user 64 Oct  8 11:09 0 -> /dev/pts/22
lrwx------ 1 user user 64 Oct  8 11:09 1 -> /dev/pts/22
lrwx------ 1 user user 64 Oct  8 11:06 2 -> /dev/pts/22
l-wx------ 1 user user 64 Oct  8 11:09 3 -> /mnt/logs/123.txt
l-wx------ 1 user user 64 Oct  8 11:15 4 -> /home/user/123.txt

私たちはパむプを䜿った䟋、぀たり bash がファむル蚘述子を倉曎する方法を芚えおおり、dup2 システムコヌルに぀いおはすでに孊習しおいたす。

あるファむル蚘述子を別のファむル蚘述子に眮き換えようずしおいたす

(gdb) call dup2(4,3)
$2 = 3

私たちはチェックしたす

(gdb) shell ls -lah /proc/10078/fd/
total 0
dr-x------ 2 user user  0 Oct  8 11:06 .
dr-xr-xr-x 9 user user  0 Oct  8 11:06 ..
lrwx------ 1 user user 64 Oct  8 11:09 0 -> /dev/pts/22
lrwx------ 1 user user 64 Oct  8 11:09 1 -> /dev/pts/22
lrwx------ 1 user user 64 Oct  8 11:06 2 -> /dev/pts/22
l-wx------ 1 user user 64 Oct  8 11:09 3 -> /home/user/123.txt
l-wx------ 1 user user 64 Oct  8 11:15 4 -> /home/user/123.txt

ファむル蚘述子 4 は必芁ないので閉じたす。

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

そしおgdbを終了したす

(gdb) quit
A debugging session is active.

    Inferior 1 [process 10078] will be detached.

Quit anyway? (y or n) y
Detaching from program: /usr/bin/python2.7, process 10078

新しいファむルを確認する:

[user@localhost ~]$ ls -lah /home/user/123.txt
-rw-rw-r-- 1 user user 5.1M Oct  8 11:18 /home/user/123.txt
[user@localhost ~]$ ls -lah /home/user/123.txt
-rw-rw-r-- 1 user user 7.1M Oct  8 11:18 /home/user/123.txt

ご芧のずおり、デヌタは新しいファむルに曞き蟌たれたす。叀いファむルを確認したす。

[user@localhost ~]$ ls -lah /mnt/logs/123.txt 
-rw-rw-r-- 1 user user 7.9M Oct  8 11:08 /mnt/logs/123.txt

デヌタは倱われず、アプリケヌションは動䜜し、ログは新しい堎所に曞き蟌たれたす。

物事をもう少し難しくしたしょう

デヌタは重芁ですが、どのパヌティションにもディスク容量がなく、ディスクに接続できないず想像しおください。

私たちができるこずは、デヌタをパむプなどのどこかにリダむレクトし、netcat などのプログラムを通じおパむプからネットワヌクにデヌタをリダむレクトするこずです。
mkfifo コマンドを䜿甚しお名前付きパむプを䜜成できたす。 ファむル システムに空き領域がない堎合でも、ファむル システム䞊に疑䌌ファむルが䜜成されたす。

アプリケヌションを再起動しお、次のこずを確認したす。

[user@localhost ]$ python openforwrite.py 
[user@localhost ~]$ ps axuf | grep [o]pen
user  5946 72.9  0.0 128600  5744 pts/22   R+   11:27   0:20  |   _ python openforwrite.py
[user@localhost ~]$ ls -lah /proc/5946/fd
total 0
dr-x------ 2 user user  0 Oct  8 11:27 .
dr-xr-xr-x 9 user user  0 Oct  8 11:27 ..
lrwx------ 1 user user 64 Oct  8 11:28 0 -> /dev/pts/22
lrwx------ 1 user user 64 Oct  8 11:28 1 -> /dev/pts/22
lrwx------ 1 user user 64 Oct  8 11:27 2 -> /dev/pts/22
l-wx------ 1 user user 64 Oct  8 11:28 3 -> /mnt/logs/123.txt
[user@localhost ~]$ df -h | grep mnt
/dev/loop0      8.7M  8.0M     0 100% /mnt

ディスク領域はありたせんが、そこに名前付きパむプを正垞に䜜成できたす。

[user@localhost ~]$ mkfifo /mnt/logs/megapipe
[user@localhost ~]$ ls -lah /mnt/logs/megapipe 
prw-rw-r-- 1 user user 0 Oct  8 11:28 /mnt/logs/megapipe

次に、このパむプに入るすべおのデヌタを䜕らかの方法でネットワヌク経由で別のサヌバヌにラップする必芁がありたす。これには同じ netcat が適しおいたす。

Remote-server.example.com サヌバヌで、次を実行したす。

[user@localhost ~]$ nc -l 7777 > 123.txt 

問題のサヌバヌ䞊で、別のタヌミナルで実行したす。

[user@localhost ~]$ nc remote-server.example.com 7777 < /mnt/logs/megapipe 

これで、パむプに入るすべおのデヌタは自動的に netcat の stdin に送られ、ポヌト 7777 でネットワヌクに送信されたす。

私たちがしなければならないのは、この名前付きパむプぞのデヌタの曞き蟌みを開始するこずだけです。

すでに実行䞭のアプリケヌションがありたす。

[user@localhost ~]$ ps axuf | grep [o]pen
user  5946 99.8  0.0 128600  5744 pts/22   R+   11:27 169:27  |   _ python openforwrite.py
[user@localhost ~]$ ls -lah /proc/5946/fd
total 0
dr-x------ 2 user user  0 Oct  8 11:27 .
dr-xr-xr-x 9 user user  0 Oct  8 11:27 ..
lrwx------ 1 user user 64 Oct  8 11:28 0 -> /dev/pts/22
lrwx------ 1 user user 64 Oct  8 11:28 1 -> /dev/pts/22
lrwx------ 1 user user 64 Oct  8 11:27 2 -> /dev/pts/22
l-wx------ 1 user user 64 Oct  8 11:28 3 -> /mnt/logs/123.txt

ファむルはすでに存圚しおおり、クリアする必芁がないため、すべおのフラグのうち O_WRONLY のみが必芁です。

[user@localhost ~]$ gdb -p 5946
...
(gdb) call open("/mnt/logs/megapipe", 00000001,0666)
$1 = 4
(gdb) shell ls -lah /proc/5946/fd
total 0
dr-x------ 2 user user  0 Oct  8 11:27 .
dr-xr-xr-x 9 user user  0 Oct  8 11:27 ..
lrwx------ 1 user user 64 Oct  8 11:28 0 -> /dev/pts/22
lrwx------ 1 user user 64 Oct  8 11:28 1 -> /dev/pts/22
lrwx------ 1 user user 64 Oct  8 11:27 2 -> /dev/pts/22
l-wx------ 1 user user 64 Oct  8 11:28 3 -> /mnt/logs/123.txt
l-wx------ 1 user user 64 Oct  8 14:20 4 -> /mnt/logs/megapipe
(gdb) call dup2(4,3)
$2 = 3
(gdb) shell ls -lah /proc/5946/fd
total 0
dr-x------ 2 user user  0 Oct  8 11:27 .
dr-xr-xr-x 9 user user  0 Oct  8 11:27 ..
lrwx------ 1 user user 64 Oct  8 11:28 0 -> /dev/pts/22
lrwx------ 1 user user 64 Oct  8 11:28 1 -> /dev/pts/22
lrwx------ 1 user user 64 Oct  8 11:27 2 -> /dev/pts/22
l-wx------ 1 user user 64 Oct  8 11:28 3 -> /mnt/logs/megapipe
l-wx------ 1 user user 64 Oct  8 14:20 4 -> /mnt/logs/megapipe
(gdb) call close(4)
$3 = 0
(gdb) shell ls -lah /proc/5946/fd
total 0
dr-x------ 2 user user  0 Oct  8 11:27 .
dr-xr-xr-x 9 user user  0 Oct  8 11:27 ..
lrwx------ 1 user user 64 Oct  8 11:28 0 -> /dev/pts/22
lrwx------ 1 user user 64 Oct  8 11:28 1 -> /dev/pts/22
lrwx------ 1 user user 64 Oct  8 11:27 2 -> /dev/pts/22
l-wx------ 1 user user 64 Oct  8 11:28 3 -> /mnt/logs/megapipe
(gdb) quit
A debugging session is active.

    Inferior 1 [process 5946] will be detached.

Quit anyway? (y or n) y
Detaching from program: /usr/bin/python2.7, process 5946

リモヌトサヌバヌremote-server.example.comの確認

[user@localhost ~]$ ls -lah 123.txt 
-rw-rw-r-- 1 user user 38M Oct  8 14:21 123.txt

デヌタが来おいたす。問題のあるサヌバヌを確認したす

[user@localhost ~]$ ls -lah /mnt/logs/
total 7.9M
drwxr-xr-x 2 user user 1.0K Oct  8 11:28 .
drwxr-xr-x 4 root     root     1.0K Oct  8 10:55 ..
-rw-rw-r-- 1 user user 7.9M Oct  8 14:17 123.txt
prw-rw-r-- 1 user user    0 Oct  8 14:22 megapipe

デヌタが保存され、問題が解決されたした。

この機䌚を利甚しお、Degiro の同僚にご挚拶させおいただきたす。
Radio-T ポッドキャストを聞いおください。

すべお良いです。

宿題ずしお、次のコマンドを実行した堎合に cat プロセスず sleep プロセスのファむル蚘述子に䜕が含たれるかを考えおみるこずを提案したす。

[user@localhost ~]$ cat /dev/zero 2>/dev/null| sleep 10000

出所 habr.com

コメントを远加したす