Filbeskrivelse i Linux med eksempler

En gang under et interview blev jeg spurgt, hvad vil du gøre, hvis du finder ud af, at en tjeneste ikke fungerer, fordi disken er løbet tør for plads?

Jeg svarede selvfølgelig, at jeg ville se, hvad der var optaget af dette sted, og om muligt ville jeg gøre stedet rent.
Så spurgte intervieweren, hvad hvis der ikke er ledig plads på partitionen, men du heller ikke ser nogen filer, der ville optage al pladsen?

Til dette sagde jeg, at man altid kan se på åbne filbeskrivelser, for eksempel med lsof-kommandoen, og forstå, hvilken applikation der har optaget al den tilgængelige plads, og så kan man handle efter omstændighederne, alt efter om dataene er nødvendige .

Intervieweren afbrød mig på det sidste ord og tilføjede til sit spørgsmål: "Antag, at vi ikke har brug for dataene, det er bare en debug-log, men applikationen virker ikke, fordi den ikke kan skrive en debug"?

"Okay," svarede jeg, "vi kan slå fejlretning fra i applikationskonfigurationen og genstarte den."
Intervieweren indvendte: "Nej, vi kan ikke genstarte applikationen, vi har stadig vigtige data gemt i hukommelsen, og vigtige klienter er forbundet til selve tjenesten, som vi ikke kan tvinge til at oprette forbindelse igen."

"okay," sagde jeg, "hvis vi ikke kan genstarte programmet, og dataene ikke er vigtige for os, så kan vi simpelthen rydde denne åbne fil gennem filbeskrivelsen, selvom vi ikke kan se den i ls-kommandoen på filsystemet."

Intervieweren var glad, men det var jeg ikke.

Så tænkte jeg, hvorfor graver den person, der tester min viden, ikke dybere? Men hvad nu hvis dataene trods alt er vigtige? Hvad hvis vi ikke kan genstarte en proces, og processen skriver til filsystemet på en partition, der ikke har ledig plads? Hvad hvis vi ikke kun kan miste de data, der allerede er skrevet, men også de data, som denne proces skriver eller forsøger at skrive?

Tuzik

Tidligt i min karriere forsøgte jeg at lave en lille applikation, der skulle gemme brugeroplysninger. Og så tænkte jeg, hvordan kan jeg matche brugeren til hans data. For eksempel har jeg Ivanov Ivan Ivanovich, og han har nogle oplysninger, men hvordan kan jeg blive venner med dem? Jeg kan direkte påpege, at hunden ved navn "Tuzik" tilhører netop denne Ivan. Men hvad nu hvis han skifter navn og i stedet for Ivan bliver for eksempel Olya? Så vil det vise sig, at vores Olya Ivanovna Ivanova ikke længere vil have en hund, og vores Tuzik vil stadig tilhøre den ikke-eksisterende Ivan. En database, der gav hver bruger en unik identifikator (ID), hjalp med at løse dette problem, og min Tuzik var bundet til dette ID, som i virkeligheden kun var et serienummer. Således havde essens ejer ID nummer 2, og på et tidspunkt var Ivan under dette ID, og ​​så blev Olya under det samme ID. Problemet med menneskelighed og dyrehold blev praktisk talt løst.

Filbeskrivelse

Problemet med filen og programmet, der fungerer med denne fil, er omtrent det samme som vores hunds og menneskes. Antag, at jeg åbnede en fil kaldet ivan.txt og begyndte at skrive ordet tuzik ind i den, men kun formåede at skrive det første bogstav "t" i filen, og denne fil blev omdøbt af nogen, for eksempel til olya.txt. Men filen forbliver den samme, og jeg vil stadig gerne optage mit es i den. Hver gang en fil åbnes af et systemkald åbent på et hvilket som helst programmeringssprog modtager jeg et unikt ID, der peger mig til en fil, dette ID er filbeskrivelsen. Og det er overhovedet ligegyldigt, hvad og hvem der næste gang gør med denne fil, den kan slettes, den kan omdøbes, ejeren kan ændres, eller rettighederne til at læse og skrive kan fratages, jeg vil stadig have adgang til den, fordi jeg på tidspunktet for åbningen af ​​filen havde rettighederne til at læse og/eller skrive den, og det lykkedes mig at begynde at arbejde med den, hvilket betyder, at jeg skal fortsætte med det.

I Linux åbner libc-biblioteket 3 deskriptorfiler for hver kørende applikation (proces), nummereret 0,1,2. Mere information kan findes på linkene mand stdio и mand standout

  • Filbeskrivelse 0 kaldes STDIN og er forbundet med applikationsinput
  • Filbeskrivelse 1 kaldes STDOUT og bruges af applikationer til at udlæse data, såsom udskriftskommandoer
  • Filbeskrivelse 2 kaldes STDERR og bruges af applikationer til at udlæse fejlmeddelelser.

Hvis du i dit program åbner en fil til læsning eller skrivning, vil du højst sandsynligt få det første gratis ID, og ​​det vil være nummer 3.

Listen over filbeskrivelser kan ses for enhver proces, hvis du kender dens PID.

Lad os for eksempel åbne bash-konsollen og se på PID'et for vores proces

[user@localhost ]$ echo $$
15771

Lad os køre i den anden konsol

[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 roligt ignorere fildeskriptor nummer 255 i forbindelse med denne artikel; den blev åbnet for sine behov af bash selv og ikke af det linkede bibliotek.

Nu er alle 3 deskriptorfiler tilknyttet pseudoterminalenheden /dev/pts, men vi kan stadig manipulere dem, for eksempel køre dem i en anden konsol

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

Og i den første konsol vil vi se

[user@localhost ]$ hello world

Redirect og Pipe

Du kan nemt tilsidesætte disse 3 deskriptorfiler i enhver proces, inklusive i bash, for eksempel gennem et rør, der forbinder to processer, se

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

Du kan selv køre denne kommando med strace -f og se hvad der foregår indeni, men jeg skal fortælle dig det kort.

Vores forældrebash-proces med PID 15771 analyserer vores kommando og forstår præcis, hvor mange kommandoer vi vil køre, i vores tilfælde er der to af dem: kat og søvn. Bash ved, at det er nødvendigt at skabe to underordnede processer og flette dem sammen til ét rør. I alt skal bash have 2 underordnede processer og et rør.

Bash kører et systemkald, før der oprettes underordnede processer rør og modtager nye filbeskrivelser på den midlertidige rørbuffer, men denne buffer forbinder endnu ikke vores to underordnede processer.

For overordnet processen ser det ud til, at der allerede er et rør, men der er ingen underordnede processer endnu:

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

Brug derefter systemkaldet klone bash opretter to underordnede processer, og vores tre processer vil se sådan ud:

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

Glem ikke, at klon kloner processen sammen med alle filbeskrivelser, så de vil være ens i forældreprocessen og i de underordnede. Opgaven for forældreprocessen med PID 15771 er at overvåge underordnede processer, så den venter blot på et svar fra børnene.

Derfor behøver den ikke pipe, og den lukker filbeskrivelser nummereret 3 og 4.

I den første underordnede bash-proces med PID 9004 kalder systemet dup2, ændrer vores STDOUT fildeskriptor nummer 1 til en fildeskriptor, der peger på pipe, i vores tilfælde er det nummer 3. Alt det, som den første underordnede proces med PID 9004 skriver til STDOUT, ender således automatisk i pipebufferen.

I den anden underordnede proces med PID 9005 bruger bash dup2 til at ændre filbeskrivelsen STDIN nummer 0. Nu vil alt, hvad vores anden bash med PID 9005 vil læse, blive læst fra røret.

Herefter lukkes fildeskriptorer nummereret 3 og 4 også i underordnede processer, da de ikke længere bruges.

Jeg ignorerer bevidst fildeskriptor 255; den bruges til interne formål af bash selv og vil også blive lukket i underordnede processer.

Dernæst, i den første underordnede proces med PID 9004, begynder bash at bruge et systemkald exec den eksekverbare fil, som vi specificerede på kommandolinjen, i vores tilfælde er det /usr/bin/cat.

I den anden underordnede proces med PID 9005 kører bash den anden eksekverbare, vi specificerede, i vores tilfælde /usr/bin/sleep.

Exec-systemkaldet lukker ikke filhåndtag, medmindre de blev åbnet med O_CLOEXEC-flaget på det tidspunkt, hvor det åbne opkald blev foretaget. I vores tilfælde vil alle aktuelle filbeskrivelser blive gemt efter lancering af de eksekverbare filer.

Tjek 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 unikke nummer på vores rør det samme i begge processer. Vi har således en sammenhæng mellem to forskellige processer med samme forælder.

For dem, der ikke er bekendt med de systemkald, som bash bruger, anbefaler jeg stærkt at køre kommandoerne gennem strace og se, hvad der sker internt, for eksempel som dette:

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

Lad os vende tilbage til vores problem med lav diskplads og forsøge at gemme data uden at genstarte processen. Lad os skrive et lille program, der vil skrive cirka 1 megabyte pr. sekund til disken. Desuden, hvis vi af en eller anden grund ikke var i stand til at skrive data til disken, vil vi simpelthen ignorere dette og prøve at skrive dataene igen om et sekund. I eksemplet, jeg bruger Python, kan du bruge et hvilket som helst andet programmeringssprog.

[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

Lad os køre programmet og se på filbeskrivelserne

[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 vores 3 standard filbeskrivelser og en mere, som vi åbnede. Lad os tjekke filstørrelsen:

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

Dataene bliver skrevet, vi forsøger at ændre tilladelserne på 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 stadig skrives, selvom vores bruger ikke har tilladelse til at skrive til filen. Lad os prøve at 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 data skrevet? Og er de overhovedet skrevet? Vi tjekker:

[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, vores filbeskrivelse eksisterer stadig, og vi kan behandle denne filbeskrivelse som vores gamle fil, vi kan læse, slette og kopiere den.

Lad os 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. Lad os prøve at rydde 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, er filstørrelsen kun stigende, og vores bagagerum fungerede ikke. Lad os se på systemopkaldsdokumentationen åbent. Hvis vi bruger flaget O_APPEND, når vi åbner en fil, så kontrollerer operativsystemet ved hver skrivning filstørrelsen og skriver data til slutningen af ​​filen, og gør dette atomært. Dette tillader flere tråde eller processer at skrive til den samme fil. Men i vores kode bruger vi ikke dette flag. Vi kan kun se en anden filstørrelse i lsof efter trunk, hvis vi åbner filen for yderligere skrivning, hvilket betyder i vores kode i stedet

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

vi er nødt til at sætte

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

Tjek med "w"-flaget

[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 "a"-flaget

[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 af en allerede kørende proces

Ofte bruger programmører, når de opretter og tester programmer, debuggere (for eksempel GDB) eller forskellige niveauer af logning i applikationen. Linux giver mulighed for faktisk at skrive og ændre et allerede kørende program, for eksempel ændre værdierne af variabler, indstille et brudpunkt osv. osv.

For at vende tilbage til det oprindelige spørgsmål om ikke nok diskplads til at skrive en fil, lad os prøve at simulere problemet.

Lad os oprette en fil til vores partition, som vi monterer som en separat 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 ~]$

Lad os oprette 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 ~]$

Monter 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

Vi opretter en mappe med vores ejer:

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

Lad os kun åbne filen til skrivning i vores program:

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

Lad os starte

[user@localhost ]$ python openforwrite.py 

Vi venter et par sekunder

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

Så vi har problemet beskrevet i begyndelsen af ​​denne artikel. Ledig plads 0, 100 % besat.

Vi husker, at vi i henhold til opgavens betingelser forsøger at registrere meget vigtige data, som ikke kan gå tabt. Og samtidig skal vi reparere tjenesten uden at genstarte processen.

Lad os sige, at vi stadig har diskplads, men i en anden partition, for eksempel i /home.

Lad os prøve at "omprogrammere i farten" vores kode.

Lad os se på PID'et for vores proces, som har spist al diskpladsen:

[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

Opret forbindelse til processen via gdb

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

Lad os se på de åbne 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å oplysningerne om fildeskriptor nummer 3, som interesserer os

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

Når vi husker, hvilket systemkald Python laver (se ovenfor, hvor vi kørte strace og fandt det åbne opkald), når vi behandler vores kode for at åbne en fil, gør vi det samme selv på vegne af vores proces, men vi har brug for O_WRONLY|O_CREAT| O_TRUNC bit erstattes med en numerisk værdi. For at gøre dette skal du for eksempel åbne kernekilderne her og se på hvilke flag der er ansvarlige for hvad

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

Vi kombinerer alle værdierne til én, vi får 00001101

Vi kører vores opkald fra gdb

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

Så vi fik en ny filbeskrivelse med nummer 4 og en ny åben fil på en anden partition, vi tjekker:

(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 eksemplet med pipe - hvordan bash ændrer filbeskrivelser, og vi har allerede lært dup2-systemkaldet.

Vi forsøger at erstatte en filbeskrivelse med en anden

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

Vi tjekker:

(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

Vi lukker filbeskrivelse 4, da vi ikke har brug for det:

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

Og forlad 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

Tjek den nye fil:

[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, er dataene skrevet til en ny fil, lad os tjekke 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

Ingen data går tabt, applikationen virker, logfiler skrives til en ny placering.

Lad os komplicere opgaven lidt

Lad os forestille os, at dataene er vigtige for os, men vi har ikke diskplads i nogen af ​​partitionerne, og vi kan ikke tilslutte disken.

Det, vi kan gøre, er at omdirigere vores data et sted, for eksempel til pipe, og til gengæld omdirigere data fra pipe til netværket gennem et eller andet program, for eksempel netcat.
Vi kan oprette et navngivet rør med kommandoen mkfifo. Det vil oprette en pseudo-fil på filsystemet, selvom der ikke er ledig plads på den.

Genstart applikationen og kontroller:

[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

Der er ingen diskplads, men vi har oprettet et navngivet rør 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

Nu skal vi på en eller anden måde pakke alle de data, der går ind i dette rør, til en anden server via netværket; den samme netcat er egnet til dette.

På serveren remote-server.example.com starter vi

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

På vores problematiske server starter vi i en separat terminal

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

Nu vil alle de data, der ender i røret, automatisk gå til stdin i netcat, som sender dem til netværket på port 7777.

Alt vi skal gøre er at begynde at skrive vores data ind i dette navngivne rør.

Vi har allerede applikationen kørende:

[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

Af alle flag har vi kun brug for O_WRONLY, da filen allerede eksisterer, og vi behøver ikke at rydde 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

Kontrol af fjernserveren remote-server.example.com

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

Dataene kommer, vi tjekker 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 gemt, problemet er løst.

Jeg benytter lejligheden til at sige hej til mine kolleger fra Degiro.
Lyt til Radio-T podcasts.

Alt det bedste.

Som hjemmearbejde foreslår jeg, at du tænker over, hvad der vil være i processens filbeskrivelser kat og søvn, hvis du kører følgende kommando:

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

Kilde: www.habr.com

Tilføj en kommentar