Una vegada, en una entrevista, em van preguntar què faries si trobes un servei trencat a causa del fet que el disc s'ha quedat sense espai?
Això sí, vaig respondre que miraria què feia aquest lloc i, si era possible, netejaria el lloc.
Llavors l'entrevistador va preguntar: què passa si no hi ha espai lliure a la partició, però tampoc veus els fitxers que ocuparien tot l'espai?
A això, vaig dir que sempre podeu mirar els descriptors de fitxers oberts, per exemple, amb l'ordre lsof i entendre quina aplicació ha ocupat tot l'espai disponible, i després podeu actuar segons les circumstàncies, depenent de si les dades són necessàries. .
L'entrevistador em va interrompre a l'última paraula, i va afegir a la seva pregunta: "Suposem que no necessitem les dades, només és un registre de depuració, però l'aplicació està inactiva perquè no pot escriure la depuració"?
"D'acord", vaig respondre, "podem desactivar la depuració a la configuració de l'aplicació i reiniciar-la".
L'entrevistador va objectar: "No, no podem reiniciar l'aplicació, encara tenim dades importants a la memòria i clients importants estan connectats al propi servei, que no podem obligar a tornar a connectar".
"D'acord", vaig dir, "si no podem reiniciar l'aplicació i no ens importen les dades, llavors només podem esborrar aquest fitxer obert mitjançant el descriptor de fitxer, fins i tot si no el veiem a ls comanda al sistema de fitxers".
L'entrevistador estava satisfet, però jo no.
Llavors vaig pensar, per què la persona que prova els meus coneixements no aprofundeix més? Però, i si les dades són importants després de tot? Què passa si no podem reiniciar el procés i, al mateix temps, aquest procés escriu al sistema de fitxers en una partició que no té espai lliure? Què passa si no podem perdre no només les dades ja escrites, sinó també les dades que aquest procés està escrivint o intentant escriure?
Tuzik
Al començament de la meva carrera, estava intentant crear una petita aplicació que necessitava emmagatzemar informació sobre els usuaris. I llavors vaig pensar, com puc relacionar l'usuari amb les seves dades. Per exemple, tinc Ivanov Ivan Ivanovich, i té algunes dades, però com fer-los amics? Puc assenyalar directament que el gos anomenat "Tuzik" pertany a aquest mateix Ivan. Però, què passa si canvia de nom i en comptes d'Ivan es converteix, per exemple, en Olya? Aleshores resultarà que la nostra Olya Ivanovna Ivanova ja no tindrà un gos i el nostre Tuzik continuarà pertanyent a l'inexistent Ivan. La base de dades va ajudar a resoldre aquest problema, que donava a cada usuari un identificador únic (ID), i el meu Tuzik estava lligat a aquest identificador, que, de fet, era només un número de sèrie. Així, el propietari del tuzik tenia el número d'identificació 2, i en algun moment Ivan estava sota aquest identificador, i després Olya es va convertir en el mateix identificador. El problema de la humanitat i la ramaderia estava pràcticament resolt.
Descriptor de fitxer
El problema d'un fitxer i d'un programa que funciona amb aquest fitxer és gairebé el mateix que el nostre gos i humà. Suposem que vaig obrir un fitxer anomenat ivan.txt i vaig començar a escriure-hi la paraula tuzik, però vaig aconseguir escriure només la primera lletra "t" al fitxer i algú va canviar el nom d'aquest fitxer, per exemple, a olya.txt. Però el fitxer és el mateix i encara vull escriure-hi el meu as. Cada vegada que obriu un fitxer amb una trucada al sistema
A Linux, la biblioteca libc obre 3 fitxers descriptors per a cada aplicació (procés) en execució, amb els números 0,1,2. Més informació podeu trobar als enllaços
- El descriptor de fitxer 0 s'anomena STDIN i està associat a l'entrada de l'aplicació.
- El descriptor de fitxer 1 s'anomena STDOUT i és utilitzat per aplicacions de sortida com ara ordres d'impressió.
- El descriptor de fitxer 2 s'anomena STDERR i les aplicacions l'utilitzen per generar missatges d'error.
Si al vostre programa obriu qualsevol fitxer per llegir o escriure, és molt probable que obtingueu el primer identificador gratuït i serà el número 3.
Podeu veure la llista de descriptors de fitxers per a qualsevol procés si coneixeu el seu PID.
Per exemple, obrim una consola amb bash i veiem el PID del nostre procés
[user@localhost ]$ echo $$
15771
A la segona consola, executeu
[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
Podeu ignorar amb seguretat el descriptor del fitxer amb el número 255 en el marc d'aquest article, ja que s'ha obert per a les vostres necessitats pel mateix bash i no per la biblioteca enllaçada.
Ara els 3 fitxers descriptors estan associats amb el dispositiu pseudoterminal
[user@localhost ]$ echo "hello world" > /proc/15771/fd/0
I a la primera consola ho veurem
[user@localhost ]$ hello world
Redirecció i canalització
Podeu substituir fàcilment aquests 3 fitxers descriptors en qualsevol procés, inclòs a bash, per exemple, a través d'una canonada (pipe) que connecta dos processos, vegeu
[user@localhost ]$ cat /dev/zero | sleep 10000
Podeu executar aquesta comanda vosaltres mateixos strace -f i a veure què passa dins, però ho faré curt.
El nostre procés bash principal amb PID 15771 analitza la nostra ordre i entén exactament quantes ordres volem executar, en el nostre cas n'hi ha dues: cat i sleep. Bash sap que ha de crear dos processos fills i fusionar-los en un sol tub. En total, bash necessitarà 2 processos secundaris i una canonada.
Abans de crear processos fills, bash executa una trucada al sistema
Per al procés principal, sembla que la canonada ja hi és, però encara no hi ha processos secundaris:
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
A continuació, utilitzeu la trucada del sistema
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
No oblideu que el clon clona el procés juntament amb tots els descriptors de fitxers, de manera que seran els mateixos en el procés pare i en els fills. La tasca del procés principal amb PID 15771 és supervisar els processos secundaris, de manera que només espera una resposta dels fills.
Per tant, no necessita cap canonada i tanca els descriptors de fitxers amb els números 3 i 4.
En el primer procés fill bash amb PID 9004, la trucada del sistema
En el segon procés fill amb PID 9005, bash dup2 el fitxer al descriptor STDIN número 0. Ara tot el que llegirà el nostre segon bash amb PID 9005 es llegirà de la canonada.
Després d'això, els descriptors de fitxers amb els números 3 i 4 també es tanquen als processos fills, ja que ja no s'utilitzen.
Ignoro deliberadament el descriptor de fitxer 255, el mateix bash l'utilitza internament i també es tancarà als processos fills.
A continuació, en el primer procés fill amb PID 9004, bash comença amb una trucada al sistema
En el segon procés fill amb PID 9005, bash executa el segon executable que hem especificat, en el nostre cas /usr/bin/sleep.
La crida al sistema exec no tanca els descriptors de fitxers tret que s'hagin obert amb el senyalador O_CLOEXEC en el moment en què es va executar la crida oberta. En el nostre cas, després d'executar els fitxers executables, es desaran tots els descriptors de fitxers actuals.
Comprovació a la consola:
[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
Com podeu veure, el número únic de la nostra canonada és el mateix en tots dos processos. Així, tenim una connexió entre dos processos diferents amb el mateix pare.
Per a aquells que no estiguin familiaritzats amb les trucades del sistema que fa servir bash, recomano encaridament executar ordres mitjançant Strace i veure què passa dins, per exemple, com aquest:
strace -s 1024 -f bash -c "ls | grep hello"
Tornem al nostre problema amb quedar-nos sense espai al disc i intentar desar dades sense reiniciar el procés. Escrivim un petit programa que escrigui al disc aproximadament 1 megabyte per segon. A més, si per algun motiu no podíem escriure dades al disc, simplement ho ignorarem i intentarem escriure les dades de nou en un segon. A l'exemple que estic fent servir Python, podeu utilitzar qualsevol altre llenguatge de programació.
[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
Executeu el programa i mireu els descriptors de fitxers
[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
Com podeu veure, tenim els nostres 3 descriptors de fitxer estàndard i un altre que hem obert. Comprovem la mida del fitxer:
[user@localhost ]$ ls -lah 123.txt
-rw-rw-r-- 1 user user 117M Oct 7 16:30 123.txt
les dades estan escrites, intentem canviar els drets del fitxer:
[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
Veiem que les dades encara s'estan escrivint, tot i que el nostre usuari no té dret a escriure al fitxer. Intentem eliminar-lo:
[user@localhost ]$ sudo rm 123.txt
[user@localhost ]$ ls 123.txt
ls: cannot access 123.txt: No such file or directory
On s'escriuen les dades? I estan escrites en absolut? Comprovem:
[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)
Sí, el nostre descriptor de fitxer encara existeix, i podem treballar amb aquest descriptor de fitxer com el nostre fitxer antic, podem llegir-lo, netejar-lo i copiar-lo.
Mireu la mida del fitxer:
[user@localhost ]$ lsof | grep 123.txt
python 31083 user 3w REG 8,5 19923457 2621522 /home/user/123.txt
La mida del fitxer és 19923457. S'està intentant esborrar el fitxer:
[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
Com podeu veure, la mida del fitxer només augmenta i el nostre tronc no va funcionar. Anem a la documentació de la trucada del sistema
with open("123.txt", "w") as f:
hem de posar
with open("123.txt", "a") as f:
Comprovació amb la bandera "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
i amb bandera "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
Programació d'un procés ja en execució
Sovint, en crear i provar un programa, els programadors utilitzen depuradors (per exemple, GDB) o diversos nivells de registre a l'aplicació. Linux ofereix la possibilitat d'escriure i canviar realment un programa que ja s'executa, com ara canviar els valors de les variables, establir un punt d'interrupció, etc.
Tornant a la pregunta original sobre la manca d'espai al disc per escriure un fitxer, intentem simular el problema.
Creem un fitxer per a la nostra partició, que muntarem com a unitat independent:
[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 ~]$
Creem un sistema de fitxers:
[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 ~]$
Muntem el sistema de fitxers:
[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
Creeu un directori amb el nostre propietari:
[user@localhost ~]$ sudo mkdir /mnt/logs
[user@localhost ~]$ sudo chown user: /mnt/logs
Obrim el fitxer per escriure només al nostre programa:
with open("/mnt/logs/123.txt", "w") as f:
Llançament
[user@localhost ]$ python openforwrite.py
Esperant uns segons
[user@localhost ~]$ df -h | grep mnt
/dev/loop0 8.7M 8.0M 0 100% /mnt
Per tant, tenim el problema descrit al principi d'aquest article. Espai lliure 0, ocupat al 100%.
Recordem que segons les condicions del problema, estem intentant registrar dades molt importants que no es poden perdre. I en fer-ho, hem de solucionar el servei sense reiniciar el procés.
Suposem que encara tenim espai al disc, però en una partició diferent, per exemple, a / home.
Intentem "reprogramar sobre la marxa" el nostre codi.
Mirem el PID del nostre procés, que va consumir tot l'espai del disc:
[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
Connexió a un procés amb gdb
[user@localhost ~]$ gdb -p 10078
...
(gdb)
Mirem els descriptors de fitxers oberts:
(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
Observem informació sobre el descriptor de fitxer amb el número 3, que ens interessa
(gdb) shell cat /proc/10078/fdinfo/3
pos: 8189952
flags: 0100001
mnt_id: 482
Tenint en compte quina trucada de sistema fa Python (vegeu més amunt on hem executat Strace i hem trobat una trucada oberta), mentre processem el nostre codi per obrir un fitxer, fem el mateix nosaltres mateixos en nom del nostre procés, però necessitem O_WRONLY|O_CREAT| Els bits O_TRUNC se substitueixen per un valor numèric. Per fer-ho, obriu les fonts del nucli, per exemple
#definir O_WRONLY 00000001
#definir O_CREAT 00000100
#definir O_TRUNC 00001000
Combinem tots els valors en un, obtenim 00001101
Executant la nostra trucada des de gdb
(gdb) call open("/home/user/123.txt", 00001101,0666)
$1 = 4
Així que tenim un nou descriptor de fitxer amb el número 4 i un nou fitxer obert en una altra partició, comproveu:
(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
Recordem l'exemple amb pipe: com bash canvia els descriptors de fitxers i ja hem après la trucada al sistema dup2.
S'està intentant substituir un descriptor de fitxer per un altre
(gdb) call dup2(4,3)
$2 = 3
Comprovem:
(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
Tanqueu el descriptor de fitxer 4, ja que no el necessitem:
(gdb) call close (4)
$1 = 0
I surt 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
Comprovant el nou fitxer:
[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
Com podeu veure, les dades s'escriuen en un fitxer nou, comprovem l'antic:
[user@localhost ~]$ ls -lah /mnt/logs/123.txt
-rw-rw-r-- 1 user user 7.9M Oct 8 11:08 /mnt/logs/123.txt
Les dades no es perden, l'aplicació funciona, els registres s'escriuen en una nova ubicació.
Posem les coses una mica més difícils
Imagineu que les dades són importants per a nosaltres, però no tenim espai en disc a cap de les particions i no podem connectar el disc.
El que podem fer és redirigir les nostres dades a algun lloc, per exemple, a una canonada, i redirigir les dades de la canonada a la xarxa mitjançant algun programa, com ara netcat.
Podem crear una canonada amb nom amb l'ordre mkfifo. Crearà un pseudofitxer al sistema de fitxers, encara que no hi hagi espai lliure.
Reinicieu l'aplicació i comproveu:
[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
No hi ha espai al disc, però creem correctament una canonada amb nom allà:
[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
Ara hem d'embolicar d'alguna manera totes les dades que entren en aquesta canonada a un altre servidor a través de la xarxa, el mateix netcat és adequat per a això.
Al servidor remote-server.example.com, executeu
[user@localhost ~]$ nc -l 7777 > 123.txt
Al nostre servidor de problemes, executeu-lo en un terminal independent
[user@localhost ~]$ nc remote-server.example.com 7777 < /mnt/logs/megapipe
Ara totes les dades que entren a la canonada aniran automàticament a stdin a netcat, que les enviarà a la xarxa al port 7777.
Tot el que hem de fer és començar a escriure les nostres dades en aquesta canonada amb nom.
Ja tenim una aplicació en funcionament:
[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
De totes les banderes, només necessitem O_WRONLY ja que el fitxer ja existeix i no cal esborrar-lo
[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
Comprovació del servidor remot remote-server.example.com
[user@localhost ~]$ ls -lah 123.txt
-rw-rw-r-- 1 user user 38M Oct 8 14:21 123.txt
Arriben les dades, comprovem el servidor del problema
[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
Es guarden les dades, es resol el problema.
Aprofito per saludar els meus companys de Degiro.
Escolta els podcasts de Radio-T.
Tot bé.
Com a deures, proposo pensar què hi haurà als descriptors de fitxers del procés cat i sleep si executeu l'ordre següent:
[user@localhost ~]$ cat /dev/zero 2>/dev/null| sleep 10000
Font: www.habr.com