が、たまに更新に失敗します。。。
しかもリトライしてくれないぽ(´・ω・`)
しかも、何故か家を離れているときに多い(涙
そんなわけで、dicedのログを監視して、IPが変わったのにDDNSのIP更新に失敗したときに、メールで通知するスクリプト(daemon動作可)を書いてみました。
#!/usr/bin/perl -w
use strict;
use POSIX qw(strftime);
use POSIX qw(setsid);
######################################################################
# 設定項目
######################################################################
# デーモンにするか?: 1(オン) / 0 (オフ)
our $DAEMON = 1;
# スリープの間隔(秒)
our $SLEEP_INTERVAL = 600;
# このスクリプトのログファイル名
our $LOG_FILE = "/var/log/chk-diced-log.log";
# diced のログファイル名(パスを含む)
our $DICED_LOG_FILE = "/usr/local/DiCE/log/events.log";
# pidファイル
our $PID_FILE = "/var/run/chk-diced-log.pid";
######################################################################
# メイン処理
######################################################################
&init;
&run;
######################################################################
# サブルーチン
######################################################################
#---------------------------------------------------------------------
# メイン処理
#---------------------------------------------------------------------
sub action {
# 現在日時を取得
my $now_time = strftime "%-m/%-d %-H:%M", localtime;
print "wake at $now_time\n";
# 自ログから前回の実行時間を取得
my ($prev_time,$prev_ip) = &get_prev_info;
# dicedのログをチェック
my $ng_flg = 0;
my $current_ip;
open IN, $DICED_LOG_FILE or die "can't open diced log file!";
foreach(<IN>){
if( />(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})$/ ){
# 最新のIPを保持
$current_ip = $1;
}
if( /▲/ ){
# 実行に失敗しました
$ng_flg = 1;
}
if( /★/ ){
# 実行されました
$ng_flg = 0;
}
}
close IN;
# 失敗したまま&以前のIPと変化があったなら通知を出す
if( $ng_flg ){
if( $current_ip ne $prev_ip ){
# 通知
&send_notify_mail( $now_time, $current_ip );
# ログファイル書き出し
&write_log( $now_time, $current_ip );
}
}
}
#---------------------------------------------------------------------
# 自ログから前回の実行時間とその時点のIPを取得
#---------------------------------------------------------------------
sub get_prev_info {
my @prev_info;
my $line;
# ログファイルがなければ、空データを返す
if( ! -e $LOG_FILE ){
@prev_info = ( "", "" );
return @prev_info;
}
# ログファイルを開く
open IN, $LOG_FILE or die "can't open log file!";
# ログファイルから前回実行時間とその時点のIPを取り出す
$line = <IN>;
close IN;
chomp($line);
@prev_info = split( /<>/, $line );
return @prev_info;
}
#---------------------------------------------------------------------
# ログ書き出し
#---------------------------------------------------------------------
sub write_log {
open OUT, ">$LOG_FILE" or die "can't open log file for writing!";
print OUT "$_[0]<>$_[1]";
close OUT;
}
#---------------------------------------------------------------------
# 更新失敗を通知
#---------------------------------------------------------------------
sub send_notify_mail {
#open OUT, ">>/tmp/hoge.txt";
#print OUT "send mail at $_[0]\n";
#print OUT "new ip : $_[1]\n";
#close OUT;
}
#---------------------------------------------------------------------
# pid書き出し
#---------------------------------------------------------------------
sub write_pid {
open OUT, ">$PID_FILE";
print OUT $$;
close OUT;
}
#---------------------------------------------------------------------
# 割り込みハンドラ
#---------------------------------------------------------------------
sub interrupt {
my $sig = shift;
setpgrp; # I *am* the leader
$SIG{$sig} = 'IGNORE';
kill $sig, 0; # death to all-comers
die "killed by $sig";
exit(0);
}
#---------------------------------------------------------------------
# 初期設定
#---------------------------------------------------------------------
sub init {
$SIG{INT} = 'interrupt'; # Ctrl-C が押された場合
$SIG{HUP} = 'interrupt'; # HUP シグナルが送られた場合
$SIG{QUIT} = 'interrupt'; # QUIT シグナルが送られた場合
$SIG{KILL} = 'interrupt'; # KILL シグナルが送られた場合
$SIG{TERM} = 'interrupt'; # TERM シグナルが送られた場合
# daemon動作?
if( $DAEMON ){
# カレントディレクトリを移動しとく。
chdir '/';
# 標準入出力を閉じる
open STDOUT, ">/dev/null";
open STDIN, ">/dev/null";
# 一時的に無視
$SIG{CHLD} = 'IGNORE';
my $pid = fork;
# forkできた?
if( $pid < 0 ){
# 失敗
exit -1;
}elsif( $pid ){
# 成功したので、親側はさようなら。
exit 0;
}
# 子プロセスで動く処理
# 無視してたのを戻す
$SIG{CHLD} = 'DEFAULT';
# プロセスIDを書き出しておく
&write_pid or exit 1;
# セッションを新しく始める
setsid or die "Can't start a new session: $!";
# 標準エラーも閉じる
open STDERR, ">/dev/null";
}
}
#---------------------------------------------------------------------
# デーモン動作
#---------------------------------------------------------------------
sub run {
while(1) {
# SLEEP_INTERVAL ごとに action を呼び出す
&action;
sleep($SLEEP_INTERVAL);
}
}
1;
サービス登録用のスクリプトは近日中には。。。