Filbeskrivelse i Linux med eksempler

En gang i et intervju ble jeg spurt om hva du ville gjort hvis du finner en ødelagt tjeneste på grunn av at disken har gått tom for plass?

Jeg svarte selvfølgelig at jeg ville se hva dette stedet gjorde, og om mulig ville jeg rydde stedet.
Så spurte intervjueren, hva om det ikke er ledig plass på partisjonen, men du heller ikke ser filene som vil ta opp all plass?

Til dette sa jeg at du alltid kan se på åpne filbeskrivelser, for eksempel med lsof-kommandoen og forstå hvilken applikasjon som har tatt all tilgjengelig plass, og så kan du handle i henhold til omstendighetene, avhengig av om dataene er nødvendige .

Intervjueren avbrøt meg ved siste ord, og la til spørsmålet sitt: "Anta at vi ikke trenger dataene, det er bare en feilsøkingslogg, men applikasjonen er nede fordi den ikke kan skrive feilsøkingen"?

"ok," svarte jeg, "vi kan slå av feilsøking i applikasjonskonfigurasjonen og starte den på nytt."
Intervjueren innvendte: "Nei, vi kan ikke starte applikasjonen på nytt, vi har fortsatt viktige data i minnet, og viktige klienter er koblet til selve tjenesten, som vi ikke kan tvinge til å koble til på nytt."

"ok," sa jeg, "hvis vi ikke kan starte programmet på nytt og vi ikke bryr oss om dataene, så kan vi bare slette denne åpne filen via filbeskrivelsen, selv om vi ikke ser den i ls kommando på filsystemet."

Intervjueren var fornøyd, men det var jeg ikke.

Da tenkte jeg, hvorfor graver ikke personen som tester kunnskapen min dypere? Men hva om dataene tross alt er viktige? Hva om vi ikke kan starte prosessen på nytt, og samtidig skriver denne prosessen til filsystemet på en partisjon som ikke har ledig plass? Hva om vi ikke bare kan miste dataene som allerede er skrevet, men også dataene som denne prosessen skriver eller prøver å skrive?

Tuzik

I begynnelsen av min karriere prøvde jeg å lage en liten applikasjon som måtte lagre informasjon om brukere. Og så tenkte jeg, hvordan kan jeg matche brukeren til hans data. For eksempel har jeg Ivanov Ivan Ivanovich, og han har noen data, men hvordan blir jeg venner med dem? Jeg kan påpeke direkte at hunden som heter "Tuzik" tilhører denne samme Ivan. Men hva om han endrer navn og i stedet for Ivan blir for eksempel Olya? Da vil det vise seg at vår Olya Ivanovna Ivanova ikke lenger vil ha en hund, og vår Tuzik vil fortsatt tilhøre den ikke-eksisterende Ivan. Databasen hjalp til med å løse dette problemet, som ga hver bruker en unik identifikator (ID), og min Tuzik var knyttet til denne IDen, som faktisk bare var et serienummer. Dermed var eieren av tuziken med ID-nummer 2, og på et tidspunkt var Ivan under denne ID-en, og da ble Olya under samme ID. Problemet med menneskeheten og dyrehold ble praktisk talt løst.

Filbeskrivelse

Problemet med en fil og et program som fungerer med denne filen er omtrent det samme som vår hund og menneske. Anta at jeg åpnet en fil som heter ivan.txt og begynte å skrive ordet tuzik inn i den, men klarte å skrive bare den første bokstaven "t" inn i filen, og denne filen ble omdøpt av noen, for eksempel til olya.txt. Men filen er den samme, og jeg vil fortsatt skrive mitt ess til den. Hver gang du åpner en fil med et systemanrop åpen på et hvilket som helst programmeringsspråk får jeg en unik ID som peker meg til en fil, denne IDen er filbeskrivelsen. Og det spiller ingen rolle i det hele tatt hva og hvem som gjør videre med denne filen, den kan slettes, den kan gis nytt navn, den kan endre eier eller ta fra rettighetene til å lese og skrive, jeg vil fortsatt ha tilgang til den, fordi jeg på tidspunktet for åpningen av filen hadde rettighetene til å lese og/eller skrive den, og jeg klarte å begynne å jobbe med den, noe som betyr at jeg må fortsette å gjøre det.

På Linux åpner libc-biblioteket 3 deskriptorfiler for hver kjørende applikasjon (prosess), med tallene 0,1,2. Mer informasjon finner du på lenkene mann stdio и mann standout

  • Filbeskrivelse 0 kalles STDIN og er knyttet til applikasjonsinndata.
  • Filbeskrivelse 1 kalles STDOUT og brukes av utdataapplikasjoner som utskriftskommandoer.
  • Filbeskrivelse 2 heter STDERR og brukes av applikasjoner til å sende ut feilmeldinger.

Hvis du åpner en fil for lesing eller skriving i programmet ditt, vil du mest sannsynlig få den første gratis ID-en, og denne vil være nummer 3.

Du kan se listen over filbeskrivelser for enhver prosess hvis du kjenner PID-en.

La oss for eksempel åpne en konsoll med bash og se PID-en til prosessen vår

[user@localhost ]$ echo $$
15771

I den andre konsollen, kjør

[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

Du kan trygt ignorere filbeskrivelsen med nummer 255 innenfor rammen av denne artikkelen, den ble åpnet for dine behov av bash selv, og ikke av det koblede biblioteket.

Nå er alle 3 deskriptorfilene assosiert med pseudoterminalenheten /dev/pts, men vi kan fortsatt manipulere dem, for eksempel kjøre i den andre konsollen

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

Og i den første konsollen vil vi se

[user@localhost ]$ hello world

Redirect og Pipe

Du kan enkelt overstyre disse 3 deskriptorfilene i en hvilken som helst prosess, inkludert i bash, for eksempel gjennom et rør (rør) som forbinder to prosesser, se

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

Du kan kjøre denne kommandoen selv med strace -f og se hva som skjer inni, men jeg skal gjøre det kort.

Vår foreldrebash-prosess med PID 15771 analyserer kommandoen vår og forstår nøyaktig hvor mange kommandoer vi vil kjøre, i vårt tilfelle er det to av dem: katt og søvn. Bash vet at den må lage to underordnede prosesser, og slå dem sammen til ett rør. Totalt vil bash trenge 2 underordnede prosesser og ett rør.

Før du oppretter underordnede prosesser, kjører bash et systemanrop rør og mottar nye filbeskrivelser på en midlertidig pipebuffer, men denne bufferen kobler ennå ikke sammen våre to underordnede prosesser på noen måte.

For overordnet prosessen ser det ut til at røret allerede er der, men det er ingen underordnede prosesser ennå:

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

Deretter bruker du systemanropet klone bash lager to underordnede prosesser, og våre tre prosesser vil se slik ut:

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

Ikke glem at klon kloner prosessen sammen med alle filbeskrivelser, slik at de vil være de samme i overordnet prosessen og i de underordnede. Oppgaven til foreldreprosessen med PID 15771 er å overvåke barneprosessene, så den venter bare på svar fra barna.

Derfor trenger han ikke et rør, og han lukker filbeskrivelsene med nummer 3 og 4.

I den første bash underordnede prosessen med PID 9004 kaller systemet dup2, endrer vår STDOUT-fildeskriptor nummer 1 til en fildeskriptor som peker på et rør, i vårt tilfelle er det nummer 3. Dermed vil alt som den første underordnede prosessen med PID 9004 skriver til STDOUT automatisk falle inn i pipebufferen.

I den andre underordnede prosessen med PID 9005, dup2ser du filen til STDIN-deskriptor nummer 0. Nå vil alt som vår andre bash med PID 9005 vil lese, lese fra røret.

Etter det lukkes også filbeskrivelser med nummer 3 og 4 i underordnede prosesser, siden de ikke lenger brukes.

Jeg ignorerer fildeskriptor 255 bevisst, den brukes internt av bash selv og vil også bli lukket i underordnede prosesser.

Deretter, i den første underordnede prosessen med PID 9004, starter bash med et systemanrop exec den kjørbare filen som vi spesifiserte på kommandolinjen, i vårt tilfelle er det /usr/bin/cat.

I den andre underordnede prosessen med PID 9005 kjører bash den andre kjørbare filen vi spesifiserte, i vårt tilfelle /usr/bin/sleep.

Exec-systemkallet lukker ikke filbeskrivelser med mindre de ble åpnet med O_CLOEXEC-flagget på det tidspunktet det åpne anropet ble utført. I vårt tilfelle, etter å ha kjørt de kjørbare filene, vil alle gjeldende filbeskrivelser bli lagret.

Sjekker i konsollen:

[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

Som du kan se, er det unike nummeret på røret vårt det samme i begge prosessene. Dermed har vi en sammenheng mellom to ulike prosesser med samme forelder.

For de som ikke er kjent med systemkallene som bash bruker, anbefaler jeg på det sterkeste å kjøre kommandoer gjennom strace og se hva som skjer inni, for eksempel slik:

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

La oss gå tilbake til problemet med å gå tom for diskplass og prøve å lagre data uten å starte prosessen på nytt. La oss skrive et lite program som vil skrive til disken med omtrent 1 megabyte per sekund. Dessuten, hvis vi av en eller annen grunn ikke kunne skrive data til disken, vil vi ganske enkelt ignorere dette og prøve å skrive dataene igjen om et sekund. I eksemplet jeg bruker Python, kan du bruke et hvilket som helst annet programmeringsspråk.

[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

Kjør programmet og se på filbeskrivelsene

[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

Som du kan se, har vi våre 3 standard filbeskrivelser og en annen som vi har åpnet. La oss sjekke filstørrelsen:

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

dataene er skrevet, prøver vi å endre rettighetene til filen:

[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

Vi ser at dataene fortsatt skrives, selv om brukeren vår ikke har rett til å skrive til filen. La oss prøve å fjerne det:

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

Hvor er dataene skrevet? Og er de i det hele tatt skrevet? Vi sjekker:

[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, filbeskrivelsen vår eksisterer fortsatt, og vi kan jobbe med denne filbeskrivelsen som vår gamle fil, vi kan lese den, rydde opp og kopiere den.

Se på filstørrelsen:

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

Filstørrelsen er 19923457. Prøver å fjerne filen:

[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

Som du kan se, øker filstørrelsen bare og bagasjerommet vårt fungerte ikke. La oss gå til dokumentasjonen på systemsamtalen åpen. Hvis vi bruker O_APPEND-flagget når vi åpner en fil, kontrollerer operativsystemet filstørrelsen ved hver skriving og skriver data helt til slutten av filen, og gjør det atomisk. Dette gjør at flere tråder eller prosesser kan skrive til samme fil. Men i koden vår bruker vi ikke dette flagget. Vi kan se en annen filstørrelse i lsof etter trunk bare hvis vi åpner filen for skriving, noe som betyr at i koden vår, i stedet for

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

vi må sette

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

Sjekker med "w"-flagget

[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

og med "et" flagg

[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 av en allerede igangværende prosess

Ofte, når de oppretter og tester et program, bruker programmerere debuggere (for eksempel GDB) eller ulike nivåer av logging i applikasjonen. Linux gir muligheten til å faktisk skrive og endre et allerede kjørende program, for eksempel å endre verdiene til variabler, sette et bruddpunkt, og så videre og så videre.

Tilbake til det opprinnelige spørsmålet om mangel på diskplass for å skrive en fil, la oss prøve å simulere problemet.

La oss lage en fil for partisjonen vår, som vi vil montere som en separat stasjon:

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

La oss lage et filsystem:

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

La oss montere filsystemet:

[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

Opprett en katalog med eieren vår:

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

La oss bare åpne filen for skriving i programmet vårt:

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

Lansering

[user@localhost ]$ python openforwrite.py 

Venter i noen sekunder

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

Så vi fikk problemet beskrevet i begynnelsen av denne artikkelen. Ledig plass 0, okkupert 100 %.

Vi husker at i henhold til betingelsene for problemet prøver vi å registrere svært viktige data som ikke kan gå tapt. Og når vi gjør det, må vi fikse tjenesten uten å starte prosessen på nytt.

La oss si at vi fortsatt har diskplass, men i en annen partisjon, for eksempel i / hjemme.

La oss prøve å "omprogrammere i farten" koden vår.

Vi ser på PID-en til prosessen vår, som spiste all diskplass:

[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

Koble til en prosess med gdb

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

Vi ser på åpne filbeskrivelser:

(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

Vi ser på informasjon om filbeskrivelsen med nummer 3, som interesserer oss

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

Med tanke på hvilket systemkall Python gjør (se ovenfor hvor vi kjørte strace og fant et åpent kall), mens vi behandler koden vår for å åpne en fil, gjør vi det samme selv på vegne av prosessen vår, men vi trenger O_WRONLY|O_CREAT| O_TRUNC-biter erstattes med en numerisk verdi. For å gjøre dette, åpne kjernekildene, for eksempel her og se hvilke flagg som er ansvarlige for hva

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

Vi kombinerer alle verdiene til en, vi får 00001101

Kjører vår samtale fra gdb

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

Så vi fikk en ny filbeskrivelse med nummer 4 og en ny åpen fil på en annen partisjon, sjekk:

(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

Vi husker eksempelet med pipe - hvordan bash endrer filbeskrivelser, og har allerede lært dup2-systemkallet.

Prøver å erstatte en filbeskrivelse med en annen

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

Vi sjekker:

(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

Lukk filbeskrivelse 4, siden vi ikke trenger den:

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

Og gå ut av 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

Sjekker den nye filen:

[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

Som du kan se, blir dataene skrevet til en ny fil, vi sjekker den gamle:

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

Dataene går ikke tapt, applikasjonen fungerer, loggene skrives til et nytt sted.

La oss gjøre ting litt vanskeligere

Tenk deg at dataene er viktige for oss, men vi har ikke diskplass i noen av partisjonene og vi kan ikke koble til disken.

Det vi kan gjøre er å omdirigere dataene våre et sted, for eksempel til et rør, og omdirigere dataene fra røret til nettverket gjennom et eller annet program, for eksempel netcat.
Vi kan lage et navngitt rør med mkfifo-kommandoen. Den vil lage en pseudofil på filsystemet, selv om det ikke er ledig plass på den.

Start applikasjonen på nytt og sjekk:

[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

Det er ingen diskplass, men vi har opprettet en navngitt pipe der:

[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

Nå må vi på en eller annen måte pakke alle dataene som kommer inn i dette røret til en annen server gjennom nettverket, den samme nettkatten er egnet for dette.

Kjør på ekstern-server.example.com-serveren

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

På vår problemserver, kjør i en egen terminal

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

Nå vil all data som kommer inn i røret automatisk gå til stdin i netcat, som vil sende den til nettverket på port 7777.

Alt vi trenger å gjøre er å begynne å skrive dataene våre til dette navngitte røret.

Vi har allerede en applikasjon som kjører:

[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

Av alle flaggene trenger vi bare O_WRONLY siden filen allerede eksisterer og vi trenger ikke å slette den

[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

Kontrollerer den eksterne serveren remote-server.example.com

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

Data kommer, vi sjekker problemserveren

[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

Dataene er lagret, problemet er løst.

Jeg benytter anledningen til å hilse på kolleger fra Degiro.
Lytt til Radio-T-podcaster.

Helt fint.

Som en hjemmelekse foreslår jeg å tenke på hva som vil være i filbeskrivelsene til katten og søvnprosessen hvis du kjører følgende kommando:

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

Kilde: www.habr.com

Legg til en kommentar