daemondoの劣化バージョンをPerlで書いてみる
昨日のエントリとちょっと関連してます。
直接デーモンプロセスを生成しない起動コマンドを持つアプリケーションをlaunchdで制御しようとした場合、デーモンの身代わりになってくれるdaemondoというユーティリティを使ったりします。
daemondoはMacPortsに付属するので、もしMacPortsを入れずにHomebrewだけにする場合はどうするのでしょう。
調べても良くわからなかったので、自分でdaemondoの代わりのものを作ってみました。
そもそもdaemondoとは何か
daemondoは、デーモンを生成しない起動コマンドをラップする機能を持ちます。
launchdで使う場合であれば、launchctl stopが実行されると、daemondoがシグナルSIGTERMを受信し、stop-cmdで指定されたコマンドが実行されます。
シグナルについては、google:UNIX シグナルなどを参照してください。
暫定版(/bin/sh)
Perl版を作る前は、shスクリプトで暫定対応していました。
例として、Redmineの場合。
Redmineのインストール先を、仮に"/redmine_home"とします。
Redmineを起動するには、"/redmine_home/ctlscript.sh start"を実行します。
デーモン化するには、以下のスクリプトを作って、launchdからはこれを呼ぶようにします。
#!/bin/sh /redmine_home/ctlscript.sh start & # background while true do sleep 60 done
停止させる場合は、launchd側の停止と"ctlscript.sh stop"は個別に実行する必要があります。
これでも、停電からの復帰だけであれば十分でした。
Perl版
第1引数に対象アプリケーションの起動スクリプトを設定します。
launchctl start の時は、第1引数のコマンドにstartを渡して実行します。
launchctl stop の時(SIGTERM)は、第1引数のコマンドにstopを指定して実行し、デーモンを終了します。
その他の細かい状態制御はあまり考えていません。
Perlでデーモンを作る場合はProc::Daemonを使うようですが、このケースではlaunchdが勝手にデーモンとして保持してくれるみたいなので不要です。(Proc::Daemonについては参考のURL参照。)
- sighookd.pl
#!/usr/bin/perl use strict; use warnings; use Sys::Syslog qw(:DEFAULT setlogsock); my $cmd; sub msg { my $msg = shift; setlogsock "unix"; openlog("sighook", "pid", "internal.none"); syslog("notice", $msg); closelog(); } sub interrupt { my $sig = shift; setpgrp; $SIG{$sig} = "IGNORE"; kill $sig, 0; if ($sig eq "TERM") { msg "recv $sig ... stop"; my $r = system $cmd, "stop"; msg "call [system $cmd stop], result=[$r]"; msg "stop daemon"; exit 0; } else { msg "recv $sig ... do nothing"; } } # main $cmd = shift; unless ($cmd && -f $cmd) { print "usage: $^X <cmd-path>\n"; exit 0; } $SIG{TERM} = "interrupt"; msg "start daemon, cmd=[$cmd]"; my $r = system $cmd, "start"; msg "call [system $cmd start], result=[$r]"; sleep 60 while 1;
Redmineの場合は、launchd(plist)に"sighookd.pl /redmine_home/ctlscript.sh"のように登録します。
GlassFishのasadminは、起動/停止時の引数が"start-domain/stop-domain
#!/bin/sh cmd=${glassfishのdir}/bin/asadmin case "$1" in start) ${cmd} start-domain <domain名>;; stop) ${cmd} stop-domain <domain名>;; *) echo "usage: $0 start|stop";; esac