Kerran haastattelussa minulta kysyttiin, mitä aiot tehdä, jos huomaat, että palvelu ei toimi, koska levytila on loppunut?
Tietenkin vastasin, että katsoisin mitä tämä paikka on miehittänyt ja jos mahdollista, siivoan paikan.
Sitten haastattelija kysyi, mitä jos osiolla ei ole vapaata tilaa, mutta et myöskään näe tiedostoja, jotka vievät kaiken tilan?
Tähän sanoin, että aina voi katsoa avoimia tiedostokuvaajia esimerkiksi lsof-komennolla ja ymmärtää mikä sovellus on vienyt kaiken käytettävissä olevan tilan, ja sitten voi toimia olosuhteiden mukaan riippuen siitä, tarvitaanko tietoja. .
Haastattelija keskeytti minut viimeiseen sanaan ja lisäsi kysymykseensä: "Oletetaan, että emme tarvitse tietoja, se on vain virheenkorjausloki, mutta sovellus ei toimi, koska se ei voi kirjoittaa virheenkorjausta"?
"Okei", vastasin, "voimme poistaa virheenkorjauksen käytöstä sovelluksen asetuksista ja käynnistää sen uudelleen."
Haastattelija vastusti: "Ei, emme voi käynnistää sovellusta uudelleen, meillä on edelleen tärkeitä tietoja muistissa ja tärkeät asiakkaat ovat yhteydessä itse palveluun, joita emme voi pakottaa yhdistämään uudelleen."
"Okei", sanoin, "jos emme voi käynnistää sovellusta uudelleen ja tiedot eivät ole meille tärkeitä, voimme yksinkertaisesti tyhjentää tämän avoimen tiedoston tiedostokuvaajan kautta, vaikka emme näe sitä ls-komennossa tiedostojärjestelmässä."
Haastattelija oli tyytyväinen, mutta minä en.
Sitten ajattelin, miksi tietoni testaaja ei kaivaudu syvemmälle? Mutta entä jos tiedot ovat kuitenkin tärkeitä? Entä jos prosessia ei voida käynnistää uudelleen ja prosessi kirjoittaa tiedostojärjestelmään osiossa, jossa ei ole vapaata tilaa? Entä jos emme voi menettää jo kirjoitettuja tietoja, vaan myös tietoja, jotka tämä prosessi kirjoittaa tai yrittää kirjoittaa?
jolla
Urani alussa yritin luoda pienen sovelluksen, joka tarvitsi käyttäjätietojen tallentamista. Ja sitten ajattelin, kuinka voin yhdistää käyttäjän hänen tietoihinsa. Esimerkiksi minulla on Ivanov Ivan Ivanovich, ja hänellä on tietoa, mutta kuinka voin ystävystyä heidän kanssaan? Voin huomauttaa suoraan, että koira nimeltä "Tuzik" kuuluu juuri tälle Ivanille. Mutta entä jos hän vaihtaa nimensä ja Ivanin sijaan tulee esimerkiksi Olya? Sitten käy ilmi, että Olya Ivanovna Ivanovallamme ei enää ole koiraa, ja Tuzikimme kuuluu edelleen olemattomalle Ivanille. Tietokanta, joka antoi jokaiselle käyttäjälle yksilöllisen tunnisteen (ID), auttoi ratkaisemaan tämän ongelman, ja Tuzikni oli sidottu tähän tunnukseen, joka itse asiassa oli vain sarjanumero. Siten ässän omistajalla oli tunnusnumero 2, ja jossain vaiheessa Ivan oli tämän tunnuksen alla, ja sitten Olyasta tuli sama tunnus. Ihmiskunnan ja karjanhoidon ongelma ratkesi käytännössä.
Tiedoston kuvaus
Tiedoston ja sen kanssa toimivan ohjelman ongelma on suunnilleen sama kuin koirallamme ja ihmisellämme. Oletetaan, että avasin tiedoston nimeltä ivan.txt ja aloin kirjoittamaan siihen sanaa tuzik, mutta onnistuin kirjoittamaan vain ensimmäisen kirjaimen "t" tiedostoon ja joku nimesi tämän tiedoston uudelleen esimerkiksi olya.txt:ksi. Mutta tiedosto pysyy samana, ja haluan silti tallentaa ässäni siihen. Aina kun tiedosto avataan järjestelmäkutsulla
Linuxissa libc-kirjasto avaa 3 kuvaustiedostoa kullekin käynnissä olevalle sovellukselle (prosessille), numeroitu 0,1,2. Lisätietoa löytyy linkeistä
- Tiedoston kuvaaja 0 on nimeltään STDIN, ja se liittyy sovelluksen syötteeseen
- Tiedoston kuvaaja 1 on nimeltään STDOUT, ja sovellukset käyttävät sitä tietojen, kuten tulostuskomentojen, tulostamiseen
- Tiedostokuvaajaa 2 kutsutaan nimellä STDERR, ja sovellukset käyttävät sitä virhesanomien tulostamiseen.
Jos ohjelmassasi avaat minkä tahansa tiedoston lukemista tai kirjoittamista varten, saat todennäköisesti ensimmäisen ilmaisen tunnuksen ja se on numero 3.
Voit tarkastella minkä tahansa prosessin tiedostokuvausluetteloa, jos tiedät sen PID:n.
Avataan esimerkiksi bash-konsoli ja katsotaan prosessimme PID-tunnusta
[user@localhost ]$ echo $$
15771
Toisessa konsolissa juostaan
[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
Voit turvallisesti jättää huomioimatta tiedostokuvaajan numero 255 tätä artikkelia varten; sen avasi tarpeitaan varten itse bash, ei linkitetty kirjasto.
Nyt kaikki 3 kuvaajatiedostoa on liitetty pseudopäätelaitteeseen
[user@localhost ]$ echo "hello world" > /proc/15771/fd/0
Ja ensimmäisessä konsolissa näemme
[user@localhost ]$ hello world
Uudelleenohjaus ja putki
Voit helposti ohittaa nämä 3 kuvaajatiedostoa missä tahansa prosessissa, myös bashissa, esimerkiksi putken kautta, joka yhdistää kaksi prosessia, katso
[user@localhost ]$ cat /dev/zero | sleep 10000
Voit suorittaa tämän komennon itse viiva -f ja katso mitä sisällä tapahtuu, mutta kerron lyhyesti.
Vanhemman bash-prosessimme PID 15771:llä jäsentää komentomme ja ymmärtää tarkalleen kuinka monta komentoa haluamme suorittaa, meidän tapauksessamme niitä on kaksi: cat ja sleep. Bash tietää, että sen on luotava kaksi aliprosessia ja yhdistettävä ne yhdeksi putkeksi. Yhteensä bash tarvitsee 2 lapsiprosessia ja yhden putken.
Bash suorittaa järjestelmäkutsun ennen aliprosessien luomista
Pääprosessissa näyttää jo olevan putki, mutta aliprosesseja ei vielä ole:
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
Käytä sitten järjestelmäkutsua
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
Älä unohda, että klooni kloonaa prosessin ja kaikki tiedostokuvaajat, joten ne ovat samat pääprosessissa ja aliprosessissa. Pääprosessin PID 15771:n tehtävänä on seurata lapsiprosesseja, joten se vain odottaa vastausta lapsilta.
Siksi se ei tarvitse putkea, ja se sulkee tiedostokuvaajat, joiden numerot ovat 3 ja 4.
Ensimmäisessä lapsibash-prosessissa, jossa on PID 9004, järjestelmäkutsu
Toisessa aliprosessissa, jossa on PID 9005, bash käyttää dup2:ta muuttaakseen tiedostokuvaajan STDIN-numeroa 0. Nyt kaikki, mitä toinen bash, jolla on PID 9005, lukee, luetaan putkesta.
Tämän jälkeen myös tiedostokuvaajat numeroilla 3 ja 4 suljetaan lapsiprosesseissa, koska niitä ei enää käytetä.
Jätän tietoisesti huomioimatta tiedostokuvaajan 255; bash itse käyttää sitä sisäisiin tarkoituksiin ja se suljetaan myös lapsiprosesseissa.
Seuraavaksi ensimmäisessä aliprosessissa, jossa on PID 9004, bash alkaa käyttää järjestelmäkutsua
Toisessa aliprosessissa, jossa on PID 9005, bash suorittaa toisen määrittämämme suoritettavan tiedoston, meidän tapauksessamme /usr/bin/sleep.
Exec-järjestelmäkutsu ei sulje tiedostokahvoja, ellei niitä ole avattu O_CLOEXEC-lipulla, kun avoin kutsu tehtiin. Meidän tapauksessamme suoritettavien tiedostojen käynnistämisen jälkeen kaikki nykyiset tiedostokuvaajat tallennetaan.
Tarkista konsolista:
[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
Kuten näet, putkemme yksilöllinen numero on sama molemmissa prosesseissa. Näin ollen meillä on yhteys kahden eri prosessin välillä saman vanhemman kanssa.
Niille, jotka eivät tunne bashin käyttämiä järjestelmäkutsuja, suosittelen komennon suorittamista stracen kautta ja katsomaan mitä tapahtuu sisäisesti, esimerkiksi näin:
strace -s 1024 -f bash -c "ls | grep hello"
Palataan ongelmaamme, jossa on vähän levytilaa ja yritämme tallentaa tietoja käynnistämättä prosessia uudelleen. Kirjoitetaan pieni ohjelma, joka kirjoittaa levylle noin 1 megatavu sekunnissa. Lisäksi, jos emme jostain syystä pystyneet kirjoittamaan tietoja levylle, jätämme tämän huomiotta ja yritämme kirjoittaa tiedot uudelleen sekunnissa. Esimerkissä, jossa käytän Pythonia, voit käyttää mitä tahansa muuta ohjelmointikieltä.
[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
Suoritetaan ohjelma ja tarkastellaan tiedostojen kuvauksia
[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
Kuten näet, meillä on kolme vakiotiedostokuvaajaamme ja vielä yksi, jonka avasimme. Katsotaanpa tiedoston kokoa:
[user@localhost ]$ ls -lah 123.txt
-rw-rw-r-- 1 user user 117M Oct 7 16:30 123.txt
Tietoja kirjoitetaan, yritämme muuttaa tiedoston käyttöoikeuksia:
[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äemme, että tietoja kirjoitetaan edelleen, vaikka käyttäjällämme ei ole oikeutta kirjoittaa tiedostoon. Yritetään poistaa se:
[user@localhost ]$ sudo rm 123.txt
[user@localhost ]$ ls 123.txt
ls: cannot access 123.txt: No such file or directory
Missä tiedot on kirjoitettu? Ja onko niitä kirjoitettu ollenkaan? Tarkistamme:
[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)
Kyllä, tiedostokuvaajamme on edelleen olemassa ja voimme käsitellä tätä tiedostokuvaajaa kuin vanhaa tiedostoamme, voimme lukea, tyhjentää ja kopioida sen.
Katsotaanpa tiedoston kokoa:
[user@localhost ]$ lsof | grep 123.txt
python 31083 user 3w REG 8,5 19923457 2621522 /home/user/123.txt
Tiedoston koko on 19923457. Yritetään tyhjentää tiedosto:
[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
Kuten näette, tiedoston koko vain kasvaa ja runkomme ei toiminut. Katsotaanpa järjestelmäkutsun dokumentaatiota
with open("123.txt", "w") as f:
meidän täytyy laittaa
with open("123.txt", "a") as f:
Tarkistetaan "w"-lipulla
[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"-lipulla
[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
Jo käynnissä olevan prosessin ohjelmointi
Usein ohjelmoijat käyttävät ohjelmia luodessaan ja testaaessaan debuggereita (esim. GDB) tai erilaisia kirjautumistasoja sovelluksessa. Linux tarjoaa mahdollisuuden kirjoittaa ja muuttaa jo käynnissä olevaa ohjelmaa, esimerkiksi muuttaa muuttujien arvoja, asettaa keskeytyskohdan jne., jne.
Palatakseni alkuperäiseen kysymykseen siitä, ettei levytilaa ole tarpeeksi tiedoston kirjoittamiseen, yritetään simuloida ongelmaa.
Luodaan osiollemme tiedosto, jonka liitämme erilliseksi levyksi:
[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 ~]$
Luodaan tiedostojärjestelmä:
[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 ~]$
Liitä tiedostojärjestelmä:
[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
Luomme hakemiston omistajamme kanssa:
[user@localhost ~]$ sudo mkdir /mnt/logs
[user@localhost ~]$ sudo chown user: /mnt/logs
Avataan tiedosto vain kirjoittamista varten ohjelmassamme:
with open("/mnt/logs/123.txt", "w") as f:
Tuoda markkinoille
[user@localhost ]$ python openforwrite.py
Odotamme muutaman sekunnin
[user@localhost ~]$ df -h | grep mnt
/dev/loop0 8.7M 8.0M 0 100% /mnt
Meillä on siis tämän artikkelin alussa kuvattu ongelma. Vapaa tila 0, 100 % varattu.
Muistamme, että ongelman olosuhteiden mukaan yritämme tallentaa erittäin tärkeitä tietoja, joita ei voi menettää. Ja samaan aikaan meidän on korjattava palvelu käynnistämättä prosessia uudelleen.
Oletetaan, että meillä on vielä levytilaa, mutta eri osiossa, esimerkiksi /home.
Yritetään "ohjelmoida uudelleen" koodimme.
Katsotaanpa prosessimme PID:tä, joka on syönyt kaiken levytilan:
[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
Yhdistä prosessiin gdb:n kautta
[user@localhost ~]$ gdb -p 10078
...
(gdb)
Katsotaanpa avoimien tiedostojen kuvauksia:
(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
Tarkastelemme meitä kiinnostavia tietoja tiedostokuvauksesta numero 3
(gdb) shell cat /proc/10078/fdinfo/3
pos: 8189952
flags: 0100001
mnt_id: 482
Kun muistamme, mitä järjestelmäkutsua Python tekee (katso yllä, missä suoritimme strace-kutsun ja löysimme avoimen kutsun), kun käsittelemme koodiamme avataksemme tiedoston, teemme saman itse prosessimme puolesta, mutta tarvitsemme O_WRONLY|O_CREAT| O_TRUNC-bitit korvataan numeerisella arvolla. Voit tehdä tämän avaamalla esimerkiksi ytimen lähteet
#define O_WRONLY 00000001
#define O_CREAT 00000100
#define O_TRUNC 00001000
Yhdistämme kaikki arvot yhdeksi, saamme 00001101
Suoritamme puhelumme gdb:stä
(gdb) call open("/home/user/123.txt", 00001101,0666)
$1 = 4
Joten saimme uuden tiedostokuvaajan numerolla 4 ja uuden avoimen tiedoston toisessa osiossa, tarkistamme:
(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
Muistamme esimerkin pipellä - kuinka bash muuttaa tiedostokuvauksia, ja olemme jo oppineet dup2-järjestelmäkutsun.
Yritämme korvata yhden tiedostokuvaajan toisella
(gdb) call dup2(4,3)
$2 = 3
tarkista:
(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
Suljemme tiedostokuvaajan 4, koska emme tarvitse sitä:
(gdb) call close (4)
$1 = 0
Ja poistu 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
Uuden tiedoston tarkistaminen:
[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
Kuten näet, tiedot kirjoitetaan uuteen tiedostoon, tarkistetaan vanha:
[user@localhost ~]$ ls -lah /mnt/logs/123.txt
-rw-rw-r-- 1 user user 7.9M Oct 8 11:08 /mnt/logs/123.txt
Tietoja ei häviä, sovellus toimii, lokit kirjoitetaan uuteen paikkaan.
Monimutkaistaan tehtävää hieman
Kuvitellaan, että tiedot ovat meille tärkeitä, mutta meillä ei ole levytilaa missään osioissa, emmekä voi yhdistää levyä.
Mitä voimme tehdä, on ohjata tietomme jonnekin, esimerkiksi putkeen, ja vuorostaan ohjata tiedot putkesta verkkoon jonkin ohjelman, esimerkiksi netcatin, kautta.
Voimme luoda nimetyn putken komennolla mkfifo. Se luo pseudotiedoston tiedostojärjestelmään, vaikka siinä ei olisi vapaata tilaa.
Käynnistä sovellus uudelleen ja tarkista:
[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
Levytilaa ei ole, mutta luomme siihen onnistuneesti nimetyn putken:
[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
Nyt täytyy jotenkin kääriä kaikki tähän putkeen menevä data verkon kautta toiselle palvelimelle, sama netcat sopii tähän.
Käynnistämme palvelimella remote-server.example.com
[user@localhost ~]$ nc -l 7777 > 123.txt
Ongelmallisella palvelimellamme käynnistämme erillisen terminaalin
[user@localhost ~]$ nc remote-server.example.com 7777 < /mnt/logs/megapipe
Nyt kaikki putkeen päätyvät tiedot menevät automaattisesti netcatin stdiniin, joka lähettää ne verkkoon portissa 7777.
Meidän tarvitsee vain alkaa kirjoittaa tietomme tähän nimettyyn putkeen.
Meillä on jo sovellus käynnissä:
[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
Kaikista lipuista tarvitsemme vain O_WRONLY, koska tiedosto on jo olemassa, eikä meidän tarvitse tyhjentää sitä
[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
Tarkistetaan etäpalvelin remote-server.example.com
[user@localhost ~]$ ls -lah 123.txt
-rw-rw-r-- 1 user user 38M Oct 8 14:21 123.txt
Tietoja tulee, tarkistamme ongelmapalvelimen
[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
Tiedot tallennetaan, ongelma on ratkaistu.
Käytän tilaisuutta hyväkseni tervehtiäkseni kollegoitani Degirosta.
Kuuntele Radio-T podcasteja.
Hyvä kaikille.
Kotitehtävänä ehdotan, että mietit, mitä prosessitiedostojen kuvauksissa cat and sleep on, jos suoritat seuraavan komennon:
[user@localhost ~]$ cat /dev/zero 2>/dev/null| sleep 10000
Lähde: will.com