4 votos

¿Cuál es el significado del comando lsof +L1

lsof +L1

Entiendo que el comando anterior muestra los archivos que han sido eliminados pero que siguen abiertos. Estos archivos tienen un "recuento de enlaces" de 0, lo que significa que no hay ninguna entrada de directorio (ningún enlace, es decir, ningún nombre) que conduzca a ellos, pero los datos del archivo todavía existen. Los datos del archivo se borrarán cuando se cierre el archivo. Suelo ver referencias a este problema cuando la gente habla de archivos de registro en los que el sistema está escribiendo. El archivo puede ser borrado, pero el proceso continúa escribiendo en el archivo y ocupa más y más memoria. Otras personas han identificado esto a veces como un comportamiento malicioso de un malware que está tratando de ocultarse.

Estoy tratando de entender cómo puede suceder esto? Cuando abro un archivo para leer o escribir en Python, el archivo existe en el disco. Intenté leer la documentación de Xcode sobre el acceso a archivos, pero es muy densa. ¿Hay diferentes tipos de archivos - los que están en la memoria RAM y los que están en el disco?

Se trata de archivos con nombre para que no sea la memoria la que utilice la aplicación. Por ejemplo, si ejecuto este comando en mi Mac, aparecen unos 300 archivos de este tipo. Los procesos "ofensivos" son cosas como loginwindow, dock, systemUIS, sharingd, CalendarA, y muchos otros. Si se trata de cosas que un proceso está escribiendo en la RAM, ¿puedo 'adjuntarme' al proceso con gdb y ver lo que está haciendo? ¿Puedo escribir estos archivos en el disco para leerlos?

14voto

Mat Puntos 217

Hay tres cosas en un "archivo" en los sistemas de archivos POSIX:

  • El conjunto de bloques de datos: el contenido real del archivo.
  • El inode que es una estructura que contiene la lista de dichos bloques, y algunos metadatos (tamaño, propiedad, permisos, recuento de enlaces y algunos otros).
  • Uno o más entradas de directorio que contienen un nombre y un número de inodo (y otras cosas)

Lo que se ve cuando se ejecuta ls o en los exploradores de archivos son las entradas del directorio, organizadas en un árbol de directorios y archivos. Cada una de las entradas de directorio asigna el nombre del archivo a un número de inodo. El número de inodo se utiliza para localizar el inodo, que se utiliza para localizar los bloques reales (y comprobar los permisos, etc.)

Cuando se crea un archivo, se crea un inodo con una cuenta inicial de enlaces de uno, y se establece una entrada de directorio con el nombre especificado, apuntando a ese inodo.

Si crea un duro se crea una segunda entrada en el directorio con el nombre elegido, pero apuntando al mismo inodo - ambas entradas de directorio se refieren al mismo inodo (es decir, ahora tiene dos nombres que se refieren al mismo archivo). La cuenta de enlaces del inodo se incrementa por cada nuevo enlace duro.

Cuando un proceso abre un archivo, utilizando un nombre de archivo, el núcleo hace la búsqueda de la entrada de directorio, encuentra el inodo y devuelve un descriptor de archivo que "hace referencia" al inodo, no a la entrada de directorio. La entrada del directorio es irrelevante una vez que el archivo ha sido abierto - es sólo una forma conveniente de localizar el inodo correcto.

Cuando se elimina un archivo (por ejemplo, utilizando rm ), en realidad no estás borrando el archivo, sino la entrada del directorio. El núcleo disminuye la cuenta de enlaces del inodo, pero no borra el inodo (y recupera espacio) a menos que:

  • que la entrada del directorio era la última que apuntaba a él (es decir, el recuento de enlaces se reduce a cero - esto es lo que lsof +L1 listas: abrir archivos completamente desvinculados)
  • no quedan descriptores de archivo abiertos que hagan referencia a él

Así que los procesos pueden seguir operando en ese archivo, incluso si no hay manera de volver a él desde la exploración del sistema de archivos. Y puedes obtener aparentes inconsistencias de la salida de df y du por ejemplo:

  • df interroga al sistema de archivos para ver cuántos bloques libres tiene. Los bloques de datos de los archivos "ocultos" sin más entradas en el directorio no están libres (todavía hay procesos que pueden leerlos/escribirlos), por lo que siguen ocupando espacio y seguirán ocupando ese espacio hasta que se cierre el último descriptor de archivo que hace referencia a ellos
  • du enumera las entradas del directorio y suma los tamaños. No puede ver estos archivos no enlazados, y por lo tanto devolverá menos espacio utilizado que el sistema de archivos.

Si los archivos están en discos tradicionales, siguen ocupando espacio en el disco como archivos normales, aún vinculados. El IO se produce con normalidad. No tiene más requerimientos de memoria principal/empieza a comer RAM.

Si los archivos desvinculados pero abiertos están en un sistema de archivos respaldado por la memoria RAM, entonces siguen ocupando memoria, como lo hacían antes de ser desvinculados. (En ambos casos, los archivos también pueden crecer/reducirse).

El espacio se recuperará sólo cuando se cierre el último descriptor de archivo abierto. (Tenga en cuenta que los descriptores de archivo aún abiertos se cierran cuando un proceso sale o se termina de otra manera).


Si adjuntas un depurador a un programa que está usando archivos no enlazados, no verás nada particularmente interesante. Las llamadas de IO de los archivos se verán exactamente igual que las de los archivos normales, aún enlazados. No ocurre nada especial. Inspeccionando lo que se lee/escribe puedes obtener algunas ideas sobre para qué está usando el proceso estos archivos, pero eso es todo.

En cuanto al acceso a estos archivos, me temo que no conozco OS X lo suficiente como para decir si hay una manera fácil. El fdesc pseudo-sistema de archivos parece que podría ser útil, pero aparentemente sólo le da acceso a los archivos del proceso actual.


Un ejemplo sencillo de cómo un proceso puede hacer esto, en perl. (Se puede hacer con casi cualquier lenguaje, incluyendo scripts).

Función de configuración y ayuda:

#! /usr/bin/perl
use strict;
use warnings;
use Fcntl qw(SEEK_SET); # for rewinding

my $fh;                 # file descriptor/handle
my $test_file = "./test_file";

sub status {            # checks if the file is "visible"
  my @st = stat($test_file);
  if (@st) {
    print "$test_file: file exists\n";
  } else {
    print "$test_file: error: $!\n";
  }     
}

La parte principal:

# open file in read/write mode, creating it if it doesn't exist
# (overwriting it if it does)
if (!open($fh, '+>', $test_file)) {
  die "Failed to open $test_file: $!";
}
print $fh "Some data before unlink.\n";
status();
unlink($test_file);
status();
print $fh "Some data after unlink.\n";

# Rewind
seek($fh, 0, SEEK_SET);
# Print file contents
foreach my $line (<$fh>) {
  print "read: $line";
}
# Close
close($fh);

Resultado esperado:

 $ perl test.pl
./test_file: file exists
./test_file: error: No such file or directory
read: Some data before unlink.
read: Some data after unlink.

Puedes mover el desenlace un poco (antes o después de las impresiones), no cambiará nada. No hay nada especial en el manejador de archivo después de la desvinculación, puede ser utilizado como cualquier otro manejador de archivo (siempre y cuando se mantenga abierto).

0 votos

Gracias. Veo un paralelismo entonces - una entrada de directorio es como una url y el inodo es como la dirección IP de esa url. Me gustaría que me aclararan cómo un proceso puede crear un archivo y luego borrar la entrada del directorio

0 votos

@aquagremlin: ha añadido un ejemplo de un perl script que hace este truco de desaparición de archivos. Realmente no hay nada especial en ello - si un proceso desvincula un archivo mientras tiene un manejador/descriptor de archivo abierto, el manejador de archivo sigue siendo válido.

AppleAyuda.com

AppleAyuda es una comunidad de usuarios de los productos de Apple en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros usuarios, hacer tus propias preguntas o resolver las de los demás.

Powered by:

X