You are currently browsing the category archive for the ‘Bash’ category.

Peut-être que comme moi, le temps de chargement de votre console est long. Plus précisément, le temps que le prompt apparaisse est interminable. (de l’ordre de la demi-seconde à la seconde…).

J’ai pensé d’abord que j’avais un bashrc codé comme un pied, en le relisant je ne voyais rien de suspect. Je me suis mis à tester le temps que mettait les divers parties de mon fichier /etc/bash.bashrc et j’ai vite découvert le coupable : bash_completion.

Si vous ne savez pas encore ce que c’est, empressez-vous de lire ce très bon article d’artisan linux.

En cherchant un peu sur le net, je suis tombé sur ce message de la liste de diffusion de debian de février 2008. Le fil de discussion confirme bien la culpabilité de bash_completion et le message que je vous cite donne un script tout à fait intéressant.

Plutôt que de charger le fichier /etc/bash_completion (et donc /etc/bash_completion.d) dans le bashrc qui lui même est chargé avant que le prompt ne s’affiche, pourquoi ne pas charger les completions au moment où l’on en a besoin ?

Le script est à lancer avec les droits root bien sûr, et il va creer un fichier /etc/bash_dyncompletion et un répertoire /etc/bash_dyncompletion.d à partir des fichiers de completions habituels.

Le résultat est incroyable. Je vous invite à tester si vous utilisez bash_completion.

Une completion dynamique devrait être implémentée dans bash-completion-3.0. Etant à la 1.2, je pense que ce contournement a encore de beaux jours à vivre sur mes machines.

A noter qu’il faudra relancer le script à chaque fois que vous mettrez à jour les completions.

PS : j’ai gardé l’anglicisme completion au lieu complétement…

L’objectif de cet article est de se donner quelques outils simples permettant d’administrer une machine à distance. Typiquement, mon cas d’utilisation est l’ordinateur de mes parents dont je prend en charge l’administration système. Je suppose dans cet article qu’un accès ssh est déjà configuré sur votre machine serveur (et, tant qu’à faire, la sécurisation qui va avec : fail2ban, accès permit qu’à certains logins…).

Se connecter en ssh

Comme vous le savez déjà, pour vous connecter en ssh il vous faut soit un nom de domaine, soit une IP. Dans le premier cas, certains utilisent les services de dyndns. Dans mon cas, je peux et je décide de me passer de ce service tiers en choisissant de passer par l’IP qu’attribue mon FAI. Dans le cas où l’IP est fixe, il n’y a pas de problème, mais si elle est dynamique comme chez moi, ça l’est un peu plus. L’idée est donc d’envoyer cette IP par email. Si vous préférez la solution dyndns, l’article garde néanmoins  son intérêt car recevoir des informations par email, c’est sympa :D et on va le voir.

Les emails avec ssmtp

Afin de pouvoir envoyer des emails depuis la machine distante, nous allons installer ssmtp et mailutils (ici sur debian) :

aptitude install ssmtp mailutils

L’avantage de ssmtp est qu’il est simple à configurer. De plus, ce n’est pas un démon, donc pas de consommation de ressources supplémentaires.

Utilisation du smtp de neuf

Mes parents étant chez neuf, nous pouvons utiliser le smtp de celui-ci. Dans ce cas, tout ce passe dans le fichier /etc/ssmtp/ssmtp.conf. On y met :

mailhub=smtp.neuf.fr
FromLineOverride=YES

La première ligne sert à donner le serveur smtp (vous ne l’aviez pas deviné ? :) )  et le seconde permet à l’utilisateur de spécifier le provenance (adresse émettrice) du courriel.

Deux lignes, pas une de plus :) Maintenant, si la machine est amenée à voyager (ie à changer de FAI), il peut être bon d’utiliser un smtp accessible de partout. Par ailleurs, il y a quelques années, lors de mes premiers essais, j’avais fini par être rapidement blacklisté par neuf :/

Utilisation du smtp de gmail

Nous allons donc donner une seconde illustration via le service de google : gmail. Pour cela, rien de plus simple, il vous faut un compte.

La configuration est un chouilla plus compliqué car google demande une authentification pour utiliser le smtp.

Dans le même fichier que précédemment, nous allons commencer par les infos du compte :

AuthUser=moi@gmail.com
AuthPass=super_mot_de_passe

puis, celles du smtp :

mailhub=smtp.gmail.com:587
AuthMethod=LOGIN
UseTLS=YES
UseSTARTTLS=YES

Ne pas hésiter à faire un petit

chmod 600 ssmtp.conf

pour la sécurité car le mot de passe est en clair.

Ouverture du port adéquat du firewall

On commet l’erreur au moins une fois : l’oubli du firewall et la croyance que les tutos des autres ne fonctionnent jamais chez soi. Pour ma part, j’utilise l’excellent guarddog pour paramétrer iptable (dommage qu’il n’existe pas un équivalent ncurse). Pour le smtp de neuf, il suffit d’ouvrir dans la partie mail le smtp. Pour celui de gmail, il faut créer une règle TCP 587 puis la selectionner dans les règles personnelles.

Petit test et première application

Pour lancer un test, rien de plus simple :

echo test | mail -s "test" -t adresse_quotidienne@truc.fr

et relever vos emails :)

Tout devrait fonctionner. La première petite application que je propose est la suivante : on souhaite qu’à chaque connection en root, qu’un email soit envoyer à l’admin. L’admin d’une machine généralement unique (sinon, on délègue avec sudo), on se rendra vite compte d’un accès non-souhaité. Pour ça, on va ajouter dans le .bashrc de root ceci :

echo Connexion (root): $(date) | mail -s "Root access" -t  admin@truc.fr

Et voilà :)

Adresse IP

Puisque l’administration se fera exclusivement par ssh, je vais mettre en place l’envoi automatique de l’adresse IP par email.

Idées du script

Le concept de base est de récupérer l’IP à l’aide d’un site tel que monip.org.

wget -q http://www.monip.org -O -  | iconv -f iso8859-1 -t utf8 | sed -nre ‘s/^.* (([0-9]{1,3}\.){3}[0-9]{1,3}).*$/\1/p’

Il suffit de passer ce résultat dans une commande similaire à ce que l’on a utilisé plus haut. Le lancement doit être automatisé. Il y a selon moi plusieurs politiques. On peut placer le script dans /etc/init.d et le lancer au démarrage (en plaçant un/des lien(s) symboliques dans /etc/rc*.d ou en utilisant sysv-rc-conf sous debian ; consultez la doc de votre distribution pour connaitre les runlevel et les éventuels logiciels pour créer les symlinks si vous ne voulez pas le faire à la main). L’autre méthode est d’utiliser cron pour envoyer réglièrement l’IP.

Chacune de ces méthodes à son avantage et son inconvénient. Le problème de la première est qu’une machine qui tourne longtemps (fort uptime) pourrait voir l’IP du routeur changer entre temps, et nous ne serions pas notifié de la modification. Pire, la machine est injoignable et on doit faire appel à une personne physique. La seconde envoie régulièrement des infos. En attendant N heures, on aura forcément la bonne IP dans le cas précédent. Mais d’une part, on reçoit plus d’emails que nécessaire et d’autres part, on n’a pas la notification juste au démarrage de la machine (bien que ça doit pouvoir se contourner pour ce dernier point avec anacron, je n’ai pas creusé).

Bien que l’on pourrait se satisfaire dans certains cas de l’une ou l’autre des solutions (j’ai tourné par un mélange des deux précédentes pendant longtemps), je viens d’élaborer une autre plus fine via un petit service qui va :

  • Envoyer une notification à son démarrage
  • Vérifier régulièrement le changement d’IP et notifier si nécessaire

Ce code (encore en test, si des personnes sont intéressées, je le publierai en GPL) se compose d’une part d’un démon (pour débian, mais adaptable facilement à d’autres distributions) et d’un petit script qui s’occupe de gérer l’envoie du email quand il le faut. Il est possible bien sûr d’envoyer d’autres informations pertinentes par la même occasion. De plus, les fans de chiffrements ne manqueront pas de chiffrer le courriel avec gpg. J’avais écrit à une certaine époque un article pour le wiki de mandriva à ce propos.

Logwatch

Outil cité par admin-linux, logwatch permet de surveiller une machine. Que fait-il ? Logwatch lit les logs du systèmes pour nous et les présente sous une forme digeste, par thème. Chaque jour, un courriel est envoyé avec ce qui est bon de savoir (iptable, espace disque, paquets, erreurs divers…) . En effet, une tâche cron est crée dans /etc/cron.daily Modifier le fichier S00logwatch pour y mettre votre adresse email après le –mailto.

Le fichier de configuration par défaut est dans /usr/share/logwatch/default.conf/logwatch.conf

On pourra le copier dans /etc/logwatch (qui prime sur /usr/share/logwatch). Les options sont très bien expliquées, au point qu’il ne me semble pas nécessaire de les repréciser ici.

Conclusion

Me voilà avec une machine fin prête à être maintenue à distance en toute simplicité en plus d’un bon amusement à bidouiller en amont :)

Avec cet article, je veux vous montrer en quoi il est facile de contribuer au logiciel libre, grâce à deux exemples. Le premier ne nécessite aucune connaissance en programmation puisqu’il s’agit d’un apport de traduction. Le second, quant à lui, requiert quelques connaissances en script shell, mais si peu que j’espère que cela restera compréhensible aux yeux de tous. Je donne les grandes lignes sans être exhaustif.

Manque de traduction

La traduction, encore nommée internationalisation (i18n) "localisation" (l10n), est sans doute le plus bel exemple où l’on contribue directement au coeur du logiciel mais sans aucun prérequis de programmation, tout au plus il faudra être sensibilisé à la gestion de projet libre. L’effort de traduction est tout aussi important à mes yeux que le soin apporté à la programmation. Un logiciel mal ou peu traduit fait souvent mauvaise impression et peut aller jusqu’à son abandon pour les nombreux utilisateurs non-anglophones.

L’exemple que j’ai choisi m’est venu lorsque j’ai parlé du logiciel grsync à un ami. grsync est une interface graphique GTK au puissant rsync permettant la synchronisation de répertoires. Après avoir installé la version 1.0.0 (qui s’avère être la dernière version comme l’atteste le site du projet), je vois que certaines phrases (que l’on nomme techniquement chaine de caractère) reste en anglais. Une première chose à se méfier est de penser que ce que l’on a sous les yeux est le dernier avancement du logiciel. Ce n’est bien sûr pas le cas, car des modifications du code peuvent être effectuées tous les jours sans pour autant qu’il y ait de nouvelles versions. Il faut donc aller sur le gestionnaire de version du projet afin de récupérer la version la plus avancée.

La traduction se fait, peu ou prou, de la même manière que ce que j’ai pu décrire dans cet article. Sur le SVN du projet, on ira toujours dans le tronc (trunk) et on va jusqu’au répertoire po et télécharger FR_fr.po. On modifie et on se fait un petit patch. Pour cela, je vous conseille la lecture de cette page par exemple. Je n’ai personnellement pas utilisé cette méthode, j’ai préféré git, mais on n’est pas obligé d’aller jusque là. ;)

Voila le résultat. :)

Correction d’un bug logiciel

Attaquons nous maintenant à la correction d’un bug sur un logiciel. L’idée m’a été soufflée par une conférence de Parinux sur la distribution légère Slitaz. Lors d’une démonstration (c’est toujours comme ça :) ), le conférencier a voulu ouvrir le gestionnaire de paquet et a entré un mot de passe erroné. Après validation, rien ne s’est passé. Après une dizaine de secondes, il s’est souvenu avoir changé le mot de passe et a pu ouvrir le gestionnaire de paquet. On a là un bug manifeste, l’utilisateur aurait dû être prévenu de l’erreur sur le mot de passe. Les gens qui ont fait un peu de programmation dans leur vie sentent de suite que c’est un cas non géré, un type de bug fréquent.

L’avantage pour cette démonstration est que le site est partiellement en français car le créateur est suisse. On arrive alors sans trop de peine à la partie développement. On a remarqué que le programme portait le doux nom de subox, et une petite recherche nous montre que dans slitaz-tools/tinyutils on retrouve le code source de subox.

On récupère le code et on va donc chercher à corriger le bug. La ligne qui attire mon attention est celle-ci :

<action>echo $PASSWD | su -c "$SU_CMD" &</action>

On remarque alors qu’en cas d’échec, rien n’est prévu. Je propose donc de la remplacer par ceci :

<action> if [[ $(echo $PASSWD | su -c "$SU_CMD" &) ]]; \
then gtkdialog --center --program=ERROR_DIALOG;fi;</action>

où ERROR_DIALOG est une fenêtre qui comporte le message d’erreur. Je passe le détail de la création de cette fenêtre, tout est dans le rapport de bug, et un simple coup d’oeil sur le premier tuto gtkdialog ou la lecture d’autres scripts de la distro permet d’écrire sans problème ce morceau de code. Une fois mon fichier modifié, j’en ai crée un patch.  Le code étant petit, j’ai ajouté le programme complet en fichier attaché.

Le rapport final est disponible , en attente d’un dev pour correction :)

Je n’ai pas la prétention que le patch soit idéal ou parfait. Sans doute ne respecte-il pas la politique de la distribution que je ne connais pas, mais quand bien même cela ne plairait pas aux développeurs, cela leur montrera très clairement le problème et une possibilité de résolution. Ceci accélérera dans aucun doute la résolution du bug.

Bien sûr, parfois on n’arrive pas à corriger le bug. On peut avoir qu’une piste voir rien du tout… nul n’est parfait. Dans tous les cas, il faut toujours ouvrir un rapport et indiquer les éventuelles pistes.

Conclusion

Les contributions au logiciel libre peuvent se faire sans connaissances particulières : écriture de documentations, entraide sur les canaux de communication, animations de manifestations… mais on peut avoir envie d’aller plus loin, de découvrir les rouages du moteur.

J’espère ainsi avoir montré, via ces deux exemples, en quoi il est possible de contribuer au code d’un logiciel libre soit sans connaître un langage ou soit sans être un codeur fou. Par contre, il est vrai qu’il faut être un peu familier de la gestion des projets et des outils associées (sourforge, svn, mercurial…), suffisamment pour savoir s’y repérer et récupérer un bout de code. Il existe pléthore de petits logiciels et de petits projets qui ne demandent que ce type de contribution.

Bref, si vous hésitez, même si vous pensez ne pas être à la hauteur, foncez ! Il n’y a pas de petites contributions. L’aventure est extraordinaire, on apprend plein de choses, c’est très enrichissant. En espérant vous avoir convaincu… :)

Je vais commencer par expliquer les motivations du script que je vais présenter.

Gnuplot est un logiciel de tracé utilisable en ligne de commande et dispose de divers formats de sortie. L’objectif est de sortir les graphiques pour les insérer dans un document le Latex. J’ai utilisé pendant un temps le format de sortie postscript :

gnuplot> set term post color enhanced

permet d’avoir cette sortie dans gnuplot. Ensuite, je convertissais le fichier à l’aide de la commande ps2pdf puis le pdf était découpé à l’aide de pdfcrop. J’avais d’ailleurs fait un petit script afin d’automatiser cette opération. Le fichier pdf résultant était inséré sans soucis dans le document et compilé avec pdflatex.

Quel est donc le problème alors ? Le problème principal est que les chaines de caractères ne possèdent pas la police utilisé dans le document. De plus, on est obligé de ruser pour les accents à l’aide de commandes que j’oublie toujours…

Gnuplot dispose du format de sortie latex qui génère un .tex. Le soucis majeur est que ce format ne gère pas la couleur, ce qui ennuyant pour des graphiques comportant plusieurs nuages de points. Deux autres formats sont a priori intéressants : epslatex et pstricks. Ces deux formats ne peuvent être utilisés avec pdflatex. On se doit d’utiliser latex pour compiler le document ce qui ne me réjouie pas puisque l’insertion d’image au format PNG est impossible. Il faut les convertir auparavant en eps avec gimp par ex. Bref, il faut utiliser la commande latex.

Je vais me concentrer sur la sortie epslatex.

gnuplot> set term epslatex color

L’idée est de conserver le format pdf pour inclure les graphiques, format qui permet une visualisation facile par ailleurs.
Via un script shell, on va créer un fichier temporaire .tex qui va inclure le fichier eps et être compilé avec la commande latex. Le fichier de sortie étant au format dvi, on va convertir en pdf avec dvipdf puis découpé avec pdfcrop. On supprime les fichiers temporaires.

L’inconvénient de cette méthode peut rester la police dans le cas où on la modifie dans le document final, mais le problème est mineur.

En outre, dans ce script, j’ai mis en place un code multi-tâche que j’ai pu expliqué dans un billet précédent. Je n’ai fait qu’un seul essai pour le moment, avec 5 fichiers à convertir, j’ai eu une réduction du temps de 33% en dual core, sachant que seulement les 4 premiers ont été parallélisé.

Le code est disponible sous licence GNU GPL v3 à cette adresse. Script à mettre dans votre PATH. Il ne me reste plus qu’à gérer complètement mes documents avec des makefiles. :)

Il y a plusieurs mois (si ce n’est pas un an), j’ai lu le billet d’un blog aujourd’hui fermé qui présentait une idée pour rendre un script utilisation la parallélisation. Avec les processeurs multi-coeur, je pense que l’on devrait plus fréquemment utiliser ce procédé. Pour l’anecdote, cela m’a bien été utile lorsque j’ai utilisé une machine ayant 8 coeurs lors d’un stage :)

Ce billet n’est pas une simple recopie du billet que j’ai pu lire puisque le script possédait un petit bug. Je vais donc le corriger ici.

On va dire que une action élémentaire traite un fichier, et que l’ensemble des fichiers est passé en argument du script.

current=1
numthreads=`cat /proc/cpuinfo|grep ‘^processor’|wc -l`

while [ $# -gt 0 ]
do

action $1 &

div=$((current/$numthreads))
mul=$((div*$numthreads))
# wait if numthreads jobs are running
if [ "$mul" = "$current" ]
then

#we reached the max of thread number
wait

else

#we wait if this thread is the last one
[[ $# -eq 1 ]] && wait

fi

current=$((current+1))

#shift to the next file
shift

done

Je vais commenter rapidement la méthode. On définie une variable current pour le numéro du thread, on récupère dans numthreads le nombre de coeurs du procésseur. Tant qu’il reste des arguments au script (à chaque étape on supprime l’argument traité) on va exécuter la fonction action quu n’est pas définie ici. Les deux lignes suivantes vérifient si deux on a lancé numthreads tâches ou non. Si c’est le cas, on attend la fin de toutes les actions précédemment lancées. Si l’argument traité s’avère être le dernier de la liste, on attend aussi l’ensemble des tâches lancées. (et c’est ce point qui avait été oublié ; le script était quitté alors qu’un thread tournait encore.)

L’inconvénient (il faut en être conscient) de ce script est que les actions élémentaires doivent avoir typiquement le même temps d’exécution sans quoi on ne sera pas très efficace car une tâche longue va occupé un coeur alors que les autres seront libres.

J’ai trouvé la documentation autour de l’internationalisation de scripts en bash assez peu fournie. Je vais donc par le biais d’un exemple vous montrer comment vous pouvez utiliser le bash pour faire des scripts dans plusieurs langues.

Voici un script court qui utilise kdialog. Mais si vous ne voulez pas l’utiliser, laissez-juste la ligne avec le echo.

#!/bin/bash

export TEXTDOMAIN=i18nscript

kdialog –title $"The title" –yesno $"This is an example \
to illustrate i18n in a bash script.\n Do you wish to continue?"

echo $"This is an example to illustrate i18n in a bash script."

exit 0

Vous remarquerez que les chaines de caractères (strings en anglais) sont précédées d’un $. C’est ce qui sera utilisé pour récupérer les chaines à traduire. A noter aussi la présence de la ligne export TEXTDOMAIN=i18nscript, qui marque où chercher la traduction. On mets généralement le nom de l’exécutable.
Ensuite nous créons un répertoire po afin de ranger tout ce qui concerne l’i18n pour notre projet.

mkdir po
bash –dump-po-strings i18nscript > po/i18nscript.po

Le fichier i18nscript.po contient ceci :

#: i18nscript:6
msgid "The title"
msgstr ""
#: i18nscript:6
msgid "This is an example to illustrate i18n in a bash script.\\n Do you wish to continue?"
msgstr ""
#: i18nscript:9
msgid "This is an example to illustrate i18n in a bash script."
msgstr ""

Ensuite, copions ce fichier de la manière suivante :

cp po/i18nscript.po po/fr.po

Ensuite, le traducteur (vous je pense :) ) va compléter les lignes commençant par msgstr. Si vous voulez traduire dans d’autres langues, vous devez appliquer la même procédure.

msgfmt -o i18nscript.mo fr.po
et on déplace ce fichier mo dans
mv i18nscript.mo /usr/share/locale/fr/LC_MESSAGES/
Si l’utilisateur utilise une langue non traduite, la langue figurant dans le script sera utilisée. C’est pour cela que l’on préférera utiliser l’anglais dans celui-ci.

Entrer votre adresse e-mail pour vous inscrire à ce blog et recevoir les notifications des nouveaux articles par courriel.

Joignez-vous à 15 followers

April

Promouvoir et soutenir le logiciel libre

Licence

Le contenu textuel de ce site est mis à votre disposition sous les termes de la licence Creative Commons CC BY-SA

Vous êtes libres :

* de reproduire, distribuer et communiquer cette création au public
* de modifier cette création

Selon les conditions suivantes :

* Paternité — Vous devez citer le nom de l'auteur original de la manière indiquée par l'auteur de l'oeuvre ou le titulaire des droits qui vous confère cette autorisation (mais pas d'une manière qui suggérerait qu'ils vous soutiennent ou approuvent votre utilisation de l'oeuvre).
* Partage des Conditions Initiales à l'Identique — Si vous modifiez, transformez ou adaptez cette création, vous n'avez le droit de distribuer la création qui en résulte que sous un contrat identique à celui-ci.

Suivre

Recevez les nouvelles publications par mail.

%d bloggers like this: