Misollar bilan Linuxda fayl deskriptori

Bir marta, suhbat chog'ida mendan so'rashdi, agar siz diskda bo'sh joy qolmagani sababli ishlamayotgan xizmatni topsangiz nima qilasiz?

Albatta, men bu joyni nima egallaganini ko'raman, iloji bo'lsa, tozalab beraman, deb javob berdim.
Keyin suhbatdosh so'radi, agar bo'limda bo'sh joy bo'lmasa-chi, lekin siz ham barcha joyni egallaydigan fayllarni ko'rmasangiz?

Bunga men aytdimki, siz har doim ochiq fayl identifikatorlarini, masalan, lsof buyrug'i bilan ko'rishingiz va qaysi dastur barcha mavjud bo'sh joyni egallaganini tushunishingiz mumkin, keyin esa ma'lumotlar kerak yoki yo'qligiga qarab, vaziyatga qarab harakat qilishingiz mumkin. .

Suhbatdosh so'nggi so'zda meni to'xtatib, o'z savoliga qo'shib qo'ydi: "Aytaylik, bizga ma'lumotlar kerak emas, bu shunchaki disk raskadrovka jurnali, lekin dastur ishlamayapti, chunki u disk raskadrovkani yoza olmaydi"?

"Yaxshi," deb javob berdim men, "biz dastur konfiguratsiyasida disk raskadrovkani o'chirib, uni qayta ishga tushirishimiz mumkin."
Suhbatdosh e'tiroz bildirdi: "Yo'q, biz dasturni qayta ishga tushira olmaymiz, bizda hali ham xotirada saqlangan muhim ma'lumotlar bor va muhim mijozlar xizmatning o'ziga ulangan, biz uni qayta ulanishga majburlay olmaymiz."

"Yaxshi," dedim men, "agar dasturni qayta ishga tushira olmasak va ma'lumotlar biz uchun muhim bo'lmasa, biz ls buyrug'ida ko'rmagan bo'lsak ham, bu ochiq faylni fayl identifikatori orqali tozalashimiz mumkin. fayl tizimida."

Suhbatdosh mamnun edi, lekin men emas.

Keyin o'yladim, nega mening bilimimni sinab ko'rayotgan odam chuqurroq qazmaydi? Ammo agar ma'lumotlar muhim bo'lsa-chi? Agar jarayonni qayta ishga tushira olmasak va jarayon bo'sh joy bo'lmagan bo'limda fayl tizimiga yozilsa-chi? Agar biz nafaqat allaqachon yozilgan ma'lumotlarni, balki ushbu jarayon yozadigan yoki yozishga harakat qiladigan ma'lumotlarni ham yo'qota olmasak-chi?

Tuzik

Faoliyatimning boshida men foydalanuvchi ma'lumotlarini saqlash uchun zarur bo'lgan kichik dastur yaratishga harakat qildim. Va keyin men foydalanuvchini uning ma'lumotlariga qanday moslashim mumkin deb o'yladim. Misol uchun, menda Ivanov Ivan Ivanovich bor va u ba'zi ma'lumotlarga ega, ammo ular bilan qanday qilib do'stlashish mumkin? To'g'ridan-to'g'ri ta'kidlashim mumkinki, "Tuzik" ismli it aynan shu Ivanga tegishli. Agar u ismini o'zgartirsa va Ivan o'rniga, masalan, Olya bo'lsa-chi? Keyin ma'lum bo'ladiki, bizning Olya Ivanovna Ivanova endi itga ega bo'lmaydi va bizning Tuzik hali ham mavjud bo'lmagan Ivanga tegishli bo'ladi. Har bir foydalanuvchiga noyob identifikator (ID) bergan ma'lumotlar bazasi bu muammoni hal qilishga yordam berdi va mening Tuzikim ushbu identifikatorga bog'langan edi, bu aslida seriya raqami edi. Shunday qilib, ace egasining ID raqami 2 bor edi va bir muncha vaqt Ivan bu ID ostida edi, keyin Olya xuddi shu ID ostida bo'ldi. Insoniyat va chorvachilik muammosi amalda hal qilindi.

Fayl deskriptori

Fayl va ushbu fayl bilan ishlaydigan dastur muammosi bizning itimiz va odamimizniki bilan taxminan bir xil. Aytaylik, men ivan.txt nomli faylni ochdim va unga tuzik so'zini yozishni boshladim, lekin faylga faqat birinchi "t" harfini yozishga muvaffaq bo'ldim va bu faylni kimdir, masalan, olya.txt deb o'zgartirdi. Ammo fayl bir xil bo'lib qoladi va men hali ham unda o'z acemni yozib olishni xohlayman. Har safar fayl tizim chaqiruvi bilan ochilganda ochiq har qanday dasturlash tilida men faylga ishora qiluvchi noyob identifikatorni olaman, bu identifikator fayl deskriptoridir. Va bundan keyin bu fayl bilan kim nima qilishi muhim emas, uni o'chirish, nomini o'zgartirish, egasini o'zgartirish yoki o'qish va yozish huquqlari olib qo'yilishi mumkin, men hali ham kirish huquqiga egaman. unga, chunki faylni ochish vaqtida men uni o'qish va/yoki yozish huquqiga ega bo'ldim va u bilan ishlashga muvaffaq bo'ldim, demak, buni davom ettirishim kerak.

Linuxda libc kutubxonasi har bir ishlayotgan dastur (jarayon) uchun 3 raqamlangan 0,1,2 ta deskriptor faylini ochadi. Batafsil ma'lumotni havolalarda topishingiz mumkin man stdio ΠΈ man stdout

  • Fayl identifikatori 0 STDIN deb ataladi va dastur kiritish bilan bog'lanadi
  • 1-fayl identifikatori STDOUT deb ataladi va ilovalar tomonidan chop etish buyruqlari kabi ma'lumotlarni chiqarish uchun ishlatiladi
  • Fayl identifikatori 2 STDERR deb nomlanadi va ilovalar tomonidan xato xabarlarini chiqarish uchun ishlatiladi.

Agar dasturingizda o'qish yoki yozish uchun biron bir faylni ochsangiz, siz birinchi bepul identifikatorni olasiz va u 3-raqam bo'ladi.

Agar siz uning PID-ni bilsangiz, har qanday jarayon uchun fayl identifikatorlari ro'yxatini ko'rish mumkin.

Misol uchun, bash konsolini ochamiz va jarayonimizning PID-ni ko'rib chiqamiz

[user@localhost ]$ echo $$
15771

Ikkinchi konsolda ishga tushamiz

[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

Ushbu maqolaning maqsadlari uchun 255-sonli fayl deskriptorini e'tiborsiz qoldirishingiz mumkin; u o'z ehtiyojlari uchun bog'langan kutubxona tomonidan emas, balki bash tomonidan ochilgan.

Endi barcha 3 ta deskriptor fayli psevdo terminal qurilmasi bilan bog'langan /dev/pts, lekin biz hali ham ularni manipulyatsiya qilishimiz mumkin, masalan, ularni ikkinchi konsolda ishga tushirish

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

Va birinchi konsolda biz ko'ramiz

[user@localhost ]$ hello world

Qayta yo'naltirish va quvur

Siz ushbu 3 ta identifikator faylini istalgan jarayonda, shu jumladan bash da, masalan, ikkita jarayonni birlashtiruvchi quvur orqali osongina bekor qilishingiz mumkin, qarang.

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

Ushbu buyruqni o'zingiz bajarishingiz mumkin strace -f va ichkarida nima bo'layotganini ko'ring, lekin men sizga qisqacha aytib beraman.

PID 15771 bilan ota-ona bash jarayoni bizning buyruqni tahlil qiladi va biz qancha buyruqni bajarishni xohlayotganimizni aniq tushunadi, bizning holatlarimizda ulardan ikkitasi bor: mushuk va uyqu. Bash ikkita bola jarayonini yaratishi va ularni bitta quvurga birlashtirishi kerakligini biladi. Hammasi bo'lib, bash uchun 2 ta bola jarayoni va bitta quvur kerak bo'ladi.

Bash bolalar jarayonlarini yaratishdan oldin tizim chaqiruvini ishga tushiradi quvur va vaqtinchalik quvur buferida yangi fayl identifikatorlarini oladi, lekin bu bufer hali bizning ikkita asosiy jarayonimizni bog'lamaydi.

Ota-ona jarayoni uchun allaqachon quvur borga o'xshaydi, lekin hali hech qanday bola jarayonlari yo'q:

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

Keyin tizim chaqiruvidan foydalaning klon bash ikkita bola jarayonini yaratadi va bizning uchta jarayonimiz quyidagicha ko'rinadi:

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

Shuni unutmangki, klon jarayonni barcha fayl identifikatorlari bilan birga klonlaydi, shuning uchun ular ota-ona va bolalarda bir xil bo'ladi. PID 15771 bilan ota-ona jarayonining vazifasi bolalar jarayonlarini kuzatishdir, shuning uchun u bolalardan javob kutadi.

Shuning uchun u quvurga muhtoj emas va u 3 va 4 raqamli fayl deskriptorlarini yopadi.

PID 9004 bilan birinchi bolali bash jarayonida tizim chaqiruvi dup2, STDOUT fayl identifikatorimiz raqami 1ni quvurga ishora qiluvchi fayl identifikatoriga o'zgartiradi, bizning holatda bu raqam 3. Shunday qilib, PID 9004 bilan birinchi bola jarayoni STDOUTga yozgan hamma narsa avtomatik ravishda quvur buferida tugaydi.

PID 9005 bilan ikkinchi bola jarayonida bash fayl identifikatori STDIN raqamini o'zgartirish uchun dup2 dan foydalanadi. Endi PID 0 bilan ikkinchi bash o'qiydigan hamma narsa quvurdan o'qiladi.

Shundan so'ng, 3 va 4-raqamli fayl deskriptorlari ham bolalar jarayonlarida yopiladi, chunki ular endi ishlatilmaydi.

Men 255-fayl identifikatorini ataylab e'tiborsiz qoldiraman; u bash tomonidan ichki maqsadlarda ishlatiladi va shuningdek, bolalar jarayonlarida yopiladi.

Keyinchalik, PID 9004 bilan birinchi bola jarayonida bash tizim chaqiruvidan foydalanishni boshlaydi exec Biz buyruq satrida ko'rsatgan bajariladigan fayl, bizning holatlarimizda bu /usr/bin/cat.

PID 9005 bilan ikkinchi bola jarayonida bash biz ko'rsatgan ikkinchi bajariladigan faylni ishga tushiradi, bizning holatlarimizda /usr/bin/sleep.

Exec tizim chaqiruvi, agar ochiq qo'ng'iroq qilingan vaqtda O_CLOEXEC bayrog'i bilan ochilmagan bo'lsa, fayl tutqichlarini yopmaydi. Bizning holatda, bajariladigan fayllarni ishga tushirgandan so'ng, barcha joriy fayl identifikatorlari saqlanadi.

Konsolda tekshiring:

[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

Ko'rib turganingizdek, quvurimizning noyob soni ikkala jarayonda ham bir xil. Shunday qilib, biz bir xil ota-ona bilan ikki xil jarayon o'rtasida aloqaga egamiz.

Bash ishlatadigan tizim qo'ng'iroqlari bilan tanish bo'lmaganlar uchun men buyruqlarni strace orqali bajarishni va ichki nima sodir bo'layotganini ko'rishni tavsiya qilaman, masalan:

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

Keling, diskda bo'sh joy tugashi va jarayonni qayta boshlamasdan ma'lumotlarni saqlashga harakat qilish muammomizga qaytaylik. Diskka sekundiga taxminan 1 megabayt yozadigan kichik dastur yozamiz. Bundan tashqari, agar biron sababga ko'ra biz diskka ma'lumot yoza olmasak, biz buni e'tiborsiz qoldiramiz va ma'lumotlarni bir soniya ichida qayta yozishga harakat qilamiz. Men Python dan foydalanayotgan misolda siz istalgan boshqa dasturlash tilidan foydalanishingiz mumkin.

[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

Keling, dasturni ishga tushiramiz va fayl deskriptorlarini ko'rib chiqamiz

[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

Ko'rib turganingizdek, bizda 3 ta standart fayl identifikatorlari va biz ochgan yana bitta fayl mavjud. Fayl hajmini tekshiramiz:

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

Ma'lumotlar yozilmoqda, biz fayldagi ruxsatlarni o'zgartirishga harakat qilamiz:

[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

Bizning foydalanuvchimiz faylga yozish uchun ruxsatga ega bo'lmasa ham, ma'lumotlar hali ham yozilayotganini ko'ramiz. Keling, uni olib tashlashga harakat qilaylik:

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

Ma'lumotlar qayerda yozilgan? Va ular umuman yozilganmi? Biz tekshiramiz:

[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)

Ha, bizning fayl identifikatorimiz hali ham mavjud va biz bu fayl deskriptorini eski faylimiz kabi ko'rib chiqishimiz, uni o'qishimiz, tozalashimiz va nusxalashimiz mumkin.

Keling, fayl hajmini ko'rib chiqaylik:

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

Fayl hajmi 19923457. Faylni tozalashga harakat qilaylik:

[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

Ko'rib turganingizdek, fayl hajmi faqat ortib bormoqda va bizning magistralimiz ishlamadi. Keling, tizim chaqiruvi hujjatlarini ko'rib chiqaylik ochiq. Agar faylni ochishda O_APPEND bayrog'idan foydalansak, u holda har bir yozishda operatsion tizim fayl hajmini tekshiradi va ma'lumotlarni faylning eng oxirigacha yozadi va buni atomik tarzda bajaradi. Bu bir xil faylga bir nechta mavzu yoki jarayonlarni yozish imkonini beradi. Lekin bizning kodimizda biz bu bayroqdan foydalanmaymiz. Agar biz faylni qo'shimcha yozish uchun ochsakgina, lsof-da trunk-dan keyin boshqa fayl hajmini ko'rishimiz mumkin, bu o'rniga bizning kodimizda

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

qo'yishimiz kerak

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

"W" belgisi bilan tekshirish

[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

va "a" bayrog'i bilan

[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

Ishlayotgan jarayonni dasturlash

Ko'pincha dasturchilar dasturlarni yaratish va sinovdan o'tkazishda nosozliklarni tuzatuvchilardan (masalan, GDB) yoki dasturda turli darajadagi kirishlardan foydalanadilar. Linux allaqachon ishlayotgan dasturni aslida yozish va o'zgartirish imkoniyatini beradi, masalan, o'zgaruvchilar qiymatlarini o'zgartirish, to'xtash nuqtasini o'rnatish va hokazo.

Fayl yozish uchun disk maydoni etarli emasligi haqidagi asl savolga qaytsak, muammoni simulyatsiya qilishga harakat qilaylik.

Keling, bo'limimiz uchun alohida disk sifatida o'rnatadigan fayl yarataylik:

[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 ~]$

Fayl tizimini yaratamiz:

[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 ~]$

Fayl tizimini o'rnating:

[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

Biz egasi bilan katalog yaratamiz:

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

Faylni faqat dasturimizda yozish uchun ochamiz:

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

Ishga tushirish

[user@localhost ]$ python openforwrite.py 

Biz bir necha soniya kutamiz

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

Shunday qilib, bizda ushbu maqolaning boshida tasvirlangan muammo bor. Bo'sh joy 0, 100% band.

Vazifa shartlariga ko'ra, biz yo'qotib bo'lmaydigan juda muhim ma'lumotlarni yozib olishga harakat qilayotganimizni eslaymiz. Va shu bilan birga, jarayonni qayta boshlamasdan xizmatni tuzatishimiz kerak.

Aytaylik, bizda hali ham disk maydoni bor, lekin boshqa bo'limda, masalan, /home.

Keling, kodimizni "tezda qayta dasturlashga" harakat qilaylik.

Keling, barcha disk maydonini egallab olgan jarayonimizning PID-ni ko'rib chiqaylik:

[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

Jarayonga gdb orqali ulaning

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

Keling, ochiq fayl deskriptorlarini ko'rib chiqaylik:

(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

Bizni qiziqtirgan 3-sonli fayl deskriptori haqidagi ma'lumotlarni ko'rib chiqamiz

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

Python qanday tizim chaqiruvini amalga oshirishini yodda tutgan holda (yuqoriga qarang, biz strace-ni ishga tushirganimiz va ochiq qo'ng'iroqni topdik), faylni ochish uchun kodimizni qayta ishlashda biz o'z jarayonimiz nomidan xuddi shunday qilamiz, lekin bizga O_WRONLY|O_CREAT| O_TRUNC bitlari raqamli qiymat bilan almashtiriladi. Buni amalga oshirish uchun, masalan, yadro manbalarini oching shu yerda va qaysi bayroqlar nima uchun javobgar ekanligini ko'ring

#O_WRONLY 00000001 ni aniqlang
#O_CREAT 00000100 ni aniqlang
#O_TRUNC 00001000 ni aniqlang

Biz barcha qiymatlarni bittaga birlashtiramiz, biz 00001101 ni olamiz

Biz qo'ng'iroqni gdb dan bajaramiz

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

Shunday qilib, biz 4-raqamli yangi fayl deskriptorini va boshqa bo'limda yangi ochiq faylni oldik, biz tekshiramiz:

(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

Biz quvur bilan misolni eslaymiz - bash fayl identifikatorlarini qanday o'zgartiradi va biz allaqachon dup2 tizim chaqiruvini o'rgandik.

Biz bitta fayl deskriptorini boshqasiga almashtirishga harakat qilamiz

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

Biz tekshiramiz:

(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

Biz 4-fayl deskriptorini yopamiz, chunki bu bizga kerak emas:

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

Va gdb dan chiqing

(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

Yangi fayl tekshirilmoqda:

[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

Ko'rib turganingizdek, ma'lumotlar yangi faylga yozilgan, eskisini tekshiramiz:

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

Hech qanday ma'lumot yo'qolmaydi, dastur ishlaydi, jurnallar yangi joyga yoziladi.

Keling, vazifani biroz murakkablashtiramiz

Tasavvur qilaylik, ma'lumotlar biz uchun muhim, ammo bizda hech qanday bo'limda disk maydoni yo'q va biz diskni ulay olmaymiz.

Biz qila oladigan narsa ma'lumotlarimizni biror joyga, masalan, quvurga yo'naltirish va o'z navbatida ma'lumotlarni quvurdan tarmoqqa ba'zi dastur, masalan, netcat orqali yo'naltirishdir.
Biz mkfifo buyrug'i bilan nomlangan quvur yaratishimiz mumkin. U fayl tizimida bo'sh joy bo'lmasa ham, psevdo fayl yaratadi.

Ilovani qayta ishga tushiring va tekshiring:

[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

Diskda bo'sh joy yo'q, lekin biz u erda nomli quvurni muvaffaqiyatli yaratamiz:

[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

Endi biz qandaydir tarzda ushbu quvurga kiradigan barcha ma'lumotlarni tarmoq orqali boshqa serverga o'rashimiz kerak; buning uchun xuddi shu netcat mos keladi.

Remote-server.example.com serverida biz ishga tushiramiz

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

Muammoli serverimizda biz alohida terminalda ishga tushiramiz

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

Endi quvurda tugaydigan barcha ma'lumotlar avtomatik ravishda netcat-dagi stdin-ga o'tadi va u uni 7777 portidagi tarmoqqa yuboradi.

Biz qilishimiz kerak bo'lgan narsa ma'lumotlarimizni ushbu nomli quvurga yozishni boshlashdir.

Bizda allaqachon ishlayotgan dastur mavjud:

[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

Barcha bayroqlardan bizga faqat O_WRONLY kerak, chunki fayl allaqachon mavjud va biz uni tozalashimiz shart emas.

[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

masofaviy server remote-server.example.com tekshirilmoqda

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

Ma'lumotlar kelmoqda, muammoli serverni tekshiramiz

[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

Ma'lumotlar saqlanadi, muammo hal qilinadi.

Fursatdan foydalanib, Degirodagi hamkasblarimga salom aytaman.
Radio-T podkastlarini tinglang.

Hamma yaxshi.

Uy vazifasi sifatida, agar siz quyidagi buyruqni bajarsangiz, mushuk va uyqu identifikatorlari jarayoni faylida nima bo'lishi haqida o'ylashni taklif qilaman:

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

Manba: www.habr.com

a Izoh qo'shish