Lister les fichiers accédés par un programme

64

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

Je cherche quelque chose de similaire qui peut lister les fichiers accessibles par un programme et ses enfants. En temps réel ou 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 cela é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 avaient des problèmes d'autorisation ou les regrouper dans des fichiers lus et des fichiers écrits). Aussi, stracec'est lent, donc ce serait bien avec un choix plus rapide.

Ole Tange
la source
Compte tenu de votre utilisation de strace, je suppose que vous êtes particulièrement intéressé par Linux. Correct?
Gilles 'SO- arrête d'être méchant'
Linux est ma principale préoccupation.
Ole Tange

Réponses:

51

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

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 sort que les fichiers, vous n'avez donc pas besoin de traiter le résultat strace.

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

Ole Tange
la source
Merci! La sortie de strace est absolument illisible. Cependant, je ne sais pas où trouver la documentation. Ce serait bien si l'option -h / - help était disponible. J'apprécierais également une option qui montre uniquement les modifications de fichiers, pas les accès.
Xerus
@Xerus Clone gitlab.com/ole.tange/tangetools et exécutez make && sudo make install. Ensuite, vous pouvez courir man tracefile.
Ole Tange
4
Bel outil. Il a emballé, pour installer: yum -y install https://extras.getpagespeed.com/release-el7-latest.rpmetyum -y install tracefile
Danila Vershinin
27

Vous pouvez suivre les appels système avec strace, mais il existe en effet une pénalité de vitesse inévitable. Vous devez exécuter en stracetant 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 qui est susceptible d'être plus rapide est de pré - charger une bibliothèque qui enroule autour des fonctions d'accès du système de fichiers: LD_PRELOAD=/path/to/libmywrapper.so mycommand. La LD_PRELOADvariable 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 de wrapper ( voici un exemple tiré de «Construire des interposeurs de bibliothèque pour le plaisir et le profit» ); Je ne sais pas s'il existe du code réutilisable sur le Web.

Si vous surveillez les fichiers dans une hiérarchie de répertoires particulière, vous pouvez créer une vue du système de fichiers avec LoggedFS de manière à ce que tous les accès via cette vue soient consignés.

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

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

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

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

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

Gilles, arrête de faire le mal
la source
LD_PRELOADégalement ne fonctionnera pas sur les binaires statiques.
David étant donné
6

Je pense que vous voulez lsof (peut-être lié à un grep sur le programme et ses enfants). Il vous indiquera tous les fichiers en cours d'accès sur le système de fichiers. Pour plus d'informations sur les fichiers accédés par processus (à partir d'ici ):

lsof -n -p `pidof your_app`
onclejamil
la source
11
Mais cela ne me donne qu'un instantané. Ce dont j'ai besoin, c'est de quels fichiers il a essayé d'accéder. Pensez à la situation dans laquelle un programme refuse de démarrer car il est écrit "Fichier manquant". Comment savoir quel fichier il cherchait?
Ole Tange
2

J'ai essayé ça tracefile. Pour moi, ça a donné beaucoup moins de matches que le mien strace ... | sed ... | sort -u. J'ai même ajouté -s256à la strace(1)ligne de commande mais cela ne m'a pas beaucoup aidé ...

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

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

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

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

Cela n'intercepte pas l'accès externe aux processus de fichiers du répertoire suivi ni le fait qu'un autre processus ait accédé à la même arborescence de répertoires, mais dans de nombreux cas, cet outil est suffisamment bon pour que le travail soit effectué.

EDIT: inotifywait n'intercepte pas l'accès aux liens symboliques (uniquement les cibles après la résolution des liens symboliques). J'ai été frappé par cela lorsque j'ai archivé des bibliothèques auxquelles un programme a accédé pour une utilisation future. A utilisé un peu plus de perl glob hackery pour choisir les liens symboliques le long des bibliothèques notifiées afin d’effectuer le travail dans ce cas particulier

EDIT2: au moins quand inotifying fichiers et liens symboliques eux - mêmes de la ligne de commande inotifywait (par exemple , inotifywait -m file symlinkou inotifywait symlink file) sortie montrera l' accès auquel on est en première ligne de commande (quel que soit ce qui, filed' symlinkest accessible). inotifywait ne supporte pas IN_DONT_FOLLOW - auquel, lorsque j'ai essayé par programmation, on ne fait que voir l'accès file(ce qui peut être ou ne pas être ce que l'on attend ...) quel que soit l'ordre dans la ligne de commande

Tomi Ollila
la source
"Pour moi, cela a donné beaucoup moins de correspondances que le mien" Pouvez-vous partager un exemple de tracefilemanque d'accès à un fichier?
Ole Tange
Je ne suis pas sûr de ce que vous demandez exactement:) ... Si j'essaie de regarder les fichiers dans / path / to / traced / directory / je vois OPEN dans la sortie inotify ... MAIS stat (1) semble-t-il aucun résultat dans les quelques cas que j'ai essayés (je me demande pourquoi, cache-t-il un peu de contenu de lecture de répertoire caché)
Tomi Ollila
Je commente le post fanotify ci-dessous (je n'ai que 21 points de réputation, même si je compte depuis plus d'une décennie; en avoir besoin de 50 pour commenter a toujours été un obstacle pour moi ...) - fanotifier est une bonne chose, mais ne le peut pas contourner le problème de déréférence des liens symboliques (c’est-à-dire que dans le cas de liens symboliques, le fichier final auquel on accède se trouve en lisant / proc / self / fd / <fd> .. de toute façon +1: la réponse: D
Tomi Ollila
1

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 les fonctions fanotify et unshare du noyau-kernel pour surveiller uniquement les fichiers modifiés (ou lus) par un processus spécifique et ses enfants. . Comparé à strace, il est assez rapide (;

Vous pouvez le trouver sur https://github.com/tycho-kirchner/shournal

Exemple sur la coque:

$ 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    
frayer
la source