coredump したら牛に怒られる仕組み(devd 芸)

![IMG_6253.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103137/c65e2771-c7f9-67d7-f4d3-3e2705784881.jpeg)

# devd は(結構)なんでも知っている
[FreeBSD で、USB機器を接続したタイミングでなんかコマンドを実行(devd設定)](https://qiita.com/s_mitu/items/7cb839a065a17d28dbfd) で、devd の設定したら USB の接続のタイミングを取得し、コマンド実行ができるという記事を書きました。
devd の取れるイベントは様々です。実際の実例は、設定ファイルである /etc/devd.conf を見ればわかります。

```/etc/devd.conf
notify 0 {
        match "system"          "IFNET";
        match "type"            "LINK_UP";
        media-type              "ethernet";
        action "service dhclient quietstart $subsystem";
};
```
WiFi ネットワークがLink-up したら、dhclient を立ち上げるというのをここで設定しています。


```devd.conf
# Notify all users before beginning emergency shutdown when we get
# a _CRT or _HOT thermal event and we're going to power down the system
# very soon.
notify 10 {
        match "system"          "ACPI";
        match "subsystem"       "Thermal";
        match "notify"          "0xcc";
        action "logger -p kern.emerg 'WARNING: system temperature too high, shutting down soon!'";
};
```
ACPIの温度情報で、高温になったら syslog に警告を出すという設定をしています。

kernel の検知した情報とユーザーランドをつなぐ役割を devd が果たしていることがわかる思います。

# プログラムが coredump したこともわかる
/etc/devd.conf の下の方には、コメントアウトの状態でいくつかの設定例が書いてあります。その中に

```devd.conf
# Handle userland coredumps.
# This commented out handler makes it possible to run an
# automated debugging session after the core dump is generated.
# Replace action with a proper coredump handler, but be aware that
# it will run with elevated privileges.
notify 10 {
        match "system"          "kernel";
        match "subsystem"       "signal";
        match "type"            "coredump";
        action "logger $comm $core";
};

```

ユーザーランドのコマンドが coredump したタイミングも取得できるようです。普通はデバッグ目的に使う設定でしょうが、面白そうなので遊びで使ってみます。

# 単純にdevdを設定しただけでは動かない

しかし試しに設定してみても設定したコマンドが実行されません。man devd や man devd.conf でも特に注意書きは見当たりません。
しかしここは FreeBSD ユーザーの野生の勘(とは？)で sysctl にスイッチがあるんじゃねーかと見てみると、それっぽいのがありました。"kern.coredump_devctl"という項目です。デフォルトが 0 なので、root 権限で

```sysctl 
sysctl kern.coredump_devctl=1
```
としてやると、イベント取得がされるようになりました。
sysctl 設定は再起動すると消えるので、常時 on にするには /etc/sysctl.conf に書いておく必要がありますが、こんな機能はセキュリティ的に危険なので、デバッグ目的や娯楽目的以外で on にする必要はないでしょう。

# 実例

RaspberryPi 3B+ で、coredump したら X に牛が登場して怒られる設定をしてみました。無意味です。
aarch64 環境ですが、amd64 など他のアーキテクチャでも基本的な同様です。
[![牛おこられ実行動画](http://img.youtube.com/vi/XTZobU4TCe8/0.jpg)](https://www.youtube.com/watch?v=XTZobU4TCe8)

# 設定

まずは coredump してしまうだめなプログラムを用意します。

```dame.c
int main()
{
    char kara[0];
    int i;
    for (i = 0; i < 2000; i++) {
        kara[i] = 0;
    }
    return 0;
}
```
全然確保されてない配列に容赦なくデータを入れまくります。だめですね。
ですがさすが C 言語、当然ながらclangでも警告一つ出ずにコンパイルされ　dame プログラムが作成されました。

```
$ cc -Wall -o dame dame.c
```

怒ってくれる牛さんは game/xcowsay というコマンドで登場させます。

```
$ xcowsay こんばんは
```
こんな感じでコマンドを実行すると、「こんばんわ」が書かれた吹き出し付きの牛が X に登場します。

インストールは pkg で基本通りです。

```
pkg install game/xcowsay
```

devd の設定は coredump.conf というファイルを /etc/devd/ 以下に

```/etc/devd/coredump.conf
notify 100 {
        match "system"          "kernel";
        match "subsystem"       "signal";
        #match "type"            "coredump";
        action  "su freebsd -c 'env DISPLAY=:0 /usr/local/bin/xcowsay だめじゃん '$comm &";
};
```

新規作成して行います。action 行の freebsd はユーザー名(RaspberryPi のFreeBSD用イメージでデフォルトの一般ユーザー)で、X を使用しているユーザーを決め打ちして指定しています。そして DISPLAY 環境変数に :0 を設定して、自ホストの画面0でウィンドウを開くように指定します。時間のかかる処理は & でバックグラウンド実行指定しないと起動に失敗します。これで、xcowsay のウィンドウが表示されます。
動画ではそれだけだとちょっとさみしいので、[openjtalk](http://open-jtalk.sourceforge.net/)(野良ビルド)で喋らせる処理も呼び出しています。

# devd は縁の下の力持ち
coredump したらなんかコマンドが起動しちゃうのがなんか個人的に面白かったのでこんなネタにしてみました。devd の話というのをあまり見ないけど、kernel と userland をつなぐ結構重要な役割かなぁということでちょっと取り上げてみました。ハード寄りな機能の実現や問題の解決などで、こういうデーモンが動いてるんだよなぁと思い出したら、いい方針が見つかったりするかもしれません。