Fitxategien deskribatzailea Linux-en adibideekin

Behin, elkarrizketa batean, zer egingo zenuke diskoa lekurik gabe geratu delako hondatutako zerbitzu bat aurkituko baduzu zer egingo zenuke?

Noski, toki hau zertan ari zen ikusiko nuela erantzun nion eta, ahal izanez gero, lekua garbituko nuela.
Orduan elkarrizketatzaileak galdetu zuen: zer gertatzen da partizioan leku librerik ez badago, baina espazio guztia hartuko luketen fitxategiak ere ez badituzu ikusten?

Honi, esan nion beti begiratu dezakezula fitxategi irekien deskribatzaileak, adibidez, lsof komandoarekin eta ulertu zein aplikaziok hartu duen espazio guztia, eta gero egoeraren arabera jokatu dezakezula, datuak behar diren ala ez kontuan hartuta. .

Elkarrizketatzaileak eten egin ninduen azken hitzean, bere galderari gehituz: β€œDemagun ez dugula daturik behar, arazketa-erregistro bat besterik ez dela, baina aplikazioa hutsik dago arazketa idatzi ezin duelako”?

"Ados", erantzun nion, "aplikazioaren konfigurazioan arazketa desaktibatu eta berrabiarazi dezakegu".
Elkarrizketatzaileak aurka egin zuen: "Ez, ezin dugu aplikazioa berrabiarazi, oraindik datu garrantzitsuak ditugu memorian, eta bezero garrantzitsuak zerbitzura konektatuta daude, ezin dugu berriro konektatzera behartu".

"Ongi", esan nion, "Aplikazioa berrabiarazi ezin badugu eta datuei buruz ez badigugu axola, orduan irekitako fitxategi hau fitxategi deskribatzailearen bidez garbitu dezakegu, ls-en ikusten ez badugu ere. komandoa fitxategi-sisteman."

Elkarrizketatzailea pozik zegoen, baina ni ez.

Orduan pentsatu nuen, zergatik ez du sakontzen nire ezagutza probatzen ari denak? Baina, azken finean, datuak garrantzitsuak badira? Zer gertatzen da prozesua berrabiarazi eta, aldi berean, prozesu honek fitxategi-sisteman leku librerik ez duen partizio batean idazten badu? Zer gertatzen da dagoeneko idatzitako datuak ez ezik, prozesu hau idazten edo idazten saiatzen ari den datuak ere galdu ezin baditugu?

Tuzik

Nire karreraren hasieran, erabiltzaileei buruzko informazioa gordetzeko behar zuen aplikazio txiki bat sortzen saiatzen ari nintzen. Eta orduan pentsatu nuen, nola lotu dezaket erabiltzailea bere datuekin. Esaterako, Ivanov Ivan Ivanovich dut, eta datu batzuk ditu, baina nola egin haiekin lagun? Zuzenean adierazi dezaket "Tuzik" izeneko txakurra Ivan honena dela. Baina zer gertatzen da izena aldatu eta Ivanen ordez, adibidez, Olya bihurtzen bada? Orduan, gure Olya Ivanovna Ivanovak ez duela gehiago txakurrik izango eta gure Tuzik oraindik existitzen ez den Ivanarena izango da. Datu-baseak arazo hau konpontzen lagundu zuen, erabiltzaile bakoitzari identifikatzaile bakarra (ID) ematen zion, eta nire Tuzik ID horri lotuta zegoen, hau da, serie-zenbaki bat besterik ez zena. Horrela, tuzik jabea 2 NAN zenbakia zuen, eta noizbait Ivan ID horren pean zegoen, eta orduan Olya ID beraren pean geratu zen. Gizadiaren eta abeltzaintzaren arazoa ia konpondu zen.

Fitxategiaren deskribatzailea

Fitxategi batekin eta fitxategi honekin lan egiten duen programa baten arazoa gure txakurra eta gizakiaren berdina da. Demagun ivan.txt izeneko fitxategi bat ireki eta tuzik hitza idazten hasi naizela, baina fitxategian lehen letra "t" bakarrik idaztea lortu dudala, eta fitxategi honi norbaitek izena aldatu diola, adibidez, olya.txt. Baina fitxategia berdina da eta oraindik nire batekoa idatzi nahi diot. Sistema-dei batekin fitxategi bat irekitzen duzun bakoitzean ireki edozein programazio-lengoaian, fitxategi batera bideratzen nauen ID bakarra lortzen dut, ID hau fitxategiaren deskribatzailea da. Eta ez du axola zer eta nork egiten duen hurrengo fitxategi honekin, ezabatu egin daiteke, izena aldatu, bere jabea alda dezake edo irakurtzeko eta idazteko eskubideak kendu, oraindik ere sarbidea izango dut, izan ere, fitxategia irekitzeko unean irakurtzeko eta/edo idazteko eskubideak nituen eta horrekin lanean hastea lortu nuen, hau da, horrela jarraitu behar dudala.

Linux-en, libc liburutegiak 3 fitxategi deskribatzaile irekitzen ditu martxan dagoen aplikazio bakoitzeko (prozesua), 0,1,2 zenbakiekin. Informazio gehiago esteketan aurki dezakezu gizon stdio ΠΈ gizon stdout

  • 0 fitxategi deskribatzailea STDIN deitzen da eta aplikazioaren sarrerarekin lotuta dago.
  • Fitxategiaren deskribatzailea 1 STDOUT deitzen da eta irteerako aplikazioek erabiltzen dute, esate baterako, inprimatzeko komandoak.
  • 2. fitxategi-deskribatzaileak STDERR izena du eta aplikazioek erabiltzen dute errore-mezuak ateratzeko.

Zure programan irakurtzeko edo idazteko fitxategiren bat irekitzen baduzu, ziurrenik doako lehen IDa lortuko duzu eta 3. zenbakia izango da.

Edozein prozesuren fitxategi deskribatzaileen zerrenda ikus dezakezu bere PID ezagutzen baduzu.

Adibidez, ireki dezagun bash-ekin kontsola bat eta ikus dezagun gure prozesuaren PID-a

[user@localhost ]$ echo $$
15771

Bigarren kontsolan, exekutatu

[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

Artikulu honen barruan 255 zenbakia duen fitxategi deskribatzaileari segurtasunez ez ikusi egin dezakezu, zure beharretarako ireki da bash-ek berak, eta ez estekatutako liburutegiak.

Orain 3 deskribatzaile fitxategiak sasi-terminal gailuarekin lotuta daude /dev/pts, baina oraindik manipula ditzakegu, adibidez, bigarren kontsolan exekutatu

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

Eta lehenengo kontsolan ikusiko dugu

[user@localhost ]$ hello world

Birbideratu eta kanalizatu

3 deskribatzaile fitxategi hauek erraz gainidatzi ditzakezu edozein prozesutan, bash-en barne, adibidez, bi prozesu lotzen dituen kanalizazio baten (hodiaren) bidez, ikus

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

Komando hau zuk zeuk exekutatu dezakezu traza -f eta ikusi zer gertatzen den barruan, baina labur egingo dut.

Gure guraso bash-prozesuak PID 15771-rekin gure komandoa analizatzen du eta zehatz-mehatz ulertzen du zenbat komando exekutatu nahi ditugun, gure kasuan bi daude: cat eta sleep. Bashek badaki bi prozesu seme-alaba sortu behar dituela eta kanalizazio batean batu. Guztira, bash-ek 2 haur-prozesu eta kanalizazio bat beharko ditu.

Haur-prozesuak sortu aurretik, bash-ek sistema-dei bat exekutatzen du kanalizazio eta fitxategi deskribatzaile berriak jasotzen ditu aldi baterako kanalizazio-buffer batean, baina buffer honek oraindik ez ditu gure bi prozesu seme-alabak konektatzen inola ere.

Prozesu nagusirako, badirudi kanalizazioa dagoeneko hor dagoela, baina oraindik ez dago prozesu seme-alabarik:

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

Ondoren, sistema-deia erabiliz klonatu bash-ek bi prozesu seme-alaba sortzen ditu, eta gure hiru prozesu hauek itxura izango dute:

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

Ez ahaztu klonak prozesua klonatzen duela fitxategi deskribatzaile guztiekin batera, beraz, berdinak izango dira prozesu nagusietan eta umeetan. PID 15771 duen guraso-prozesuaren zeregina haurraren prozesuak kontrolatzea da, beraz, haurren erantzunaren zain geratzen da.

Horregatik, ez du kanalizaziorik behar, eta fitxategien deskribatzaileak 3 eta 4 zenbakiekin ixten ditu.

PID 9004 duen lehen bash haur-prozesuan, sistema deia dup2, gure STDOUT fitxategiaren deskribatzailea 1 zenbakia aldatzen du kanalizazio batera seinalatzen duen fitxategi deskribatzailea, gure kasuan 3. zenbakia da. Horrela, PID 9004 duen lehen seme-alabak STDOUT-en idazten duen guztia automatikoki hodi-bufferera eroriko da.

PID 9005 duen bigarren haur-prozesuan, bash dup2 fitxategia STDIN deskribatzaile zenbakira 0. Orain PID 9005 duen bigarren bash-ek irakurriko duen guztia kanaletik irakurriko da.

Horren ostean, 3. eta 4. zenbakiak dituzten fitxategi-deskribatzaileak ere itxi egiten dira prozesu umeetan, jada ez baitira erabiltzen.

Nahita ez dut jaramonik egiten 255 fitxategi-deskribatzailea, bash-ek barnean erabiltzen du eta ume-prozesuetan ere itxiko da.

Ondoren, PID 9004 duen lehen haur-prozesuan, bash sistema dei batekin hasten da exec komando lerroan zehaztu dugun fitxategi exekutagarria, gure kasuan /usr/bin/cat da.

PID 9005 duen bigarren haur-prozesuan, bash-ek zehaztu dugun bigarren exekutagarria exekutatzen du, gure kasuan /usr/bin/sleep.

Exec sistema-deiak ez ditu fitxategi-deskribatzaileak ixten, deia exekutatu zenean O_CLOEXEC banderarekin ireki ezean. Gure kasuan, fitxategi exekutagarriak exekutatu ondoren, uneko fitxategi deskribatzaile guztiak gordeko dira.

Kontsolan egiaztatzea:

[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

Ikus dezakezunez, gure hodiaren zenbaki bakarra berdina da bi prozesuetan. Horrela, guraso bera duten bi prozesu ezberdinen arteko lotura dugu.

Bashek erabiltzen dituen sistema-deiak ezagutzen ez dituztenentzat, gomendatzen dut strace bidez komandoak exekutatu eta ikustea zer gertatzen den barruan, adibidez, honela:

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

Itzul gaitezen gure arazora diskoko lekurik gabe geratu eta datuak gordetzen saiatzean prozesua berrabiarazi gabe. Idatz dezagun diskoan segundoko 1 megabyte inguru idatziko duen programa txiki bat. Gainera, arrazoiren batengatik ezin izan bagenu datuak diskoan idatzi, hau baztertu eta segundo batean datuak berriro idazten saiatuko gara. Python erabiltzen ari naizen adibidean, beste edozein programazio-lengoaia erabil dezakezu.

[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

Exekutatu programa eta begiratu fitxategien deskribatzaileak

[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

Ikus dezakezunez, gure 3 fitxategi deskribatzaile estandarrak ditugu eta ireki dugun beste bat. Ikus dezagun fitxategiaren tamaina:

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

datuak idatzita daude, fitxategiaren eskubideak aldatzen saiatzen gara:

[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

Datuak oraindik idazten ari direla ikusten dugu, nahiz eta gure erabiltzaileak fitxategian idazteko eskubiderik ez duen. Saia gaitezen kentzen:

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

Non daude idatzita datuak? Eta idatzita daude? Egiaztatzen dugu:

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

Bai, gure fitxategi-deskribatzailea oraindik existitzen da, eta fitxategi-deskribatzaile honekin lan egin dezakegu gure fitxategi zaharra bezala, irakurri, garbitu eta kopiatu.

Begiratu fitxategiaren tamaina:

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

Fitxategiaren tamaina 19923457 da. Fitxategia garbitu nahian:

[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

Ikus dezakezunez, fitxategiaren tamaina handitzen da soilik eta gure enborrak ez zuen funtzionatu. Goazen sistema-deiari buruzko dokumentaziora ireki. Fitxategi bat irekitzean O_APPEND bandera erabiltzen badugu, idazketa bakoitzean, sistema eragileak fitxategiaren tamaina egiaztatzen du eta datuak fitxategiaren amaieran idazten ditu, eta atomikoki egiten ditu. Honek hainbat hari edo prozesu fitxategi berean idazteko aukera ematen du. Baina gure kodean ez dugu bandera hau erabiltzen. Fitxategiaren tamaina desberdina ikus dezakegu lsof-en trunk ondoren fitxategia idazteko irekitzen badugu, hau da, gure kodean, ordez

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

jarri behar dugu

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

"w" banderarekin egiaztatzen

[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

eta "a" banderarekin

[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

Dagoeneko martxan dagoen prozesu bat programatzea

Askotan, programa bat sortu eta probatzerakoan, programatzaileek araztaileak (adibidez, GDB) edo aplikazioan saioaren hainbat maila erabiltzen dituzte. Linux-ek dagoeneko martxan dagoen programa bat idazteko eta aldatzeko gaitasuna eskaintzen du, hala nola aldagaien balioak aldatzea, eten puntu bat ezartzea, eta abar.

Fitxategi bat idazteko diskoko leku faltari buruzko jatorrizko galderara itzuliz, saia gaitezen arazoa simulatzen.

Sortu dezagun fitxategi bat gure partiziorako, disko bereizi gisa muntatuko duguna:

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

Sortu dezagun fitxategi-sistema bat:

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

Munta dezagun fitxategi-sistema:

[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

Sortu direktorio bat gure jabearekin:

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

Ireki dezagun fitxategia gure programan soilik idazteko:

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

korrika

[user@localhost ]$ python openforwrite.py 

Segundo batzuk zain

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

Beraz, artikulu honen hasieran deskribatutako arazoa lortu dugu. Espazio librea 0, %100 okupatua.

Gogoratzen dugu arazoaren baldintzen arabera, galdu ezin diren datu oso garrantzitsuak erregistratzen saiatzen ari garela. Eta horrela, zerbitzua konpondu behar dugu prozesua berrabiarazi gabe.

Demagun oraindik diskoan tokia dugula, baina beste partizio batean, adibidez, / homen.

Saia gaitezen gure kodea "berrantoan birprogramatzen".

Gure prozesuaren PID-a ikusten dugu, diskoko espazio guztia jan zuen:

[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-rekin prozesu batera konektatzen

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

Fitxategi irekien deskribatzaileak aztertuko ditugu:

(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

Interesatzen zaigun 3. zenbakia duen fitxategi deskribatzaileari buruzko informazioa ikusten dugu

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

Python-ek sistema-deiak zer egiten duen kontuan izanda (ikusi gorago non exekutatu dugun strace eta dei ireki bat aurkitu dugun), fitxategi bat irekitzeko gure kodea prozesatzen dugun bitartean, guk ere gauza bera egiten dugu gure prozesuaren izenean, baina O_WRONLY|O_CREAT| behar dugu. O_TRUNC bitek zenbakizko balio batekin ordezkatzen dute. Horretarako, ireki nukleoaren iturriak, adibidez Hemen eta ikusi zein banderak diren zeren arduradun

#defini O_WRONLY 00000001
#defini O_CREAT 00000100
#defini O_TRUNC 00001000

Balio guztiak bakar batean konbinatzen ditugu, 00001101 lortzen dugu

Gdb-tik gure deia exekutatzen

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

Beraz, 4. zenbakia duen fitxategi deskribatzaile berri bat eta beste partizio batean irekitako fitxategi berri bat lortu dugu, egiaztatu:

(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

Pipe-rekin duen adibidea gogoratzen dugu: bash-ek fitxategien deskribatzaileak nola aldatzen dituen eta dagoeneko ikasi dugu dup2 sistema-deia.

Fitxategi deskribatzaile bat beste batekin ordezkatzen saiatzen

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

Egiaztatzen dugu:

(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

Itxi fitxategi deskribatzailea 4, ez dugulako behar:

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

Eta gdb irten

(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

Fitxategi berria egiaztatzen:

[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

Ikus dezakezunez, datuak fitxategi berri batean idazten dira, zaharra egiaztatuko dugu:

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

Datuak ez dira galtzen, aplikazioak funtzionatzen du, erregistroak kokapen berri batean idazten dira.

Egin ditzagun gauzak pixka bat zailago

Imajinatu datuak garrantzitsuak direla guretzat, baina ez daukagu ​​diskoko lekurik edozein partiziotan eta ezin dugu diskoa konektatu.

Egin dezakeguna gure datuak nonbaitera birbideratzea da, adibidez, kanalizazio batera, eta datuak kanaletik sarera birbideratzea programa batzuen bidez, netcat adibidez.
Izeneko kanalizazio bat sor dezakegu mkfifo komandoarekin. Fitxategi-sisteman sasi-fitxategi bat sortuko du, leku librerik ez badago ere.

Berrabiarazi aplikazioa eta egiaztatu:

[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

Ez dago diskoko lekurik, baina izendun kanalizazio bat sortuko dugu bertan:

[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

Orain hodi honetan sartzen diren datu guztiak sarearen bidez beste zerbitzari batera bildu behar ditugu nolabait, netcat bera egokia da horretarako.

remote-server.example.com zerbitzarian, exekutatu

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

Gure arazo-zerbitzarian, exekutatu beste terminal batean

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

Orain kanalizazioan sartzen diren datu guztiak netcat-en stdin-era joango dira automatikoki, eta 7777 atakako sarera bidaliko ditu.

Egin behar duguna da gure datuak idazten hastea izendun hodi honetan.

Dagoeneko badugu aplikazio bat martxan:

[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

Bandera guztien artean, O_WRONLY baino ez dugu behar, fitxategia jada existitzen baita eta ez dugulako garbitu behar

[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

Urruneko zerbitzaria egiaztatzea remote-server.example.com

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

Datuak iristen ari dira, arazoaren zerbitzaria egiaztatzen dugu

[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

Datuak gordetzen dira, arazoa konpondu da.

Aukera hau aprobetxatzen dut Degiroko lankideei agurtzeko.
Entzun Radio-T podcastak.

Ongi dena.

Etxeko lan gisa, katu eta lo prozesuaren fitxategi-deskribatzaileetan zer egongo den pentsatzea proposatzen dut komando hau exekutatzen baduzu:

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

Iturria: www.habr.com

Gehitu iruzkin berria