Skráarlýsing í Linux með dæmum

Einu sinni í viðtali var ég spurður að því hvað myndir þú gera ef þú finnur bilaða þjónustu vegna þess að diskurinn er orðinn plásslaus?

Ég svaraði að sjálfsögðu að ég myndi sjá hvað þessi staður væri að gera og ef hægt væri þá myndi ég þrífa staðinn.
Þá spurði spyrillinn, hvað ef það er ekkert laust pláss á skiptingunni, en þú sérð heldur ekki skrárnar sem myndu taka allt plássið?

Við þessu sagði ég að það er alltaf hægt að skoða opna skráarlýsingar, til dæmis með lsof skipuninni og skilja hvaða forrit hefur tekið allt tiltækt pláss, og þá er hægt að bregðast við eftir aðstæðum, allt eftir því hvort gagna er þörf .

Spyrillinn truflaði mig við síðasta orðið og bætti við spurningu sinni: „Segjum sem svo að við þurfum ekki gögnin, þetta er bara kembiforrit, en forritið liggur niðri vegna þess að það getur ekki skrifað kembiforritið“?

„allt í lagi,“ svaraði ég, „við getum slökkt á villuleit í forritastillingunni og endurræst hana.
Spyrjandinn mótmælti: „Nei, við getum ekki endurræst forritið, við erum enn með mikilvæg gögn í minni og mikilvægir viðskiptavinir eru tengdir við þjónustuna sjálfa, sem við getum ekki þvingað til að tengjast aftur.

„allt í lagi,“ sagði ég, „ef við getum ekki endurræst forritið og okkur er alveg sama um gögnin, þá getum við hreinsað þessa opnu skrá í gegnum skráarlýsinguna, jafnvel þótt við sjáum hana ekki í ls. skipun á skráarkerfinu."

Spyrillinn var sáttur en ég var það ekki.

Þá hugsaði ég, hvers vegna kafar sá sem prófar þekkingu mína ekki dýpra? En hvað ef gögnin eru mikilvæg eftir allt saman? Hvað ef við getum ekki endurræst ferlið og á sama tíma skrifar þetta ferli í skráarkerfið á skipting sem hefur ekkert laust pláss? Hvað ef við getum ekki týnt ekki aðeins gögnunum sem þegar eru skrifuð, heldur einnig gögnunum sem þetta ferli er að skrifa eða reyna að skrifa?

Tuzik

Í upphafi ferils míns var ég að reyna að búa til lítið forrit sem þurfti að geyma upplýsingar um notendur. Og þá hugsaði ég, hvernig get ég passað notandann við gögnin hans. Til dæmis, ég á Ivanov Ivan Ivanovich, og hann hefur nokkur gögn, en hvernig á að eignast vini við þá? Ég get beint bent á að hundurinn sem heitir "Tuzik" tilheyrir þessum sama Ivan. En hvað ef hann skiptir um nafn og í stað Ivan verður til dæmis Olya? Þá mun það koma í ljós að Olya Ivanovna Ivanova okkar mun ekki lengur eiga hund og Tuzik okkar mun enn tilheyra hinum sem ekki er til Ivan. Gagnagrunnurinn hjálpaði til við að leysa þetta vandamál, sem gaf hverjum notanda einstakt auðkenni (ID), og Tuzik minn var bundinn við þetta auðkenni, sem í raun var bara raðnúmer. Þannig var eigandi tuziksins með kennitölu 2 og á einhverjum tímapunkti var Ivan undir þessum skilríkjum og þá varð Olya undir sömu skilríkjum. Vandamál mannkyns og búfjárræktar var nánast leyst.

Skráarlýsing

Vandamálið við skrá og forrit sem vinnur með þessari skrá er um það bil það sama og hundurinn okkar og maðurinn. Segjum sem svo að ég opnaði skrá sem heitir ivan.txt og byrjaði að skrifa orðið tuzik inn í hana, en tókst að skrifa aðeins fyrsta stafinn „t“ inn í skrána, og þessi skrá var endurnefnd af einhverjum, til dæmis, í olya.txt. En skráin er sú sama og ég vil samt skrifa essið mitt í hana. Í hvert skipti sem þú opnar skrá með kerfiskalli opna í hvaða forritunarmáli sem er fæ ég einstakt auðkenni sem vísar mér á skrá, þetta auðkenni er skráarlýsingin. Og það er alveg sama hvað og hver gerir næst með þessa skrá, það er hægt að eyða henni, það er hægt að endurnefna, það getur skipt um eiganda eða tekið af réttindi til að lesa og skrifa, ég mun samt hafa aðgang að henni, vegna þess að þegar ég opnaði skrána hafði ég réttindi til að lesa og/eða skrifa hana og ég náði að byrja að vinna með hana, sem þýðir að ég verð að halda því áfram.

Á Linux opnar libc bókasafnið 3 lýsingarskrár fyrir hvert keyrt forrit (ferli), með tölunum 0,1,2. Frekari upplýsingar er að finna á krækjunum maður stdio и maður stdout

  • Skráarlýsing 0 heitir STDIN og tengist innslátt forrits.
  • Skráarlýsing 1 heitir STDOUT og er notuð af úttaksforritum eins og prentskipunum.
  • Skráarlýsing 2 heitir STDERR og er notuð af forritum til að gefa út villuboð.

Ef þú opnar einhverja skrá í forritinu þínu til að lesa eða skrifa, þá færðu líklega fyrsta ókeypis auðkennið og það verður númer 3.

Þú getur séð lista yfir skráarlýsingar fyrir hvaða ferli sem er ef þú veist PID þess.

Til dæmis, við skulum opna leikjatölvu með bash og sjá PID ferlisins okkar

[user@localhost ]$ echo $$
15771

Í annarri stjórnborðinu skaltu keyra

[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

Þú getur örugglega hunsað skráarlýsinguna með númerinu 255 innan ramma þessarar greinar, það var opnað fyrir þarfir þínar af bash sjálfum, en ekki af tengda bókasafninu.

Nú eru allar 3 lýsingarskrárnar tengdar gervistöðvatækinu /dev/pts, en við getum samt stjórnað þeim, til dæmis, keyrt í annarri vélinni

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

Og í fyrstu vélinni munum við sjá

[user@localhost ]$ hello world

Redirect og Pipe

Þú getur auðveldlega hnekkt þessum 3 lýsingarskrám í hvaða ferli sem er, þar á meðal í bash, til dæmis í gegnum pípu (pípu) sem tengir tvo ferla, sjá

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

Þú getur keyrt þessa skipun sjálfur með strá -f og sjá hvað er að gerast inni, en ég skal gera það stutt.

Foreldrabash ferli okkar með PID 15771 greinir skipunina okkar og skilur nákvæmlega hversu margar skipanir við viljum keyra, í okkar tilviki eru tvær þeirra: köttur og svefn. Bash veit að það þarf að búa til tvö undirferli og sameina þau í eina pípu. Alls mun bash þurfa 2 undirferli og eina pípu.

Áður en undirferli er búið til, keyrir bash kerfiskall pípa og fær nýjar skráarlýsingar á bráðabirgðapípubuffi, en þessi biðminni tengir enn ekki tvö barnaferla okkar á nokkurn hátt.

Fyrir foreldraferlið lítur út fyrir að pípan sé þegar til staðar, en það eru engir undirferli enn:

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

Notaðu síðan kerfiskallið klón bash býr til tvö undirferli og þrjú ferli okkar munu líta svona út:

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

Ekki gleyma því að klón klónar ferlið ásamt öllum skráarlýsingum, þannig að þeir verða eins í foreldraferlinu og í barninu. Verkefni foreldraferlisins með PID 15771 er að fylgjast með barnaferlunum, svo það bíður bara eftir svari frá börnunum.

Þess vegna þarf hann ekki pípu og hann lokar skráarlýsingunum með tölunum 3 og 4.

Í fyrsta bash barnaferlinu með PID 9004 hringir kerfið dup2, breytir STDOUT skráarlýsingunni okkar númer 1 í skráarlýsingu sem vísar á pípu, í okkar tilfelli er það númer 3. Þannig mun allt sem fyrsta barn ferlið með PID 9004 skrifar í STDOUT falla sjálfkrafa inn í pípubuffið.

Í öðru barnaferlinu með PID 9005, dup2sar þú skrána í STDIN lýsingu númer 0. Nú mun allt sem annað bash okkar með PID 9005 mun lesa úr pípunni.

Eftir það er skráarlýsingum með númerum 3 og 4 einnig lokað í undirferli þar sem þeir eru ekki lengur notaðir.

Ég hunsa vísvitandi skráarlýsingu 255, hann er notaður innbyrðis af bash sjálfum og verður einnig lokaður í undirferli.

Næst, í fyrsta barnaferlinu með PID 9004, byrjar bash með kerfiskalli exec keyrsluskráin sem við tilgreindum á skipanalínunni, í okkar tilviki er það /usr/bin/cat.

Í öðru barnaferlinu með PID 9005 keyrir bash seinni keyrsluna sem við tilgreindum, í okkar tilviki /usr/bin/sleep.

Exec kerfiskallið lokar ekki skráarlýsingum nema þær hafi verið opnaðar með O_CLOEXEC fánanum á þeim tíma sem opna símtalið var keyrt. Í okkar tilviki, eftir að keyra keyrsluskrárnar, verða allar núverandi skráarlýsingar vistaðar.

Athugar í stjórnborðinu:

[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

Eins og þú sérð er einstakt númer pípunnar okkar það sama í báðum ferlunum. Þannig höfum við tengsl milli tveggja mismunandi ferla með sama foreldri.

Fyrir þá sem ekki kannast við kerfissímtölin sem bash notar, mæli ég eindregið með því að keyra skipanir í gegnum strace og sjá hvað gerist inni, til dæmis, svona:

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

Við skulum fara aftur að vandamálinu okkar með að verða uppiskroppa með pláss og reyna að vista gögn án þess að endurræsa ferlið. Skrifum lítið forrit sem mun skrifa á disk um 1 megabæti á sekúndu. Þar að auki, ef við af einhverjum ástæðum gátum ekki skrifað gögn á disk, munum við einfaldlega hunsa þetta og reyna að skrifa gögnin aftur eftir sekúndu. Í dæminu sem ég er að nota Python geturðu notað hvaða önnur forritunarmál sem er.

[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

Keyrðu forritið og skoðaðu skráarlýsingarnar

[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

Eins og þú sérð höfum við 3 staðlaða skráarlýsingar og annan sem við höfum opnað. Við skulum athuga skráarstærðina:

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

gögnin eru skrifuð, við reynum að breyta réttindum á skránni:

[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

Við sjáum að enn er verið að skrifa gögnin, þó notandi okkar hafi ekki rétt til að skrifa í skrána. Við skulum reyna að fjarlægja það:

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

Hvar eru gögnin skrifuð? Og eru þær yfirleitt skrifaðar? Við athugum:

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

Já, skráarlýsingin okkar er enn til og við getum unnið með þessa skráarlýsingu eins og gömlu skrána okkar, við getum lesið hana, hreinsað hana upp og afritað hana.

Skoðaðu skráarstærðina:

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

Skráarstærðin er 19923457. Reynir að hreinsa skrána:

[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

Eins og þú sérð eykst skráarstærðin aðeins og skottið okkar virkaði ekki. Snúum okkur að skjölunum um kerfiskallið opna. Ef við notum O_APPEND fánann þegar skrá er opnuð, þá athugar stýrikerfið við hverja ritun skráarstærðina og skrifar gögn til enda skráarinnar og gerir það atómlega. Þetta gerir mörgum þráðum eða ferlum kleift að skrifa í sömu skrána. En í kóðanum okkar notum við ekki þennan fána. Við getum aðeins séð aðra skráarstærð í lsof eftir trunk ef við opnum skrána til að skrifa, sem þýðir að í kóðanum okkar, í staðinn fyrir

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

við verðum að setja

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

Athugar með "w" fána

[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

og með "a" fána

[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

Forritun ferli sem þegar er í gangi

Oft, þegar forritarar eru búnir til og prófað, nota forritarar villuleit (til dæmis GDB) eða ýmis stig innskráningar í forritinu. Linux veitir möguleika á að skrifa og breyta forriti sem þegar er í gangi, eins og að breyta gildum breyta, stilla brotpunkt, og svo framvegis og svo framvegis.

Þegar við snúum aftur að upprunalegu spurningunni um skort á plássi til að skrifa skrá, skulum við reyna að líkja eftir vandamálinu.

Við skulum búa til skrá fyrir skiptinguna okkar, sem við munum tengja sem sérstakt drif:

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

Við skulum búa til skráarkerfi:

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

Við skulum tengja skráarkerfið:

[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

Búðu til möppu með eiganda okkar:

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

Við skulum opna skrána til að skrifa aðeins í forritinu okkar:

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

Sjósetja

[user@localhost ]$ python openforwrite.py 

Bíð í nokkrar sekúndur

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

Svo við fengum vandamálið sem lýst er í upphafi þessarar greinar. Laust pláss 0, upptekið 100%.

Við munum að í samræmi við aðstæður vandamálsins erum við að reyna að skrá mjög mikilvæg gögn sem ekki má glatast. Og við að gera það þurfum við að laga þjónustuna án þess að endurræsa ferlið.

Segjum að við höfum ennþá diskpláss, en í annarri skiptingu, til dæmis í / heima.

Við skulum reyna að "endurforrita á flugi" kóðann okkar.

Við skoðum PID ferlisins okkar, sem borðaði allt diskplássið:

[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

Tengist ferli með gdb

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

Við skoðum opna skráarlýsingar:

(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

Við skoðum upplýsingar um skráarlýsinguna með númer 3, sem vekur áhuga okkar

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

Með því að hafa í huga hvaða kerfiskall Python gerir (sjá hér að ofan hvar við keyrðum strace og fundum opið símtal), á meðan við vinnum kóðann okkar til að opna skrá, gerum við það sama sjálf fyrir hönd ferlisins okkar, en við þurfum O_WRONLY|O_CREAT| O_TRUNC bitar skipt út fyrir tölugildi. Til að gera þetta, opnaðu til dæmis kjarnaheimildirnar hér og sjá hvaða fánar bera ábyrgð á hverju

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

Við sameinum öll gildin í eitt, við fáum 00001101

Keyrir símtal okkar frá gdb

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

Svo við fengum nýjan skráarlýsingu með númeri 4 og nýja opna skrá á annarri skipting, athugaðu:

(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

Við munum eftir dæminu með pipe - hvernig bash breytir skráarlýsingum og höfum þegar lært dup2 kerfiskallið.

Er að reyna að skipta út einum skráarlýsingu fyrir annan

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

Við athugum:

(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

Lokaðu skráarlýsingu 4, þar sem við þurfum hana ekki:

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

Og farðu úr 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

Athugar nýju skrána:

[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

Eins og þú sérð eru gögnin skrifuð í nýja skrá, við athugum þá gömlu:

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

Gögnin glatast ekki, forritið virkar, annálarnir eru skrifaðir á nýjan stað.

Gerum hlutina aðeins erfiðari

Ímyndaðu þér að gögnin séu okkur mikilvæg, en við höfum ekki pláss í neinum skiptingum og getum ekki tengt diskinn.

Það sem við getum gert er að beina gögnunum okkar einhvers staðar, til dæmis í pípu, og beina gögnunum frá pípunni yfir á netið í gegnum eitthvað forrit, eins og netcat.
Við getum búið til nafngreinda pípu með mkfifo skipuninni. Það mun búa til gerviskrá á skráarkerfinu, jafnvel þótt ekkert laust pláss sé á henni.

Endurræstu forritið og athugaðu:

[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

Það er ekkert pláss, en við búum til nafngreinda pípu þar:

[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ú þurfum við einhvern veginn að vefja öllum gögnum sem komast inn í þessa pípu yfir á annan netþjón í gegnum netið, sami netkötturinn er hentugur fyrir þetta.

Á remote-server.example.com þjóninum skaltu keyra

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

Á vandamálaþjóninum okkar skaltu keyra í sérstakri flugstöð

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

Nú fara öll gögnin sem komast inn í pípuna sjálfkrafa í stdin í netcat, sem mun senda þau á netið á port 7777.

Allt sem við þurfum að gera er að byrja að skrifa gögnin okkar í þessa nafngreindu pípu.

Við erum nú þegar með forrit í gangi:

[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

Af öllum fánum þurfum við aðeins O_WRONLY þar sem skráin er þegar til og við þurfum ekki að hreinsa hana

[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

Athugar ytri netþjóninn remote-server.example.com

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

Gögn eru að koma, við athugum vandamálaþjóninn

[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

Gögnin eru vistuð, vandamálið er leyst.

Ég nota tækifærið til að heilsa upp á samstarfsfólk mitt frá Degiro.
Hlustaðu á Radio-T podcast.

Gott fyrir alla.

Sem heimavinna legg ég til að hugsa um hvað verður í skráarlýsingum katta- og svefnferlisins ef þú keyrir eftirfarandi skipun:

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

Heimild: www.habr.com

Bæta við athugasemd