第１５回　Raspberry Pi で監視カメラを作ろう！　～アプリの自動起動編～

Raspberry Piと専用のカメラモジュールを使用し、ONVIF対応の監視カメラを作成する[シリーズ記事](https://qiita.com/lis-hanzomon/items/cc1f7f316fbeb9579b28)です。
本記事は[リンク情報システム株式会社](https://www.lis.co.jp/)の有志が作成しています。

---

Raspberry Piの起動と共に監視カメラ映像配信アプリを自動で開始できるようにします。

#アプリの自動起動
今回使用しているOSはRaspbianというdebianベースのLinuxです。
Linuxで一般的に自動で起動するアプリケーションの事をデーモンと呼びます。
そこで、監視カメラ映像配信アプリをデーモンに改造し、自動起動できるようにします。

デーモンの作成や起動/停止について、銀の弾丸さんの記事を参考にさせて頂きました。
参考元：[ラズパイで自動起動するデーモンを自作する - 銀の弾丸](http://takamints.hatenablog.jp/entry/2015/06/07/211150)

###デーモン作成
デーモン作成の流れは以下のようになります。
　1.デーモンプロセスの生成
　2.ログ(syslog)の出力
　3.プロセスIDをファイルへ保存
　4.SIGTERMで終了

参考記事に紹介されているdaeomonize.c を元に、ポイントとなる実際の処理を抜粋して解説します。

#####1.デーモンプロセスの生成 (daemonize関数)
Linuxに用意されている、デーモンを生成するためのdaemonという関数を実行します。
daemon関数を実行したプロセスはforkしてから終了するそうなので、daemon関数を実行した時点でプログラムがデーモンに変化した事になります。

```cpp
if (daemon(0, 0) != -1) {
```

#####2.ログ(syslog)の出力 (daemonize関数)
デーモンはターミナルとは切り離されているため、ユーザーと直接対話する事ができません。そのため、エラー発生や動作状態等の情報はログ(syslog)に出力することになります。

```cpp
/* syslog_ident, = "redbrick" */
/* syslog_option = LOG_PID */
/* syslog_facility = LOG_DAEMON */
openlog(syslog_ident, syslog_option, syslog_facility);
```

#####3.プロセスIDをファイルへ保存 (daemonize関数)
起動や停止する対象(デーモン)を特定するためにプロセスIDを使用します。そのため、ファイルにプロセスIDを出力しておきます。

```cpp
if(pidfilepath) {
  FILE* pidfile = fopen(pidfilepath, "w+");
  if (pidfile) {
    int pid = getpid();
    fprintf(pidfile, "%d\n", pid);
    fclose(pidfile);
  } else {
    syslog(LOG_ERR,
      "daemonize() : failed to write pid.\n");
  }
}
```

####4.SIGTERMで終了 
デーモン終了時は、SIGTERMが送信されます。
ですので、デーモン形式のプログラムは、SIGTERMを受け取る準備を行ってから、目的の処理を行い、SIGTERMを受け取った時点で、処理を終了するようにします。

```cpp
static int terminate = 0;
static void signal_handler(int signal_number)
{
   terminate = 1;
}

static int MainLoop()
{
    signal(SIGTERM, signal_handler); 
    while(terminate == 0)
    {
        // 何らかの処理を行う
        sleep(1);
    }
    signal(SIGTERM, NULL);
}
```

###デーモン起動/停止スクリプト作成
デーモンの起動/停止を行う為には、スクリプトを用意する必要があります。
スケルトン（/etc/init.d/skeleton）をコピーしてデーモン起動/停止スクリプト（/etc/init.d/redbrick）を作成します。

```sh
#!/bin/sh
# kFreeBSD do not accept scripts as interpreters, using #!/bin/sh and sourcing.
if [ true != "$INIT_D_SCRIPT_SOURCED" ] ; then
    set "$0" "$@"; INIT_D_SCRIPT_SOURCED=true . /lib/init/init-d-script
fi
### BEGIN INIT INFO
# Provides:          redbrick
# Required-Start:    $remote_fs $syslog
# Required-Stop:     $remote_fs $syslog
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: Example initscript
# Description:       This file should be used to construct scripts to be
#                    placed in /etc/init.d.  This example start a
#                    single forking daemon capable of writing a pid
#                    file.  To get other behavoirs, implemend
#                    do_start(), do_stop() or other functions to
#                    override the defaults in /lib/init/init-d-script.
### END INIT INFO

DESC="RedBrick Onvif Camera service"
NAME=redbrick
DAEMON=/usr/bin/redbrick
DAEMON_ARGS=""
PIDFILE=/var/run/$NAME.pid
SCRIPTNAME=/etc/init.d/$NAME
```

「# Provides」、「DESC」、「NAME」を監視カメラ映像配信アプリの名称に書き換えます。
「DAEMON」には監視カメラ映像配信アプリのパスを設定します。
「DAEMON_ARGS」はパラメータを設定しますが、監視カメラ映像配信アプリには不要なので、空文字にします。
「PIDFILE」はプロセスIDを保存したファイル名を設定します。
「SCRIPTNAME」は編集しているデーモン起動/停止スクリプトファイル名が設定されていれば、変更の必要はありません。

###自動起動の登録
スクリプトが完成したら、insservコマンドで自動起動の設定を登録します。

```sh
$ sudo insserv redbrick
```

自動起動が登録されると各ランレベルのディレクトリにスクリプトのシンボリックリンクが作成されます。
lsコマンドなどでリンクが作成されていることを確認してください。

```sh
$ ls -l /etc/rc3.d/
S03redbrick
```

"S～" が作成されている場合は、自動起動の対象となっている事を意味します。
自動起動が無効になっていると"K～" となります。

###自動起動の確認
rebootコマンドで再起動すれば、自動起動します。
起動できているかは、statusコマンドで確認できます。

```sh
$ sudo /etc/init.d/redbrick status
[ ok ] redbrick is running.
```

---
[インデックス記事へ](https://qiita.com/lis-hanzomon/items/cc1f7f316fbeb9579b28)
[第１４回記事へ](https://qiita.com/lis-hanzomon/items/7454627183cf8ce9e9e8)
[第１６回記事へ](https://qiita.com/lis-hanzomon/items/7c4eba19e256ace5fde7)

---
[リンク情報システム株式会社](https://www.lis.co.jp)では一緒に働く仲間を[随時募集](https://www.lis.co.jp/employ_top)しています！
また、お仕事のご依頼、ビジネスパートナー様も募集しております。[お気軽にご連絡](https://www.lis.co.jp/inquiry)ください。