Descriptor d'archivi in ​​Linux cù esempi

Una volta, durante una entrevista, mi sò dumandatu, chì fate si truvate un serviziu chì ùn funziona micca per via di u fattu chì u discu hà scappatu di u spaziu?

Di sicuru, aghju rispostu ch'e aghju vistu ciò chì era occupatu da stu locu è, s'ellu hè pussibule, aghju pulitu u locu.
Allora l'entrevistadore dumandò, chì s'ellu ùn ci hè micca spaziu liberu nantu à a partizione, ma ùn vede micca ancu i schedari chì piglianu tuttu u spaziu?

À questu aghju dettu chì pudete sempre guardà i descriptori di u schedariu aperti, per esempiu cù u cumandamentu lsof, è capisce quale applicazione hà pigliatu tuttu u spaziu dispunibule, è poi pudete agisce secondu e circustanze, secondu chì a dati hè necessariu. .

L'intervistatore m'hà interrottu nantu à l'ultima parola, aghjunghjendu à a so quistione: "Suppone chì ùn avemu micca bisognu di e dati, hè solu un log di debug, ma l'applicazione ùn funziona micca perchè ùn pò micca scrive un debug"?

"Va bè", aghju rispostu, "pudemu disattivà u debug in a cunfigurazione di l'applicazione è riavvia".
L'entrevistadore hà oppostu: "No, ùn pudemu micca riavvia l'applicazione, avemu sempre dati impurtanti almacenati in memoria, è i clienti impurtanti sò cunnessi à u serviziu stessu, chì ùn pudemu micca forza à ricunnisce micca di novu".

"Va bè", aghju dettu, "se ùn pudemu micca riavvia l'applicazione è i dati ùn sò micca impurtanti per noi, allora pudemu simpricimenti sguassate stu schedariu apertu attraversu u descrittore di u schedariu, ancu s'ellu ùn vedemu micca in u cumandimu ls. nantu à u sistema di fugliale ".

L'entrevistadore era cuntentu, ma ùn era micca.

Allora aghju pensatu, perchè a persona chì prova a mo cunniscenza ùn scava più profonda? Ma chì si i dati sò impurtanti dopu à tuttu? E se ùn pudemu micca riavvià un prucessu, è u prucessu scrive à u sistema di schedari nantu à una partizione chì ùn hà micca spaziu liberu? E se ùn pudemu micca perde micca solu i dati chì sò digià scritti, ma ancu i dati chì stu prucessu scrive o prova di scrive?

Tuzik

A principiu di a mo carriera, aghju pruvatu à creà una piccula applicazione chì avia bisognu di almacenà l'infurmazioni di l'utilizatori. E poi aghju pensatu, cumu possu currisponde à l'utilizatori cù i so dati. Per esempiu, aghju Ivanov Ivan Ivanovich, è hà qualchì infurmazione, ma cumu possu fà amici cù elli? Puderaghju direttamente chì u cane chjamatu "Tuzik" appartene à questu Ivan. Ma chì si cambia u so nome è invece di Ivan diventa, per esempiu, Olya? Allora vi sarà chì a nostra Olya Ivanovna Ivanova ùn avarà più un cane, è u nostru Tuzik appartene ancu à l'Ivan inesistente. Una basa di dati chì dete à ogni utilizatore un identificatore unicu (ID) hà aiutatu à risolve stu prublema, è u mo Tuzik era ligatu à questu ID, chì, in fattu, era solu un numeru di serie. Cusì, u pruprietariu di l'as hà avutu u numeru ID 2, è in un certu puntu in u tempu Ivan era sottu à questu ID, è dopu Olya diventò sottu à u listessu ID. U prublema di l'umanità è l'allevamentu di l'animali hè stata praticamente risolta.

Descrizzione di u schedariu

U prublema di u schedariu è u prugramma chì travaglia cù stu schedariu hè apprussimatamente u listessu cum'è quellu di u nostru cane è omu. Eppo supponi chì aghju apertu un schedariu chjamatu ivan.txt è hà cuminciatu à scrive a parolla tuzik in questu, ma solu riesciutu à scrive a prima lettera "t" in u schedariu, è questu schedariu hè statu rinominatu da qualchissia, per esempiu, olya.txt. Ma u schedariu ferma u listessu, è vogliu sempre registrà u mo zitellu in questu. Ogni volta chì un schedariu hè apertu da una chjama di sistema apartu in ogni lingua di prugrammazione, riceve un ID unicu chì mi indica un schedariu, questu ID hè u descrittore di u schedariu. È ùn importa à tuttu ciò chì è quale face cù stu schedariu dopu, pò esse sguassatu, pò esse rinominatu, u pruprietariu pò esse cambiatu, o i diritti di leghje è di scrive ponu esse tolti, aghju sempre accessu. à questu, perchè à u mumentu di l'apertura di u schedariu, aghju avutu i diritti di leghje è / o di scrive è aghju sappiutu di cumincià à travaglià cun ellu, chì significa chì deve cuntinuà à fà.

In Linux, a libreria libc apre 3 file descriptori per ogni applicazione in esecuzione (processu), numerata 0,1,2. Più infurmazione pò esse truvata nantu à i ligami omu stdio и omu stdout

  • U descrittore di u schedariu 0 hè chjamatu STDIN è hè assuciatu cù l'input di l'applicazione
  • U descriptor d'archiviu 1 hè chjamatu STDOUT è hè utilizatu da l'applicazioni per pruduce dati, cum'è cumandamenti di stampa
  • U descriptor d'archiviu 2 hè chjamatu STDERR è hè utilizatu da l'applicazioni per pruduce missaghji d'errore.

Se in u vostru prugramma avete apertu un schedariu per leghje o scrive, allora u più prubabile uttene u primu ID gratuitu è ​​serà u numeru 3.

A lista di descriptori di u schedariu pò esse vistu per qualsiasi prucessu se cunnosci u so PID.

Per esempiu, apremu a cunsola bash è fighjemu u PID di u nostru prucessu

[user@localhost ]$ echo $$
15771

In a seconda cunsola corremu

[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

Pudete ignurà in modu sicuru u descrittore di u schedariu 255 per i scopi di questu articulu; hè statu apertu per i so bisogni da bash stessu, è micca da a biblioteca ligata.

Avà tutti i schedarii descriptori 3 sò assuciati cù u pseudo-dispositivu terminal /dev/pts, ma pudemu ancu manipulà, per esempiu, eseguite in una seconda cunsola

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

È in a prima cunsola videremu

[user@localhost ]$ hello world

Redirect è Pipe

Pudete facilmente rimpiazzà questi file descriptori 3 in ogni prucessu, cumpresu in bash, per esempiu attraversu una pipa chì cunnetta dui prucessi, vede

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

Pudete eseguisce stu cumandamentu sè stessu strace -f è vedi ciò chì si passa ind'è, ma ti dicu brevemente.

U nostru prucessu parent bash cù PID 15771 analizà u nostru cumandamentu è capisce esattamente quanti cumandamenti vulemu eseguisce, in u nostru casu ci sò dui: cat è dorme. Bash sà chì ci vole à creà dui prucessi di u zitellu, è unisce in una pipa. In totale, bash hà bisognu di 2 prucessi di u zitellu è una pipa.

Bash esegue una chjama di sistema prima di creà prucessi di u zitellu Pipe è riceve novi descrittori di fugliale nantu à u buffer di pipa temporale, ma questu buffer ùn cunnetta ancu i nostri dui prucessi di u zitellu.

Per u prucessu parent, pare chì ci hè digià una pipa, ma ùn ci hè ancu micca prucessi di u zitellu:

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

Dopu aduprà a chjama di u sistema clonazzioni bash crea dui prucessi figlioli, è i nostri trè prucessi seranu cusì:

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

Ùn vi scurdate micca chì u clone clone u prucessu inseme cù tutti i descrittori di u schedariu, cusì seranu listessi in u prucessu parent è in i zitelli. U travagliu di u prucessu parentale cù PID 15771 hè di monitorà i prucessi di u zitellu, cusì aspetta solu una risposta da i zitelli.

Dunque, ùn hà micca bisognu di pipa, è chjude i descrittori di u schedariu numerati 3 è 4.

In u primu prucessu di bash di u zitellu cù PID 9004, a chjama di u sistema dup2, cambia u nostru descriptor d'archivi STDOUT nùmeru 1 à un descriptor d'archivi chì punta à pipa, in u nostru casu hè u numeru 3. Cusì, tuttu ciò chì u primu prucessu di u zitellu cù PID 9004 scrive à STDOUT finisce automaticamente in u buffer di pipa.

In u sicondu prucessu di u zitellu cù PID 9005, bash usa dup2 per cambià u descriptor d'archivi STDIN numeru 0. Avà tuttu ciò chì a nostra seconda bash cù PID 9005 leghjite serà lettu da a pipa.

Dopu questu, i descriptori di fugliale numerati 3 è 4 sò ancu chjusi in i prucessi di u zitellu, postu chì ùn sò più usati.

Ignoru deliberatamente u descrittore di u schedariu 255; hè adupratu per scopi interni da bash stessu è serà ancu chjusu in i prucessi di u zitellu.

In seguitu, in u primu prucessu di u zitellu cù PID 9004, bash principia cù una chjama di sistema exec u schedariu eseguibile chì avemu specificatu nantu à a linea di cummanda, in u nostru casu hè /usr/bin/cat.

In u sicondu prucessu di u zitellu cù PID 9005, bash corre u secondu eseguibile chì avemu specificatu, in u nostru casu /usr/bin/sleep.

A chjama di u sistema execu ùn chjude micca i manichi di i schedari, salvu ch'elli sò stati aperti cù a bandiera O_CLOEXEC à u mumentu chì a chjama aperta hè stata fatta. In u nostru casu, dopu avè lanciatu i fugliali eseguibili, tutti i descriptori di u schedariu attuale seranu salvati.

Verificate in a cunsola:

[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

Comu pudete vede, u numeru unicu di a nostra pipa hè u listessu in i dui prucessi. Cusì avemu una cunnessione trà dui prucessi diffirenti cù u stessu parente.

Per quelli chì ùn sò micca familiarizati cù e chjama di u sistema chì bash usa, vi cunsigliu assai di eseguisce i cumandamenti attraversu strace è vede ciò chì succede internamente, per esempiu cusì:

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

Andemu à u nostru prublemu di scappari fora di u spaziu discu è circannu à salvà dati senza ripigliate u prucessu. Scrivemu un picculu prugramma chì scriverà circa 1 megabyte per seconda à u discu. Inoltre, se per una certa ragione ùn pudemu micca scrive dati à u discu, simpricimenti ignurà questu è pruvate à scrive i dati di novu in un secondu. In l'esempiu chì aghju utilizatu Python, pudete aduprà qualsiasi altra lingua di prugrammazione.

[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

Eseguimu u prugramma è fighjemu i descrittori di u schedariu

[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

Comu pudete vede, avemu i nostri 3 descriptori di file standard è un altru chì avemu apertu. Cuntrollamu a dimensione di u schedariu:

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

I dati sò scritti, pruvemu di cambià i permessi nantu à u schedariu:

[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

Avemu vistu chì i dati sò sempre scritti, ancu s'è u nostru utilizatore ùn hà micca permessu di scrive à u schedariu. Pruvemu di sguassà:

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

Induve sò scritti i dati? È sò scritti à tutti ? Avemu verificatu:

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

Iè, u nostru descriptore di u schedariu esiste sempre è pudemu trattà stu descrittore di u schedariu cum'è u nostru vechju schedariu, pudemu leghje, sbulicà è copià.

Fighjemu a dimensione di u schedariu:

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

A dimensione di u schedariu hè 19923457. Pruvemu di sguassà u schedariu:

[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

Comu pudete vede, a dimensione di u schedariu hè solu crescente è u nostru troncu ùn hà micca travagliatu. Fighjemu a documentazione di a chjama di u sistema apartu. Se avemu aduprà a bandiera O_APPEND quandu apre un schedariu, dopu cù ogni scrittura, u sistema upirativu verifica a dimensione di u schedariu è scrive dati à a fine di u schedariu, è fà questu atomically. Questu permette parechje fili o prucessi per scrive à u stessu schedariu. Ma in u nostru codice ùn avemu micca aduprà sta bandiera. Pudemu vede una dimensione di u schedariu sfarente in lsof dopu à u troncu solu s'ellu apre u schedariu per scrittura supplementu, chì significa invece in u nostru codice.

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

avemu da mette

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

Verificate cù a bandiera "w".

[user@localhost ]$ strace -e trace=open python openforwrite.py 2>&1| grep 123.txt
open("123.txt", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 3

è cù a bandiera "a".

[user@localhost ]$ strace -e trace=open python openforwrite.py 2>&1| grep 123.txt
open("123.txt", O_WRONLY|O_CREAT|O_APPEND, 0666) = 3

Prugrammazione di un prucessu digià in esecuzione

Spessu i programatori, quandu creanu è teste prugrammi, utilizanu debuggers (per esempiu GDB) o diversi livelli di logging in l'applicazione. Linux furnisce l'abilità di scrive veramente è cambià un prugramma digià in esecuzione, per esempiu, cambià i valori di variabili, stabilisce un puntu di ruptura, etc., etc.

Riturnendu à a quistione originale chì ùn hè micca abbastanza spaziu di discu per scrive un schedariu, pruvemu à simule u prublema.

Creemu un schedariu per a nostra partizione, chì monteremu cum'è un discu separatu:

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

Creemu un sistema di schedari:

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

Muntà u sistema di schedari:

[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

Creemu un annuariu cù u nostru pruprietariu:

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

Aprimu u schedariu per scrive solu in u nostru prugramma:

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

Lanciari

[user@localhost ]$ python openforwrite.py 

Aspittemu uni pochi seconde

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

Dunque, avemu u prublema discritta à u principiu di stu articulu. Spaziu liberu 0, 100% occupatu.

Ricurdamu chì secondu e cundizioni di u compitu, avemu a prova di arregistrà dati assai impurtanti chì ùn ponu micca persu. È à u listessu tempu, avemu bisognu di riparà u serviziu senza ripiglià u prucessu.

Diciamu chì avemu sempre spaziu di discu, ma in una partizione diversa, per esempiu in /home.

Pruvemu di "riprogrammà nantu à a mosca" u nostru codice.

Fighjemu u PID di u nostru prucessu, chì hà manghjatu tuttu u spaziu di discu:

[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

Cunnette vi u prucessu via gdb

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

Fighjemu i descrittori di u schedariu aperti:

(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

Fighjemu l'infurmazioni nantu à u descriptore di u schedariu numeru 3, chì ci interessa

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

Tenendu in mente ciò chì u sistema chjamatu Python face (vede sopra induve curriamu strace è truvamu a chjama aperta), quandu trasfurmava u nostru codice per apre un schedariu, facemu u stessu in nome di u nostru prucessu, ma avemu bisognu di u O_WRONLY|O_CREAT| I bits O_TRUNC rimpiazzanu cù un valore numericu. Per fà questu, apre i fonti di u kernel, per esempiu ccà è fighjate chì bandiere sò rispunsevuli di ciò chì

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

Cumbinemu tutti i valori in unu, avemu 00001101

Eseguimu a nostra chjama da gdb

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

Allora avemu un novu descriptore di schedariu cù u numeru 4 è un novu schedariu apertu nantu à una altra partizione, cuntrollemu:

(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

Ricurdamu l'esempiu cù pipe - cumu bash cambia i descrittori di u schedariu, è avemu digià amparatu a chjama di u sistema dup2.

Pruvemu di rimpiazzà un descrittore di fugliale cù un altru

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

Verificate:

(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

Chiudemu u descriptore di u schedariu 4, postu chì ùn ne avemu micca bisognu:

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

È esce da 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

Verificate u novu schedariu:

[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

Comu pudete vede, i dati sò scritti in un novu schedariu, cuntrollemu u vechju:

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

Nisuna dati hè persu, l'applicazione funziona, i logs sò scritti in un novu locu.

Cumplichemu un pocu u compitu

Imaginemu chì i dati sò impurtanti per noi, ma ùn avemu micca spaziu di discu in alcuna partizioni è ùn pudemu micca cunnette u discu.

Ciò chì pudemu fà hè di ridirezzione di i nostri dati in un locu, per esempiu à pipa, è in turnu redirezzione di dati da a pipa à a reta per un prugramma, per esempiu netcat.
Pudemu creà una pipa chjamata cù u cumandimu mkfifo. Ci hà da creà un pseudo schedariu nant'à u sistema di schedari ancu s'ellu ùn ci hè micca spaziu liberu nantu à ellu.

Riavvia l'applicazione è verificate:

[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

Ùn ci hè micca spaziu di discu, ma avemu criatu bè una pipa chjamata quì:

[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

Avà avemu bisognu d'incarcerà tutte e dati chì entranu in questa pipa à un altru servitore via a reta; u stessu netcat hè adattatu per questu.

Nant'à u servitore remote-server.example.com curriamu

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

In u nostru servitore problematicu lanciamu in un terminal separatu

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

Avà tutti i dati chì finiscinu in u pipe andaranu automaticamente à stdin in netcat, chì u mandarà à a reta in u portu 7777.

Tuttu ciò chì avemu da fà hè di cumincià à scrive i nostri dati in questa pipa chjamata.

Avemu digià l'applicazione in esecuzione:

[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

Di tutti i bandieri, avemu solu bisognu di O_WRONLY postu chì u schedariu esiste digià è ùn avemu micca bisognu di sguassà

[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

Verificate u servitore remoto remote-server.example.com

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

I dati venenu, cuntrollemu u servitore prublema

[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

I dati sò salvati, u prublema hè risolta.

Approfittu di sta occasione per salutà i mo culleghi di Degiro.
Ascolta i podcast di Radio-T.

Bon à tutti.

Cum'è i travaglii di casa, vi suggerenu di pensà à ciò chì serà in i descrittori di u schedariu di prucessu cat and sleep si eseguite u cumandimu seguente:

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

Source: www.habr.com

Add a comment