savoir quels descripteurs de fichiers partagent la même «description de fichier ouvert»


17

Si je le fais (dans un shell de type Bourne):

exec 3> file 4>&3 5> file 6>> file

Les descripteurs de fichiers 3 et 4, puisque 4 a été dup()édité à partir de 3, partagent la même description de fichier ouvert (mêmes propriétés, même décalage dans le fichier ...). Alors que les descripteurs de fichiers 5 et 6 de ce processus se trouvent sur une description de fichier ouverte différente (par exemple, ils ont chacun leur propre pointeur dans le fichier).

Maintenant, en lsofsortie, tout ce que nous voyons est:

zsh     21519 stephane    3w   REG  254,2        0 10505865 /home/stephane/file
zsh     21519 stephane    4w   REG  254,2        0 10505865 /home/stephane/file
zsh     21519 stephane    5w   REG  254,2        0 10505865 /home/stephane/file
zsh     21519 stephane    6w   REG  254,2        0 10505865 /home/stephane/file

C'est un peu mieux avec lsof +fg:

zsh     21519 stephane    3w   REG          W,LG  254,2        0 10505865 /home/stephane/file
zsh     21519 stephane    4w   REG          W,LG  254,2        0 10505865 /home/stephane/file
zsh     21519 stephane    5w   REG          W,LG  254,2        0 10505865 /home/stephane/file
zsh     21519 stephane    6w   REG       W,AP,LG  254,2        0 10505865 /home/stephane/file

(ici sur Linux 3.16) en ce que nous voyons que fd 6 a des drapeaux différents, donc il doit s'agir d'une description de fichier ouvert différente de celle de fd 3, 4 ou 5, mais à partir de cela, nous ne pouvons pas dire que fd 5 est sur un description de fichier ouvert différente . Avec -o, nous pourrions également voir le décalage, mais là encore, le même décalage ne garantit pas qu'il s'agit de la même description de fichier ouvert .

Y at - il non intrusif 1 moyen de savoir? En externe ou pour les descripteurs de fichiers d'un processus?


1 . Une approche heuristique pourrait être de changer les indicateurs d'un fd avec fcntl()et de voir avec quels autres descripteurs de fichier leurs indicateurs sont mis à jour en conséquence, mais ce n'est évidemment pas idéal ni infaillible


Cette approche devrait fonctionner, en principe, et ne pas être trop perturbatrice dans la plupart des scénarios: commencez par bifurquer un enfant (avec ptrace si vous le faites de l'extérieur). Ensuite, chez l'enfant, faites quelque chose avec le descripteur de fichier qui n'affecte pas les autres processus. Sous Linux, les baux devraient fonctionner pour cela.
Gilles 'SO- arrête d'être méchant'

@ Gilles, merci mais c'est plus ou moins l'approche que je suggère déjà dans la question. les baux (en supposant que vous voulez dire le F_SETLEASE fcntl, merci de m'avoir informé d'eux BTW) ne fonctionneront que pour les fichiers normaux que vous possédez et pas s'il y a une autre description de fichier ouvert "écriture" dans le même fichier (EBUSY), et ce n'est pas exactement non -intrusif.
Stéphane Chazelas

Avez-vous abandonné cette question? J'ai posté des informations sur la façon dont SystemTap pourrait faire ce que vous voulez, mais vous n'avez marqué aucune réponse comme complète ...?
Azhrei

Réponses:


2

Pour Linux 3.5 et versions ultérieures, cela peut être accompli avec kcmp (3) :

KCMP_FILE

  • Vérifiez si un descripteur de fichier idx1 dans le processus pid1 fait référence à la même description de fichier ouvert (voir open (2) ) que le descripteur de fichier idx2 dans le processus pid2 . L'existence de deux descripteurs de fichier faisant référence à la même description de fichier ouvert peut se produire à la suite de dup (2) (et similaire) fork (2) , ou en passant des descripteurs de fichier via un socket de domaine (voir unix (7) ).

La page de manuel fournit un exemple spécifique au cas d'utilisation OP demandé. Notez que cet appel système nécessite que le noyau soit compilé avec CONFIG_CHECKPOINT_RESTOREset.


Merci. Exactement ce que je cherchais. Notez qu'à moins que vous ne soyez superutilisateur, il doit s'agir de deux processus (et non setuid / setgid ...) (c'est compréhensible)
Stéphane Chazelas

@ StéphaneChazelas Exactement. Si pour une raison quelconque, le support CPIU n'a pas été intégré à votre noyau et que vous ne voulez pas le reconstruire, alors je suppose que vous pouvez toujours écrire un module du noyau qui exporte une interface utilisateur qui vous permet de comparer des struct file *pointeurs.
minmaxavg

3

Ce que vous cherchez à comparer, ce sont les struct filepointeurs vers lesquels pointent les descripteurs de fichiers. (À l'intérieur du noyau se trouve une task_structstructure de données pour chaque thread. Elle contient un pointeur vers une autre structure appelée files_struct. Et cette structure contient un tableau de pointeurs, chacun vers un struct file. C'est le struct filequi contient le décalage de recherche, les drapeaux ouverts et un quelques autres domaines.)

Je ne connais aucun moyen visible par l'utilisateur de voir les pointeurs dans l' files_structautre que l'utilisation de certains outils intrusifs. Par exemple, SystemTap pourrait recevoir un PID et il pourrait trouver le correspondant task_structet suivre les pointeurs. Si vous êtes à la recherche de passif, je pense que c'est à peu près tout. Dell a publié il y a longtemps un outil appelé KME (Kernel Memory Editor) qui offrait une interface semblable à une feuille de calcul pour la mémoire du noyau en direct et il pouvait faire ce que vous vouliez, mais il n'a jamais été porté sur 64 bits. (J'ai essayé et je n'ai jamais réussi à le faire fonctionner complètement, et je ne savais pas pourquoi.)

L'une des raisons pour lesquelles vous ne trouvez lsofpas utile est qu'il ne voit pas non plus ces pointeurs (mais regardez l' +foption pour les systèmes non Linux). Vous pourriez théoriquement comparer tous les champs du struct fileet penser que les deux structures sont les mêmes, mais elles pourraient toujours provenir d' open(2)appels distincts .

Jetez un oeil au script pfiles SystemTap pour des idées. Si vous le modifiiez pour imprimer l'adresse du struct file, vous auriez votre solution. Vous pouvez également vérifier le fichier open_file_by_pid.stp car il contient une fonction qui parcourt le files_struct, c.-à-d. la table des descripteurs de fichiers, en regardant les struct fileobjets ...

Puis-je vous demander ce que vous essayez d'accomplir?


Je dois admettre que je ne me souviens pas du cas où j'en avais besoin. Certains débogage ou tâche médico-légale sans aucun doute.
Stéphane Chazelas

J'attends avec impatience le code PoT systemtap :-)
Stéphane Chazelas

Avant de poster la question, j'ai jeté un œil aux approches systemtap ou / proc / kcore. La partie difficile était d'obtenir les informations pour chaque fd de chaque tâche . L'approche la plus prometteuse que j'ai trouvée était de se connecter aux fonctions qui génèrent le contenu du répertoire / proc / * / task / fd, mais les seules choses réalisables que j'ai pu trouver impliquaient le raccordement à des numéros de ligne spécifiques dans le fichier source, donc pas portable d'une version du noyau à l'autre. Vous ne pouvez pas vraiment parcourir la liste des tâches dans systemtap. Peut-être possible via / proc / kcore, mais trop d'efforts et probablement peu fiable.
Stéphane Chazelas

Merci pour la meilleure réponse jusqu'à présent. Je vais jeter un œil à vos pointeurs.
Stéphane Chazelas

Sûr que vous pouvez! Configurez un probe beginbloc et for_each_processfaites- le utiliser la macro dans un bloc de code C incorporé dans le script (vous devrez utiliser le mode "gourou" SystemTap pour incorporer du code C). En fait, pour rendre cela intéressant (!), Vous pouvez utiliser l'un des tableaux associatifs de SystemTap; utilisez l' files_structadresse comme clé et une liste de PID / TID comme valeurs. Vous avez maintenant une liste de tous les fichiers ouverts et des tâches qui les partagent (ils peuvent être partagés entre parent / enfant). Répondez à nouveau si vous souhaitez discuter de SystemTap.
Azhrei

0

Voici une solution spécifique à Linux: / proc / self / fd est un répertoire de liens symboliques pour les descripteurs de fichiers ouverts dans le processus en cours. Vous pouvez simplement comparer les valeurs des liens. Cela devient plus compliqué lors de l'utilisation d'un processus enfant, car l'enfant aura un / proc / self différent car il s'agit d'un lien symbolique dépendant du pid. Vous pouvez contourner ce problème en utilisant / proc / $$ / fd où $$ est le pid souhaité.


Merci. Mais ce n'est pas ce que je demande. Sous Linux, lsof utilise en effet / proc / pid / fd pour récupérer les chemins pour chaque descripteur de fichier et / proc / pid / fdinfo pour les drapeaux. Mais ce que je veux, c'est que pour deux fds vers le même fichier, qu'ils pointent vers la même description de fichier ouvert ou si les deux descripteurs de fichier ont été ouverts indépendamment.
Stéphane Chazelas

ok, après avoir trouvé des paires de descripteurs de fichiers ouverts avec le même nom de fichier, faites un test sur les deux et comparez les résultats, s'ils diffèrent, ils sont séparés. S'ils sont identiques, recherchez sur un descripteur de fichier et répétez. S'ils correspondent toujours, ils sont identiques.
hildred

Eh bien, c'est une variante plus intrusive de l'approche heuristique à laquelle je fais référence dans la question et qui ne fonctionne que pour les fichiers normaux (pas les sockets, les périphériques (comme les terminaux), les tuyaux ...).
Stéphane Chazelas
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.