Comment déboguer des variables d'environnement sous Linux

Il arrive souvent que vous arriviez sur la machine et que vous trouviez une sorte de script en cours d'exécution sous l'utilisateur système il y a une semaine. Qui l'a lancé? Où chercher ce run.php? Ou vous ajoutez une entrée à / etc / crontab, et le script se bloque là-bas avec l'erreur "commande introuvable". Pourquoi? Et que faire?

J'ai les réponses à ces questions.



Variables d'environnement


Dans presque tous les systèmes d'exploitation modernes, les processus ont des variables d'environnement. Techniquement, ils sont une collection de chaînes nommées. Si un sous-processus est démarré, il hérite automatiquement d'une copie de l'environnement du parent.

Entre autres, il y a la variable PATH, qui indique les chemins pour rechercher des fichiers exécutables, la variable HOME, qui pointe vers le répertoire personnel de l'utilisateur, les variables responsables des préférences linguistiques de l'utilisateur, et bien d'autres.

Il existe de nombreuses revues décrivant la signification de ces variables, mais il n'y a pratiquement aucun article sur la façon d'enquêter sur les problèmes. Comblez cette lacune.

Qui a commencé le processus?


Nous avons donc trouvé un script exécuté sous l'utilisateur système il y a une semaine. Qui l'a lancé? Pourquoi? Peut-être qu'ils l'ont juste oublié? 10 à 15 personnes pourraient le lancer, vous n'interviewerez pas tout le monde. Comment savoir qui c'était? Et où se trouve ce run.php?

$ ps x | grep run.php 10684 ? Ss 472:25 /local/php/bin/php run.php 

Les variables d'environnement de processus et la fonction sudo viennent à la rescousse. Il existe une telle variable PWD dans laquelle le shell stocke le répertoire de travail actuel; cette valeur, en fait, enregistre des informations sur le répertoire courant au moment où la commande est exécutée. De plus, l'utilitaire sudo laisse par défaut des informations dans la variable d'environnement de processus sur l'utilisateur à partir duquel il a été lancé.

Les variables d'environnement (et bien plus) pour tout processus en cours d'exécution peuvent être trouvées dans / proc. Voila:

 $ cat /proc/10684/environ | tr '\0' '\n' | grep SUDO_USER SUDO_USER=alexxz $ cat /proc/10684/environ | tr '\0' '\n' | grep PWD PWD=/home/etlmaster 

Ahem, je l'ai lancé moi-même. Eh bien, qui ne se produit pas? ..

En général, en utilisant une méthode aussi simple dans des situations simples, vous pouvez trouver des informations sur le processus, qui ne sont généralement pas disponibles.

Le script fonctionne à partir de la ligne de commande, mais ne fonctionne pas à partir de cron


L'un des cas où vous devez penser aux variables d'environnement est lorsqu'un script ajouté à / etc / crontab se bloque avec une erreur. Vous allez sur le serveur via SSH, exécutez la commande, tout semble fonctionner comme il se doit. Et quand il démarre automatiquement, il affiche quelque chose comme «hive: commande introuvable».

En général, il est recommandé d'écrire le chemin d'accès complet aux commandes exécutables, mais ce n'est pas toujours possible. Dans de tels cas, les développeurs s'en sortent comme n'importe qui peut. Quelqu'un ajoute le chemin souhaité dans PATH en tant que membre de l'équipe de crontab. Les plus expérimentés encapsulent leur commande dans bash -l. Et les bombes à corbeau enseignées par une expérience amère n’oublient toujours pas de se rassembler. Tout est ainsi: fait, ajouté à la surveillance et oublié.

Après de telles manipulations, un sédiment reste dans l'âme d'un véritable ingénieur. Oui, le problème est résolu. Mais je ne comprenais pas ce qui se passait! Comment une approche est-elle meilleure qu'une autre? Où sont stockés tous ces paramètres et par qui sont-ils modifiés?

Comparons les variables d'environnement d'un processus lorsqu'il est lancé à partir de la couronne et les variables d'environnement que nous avons sur la ligne de commande. Nous enregistrons la sortie de la commande env depuis la couronne et notre environnement actuel:

 $ echo "* * * * * env > ~/crontab.env" | crontab; sleep 60; echo "" | crontab; $ env > my.env 

Regardez ce qu'il y a dans la variable PATH:

 > grep ^PATH= crontab.env my.env Crontab.env: PATH=/usr/bin:/bin My.env: PATH=/local/hive/bin:/local/python/bin:/local/hadoop/bin:/local/hadoop/bin:/local/hive/bin:/local/hadoop/bin:/usr/local/bin:/usr/bin:/bin 



Mama Mia! Il n'y a donc sous la couronne que le minimum! Bien sûr, vous devez charger les variables d'environnement normales.

Voyons ce que sera l'environnement si nous ajoutons bash -l:

 $ echo "* * * * * bash -l env > ~/crontab.env" | crontab; sleep 60; echo "" | crontab; alexxz@bi1.mlan:~> grep ^PATH= crontab.env my.env Crontab.env: PATH=/local/hive/bin:/local/python/bin:/local/hadoop/bin:/local/hadoop/bin:/local/hadoop/bin:/local/hive/bin:/usr/local/bin:/usr/bin:/bin My.env: PATH=/local/hive/bin:/local/python/bin:/local/hadoop/bin:/local/hadoop/bin:/local/hive/bin:/local/hadoop/bin:/usr/local/bin:/usr/bin:/bin 

La différence n'est pas si perceptible. Tous les chemins sont présentés. Certains dans un ordre différent, certains sont répétés, mais c'est déjà beaucoup mieux que ce qu'il était. Les autres variables sont également bien ajustées. Il y a, bien sûr, une légère différence dans les paramètres régionaux, dans les variables de SSH, mais cela ne devrait plus affecter considérablement le script.

Maintenant, il est clair pourquoi bash -l est nécessaire dans les entrées crontab. Et, bien sûr, n'oubliez pas le troupeau.

Déboguer l'initialisation des scripts de connexion


Le problème semble être résolu, tout depuis la couronne fonctionne. Mais comment se fait-il que certains chemins soient dupliqués dans la variable PATH? Il y a donc une sorte de gâchis dans la configuration du serveur. Essayons de le comprendre.

Nous ouvrons quelques hommes pour initialiser l'environnement, nous lisons quels scripts et dans quel ordre sont exécutés, avec enthousiasme nous commençons à courir à travers leurs yeux - et après quelques minutes, un sentiment de désespoir survient. Un flux infini de conditions sur certains cas particuliers d'architectures, de terminaux et de paramètres de couleurs incroyablement importants pour la commande ls. Douleur, désespoir, haine! Nous sommes intéressés par une fichue variable PATH!

En fait, tout est un peu plus simple. Rencontrez:

 env -i bash -x -l -c 'echo 123' > login.log 2>&1 

Que fait cette équipe? Crée un nouveau processus bash avec un environnement vierge, indique qu'il est nécessaire d'exécuter des scripts d'initialisation et de tout sécuriser en détail dans le fichier login.log. Nous avons maintenant la possibilité de ne pas exécuter tous les scripts dans notre esprit, mais simplement de lire quoi, où et quand il a été exécuté et d'où vient tel ou tel paramètre d'environnement.

Je n'analyserai pas en détail comment lire le journal résultant. Tout y est presque banal. Je mentionne seulement qu'un hit est venu de / etc / profile et deux de /etc/bash.bashrc. Oui, quelque part, ils étaient trop intelligents lors de la configuration des packages dans un pappet. Bon, rien, ça ne me dérange pas de travailler.

Mais maintenant je sais et je peux!

PS Dans les cas très difficiles et afin de tout comprendre, vous pouvez encapsuler la commande en strace:

  strace -f env -i bash -x -l -c 'echo 123' > login.log 2>&1 

Source: https://habr.com/ru/post/fr465021/


All Articles