Kord, ühes intervjuus küsiti minult, mida sa teeksid, kui avastad, et teenus ei tööta, kuna kettaruumi on vähe?
Muidugi vastasin, et vaataksin, mis seda ruumi täidab ja vajadusel teeksin seal korda.
Siis küsis intervjueerija, aga mis siis, kui partitsioonil pole vaba ruumi, aga ei näe ka faile, mis kogu ruumi võtaksid?
Sellele vastasin, et alati saab vaadata avatud failide deskriptorite nimekirja, näiteks käsuga lsof, et mõista, milline rakendus on kogu saadavaloleva ruumi ära kasutanud, ja seejärel toimetada olenevalt asjaoludest, sõltuvalt sellest, kas andmed on vajalikud.
Intervjueerija katkestas mind viimase sõnaga, lisades oma küsimusele: „Oletame, et andmed ei ole meile vajalikud, see on lihtsalt tõrke logi, aga rakendus ei tööta, kuna ei saa tõrke logi kirjutada“?
„Okei,“ vastasin ma, „me saame välja lülitada tõrke logimise rakenduse konfigurasioonis ja seejärel taaskäivitada.“
Intervjueerija vastas: „Ei, rakendust me taaskäivitada ei saa, meil on mälus endiselt olulised andmed ja teenusele on ühendatud olulised kliendid, keda me ei saa sundida uuesti ühendama.“
«No hästi», ütlesin ma, «kui me ei saa rakendust taaskäivitada ja andmed pole meile olulised, siis võime lihtsalt selle avatud faili descriptor kaudu puhastada, isegi kui me ei näe seda ls käskluses failisüsteemis.»
Intervjueerija jäi rahule, kuid mina mitte.
Siis mõtlesin, miks inimene, kes kontrollib minu teadmisi, ei kaeva sügavamale? Ent mis siis, kui andmed on ikkagi olulised? Mis siis, kui me ei saa protsessi taaskäivitada ja see protsess kirjutab failisüsteemi sektsiooni, kus pole vaba ruumi? Mis siis, kui me ei saa kaotada mitte ainult juba kirjutatud andmeid, vaid ka neid andmeid, mida see protsess kirjutab või püüab kirjutada?
Tuzik
Oma karjääri alguses püüdsin luua väikest rakendust, kus tuli salvestada teavet kasutajate kohta. Siis mõtlesin, kuidas siduda kasutaja tema andmetega. Näiteks mul on Ivanov Ivan Ivanovich ning tal on mingid andmed, kuid kuidas neid omavahel seostada? Ma võin otse märkida, et koer nimega "Tuzik" kuulub just sellele Ivanile. Aga mis juhtub, kui ta vahetab nime ja muutub näiteks Olgaks? Selgub, et meie Olya Ivanovna Ivanova ei saa enam koera omanikuks, kuid meie Tuzik kuulub endiselt mitteeksisteerivale Ivanile. Selle probleemi lahendas andmebaas, mis andis igale kasutajale unikaalse identifikaatori (ID), ja minu Tuzik seostus selle ID-ga, mis oli tegelikult lihtsalt järjestusnumber. Seega oli Tuziku omanikul ID numbriga 2, ja mingil hetkel sellel ID-l oli Ivan, aga hiljem sai sellest samast ID-st Olya. Inimkonna ja loomakasvatuse probleem oli praktiliselt lahendatud.
Faili deskriptor
Faili ja programmi probleem, mis sellega tegeleb, on umbes sama nagu meie koer ja inimene. Oletame, et avasin faili nimega ivan.txt ja hakkasin sellesse kirjutama sõna tuzik, kuid jõudsin kirjutada vaid esimese tähe «t» faili ning see fail nimetati keegi näiteks ümber olya.txt-ks. Fail jäi aga samaks ja ma tahan endiselt oma tuziki sinna kirjutada. Iga kord, kui avatakse fail süsteemikutsumise teel. Igas programmeerimiskeeles saan ma unikaalse ID, mis viitab mulle failile, see ID ongi faili deskriptor. Täiesti ükskõik, mida ja kes selle failiga hiljem teeb, seda võidakse kustutada, selle võidakse ümber nimetada, selle omanikku võidakse muuta või õigusi lugemiseks ja kirjutamiseks röövida, mul on sellegipoolest juurdepääs, sest fail avamise hetkel olid mul õigused selle lugemiseks ja/või kirjutamiseks ning ma olen juba alustanud sellega töötamist, seega pean ma seda jätkama.
Linuxis avab libc iga jooksva rakenduse (protsessi) jaoks 3 faili deskriptorit, numbritega 0, 1, 2. Rohkem teavet leiate linkidelt. ja
- Faili descriptor 0 nimetatakse STDIN-iks ja see on seotud rakenduse andmete sisendi vastuvõtmisega.
- Faili descriptor 1 nimetatakse STDOUT-iks ja rakendused kasutavad seda andmete väljastamiseks, näiteks printimis käsud.
- Faili descriptor 2 nimetatakse STDERR-iks ja seda kasutatakse rakendustes, mis väljastavad vigadega seotud andmeid.
Kui avate oma programmis mõne faili lugemiseks või kirjutamiseks, siis tõenäoliselt saate esimese vabade ID ja see on number 3.
Faili deskriptorite loendit saab vaadata igas protsessis, kui teate selle PID-d.
Näiteks avame bashiga konsooli ja vaatame meie protsessi PID-d.
[user@localhost ]$ echo $$
15771
Teises konsoolis käivitame
[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
Faili descriptor numbriga 255 võite selle artikli ulatuses rahule jätta, see avati juba bash'i enda vajaduste jaoks, mitte seotud teegi poolest.
Praegu on kõik 3 faili deskriptorit seotud pseudoterminaali seadmega. , kuid me saame neid ikkagi käsitleda, näiteks käivitame teises konsoolis
[user@localhost ]$ echo "hello world" > /proc/15771/fd/0
Ja esimeses konsoolis näeme
[user@localhost ]$ hello world
Redirect ja Pipe
Sa saad neid 3 failide descriptorit igas protsessis, sealhulgas bash-is, lihtsalt ümber määrata, näiteks läbi toru (pipe), mis ühendab kahte protsessi, vaatame
[user@localhost ]$ cat /dev/zero | sleep 10000
Sa saad selle käsu ise käivitada strace -f ja näha, mis toimub sees, aga ma räägin sellest lühidalt.
Meie vanem protsess bash PID 15771 tõlgendab meie käsku ja mõistab, kui palju käsklusi me soovime käivitada, meie puhul on neid kaks: cat ja sleep. Bash teab, et peab looma kaks alammenetlust ja ühendama need ühe toruga. Kokku vajab bash 2 alammenetlust ja ühte pipe.
Enne alammenetluste loomist käivitab bash süsteemikõne ja saab uued failide descriptorid ajutisele pipe-bufrile, kuid see buffer ei seo meie kahte alammenetlust.
Vanem protsessile näib, et pipe on juba olemas, kuid alammenetlusi pole veel:
PID käsk
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
Seejärel kasutab süsteemikõne bash loob kaks lapsprotsessi ja meie kolm protsessi näevad välja sellised:
PID käsk
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 käsk
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 käsk
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
Ärge unustage, et clone kopeerib protsessi koos kõikide failideskirjeldajatega, seetõttu on need vanemas ja alamprotsessides samad. Vanema protsessi ülesanne PID 15771 on jälgida alamprotsesse, seetõttu ootab ta lihtsalt vastust alamprotsessidelt.
Seetõttu pole pipe talle vajalik ja ta sulgeb failideskirjeldajad numbritega 3 ja 4.
Esimeses alamprotsessis bash PID 9004, süsteemi kutsumisega , muudab meie STDOUT failideskirjeldaja numbri 1 faili kirjeldaja numbriks, mis osutab pipe'ile, meie juhul on see number 3. Nõnda kõik, mida esimene alamprotsess PID 9004 kirjutab STDOUT-i, suunatakse automaatselt pipe'i puhvrisse.
Teises alamprotsessis PID 9005 bash muudab dup2 abil STDIN failideskirjeldaja numbri 0. Nüüd loeb kõik, mida meie teine bash PID 9005 loeb, pipe'ist.
Pärast seda sulgevad alamprotsessides samuti failideskirjeldajad numbritega 3 ja 4, kuna neid enam ei kasutata.
Failideskirjeldajat 255 ignoreerin ma teadlikult, seda kasutatakse bashi enda sisemiste vajaduste jaoks ja alamprotsessides suletakse see samuti.
See esimese alamprotsessi PID 9004 korral bash käivitab meie käskude reas määratud täitmisfaili, meie juhul on see /usr/bin/cat. Teises alamprotsessis PID 9005 korral bash käivitab teise täitmisfaili, mille oleme määranud, meie juhul on see /usr/bin/sleep.
Süsteemi kutse exec ei sulge faili deskripteerijaid, kui need ei ole avatud O_CLOEXEC lipu all open kutse käivitamise ajal. Meie puhul pärast täitmisfailide käivitamist jäävad kõik praegused faili deskripteerijad alles.
Kontrollime konsoolis:
Kasutame konsolis:
[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
Nagu näete, on meie pipe'i unikaalne number mõlemas protsessis sama. Seega on meil seos kahe erineva protsessi vahel, millel on üks ja sama vanem.
Neile, kes ei tunne bashis kasutatavaid süsteemikutseid, soovitan tungivalt käivitada käsud strace'i abil ja vaadata, mis tegelikult toimub, näiteks nii:
strace -s 1024 -f bash -c "ls | grep hello"
Naaseme meie probleemi juurde, mis on seotud kettaruumi puudusega ja andmete salvestamisega ilma protsessi taaskäivitamiseta. Kirjutame väikese programmi, mis salvestab kettale umbes 1 megabaidi sekundis. Sel juhul, kui mingil põhjusel ei õnnestu andmeid kettale salvestada, ignoreerime seda lihtsalt ja püüame andmeid uuesti salvestada sekundi pärast. Näites kasutan Pythonit, kuid võite kasutada mõnda muud programmeerimiskeelt.
[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
Käivitage programm ja vaadake failide deskriptorite seisu
[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
Nagu näha, on meil kolm tavalist failideskriptorit ja veel üks, mille me avasime. Kontrollime faili suurust:
[user@localhost ]$ ls -lah 123.txt
-rw-rw-r-- 1 user user 117M Oct 7 16:30 123.txt
Andmed kirjutatakse, proovime muuta faili õigusi:
[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
Näeme, et andmed kirjutatakse endiselt, kuigi meie kasutajal pole faili kirjutamise õigusi. Proovime selle kustutada:
[user@localhost ]$ sudo rm 123.txt
[user@localhost ]$ ls 123.txt
ls: cannot access 123.txt: No such file or directory
Kuhu andmed kirjutatakse? Ja kas need kirjutatakse üldse? Kontrollime:
[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)
Jah, meie failikirjeldaja eksisteerib endiselt ning me saame sellega töötada nagu meie vana failiga, saame seda lugeda, puhastada ja kopeerida.
Vaadates faili suurust:
[user@localhost ]$ lsof | grep 123.txt
python 31083 user 3w REG 8,5 19923457 2621522 /home/user/123.txt
Faili suurus on 19923457. Proovime faili puhastada:
[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
Kuidas näha, et faili suurus ainult suureneb ja meie truncate ei töötanud. Vaatame süsteemi kõne dokumentatsiooni. . Kui avame faili O_APPEND lipuga, siis iga kirjutamise korral kontrollib operatsioonisüsteem faili suurust ja kirjutab andmed faili lõppu, tehes seda atomaarselt. See võimaldab mitmel tõsil või protsessil kirjutada ühte ja sama faili. Kuid meie koodis me seda lippu ei kasuta. Saame lsof-is faili erineva suuruse näha pärast truncate'i alles siis, kui avame faili lisamiseks, seega meie koodis peaks olema
with open("123.txt", "w") as f:
peame panema
with open("123.txt", "a") as f:
Kontrollime „w“ lipuga
[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
ja "a" lipuga
[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
Programmeerime juba käivitatud protsessi
Sageli kasutavad programmeerijad programmi loomisel ja testimisel silurite (nt GDB) või rakenduse erinevate logimisastmete abi. Linux pakub tegelikult võimalust kirjutada ja muuta juba käivitatud programmi, näiteks muuta muutujate väärtusi, seada peatuspunkt ja muud sellised asjad.
Naaseme algse küsimuse juurde, mis puudutab failikirjutamiseks kettaruumi puudumist, ja proovime simuleerida probleemi.
Loome faili meie jao jaoks, mille me installime eraldi kettana:
[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 ~]$
Loome failisüsteemi:
[user@localhost ~]$ mkfs.ext4 ~/tempfile_for_article.dd
mke2fs 1.42.9 (28-Dec-2013)
/home/user/tempfile_for_article.dd ei ole blokeeritud eriseade.
Kas jätkata? (y,n) y
...
Kirjutamine superblokid ja failisüsteemi arvestuse teave: tehtud
[user@localhost ~]$
Installime failisüsteemi:
[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
Loome kausta meie kasutaja jaoks:
[user@localhost ~]$ sudo mkdir /mnt/logs
[user@localhost ~]$ sudo chown user: /mnt/logs
Avame faili ainult kirjutamiseks meie programmis:
with open("/mnt/logs/123.txt", "w") as f:
Käivitage
[user@localhost ]$ python openforwrite.py
Ootame paar sekundi.
[user@localhost ~]$ df -h | grep mnt
/dev/loop0 8.7M 8.0M 0 100% /mnt
Nii, me saime probleemi, millest artikli alguses rääkisime. Vaba ruumi 0, kasutatud 100%.
Peame meeles, et ülesande tingimuste kohaselt püüame salvestada väga olulisi andmeid, mida ei saa kaotada. Ja samal ajal peame teenuse parandama, ilma et protsessi taaskäivitama peaksime.
Oletame, et meil on siiski ruumi kettal, aga teises partitsioonis, näiteks /home.
Proovime oma koodi 'lennult' ümber programmeerida.
Vaadakem meie protsessi PID-d, mis on kogu ruumi ära kulutanud:
[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
Ühendume protsessiga läbi gdb
[user@localhost ~]$ gdb -p 10078
...
(gdb)
Vaadake avatud faili deskriptorid:
(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
Vaadake faili descriptorite teavet numbriga 3, mis meid huvitab
(gdb) shell cat /proc/10078/fdinfo/3
pos: 8189952
flags: 0100001
mnt_id: 482
Meeles pidades, millist süsteemikutsungit Python teeb (vt ülal, kus me jooksime strace'i ja leidsime open-kutsungi), töötades meie koodi, et avada fail, teeme sama ise meie protsessi nimel, kuid O_WRONLY|O_CREAT|O_TRUNC bitid tuleb asendada numbrilise väärtusega. Selleks avame tuuma allikakoodid, näiteks ja vaatame, millised lipud millega vastutavad
#define O_WRONLY 00000001
#define O_CREAT 00000100
#define O_TRUNC 00001000
Kombineerime kõik väärtused ühte, saame 00001101
Käivitame meie kutse gdb-s
(gdb) call open("/home/user/123.txt", 00001101,0666)
$1 = 4
Nii saime uue faili deskriptoriga numbriga 4 ja uue avatud faili teisel partitsioonil, kontrollime:
(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
Meename no näiteks pipe - kuidas bash muudab failidesse viitavad deskriptorid ning oleme juba õppinud süsteemikõnet dup2.
Proovime asendada üks failidesse viitav deskriptor teisega
(gdb) call dup2(4,3)
$2 = 3
Kontrollin:
(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
Sulgeme failidesse viitava deskriptor 4, kuna me ei vaja seda:
(gdb) call close(4)
$1 = 0
Ja lahkume gdb-st
(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
Kontrollime uut faili:
[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
Nagu näeme, kirjutatakse andmed uude faili, kontrollime vana:
[user@localhost ~]$ ls -lah /mnt/logs/123.txt
-rw-rw-r-- 1 user user 7.9M Oct 8 11:08 /mnt/logs/123.txt
Andmed ei ole kadunud, rakendus töötab ja logid kirjutatakse uude kohta.
Teeme ülesande veidi keerulisemaks
Oletame, et andmed on meile olulised, kuid meil ei ole üheski jaotises kettaruumi ning me ei saa ketast ühendada.
Saame teha nii, et suuname meie andmed kuskile, näiteks pipe'i, ja andmed pipe'ist omakorda suunata võrku läbi mõne programmi, näiteks netcat'i.
Saame luua nimelise pipe'i käsuga mkfifo. See loob failisüsteemis pseudo-faili, isegi kui seal ei ole vaba ruumi.
Taaskäivitame rakenduse ja kontrollime:
[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
Kettaruumi pole, kuid me loome seal edukalt nimelise pipe'i:
[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
Nüüd peame kuidagi kapseldama kõik andmed, mis jõuavad sellesse pipe'i teisele serverile üle võrgu, selleks sobib endiselt netcat.
Käivitame serveris remote-server.example.com
[user@localhost ~]$ nc -l 7777 > 123.txt
Käivitame meie probleemserveris eraldi terminalis
[user@localhost ~]$ nc remote-server.example.com 7777 < /mnt/logs/megapipe
Nüüd jõuavad kõik andmed, mis sisenevad pipe'i, automaatselt netcat'i stdin'i, mis saadab need võrku pordile 7777.
Kõik, mis meil veel üle jääb, on hakata kirjutama meie andmeid sellesse nimetatud pipe'i.
Meil on juba käivitatud rakendus:
[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
Kõigist lipukestest vajame ainult O_WRONLY, kuna fail juba eksisteerib ja me ei pea seda tühjendama.
[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
Kontrollime eemalserverit remote-server.example.com
[user@localhost ~]$ ls -lah 123.txt
-rw-rw-r-- 1 user user 38M Oct 8 14:21 123.txt
Andmed liiguvad, kontrollime probleemset serverit
[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
Andmed on salvestatud, probleem on lahendatud.
Kasutades võimalust, edastan tervitused Degiro ettevõtte kolleegidele.
Kuulake Raadio-T taskuhäälinguid.
Kõigile head päeva.
Koduülesandena soovitan mõelda, mis toimub protsessi failides cat ja sleep, kui käivitada järgmine käsk:
[user@localhost ~]$ cat /dev/zero 2>/dev/null| sleep 10000
Allikas: habr.com
