Maelezo ya faili katika Linux na mifano

Mara moja, wakati wa mahojiano, niliulizwa, utafanya nini ikiwa unapata huduma haifanyi kazi kutokana na ukweli kwamba disk imekwisha nafasi?

Bila shaka, nilijibu kwamba nitaona kilichokaliwa na mahali hapa na, ikiwezekana, ningesafisha mahali hapo.
Kisha mhojiwaji akauliza, je, ikiwa hakuna nafasi ya bure kwenye kizigeu, lakini pia huoni faili zozote ambazo zitachukua nafasi yote?

Kwa hili nilisema kwamba unaweza kutazama maelezo ya faili wazi kila wakati, kwa mfano na lsof amri, na kuelewa ni programu gani imechukua nafasi yote inayopatikana, na kisha unaweza kuchukua hatua kulingana na hali, kulingana na ikiwa data inahitajika. .

Mhojiwa alinizuia kwa neno la mwisho, akiongeza kwa swali lake: "Tuseme hatuhitaji data, ni logi ya utatuzi tu, lakini programu haifanyi kazi kwa sababu haiwezi kuandika utatuzi"?

"Sawa," nilijibu, "tunaweza kuzima utatuzi katika usanidi wa programu na kuianzisha tena."
Mhojiwa alipinga: "Hapana, hatuwezi kuanzisha upya programu, bado tuna data muhimu iliyohifadhiwa kwenye kumbukumbu, na wateja muhimu wameunganishwa kwenye huduma yenyewe, ambayo hatuwezi kulazimisha kuunganisha tena."

"sawa," nilisema, "ikiwa hatuwezi kuanzisha tena programu na data sio muhimu kwetu, basi tunaweza kufuta faili hii wazi kupitia maelezo ya faili, hata ikiwa hatuioni kwenye ls amri. kwenye mfumo wa faili."

Mhojiwa alifurahi, lakini sikufurahi.

Kisha nikafikiria, kwa nini mtu anayejaribu ujuzi wangu asichimbue zaidi? Lakini vipi ikiwa data ni muhimu baada ya yote? Je, ikiwa hatuwezi kuanzisha upya mchakato, na mchakato unaandika kwa mfumo wa faili kwenye kizigeu ambacho hakina nafasi ya bure? Je, ikiwa hatuwezi kupoteza sio tu data ambayo tayari imeandikwa, lakini pia data ambayo mchakato huu unaandika au unajaribu kuandika?

Tuzik

Mapema katika kazi yangu, nilijaribu kuunda programu ndogo ambayo inahitajika kuhifadhi maelezo ya mtumiaji. Na kisha nikafikiria, ninawezaje kulinganisha mtumiaji na data yake. Kwa mfano, nina Ivanov Ivan Ivanovich, na ana habari fulani, lakini ninawezaje kufanya urafiki nao? Ninaweza kusema moja kwa moja kwamba mbwa anayeitwa "Tuzik" ni wa Ivan huyu sana. Lakini vipi ikiwa atabadilisha jina lake na badala ya Ivan inakuwa, kwa mfano, Olya? Kisha itakuwa kwamba Olya Ivanovna Ivanova wetu hatakuwa na mbwa tena, na Tuzik yetu bado itakuwa ya Ivan ambaye hayupo. Hifadhidata ambayo ilimpa kila mtumiaji kitambulisho cha kipekee (Kitambulisho) kilisaidia kutatua tatizo hili, na Tuzik yangu iliunganishwa na kitambulisho hiki, ambacho, kwa kweli, kilikuwa nambari ya serial tu. Kwa hivyo, mmiliki wa ace alikuwa na nambari ya kitambulisho 2, na wakati fulani Ivan alikuwa chini ya kitambulisho hiki, na kisha Olya akawa chini ya kitambulisho sawa. Tatizo la ubinadamu na ufugaji lilitatuliwa kivitendo.

Kifafanuzi cha faili

Tatizo la faili na programu inayofanya kazi na faili hii ni takriban sawa na ile ya mbwa wetu na mwanadamu. Tuseme nilifungua faili inayoitwa ivan.txt na kuanza kuandika neno tuzik ndani yake, lakini niliweza tu kuandika barua ya kwanza "t" kwenye faili, na faili hii iliitwa jina na mtu, kwa mfano, kwa olya.txt. Lakini faili inabakia sawa, na bado nataka kurekodi ace yangu ndani yake. Kila wakati faili inafunguliwa na simu ya mfumo kufungua katika lugha yoyote ya programu ninapokea kitambulisho cha kipekee kinachonielekeza kwenye faili, kitambulisho hiki ndicho kielezi cha faili. Na haijalishi ni nini na ni nani anayefanya na faili hii ijayo, inaweza kufutwa, inaweza kubadilishwa jina, mmiliki anaweza kubadilishwa, au haki za kusoma na kuandika zinaweza kuondolewa, bado nitapata ufikiaji. kwa hiyo, kwa sababu wakati wa kufungua faili, nilikuwa na haki ya kusoma na / au kuandika na nilifanikiwa kuanza kufanya kazi nayo, ambayo ina maana ni lazima niendelee kufanya hivyo.

Katika Linux, maktaba ya libc hufungua faili 3 za maelezo kwa kila programu inayoendesha (mchakato), yenye nambari 0,1,2. Habari zaidi inaweza kupatikana kwenye viungo mtu stdio ΠΈ mtu stdout

  • Maelezo ya faili 0 inaitwa STDIN na inahusishwa na uingizaji wa programu
  • Kifafanuzi cha faili 1 kinaitwa STDOUT na hutumiwa na programu kutoa data, kama vile maagizo ya kuchapisha
  • Kifafanuzi cha faili 2 kinaitwa STDERR na hutumiwa na programu kutoa ujumbe wa makosa.

Ikiwa katika programu yako utafungua faili yoyote ya kusoma au kuandika, basi uwezekano mkubwa utapata kitambulisho cha kwanza cha bure na itakuwa nambari 3.

Orodha ya maelezo ya faili inaweza kutazamwa kwa mchakato wowote ikiwa unajua PID yake.

Kwa mfano, wacha tufungue koni ya bash na tuangalie PID ya mchakato wetu

[user@localhost ]$ echo $$
15771

Katika console ya pili hebu tukimbie

[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

Unaweza kupuuza kwa usalama nambari ya maelezo ya faili 255 kwa madhumuni ya kifungu hiki; ilifunguliwa kwa mahitaji yake na bash yenyewe, na sio na maktaba iliyounganishwa.

Sasa faili zote 3 za maelezo zinahusishwa na kifaa cha mwisho cha pseudo /dev/pts, lakini bado tunaweza kuzidanganya, kwa mfano, kuziendesha kwenye koni ya pili

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

Na katika console ya kwanza tutaona

[user@localhost ]$ hello world

Elekeza upya na Bomba

Unaweza kubatilisha faili hizi 3 za maelezo kwa urahisi katika mchakato wowote, pamoja na bash, kwa mfano kupitia bomba inayounganisha michakato miwili, ona.

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

Unaweza kuendesha amri hii mwenyewe na kamba -f na uone kinachoendelea ndani, lakini nitakuambia kwa ufupi.

Mchakato wetu wa mzazi bash na PID 15771 huchanganua amri yetu na inaelewa ni amri ngapi tunataka kutekeleza, kwa upande wetu kuna mbili kati yao: paka na kulala. Bash anajua kuwa inahitaji kuunda michakato miwili ya watoto, na kuwaunganisha kwenye bomba moja. Kwa jumla, bash itahitaji michakato 2 ya watoto na bomba moja.

Bash huendesha simu ya mfumo kabla ya kuunda michakato ya mtoto bomba na hupokea maelezo mapya ya faili kwenye bafa ya bomba ya muda, lakini bafa hii bado haiunganishi michakato yetu ya watoto wawili.

Kwa mchakato wa mzazi, inaonekana kama tayari kuna bomba, lakini hakuna michakato ya mtoto bado:

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

Kisha kutumia simu ya mfumo Clone bash huunda michakato miwili ya watoto, na michakato yetu mitatu itaonekana kama hii:

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

Usisahau kwamba clone inachukua mchakato pamoja na maelezo yote ya faili, kwa hivyo yatakuwa sawa katika mchakato wa mzazi na kwa watoto. Kazi ya mchakato wa mzazi na PID 15771 ni kufuatilia michakato ya mtoto, kwa hiyo inasubiri tu majibu kutoka kwa watoto.

Kwa hivyo, haiitaji bomba, na inafunga maelezo ya faili yenye nambari 3 na 4.

Katika mchakato wa kwanza wa bash wa mtoto na PID 9004, simu ya mfumo dup2, hubadilisha kifafanuzi cha faili yetu ya STDOUT nambari 1 hadi kielezi cha faili kinachoelekeza bomba, kwa upande wetu ni nambari 3. Kwa hivyo, kila kitu ambacho mchakato wa mtoto wa kwanza na PID 9004 huandika kwa STDOUT kitaishia kiotomatiki kwenye bafa ya bomba.

Katika mchakato wa mtoto wa pili na PID 9005, bash hutumia dup2 kubadilisha maelezo ya faili STDIN nambari 0. Sasa kila kitu ambacho bash yetu ya pili na PID 9005 itasoma itasomwa kutoka kwa bomba.

Baada ya hayo, maelezo ya faili yenye nambari 3 na 4 pia imefungwa katika michakato ya mtoto, kwani haitumiki tena.

Mimi hupuuza kwa makusudi maelezo ya faili 255; inatumika kwa madhumuni ya ndani na bash yenyewe na pia itafungwa katika michakato ya watoto.

Ifuatayo, katika mchakato wa mtoto wa kwanza na PID 9004, bash huanza kutumia simu ya mfumo kutekeleza faili inayoweza kutekelezwa ambayo tulielezea kwenye mstari wa amri, kwa upande wetu ni /usr/bin/cat.

Katika mchakato wa pili wa mtoto na PID 9005, bash huendesha utekelezaji wa pili tulioainisha, kwa upande wetu /usr/bin/sleep.

Simu ya mfumo wa utekelezaji haifungi vishikizo vya faili isipokuwa vilifunguliwa na bendera ya O_CLOEXEC wakati simu iliyofunguliwa ilipopigwa. Kwa upande wetu, baada ya kuzindua faili zinazoweza kutekelezwa, maelezo yote ya faili ya sasa yatahifadhiwa.

Angalia kwenye console:

[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

Kama unaweza kuona, nambari ya kipekee ya bomba letu ni sawa katika michakato yote miwili. Kwa hivyo tuna uhusiano kati ya michakato miwili tofauti na mzazi mmoja.

Kwa wale ambao hawajui simu za mfumo ambazo bash hutumia, ninapendekeza sana kutekeleza amri kupitia strace na kuona kile kinachotokea ndani, kwa mfano kama hii:

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

Hebu turudi kwenye tatizo letu na nafasi ya chini ya diski na kujaribu kuhifadhi data bila kuanzisha upya mchakato. Wacha tuandike programu ndogo ambayo itaandika takriban megabyte 1 kwa sekunde kwa diski. Aidha, ikiwa kwa sababu fulani hatukuweza kuandika data kwenye diski, tutapuuza tu hili na kujaribu kuandika data tena kwa pili. Katika mfano ninaotumia Python, unaweza kutumia lugha nyingine yoyote ya programu.

[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

Wacha tuendeshe programu na tuangalie maelezo ya faili

[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

Kama unavyoona, tuna vifafanuzi vyetu 3 vya kawaida vya faili na moja zaidi ambayo tulifungua. Wacha tuangalie saizi ya faili:

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

Data inaandikwa, tunajaribu kubadilisha ruhusa kwenye faili:

[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

Tunaona kwamba data bado inaandikwa, ingawa mtumiaji wetu hana ruhusa ya kuiandikia faili. Wacha tujaribu kuiondoa:

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

Data imeandikwa wapi? Na zimeandikwa kabisa? Tunaangalia:

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

Ndiyo, kifafanuzi cha faili yetu bado kipo na tunaweza kutibu kifafanuzi cha faili hii kama faili yetu ya zamani, tunaweza kuisoma, kuifuta na kuinakili.

Wacha tuangalie saizi ya faili:

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

Saizi ya faili ni 19923457. Hebu tujaribu kufuta faili:

[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

Kama unaweza kuona, saizi ya faili inaongezeka tu na shina yetu haikufanya kazi. Wacha tuangalie hati za simu za mfumo kufungua. Ikiwa tunatumia bendera ya O_APPEND wakati wa kufungua faili, basi kwa kila kuandika, mfumo wa uendeshaji huangalia ukubwa wa faili na kuandika data hadi mwisho wa faili, na hufanya hivi kwa atomiki. Hii inaruhusu nyuzi nyingi au michakato kuandika kwa faili moja. Lakini katika kanuni zetu hatutumii bendera hii. Tunaweza kuona saizi tofauti ya faili katika lsof baada ya shina ikiwa tu tutafungua faili kwa maandishi ya ziada, ambayo inamaanisha katika nambari yetu badala yake.

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

inabidi tuweke

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

Inaangalia na bendera ya "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

na 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

Kupanga mchakato ambao tayari unaendeshwa

Mara nyingi waandaaji programu, wakati wa kuunda na kujaribu programu, hutumia vitatuzi (kwa mfano GDB) au viwango mbalimbali vya kuingia kwenye programu. Linux hutoa uwezo wa kuandika na kubadilisha programu tayari inayoendesha, kwa mfano, kubadilisha maadili ya vigezo, kuweka sehemu ya kuvunja, nk, nk.

Kurudi kwa swali la awali kuhusu nafasi ya kutosha ya disk kuandika faili, hebu tujaribu kuiga tatizo.

Wacha tuunda faili ya kizigeu chetu, ambacho tutaweka kama diski tofauti:

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

Wacha tuunda mfumo wa faili:

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

Weka mfumo wa faili:

[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

Tunaunda saraka na mmiliki wetu:

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

Wacha tufungue faili kwa kuandika tu katika programu yetu:

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

Uzinduzi

[user@localhost ]$ python openforwrite.py 

Tunasubiri sekunde chache

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

Kwa hiyo, tuna tatizo lililoelezwa mwanzoni mwa makala hii. Nafasi ya bure 0, 100% ulichukua.

Tunakumbuka kwamba kwa mujibu wa masharti ya kazi, tunajaribu kurekodi data muhimu sana ambayo haiwezi kupotea. Na wakati huo huo, tunahitaji kurekebisha huduma bila kuanzisha upya mchakato.

Wacha tuseme bado tunayo nafasi ya diski, lakini kwa kizigeu tofauti, kwa mfano ndani / nyumbani.

Wacha tujaribu "kupanga upya kwa kuruka" nambari yetu.

Wacha tuangalie PID ya mchakato wetu, ambao umekula nafasi yote ya diski:

[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

Unganisha kwa mchakato kupitia gdb

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

Wacha tuangalie maelezo ya faili wazi:

(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

Tunaangalia habari kuhusu nambari ya maelezo ya faili 3, ambayo inatupendeza

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

Kwa kuzingatia kile ambacho Python inaita mfumo (tazama hapo juu tulipofuatilia na kupata simu iliyofunguliwa), tunapochakata msimbo wetu ili kufungua faili, tunafanya vivyo hivyo sisi wenyewe kwa niaba ya mchakato wetu, lakini tunahitaji O_WRONLY|O_CREAT| Biti za O_TRUNC hubadilishwa kwa thamani ya nambari. Ili kufanya hivyo, fungua vyanzo vya kernel, kwa mfano hapa na angalia bendera zipi zinahusika na nini

#fafanua O_WRONLY 00000001
#fafanua O_CREAT 00000100
#fafanua O_TRUNC 00001000

Tunachanganya maadili yote kuwa moja, tunapata 00001101

Tunaendesha simu yetu kutoka kwa gdb

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

Kwa hivyo tulipata maelezo mapya ya faili na nambari 4 na faili mpya wazi kwenye kizigeu kingine, tunaangalia:

(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

Tunakumbuka mfano na bomba - jinsi bash inavyobadilisha maelezo ya faili, na tayari tumejifunza simu ya mfumo wa dup2.

Tunajaribu kubadilisha maelezo ya faili moja na nyingine

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

Tunaangalia:

(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

Tunafunga maelezo ya faili 4, kwani hatuitaji:

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

Na utoke kwenye 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

Kuangalia faili mpya:

[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

Kama unaweza kuona, data imeandikwa kwa faili mpya, wacha tuangalie ya zamani:

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

Hakuna data iliyopotea, programu inafanya kazi, kumbukumbu zimeandikwa kwa eneo jipya.

Wacha tufanye kazi ngumu kidogo

Hebu fikiria kwamba data ni muhimu kwetu, lakini hatuna nafasi ya disk katika sehemu yoyote na hatuwezi kuunganisha diski.

Tunachoweza kufanya ni kuelekeza data yetu mahali pengine, kwa mfano kwa bomba, na kuelekeza data kutoka bomba hadi kwa mtandao kupitia programu fulani, kwa mfano netcat.
Tunaweza kuunda bomba iliyopewa jina na amri ya mkfifo. Itaunda faili ya pseudo kwenye mfumo wa faili hata ikiwa hakuna nafasi ya bure juu yake.

Anzisha tena programu na uangalie:

[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

Hakuna nafasi ya diski, lakini tumefanikiwa kuunda bomba lililopewa jina hapo:

[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

Sasa tunahitaji kwa namna fulani kufunika data yote inayoingia kwenye bomba hili kwa seva nyingine kupitia mtandao; netcat sawa inafaa kwa hili.

Kwenye seva ya remote-server.example.com tunazindua

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

Kwenye seva yetu yenye shida tunazindua kwenye terminal tofauti

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

Sasa data yote inayoishia kwenye bomba itaenda moja kwa moja kwa stdin in netcat, ambayo itaituma kwa mtandao kwenye bandari 7777.

Tunachotakiwa kufanya ni kuanza kuandika data zetu kwenye bomba hili lililopewa jina.

Tayari tunayo programu inayoendesha:

[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

Kati ya bendera zote, tunahitaji O_WRONLY pekee kwa kuwa faili tayari ipo na hatuhitaji kuifuta.

[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

Inakagua seva ya mbali remote-server.example.com

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

Data inakuja, tunaangalia seva ya tatizo

[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 imehifadhiwa, tatizo linatatuliwa.

Nachukua fursa hii kuwasalimu wenzangu kutoka Degiro.
Sikiliza podikasti za Radio-T.

Kila la kheri.

Kama kazi ya nyumbani, ninapendekeza ufikirie juu ya nini kitakuwa kwenye maelezo ya faili ya paka na ulale ikiwa utaendesha amri ifuatayo:

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

Chanzo: mapenzi.com

Kuongeza maoni