Ours & Hippy — le blogOurs & Hippyourshippy@huoc.orgtag:blog.huoc.org,2009:atom2009-08-03T01:12:08+02:00tag:blog.huoc.org,2009:posts/18
shutdown, Emacs, et Firefox
2009-08-03T01:12:08+02:002009-08-03T01:12:08+02:00Nhat Minh Lê (rz0)
<p>Depuis quelques temps déjà, Emacs 23 dispose de l’option <code>--daemon</code>,
qui permet de lancer l’éditeur en tâche de fond. Les connexions s’y
font alors avec <b>emacsclient(1)</b>, comme avec l’ancien mode
serveur. La différence avec <code>server-start</code> est qu’il n’est pas
nécessaire d’avoir une <i>frame</i> toujours ouverte. Cela permet entre
autre de garder sa session Emacs indépendante de son environnement
graphique. Tout cela n’a été rendu possible, bien sûr, que grâce
à l’arrivée du <i>multi-tty</i>, qui permet, comme son nom l’indique,
à Emacs de se manifester sur plusieurs supports : X, console, etc.
</p><p>Quel rapport avec <b>shutdown(8)</b> et Firefox, donc ?
</p><p>Puisque je lance désormais Emacs directement lors de mon <b>login(1)</b>
(quelques lignes qui vont bien, dans mon <code>.profile</code>) et que <code>C-x C-c</code>
ne supprime plus le processus entier mais seulement sa manifestation
sur un terminal donné, il paraît naturel de vouloir tuer Emacs à la
fin de ma session.
</p><p>Or, si je me connecte avec login, je quitte habituellement ma session
en éteignant ma machine avec un <code>sudo shutdown -p now</code>. Au-delà des
services gérés par <b>rc(8)</b>, cette commande a pour effet d’envoyer un
<code>SIGTERM</code> à tous les processus vivants. Cela fonctionne à merveille
pour tous les programmes ne nécessitant aucune action à leur fermeture
ou prenant adroitement en compte <code>SIGTERM</code>. Ce n’est malheureusement
ni le cas d’Emacs, ni celui de Firefox, qui se terminent tous deux
brutalement, en n’opérant pas la maintenance requise. En utilisant
shutdown simplement de cette façon, je me retrouvais donc au démarrage
suivant avec un Emacs mécontent de trouver un vieux fichier <i>desktop</i>
et un Firefox grognant que la dernière session s’est terminée
anormalement.
</p><p>Il fallait donc trouver un moyen d’obliger Emacs et Firefox à quitter
proprement, et ce depuis la ligne de commandes.
</p><p>Pour Emacs, je n’eus pas trop de mal à trouver comment attacher une
fonction ELisp à la réception du signal <code>SIGUSR2</code> :
</p><pre><code>(defun my-sigusr2-handler ()
(interactive)
(kill-emacs))
(define-key special-event-map [sigusr2] 'my-sigusr2-handler)
</code></pre><p>Pour Firefox, en revanche, il fallut davantage peiner. La solution que
j’ai finalement adoptée n’est sans doute pas la meilleure, mais elle
a le mérite de fonctionner. Elle repose sur l’utilisation de <a class="extern" href="http://wiki.github.com/bard/mozrepl">MozRepl</a>
et de <b>nc(1)</b> (<code>net/netcat</code> dans pkgsrc) pour injecter du JavaScript
dans l’instance de Firefox en cours. Le code JavaScript, trouvé dans
<a class="extern" href="http://search.cpan.org/~zigorou/MozRepl-Plugin-Restart-0.02/">un module Perl</a>, est le suivant :
</p><pre><code>var app = repl.Ci.nsIAppStartup;
repl.Cc["@mozilla.org/toolkit/app-startup;1"].
getService(app).quit(app.eForceQuit);
</code></pre><p>Après tous ces efforts, j’obtiens enfin un script <i>shell</i> permettant
de tuer Emacs et Firefox en toute sérénité (à exécuter en tant
qu’utilisateur) :
</p><pre><code>TIMEOUT=5
waitfor()
{
while [ $TIMEOUT -gt 0 ] && /usr/bin/pgrep -U $LOGNAME $1 >/dev/null; do
sleep 1
TIMEOUT=$((TIMEOUT-1))
done
}
# Emacs.
/usr/bin/pkill -USR2 -U $LOGNAME emacs
waitfor emacs
# Firefox.
/usr/pkg/sbin/nc localhost 4242 <<EOF >/dev/null
var app = repl.Ci.nsIAppStartup;
repl.Cc["@mozilla.org/toolkit/app-startup;1"].
getService(app).quit(app.eForceQuit);
EOF
waitfor firefox
</code></pre><p>À moi les extinctions en une commande ! Encore une fois, on remarquera
que c’est la paresse qui guide l’apprenti-administrateur à améliorer
son système. :)
</p>