Lêerbeskrywing in Linux met voorbeelde

Ek is eenkeer in 'n onderhoud gevra wat sou jy doen as jy 'n stukkende diens vind as gevolg van die feit dat die skyf nie meer spasie het nie?

Ek het natuurlik geantwoord dat ek sal sien wat hierdie plek doen en, indien moontlik, sal ek die plek skoonmaak.
Toe vra die onderhoudvoerder, wat as daar geen vrye spasie op die partisie is nie, maar jy sien ook nie die lêers wat al die spasie sal opneem nie?

Hierop het ek gesê dat jy altyd na oop lêerbeskrywings kan kyk, byvoorbeeld met die lsof-opdrag en verstaan ​​watter toepassing al die beskikbare spasie in beslag geneem het, en dan kan jy volgens die omstandighede optree, afhangend van of die data benodig word .

Die onderhoudvoerder onderbreek my by die laaste woord en voeg by sy vraag: "Gestel ons het nie die data nodig nie, dit is net 'n debug-log, maar die toepassing is af omdat dit nie die debug kan skryf nie"?

"ok," het ek geantwoord, "ons kan ontfouting in die toepassingsopstelling afskakel en dit herbegin."
Die onderhoudvoerder het beswaar gemaak: "Nee, ons kan nie die toepassing herbegin nie, ons het steeds belangrike data in die geheue, en belangrike kliënte is aan die diens self gekoppel, wat ons nie kan dwing om weer te koppel nie."

“goed,” het ek gesê, “as ons nie die toepassing kan herbegin nie en ons gee nie om oor die data nie, dan kan ons hierdie oop lêer deur die lêerbeskrywing uitvee, selfs al sien ons dit nie in die ls opdrag op die lêerstelsel.”

Die onderhoudvoerder was tevrede, maar ek was nie.

Toe dink ek, hoekom delf die persoon wat my kennis toets nie dieper nie? Maar wat as die data tog belangrik is? Wat as ons nie die proses kan herbegin nie, en terselfdertyd skryf hierdie proses na die lêerstelsel op 'n partisie wat geen vrye spasie het nie? Wat as ons nie net die data wat reeds geskryf is, kan verloor nie, maar ook die data wat hierdie proses skryf of probeer skryf?

Tuzik

Aan die begin van my loopbaan het ek probeer om 'n klein toepassing te skep wat inligting oor gebruikers moes stoor. En toe dink ek, hoe kan ek die gebruiker by sy data pas. Byvoorbeeld, ek het Ivanov Ivan Ivanovich, en hy het 'n paar data, maar hoe om vriende met hulle te maak? Ek kan direk daarop wys dat die hond met die naam "Tuzik" aan hierdie selfde Ivan behoort. Maar wat as hy sy naam verander en in plaas van Ivan byvoorbeeld Olya word? Dan sal dit blyk dat ons Olya Ivanovna Ivanova nie meer 'n hond sal hê nie, en ons Tuzik sal steeds aan die nie-bestaande Ivan behoort. Die databasis het gehelp om hierdie probleem op te los, wat aan elke gebruiker 'n unieke identifiseerder (ID) gegee het, en my Tuzik was aan hierdie ID gekoppel, wat in werklikheid net 'n reeksnommer was. Dus, die eienaar van die tuzik was met ID-nommer 2, en op 'n sekere tydstip was Ivan onder hierdie ID, en toe het Olya onder dieselfde ID geword. Die probleem van die mensdom en veeteelt is prakties opgelos.

Lêerbeskrywing

Die probleem van 'n lêer en 'n program wat met hierdie lêer werk, is omtrent dieselfde as ons hond en mens. Gestel ek het 'n lêer met die naam ivan.txt oopgemaak en die woord tuzik daarin begin skryf, maar het daarin geslaag om net die eerste letter "t" in die lêer te skryf, en hierdie lêer is deur iemand hernoem, byvoorbeeld na olya.txt. Maar die lêer is dieselfde en ek wil steeds my aas daaraan skryf. Elke keer as jy 'n lêer oopmaak met 'n stelseloproep oop in enige programmeertaal kry ek 'n unieke ID wat my na 'n lêer wys, hierdie ID is die lêerbeskrywer. En dit maak glad nie saak wat en wie volgende met hierdie lêer doen nie, dit kan uitgevee word, dit kan hernoem word, dit kan sy eienaar verander of die regte om te lees en te skryf wegneem, ek sal steeds toegang daartoe hê, want toe ek die lêer oopgemaak het, het ek die regte gehad om dit te lees en/of te skryf en ek het daarin geslaag om daarmee te begin werk, wat beteken ek moet voortgaan om dit te doen.

Op Linux maak die libc-biblioteek 3 beskrywinglêers oop vir elke lopende toepassing (proses), met nommers 0,1,2. Meer inligting kan jy op die skakels kry man studio и man uitstaande

  • Lêerbeskrywing 0 word STDIN genoem en word geassosieer met toepassinginvoer.
  • Lêerbeskrywer 1 word STDOUT genoem en word gebruik deur uitvoertoepassings soos drukopdragte.
  • Lêerbeskrywer 2 word STDERR genoem en word deur toepassings gebruik om foutboodskappe uit te voer.

As jy in jou program enige lêer oopmaak vir lees of skryf, dan sal jy heel waarskynlik die eerste gratis ID kry en dit sal nommer 3 wees.

U kan die lys lêerbeskrywers vir enige proses sien as u die PID daarvan ken.

Kom ons maak byvoorbeeld 'n konsole met bash oop en sien die PID van ons proses

[user@localhost ]$ echo $$
15771

In die tweede konsole, hardloop

[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

U kan die lêerbeskrywer met nommer 255 veilig binne die raamwerk van hierdie artikel ignoreer, dit is deur bash self vir u behoeftes oopgemaak en nie deur die gekoppelde biblioteek nie.

Nou word al 3 beskrywerlêers met die pseudo-terminale toestel geassosieer /dev/pts, maar ons kan hulle steeds manipuleer, byvoorbeeld, hardloop in die tweede konsole

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

En in die eerste konsole sal ons sien

[user@localhost ]$ hello world

Herlei en pyp

Jy kan hierdie 3 beskrywinglêers maklik in enige proses ignoreer, insluitend in bash, byvoorbeeld, deur 'n pyp (pyp) wat twee prosesse verbind, sien

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

Jy kan hierdie opdrag self uitvoer met spoor -f en kyk wat binne aangaan, maar ek sal dit kort maak.

Ons ouerbash-proses met PID 15771 ontleed ons opdrag en verstaan ​​presies hoeveel opdragte ons wil uitvoer, in ons geval is daar twee van hulle: kat en slaap. Bash weet dat dit twee kinderprosesse moet skep en dit in een pyp moet saamsmelt. In totaal sal bash 2 kinderprosesse en een pyp benodig.

Voordat u kinderprosesse skep, voer bash 'n stelseloproep uit pyp en ontvang nuwe lêerbeskrywers op 'n tydelike pypbuffer, maar hierdie buffer verbind nog nie ons twee kindprosesse op enige manier nie.

Vir die ouerproses lyk dit of die pyp reeds daar is, maar daar is nog geen kinderprosesse nie:

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

Gebruik dan die stelseloproep kloon bash skep twee kinderprosesse, en ons drie prosesse sal so lyk:

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

Moenie vergeet dat kloon die proses saam met alle lêerbeskrywers kloon nie, so hulle sal dieselfde wees in die ouerproses en in die kinderproses. Die taak van die ouerproses met PID 15771 is om die kinderprosesse te monitor, so dit wag net vir 'n reaksie van die kinders.

Daarom het hy nie 'n pyp nodig nie, en hy maak die lêerbeskrywers toe met nommers 3 en 4.

In die eerste bash kind proses met PID 9004, die stelsel oproep dup 2, verander ons STDOUT-lêerbeskrywing nommer 1 na 'n lêerbeskrywer wat na 'n pyp wys, in ons geval is dit nommer 3. Dus, alles wat die eerste kind-proses met PID 9004 na STDOUT skryf, sal outomaties in die pypbuffer val.

In die tweede kind proses met PID 9005, bash dup2s die lêer na STDIN beskrywing nommer 0. Nou sal alles wat ons tweede bash met PID 9005 sal lees uit die pyp lees.

Daarna word lêerbeskrywers met nommers 3 en 4 ook in kinderprosesse gesluit, aangesien dit nie meer gebruik word nie.

Ek ignoreer lêerbeskrywer 255 doelbewus, dit word intern deur bash self gebruik en sal ook in kinderprosesse gesluit word.

Vervolgens, in die eerste kind-proses met PID 9004, begin bash met 'n stelseloproep exec die uitvoerbare lêer wat ons op die opdragreël gespesifiseer het, in ons geval is dit /usr/bin/cat.

In die tweede kinderproses met PID 9005, loop bash die tweede uitvoerbare lêer wat ons gespesifiseer het, in ons geval /usr/bin/sleep.

Die exec-stelseloproep sluit nie lêerbeskrywers nie, tensy hulle met die O_CLOEXEC-vlag oopgemaak is toe die oop oproep uitgevoer is. In ons geval, nadat die uitvoerbare lêers uitgevoer is, sal alle huidige lêerbeskrywings gestoor word.

Kyk na die konsole:

[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

Soos u kan sien, is die unieke nommer van ons pyp dieselfde in beide prosesse. Ons het dus 'n verband tussen twee verskillende prosesse met dieselfde ouer.

Vir diegene wat nie vertroud is met die stelseloproepe wat bash gebruik nie, beveel ek sterk aan om opdragte deur strace te laat loop en kyk wat binne gebeur, byvoorbeeld, soos volg:

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

Kom ons gaan terug na ons probleem met die opraak van skyfspasie en probeer om data te stoor sonder om die proses te herbegin. Kom ons skryf 'n klein program wat ongeveer 1 megagreep per sekonde na skyf sal skryf. Verder, as ons om een ​​of ander rede nie data na skyf kon skryf nie, sal ons dit eenvoudig ignoreer en probeer om die data binne 'n sekonde weer te skryf. In die voorbeeld wat ek Python gebruik, kan jy enige ander programmeertaal gebruik.

[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

Begin die program en kyk na die lêerbeskrywings

[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

Soos u kan sien, het ons ons 3 standaard lêerbeskrywings en nog een wat ons oopgemaak het. Kom ons kyk na die lêergrootte:

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

die data geskryf is, probeer ons om die regte op die lêer te verander:

[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

Ons sien dat die data steeds geskryf word, alhoewel ons gebruiker nie die reg het om na die lêer te skryf nie. Kom ons probeer dit verwyder:

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

Waar is die data geskryf? En is hulle enigsins geskryf? Ons kontroleer:

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

Ja, ons lêerbeskrywing bestaan ​​steeds, en ons kan met hierdie lêerbeskrywing werk soos ons ou lêer, ons kan dit lees, dit skoonmaak en dit kopieer.

Kyk na die lêergrootte:

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

Die lêergrootte is 19923457. Probeer om die lêer skoon te maak:

[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

Soos u kan sien, neem die lêergrootte net toe en ons stam het nie gewerk nie. Kom ons blaai na die dokumentasie oor die stelseloproep oop. As ons die O_APPEND-vlag gebruik wanneer 'n lêer oopgemaak word, gaan die bedryfstelsel met elke skryfwerk die lêergrootte na en skryf data heel aan die einde van die lêer, en doen dit atoomies. Dit laat verskeie drade of prosesse toe om na dieselfde lêer te skryf. Maar in ons kode gebruik ons ​​nie hierdie vlag nie. Ons kan slegs 'n ander lêergrootte in lsof na stam sien as ons die lêer oopmaak vir skryf, wat beteken dat in ons kode, in plaas van

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

ons moet sit

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

Kontroleer met "w" vlag

[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

en met 'n vlag

[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

Programmering van 'n reeds lopende proses

Dikwels, wanneer 'n program geskep en getoets word, gebruik programmeerders ontfouters (byvoorbeeld GDB) of verskeie vlakke van aanteken in die toepassing. Linux bied die vermoë om werklik 'n program wat reeds loop, te skryf en te verander, soos om die waardes van veranderlikes te verander, 'n breekpunt te stel, ensovoorts, ensovoorts.

Om terug te keer na die oorspronklike vraag oor die gebrek aan skyfspasie om 'n lêer te skryf, kom ons probeer om die probleem te simuleer.

Kom ons skep 'n lêer vir ons partisie, wat ons as 'n aparte aandrywer sal monteer:

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

Kom ons skep 'n lêerstelsel:

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

Kom ons monteer die lêerstelsel:

[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

Skep 'n gids met ons eienaar:

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

Kom ons maak die lêer oop vir skryf slegs in ons program:

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

Begin

[user@localhost ]$ python openforwrite.py 

Wag vir 'n paar sekondes

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

Dus, ons het die probleem wat aan die begin van hierdie artikel beskryf word. Vrye spasie 0, 100% beset.

Ons onthou dat ons volgens die toestande van die probleem probeer om baie belangrike data op te neem wat nie verlore kan gaan nie. En om dit te doen, moet ons die diens regmaak sonder om die proses te herbegin.

Kom ons sê ons het nog skyfspasie, maar in 'n ander partisie, byvoorbeeld in / tuis.

Kom ons probeer om ons kode "on the fly te herprogrammeer".

Ons kyk na die PID van ons proses, wat al die skyfspasie geëet het:

[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

Koppel aan 'n proses met gdb

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

Ons kyk na oop lêerbeskrywings:

(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

Ons kyk na inligting oor die lêerbeskrywer met nommer 3, wat ons interesseer

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

As ons in gedagte hou watter stelseloproep Python doen (sien hierbo waar ons 'n soektog gehardloop het en 'n oop oproep gevind het), terwyl ons ons kode verwerk om 'n lêer oop te maak, doen ons dieselfde self namens ons proses, maar ons benodig die O_WRONLY|O_CREAT| O_TRUNC bisse vervang met 'n numeriese waarde. Om dit te doen, maak byvoorbeeld die kernbronne oop hier en kyk watter vlae waarvoor verantwoordelik is

#definieer O_WRONLY 00000001
#definieer O_CREAT 00000100
#definieer O_TRUNC 00001000

Ons kombineer al die waardes in een, ons kry 00001101

Begin ons oproep vanaf gdb

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

So ons het 'n nuwe lêerbeskrywing met nommer 4 en 'n nuwe oop lêer op 'n ander partisie gekry, kyk:

(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

Ons onthou die voorbeeld met pipe - hoe bash lêerbeskrywings verander, en het reeds die dup2-stelseloproep geleer.

Probeer om een ​​lêerbeskrywer met 'n ander te vervang

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

Ons kyk na:

(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

Maak lêerbeskrywing 4 toe, aangesien ons dit nie nodig het nie:

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

En verlaat 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

Gaan die nuwe lêer 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

Soos u kan sien, word die data na 'n nuwe lêer geskryf, ons kyk na die ou:

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

Die data gaan nie verlore nie, die toepassing werk, die logs word na 'n nuwe plek geskryf.

Kom ons maak dinge 'n bietjie moeiliker

Stel jou voor dat die data vir ons belangrik is, maar ons het nie skyfspasie in enige van die partisies nie en ons kan nie die skyf koppel nie.

Wat ons kan doen, is om ons data iewers heen te herlei, byvoorbeeld na 'n pyp, en die data van die pyp na die netwerk te herlei deur een of ander program, soos netcat.
Ons kan 'n benoemde pyp skep met die mkfifo-opdrag. Dit sal 'n pseudo-lêer op die lêerstelsel skep, selfs al is daar geen vrye spasie daarop nie.

Herbegin die toepassing en kontroleer:

[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

Daar is geen skyfspasie nie, maar ons skep 'n genoemde pyp suksesvol daar:

[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

Nou moet ons op een of ander manier al die data wat in hierdie pyp kom, na 'n ander bediener deur die netwerk toedraai, dieselfde netkat is geskik hiervoor.

Op die remote-server.example.com-bediener, hardloop

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

Op ons probleembediener, hardloop in 'n aparte terminaal

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

Nou sal al die data wat in die pyp kom, outomaties na stdin in netcat gaan, wat dit na die netwerk op poort 7777 sal stuur.

Al wat ons moet doen is om ons data na hierdie benoemde pyp te begin skryf.

Ons het reeds 'n lopende toepassing:

[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

Van al die vlae het ons net O_WRONLY nodig aangesien die lêer reeds bestaan ​​en ons hoef dit nie skoon te maak nie

[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

Kontroleer tans die afgeleë bediener remote-server.example.com

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

Data kom, ons kyk na die probleembediener

[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

Die data word gestoor, die probleem is opgelos.

Ek gebruik hierdie geleentheid om te groet aan my kollegas van Degiro.
Luister na Radio-T-podcasts.

Alles goed.

As 'n huiswerk stel ek voor om te dink oor wat in die lêerbeskrywings van die kat- en slaapproses sal wees as jy die volgende opdrag uitvoer:

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

Bron: will.com

Voeg 'n opmerking