Triembeskriuwing yn Linux mei foarbylden

Ien kear, tidens in ynterview, waard ik frege, wat sille jo dwaan as jo fine dat in tsjinst net wurket fanwege it feit dat de skiif gjin romte hat?

Fansels, ik antwurde dat ik soe sjen wat waard beset troch dit plak en, as it kin, ik soe skjin it plak.
Doe frege de ynterviewer, wat as der gjin frije romte is op 'e partysje, mar jo sjogge ek gjin bestannen dy't alle romte ynnimme?

Dêrop sei ik dat jo altyd kinne sjen nei iepen bestânbeskriuwers, bygelyks mei it kommando lsof, en begripe hokker applikaasje alle beskikbere romte ynnommen hat, en dan kinne jo hannelje neffens de omstannichheden, ôfhinklik fan oft de gegevens nedich binne .

De ynterviewer ûnderbriek my op it lêste wurd, en tafoege oan syn fraach: "Stel dat wy de gegevens net nedich binne, it is gewoan in debug-log, mar de applikaasje wurket net om't it gjin debug kin skriuwe"?

"Okee," antwurde ik, "wy kinne debug útsette yn 'e applikaasjekonfiguraasje en opnij starte."
De ynterviewer makke beswier: "Nee, wy kinne de applikaasje net opnij starte, wy hawwe noch wichtige gegevens opslein yn it ûnthâld, en wichtige kliïnten binne ferbûn mei de tsjinst sels, dy't wy net kinne twinge om opnij te ferbinen."

"Okee," sei ik, "as wy de applikaasje net opnij starte kinne en de gegevens binne net wichtich foar ús, dan kinne wy ​​dit iepen bestân gewoan wiskje fia de triembeskriuwing, sels as wy it net sjogge yn it ls kommando op it bestânsysteem."

De ynterviewer wie bliid, mar ik wie net.

Doe tocht ik, wêrom graaft de persoan dy't myn kennis testet net djipper? Mar wat as de gegevens nei alle gedachten wichtich binne? Wat as wy in proses net opnij starte kinne, en it proses skriuwt nei it bestânsysteem op in partysje dy't gjin frije romte hat? Wat as wy net allinich de gegevens kinne ferlieze dy't al skreaun binne, mar ek de gegevens dy't dit proses skriuwt of besiket te skriuwen?

Tuzik

Betiid yn myn karriêre besocht ik in lytse applikaasje te meitsjen dy't nedich wie om brûkersynformaasje op te slaan. En doe tocht ik, hoe kin ik de brûker oerienkomme mei syn gegevens. Bygelyks, ik haw Ivanov Ivan Ivanovich, en hy hat wat ynformaasje, mar hoe kin ik meitsje freonen mei harren? Ik kin direkt oanjaan dat de hûn mei de namme "Tuzik" heart ta dizze Ivan. Mar wat as hy feroaret syn namme en ynstee fan Ivan wurdt, bygelyks, Olya? Dan sil bliken dien dat ús Olya Ivanovna Ivanova gjin hûn mear sil hawwe, en ús Tuzik sil noch hearre ta de net-besteande Ivan. In databank dy't elke brûker in unike identifier (ID) joech, holp dit probleem op te lossen, en myn Tuzik wie bûn oan dizze ID, dy't yn feite gewoan in serial number wie. Sa hie de eigner fan 'e ace ID nûmer 2, en op in stuit wie Ivan ûnder dizze ID, en doe waard Olya ûnder deselde ID. It probleem fan minskdom en feehâlderij waard praktysk oplost.

Triem descriptor

It probleem fan de triem en it programma dat wurket mei dizze triem is likernôch itselde as dat fan ús hûn en minske. Stel dat ik iepene in triem neamd ivan.txt en begûn te skriuwen it wurd tuzik yn it, mar allinne slagge om te skriuwen de earste letter "t" yn de triem, en dizze triem waard omneamd troch immen, bygelyks, olya.txt. Mar de triem bliuwt itselde, en ik wol noch opnimme myn ace yn it. Elke kear as in bestân wurdt iepene troch in systeemoprop iepen yn elke programmeartaal krij ik in unike ID dy't my ferwiist nei in bestân, dizze ID is de triembeskriuwing. En it makket hielendal net út wat en wa't dêrnei mei dit bestân docht, it kin wiske wurde, it kin omneamd wurde, de eigner kin feroare wurde, of it lêzen en skriuwen kinne ôfnommen wurde, ik sil noch tagong hawwe deroan, om't ik by it iepenjen fan it bestân de rjochten hie om it te lêzen en/of te skriuwen en it is my slagge om dermei te wurkjen, wat betsjut dat ik dat trochgean moat.

Yn Linux iepenet de libc-bibleteek 3 deskriptorbestannen foar elke rinnende applikaasje (proses), nûmere 0,1,2. Mear ynformaasje is te finen op de keppelings man stio и man stdout

  • Triembeskriuwing 0 hjit STDIN en is ferbûn mei applikaasje-ynfier
  • Triembeskriuwing 1 hjit STDOUT en wurdt brûkt troch applikaasjes om gegevens út te fieren, lykas printkommando's
  • Triembeskriuwing 2 hjit STDERR en wurdt brûkt troch applikaasjes om flaterberjochten út te fieren.

As jo ​​yn jo programma in bestân iepenje foar lêzen of skriuwen, dan sille jo wierskynlik de earste fergese ID krije en it sil nûmer 3 wêze.

De list mei triembeskriuwers kin wurde besjoen foar elk proses as jo syn PID kenne.

Litte wy bygelyks de bash-konsole iepenje en nei de PID fan ús proses sjen

[user@localhost ]$ echo $$
15771

Yn 'e twadde konsole litte wy rinne

[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

Jo kinne feilich negearje triem descriptor nûmer 255 foar de doelen fan dit artikel; it waard iepene foar syn behoeften troch bash sels, en net troch de keppele bibleteek.

No binne alle 3 descriptor-bestannen ferbûn mei it pseudo-terminalapparaat /dev/pts, mar wy kinne noch manipulearje se, bygelyks, rinne se yn in twadde konsole

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

En yn 'e earste konsole sille wy sjen

[user@localhost ]$ hello world

Redirect en Pipe

Jo kinne dizze 3 beskriuwingsbestannen maklik oerskriuwe yn elk proses, ynklusyf yn bash, bygelyks troch in piip dy't twa prosessen ferbynt, sjoch

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

Jo kinne dit kommando sels útfiere mei striek -f en sjoch wat der binnen bart, mar ik sil it dy koart fertelle.

Us âlder bash-proses mei PID 15771 parses ús kommando en begrypt krekt hoefolle kommando's wy wolle útfiere, yn ús gefal binne d'r twa fan har: kat en sliep. Bash wit dat it moat meitsje twa bern prosessen, en fusearje se yn ien pipe. Yn totaal sil bash 2 bernprosessen en ien piip nedich wêze.

Bash rint in systeemoprop foardat jo bernprosessen meitsje piip en ûntfangt nije triembeskriuwers op 'e tydlike pipebuffer, mar dizze buffer ferbynt ús twa bernprosessen noch net.

Foar it âlderproses liket it derop dat der al in piip is, mar d'r binne noch gjin bernprosessen:

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

Dan mei help fan it systeem oprop klon bash makket twa bernprosessen, en ús trije prosessen sille der sa útsjen:

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

Ferjit net dat kloon it proses klonet tegearre mei alle bestânbeskriuwers, dus se sille itselde wêze yn it âlderproses en yn 'e bern. De taak fan it âlderproses mei PID 15771 is om de bernprosessen te kontrolearjen, sadat it gewoan wachtet op in antwurd fan 'e bern.

Dêrom hat it gjin pipe nedich, en it slút triembeskriuwers nûmere 3 en 4.

Yn it earste bern bash proses mei PID 9004, it systeem oprop dup 2, feroaret ús STDOUT triem descriptor nûmer 1 yn in triem descriptor dy't wiist nei pipe, yn ús gefal is it nûmer 3. Sa komt alles dat it earste bern proses mei PID 9004 skriuwt nei STDOUT automatysk telâne yn de pipe buffer.

Yn it twadde bernproses mei PID 9005 brûkt bash dup2 om de triembeskriuwing STDIN nûmer 0 te feroarjen. No sil alles wat ús twadde bash mei PID 9005 lêze sil lêzen wurde fan 'e piip.

Hjirnei wurde ek triembeskriuwings nûmere 3 en 4 yn 'e bernprosessen sluten, om't se net mear brûkt wurde.

Ik negearje mei opsetsin bestânbeskriuwing 255; it wurdt brûkt foar ynterne doelen troch bash sels en sil ek sluten wurde yn berneprosessen.

Folgjende, yn it earste bernproses mei PID 9004, begjint bash in systeemoprop te brûken exec it útfierbere bestân dat wy op 'e kommandorigel opjûn hawwe, yn ús gefal is it /usr/bin/cat.

Yn it twadde bernproses mei PID 9005 rint bash it twadde útfierbere dat wy spesifisearre hawwe, yn ús gefal /usr/bin/sleep.

De oprop fan it exec-systeem slút gjin triemhannels, útsein as se waarden iepene mei de O_CLOEXEC-flagge op it momint dat de iepen oprop makke waard. Yn ús gefal, nei it starten fan de útfierbere bestannen, wurde alle aktuele beskriuwers opslein.

Kontrolearje yn 'e 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

Sa't jo sjen kinne, is it unike nûmer fan ús piip itselde yn beide prosessen. Sa hawwe wy in ferbining tusken twa ferskillende prosessen mei deselde âlder.

Foar dyjingen dy't net bekend binne mei de systeemoproppen dy't bash brûkt, ried ik tige oan om de kommando's troch strace te rinnen en te sjen wat der yntern bart, bygelyks sa:

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

Litte wy weromgean nei ús probleem fan it rinnen fan skiifromte en besykje gegevens te bewarjen sûnder it proses opnij te begjinnen. Litte wy in lyts programma skriuwe dat sawat 1 megabyte per sekonde op skiif skriuwt. Boppedat, as wy om ien of oare reden gjin gegevens op 'e skiif kinne skriuwe, sille wy dit gewoan negearje en besykje de gegevens yn in sekonde opnij te skriuwen. Yn it foarbyld dat ik Python brûke, kinne jo elke oare programmeartaal brûke.

[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

Litte wy it programma útfiere en nei de triembeskriuwers sjen

[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

Sa't jo kinne sjen, hawwe wy ús 3 standert bestânbeskriuwers en noch ien dy't wy iepene hawwe. Litte wy de triemgrutte kontrolearje:

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

De gegevens wurde skreaun, wy besykje de tagongsrjochten op it bestân te feroarjen:

[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

Wy sjogge dat de gegevens noch skreaun wurde, hoewol ús brûker gjin tastimming hat om nei it bestân te skriuwen. Litte wy besykje it te ferwiderjen:

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

Wêr binne de gegevens skreaun? En binne se hielendal skreaun? Wy kontrolearje:

[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, ús bestânbeskriuwing bestiet noch en wy kinne dizze bestânbeskriuwing behannelje as ús âlde bestân, wy kinne it lêze, wiskje en kopiearje.

Litte wy nei de triemgrutte sjen:

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

De triemgrutte is 19923457. Litte wy besykje de triem te wiskjen:

[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

Sa't jo sjen kinne, nimt de triemgrutte allinich ta en ús kofferbak wurke net. Litte wy nei de systeemopropdokumintaasje sjen iepen. As wy de flagge O_APPEND brûke by it iepenjen fan in bestân, dan kontrolearret it bestjoeringssysteem mei elke skriuw de triemgrutte en skriuwt gegevens oan 'e ein fan' e bestân, en docht dit atomysk. Hjirmei kinne meardere threaden of prosessen nei itselde bestân skriuwe. Mar yn ús koade brûke wy dizze flagge net. Wy kinne allinich in oare triemgrutte yn lsof nei trunk sjen as wy it bestân iepenje foar ekstra skriuwen, dat betsjut yn ús koade ynstee

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

wy moatte sette

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

Kontrolearje mei de "w" flagge

[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 mei de "a" flagge

[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

Programmearje in al rinnend proses

Faak brûke programmeurs, by it meitsjen en testen fan programma's, debuggers (bygelyks GDB) of ferskate nivo's fan loggen yn 'e applikaasje. Linux biedt de mooglikheid om in al rinnend programma feitlik te skriuwen en te feroarjen, bygelyks de wearden fan fariabelen te feroarjen, in brekpunt yn te stellen, ensfh., ensfh.

Werom nei de oarspronklike fraach oer net genôch skiifromte om in bestân te skriuwen, litte wy besykje it probleem te simulearjen.

Litte wy in bestân meitsje foar ús partition, dy't wy as in aparte skiif montearje:

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

Litte wy in bestânsysteem oanmeitsje:

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

Mount it triemsysteem:

[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

Wy meitsje in map mei ús eigner:

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

Litte wy it bestân iepenje foar skriuwen allinich yn ús programma:

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

Launch

[user@localhost ]$ python openforwrite.py 

Wy wachtsje in pear sekonden

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

Dat, wy hawwe it probleem beskreaun oan it begjin fan dit artikel. Frije romte 0, 100% beset.

Wy betinke dat, neffens de betingsten fan 'e taak, wy besykje tige wichtige gegevens op te nimmen dy't net ferlern gean kinne. En tagelyk moatte wy de tsjinst reparearje sûnder it proses opnij te begjinnen.

Litte wy sizze dat wy noch skiifromte hawwe, mar yn in oare partition, bygelyks yn /home.

Litte wy besykje ús koade "op 'e flecht opnij te programmearjen".

Litte wy nei de PID fan ús proses sjen, dat alle skiifromte hat opfretten:

[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

Ferbine mei it proses fia gdb

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

Litte wy nei de iepen bestânbeskriuwers sjen:

(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

Wy sjogge nei de ynformaasje oer triembeskriuwing nûmer 3, dy't ús ynteresseart

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

Tink derom hokker systeemoprop Python makket (sjoch hjirboppe wêr't wy strace rûnen en de iepen oprop fûnen), by it ferwurkjen fan ús koade om in bestân te iepenjen, dogge wy itselde sels út namme fan ús proses, mar wy moatte de O_WRONLY|O_CREAT| O_TRUNC bits ferfange mei in numerike wearde. Om dit te dwaan, iepenje de kernel boarnen, bygelyks hjir en sjoch nei hokker flaggen binne ferantwurdlik foar wat

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

Wy kombinearje alle wearden yn ien, wy krije 00001101

Wy rinne ús oprop fan gdb

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

Dat wy krigen in nije bestânbeskriuwing mei nûmer 4 en in nij iepen bestân op in oare partysje, wy kontrolearje:

(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

Wy ûnthâlde it foarbyld mei pipe - hoe't bash triembeskriuwers feroaret, en wy hawwe de dup2-systeemoprop al leard.

Wy besykje ien triembeskriuwer te ferfangen troch in oare

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

Wy kontrolearje:

(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

Wy slute triembeskriuwing 4, om't wy it net nedich binne:

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

En út 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

It nije bestân kontrolearje:

[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

Sa't jo sjen kinne, wurde de gegevens skreaun nei in nij bestân, litte wy de âlde kontrolearje:

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

Gjin gegevens binne ferlern, de applikaasje wurket, logs wurde skreaun nei in nije lokaasje.

Litte wy de taak in bytsje komplisearje

Litte wy ús foarstelle dat de gegevens foar ús wichtich binne, mar wy hawwe gjin skiifromte yn ien fan 'e partysjes en wy kinne de skiif net ferbine.

Wat wy kinne dwaan is omliede ús gegevens earne, bygelyks nei pipe, en op syn beurt omliede gegevens fan pipe nei it netwurk troch guon programma, bygelyks netcat.
Wy kinne in neamde pipe meitsje mei it mkfifo kommando. It sil in pseudo-bestân oanmeitsje op it bestânsysteem, sels as d'r gjin frije romte op is.

Start de applikaasje opnij en kontrolearje:

[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

D'r is gjin skiifromte, mar wy meitsje dêr mei súkses in neamde pipe:

[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

No moatte wy op ien of oare manier alle gegevens dy't yn dizze piip geane nei in oare server fia it netwurk ynpakke; deselde netcat is geskikt foar dit.

Op de tsjinner remote-server.example.com rinne wy

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

Op ús problematyske server lansearje wy yn in aparte terminal

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

No sille alle gegevens dy't yn 'e piip einigje automatysk nei stdin gean yn netcat, dy't it sil stjoere nei it netwurk op poarte 7777.

Alles wat wy hoege te dwaan is ús gegevens yn dizze neamde pipe te begjinnen.

Wy hawwe de applikaasje al rinnend:

[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

Fan alle flaggen hawwe wy allinich O_WRONLY nedich, om't it bestân al bestiet en wy it net hoege te wiskjen

[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

Kontrolearje de tsjinner op ôfstân remote-server.example.com

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

De gegevens komme, wy kontrolearje de probleemserver

[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

De gegevens wurde bewarre, it probleem is oplost.

Ik nim dizze gelegenheid oan om myn kollega's fan Degiro te groetsjen.
Harkje nei Radio-T-podcasts.

Goed foar allegear.

As húswurk stel ik foar dat jo tinke oer wat sil wêze yn it proses bestânbeskriuwers kat en sliepe as jo it folgjende kommando útfiere:

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

Boarne: www.habr.com

Add a comment