Raz som sa v rozhovore spýtal, čo by ste urobili, keby ste našli nefunkčnú službu kvôli tomu, že na disku došlo miesto?
Samozrejme som odpovedal, že uvidím, čo toto miesto robí a ak to bude možné, miesto vyčistím.
Potom sa anketár spýtal, čo ak na oddiele nie je voľné miesto, ale nevidíte ani súbory, ktoré by zaberali celý priestor?
Na to som povedal, že vždy sa môžete pozrieť na otvorené deskriptory súborov, napríklad pomocou príkazu lsof, a pochopiť, ktorá aplikácia zabrala všetok dostupný priestor, a potom môžete konať podľa okolností v závislosti od toho, či sú potrebné údaje. .
Anketár ma prerušil pri poslednom slove a dodal na svoju otázku: „Predpokladajme, že nepotrebujeme údaje, je to len denník ladenia, ale aplikácia nefunguje, pretože nemôže zapísať ladenie“?
"OK," odpovedal som, "môžeme vypnúť ladenie v konfigurácii aplikácie a reštartovať ju."
Anketár namietal: „Nie, nemôžeme reštartovať aplikáciu, stále máme dôležité dáta v pamäti a k samotnej službe sú pripojení dôležití klienti, ktorých nemôžeme prinútiť znovu sa pripojiť.“
"Dobre," povedal som, "ak nemôžeme reštartovať aplikáciu a nestaráme sa o dáta, potom môžeme jednoducho vyčistiť tento otvorený súbor cez deskriptor súboru, aj keď ho nevidíme v ls príkaz v súborovom systéme."
Anketár bol spokojný, ale ja nie.
Potom som si pomyslel, prečo človek, ktorý testuje moje vedomosti, nepátra hlbšie? Čo ak sú však údaje predsa len dôležité? Čo ak nemôžeme reštartovať proces a zároveň tento proces zapisuje do súborového systému na oddiel, ktorý nemá voľné miesto? Čo ak nemôžeme stratiť nielen už zapísané dáta, ale ani dáta, ktoré tento proces zapisuje alebo sa pokúša zapísať?
Tuzik
Na začiatku mojej kariéry som sa snažil vytvoriť malú aplikáciu, ktorá potrebovala uchovávať informácie o používateľoch. A potom som si pomyslel, ako môžem priradiť používateľa k jeho údajom. Napríklad mám Ivanova Ivana Ivanoviča a má nejaké údaje, ale ako sa s nimi spriateliť? Môžem priamo podotknúť, že pes menom "Tuzik" patrí tomu istému Ivanovi. Čo ak si však zmení meno a namiesto Ivana sa stane napríklad Olya? Potom sa ukáže, že naša Olya Ivanovna Ivanova už nebude mať psa a náš Tuzik bude stále patriť neexistujúcemu Ivanovi. Tento problém pomohla vyriešiť databáza, ktorá každému používateľovi pridelila jedinečný identifikátor (ID) a môj Tuzik bol naviazaný na toto ID, ktoré bolo v skutočnosti len sériové číslo. Majiteľ tuziku mal teda ID číslo 2 a v určitom čase bol pod týmto ID Ivan a potom sa pod rovnakým ID stala Olya. Problém ľudstva a chovu zvierat bol prakticky vyriešený.
Deskriptor súboru
Problém súboru a programu, ktorý s týmto súborom pracuje, je asi rovnaký ako u nášho psa a človeka. Predpokladajme, že som otvoril súbor s názvom ivan.txt a začal som doň písať slovo tuzik, no podarilo sa mi do súboru napísať len prvé písmeno „t“ a tento súbor niekto premenoval napríklad na olya.txt. Spis je ale ten isty a aj tak do neho chcem napisat svoje eso. Zakaždým, keď otvoríte súbor pomocou systémového volania
V systéme Linux knižnica libc otvára 3 súbory deskriptorov pre každú spustenú aplikáciu (proces) s číslami 0,1,2. Viac informácií nájdete na odkazoch
- Deskriptor súboru 0 sa nazýva STDIN a je spojený so vstupom aplikácie.
- Deskriptor súboru 1 sa nazýva STDOUT a používajú ho výstupné aplikácie, ako sú tlačové príkazy.
- Deskriptor súboru 2 má názov STDERR a používajú ho aplikácie na výstup chybových správ.
Ak vo svojom programe otvoríte akýkoľvek súbor na čítanie alebo zápis, potom s najväčšou pravdepodobnosťou dostanete prvé bezplatné ID a bude to číslo 3.
Môžete vidieť zoznam deskriptorov súborov pre každý proces, ak poznáte jeho PID.
Otvorme napríklad konzolu s bashom a pozrime si PID nášho procesu
[user@localhost ]$ echo $$
15771
V druhej konzole spustite
[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
Deskriptor súboru s číslom 255 môžete v rámci tohto článku pokojne ignorovať, otvoril ho pre vaše potreby samotný bash a nie prepojená knižnica.
Teraz sú všetky 3 súbory deskriptorov spojené s pseudoterminálnym zariadením
[user@localhost ]$ echo "hello world" > /proc/15771/fd/0
A v prvej konzole uvidíme
[user@localhost ]$ hello world
Presmerovanie a Pipe
Tieto 3 súbory deskriptorov môžete jednoducho prepísať v akomkoľvek procese, vrátane bash, napríklad prostredníctvom potrubia (pipe) spájajúceho dva procesy, pozri
[user@localhost ]$ cat /dev/zero | sleep 10000
Tento príkaz môžete spustiť sami strace -f a uvidíte, čo sa deje vo vnútri, ale skrátim to.
Náš nadradený bash proces s PID 15771 analyzuje náš príkaz a presne chápe, koľko príkazov chceme spustiť, v našom prípade sú dva: mačka a spánok. Bash vie, že potrebuje vytvoriť dva podradené procesy a zlúčiť ich do jedného potrubia. Celkovo bude bash potrebovať 2 podradené procesy a jedno potrubie.
Pred vytvorením podriadených procesov bash spustí systémové volanie
V prípade nadradeného procesu sa zdá, že kanál už existuje, ale zatiaľ neexistujú žiadne podriadené procesy:
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
Potom pomocou systémového volania
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
Nezabudnite, že klon klonuje proces spolu so všetkými deskriptormi súborov, takže budú rovnaké v nadradenom procese aj v podradenom procese. Úlohou nadradeného procesu s PID 15771 je monitorovať podriadené procesy, takže len čaká na odpoveď od potomkov.
Preto nepotrebuje fajku a deskriptory súborov zatvorí číslami 3 a 4.
V prvom bash podriadenom procese s PID 9004 systémové volanie
V druhom podradenom procese s PID 9005 bash dup2s súbor do STDIN deskriptora číslo 0. Teraz všetko, čo bude čítať náš druhý bash s PID 9005, bude čítať z potrubia.
Potom sa deskriptory súborov s číslami 3 a 4 uzavrú aj v podriadených procesoch, pretože sa už nepoužívajú.
Zámerne ignorujem deskriptor súboru 255, používa ho interne samotný bash a bude tiež uzavretý v podriadených procesoch.
Ďalej, v prvom podradenom procese s PID 9004 bash začína systémovým volaním
V druhom podradenom procese s PID 9005 bash spustí druhý spustiteľný súbor, ktorý sme špecifikovali, v našom prípade /usr/bin/sleep.
Systémové volanie exec nezatvorí deskriptory súborov, pokiaľ neboli otvorené s príznakom O_CLOEXEC v čase, keď bolo otvorené volanie vykonané. V našom prípade sa po spustení spustiteľných súborov uložia všetky aktuálne deskriptory súborov.
Kontrola v konzole:
[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
Ako vidíte, jedinečné číslo našej fajky je v oboch procesoch rovnaké. Máme teda spojenie medzi dvoma rôznymi procesmi s tým istým rodičom.
Pre tých, ktorí nie sú oboznámení so systémovými volaniami, ktoré bash používa, veľmi odporúčam spúšťať príkazy cez strace a zistiť, čo sa deje vo vnútri, napríklad takto:
strace -s 1024 -f bash -c "ls | grep hello"
Vráťme sa k nášmu problému s nedostatkom miesta na disku a pokusom o záchranu dát bez reštartovania procesu. Napíšme malý program, ktorý bude zapisovať na disk rýchlosťou asi 1 megabajt za sekundu. Navyše, ak by sme z nejakého dôvodu nemohli zapisovať dáta na disk, jednoducho to ignorujeme a pokúsime sa dáta zapísať znova za sekundu. V príklade, ktorý používam Python, môžete použiť akýkoľvek iný programovací jazyk.
[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
Spustite program a pozrite sa na deskriptory súborov
[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
Ako môžete vidieť, máme 3 štandardné deskriptory súborov a ďalší, ktorý sme otvorili. Skontrolujeme veľkosť súboru:
[user@localhost ]$ ls -lah 123.txt
-rw-rw-r-- 1 user user 117M Oct 7 16:30 123.txt
údaje sú zapísané, snažíme sa zmeniť práva k súboru:
[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
Vidíme, že údaje sa stále zapisujú, hoci náš používateľ nemá právo zapisovať do súboru. Skúsme to odstrániť:
[user@localhost ]$ sudo rm 123.txt
[user@localhost ]$ ls 123.txt
ls: cannot access 123.txt: No such file or directory
Kde sú zapísané údaje? A sú vôbec napísané? Kontrolujeme:
[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)
Áno, náš deskriptor súboru stále existuje a môžeme s ním pracovať ako s naším starým súborom, môžeme ho čítať, čistiť a kopírovať.
Pozrite sa na veľkosť súboru:
[user@localhost ]$ lsof | grep 123.txt
python 31083 user 3w REG 8,5 19923457 2621522 /home/user/123.txt
Veľkosť súboru je 19923457. Pokus o vymazanie súboru:
[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
Ako vidíte, veľkosť súboru sa len zväčšuje a náš kmeň nefungoval. Obráťme sa na dokumentáciu k systémovému volaniu
with open("123.txt", "w") as f:
musíme dať
with open("123.txt", "a") as f:
Kontrola s príznakom "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
a s vlajkou „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
Programovanie už spusteného procesu
Programátori často pri vytváraní a testovaní programu používajú debuggery (napríklad GDB) alebo rôzne úrovne logovania v aplikácii. Linux poskytuje možnosť skutočne písať a meniť už spustený program, ako je zmena hodnôt premenných, nastavenie bodu prerušenia atď.
Ak sa vrátime k pôvodnej otázke o nedostatku miesta na disku na zápis súboru, skúsme problém nasimulovať.
Vytvorme súbor pre náš oddiel, ktorý pripojíme ako samostatný 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 ~]$
Vytvorme súborový systém:
[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 ~]$
Pripojíme súborový systém:
[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
Vytvorte si adresár s naším vlastníkom:
[user@localhost ~]$ sudo mkdir /mnt/logs
[user@localhost ~]$ sudo chown user: /mnt/logs
Otvorme súbor na zápis iba v našom programe:
with open("/mnt/logs/123.txt", "w") as f:
Spustiť
[user@localhost ]$ python openforwrite.py
Čaká sa niekoľko sekúnd
[user@localhost ~]$ df -h | grep mnt
/dev/loop0 8.7M 8.0M 0 100% /mnt
Takže sme dostali problém popísaný na začiatku tohto článku. Voľné miesto 0, obsadené na 100 %.
Pamätáme si, že podľa podmienok problému sa snažíme zaznamenať veľmi dôležité údaje, ktoré nemožno stratiť. A pritom musíme službu opraviť bez reštartovania procesu.
Povedzme, že stále máme miesto na disku, ale v inom oddiele, napríklad v / home.
Skúsme "preprogramovať za behu" náš kód.
Pozeráme sa na PID nášho procesu, ktorý zjedol celý priestor 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
Pripojenie k procesu s gdb
[user@localhost ~]$ gdb -p 10078
...
(gdb)
Pozeráme sa na otvorené deskriptory súborov:
(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
Pozeráme sa na informácie o deskriptore súboru s číslom 3, ktorý nás zaujíma
(gdb) shell cat /proc/10078/fdinfo/3
pos: 8189952
flags: 0100001
mnt_id: 482
Majme na pamäti, aké systémové volanie robí Python (pozri vyššie, kde sme spustili strace a našli otvorené volanie), pri spracovaní nášho kódu na otvorenie súboru robíme to isté sami v mene nášho procesu, ale potrebujeme O_WRONLY|O_CREAT| Bity O_TRUNC nahradia číselnou hodnotou. Ak to chcete urobiť, otvorte napríklad zdrojové kódy jadra
#define O_WRONLY 00000001
#define O_CREAT 00000100
#define O_TRUNC 00001000
Skombinujeme všetky hodnoty do jednej, dostaneme 00001101
Spustenie nášho hovoru z gdb
(gdb) call open("/home/user/123.txt", 00001101,0666)
$1 = 4
Takže máme nový deskriptor súboru s číslom 4 a nový otvorený súbor na inom oddiele, skontrolujte:
(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
Pamätáme si príklad s pipe - ako bash mení deskriptory súborov a už sme sa naučili systémové volanie dup2.
Pokúšame sa nahradiť jeden deskriptor súboru iným
(gdb) call dup2(4,3)
$2 = 3
skontrolujte:
(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
Zatvorte deskriptor súboru 4, pretože ho nepotrebujeme:
(gdb) call close (4)
$1 = 0
A ukončite 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
Kontrola nového súboru:
[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
Ako vidíte, údaje sa zapisujú do nového súboru, skontrolujeme starý:
[user@localhost ~]$ ls -lah /mnt/logs/123.txt
-rw-rw-r-- 1 user user 7.9M Oct 8 11:08 /mnt/logs/123.txt
Údaje sa nestratia, aplikácia funguje, protokoly sa zapisujú na nové miesto.
Poďme si veci trochu sťažiť
Predstavte si, že dáta sú pre nás dôležité, no v žiadnom z oddielov nemáme miesto na disku a nevieme disk pripojiť.
Čo môžeme urobiť, je presmerovať naše údaje niekam, napríklad do potrubia, a presmerovať údaje z potrubia do siete pomocou nejakého programu, ako je napríklad netcat.
Pomenované potrubie môžeme vytvoriť pomocou príkazu mkfifo. V súborovom systéme vytvorí pseudo súbor, aj keď na ňom nie je voľné miesto.
Reštartujte aplikáciu a skontrolujte:
[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
Na disku nie je miesto, ale úspešne sme tam vytvorili pomenované prepojenie:
[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
Teraz musíme nejakým spôsobom zabaliť všetky údaje, ktoré sa dostanú do tohto potrubia, na iný server cez sieť, na to je vhodný rovnaký netcat.
Na serveri remote-server.example.com spustite
[user@localhost ~]$ nc -l 7777 > 123.txt
Na našom problémovom serveri spustite v samostatnom termináli
[user@localhost ~]$ nc remote-server.example.com 7777 < /mnt/logs/megapipe
Teraz všetky údaje, ktoré sa dostanú do potrubia, automaticky prejdú na stdin v netcat, ktorý ich odošle do siete na port 7777.
Jediné, čo musíme urobiť, je začať zapisovať naše údaje do tohto pomenovaného potrubia.
Už máme spustenú aplikáciu:
[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
Zo všetkých príznakov potrebujeme iba O_WRONLY, pretože súbor už existuje a nemusíme ho vymazávať
[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
Kontrola vzdialeného servera remote-server.example.com
[user@localhost ~]$ ls -lah 123.txt
-rw-rw-r-- 1 user user 38M Oct 8 14:21 123.txt
Prichádzajú dáta, skontrolujeme problémový server
[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
Dáta sú uložené, problém je vyriešený.
Využívam túto príležitosť, aby som pozdravil svojich kolegov z Degiro.
Počúvajte podcasty Radio-T.
Všetko dobré.
Ako domácu úlohu navrhujem zamyslieť sa nad tým, čo bude v deskriptoroch súborov procesu mačky a spánku, ak spustíte nasledujúci príkaz:
[user@localhost ~]$ cat /dev/zero 2>/dev/null| sleep 10000
Zdroj: hab.com