[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Re: [HS Debian] rm : liste d'arguments trop longue



On Fri, Mar 23, 2007 at 11:24:32PM +0100, François TOURDE wrote:
> > 1- quelle est le nombre maximal ? comment le trouver ?
> 
> Je ne sais pas le max, mais ça doit être marqué dans bash, non? :)

Attention, la curiosité est un défaut dangereux qui peut
vous emmener à des endroits que vous n'imaginiez pas.

Or donc, je me dis que j'allais trouver la limite dans le
code de bash.

Manque de bol, bash gère les paramètres comme des listes
chainées. Lorsqu'il y a expansion (de variables, de 'globs'
comme * en listes de fichiers, etc) il crée de nouveaux
éléments dans la liste. Toute la liste est ensuite passée à
execve sous forme d'un tableau de chaînes (argc, argv)[1]. À
aucun moment bash ne travaille sur la chaîne d'entrée
complète.

Conclusion 1: Bash n'a aucune limite de taille de ligne de
commande.

Bon, faut regarder execve alors. 

Dans glibc, on se rend compte que la libc fait quelques
vérifications sur les paramètres, mais globalement ne fait
que passer le argc et argv au noyau[2].

Bon, faut regarder dans le noyau alors.

Bingo: execve dans le noyau[3] additionne le nombre
d'arguments et vérifie qu'il soit inférieur à
(PAGE_SIZE*MAX_ARGPAGES-4)/4, soit 32767, puis il additionne
la taille de tous les arguments et de l'environnement et
vérifie qu'il soit inférieur à (PAGE_SIZE*MAX_ARGPAGES-4),
soit 131068.

Conclusion 2: La limitation est le fait de Linux, le
comportement de Bash devrait donc être différent sur Cygwin
ou BSD.

Conclusion 3: Linux limite le nombre d'arguments à 32767 et
la longueur totale des arguments plus de l'environnement à
131068 octets.

Vérification expérimentale:

yves@thelonious:~/try$ env | wc
     24      24    1046

Taille maximum de ligne de commande:
yves@thelonious:~/try$ for i in `seq 1 13002`; do touch `printf "%09d" $i`; done
yves@thelonious:~/try$ ls | wc
  13002   13002  130020
yves@thelonious:~/try$ rm *
bash: /bin/rm: Argument list too long

Environnement + Ligne = 1046 + 130020 = 131066

yves@thelonious:~/try$ for i in `seq 1 13000`; do touch `printf "%09d" $i`; done
yves@thelonious:~/try$ ls | wc
  13000   13000  130000
yves@thelonious:~/try$ rm *
yves@thelonious:~/try$ 

Environnement + Ligne = 1046 + 130000 = 131046

(apparement je me suis trompé dans une limite, c'est un peu
moins que 131068)

Nombre d'arguments:
yves@thelonious:~/try2$ ( for i in `seq 1 32766`; do echo -n "a "; done ) > toto
yves@thelonious:~/try2$ touch `cat toto`
yves@thelonious:~/try2$ ( for i in `seq 1 32767`; do echo -n "a "; done ) > toto
yves@thelonious:~/try2$ touch `cat toto`
bash: /usr/bin/touch: Argument list too long


Voilà voilà.

Y. --  Oh, bah, on s'est bien amusés.

[1] bash:execute_cmd.c:shell_execve()
[2] glibc:sysdeps/unix/sysv/linux/execve.c
[3] linux-2.6.14:fs/exec.c:do_execve() et copy_strings()



Reply to: