Faili deskriptor Linuxis koos näidetega

Kord küsiti minult intervjuu ajal, et mida teete, kui leiate, et teenus ei tööta, kuna kettal on ruum otsa saanud?

Muidugi vastasin, et vaatan, mis see koht hõivab ja võimalusel koristan selle koha ära.
Seejärel küsis intervjueerija, et mis siis, kui partitsioonil pole vaba ruumi, kuid te ei näe ka ühtegi faili, mis kogu ruumi võtaks?

Selle peale ütlesin, et alati saab vaadata avatud failideskriptoreid, näiteks käsuga lsof ja aru saada, milline rakendus on kogu vaba ruumi enda alla võtnud ja siis saab vastavalt oludele tegutseda, olenevalt kas andmeid on vaja .

Intervjueerija katkestas mind viimase sõna peale, lisades oma küsimusele: "Oletame, et me ei vaja andmeid, see on lihtsalt silumislogi, kuid rakendus ei tööta, kuna see ei saa silumist kirjutada"?

"Olgu," vastasin, "saame rakenduse konfiguratsioonis silumise välja lülitada ja selle taaskäivitada."
Intervjueerija vaidles vastu: "Ei, me ei saa rakendust taaskäivitada, olulised andmed on endiselt mällu salvestatud ja olulised kliendid on ühendatud teenuse endaga, mida me ei saa sundida uuesti ühendama."

"Olgu," ütlesin ma, "kui me ei saa rakendust taaskäivitada ja andmed pole meile olulised, siis saame selle avatud faili lihtsalt failideskriptori kaudu kustutada, isegi kui me seda käsus ls ei näe failisüsteemis."

Intervjueerija oli rahul, aga mina mitte.

Siis mõtlesin, et miks see inimene, kes minu teadmisi proovile paneb, ei süvene? Aga mis siis, kui andmed on siiski olulised? Mis siis, kui me ei saa protsessi taaskäivitada ja protsess kirjutab failisüsteemi partitsioonile, millel pole vaba ruumi? Mis siis, kui me ei saa kaotada mitte ainult juba kirjutatud andmeid, vaid ka andmeid, mida see protsess kirjutab või üritab kirjutada?

Tuzik

Oma karjääri alguses püüdsin luua väikest rakendust, mis vajas kasutajateabe salvestamist. Ja siis ma mõtlesin, et kuidas ma saan kasutaja tema andmetega kokku sobitada. Näiteks on mul Ivanov Ivan Ivanovitš ja tal on natuke teavet, aga kuidas ma saan nendega sõbraks saada? Võin otse välja tuua, et koer nimega “Tuzik” kuulub just sellele Ivanile. Aga mis siis, kui ta muudab nime ja saab Ivani asemel näiteks Olya? Siis selgub, et meie Olja Ivanovna Ivanoval pole enam koera ja meie Tuzik jääb ikkagi olematule Ivanile. Andmebaas, mis andis igale kasutajale kordumatu identifikaatori (ID), aitas seda probleemi lahendada ja minu Tuzik oli seotud selle ID-ga, mis tegelikult oli vaid seerianumber. Seega oli tuziku omanikul ID-number 2 ja mingil ajal oli selle ID all Ivan ja siis sai selle ID all ka Olya. Inimkonna ja loomakasvatuse probleem sai praktiliselt lahendatud.

Faili deskriptor

Faili ja selle failiga töötava programmi probleem on ligikaudu sama, mis meie koeral ja inimesel. Oletame, et avasin faili nimega ivan.txt ja hakkasin sinna kirjutama sõna tuzik, kuid jõudsin failis kirjutada ainult esimese tähe “t” ja keegi nimetas selle faili ümber, näiteks nimeks olya.txt. Kuid fail jääb samaks ja ma tahan ikka oma ässa sinna salvestada. Iga kord, kui fail avatakse süsteemikõnega avatud mis tahes programmeerimiskeeles saan kordumatu ID, mis suunab mind failile, see ID on faili deskriptor. Ja üldse pole vahet, mida ja kes selle failiga järgmiseks teeb, selle saab kustutada, ümber nimetada, omanikku vahetada või lugemis- ja kirjutamisõigused ära võtta, mul on ikkagi juurdepääs sellele, kuna faili avamise ajal oli mul õigus seda lugeda ja/või kirjutada ning mul õnnestus sellega tööd alustada, mis tähendab, et pean seda ka edaspidi tegema.

Linuxis avab libc teek iga töötava rakenduse (protsessi) jaoks 3 deskriptorifaili, mis on nummerdatud 0,1,2. Rohkem infot leiab linkidelt mees stdio и mees stdout

  • Failideskriptorit 0 nimetatakse STDIN-iks ja see on seotud rakenduse sisendiga
  • Faili deskriptorit 1 nimetatakse STDOUT ja rakendused kasutavad seda andmete, näiteks printimiskäskude, väljastamiseks
  • Failideskriptorit 2 nimetatakse STDERR-iks ja rakendused kasutavad seda veateadete väljastamiseks.

Kui avate oma programmis lugemiseks või kirjutamiseks mis tahes faili, saate suure tõenäosusega esimese tasuta ID ja see on number 3.

Failideskriptorite loendit saab vaadata mis tahes protsessi jaoks, kui teate selle PID-d.

Näiteks avame bash-konsooli ja vaatame oma protsessi PID-d

[user@localhost ]$ echo $$
15771

Teises konsoolis jookseme

[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

Selle artikli puhul võite failideskriptorit number 255 julgelt ignoreerida; selle avas oma vajadusteks bash ise, mitte lingitud teek.

Nüüd on kõik 3 deskriptorifaili seotud pseudoterminali seadmega /dev/pts, kuid me saame nendega siiski manipuleerida, näiteks käitada neid teises konsoolis

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

Ja esimeses konsoolis näeme

[user@localhost ]$ hello world

Ümbersuunamine ja toru

Neid 3 deskriptorifaili saate hõlpsasti alistada mis tahes protsessis, sealhulgas bashis, näiteks kahte protsessi ühendava toru kaudu, vt

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

Saate selle käsu ise käivitada joon -f ja vaata, mis seal sees toimub, aga ma räägin sulle lühidalt.

Meie vanem bash protsess PID 15771-ga parsib meie käsku ja mõistab täpselt, kui palju käske tahame käivitada, meie puhul on neid kaks: kass ja uni. Bash teab, et ta peab looma kaks alamprotsessi ja liitma need üheks toruks. Kokku vajab bash 2 alamprotsessi ja ühte toru.

Bash käivitab enne alamprotsesside loomist süsteemikutse toru ja võtab vastu uued failideskriptorid ajutises torupuhvris, kuid see puhver ei ühenda veel meie kahte alamprotsessi.

Vanemprotsessi jaoks näib, et toru on juba olemas, kuid alamprotsesse pole veel:

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

Seejärel kasutage süsteemikõnet kloonida bash loob kaks alamprotsessi ja meie kolm protsessi näevad välja järgmised:

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

Ärge unustage, et kloon kloonib protsessi koos kõigi failideskriptoritega, nii et need on põhiprotsessis ja alamprotsessis samad. PID 15771-ga vanemprotsessi ülesanne on jälgida alamprotsesse, nii et see lihtsalt ootab lastelt vastust.

Seetõttu ei vaja see toru ja see sulgeb failideskriptorid numbritega 3 ja 4.

Esimeses alam-bash-protsessis PID 9004-ga kutsub süsteem välja dup2, muudab meie STDOUT failideskriptori number 1 failideskriptoriks, mis osutab torule, meie puhul on see number 3. Seega kõik, mis PID 9004-ga esimene alamprotsess STDOUT-i kirjutab, jõuab automaatselt torupuhvrisse.

Teises PID 9005 alamprotsessis kasutab bash failideskriptori STDIN numbri 2 muutmiseks dup0. Nüüd loetakse torust kõik, mida meie teine ​​bash PID 9005-ga loeb.

Pärast seda suletakse alamprotsessides ka failideskriptorid numbritega 3 ja 4, kuna neid enam ei kasutata.

Ignoreerin meelega failideskriptorit 255; seda kasutab sisemistel eesmärkidel bash ise ja see suletakse ka alamprotsessides.

Järgmisena hakkab bash PID 9004-ga esimeses alamprotsessis kasutama süsteemikutset exec käivitatav fail, mille me käsureal määrasime, meie puhul on see /usr/bin/cat.

Teises PID 9005 alamprotsessis käivitab bash teist meie määratud käivitatavat faili, meie puhul /usr/bin/sleep.

Exec-süsteemikutse ei sulge failikäepidemeid, välja arvatud juhul, kui need avati avatud kõne tegemise ajal lipuga O_CLOEXEC. Meie puhul salvestatakse pärast käivitatavate failide käivitamist kõik praegused failideskriptorid.

Kontrollige konsoolis:

[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 toru kordumatu number mõlemas protsessis sama. Seega on meil seos kahe erineva protsessi vahel sama vanemaga.

Neile, kes pole bashi kasutatavate süsteemikutsega tuttavad, soovitan tungivalt käivitada käsud läbi strace ja vaadata, mis toimub sisemiselt, näiteks järgmiselt:

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

Pöördume tagasi probleemi juurde, mis puudutab vähest kettaruumi ja andmete salvestamist ilma protsessi taaskäivitamata. Kirjutame väikese programmi, mis kirjutab kettale umbes 1 megabaidi sekundis. Veelgi enam, kui me mingil põhjusel ei saanud andmeid kettale kirjutada, siis me lihtsalt ignoreerime seda ja proovime andmed sekundi pärast uuesti kirjutada. Näites, kus ma kasutan Pythoni, saate kasutada mis tahes 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äivitame programmi ja vaatame failide kirjeldusi

[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äete, on meil kolm standardset failideskriptorit ja veel üks, mille avasime. Kontrollime faili suurust:

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

Andmeid kirjutatakse, proovime faili õigusi muuta:

[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 andmeid alles kirjutatakse, kuigi meie kasutajal puudub luba faili kirjutamiseks. Proovime selle eemaldada:

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

Kuhu andmed kirjas on? Ja kas need on üldse kirjutatud? 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 failideskriptor on endiselt olemas ja me saame seda failideskriptorit käsitleda nagu meie vana faili, saame seda lugeda, kustutada ja kopeerida.

Vaatame 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 tühjendada:

[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

Nagu näete, faili suurus ainult suureneb ja meie pagasiruumi ei töötanud. Vaatame süsteemikõnede dokumentatsiooni avatud. Kui kasutame faili avamisel lippu O_APPEND, siis iga kirjutamise korral kontrollib operatsioonisüsteem faili suurust ja kirjutab andmed faili päris lõppu ning teeb seda aatomiliselt. See võimaldab samasse faili kirjutada mitu lõime või protsessi. Kuid meie koodis me seda lippu ei kasuta. Erinevat failisuurust näeme lsof-is pärast pagasiruumi ainult siis, kui avame faili täiendavaks kirjutamiseks, mis tähendab hoopis meie koodis

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

peame panema

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

Kontrollimine "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

Juba käimasoleva protsessi programmeerimine

Sageli kasutavad programmeerijad programmide loomisel ja testimisel silujaid (näiteks GDB) või rakenduses erinevaid logimise tasemeid. Linux annab võimaluse kirjutada ja muuta juba töötavat programmi, näiteks muuta muutujate väärtusi, määrata katkestuspunkti jne jne.

Tulles tagasi algse küsimuse juurde, et faili kirjutamiseks pole piisavalt kettaruumi, proovime probleemi simuleerida.

Loome oma partitsiooni jaoks faili, mille ühendame 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 is not a block special device.
Proceed anyway? (y,n) y
...
Writing superblocks and filesystem accounting information: done
[user@localhost ~]$

Paigaldage failisüsteem:

[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

Koostame oma omanikuga kataloogi:

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

Avame faili ainult meie programmis kirjutamiseks:

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

Käivitamine

[user@localhost ]$ python openforwrite.py 

Ootame paar sekundit

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

Niisiis, meil on selle artikli alguses kirjeldatud probleem. Vaba ruum 0, 100% hõivatud.

Peame meeles, et vastavalt ülesande tingimustele püüame salvestada väga olulisi andmeid, mis ei saa kaduda. Ja samal ajal peame teenuse parandama ilma protsessi taaskäivitamata.

Oletame, et meil on veel kettaruumi, kuid teises partitsioonis, näiteks /home.

Proovime oma koodi "lennult ümber programmeerida".

Vaatame meie protsessi PID-d, mis on ära söönud kogu kettaruumi:

[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

Ühendage protsessiga gdb kaudu

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

Vaatame avatud faili kirjeldusi:

(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

Vaatame teavet failideskriptori number 3 kohta, mis meid huvitab

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

Pidades meeles, millist süsteemikutset Python teeb (vt ülalt, kus käivitasime strace ja leidsime avatud kutse), teeme faili avamiseks koodi töötlemisel sama protsessi nimel, kuid vajame O_WRONLY|O_CREAT| O_TRUNC bitid asendatakse arvväärtusega. Selleks ava näiteks kerneli allikad siin ja vaadake, millised lipud mille eest vastutavad

#define O_WRONLY 00000001
#define O_CREAT 00000100
#define O_TRUNC 00001000

Ühendame kõik väärtused üheks, saame 00001101

Teeme oma kõne gdb-st

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

Nii saime uue failideskriptori 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

Meenub näide toruga - kuidas bash muudab failideskriptoreid ja oleme juba õppinud dup2 süsteemikutset.

Püüame asendada ühe failikirjelduse teisega

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

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 -> /home/user/123.txt
l-wx------ 1 user user 64 Oct  8 11:15 4 -> /home/user/123.txt

Sulgeme failideskriptori 4, kuna me ei vaja seda:

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

Ja välju 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

Uue faili kontrollimine:

[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äete, 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 lähe kaduma, rakendus töötab, logid kirjutatakse uude asukohta.

Teeme ülesande pisut keerulisemaks

Kujutagem ette, et andmed on meile olulised, kuid meil pole üheski partitsioonis kettaruumi ja me ei saa ketast ühendada.

Mida me saame teha, on suunata oma andmed kuhugi, näiteks torusse, ja omakorda suunata andmed torust võrku läbi mõne programmi, näiteks netcat.
Nimega toru saame luua käsuga mkfifo. See loob failisüsteemis pseudofaili isegi siis, kui sellel pole vaba ruumi.

Taaskäivitage rakendus ja kontrollige:

[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 loome seal edukalt nimega toru:

[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 kõik sellesse torusse minevad andmed kuidagi võrgu kaudu teise serverisse pakkima, selleks sobib sama netcat.

Töötame serveris remote-server.example.com

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

Meie probleemse serveri käivitame eraldi terminalis

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

Nüüd lähevad kõik torusse sattunud andmed automaatselt netcati stdini, mis saadab need pordi 7777 kaudu võrku.

Peame vaid hakkama oma andmeid sellesse nimega torusse kirjutama.

Rakendus meil juba töötab:

[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 lippudest vajame ainult O_WRONLY, kuna fail on juba olemas ja me ei pea seda kustutama

[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

Kaugserveri remote-server.example.com kontrollimine

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

Andmed tulevad, 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 salvestatakse, probleem on lahendatud.

Kasutan võimalust ja tervitan oma kolleege Degirost.
Kuulake Radio-T taskuhäälingusaateid.

Hea kõigile.

Kodutööna soovitan teil mõelda, mis on protsessi failikirjeldustes cat and sleep, kui käivitate järgmise käsu:

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

Allikas: www.habr.com

Lisa kommentaar