Listar los archivos a los que accede un programa

64

time es un comando brillante si desea calcular cuánto tiempo de CPU tarda un comando determinado.

Estoy buscando algo similar que pueda enumerar los archivos a los que accede un programa y sus hijos. Ya sea en tiempo real o como un informe posterior.

Actualmente uso:

#!/bin/bash

strace -ff -e trace=file "$@" 2>&1 | perl -ne 's/^[^"]+"(([^\\"]|\\[\\"nt])*)".*/$1/ && print'

pero falla si el comando para ejecutar implica sudo. No es muy inteligente (sería bueno si solo pudiera enumerar archivos existentes o que tuvieran problemas de permisos o agruparlos en archivos que se leen y archivos que se escriben). También stracees lento, por lo que sería bueno con una elección más rápida.

Ole Tange
fuente
Dado su uso de strace, supongo que está específicamente interesado en Linux. ¿Correcto?
Gilles 'SO- deja de ser malvado'
Linux es mi principal preocupación.
Ole Tange

Respuestas:

51

Me di por vencido y codifiqué mi propia herramienta. Para citar de sus documentos:

SYNOPSIS
    tracefile [-adefnu] command
    tracefile [-adefnu] -p pid

OPTIONS
    -a        List all files
    -d        List only dirs
    -e        List only existing files
    -f        List only files
    -n        List only non-existing files
    -p pid    Trace process id
    -u        List only files once

Solo genera los archivos, por lo que no necesita tratar con la salida de strace.

https://gitlab.com/ole.tange/tangetools/tree/master/tracefile

Ole Tange
fuente
¡Gracias! La salida de strace es absolutamente ilegible. Sin embargo, no sé dónde encontrar los documentos, sería bueno si tuviera una opción de ayuda -h / -. También agradecería una opción que solo muestre ediciones de archivos, no accesos.
Xerus
@Xerus Clone gitlab.com/ole.tange/tangetools y ejecuta make && sudo make install. Entonces puedes correr man tracefile.
Ole Tange
44
Buena herramienta Empaquetado, para instalar: yum -y install https://extras.getpagespeed.com/release-el7-latest.rpmyyum -y install tracefile
Danila Vershinin
27

Puede rastrear las llamadas del sistema strace, pero de hecho hay una penalización de velocidad inevitable. Debe ejecutar stracecomo root si el comando se ejecuta con privilegios elevados:

sudo strace -f -o foo.trace su user -c 'mycommand'

Otro método que es probable que sea más rápido es para precargar una biblioteca que se envuelve alrededor de las funciones de acceso del sistema de archivos: LD_PRELOAD=/path/to/libmywrapper.so mycommand. La LD_PRELOADvariable de entorno no se pasará a los programas invocados con privilegios elevados. Tendría que escribir el código de esa biblioteca de envoltura ( aquí hay un ejemplo de "Crear interpositores de biblioteca para divertirse y obtener ganancias" ); No sé si hay código reutilizable disponible en la web.

Si está monitoreando los archivos en una jerarquía de directorio particular, puede hacer una vista del sistema de archivos con LoggedFS de modo que todos los accesos a través de esa vista se registren.

loggedfs -c my-loggedfs.xml /logged-view
mycommand /logged-view/somedir

Para configurar LoggedFS, comience con la configuración de muestra incluida con el programa y lea la sintaxis del archivo de configuración LoggedFS .

Otra posibilidad es el subsistema de auditoría de Linux . Asegúrese de que el auditddemonio esté iniciado, luego configure con qué desea iniciar sesión auditctl. Cada operación registrada se registra en /var/log/audit/audit.log(en distribuciones típicas). Para comenzar a mirar un archivo en particular:

auditctl -a exit,always -w /path/to/file

Si coloca un reloj en un directorio, los archivos en él y sus subdirectorios también se verán de forma recursiva. Tenga cuidado de no mirar el directorio que contiene los registros de auditoría. Puede restringir el registro a ciertos procesos; consulte la auditctlpágina de manual para ver los filtros disponibles. Debe ser root para usar el sistema de auditoría.

Gilles 'SO- deja de ser malvado'
fuente
LD_PRELOADtampoco funcionará en binarios estáticos.
David dado
6

Creo que quieres lsof (posiblemente canalizado a un grep en el programa y son niños). Le indicará cada archivo al que se está accediendo actualmente en el sistema de archivos. Para obtener información sobre a qué archivos se accede por proceso ( desde aquí ):

lsof -n -p `pidof your_app`
unclejamil
fuente
11
Pero solo me da una instantánea. Lo que necesito es a qué archivos intentó acceder. Piense en la situación en la que un programa se niega a comenzar porque dice "Falta el archivo". ¿Cómo puedo averiguar qué archivo estaba buscando?
Ole Tange
2

He intentado que tracefile. Para mí, dio muchos menos partidos que el mío strace ... | sed ... | sort -u. Incluso agregué -s256a la strace(1)línea de comando pero no ayudó mucho ...

Entonces lo intenté loggedfs. Primero falló ya que no tenía acceso de lectura / escritura al directorio en el que intenté iniciar sesión. Después de hacer chmod 755 temporalmente, recibí algunos golpes ...

Pero, para mí, hacer lo siguiente parece funcionar mejor:

inotifywait -m -r -e OPEN /path/to/traced/directory

Y luego procese el resultado después de ejecutar el proceso de interés.

Esto no detecta el acceso al proceso de archivos fuera del directorio rastreado ni tampoco sabe si algún otro proceso accedió al mismo árbol de directorios, pero en muchos casos esta es una herramienta suficientemente buena para hacer el trabajo.

EDITAR: inotifywait no captura el acceso de enlace simbólico (solo los objetivos después de que se hayan resuelto los enlaces simbólicos). Esto me golpeó cuando archivé bibliotecas a las que accedió un programa para uso futuro. Usé un poco de piratería adicional de Perl Glob para elegir los enlaces simbólicos a lo largo de las bibliotecas notificadas para hacer el trabajo en ese caso particular.

Edit2: al menos cuando inotifying archivos y enlaces simbólicos propios de línea de comandos inotifywait (por ejemplo, inotifywait -m file symlinko inotifywait symlink file) de salida mostrará el acceso a cuál es el primero en la línea de comandos (sin tener en cuenta el que, filede symlinkse accede). inotifywait no admite IN_DONT_FOLLOW, que, cuando lo intenté programáticamente, solo hace que uno vea el acceso file(que puede o no ser lo que uno espera ...) independientemente del orden en la línea de comandos

Tomi Ollila
fuente
"Para mí, dio mucho menos coincidencias que la mía" ¿Puedes compartir un ejemplo de tracefilefalta de acceso a un archivo?
Ole Tange
No estoy seguro de lo que estás preguntando exactamente:) ... Si trato de buscar archivos dentro de / path / to / traced / directory / veo OPEN en la salida de inotify ... PERO stat (1) ing los archivos parece que para no obtener resultados en los pocos casos que probé (me pregunto por qué, se está leyendo algo del contenido del directorio de ocultación del almacenamiento en caché)
Tomi Ollila
Estoy comentando la publicación de fanotify a continuación (solo tengo 21 reputación, aunque he tenido cuenta durante más de una década; requerir 50 para comentar siempre ha sido un obstáculo para mí ...) - fanotify es algo bueno, pero no puede evite el problema de desreferencia de enlaces simbólicos (es decir, en el caso de enlaces simbólicos, el archivo final al que se accede se encuentra leyendo / proc / self / fd / <fd> .. de todos modos +1: ing la respuesta: D
Tomi Ollila
1

Si bien es posible que no le brinde suficiente control (¿todavía?), He escrito un programa que satisface al menos parcialmente sus necesidades, usando fanotify y no compartido de linux-kernel para monitorear solo archivos modificados (o leídos) por un proceso específico y sus hijos . En comparación con strace, es bastante rápido (;

Se puede encontrar en https://github.com/tycho-kirchner/shournal

Ejemplo en el shell:

$ shournal -e sh -c 'echo hi > foo1; echo hi2 > foo2'
$ shournal -q --history 1
  # ...
  Written file(s):                                                                                                                                                                              
 /tmp/foo1 (3 bytes) Hash: 15349503233279147316                                                                                                                                             
 /tmp/foo2 (4 bytes) Hash: 2770363686119514911    
Aparecer
fuente