・ Web系SE募集 (技術開発部開発系エンジニア・Java/Tomcat 420万円~750万円)
   ・ 社内SE募集 (業務系システムの開発・社内イントラ)

LinuxからFreeBSDを触る事になって戸惑うのは、おそらくサービス系を管理するツール(コマンド)が無い事も、その一つだろう。

Linuxであれば、
/sbin/chkconfig
コマンドで、サービスの一覧や、サービスの起動・停止などが簡単に設定可能である。
ところが、FreeBSDには、そういったコマンドは無い。

そこで ググると だいたいの回答は、
/etc/rc.conf や /etc/defaults/rc.conf ファイルの、`*_enable=' を確認する様に書かれている。
サービスの一覧を取得したいだけなのに、その度にそれらファイルから grep するのは後回しにしたくなる作業だ。

そこで、サービス一覧を取得するための簡単なコマンド(シェルスクリプト)を作りました。

rclist  (version 0.01)
(※ソース内の英語が意味不明でしたら、ご指摘とアドバイスを・・)

このFreeBSDからサービス一覧を取得するコマンドは次の特徴(機能)がある。

1./etc/rc.conf や /etc/defaults/rc.conf から 「*_enable=」を grep 出力してくれる。

$ ./rclist -f
/etc/rc.conf: ntpdate_enable="YES"
/etc/rc.conf: sshd_enable="YES"
/etc/defaults/rc.conf: accounting_enable="NO"
/etc/defaults/rc.conf: amd_enable="NO"
/etc/defaults/rc.conf: apm_enable="NO"
/etc/defaults/rc.conf: apmd_enable="NO"

2./etc/rc の 一部を再現して、/etc/rc.d/ や /usr/local/etc/rc.d/ から、サービスのコマンドの一覧に YES/NO を出力してくれる。
これは、サービスの起動順に表示され、一度だけ必ず実行されるコマンドも表示される。
※一度だけ必ず実行されるコマンドは、rc.conf に `*_enable=' というのは無い。

>$ ./rclist -c
rc_elem                       name                                                   rcvar
--------------------          --------------------                    ------------------------
/etc/rc.d/random              random
/etc/rc.d/adjkerntz           adjkerntz
/etc/rc.d/atm1                atm                                               atm_enable=NO
/etc/rc.d/hostname            hostname
/etc/rc.d/kldxref             kldxref                                       kldxref_enable=NO
/etc/rc.d/sppp                sppp
/etc/rc.d/ipfilter            ipfilter                                     ipfilter_enable=NO
/etc/rc.d/ipnat               ipnat                                           ipnat_enable=NO

3./etc/rc の 一部を再現して、/etc/rc.d/ や /usr/local/etc/rc.d/ から、*_enable="YES" のサービスのコマンドやコマンドを実行するシェル関数名を出力してくれる。
これも、サービスの起動順に表示され、一度だけ必ず実行されるコマンドも表示される。
※一度だけ必ず実行されるコマンドは、rc.conf に `*_enable=' というのは無い。

$ ./rclist -d
rc_elem                       name                                                   rcvar      start_cmd/command
--------------------          --------------------                    ------------------------  --------------------
/etc/rc.d/random              random                                                            random_start
/etc/rc.d/adjkerntz           adjkerntz                                                         adjkerntz -i
/etc/rc.d/hostname            hostname                                                          hostname_start
/etc/rc.d/sppp                sppp                                                              sppp_start
/etc/rc.d/addswap             addswap                                                           addswap_start
/etc/rc.d/auto_linklocal      auto_linklocal                                                    auto_linklocal_start
/etc/rc.d/sysctl              sysctl                                                            sysctl_start
/etc/rc.d/cleanvar            cleanvar                                     cleanvar_enable=YES  cleanvar_start
  :(省略)
/etc/rc.d/sshd                sshd                                             sshd_enable=YES  /usr/sbin/sshd
/etc/rc.d/sendmail            sendmail_submit                       sendmail_submit_enable=YES  /usr/sbin/sendmail -L sm-mta -bd -q30m -ODaemonPortOptions=Addr=localhost
/etc/rc.d/sendmail            sendmail_clientmqueue              sendmail_msp_queue_enable=YES  /usr/sbin/sendmail -L sm-msp-queue -Ac -q30m
/etc/rc.d/cron                cron                                             cron_enable=YES  /usr/sbin/cron  -s
/etc/rc.d/localpkg            localpkg                                                          pkg_start
/etc/rc.d/mixer               mixer                                           mixer_enable=YES  mixer_start
/etc/rc.d/geli2               geli2                                                             geli2_start
/etc/rc.d/bridge              bridge                                                            bridge_start
/etc/rc.d/bgfsck              background-fsck                              background_fsck=YES  bgfsck_start

EveryDNS.netサイトにログインして
左側の、「Dynamic Domains:」という欄の説明に、「 You must use a client」と書かれているので、そこのClient(http://www.everydns.com/eDNS.pl.txt)を使用するのでダウンロードする。
これは、IPの更新のみ行うツールなので、IPアドレスが変わるたびに更新を行うための簡単なプログラムを書く。

RT-200KI で NAPT/NATにて プライベートIPを使用する場合、IPアドレスの取得は、その管理画面のIPアドレスを取得する。

以下は、具体的なプログラム例:

$ cat ip_update.pl
#!/usr/bin/perl

use strict;
use Web::Scraper;
use URI;

my $fartime = time;
my $force = 60*60;♯ 強制的に更新を行う間隔
my $sleep_sec = 5;♯ IPアドレスを確認(取得)する間隔

my @domainlist = qw{ # ここに更新対象のドメインを列挙する
        www.mydomain.jp
www1.mydomain.jp
www2.mydomain.jp
}; my $farip=''; while(1){ my $uri = URI->new('http://loginname:password@ntt.setup/cgi-bin/paractl.cgi?st_state'); my $scraper = scraper { process '/html/body/form/div/table[10]/tr[4]/td[4]', 'ip'=>'TEXT'; }; my $result = $scraper->scrape($uri)->{ip}; my ($ip) = $result =~ m{(\d+\.\d+\.\d+\.\d+)/}; if (($fartime + $force < time) or ($farip ne $ip)){ $farip = $ip; $fartime = time; for my $domain( @domainlist ){ my $cmd = "/path/eDNS.pl -u Username -p Password -ip $ip -d $domain"; print $cmd, "\t"; print `$cmd`; } } sleep($sleep_sec); } __END__

ログイン名やパスワード、更新対象ドメインを、適切に設定して、daemontools などで実行させておく。

確実に再起動して欲しい(ダウンして欲しくない)プログラム(デーモン)は、daemontools を使いますが
(※ runit というツールもある様ですが、未検証・・・。)
FreeBSD上にインストールした daemontools は、daemontools 自体のプロセスが落ちると再起動されない。

※ daemontools が面倒をみているプロセスは(daemontools 自体がダウンしていなければ)確実に再起動されます。

どういう事かと言うと、
Linux であれば、/etc/inittab に ダウンしてほしくないプログラムのコマンドを書くと、
プロセスがダウンしても確実に再起動してくれます。
例えば、daemontools をインストールすると

$ tail -n1 /etc/inittab
SV:123456:respawn:/command/svscanboot

となり、daemontools(svscanboot)がダウンしても、inittab が確実に再起動してくれます。

FreeBSD は、inittab が無く init と、/etc/rcやrc.local等と、/etc/ttys で構成されている?様です。
/etc/rcやrc.local は、
http://tools.qmail.jp/daemontools/faq/create.html#why
に書かれている通り、
inittabの様にダウンしてしまったプロセスは再起動されない。

そこでの対応方法は、
http://www.jp.freebsd.org/cgi/mroff.cgi?subdir=man&lc=1&cmd=&man=init&dir=jpman-8.0.2%2Fman&sect=0
に、

init ユーティリティは任意のデーモンを走行させ続けるためにも使用可能であ
り、デーモンが死んだ場合には自動的に再開します。この場合、ttys(5) ファイ
ルの 1 番目のフィールドは、設定されたデバイスノードへのパスを参照してはな
らず、デーモンに対する最後のコマンドライン引数として渡されます。これは
AT&T System V UNIX /etc/inittab にある機能と同様です。

との記載があるのを参考に、
次の様に設定を行う。

>$ vim /etc/ttys
# name  getty                           type    status          comments
# Virtual terminals
ttyv1   "/usr/libexec/getty Pc"         cons25  on  secure
ttyv2   "/usr/libexec/getty Pc"         cons25  on  secure
ttyv3   "/usr/libexec/getty Pc"         cons25  on  secure
# daemontools
daemontools "/command/svscanboot" unknown on

name の欄に、「daemontools」 と設定しているが、これは コマンドの引数となるもの。ここでは適当に設定している。

この様な使い方があっているかは不明であるが、これで確実に再起動される様になる。


「参考」

※インストールの仕方による、起動プロセスの違い:

pkg_add -r daemontools した場合

>$ ps axd
  PID  TT  STAT      TIME COMMAND
    0  ??  DLs    0:16.34 [kernel]
    1  ??  ILs    0:00.13 - /sbin/init --
 5243  ??  S      0:00.14 |-- /usr/local/bin/svscan /var/service
 5352  ??  I      0:00.21 | |-- supervise demo
 5503  ??  S      0:00.11 | | `-- perl ./demodaemon.pl
 5353  ??  I      0:00.01 | `-- supervise log
 5355  ??  S      0:00.10 |   `-- multilog t -* +*COUNT* ./count -* +*[SIG-* ./sig +* ./main
 5244  ??  I      0:00.00 |-- [readproctitle]

ソースからインストールした場合(http://cr.yp.to/daemontools/install.html)

>$ cat /etc/rc.local

csh -cf '/command/svscanboot &'

>$ ps axd
  PID  TT  STAT      TIME COMMAND
    0  ??  DLs    0:16.68 [kernel]
    1  ??  ILs    0:00.14 - /sbin/init --
 6629   0  I      0:00.04 `-- /bin/sh /command/svscanboot
6631 0 S 0:00.02 |-- svscan /service 6650 0 I 0:00.01 | |-- supervise demo 6653 0 S 0:00.03 | | `-- perl ./demodaemon.pl 6651 0 I 0:00.01 | `-- supervise log 6652 0 S 0:00.01 | `-- multilog t -* +*COUNT* ./count -* +*[SIG-* ./sig +* ./main 6632 0 I 0:00.01 `-- [readproctitle]

ソースからインストールした場合、 svscanboot が使用されるが、 pkg_add だと 使用されない。

$ ftp ftp://ftp.freebsd.org/pub/FreeBSD/ports/i386/packages-8.0-release/Latest/

ftp> ls ./ pkg-list.txt

cat >> ~/.cshrc
# prompt (root)
#set prompt = "\n%{\e[32m%}[%{\e[0m%}%n%{\e[1;36m%}@%{\e[0m%}%{\e[1;31m%}%m%}%{\e[0;32m%}]%{\e[33m%}%{\e[1;32m%}[%Y/%W/%D %T]\n%{\e[0;33m%}%/\n%{\e[00m%}%# "
# prompt (user)
set prompt = "\n%{\e[32m%}[%{\e[0m%}%n%{\e[1;36m%}@%{\e[0m%}%{\e[1;31m%}%m%}%{\e[0;32m%}]%{\e[33m%}%{\e[1;32m%}[%Y/%W/%D %T]\n%{\e[0;33m%}%/\n%{\e[00m%}%{\e[1;35m%}%#%{\e[0;37m%}$ "

# ls 候補表示
set autolist
# 色
#set color; alias ls ls-F
alias ls ls -G
# alias
unalias ll
alias ll ls -l
# Ctrl-D でログアウトしない
set ignoreeof
# 履歴
set history  = 10000
set savehist = 10000
set savehist = (10000 merge)

# locale
setenv LANG ja_JP.UTF-8
# ---
# setenv LANGUAGE ja_JP.UTF-8
# setenv LC_ALL ja_JP.UTF-8

^D
source ~/.cshrc

http://www.jp.freebsd.org/

FreeBSD をインストールするためのイメージをダウンロード
wget ftp://ftp8.jp.freebsd.org/pub/FreeBSD/ISO-IMAGES-i386/8.0/8.0-RELEASE-i386-bootonly.iso
(これはbootonlyのイメージ)

wgetで再帰ダウンロードを行う

$ wget -c -N -r --level=1 -np ftp://ftp.rfc-editor.org/in-notes/

  -c,  --continue           部分的にダウンロードしたファイルの続きから始める
  -N,  --timestamping       ローカルにあるファイルよりも新しいファイルだけ取得する
  -r,  --recursive          再帰ダウンロードを行う
  -l,  --level=NUMBER       再帰時の階層の最大の深さを NUMBER に設定する (0 で無制限)
  -np, --no-parent          親ディレクトリを取得対象にしない

サービス起動

$ sudo svc -u /service/demo/

サービス停止

$ sudo svc -d /service/demo/

サービスの再起動

$ sudo svc -t /service/demo/

サービスとログの停止

$ sudo svc -d /service/demo/ /service/demo/log/

サービスとログの起動

$ sudo svc -u /service/demo/ /service/demo/log/

全ての サービスとログの停止

$ sudo svc -d /service/* /service/*/log

全ての サービスとログの起動

$ sudo svc -u /service/* /service/*/log

 

前回の記事「daemontools で プログラムをデーモン化する。 (1) インストールする。」に引き続き、サービスの登録準備をします。

サービスのディレクトリの作成とデーモン化したいプログラムの用意

$ sudo mkdir /var/daemontools

この下にサービス名でディレクトリを作っていくことになる。

デーモン化したいプログラム例:

$ cat /home/suzu/work/demo_daemon.pl
#!/bin/env perl
# デモ
$|=1;

our $sigDown = '';
$SIG{TERM} = $SIG{INT} = sub {$sigDown = shift;};

our $sigUser = '';
$SIG{USR1} = $SIG{USR2} = sub {$sigUser = shift;};

print "[UP]\n";
our $count = 0;
while(1){
    $count++;
    print "COUNT: $count\n";
    $sigDown and warn("[SIG-$sigDown]\n"), last;
    $sigUser and warn("[SIG-$sigUser]\n"), $sigUser='';
    sleep 1;
}
printf "[DOWN]\n";

__END__

上記のデモプログラムを登録するために /var/daemontools の下にPATHを用意。

$ sudo mkdir -p /var/daemontools/demo/log

サービス起動用スクリプトを用意

$ cat > /var/daemontools/demo/run
#!/bin/sh
exec 2>&1
exec /home/suzu/work/demo_daemon.pl

$ chmod 775 /var/daemontools/demo/run

ログ出力用スクリプトを用意

$ cat > /var/daemontools/demo/log/run
#!/bin/sh
exec multilog t  -'*' +'*COUNT*' ./count  -'*' +'*[SIG-*' ./sig   +'*' ./main

$ chmod 775 /var/daemontools/demo/log/run

サービス登録と動作確認

サービス登録前のプロセス

$ ps axf
20787 ?        Ss     0:00 /bin/sh /command/svscanboot
20789 ?        S      0:00  \_ svscan /service
20790 ?        S      0:00  \_ readproctitle service errors:

サービス登録

$ sudo ln -s /var/daemontools/demo/ /service/

サービス登録後のプロセス

$ ps axf
20787 ?        Ss     0:00 /bin/sh /command/svscanboot
20789 ?        S      0:00  \_ svscan /service
30156 ?        S      0:00  |   \_ supervise demo
30159 ?        S      0:00  |   |   \_ perl /home/suzu/work/demo_daemon.pl
30157 ?        S      0:00  |   \_ supervise log
30245 ?        S      0:00  |       \_ multilog t -* +*COUNT* ./count -* +*[SIG-* ./sig +* ./main
20790 ?        S      0:00  \_ readproctitle service errors: ...pervise: fatal: unable to start log/run: access denied?supervise: fatal: unable to start log/run: access denied?supervise: fatal: unable to s

ログ確認

$ tai64nlocal < /var/daemontools/demo/log/main/current
$ tai64nlocal < /var/daemontools/demo/log/count/current
$ tai64nlocal < /var/daemontools/demo/log/sig/current

シグナルを送ってみる。

シグナル送信状況をログで確認しながら

$ tail -f /var/daemontools/demo/log/main/current | tai64nlocal

シグナル送信

$ sudo pkill -USR1 -f demo_daemon

ログの例

2009-11-07 07:49:34.327045500 COUNT: 5
2009-11-07 07:49:35.327809500 COUNT: 6
2009-11-07 07:49:36.328742500 COUNT: 7
2009-11-07 07:49:36.406393500 COUNT: 8
2009-11-07 07:49:36.406398500 [SIG-USR1]
2009-11-07 07:49:37.403580500 COUNT: 9
2009-11-07 07:49:38.404430500 COUNT: 10
2009-11-07 07:49:39.405269500 COUNT: 11

停止

$ sudo svc -d /service/demo/

停止後のプロセス

$ ps axf
0787 ?        Ss     0:00 /bin/sh /command/svscanboot
20789 ?        S      0:00  \_ svscan /service
30156 ?        S      0:00  |   \_ supervise demo
30157 ?        S      0:00  |   \_ supervise log
30245 ?        S      0:00  |       \_ multilog t -* +*COUNT* ./count -* +*[SIG-* ./sig +* ./main
20790 ?        S      0:00  \_ readproctitle service errors: ...pervise: fatal: unable to start log/run: access denied?supervise: fatal: unable to start log/run: access denied?supervise: fatal: unable to s

PerlでSSL対応IRCサーバーの作り方」にある、IRCサーバーをデーモン化するために、実は次の様なコマンドでバックグラウンドで動かしてました。

./poe_irc_server 2>&1 | perl -ne 'BEGIN{$|=1};(/^..P[I|O]NG/ or /<-:irc.arbolbell.jp 372/) or print(scalar(localtime)." # ".$_)'  >> $HOME/logs/ircd.txt &

そんな事はせずとも、daemontools は、デーモン化も、プロセス監視とプロセス自動起動も、そしてログの面倒まで見てくれる。なんとも素晴らしいツールです。

そして、インストールすると

$ tail -n1 /etc/inittab
SV:123456:respawn:/command/svscanboot

という事で、何かしらの不手際により daemontools 自体がダウンしたとしても、直ぐに起動して管理下のサービスをデーモン化してくれます。
ですので、何が何でも起動していてほしいシステムを daemontools でデーモン化して管理しておけば、無問題。

◆ソースの取得とインストール

$ cd /tmp/
$ wget http://cr.yp.to/daemontools/daemontools-0.76.tar.gz

$ cd /usr/local/
$ sudo tar xzvf /tmp/daemontools-0.76.tar.gz
$ cd /usr/local/admin/daemontools-0.76/

コンパイルオプションの修正

$ sudo vim src/conf-cc

変更内容

$ diff src/conf-cc /tmp/admin/daemontools-0.76/src/conf-cc
1c1
< gcc -O2 -Wimplicit -Wunused -Wcomment -Wchar-subscripts -Wuninitialized -Wshadow -Wcast-qual -Wcast-align -Wwrite-strings --include=/usr/include/errno.h
---
> gcc -O2 -Wimplicit -Wunused -Wcomment -Wchar-subscripts -Wuninitialized -Wshadow -Wcast-qual -Wcast-align -Wwrite-strings

インストール

$ sudo package/install

確認

$ ls -lt /
合計 156
drwxr-xr-x   2 root root  4096 11月  5 23:43 command
drwxr-xr-x  90 root root 12288 11月  5 23:43 etc
drwxr-xr-x   2 root root  4096 11月  5 23:43 service
drwxrwxrwt   8 root root  4096 11月  5 23:43 tmp
drwxr-xr-x  11 root root  3960 10月 19 00:05 dev
drwxr-x---  10 root root  4096 10月 15 14:31 root
drwxr-xr-x   2 root root 12288 10月 15 04:10 sbin
drwxr-xr-x  14 root root  4096 10月 15 04:09 lib
drwxr-xr-x   7 root root  4096  9月 18 19:55 home
drwxr-xr-x  11 root root     0  5月  8 15:11 sys
dr-xr-xr-x 116 root root     0  5月  8 15:11 proc
drwxr-xr-x   2 root root  4096  5月  8 06:12 media
drwxr-xr-x   2 root root     0  5月  8 06:12 net
drwxr-xr-x   2 root root     0  5月  8 06:12 misc
drwx------   2 root root 16384 11月 27  2008 lost+found
drwxr-xr-x   2 root root  4096 11月 27  2008 bin
drwxr-xr-x  22 root root  4096 11月 26  2008 var
drwxr-xr-x   3 root root  4096 11月 26  2008 boot
drwxr-xr-x  14 root root  4096 11月 26  2008 usr
drwxr-xr-x   2 root root  4096 11月 26  2008 selinux
drwxr-xr-x   2 root root  4096  3月 30  2007 mnt
drwxr-xr-x   2 root root  4096  3月 30  2007 opt
drwxr-xr-x   2 root root  4096  3月 30  2007 srv

$ ls -lt /command/
合計 0
lrwxrwxrwx 1 root root 43 11月  5 23:43 envdir -> /usr/local/admin/daemontools/command/envdir
lrwxrwxrwx 1 root root 46 11月  5 23:43 envuidgid -> /usr/local/admin/daemontools/command/envuidgid
lrwxrwxrwx 1 root root 43 11月  5 23:43 fghack -> /usr/local/admin/daemontools/command/fghack
lrwxrwxrwx 1 root root 45 11月  5 23:43 multilog -> /usr/local/admin/daemontools/command/multilog
lrwxrwxrwx 1 root root 45 11月  5 23:43 pgrphack -> /usr/local/admin/daemontools/command/pgrphack
lrwxrwxrwx 1 root root 50 11月  5 23:43 readproctitle -> /usr/local/admin/daemontools/command/readproctitle
lrwxrwxrwx 1 root root 44 11月  5 23:43 setlock -> /usr/local/admin/daemontools/command/setlock
lrwxrwxrwx 1 root root 46 11月  5 23:43 setuidgid -> /usr/local/admin/daemontools/command/setuidgid
lrwxrwxrwx 1 root root 46 11月  5 23:43 softlimit -> /usr/local/admin/daemontools/command/softlimit
lrwxrwxrwx 1 root root 46 11月  5 23:43 supervise -> /usr/local/admin/daemontools/command/supervise
lrwxrwxrwx 1 root root 40 11月  5 23:43 svc -> /usr/local/admin/daemontools/command/svc
lrwxrwxrwx 1 root root 41 11月  5 23:43 svok -> /usr/local/admin/daemontools/command/svok
lrwxrwxrwx 1 root root 43 11月  5 23:43 svscan -> /usr/local/admin/daemontools/command/svscan
lrwxrwxrwx 1 root root 47 11月  5 23:43 svscanboot -> /usr/local/admin/daemontools/command/svscanboot
lrwxrwxrwx 1 root root 43 11月  5 23:43 svstat -> /usr/local/admin/daemontools/command/svstat
lrwxrwxrwx 1 root root 43 11月  5 23:43 tai64n -> /usr/local/admin/daemontools/command/tai64n
lrwxrwxrwx 1 root root 48 11月  5 23:43 tai64nlocal -> /usr/local/admin/daemontools/command/tai64nlocal

後かたずけ

$ rm /tmp/daemontools-0.76.tar.gz