Jednom su me tijekom intervjua pitali što ćete učiniti ako ustanovite da servis ne radi zbog činjenice da je na disku ponestalo prostora?
Naravno, odgovorio sam da ću vidjeti što je na ovom mjestu i ako bude moguće, očistit ću to mjesto.
Zatim je ispitivač pitao, što ako nema slobodnog prostora na particiji, ali također ne vidite datoteke koje bi zauzele sav prostor?
Na ovo sam rekao da uvijek možete pogledati otvorene deskriptore datoteka, na primjer pomoću naredbe lsof, i shvatiti koja je aplikacija zauzela sav raspoloživi prostor, a zatim možete djelovati prema okolnostima, ovisno o tome jesu li podaci potrebni .
Ispitivač me prekinuo na posljednjoj riječi, dodajući na svoje pitanje: "Pretpostavimo da nam podaci nisu potrebni, to je samo zapisnik o otklanjanju pogrešaka, ali aplikacija ne radi jer ne može napisati ispravljanje pogrešaka"?
"U redu", odgovorio sam, "možemo isključiti debug u konfiguraciji aplikacije i ponovno je pokrenuti."
Ispitivač se usprotivio: "Ne, ne možemo ponovno pokrenuti aplikaciju, još uvijek imamo važne podatke pohranjene u memoriji, a važni klijenti povezani su sa samom uslugom, koje ne možemo prisiliti da se ponovno povežu."
“u redu,” rekao sam, “ako ne možemo ponovo pokrenuti aplikaciju i podaci nam nisu važni, onda možemo jednostavno izbrisati ovu otvorenu datoteku kroz deskriptor datoteke, čak i ako je ne vidimo u naredbi ls na sustavu datoteka.”
Ispitivač je bio zadovoljan, ali ja nisam.
Onda sam pomislio, zašto osoba koja testira moje znanje ne kopa dublje? Ali što ako su podaci ipak važni? Što ako ne možemo ponovno pokrenuti proces, a proces piše u datotečni sustav na particiji na kojoj nema slobodnog prostora? Što ako ne možemo izgubiti ne samo podatke koji su već zapisani, već i podatke koje ovaj proces zapisuje ili pokušava zapisati?
Tuzik
Na početku svoje karijere pokušao sam stvoriti malu aplikaciju koja je trebala pohranjivati korisničke podatke. I onda sam pomislio, kako mogu spojiti korisnika s njegovim podacima. Na primjer, imam Ivanova Ivana Ivanoviča i on ima neke informacije, ali kako se mogu sprijateljiti s njima? Mogu izravno istaknuti da pas po imenu “Tuzik” pripada upravo ovom Ivanu. Ali što ako promijeni ime i umjesto Ivana postane, na primjer, Olya? Tada će se ispostaviti da naša Olya Ivanovna Ivanova više neće imati psa, a naš će Tuzik i dalje pripadati nepostojećem Ivanu. U rješavanju ovog problema pomogla je baza podataka koja je svakom korisniku davala jedinstveni identifikator (ID), a moj Tuzik je bio vezan za taj ID, koji je, zapravo, bio samo serijski broj. Dakle, vlasnik tuzika je imao broj osobne iskaznice 2, te je u nekom trenutku pod ovom osobnom iskaznicom bio Ivan, a zatim je pod tom istom osobnom iskaznicom postala Olya. Problem ljudstva i stočarstva bio je praktički riješen.
Deskriptor datoteke
Problem datoteke i programa koji radi s tom datotekom otprilike je isti kao kod našeg psa i čovjeka. Pretpostavimo da sam otvorio datoteku pod nazivom ivan.txt i počeo u nju pisati riječ tuzik, ali sam uspio napisati samo prvo slovo “t” u datoteku, a tu je datoteku netko preimenovao, na primjer, u olya.txt. Ali datoteka ostaje ista i još uvijek želim u nju zabilježiti svog asa. Svaki put kad se datoteka otvori pozivom sustava
U Linuxu biblioteka libc otvara 3 datoteke deskriptora za svaku pokrenutu aplikaciju (proces), označene brojevima 0,1,2. Više informacija možete pronaći na poveznicama
- Deskriptor datoteke 0 naziva se STDIN i povezan je s unosom aplikacije
- Deskriptor datoteke 1 naziva se STDOUT i koriste ga aplikacije za izlaz podataka, kao što su naredbe za ispis
- Deskriptor datoteke 2 naziva se STDERR i koriste ga aplikacije za ispis poruka o pogreškama.
Ako u svom programu otvorite bilo koju datoteku za čitanje ili pisanje, tada ćete najvjerojatnije dobiti prvi besplatni ID i to će biti broj 3.
Popis deskriptora datoteka može se vidjeti za bilo koji proces ako znate njegov PID.
Na primjer, otvorimo bash konzolu i pogledajmo PID našeg procesa
[user@localhost ]$ echo $$
15771
U drugoj konzoli trčimo
[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
Za potrebe ovog članka možete slobodno zanemariti deskriptor datoteke broj 255; otvorio ga je za svoje potrebe sam bash, a ne povezana biblioteka.
Sada su sve 3 datoteke deskriptora pridružene pseudoterminalnom uređaju
[user@localhost ]$ echo "hello world" > /proc/15771/fd/0
A u prvoj konzoli ćemo vidjeti
[user@localhost ]$ hello world
Preusmjeravanje i usmjeravanje
Ove 3 datoteke deskriptora možete lako nadjačati u bilo kojem procesu, uključujući bash, na primjer kroz cijev koja povezuje dva procesa, pogledajte
[user@localhost ]$ cat /dev/zero | sleep 10000
Ovu naredbu možete sami pokrenuti pomoću strace -f i vidjeti što se unutra događa, ali reći ću vam ukratko.
Naš nadređeni bash proces s PID-om 15771 analizira našu naredbu i točno razumije koliko naredbi želimo pokrenuti, u našem slučaju postoje dvije: cat i sleep. Bash zna da treba stvoriti dva procesa djeteta i spojiti ih u jednu cijev. Ukupno će bash trebati 2 podređena procesa i jednu cijev.
Bash pokreće sistemski poziv prije stvaranja podređenih procesa
Za nadređeni proces, izgleda da već postoji kanal, ali još nema podređenih procesa:
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
Zatim pomoću sistemskog poziva
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
Ne zaboravite da clone klonira proces zajedno sa svim deskriptorima datoteka, tako da će oni biti isti u roditeljskom procesu iu podređenim. Posao nadređenog procesa s PID-om 15771 je nadgledanje podređenih procesa, tako da jednostavno čeka odgovor od djece.
Stoga mu ne treba cijev i zatvara deskriptore datoteka pod brojevima 3 i 4.
U prvom podređenom bash procesu s PID-om 9004, sistemski poziv
U drugom podređenom procesu s PID-om 9005, bash koristi dup2 za promjenu deskriptora datoteke STDIN broj 0. Sada će sve što će naš drugi bash s PID-om 9005 pročitati biti pročitano iz cijevi.
Nakon toga se deskriptori datoteka pod brojevima 3 i 4 također zatvaraju u podređenim procesima jer se više ne koriste.
Namjerno zanemarujem deskriptor datoteke 255; koristi ga sam bash za interne potrebe i također će biti zatvoren u podređenim procesima.
Zatim, u prvom podređenom procesu s PID-om 9004, bash počinje koristiti sistemski poziv
U drugom podređenom procesu s PID-om 9005, bash pokreće drugu izvršnu datoteku koju smo naveli, u našem slučaju /usr/bin/sleep.
Exec sistemski poziv ne zatvara rukovanje datotekama osim ako nisu bile otvorene s O_CLOEXEC zastavom u vrijeme otvaranja poziva. U našem slučaju, nakon pokretanja izvršnih datoteka, svi trenutni deskriptori datoteka bit će spremljeni.
Provjerite u konzoli:
[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
Kao što vidite, jedinstveni broj naše cijevi isti je u oba procesa. Tako imamo vezu između dva različita procesa s istim roditeljem.
Za one koji nisu upoznati sa sistemskim pozivima koje bash koristi, toplo preporučujem pokretanje naredbi kroz strace i vidjeti što se interno događa, na primjer ovako:
strace -s 1024 -f bash -c "ls | grep hello"
Vratimo se našem problemu s malo prostora na disku i pokušaju spremanja podataka bez ponovnog pokretanja procesa. Napišimo mali program koji će pisati otprilike 1 megabajt u sekundi na disk. Štoviše, ako iz nekog razloga nismo uspjeli zapisati podatke na disk, jednostavno ćemo to ignorirati i pokušati ponovno zapisati podatke za sekundu. U primjeru koji koristim Python, možete koristiti bilo koji drugi programski jezik.
[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
Pokrenimo program i pogledajmo deskriptore datoteka
[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
Kao što vidite, imamo svoja 3 standardna deskriptora datoteka i još jedan koji smo otvorili. Provjerimo veličinu datoteke:
[user@localhost ]$ ls -lah 123.txt
-rw-rw-r-- 1 user user 117M Oct 7 16:30 123.txt
Podaci se zapisuju, pokušavamo promijeniti dopuštenja za datoteku:
[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
Vidimo da se podaci još uvijek zapisuju, iako naš korisnik nema dozvolu za pisanje u datoteku. Pokušajmo ga ukloniti:
[user@localhost ]$ sudo rm 123.txt
[user@localhost ]$ ls 123.txt
ls: cannot access 123.txt: No such file or directory
Gdje su upisani podaci? I jesu li uopće napisani? Provjeravamo:
[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)
Da, naš deskriptor datoteke još uvijek postoji i možemo tretirati ovaj deskriptor datoteke kao našu staru datoteku, možemo je čitati, brisati i kopirati.
Pogledajmo veličinu datoteke:
[user@localhost ]$ lsof | grep 123.txt
python 31083 user 3w REG 8,5 19923457 2621522 /home/user/123.txt
Veličina datoteke je 19923457. Pokušajmo izbrisati datoteku:
[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
Kao što vidite, veličina datoteke se samo povećava, a naš trunk nije radio. Pogledajmo dokumentaciju o pozivu sustava
with open("123.txt", "w") as f:
moramo staviti
with open("123.txt", "a") as f:
Provjera zastavom "w".
[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
i sa zastavom "a".
[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
Programiranje već pokrenutog procesa
Često programeri pri izradi i testiranju programa koriste debuggere (primjerice GDB) ili razne razine logovanja u aplikaciji. Linux pruža mogućnost stvarnog pisanja i mijenjanja već pokrenutog programa, na primjer, mijenjanje vrijednosti varijabli, postavljanje prijelomne točke, itd., itd.
Vraćajući se na izvorno pitanje o nedovoljno prostora na disku za pisanje datoteke, pokušajmo simulirati problem.
Kreirajmo datoteku za našu particiju, koju ćemo montirati kao zaseban disk:
[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 ~]$
Kreirajmo datotečni sustav:
[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 ~]$
Montirajte datotečni sustav:
[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
S našim vlasnikom kreiramo imenik:
[user@localhost ~]$ sudo mkdir /mnt/logs
[user@localhost ~]$ sudo chown user: /mnt/logs
Otvorimo datoteku samo za pisanje u našem programu:
with open("/mnt/logs/123.txt", "w") as f:
Pokreni
[user@localhost ]$ python openforwrite.py
Čekamo nekoliko sekundi
[user@localhost ~]$ df -h | grep mnt
/dev/loop0 8.7M 8.0M 0 100% /mnt
Dakle, imamo problem opisan na početku ovog članka. Slobodnog prostora 0, 100% zauzeto.
Sjećamo se da prema uvjetima zadatka pokušavamo zabilježiti vrlo važne podatke koji se ne mogu izgubiti. A u isto vrijeme, moramo popraviti uslugu bez ponovnog pokretanja procesa.
Recimo da još uvijek imamo prostora na disku, ali na drugoj particiji, na primjer u /home.
Pokušajmo “u hodu reprogramirati” naš kod.
Pogledajmo PID našeg procesa, koji je pojeo sav prostor na disku:
[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
Povežite se s procesom putem gdb-a
[user@localhost ~]$ gdb -p 10078
...
(gdb)
Pogledajmo deskriptore otvorene datoteke:
(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
Gledamo informacije o deskriptoru datoteke broj 3, koji nas zanima
(gdb) shell cat /proc/10078/fdinfo/3
pos: 8189952
flags: 0100001
mnt_id: 482
Imajući na umu koji sistemski poziv upućuje Python (pogledajte gore gdje smo pokrenuli strace i pronašli otvoreni poziv), prilikom obrade našeg koda za otvaranje datoteke, sami činimo isto u ime našeg procesa, ali trebamo O_WRONLY|O_CREAT| O_TRUNC bitovi zamjenjuju se numeričkom vrijednošću. Da biste to učinili, otvorite, na primjer, izvore kernela
#define O_POGREŠNO 00000001
#define O_CREAT 00000100
#definiraj O_TRUNC 00001000
Kombiniramo sve vrijednosti u jednu, dobivamo 00001101
Pozivamo iz gdb-a
(gdb) call open("/home/user/123.txt", 00001101,0666)
$1 = 4
Dakle, dobili smo novi deskriptor datoteke s brojem 4 i novu otvorenu datoteku na drugoj particiji, provjeravamo:
(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
Sjećamo se primjera s pipe - kako bash mijenja deskriptore datoteka, a sistemski poziv dup2 već smo naučili.
Pokušavamo zamijeniti jedan deskriptor datoteke drugim
(gdb) call dup2(4,3)
$2 = 3
Provjeravamo:
(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
Zatvaramo deskriptor datoteke 4 jer nam ne treba:
(gdb) call close (4)
$1 = 0
I izađite iz gdb-a
(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
Provjera nove datoteke:
[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
Kao što vidite, podaci su zapisani u novu datoteku, provjerimo staru:
[user@localhost ~]$ ls -lah /mnt/logs/123.txt
-rw-rw-r-- 1 user user 7.9M Oct 8 11:08 /mnt/logs/123.txt
Podaci se ne gube, aplikacija radi, dnevnici se zapisuju na novu lokaciju.
Zakomplicirajmo malo zadatak
Zamislimo da su nam podaci važni, ali nemamo prostora na disku ni na jednoj od particija i ne možemo spojiti disk.
Ono što možemo učiniti je preusmjeriti naše podatke negdje, na primjer u pipe, a zatim preusmjeriti podatke iz cijevi u mrežu kroz neki program, na primjer netcat.
Možemo stvoriti imenovanu cijev pomoću naredbe mkfifo. Stvorit će pseudo datoteku na datotečnom sustavu čak i ako na njoj nema slobodnog prostora.
Ponovno pokrenite aplikaciju i provjerite:
[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
Nema prostora na disku, ali smo uspješno stvorili imenovanu cijev tamo:
[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
Sada moramo nekako omotati sve podatke koji ulaze u ovu cijev na drugi poslužitelj putem mreže; za to je prikladan isti netcat.
Na poslužitelju remote-server.example.com pokrećemo
[user@localhost ~]$ nc -l 7777 > 123.txt
Na našem problematičnom poslužitelju pokrećemo u zasebnom terminalu
[user@localhost ~]$ nc remote-server.example.com 7777 < /mnt/logs/megapipe
Sada će svi podaci koji završe u cijevi automatski ići na stdin u netcat, koji će ih poslati mreži na port 7777.
Sve što trebamo učiniti je početi pisati svoje podatke u ovu imenovanu cijev.
Već imamo pokrenutu aplikaciju:
[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
Od svih zastavica, trebamo samo O_WRONLY jer datoteka već postoji i ne moramo je brisati
[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
Provjera udaljenog poslužitelja remote-server.example.com
[user@localhost ~]$ ls -lah 123.txt
-rw-rw-r-- 1 user user 38M Oct 8 14:21 123.txt
Podaci stižu, provjeravamo problematični poslužitelj
[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
Podaci su spremljeni, problem riješen.
Koristim priliku da pozdravim kolege iz Degira.
Slušajte podcaste Radio-T.
Sve najbolje.
Kao domaću zadaću, predlažem da razmislite o tome što će biti u deskriptorima datoteka procesa cat i sleep ako pokrenete sljedeću naredbu:
[user@localhost ~]$ cat /dev/zero 2>/dev/null| sleep 10000
Izvor: www.habr.com