Suatu kali, dalam sebuah wawancara, mereka bertanya kepada saya apa yang akan Anda lakukan jika Anda menemukan layanan yang tidak berfungsi karena disk sudah kehabisan ruang?
Tentu saja, saya menjawab bahwa saya akan melihat apa yang ditempati tempat ini dan, jika mungkin, saya akan membersihkan tempat itu.
Kemudian pewawancara bertanya, bagaimana jika tidak ada ruang kosong di bagian itu, tetapi Anda juga tidak melihat file yang akan menempati seluruh tempat?
Untuk ini, saya mengatakan bahwa Anda selalu dapat melihat deskriptor file terbuka, misalnya dengan perintah lsof dan memahami aplikasi mana yang mengambil semua ruang yang tersedia, dan kemudian Anda dapat melanjutkan sesuai dengan keadaan, tergantung pada apakah data diperlukan.
Pewawancara menyela saya di kata terakhir, menambahkan pertanyaan saya: "Misalkan kita tidak membutuhkan data, itu hanya log debug, tetapi aplikasi tidak bekerja karena tidak dapat merekam debug"?
"Oke," jawab saya, "kita bisa mematikan debug di konfigurasi aplikasi dan memulai kembali."
Pewawancara keberatan: "Tidak, kami tidak dapat memulai ulang aplikasi, data penting masih tersimpan dalam memori kami, dan klien penting terhubung ke layanan itu sendiri, yang kami tidak dapat memaksa untuk menyambung kembali".
"Ya," kataku, "jika kita tidak bisa memulai ulang aplikasi dan datanya tidak penting bagi kita, maka kita bisa menghapus file terbuka ini melalui deskriptor file, bahkan jika kita tidak melihatnya dalam perintah ls pada sistem file."
Pewawancara merasa senang, tetapi saya tidak.
Lalu saya berpikir, mengapa orang yang menguji pengetahuan saya tidak menggali lebih dalam? Tetapi bagaimana jika datanya masih penting? Bagaimana jika kita tidak dapat memulai ulang proses, dan pada saat yang sama proses ini menulis ke sistem file di bagian di mana tidak ada ruang kosong? Bagaimana jika kita tidak bisa kehilangan tidak hanya data yang sudah direkam, tetapi juga data yang ditulis atau coba direkam oleh proses ini?
Tuzik
Di awal karir saya, saya mencoba membuat aplikasi kecil yang di dalamnya diperlukan untuk menyimpan informasi tentang pengguna. Dan kemudian saya berpikir, bagaimana saya bisa memetakan pengguna ke datanya. Sebagai contoh, saya memiliki Ivan Ivanov Ivanich, dan dia memiliki beberapa data, tetapi bagaimana cara berteman dengan mereka? Saya dapat langsung menunjukkan bahwa anjing bernama "Tuzik" milik Ivan ini. Tetapi bagaimana jika dia mengubah namanya dan bukannya Ivan menjadi, misalnya, Olya? Kemudian ternyata bahwa Olya Ivanovna Ivanova kita tidak akan lagi memiliki anjing, dan Tuzik kita akan tetap milik Ivan yang tidak ada. Basis data ini dibantu oleh basis data yang memberi setiap pengguna pengidentifikasi unik (ID), dan Tuzik saya dilampirkan pada ID ini, yang, pada kenyataannya, hanyalah nomor urut. Jadi, pemilik tuzik dengan ID nomor 2, dan pada suatu waktu Ivan berada di bawah ID ini, dan kemudian Olya menjadi ID yang sama. Masalah kemanusiaan dan peternakan telah dipecahkan secara praktis.
Deskriptor file
Masalah file dan program yang bekerja dengan file ini hampir sama dengan masalah anjing dan manusia kita. Misalkan saya membuka file dengan nama ivan.txt dan mulai menulis kata tuzik ke dalamnya, tetapi berhasil menulis hanya huruf pertama "t" ke file, dan file ini diganti namanya oleh seseorang, misalnya, olya.txt. Tetapi file tersebut tetap sama, dan saya masih ingin menulis kartu as saya di dalamnya. Setiap kali saya membuka file dengan panggilan sistem terbuka dalam bahasa pemrograman apa pun, saya mendapatkan ID unik yang mengarahkan saya ke file, ID ini adalah deskriptor file. Dan tidak masalah apa yang dilakukan orang selanjutnya dengan file ini, mereka dapat menghapusnya, mereka dapat mengganti nama, mereka dapat mengubah pemilik atau menghapus izin baca dan tulis, saya masih akan memiliki akses ke sana, karena pada saat file dibuka, Saya memiliki hak untuk membaca dan / atau menulisnya, dan saya berhasil mulai bekerja dengannya, yang berarti saya harus terus melakukan ini.
Di Linux, perpustakaan libc terbuka untuk setiap aplikasi yang sedang berjalan (proses) 3 file deskriptor, dengan angka 0,1,2. Anda dapat menemukan informasi lebih lanjut di tautan
man stdio dan
man stdout- Deskriptor file 0 disebut STDIN dan dikaitkan dengan input data dari aplikasi
- Deskriptor file 1 disebut STDOUT dan digunakan oleh aplikasi untuk menampilkan data, misalnya, perintah cetak
- File descriptor 2 disebut STDERR dan digunakan oleh aplikasi untuk menghasilkan data pelaporan kesalahan.
Jika dalam program Anda Anda membuka file untuk membaca atau menulis, maka kemungkinan besar Anda akan mendapatkan ID gratis pertama dan ini akan menjadi nomor 3.
Daftar file deskriptor dapat dilihat dari proses apa pun jika Anda mengetahui PID-nya.
Misalnya, buka konsol dengan bash dan lihat PID proses kami
[user@localhost ]$ echo $$ 15771
Di konsol kedua, jalankan
[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
Anda dapat dengan aman mengabaikan file deskriptor nomor 255 dalam kerangka artikel ini, dibuka untuk kebutuhan Anda dengan bash sendiri, dan bukan oleh pustaka yang ditautkan.
Sekarang semua 3 file deskriptor dikaitkan dengan perangkat pseudo-terminal
/ dev / pts , tetapi kita masih dapat memanipulasi mereka, misalnya, berjalan di konsol kedua
[user@localhost ]$ echo "hello world" > /proc/15771/fd/0
Dan di konsol pertama kita akan lihat
[user@localhost ]$ hello world
Redirect dan Pipe
Anda dapat dengan mudah mengganti 3 file deskriptor ini dalam proses apa pun, termasuk dalam bash, misalnya, melalui pipa yang menghubungkan dua proses, lihat
[user@localhost ]$ cat /dev/zero | sleep 10000
Anda dapat menjalankan perintah ini sendiri dengan
strace -f dan melihat apa yang terjadi di dalamnya, tetapi saya akan memberi tahu Anda secara singkat.
Proses induk kami bash dengan PID 15771 mem-parsing perintah kami dan mengerti persis berapa banyak perintah yang ingin kami jalankan, dalam kasus kami ada dua: kucing dan tidur. Bash tahu bahwa ia perlu membuat dua proses anak, dan menggabungkannya dengan satu pipa. Total bash akan membutuhkan 2 proses anak dan satu pipa.
Sebelum membuat proses anak, bash meluncurkan pemanggilan sistem
pipa dan menerima deskriptor file baru untuk buffer pipa sementara, tetapi buffer ini belum mengikat kedua proses anak kami.
Untuk proses induk, sepertinya pipa sudah ada, dan belum ada proses anak:
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
Kemudian, menggunakan system call,
clone bash menciptakan dua proses anak, dan tiga proses kami akan terlihat seperti ini:
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
Jangan lupa bahwa klon mengkloning proses bersama dengan semua deskriptor file, sehingga mereka akan sama dalam proses induk dan yang anak. Tugas proses induk dengan PID 15771 adalah untuk memantau proses anak, sehingga hanya menunggu respons dari proses anak.
Karena itu, ia tidak perlu pipa, dan ia menutup file deskriptor dengan angka 3 dan 4.
Dalam proses bash child pertama dengan PID 9004, panggilan sistem
dup2 , mengubah deskriptor file STDOUT kami dengan nomor 1 menjadi deskriptor file yang menunjuk ke pipa, dalam kasus kami ini adalah nomor 3. Dengan demikian, segala yang diproses oleh anak pertama dengan PID 9004 akan menulis ke STDOUT secara otomatis akan jatuh ke dalam buffer pipa.
Dalam proses anak kedua dengan PID 9005, bash mengubah deskriptor file STDIN dengan angka 0 menggunakan dup2. Sekarang semua yang dibaca bash kedua dengan PID 9005 akan dibaca dari pipa.
Setelah itu, deskriptor dengan angka 3 dan 4 juga ditutup dalam proses anak, karena mereka tidak lagi digunakan.
Saya sengaja mengabaikan file deskriptor 255, ini menggunakan bash untuk kebutuhan internal dan juga akan ditutup dalam proses anak.
Selanjutnya, dalam proses anak pertama dengan PID 9004, bash memulai file yang dapat dieksekusi yang kami tentukan pada baris perintah dengan
exec panggilan sistem, dalam kasus kami adalah / usr / bin / cat.
Dalam proses anak kedua dengan PID 9005, bash memulai file eksekusi kedua yang kami tentukan, dalam kasus kami adalah / usr / bin / sleep.
Panggilan sistem exec tidak menutup deskriptor file jika tidak dibuka dengan tanda O_CLOEXEC selama panggilan terbuka. Dalam kasus kami, setelah menjalankan file yang dapat dieksekusi, semua deskriptor file saat ini akan disimpan.
Periksa di konsol:
[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
Seperti yang Anda lihat, jumlah unik pipa kami adalah sama di kedua proses. Jadi kami memiliki koneksi antara dua proses yang berbeda dengan satu orangtua.
Bagi mereka yang tidak terbiasa dengan panggilan sistem yang menggunakan bash, saya sangat merekomendasikan menjalankan perintah melalui strace dan melihat apa yang terjadi di dalam, misalnya, seperti ini:
strace -s 1024 -f bash -c "ls | grep hello"
Mari kita kembali ke masalah kita dengan kehabisan ruang disk dan mencoba untuk menyimpan data tanpa memulai kembali prosesnya. Mari kita menulis sebuah program kecil yang akan menulis ke disk sekitar 1 megabyte per detik. Selain itu, jika karena alasan tertentu kami tidak dapat menulis data ke disk, kami hanya akan mengabaikannya dan mencoba untuk menulis data lagi setelah satu detik. Dalam contoh saya menggunakan Python, Anda bisa menggunakan bahasa pemrograman lain.
[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
Jalankan program dan lihat deskriptor file
[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
Seperti yang Anda lihat, kami memiliki 3 file deskriptor standar dan satu lagi yang kami buka. Periksa ukuran file:
[user@localhost ]$ ls -lah 123.txt -rw-rw-r-- 1 user user 117M Oct 7 16:30 123.txt
data sedang ditulis, coba ubah izin file:
[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
Kami melihat bahwa data masih ditulis, meskipun pengguna kami tidak memiliki hak untuk menulis ke file. Mari kita coba hapus:
[user@localhost ]$ sudo rm 123.txt [user@localhost ]$ ls 123.txt ls: cannot access 123.txt: No such file or directory
Di mana data ditulis? Dan apakah semuanya itu ditulis? Kami memeriksa:
[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)
Ya, file deskriptor kami masih ada, dan kami dapat bekerja dengan file deskriptor ini seperti halnya file lama kami, kami dapat membaca, membersihkan, dan menyalinnya.
Kami melihat ukuran file:
[user@localhost ]$ lsof | grep 123.txt python 31083 user 3w REG 8,5 19923457 2621522 /home/user/123.txt
Ukuran file 19923457. Mencoba menghapus file:
[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
Seperti yang Anda lihat, ukuran file hanya meningkat dan trankate kami tidak berfungsi. Lihat dokumentasi untuk panggilan sistem
terbuka . Jika kita menggunakan flag O_APPEND saat membuka file, maka setiap kali sistem operasi memeriksa ukuran file dan menulis data hingga akhir file, ia melakukan ini secara atomis. Ini memungkinkan beberapa utas atau proses untuk menulis ke file yang sama. Namun dalam kode kami, kami tidak menggunakan bendera ini. Kita dapat melihat ukuran file yang berbeda di lsof setelah trankate hanya jika kita membuka file untuk rekaman tambahan, yang berarti bahwa alih-alih dalam kode kita
with open("123.txt", "w") as f:
kita harus meletakkan
with open("123.txt", "a") as f:
Memeriksa dengan tanda "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
dan dengan bendera "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
Memprogram proses yang sudah berjalan
Seringkali, programmer menggunakan debugger (misalnya GDB) atau berbagai level logging dalam aplikasi saat membuat dan menguji program. Linux menyediakan kemampuan untuk benar-benar menulis dan mengubah program yang sudah berjalan, misalnya mengubah nilai variabel, mengatur breakpoint, dll., Dll.
Kembali ke pertanyaan awal dengan ruang disk yang tidak cukup untuk menulis file, kami akan mencoba meniru masalahnya.
Buat file untuk partisi kami, yang akan kami pasang sebagai disk terpisah:
[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 ~]$
Buat sistem file:
[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 ~]$
Pasang sistem file:
[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
Buat direktori dengan pemilik kami:
[user@localhost ~]$ sudo mkdir /mnt/logs [user@localhost ~]$ sudo chown user: /mnt/logs
Kami membuka file hanya untuk menulis di program kami:
with open("/mnt/logs/123.txt", "w") as f:
Kami meluncurkan
[user@localhost ]$ python openforwrite.py
Menunggu beberapa detik
[user@localhost ~]$ df -h | grep mnt /dev/loop0 8.7M 8.0M 0 100% /mnt
Jadi, kami mendapatkan masalah yang dijelaskan di awal artikel ini. Ruang bebas 0, ditempati 100%.
Kami ingat bahwa sesuai dengan kondisi tugas, kami mencoba untuk merekam data yang sangat penting yang tidak dapat hilang. Dan pada saat yang sama kita perlu memperbaiki layanan tanpa memulai kembali prosesnya.
Misalkan kita masih memiliki ruang disk, tetapi di partisi yang berbeda, misalnya di / home.
Mari kita coba "memprogram ulang dengan cepat" kode kita.
Kami melihat PID dari proses kami, yang memakan semua ruang disk:
[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
Kami terhubung ke proses melalui gdb
[user@localhost ~]$ gdb -p 10078 ... (gdb)
Kami melihat deskriptor file terbuka:
(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
Kami melihat informasi tentang file descriptor dengan nomor 3, yang menarik minat kami
(gdb) shell cat /proc/10078/fdinfo/3 pos: 8189952 flags: 0100001 mnt_id: 482
Mengingat apa jenis panggilan sistem yang dibuat oleh Python (lihat di atas, di mana kami menjalankan strace dan menemukan panggilan terbuka), saat memproses kode kami untuk membuka file, kami melakukan hal yang sama atas nama kami sendiri, tetapi kami memerlukan bit O_WRONLY | O_CREAT | O_TRUNC ganti dengan nilai numerik. Untuk melakukan ini, buka sumber kernel, misalnya, di
sini dan lihat flag apa yang bertanggung jawab atas apa
#define O_WRONLY 00000001
#define O_CREAT 00000100
#define O_TRUNC 00001000
Kami menggabungkan semua nilai menjadi satu, kami mendapatkan 00001101
Jalankan panggilan kami dari gdb
(gdb) call open("/home/user/123.txt", 00001101,0666) $1 = 4
Jadi kami mendapat file deskriptor baru dengan nomor 4 dan file terbuka baru di bagian lain, periksa:
(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
Kita ingat contoh pipa - bagaimana bash mengubah deskriptor file, dan telah mempelajari panggilan sistem dup2.
Kami mencoba mengganti satu deskriptor file dengan yang lainnya
(gdb) call dup2(4,3) $2 = 3
Kami memeriksa:
(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
Kami menutup file descriptor 4, karena kami tidak memerlukannya:
(gdb) call close (4) $1 = 0
Dan keluar 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
Periksa file baru:
[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
Seperti yang Anda lihat, data ditulis ke file baru, kami memeriksa yang lama:
[user@localhost ~]$ ls -lah /mnt/logs/123.txt -rw-rw-r-- 1 user user 7.9M Oct 8 11:08 /mnt/logs/123.txt
Data tidak hilang, aplikasi berfungsi, log ditulis ke tempat baru.
Mari kita sedikit menyulitkan tugas
Bayangkan bahwa data itu penting bagi kami, tetapi kami tidak memiliki ruang disk di salah satu bagian dan kami tidak dapat menghubungkan disk.
Apa yang dapat kita lakukan adalah mengarahkan ulang data kita di suatu tempat, misalnya ke pipa, dan data dari pipa, pada gilirannya, mengarahkan kembali ke jaringan melalui beberapa program, misalnya netcat.
Kita dapat membuat pipa bernama dengan perintah mkfifo. Ini akan membuat file pseudo pada sistem file, bahkan jika tidak ada ruang kosong di dalamnya.
Kami me-restart aplikasi, dan memeriksa:
[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
Tidak ada ruang disk, tetapi kami berhasil membuat pipa bernama di sana:
[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
Sekarang kita perlu membungkus semua data yang masuk ke pipa ini ke server lain melalui jaringan, untuk ini semua netcat yang sama akan dilakukan.
Di server remote-server.example.com, jalankan
[user@localhost ~]$ nc -l 7777 > 123.txt
Di server bermasalah kami, jalankan di terminal terpisah
[user@localhost ~]$ nc remote-server.example.com 7777 < /mnt/logs/megapipe
Sekarang semua data yang masuk ke pipa akan secara otomatis pergi ke stdin di netcat, yang akan mengirimkannya ke jaringan pada port 7777.
Yang harus kita lakukan adalah mulai menulis data kita ke dalam pipa bernama ini.
Kami sudah memiliki aplikasi yang berjalan:
[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
Dari semua flag, kita hanya perlu O_WRONLY karena file sudah ada dan kita tidak perlu menghapusnya
[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
Memeriksa server jarak jauh remote-server.example.com
[user@localhost ~]$ ls -lah 123.txt -rw-rw-r-- 1 user user 38M Oct 8 14:21 123.txt
Data masuk, kami memeriksa server masalah
[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
Data disimpan, masalah teratasi.
Saya mengambil kesempatan ini untuk menyampaikan salam saya kepada kolega saya di Degiro.
Dengarkan podcast Radio T.
Baik untuk semua
Sebagai pekerjaan rumah, saya mengusulkan untuk memikirkan apa yang akan ada dalam file deskriptor proses kucing dan tidur jika Anda menjalankan perintah ini:
[user@localhost ~]$ cat /dev/zero 2>/dev/null| sleep 10000