GNU/Linux >> Tutoriels Linux >  >> Linux

Qu'est-ce qui définit la taille maximale d'un seul argument de commande ?

J'avais l'impression que la longueur maximale d'un seul argument n'était pas le problème ici autant que la taille totale du tableau d'arguments global plus la taille de l'environnement, qui est limitée à ARG_MAX . Ainsi, j'ai pensé que quelque chose comme ce qui suit réussirait :

env_size=$(cat /proc/$$/environ | wc -c)
(( arg_size = $(getconf ARG_MAX) - $env_size - 100 ))
/bin/echo $(tr -dc [:alnum:] </dev/urandom | head -c $arg_size) >/dev/null

Avec le - 100 étant plus que suffisant pour tenir compte de la différence entre la taille de l'environnement dans le shell et le echo processus. Au lieu de cela, j'ai eu l'erreur :

bash: /bin/echo: Argument list too long

Après avoir joué un moment, j'ai trouvé que le maximum était d'un ordre de grandeur plus petit :

/bin/echo 
  $(tr -dc [:alnum:] </dev/urandom | head -c $(($(getconf ARG_MAX)/16-1))) 
  >/dev/null

Lorsque le moins un est supprimé, l'erreur revient. Apparemment, le maximum pour un seul argument est en fait ARG_MAX/16 et le -1 tient compte de l'octet nul placé à la fin de la chaîne dans le tableau d'arguments.

Un autre problème est que lorsque l'argument est répété, la taille totale du tableau d'arguments peut être plus proche de ARG_MAX , mais toujours pas tout à fait là :

args=( $(tr -dc [:alnum:] </dev/urandom | head -c $(($(getconf ARG_MAX)/16-1))) )
for x in {1..14}; do
  args+=( ${args[0]} )
done

/bin/echo "${args[@]}" "${args[0]:6534}" >/dev/null

Utilisation de "${args[0]:6533}" ici rend le dernier argument plus long d'un octet et donne la Argument list too long Erreur. Il est peu probable que cette différence s'explique par la taille de l'environnement donné :

$ cat /proc/$$/environ | wc -c
1045

Questions :

  1. Ce comportement est-il correct ou y a-t-il un bogue quelque part ?
  2. Si non, ce comportement est-il documenté quelque part ? Existe-t-il un autre paramètre qui définit le maximum pour un seul argument ?
  3. Ce comportement est-il limité à Linux (ou même à des versions particulières de Linux) ?
  4. Ce qui explique l'écart supplémentaire d'environ 5 Ko entre la taille maximale réelle du tableau d'arguments plus la taille approximative de l'environnement et ARG_MAX ?

Informations supplémentaires :

uname -a
Linux graeme-rock 3.13-1-amd64 #1 SMP Debian 3.13.5-1 (2014-03-04) x86_64 GNU/Linux

Réponse acceptée :

Réponses

  1. Certainement pas un bug.
  2. Le paramètre qui définit la taille maximale pour un argument est MAX_ARG_STRLEN . Il n'y a pas de documentation pour ce paramètre autre que les commentaires dans binfmts.h :

    /*
     * These are the maximum length and maximum number of strings passed to the
     * execve() system call.  MAX_ARG_STRLEN is essentially random but serves to
     * prevent the kernel from being unduly impacted by misaddressed pointers.
     * MAX_ARG_STRINGS is chosen to fit in a signed 32-bit integer.
     */
    #define MAX_ARG_STRLEN (PAGE_SIZE * 32)
    #define MAX_ARG_STRINGS 0x7FFFFFFF
    

    Comme indiqué, Linux a également une (très grande) limite sur le nombre d'arguments d'une commande.

  3. Une limite sur la taille d'un seul argument (qui diffère de la limite globale sur les arguments plus l'environnement) semble être spécifique à Linux. Cet article donne une comparaison détaillée de ARG_MAX et équivalents sur les systèmes de type Unix. MAX_ARG_STRLEN est discuté pour Linux, mais il n'y a aucune mention d'équivalent sur d'autres systèmes.

    L'article ci-dessus indique également que MAX_ARG_STRLEN a été introduit dans Linux 2.6.23, ainsi qu'un certain nombre d'autres changements relatifs aux maximums d'arguments de commande (discutés ci-dessous). Le log/diff pour le commit peut être trouvé ici.

  4. On ne sait toujours pas ce qui explique l'écart supplémentaire entre le résultat de getconf ARG_MAX et la taille maximale réelle possible des arguments plus l'environnement. La réponse connexe de Stéphane Chazelas suggère qu'une partie de l'espace est représentée par des pointeurs vers chacune des chaînes d'argument/environnement. Cependant, ma propre enquête suggère que ces pointeurs ne sont pas créés au début de l'execve appel système alors qu'il peut toujours renvoyer un E2BIG erreur au processus appelant (bien que des pointeurs vers chaque argv chaîne sont certainement créées plus tard).

    De plus, les chaînes sont contiguës en mémoire pour autant que je puisse voir, donc aucun trou de mémoire n'est dû à l'alignement ici. Bien que ce soit très probablement un facteur dans tout ce que fait utiliser la mémoire supplémentaire. Comprendre ce qui utilise l'espace supplémentaire nécessite une connaissance plus détaillée de la façon dont le noyau alloue la mémoire (ce qui est une connaissance utile à avoir, donc je vais enquêter et mettre à jour plus tard).

En relation :Quelle est la différence entre un point-virgule et une double esperluette && ?

ARG_MAX Confusion

Depuis Linux 2.6.23 (à la suite de cette validation), des modifications ont été apportées à la manière dont les maximums d'arguments de commande sont gérés, ce qui différencie Linux des autres systèmes de type Unix. En plus d'ajouter MAX_ARG_STRLEN et MAX_ARG_STRINGS , le résultat de getconf ARG_MAX dépend maintenant de la taille de la pile et peut être différent de ARG_MAX dans limits.h .

Normalement le résultat de getconf ARG_MAX sera 1/4 de la taille de la pile. Considérez ce qui suit dans bash en utilisant ulimit pour obtenir la taille de la pile :

$ echo $(( $(ulimit -s)*1024 / 4 ))  # ulimit output in KiB
2097152
$ getconf ARG_MAX
2097152

Cependant, le comportement ci-dessus a été légèrement modifié par ce commit (ajouté dans Linux 2.6.25-rc4~121). ARG_MAX dans limits.h sert maintenant de limite inférieure dure sur le résultat de getconf ARG_MAX . Si la taille de la pile est définie de telle sorte que 1/4 de la taille de la pile est inférieure à ARG_MAX dans limits.h , puis le limits.h valeur sera utilisée :

$ grep ARG_MAX /usr/include/linux/limits.h 
#define ARG_MAX       131072    /* # bytes of args + environ for exec() */
$ ulimit -s 256
$ echo $(( $(ulimit -s)*1024 / 4 ))
65536
$ getconf ARG_MAX
131072

Notez également que si la taille de la pile est inférieure au minimum possible ARG_MAX , puis la taille de la pile (RLIMIT_STACK ) devient la limite supérieure de la taille de l'argument/de l'environnement avant E2BIG est renvoyé (bien que getconf ARG_MAX affichera toujours la valeur dans limits.h ).

Une dernière chose à noter est que si le noyau est construit sans CONFIG_MMU (prise en charge du matériel de gestion de la mémoire), puis la vérification de ARG_MAX est désactivé, la limite ne s'applique donc pas. Bien que MAX_ARG_STRLEN et MAX_ARG_STRINGS s'applique toujours.

Autres lectures

  • Réponse connexe de Stéphane Chazelas - https://unix.stackexchange.com/a/110301/48083
  • Dans une page détaillée couvrant la plupart des éléments ci-dessus. Inclut un tableau de ARG_MAX (et équivalents) sur d'autres systèmes de type Unix - http://www.in-ulm.de/~mascheck/various/argmax/
  • Apparemment l'introduction de MAX_ARG_STRLEN a causé un bogue avec Automake qui intégrait des scripts shell dans les Makefiles en utilisant sh -c – http://www.mail-archive.com/[email protected]/msg05522.html

Linux
  1. Quelle est l'unité de taille par défaut dans la commande Linux ls -l

  2. À quoi sert Linux test -a command test ?

  3. Quel est le but de cd ` (backtick) ?

  4. Qu'est-ce qui constitue un 'champ' pour la commande cut ?

  5. A quoi sert la commande hostnamectl ?

Qu'est-ce que la commande Linux Watch + Exemples

Qu'est-ce que la commande kill sous Linux ?

quelle est la commande la plus fiable pour trouver la taille réelle d'un fichier linux

Quel est l'équivalent de la commande Linux File pour Windows ?

Changé le PATH, maintenant je reçois une commande introuvable pour tout

A quoi sert l'option -o dans la commande useradd ?