web-dev-qa-db-fra.com

Lister les fichiers auxquels accède un programme

time est une commande brillante si vous voulez savoir combien de temps CPU prend une commande donnée.

Je recherche quelque chose de similaire qui peut répertorier les fichiers auxquels accède un programme et ses enfants. Soit en temps réel, soit sous forme de rapport par la suite.

Actuellement j'utilise:

#!/bin/bash

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

mais son échoue si la commande à exécuter implique Sudo. Ce n'est pas très intelligent (ce serait bien s'il pouvait seulement lister les fichiers existants ou qui ont eu des problèmes d'autorisation ou les regrouper en fichiers lus et en fichiers écrits). strace est également lent, donc ce serait bien avec un choix plus rapide.

65
Ole Tange

J'ai abandonné et codé mon propre outil. Pour citer ses documents:

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

Il ne produit que les fichiers, vous n'avez donc pas besoin de traiter la sortie de strace.

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

56
Ole Tange

Vous pouvez tracer les appels système avec strace, mais il y a en effet une pénalité de vitesse inévitable. Vous devez exécuter strace en tant que root si la commande s'exécute avec des privilèges élevés:

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

Une autre méthode susceptible d'être plus rapide consiste à précharger une bibliothèque qui contourne les fonctions d'accès au système de fichiers: LD_PRELOAD=/path/to/libmywrapper.so mycommand. Le LD_PRELOAD la variable d'environnement ne sera pas transmise aux programmes appelés avec des privilèges élevés. Vous devez écrire le code de cette bibliothèque wrapper ( voici un exemple tiré de "Construire des interposeurs de bibliothèque pour le plaisir et le profit" ); Je ne sais pas si du code réutilisable est disponible sur le Web.

Si vous surveillez les fichiers dans une hiérarchie de répertoires particulière, vous pouvez faire une vue du système de fichiers avec LoggedFS de sorte que tous les accès via cette vue soient enregistrés .

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

Pour configurer LoggedFS, commencez par l'exemple de configuration fourni avec le programme et lisez Syntaxe du fichier de configuration LoggedFS .

Une autre possibilité est le sous-système d'audit de Linux . Assurez-vous que le démon auditd est démarré, puis configurez ce que vous souhaitez enregistrer avec auditctl . Chaque opération enregistrée est enregistrée dans /var/log/audit/audit.log (sur les distributions typiques). Pour commencer à regarder un fichier particulier:

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

Si vous placez une surveillance sur un répertoire, les fichiers qu'il contient et ses sous-répertoires sont également surveillés de manière récursive. Veillez à ne pas regarder le répertoire contenant les journaux d'audit. Vous pouvez limiter la journalisation à certains processus, consultez la page de manuel auditctl pour les filtres disponibles. Vous devez être root pour utiliser le système d'audit.

Je pense que vous voulez lsof (éventuellement canalisé vers un grep sur le programme et ses enfants). Il vous indiquera tous les fichiers auxquels vous accédez actuellement sur le système de fichiers. Pour plus d'informations sur les fichiers auxquels le processus accède ( d'ici ):

lsof -n -p `pidof your_app`
7
unclejamil

J'ai essayé ça tracefile. Pour moi, cela donnait beaucoup moins de correspondances que les miennes strace ... | sed ... | sort -u. J'ai même ajouté -s256 À la ligne de commande strace(1) mais cela n'a pas beaucoup aidé ...

Ensuite, j'ai essayé ça loggedfs. Tout d'abord, il a échoué car je n'avais pas accès en lecture/écriture au répertoire que j'ai essayé de me connecter avec. Après avoir fait chmod 755 temporairement, j'ai eu quelques hits ...

Mais, pour moi, ce qui semble fonctionner le mieux:

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

Et puis post-traiter la sortie après avoir exécuté le processus d'intérêt.

Cela n'attrape pas l'outice d'accès au processus de fichiers du répertoire tracé ni cela ne sait pas si un autre processus a accédé à la même arborescence de répertoires, mais dans de nombreux cas, c'est un outil assez bon pour obtenir le travail terminé.

EDIT: inotifywait n'attrape pas l'accès aux liens symboliques (juste les cibles après la résolution des liens symboliques). J'ai été frappé par cela lorsque j'ai archivé des bibliothèques accessibles par un programme pour une utilisation future. Utilisé quelques hackery Perl glob supplémentaires pour choisir les liens symboliques le long des bibliothèques notifiées pour faire le travail dans ce cas particulier.

EDIT2: au moins lors de l'inotification des fichiers et des liens symboliques eux-mêmes à partir de la ligne de commande inotifywait (par exemple, inotifywait -m file symlink Ou inotifywait symlink file), La sortie montrera l'accès à celui qui est le premier en ligne de commande (quel que soit, file de symlink est accessible). inotifywait ne prend pas en charge IN_DONT_FOLLOW - ce qui, lorsque j'ai essayé par programme, donne simplement accès à file (ce qui peut ou non être ce à quoi on s'attend ...) indépendamment de l'ordre dans la ligne de commande

2
Tomi Ollila

Bien que cela ne vous donne peut-être pas assez de contrôle (encore?), J'ai écrit un programme, qui répond au moins partiellement à vos besoins, en utilisant le fanotify et le unshare du noyau Linux pour surveiller uniquement les fichiers modifiés (ou lus) par un processus spécifique et ses enfants . Comparé à strace, il est assez rapide (;

Il peut être trouvé sur https://github.com/tycho-kirchner/shournal

Exemple sur le 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    
1
spawn