Ours & Hippy — le blog Ours & Hippy ourshippy@huoc.org tag:blog.huoc.org,2009:atom 2009-08-03T01:12:08+02:00 tag:blog.huoc.org,2009:posts/18 shutdown, Emacs, et Firefox 2009-08-03T01:12:08+02:00 2009-08-03T01:12:08+02:00 Nhat Minh Lê (rz0) <p>Depuis quelques temps déjà, Emacs&#xA0;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,&#xA0;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[&quot;@mozilla.org/toolkit/app-startup;1&quot;]. 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 ] &amp;&amp; /usr/bin/pgrep -U $LOGNAME $1 &gt;/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 &lt;&lt;EOF &gt;/dev/null var app = repl.Ci.nsIAppStartup; repl.Cc[&quot;@mozilla.org/toolkit/app-startup;1&quot;]. 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>