web-dev-qa-db-fra.com

Quels sont ces descripteurs de fichiers auxiliaires?

En fouillant dans le dossier /proc/self pour mon shell mksh, j'ai trouvé une chose particulière: dans /proc/self/fd/*, il existe tous les descripteurs de fichiers standard (0 pour stdin, 1 pour stdout et 2 stderr) des descripteurs de fichiers, mais aussi des descripteurs supplémentaires - 24, 25, 3. Et techniquement, je peux les lister avec un glob dans le shell:

$ for fd in /proc/self/fd/* ; do echo $fd ; done                                                      
/proc/self/fd/0
/proc/self/fd/1
/proc/self/fd/2
/proc/self/fd/24
/proc/self/fd/25
/proc/self/fd/3

Mais lorsque j'essaie de stat ou d'utiliser find sur eux, ils sont signalés comme inexistants.

$ find  /proc/self/fd/*                                                                               
/proc/self/fd/0
/proc/self/fd/1
/proc/self/fd/2
find: ‘/proc/self/fd/24’: No such file or directory
find: ‘/proc/self/fd/25’: No such file or directory
/proc/self/fd/3

La même chose se produit dans bash, mais avec un seul descripteur de fichier auxiliaire.

$ for fd in /proc/self/fd/* ; do echo $fd; done
/proc/self/fd/0
/proc/self/fd/1
/proc/self/fd/2
/proc/self/fd/255
/proc/self/fd/3

$ find /proc/self/fd/*
/proc/self/fd/0
/proc/self/fd/1
/proc/self/fd/2
find: ‘/proc/self/fd/255’: No such file or directory
/proc/self/fd/3

La question est: quels sont ces descripteurs de fichier supplémentaires? Quel est leur but?

7

Le sondage /proc/self est une affaire délicate, car il change pour chaque processus. Lorsque vous faites /proc/self/fd/*, le shell développe le caractère générique et répertorie donc ses propres descripteurs de fichier. Mais lorsque ceux-ci sont passés à une autre commande, comme find ou ls, les chemins seront maintenant pour ce processus '/proc/self, et il pourra avoir ou non des fds avec ces nombres.

Encore plus délicat, le shell peut ouvrir des descripteurs de fichier pendant l’extension du caractère générique.

La comparaison avec /proc/$$/fd pourrait être éclairante:

bash:

$ ls -l /proc/self/fd /proc/$$/fd/* &
[1] 5172
$ lrwx------ 1 muru muru 64 Jan  1 20:16 /proc/4932/fd/0 -> /dev/pts/1
lrwx------ 1 muru muru 64 Jan  1 20:16 /proc/4932/fd/1 -> /dev/pts/1
lrwx------ 1 muru muru 64 Jan  1 20:16 /proc/4932/fd/2 -> /dev/pts/1
lrwx------ 1 muru muru 64 Jan  1 20:16 /proc/4932/fd/255 -> /dev/pts/1

/proc/self/fd:
total 0
lrwx------ 1 muru muru 64 Jan  1 20:24 0 -> /dev/pts/1
lrwx------ 1 muru muru 64 Jan  1 20:24 1 -> /dev/pts/1
lrwx------ 1 muru muru 64 Jan  1 20:24 2 -> /dev/pts/1
lr-x------ 1 muru muru 64 Jan  1 20:24 3 -> /proc/5172/fd

[1]+  Done                    ls --color=auto -l /proc/self/fd /proc/$$/fd/*

En l’envoyant à l’arrière-plan, j’ai dû imprimer le PID, et vous pouvez voir que /proc/self/fd/3 pointe sur ls 'own /proc/<PID>/fd, qu’il avait ouvert pour numériser. Les entrées avec 4932, OTOH sont pour le fds de bash et la spéciale est 255. Une explication se trouve dans this SO post :

Les fichiers ouverts sont 0 (stdin), 1 (stdout) et 2 (stderr). 255 est un petit truc que bash utilise pour conserver une copie de ces informations lorsqu’elles sont redirigées. Ceci est spécifique à bash.

Source: https://books.google.com/books?id=wWjqCF9HLfYC&pg=PA231

Avec mksh:

$ ls -l /proc/self/fd /proc/$$/fd/*   &
[1] 5075
$ lrwx------ 1 muru muru 64 Jan  1 20:22 /proc/5074/fd/0 -> /dev/pts/1
lrwx------ 1 muru muru 64 Jan  1 20:22 /proc/5074/fd/1 -> /dev/pts/1
lrwx------ 1 muru muru 64 Jan  1 20:22 /proc/5074/fd/10 -> /dev/tty
lrwx------ 1 muru muru 64 Jan  1 20:22 /proc/5074/fd/2 -> /dev/pts/1

/proc/self/fd:
total 0
lrwx------ 1 muru muru 64 Jan  1 20:22 0 -> /dev/pts/1
lrwx------ 1 muru muru 64 Jan  1 20:22 1 -> /dev/pts/1
lrwx------ 1 muru muru 64 Jan  1 20:22 2 -> /dev/pts/1
lr-x------ 1 muru muru 64 Jan  1 20:22 3 -> /proc/5075/fd

[1] + Done                 ls -l /proc/self/fd /proc/$$/fd/* 

Pratiquement la même chose, sauf que le fd supplémentaire est 10, et je parie que c'est pour la même raison que bash, puisque le code source indique que le fd 10 et les suivants sont utilisés par Shell.

Je n'ai pas eu deux ou trois fds supplémentaires, mais cela peut être dû à un certain nombre de choses qui se produisent lors de l'expansion d'un caractère générique, ou à des tâches en arrière-plan ou à une autre raison obscure.

Si je lance votre boucle for, je reçois un fd 3 éphémère:

$ for fd in /proc/$$/fd/* ; do ls -l $fd ; done
lrwx------ 1 muru muru 64 Jan  2 17:39 /proc/6012/fd/0 -> /dev/pts/1
lrwx------ 1 muru muru 64 Jan  2 17:39 /proc/6012/fd/1 -> /dev/pts/1
lrwx------ 1 muru muru 64 Jan  2 17:39 /proc/6012/fd/2 -> /dev/pts/1
lrwx------ 1 muru muru 64 Jan  2 17:39 /proc/6012/fd/255 -> /dev/pts/1
ls: cannot access '/proc/6012/fd/3': No such file or directory

Et ici, en utilisant strace pour suivre l'exécution:

strace -e open -o log bash -c 'for fd in /proc/$$/fd/* ; do : ; done'

Nous verrons que le troisième fd est en fait /proc/<PID>/fd:

$ tail log
open("/usr/lib/libreadline.so.7", O_RDONLY|O_CLOEXEC) = 3
open("/usr/lib/libdl.so.2", O_RDONLY|O_CLOEXEC) = 3
open("/usr/lib/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
open("/usr/lib/libncursesw.so.6", O_RDONLY|O_CLOEXEC) = 3
open("/dev/tty", O_RDWR|O_NONBLOCK)     = 3
open("/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = 3
open("/usr/lib/gconv/gconv-modules.cache", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/lib/gconv/gconv-modules", O_RDONLY|O_CLOEXEC) = 3
open("/proc/9975/fd/", O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC) = 3
+++ exited with 0 +++

Maintenant, la question est: pourquoi ce fd n’a-t-il pas été affiché dans les tests ls précédents? Il semblerait que les antécédents aient quelque chose à voir avec cela:

$ ls -l /proc/$$/fd/*   &
[1] 10091
$ lrwx------ 1 muru muru 64 Jan  2 17:46 /proc/10076/fd/0 -> /dev/pts/1
lrwx------ 1 muru muru 64 Jan  2 17:46 /proc/10076/fd/1 -> /dev/pts/1
lrwx------ 1 muru muru 64 Jan  2 17:46 /proc/10076/fd/2 -> /dev/pts/1
lrwx------ 1 muru muru 64 Jan  2 17:46 /proc/10076/fd/255 -> /dev/pts/1

[1]+  Done                    ls --color=auto -l /proc/self/fd /proc/$$/fd/*
$ ls -l /proc/$$/fd/* 
ls: cannot access '/proc/10076/fd/3': No such file or directory
lrwx------ 1 muru muru 64 Jan  2 17:46 /proc/10076/fd/0 -> /dev/pts/1
lrwx------ 1 muru muru 64 Jan  2 17:46 /proc/10076/fd/1 -> /dev/pts/1
lrwx------ 1 muru muru 64 Jan  2 17:46 /proc/10076/fd/2 -> /dev/pts/1
lrwx------ 1 muru muru 64 Jan  2 17:46 /proc/10076/fd/255 -> /dev/pts/1

Le premier plan ls montre le fd manquant.

Maintenant, tracez à nouveau avec strace:

strace -fe open,execve,fork -o log bash -ic 'ls -l /proc/self/fd /proc/$$/fd/* &'

Nous voyons:

10731 execve("/usr/bin/bash", ["bash", "-ic", "ls -l /proc/$$/fd/* &"], [/* 67 vars */]) = 0
10731 open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
# snip
10734 open("/proc/10731/fd/", O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC) = 3
10734 execve("/usr/bin/ls", ["ls", "--color=auto", "-l", "/proc/10731/fd/0", "/proc/10731/fd/1", "/proc/10731/fd/2", "/proc/10731/fd/255"], [/* 68 vars */]) = 0

Notez le changement de PID. Il semble que l’extension avec caractère générique se produise après le forgeage, mais l’extension variable se produit avant . Ainsi, le résultat 3 existe, mais dans un processus différent. Maintenant, si vous utilisez self au lieu de $$, vous verrez les 3 et 255:

$ strace -fe open,execve -o log bash -ic 'ls -l /proc/self/fd/* &'
[1] 10790
ls: cannot access '/proc/self/fd/255': No such file or directory
ls: cannot access '/proc/self/fd/3': No such file or directory
lrwx------ 1 muru muru 64 Jan  2 18:04 /proc/self/fd/0 -> /dev/pts/1
lrwx------ 1 muru muru 64 Jan  2 18:04 /proc/self/fd/1 -> /dev/pts/1
lrwx------ 1 muru muru 64 Jan  2 18:04 /proc/self/fd/2 -> /dev/pts/1

Addenda

A réponse associée sous Unix et Linux Le site Stackexchange cite une réponse d'un liste de diffusion :

Fd 255 est utilisé en interne en tant que connexion au terminal, de sorte qu'il n'interfère pas avec l'utilisation de exec pour relocaliser fds. Bash alloue également des fds élevés lors du traitement d'une substitution de processus `<(foo) ', pour la même raison.

Andreas Schwab

14
muru