Intel Edison に InfluxDB をインストールする方法

http://influxdb.com/download/から最新版をダウンロードします。
Go もインストールしてあるのでソースからビルドしても良いかと思ったのですが、意外とビルド方法が難しそうだったので linux/386 版のバイナリパッケージを利用することにしました。

パッケージをダウンロードしたら、それを /home/root/opt/influxdb 以下に展開します。
(Edison は / 以下は容量が少ないので、容量の多い /home 以下にダウンロードして展開する必要があります。また、あとで設定ファイルを編集する手間のことを考えると ~~/opt/influxdb というディレクトリになるようにしておいたほうが良いと思います。ということで私は /home/root/opt/influxdb 以下に展開しました。)

展開したら、以下の様なツリー構造になります。

~/opt/influxdb# tree
.
|-- benchmark_config.toml
|-- config.toml
|-- influxdb
|-- influxdb-benchmark
|-- scripts
|   |-- influxdb-daemon.sh
|   |-- init.sh
|   `-- post_install.sh
`-- shared
    |-- data
    |   |-- db
    |   |   `-- shard_db_v2
    |   |-- raft
    |   |   |-- conf
    |   |   |-- log
    |   |   |-- name
    |   |   `-- snapshot
    |   `-- wal
    |       `-- bookmark
    `-- log.txt

(tree コマンドは The Tree Command for Linux Homepage からダウンロードして make して使用しました)


展開したら、influxdb という実行ファイルがあるのでそれを実行してみましょう。
おそらく、libbz2.so.1 が見つからないとかでエラーになってしまうはずです。

ldd コマンドで確認してみても、

# ldd influxdb
	linux-gate.so.1 (0xb777f000)
	librt.so.1 => /lib/librt.so.1 (0x41815000)
	libm.so.6 => /lib/libm.so.6 (0x417c6000)
	libz.so.1 => /lib/libz.so.1 (0x417ae000)
	libbz2.so.1 => not found
	libpthread.so.0 => /lib/libpthread.so.0 (0x41790000)
	libgcc_s.so.1 => /lib/libgcc_s.so.1 (0x41a3f000)
	libc.so.6 => /lib/libc.so.6 (0x41618000)
	/lib/ld-linux.so.2 (0x415e9000)

という具合に not found になっています。

Edison には opkg で bzip2 や libbz2 などがすでにインストールされていたのですが、find コマンドで検索してみても libbz2.so.1 というファイルは見つかりません。

bzip2 コマンドは正常に動作しているので libbz2 はインストールされているはずなのですが、、、

試しに bzip2 コマンドを ldd で確認してみると

# ldd /usr/bin/bzip2
	linux-gate.so.1 (0xb773c000)
	libbz2.so.0 => /usr/lib/libbz2.so.0 (0x41b48000)
	libc.so.6 => /lib/libc.so.6 (0x41618000)
	/lib/ld-linux.so.2 (0x415e9000)

となっていましたので、どうやら libbz2.so.0 は存在しますが libbz2.so.1 が存在しないようです。

仕方がないので古いバージョンの libbz2.so.0 で新しいバージョンの libbz2.so.1 を肩代わりさせてみましょう・・・

# ls -la /usr/lib/libbz2.so*
lrwxrwxrwx    1 root     root            15 Oct 14 13:32 libbz2.so -> libbz2.so.0.0.0
lrwxrwxrwx    1 root     root            15 Oct 14 13:32 libbz2.so.0 -> libbz2.so.0.0.0
-rwxr-xr-x    1 root     root         76100 Oct  9 09:11 libbz2.so.0.0.0
# cd /usr/lib && ln -s libbz2.so.0.0.0 libbz2.so.1
# ls -la /usr/lib/libbz2.so*
lrwxrwxrwx    1 root     root            15 Oct 14 13:32 /usr/lib/libbz2.so -> libbz2.so.0.0.0
lrwxrwxrwx    1 root     root            15 Oct 14 13:32 /usr/lib/libbz2.so.0 -> libbz2.so.0.0.0
-rwxr-xr-x    1 root     root         76100 Oct  9 09:11 /usr/lib/libbz2.so.0.0.0
lrwxrwxrwx    1 root     root            15 Dec 25 09:31 /usr/lib/libbz2.so.1 -> libbz2.so.0.0.0

influxdb を展開したディレクトリに戻り、

# influxdb
Couldn't parse configuration file: config.sample.toml
[12/25/14 09:31:56] [INFO] Loading configuration file config.sample.toml
open config.sample.toml: no such file or directory

一応動きました・・・が、これがちゃんと期待通りに動くという保証はありません。
それに、config.sample.toml というファイルが見つからないというエラーになってしまいました。

そこで、config ファイルを用意します。

influxdb の実行ファイルと同じディレクトリに config.toml というファイルがありますので、これを開いて編集し、ファイルの内容で /opt/influxdb/〜〜 というパスになっている箇所をすべて /home/root/opt/influxdb/〜〜 に書き換えます。(/home/root を付け加える)

編集したら、以下のように config ファイルをオプションで指定して起動します。

~/opt/influxdb# ./influxdb -config ./config.toml
[12/28/14 14:36:42] [INFO] Loading configuration file ./config.toml

+---------------------------------------------+
|  _____        __ _            _____  ____   |
| |_   _|      / _| |          |  __ \|  _ \  |
|   | |  _ __ | |_| |_   ___  _| |  | | |_) | |
|   | | | '_ \|  _| | | | \ \/ / |  | |  _ <  |
|  _| |_| | | | | | | |_| |>  <| |__| | |_) | |
| |_____|_| |_|_| |_|\__,_/_/\_\_____/|____/  |
+---------------------------------------------+

上記のようにロゴのバナーが現れたら成功です。

この状態で Web ブラウザを開、Edison のアドレスの 8083 番ポートにアクセスしてみましょう。
f:id:bearmini:20141229002521p:plain

このような管理画面が現れれば成功です。
あとは Series にデータを追加したりしていきましょう。

Intel Edison で動かした Arduino のスケッチを停止・削除する方法

Edison を入手して、「"Lチカ" してみました!」という記事は世の中に履いて捨てるほどありますが、じゃあそのアップロードしたプログラムを消去したい場合はどうすればよいの?と思って調べてみるも、なかなか第一次情報ソースに行き当たりません。

Intel Edison Kit for Arduino

Intel Edison Kit for Arduino

ですが、Edison のコンソールに接続して top コマンドなどを見るとすぐにどうすればよいかがわかります。

/sketch/sketch.elf というファイルが実行されており、CPUを多少消費しているではありませんか。
すぐにそのプロセスを kill して、/sketch/sketch.elf を削除(ついでに/sketch/sketch.elf.old というファイルもあったので削除)しました。

本当にこの方法で良いかどうかはわかりませんが、とりあえず大丈夫そうです。


空のスケッチを書き込めば良いと書いていた記事もありましたが、それをやってみたところ /sketch/sketch.elf の CPU 使用率が50% になってしまいました!
これは、Edison の持っている 2 つの CPU コアのうち 1 つを無駄に空の無限ループで使いきってしまっているということを意味します。空のスケッチを実行するということはそういうことになりますよね。
ということでこの方法は使えません。

Intel Edison に Go をインストールする方法

Go はクロスコンパイルが簡単で、出来上がったバイナリの配布も簡単なので、わざわざ Edison 上で Go コンパイラを動かす必要もないのですが、、、
やってみたかったからやってみただけです。

Intel Edison Kit for Arduino

Intel Edison Kit for Arduino


大まかに分けて以下の3ステップでインストールを行います。
Edison 自体のセットアップは終わっているという人は 0. は飛ばして 1. からやってください。

0. Edison 自体のセットアップ
1. 依存パッケージのインストール
2. Go のインストール

0. Edison 自体のセットアップ

Edison のセットアップは、組み込み機器と考えるとかなりラクな方で、

公式サイト


スタートアップ Intel Edison - Qiita

Kindle 本 The Hands-on Intel Edison Manual Lab (English Edition)

The Hands-on Intel Edison Manual Lab (English Edition)

The Hands-on Intel Edison Manual Lab (English Edition)

あたりの手順にしたがってセットアップすれば特に難しいことはないと思います。

私の環境は Windows だったので、まずは PC にドライバをインストールして、USB ケーブル2本を Edison に接続(一本は電源供給+USBメモリのようなデバイスとして見るため、もう一本はUSBシリアルでコンソールにつなぐため)、最新版のファームウェアに更新します。

ファームウェアの更新方法はいたって簡単で、Edison と PC を USB で接続、Edison という名前の外付けドライブとして見えますのでそこに Intel のサイトからダウンロードしてきた最新版のファームを展開し、シリアルコンソールから

$ reboot ota

というコマンドを実行してしばらく待つのみです。

Edison が勝手に再起動したらファームが最新版になってるはずなので、同じくシリアルコンソールで

$ cat /etc/version
$ configure_edison --version

などで確認します。

最後に

$ configure_edison --setup

を実行して、ホスト名/root のパスワード/WiFi 接続 のセットアップを行います。

この時点で nodejs とか python とかが使える状態です。
PC から Edison に ssh で接続もできるはずです。
(名前解決に mDNS を使うので、Windows であれば iTunes をインストールする必要があるかもしれません。iTunes 本体は不要なのですが、一緒にインストールされる Bonjour が必要です。)

以下の作業は ssh 経由でもシリアルコンソールでもどちらで実施しても構わないと思います。

1. 依存パッケージのインストール

Go をソースからビルドしてインストールするには bash スクリプトを動かす必要があるのですが、bash はデフォルトでは Edison にインストールされていません。 (標準では ash というシェルがインストールされ使われているようです)
Edison には opkg というパッケージマネージャが用意されていますのでそれを用いてインストールします。

ということで、まずは opkg 自体をセットアップします。opkg コマンド自体は最初からインストールされていますが、opkg が参照するリポジトリの設定をする必要があります。
以下の2つのファイルを編集して(なければ作成して)以下のような内容にします。

/etc/opkg/base-feeds.conf

src/gz all http://repo.opkg.net/edison/repo/all
src/gz edison http://repo.opkg.net/edison/repo/edison
src/gz core2-32 http://repo.opkg.net/edison/repo/core2-32

/etc/opkg/intel-iotdk.conf

src intel-iotdk http://iotdk.intel.com/repos/1.1/intelgalactic
src intel-all http://iotdk.intel.com/repos/1.1/iotdk/all
src intel-i586 http://iotdk.intel.com/repos/1.1/iotdk/i586
src intel-x86 http://iotdk.intel.com/repos/1.1/iotdk/x86

以下のコマンドを実行します。

$ opkg update
$ opkg upgrade
$ opkg install bash

2. Go をインストール

まず Go のソース(linux/386)をダウンロードします。
Edisonは / の空き容量が少ないため、空き容量の大きい /home 以下で作業を行う必要があります。
ダウンロード先もインストール先も /home 以下にする必要があります。(以下の例では /home/root にダウンロードして /home/root/go に展開・インストールされます)

$ cd /home/root
$ wget https://storage.googleapis.com/golang/go1.4.linux-386.tar.gz
$ tar xzf go1.4.linux-386.tar.gz

この記事を書いた時点では 1.4 が最新なので上記のファイル名になります。新しいバージョンがでたら新しいバージョンで適宜読み替えてください。

Go のビルドを行います。

$ cd go/src
$ ./make.bash

ビルドに成功したら、あとはパスを通して・・・

$ vi ~/.profile
export PATH=$PATH:~/go/bin
$ . .profile

go コマンドを実行します。

$ go version
go version go1.4 linux/386

Android L Preview のデバイスで Heads-up Notification を表示する方法

注:この記事は 2014年 7 月上旬現在の Android L Preview の ROM イメージおよび SDK の内容に基づいて書かれています。Android L が正式バージョンとしてリリースされるまでの間に、この記事の内容は obsolete になるかもしれません。


Android L Preview では新しい通知の種類として Heads-up Notification が追加されました。
Heads-up Notification についての詳細は以下のページ内で "Heads-up Notification" を検索してみてください。
https://developer.android.com/preview/notifications.html

さて、この Heads-up Notification は電話着信時に出ることがわかっていますが、自分のアプリからも出したい場合どうすればよいかということがまだ公式のドキュメントには書かれていないようです。
いろいろやって調べた結果、そもそも必要な定数が @hide されていたり API リファレンスに載っているメソッド名が間違っていたりしたので大変でしたが 自分のアプリから Heads-up Notification を出すことができましたのでその方法を紹介します。

手順としては、以下の様な感じになります。

  1. 実行環境の API Level から、そもそも Heads-up Notification を出せるかどうかを調べる。
  2. Notification.Builder で Notification を構築する。このとき、設定しなければならないパラメータに一定の決まりがある。
  3. NotificationManager で表示する。

大事なのは、Notification を構築するときに与えるオプションですね。
今のところ、Notification.Builder で以下のメソッドの呼び出しが必須であることがわかっています。

  • 通常の Notification を出すために最低限必要なオプション
    • setContentTitle()
    • setContentText()
    • setSmallIcon()
  • Heads-up Notification を出すために最低限必要なオプション
    • setPriority()
    • setFullScreenIntent()
    • setOngoing()
    • setExtras()

この中で、手強いのは setPriority() と setExtras() です。setFullScreenIntent() に指定するのは空のインテントでも良いようです。

まず、setPriority() には Notification.PRIORITY_HIGH を指定する必要があるのですが、どうも Eclipse ADT で開発しているとこのような値は認識されていないようでビルドできません。SDK も ADT も最新バージョン(r23.0.2)に上げているのですが・・・
仕方ないので AOSP のソースを見るとその値が 1 であることがわかるのでそれを直接指定します。

次に setExtras() ですが、これはこのようなメソッドは無いと言われますのでリフレクションで呼び出します。(ちなみに、API リファレンスには addExtras() という違う名前のメソッドが載っています。これも Eclipse からは認識されていません)
setExtras() の引数には Bundle を指定します。Bundle の中身としては、Notification.EXTRA_AS_HEADS_UP をキーとして int 型の値 Notification.HEADS_UP_REQUESTED を指定します。しかし、これらの値もお察しの通り存在しないと言われてしまいます(これは AOSP を見ると @hide が指定されているので明示的に隠されています)のでこれまた AOSP のソースを見てそれぞれ "headsup" および 2 という値を知り、それらを直接指定します。

@SuppressLint("NewApi")
private void showHeadsupNotification(int id) {
    if (Build.VERSION.SDK_INT < 20) {
        Log.i(TAG, "Heads-up Notification is not supported.");
        return;
    }

    Bundle b = new Bundle();
    b.putInt(/* Notification.EXTRA_AS_HEADS_UP */"headsup", /* HEADS_UP_REQUESTED */2);
    Notification.Builder nb = new Notification.Builder(getApplicationContext());
    try {
        Method m = Notification.Builder.class.getMethod("setExtras", Bundle.class);
        m.invoke(nb, b);
    } catch (NoSuchMethodException e) {
        Log.e(TAG, e.getMessage(), e);
    } catch (IllegalArgumentException e) {
        Log.e(TAG, e.getMessage(), e);
    } catch (IllegalAccessException e) {
        Log.e(TAG, e.getMessage(), e);
    } catch (InvocationTargetException e) {
        Log.e(TAG, e.getMessage(), e);
    }

    Notification n = nb
            .setContentTitle("Test Title " + Integer.toString(id))
            .setContentText("test test test")
            .setSmallIcon(R.drawable.ic_launcher)
            .setPriority(1 /* Notification.PRIORITY_HiGH */)
            .setAutoCancel(true)
            .setFullScreenIntent(
                    PendingIntent.getActivity(getApplicationContext(), 0, new Intent(), 0),
                    true).setOngoing(true).build();
    NotificationManager nm = (NotificationManager) getApplicationContext().getSystemService(
            Context.NOTIFICATION_SERVICE);
    nm.notify(id, n);
}    

setExtras() を呼ぶところが不必要に複雑に見えますが、それ以外は特に難しいことはありません。

上記の関数を呼んで表示させた Heads-up Notification がこちら:
f:id:bearmini:20140711152303p:plain


Heads-up Notification は同時に表示されるのは 1 つだけで、あとから表示したほうが勝つようです。(先に表示されていたものは、ステータスバーに引っ込みます)

たとえば電話がかかってきて着信の Heads-up Notification が表示されているときに自分のアプリから Heads-up Notification を出すと、着信のほうが消えて(ステータスバーに格納されて)自分のものが表示されます。

自分のアプリ内で2個以上出そうとしても同様です。最後に表示したものだけが表示されています。
プルダウンするとすべての通知を見ることができます。


ちなみに Android L Preview は Nexus 5 に入れて試しました。


Vim で数のインクリメントやデクリメントをするキーバインド

Vim には Ctrl-A (以後 C-a) を押すとその時カーソルの下にある数をインクリメントしてくれるというプログラマに嬉しいキーバインドがあります。(C-x でデクリメント)

これはたとえば 1 という文字の上で C-a を押すとその文字が 2 になり、続けて押していくと 3, 4, ... と増えていきます。9 の上で C-a を押すと 10 になり、続けて押していくと 11, 12, ... となります。また、3C-a と押すと一気に 3 増やしてくれます。なかなか賢いですね。

それから、-1 の上で C-a を押すと -2 ではなく 0 になるということに今日気づきました。

というのも、1−2 みたいなテキストの上で、2 を 3 に増やそうとして C-a を押したら 1-1 になったのでびっくりして気づいたわけです。(ちなみにそのまま C-a を押し続けると、1-2 => 1-1 => 10 => 11 ってなりました)

あまり内容が無いですが、ちょっと面白かったので書いてみました。

Vim 使いなら誰もが通る道なのかな。

useradd コマンドでユーザのパスワードを指定する方法

スクリプトなどで自動で Linux のユーザを追加して、そのユーザにパスワードまで設定したいということはあると思います。たとえばテスト環境の構築を自動化していてダミーユーザをたくさん作らないといけない場合など、たとえパスワードがバレても特に問題ない場合が当てはまるかと思います。

ちなみに Linuxコマンドラインからユーザを追加したい時に使えるコマンドとして adduser コマンドと useradd コマンドがあってどっちを使ったらいいのか迷ってしまってユーザ泣かせですが、私の認識では両者は基本的に同じことができて、単に adduser コマンドはインタラクティブ、useradd はワンライナー向き、というところで落ち着いています。

adduser コマンドや passwd コマンドなどはユーザのパスワードをコマンドラインオプションから指定できるようになっていません。インタラクティブにプロンプトを表示してエコーなしで(キータイプが表示されない状態で)ユーザに入力させパスワードを設定するようになっています。

コマンドラインからパスワードを指定できるようにしてしまうとパスワードが丸見えになってしまってコマンドの履歴とかターミナルのログとかいろんな所にパスワード文字列が平文で残ってしまってセキュリティ上よろしくないということでこうなっているのだと思います。

というわけでスクリプトでユーザ作成時にパスワードまで指定できるようにするには useradd コマンドを使用します。

といっても useradd コマンドも単純に平文ではパスワードを指定させてくれません。
useradd コマンドの -p オプションには、暗号化(ハッシュ)されたパスワードを指定する必要があります。

さて、そのハッシュの方法ですが、man によると crypt(3) を使って取得した値を指定するようにと書いてあります。

crypt(3) というのは、crypt() という関数のことで、コマンドラインから簡単に呼び出すことができません。C 言語のプログラムを書かないといけません。
Perl の crypt 関数は内部的に crypt(3) を呼んでいるようですのでそれを使って回避するやり方はあるようです。

useraddコマンド | ユーザー管理コマンド | ウナのLinux講座 | ウナのIT資格一問一答
http://una.soragoto.net/lecture/linux/user_cmd/useradd.html

ただ、上記の URL で示されている方法だと、POSIX 準拠ではあるのですがダイジェスト生成に DES が使われていて crack(1) で簡単に破られてしまうというのと、パスワード文字列の長さが 8 文字以上あっても 8 文字までしか使われないという問題があります。

そこで、Glibc2 以降の拡張を使って $id$salt$ というソルト(id は 1, 5, 6 などの数、salt は 16 文字以内の任意のランダムな文字列) を指定すると MD5 や SHA256, SHA512 といった暗号学的ハッシュが使えるので安全性が高まりパスワード文字列の長さの制限もなくなります。

ただ、これでもやはりパスワード文字列がコマンドラインに丸見えなので、それが気持ち悪いという場合はファイルにパスワードを書いておいてそれを読みこませるという方法を取る必要がでてきてだんだんワンライナーの範疇を超えてくる感じです。(Perl ならそれくらい簡単にできるかもしれませんが、、、)

また、適切な salt を選ぶのはなかなか難しい作業です。(ランダムな文字列を生成するワンライナーを書くという手はありますが・・・)


そこで、mkpasswd コマンドが使える環境(Ubuntu 12.04 では whois パッケージに mkpasswd が含まれています)では、perl によるワンライナーの代わりに mkpasswd コマンドを使うことをお勧めします。

mkpasswd コマンドは、標準入力もしくはファイルディスクリプタからパスワードを読み込ませてそれを適切なソルトをつけて -m オプションで指定した方法でハッシュしてくれるというコマンドです。

使い方は以下のようになると思います。

$ cat mypassword.txt | mkpasswd -s -m sha-512

$6$Tqd5rI9..0tS8Af$ZQkNOfrZpdw6tz1bvUZFyjmPmJ4OXhVILyUJCqF1gopahmc8L6xe9hZ62YyKYY1qeWLRqvVXXB97r6OCFlgFq/
という感じの文字列が表示されたら成功です。

mkpasswd コマンドの -s は標準入力からパスワード文字列を読み込むように指定するオプション、-m sha-512 は SHA 512 でハッシュすることを指定するオプションです。

これでパスワードをコマンドラインに晒すことなく、適切なソルトで強いハッシュでパスワードを保護することができました。

あとはこれを useradd コマンドに指定するだけです。

$ sudo useradd -p `cat mypassword.txt | mkpasswd -s -m sha-512` username

useradd の man を見ると、-p でパスワードを指定したアカウントはデフォルトではアクティブでないとされていますが、私の環境ではこれでこのユーザでログインできました。

また、試しに /etc/shadow の中身を見てみると、mkpasswd で生成された文字列が書きこまれているのがわかると思います。

Ubuntu 14.04 にしたら mount cifs がエラー

最近、開発のサブで使っている環境を Ubuntu 12.04 から 14.04 にアップグレードしたのですが、いろいろ細かいことで変化があって困っています。
なのでメイン環境の移行はもうちょっと先ですね。

その困りごとのうちの一つが、Windows Server のフォルダをマウントするときに起こる、

mount error(22): Invalid argument

というエラーです。


dmesg でエラーメッセージを見てみると、

CIFS: Unknown mount option "codepage=cp932"

ということでした。

どうやら、codepage=cp932 というオプションを指定しなくても日本語ファイル名の文字化けは起こらないようなので外してしまいました。
Samba のバージョンが上がって、いちいちコードページを指定しなくても良きに計らってくれるようになったのでしょうかね。
暇があればソースでも覗いてみて確信を得るところなのですが、忙しいので今はとりあえずこれで動いているようなのでよしとします。


他に困っているのは、IBusかな漢字変換のモード(ひらがな入力、直接入力など)を切り替えるのになるべくホームポジションから指を動かさなくて済むようなキーバインドを割り当てていたのですが、14.04 ではその方法がよくわからないというものです。
(12.04 では GUI 画面で簡単に設定できていたのですが、14.04 ではその画面が見つけられません。英語キーボードなので半角/全角キーとかもないので、切り替えるのにいちいちマウス操作をしないといけないという苦痛な現状・・・xmodmap でも書かないといけませんかね、、、)

valgrind の track-fds=yes オプションを指定した時に fd=0,1,2 が open されたままだと指摘されるのをどうにかする方法

たとえば以下のような無害なプログラムをコンパイルして valgrind にかけて実行します。

main.c

int main()
{
    return 0;
}
$ gcc main.c
$ valgrind --track-fds=yes ./a.out
==2227== Memcheck, a memory error detector
==2227== Copyright (C) 2002-2011, and GNU GPL'd, by Julian Seward et al.
==2227== Using Valgrind-3.7.0 and LibVEX; rerun with -h for copyright info
==2227== Command: ./a.out
==2227== 
==2227== 
==2227== FILE DESCRIPTORS: 3 open at exit.
==2227== Open file descriptor 2: /dev/pts/10
==2227==    <inherited from parent>
==2227== 
==2227== Open file descriptor 1: /dev/pts/10
==2227==    <inherited from parent>
==2227== 
==2227== Open file descriptor 0: /dev/pts/10
==2227==    <inherited from parent>
==2227== 
==2227== 
==2227== HEAP SUMMARY:
==2227==     in use at exit: 0 bytes in 0 blocks
==2227==   total heap usage: 0 allocs, 0 frees, 0 bytes allocated
==2227== 
==2227== All heap blocks were freed -- no leaks are possible
==2227== 
==2227== For counts of detected and suppressed errors, rerun with: -v
==2227== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 2 from 2)

このエラーは実質的には無害なのですが、偏執狂な私やあなたのような人はこのようなものでさえも消し去りたいですよね。

fd 0, 1, 2 はそれぞれ stdin, stdout, stderr なので、main() を抜ける前に(もしくはそれらの fd を使わなくなった時点で)それらを close すればこの問題は解決します。

main2.c

int main()
{
    close(0);
    close(1);
    close(2);

    return 0;
}

もしくは #include <stdio.h> してから close() の代わりに fclose() を使って fclose(stdin); fclose(stdout); fclose(stderr); としてもよいでしょう。

$ gcc main2.c
$ valgrind --track-fds=yes ./a.out
==5413== Memcheck, a memory error detector
==5413== Copyright (C) 2002-2011, and GNU GPL'd, by Julian Seward et al.
==5413== Using Valgrind-3.7.0 and LibVEX; rerun with -h for copyright info
==5413== Command: ./a.out
==5413== 
==5413== 
==5413== FILE DESCRIPTORS: 0 open at exit.
==5413== 
==5413== HEAP SUMMARY:
==5413==     in use at exit: 0 bytes in 0 blocks
==5413==   total heap usage: 0 allocs, 0 frees, 0 bytes allocated
==5413== 
==5413== All heap blocks were freed -- no leaks are possible
==5413== 
==5413== For counts of detected and suppressed errors, rerun with: -v
==5413== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 2 from 2)

おめでとう!
気持ちのいい結果になりました。


ところが、これだけではまだ話は終わらないのです。

この結果に気をよくした私とあなたは、この valgrind のテストを CI に組み込みたくなるかもしれません。結果を後から確認するために、--log-file オプションでログファイルのパスを指定します。

$ gcc main2.c
$ valgrind --track-fds=yes --log-file=/tmp/v.log ./a.out
$ cat /tmp/v.log
==5391== Memcheck, a memory error detector
==5391== Copyright (C) 2002-2011, and GNU GPL'd, by Julian Seward et al.
==5391== Using Valgrind-3.7.0 and LibVEX; rerun with -h for copyright info
==5391== Command: ./a.out
==5391== Parent PID: 1927
==5391== 
==5391== 
==5391== FILE DESCRIPTORS: 1 open at exit.
==5391== Open file descriptor 3: /tmp/v.log
==5391==    <inherited from parent>
==5391== 
==5391== 
==5391== HEAP SUMMARY:
==5391==     in use at exit: 0 bytes in 0 blocks
==5391==   total heap usage: 0 allocs, 0 frees, 0 bytes allocated
==5391== 
==5391== All heap blocks were freed -- no leaks are possible
==5391== 
==5391== For counts of detected and suppressed errors, rerun with: -v
==5391== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 2 from 2)

なんと!
Valgrind が使っていたであろうログファイルのディスクリプタがリークしていると指摘されてしまいました。

これを解決するためにもうひと工夫必要そうです。

ヒントは inherited from parent という行にあります。
valgrind が a.out を実行するときに、その時点で開かれているファイルディスクリプタは引き継がれてしまうんですね。exec() 系や fork(), system() など、子プロセスを起動する関数(システムコール)はそのような動作をするようになっています。

fork() した子プロセスで同じファイルを継続して使用したいときにはそれは便利かもしれませんが、この場合は全くもって不要です。

ということで、不要な fd はプログラム起動直後にすべて閉じてしまいましょう。

といっても、どのような fd を引き継いで起動されたかは事前にはわかりません(頑張って /proc/$$/fd の下をチェックすればわかるかもしれませんが、面倒ですしあまり意味がありません)ので、ここでは少し強引な方法を取ります。

main3.c

#include <unistd.h>

void close_all_inherited_fds()
{
    int i = 3;
    int maxfds = getdtablesize();
    for (; i < maxfds; i++)
        close(i);
}

int main()
{
    close_all_inherited_fds();

    /* do all your stuff here */

    close(0);
    close(1);
    close(2);
    return 0;
}

fd が open されているかどうかにかかわらず、3 以上の fd すべてに対して close() を呼び出します。
このコードは Linux での例ですが、他の環境でも同様のコードが使えるでしょう。(getdtablesize() の代わりに OPEN_MAX のような定数や sysconf(_SC_OPEN_MAX) のような POSIX 準拠の関数が使えるのではないでしょうか。)

Linux の場合は open() されていない fd に対して close() を呼び出すと、close() は -1 を返し errno には EBADF がセットされますが、この場合は実質的には問題ないでしょう。

これで valgrind を実行すると、

$ gcc main3.c
$ valgrind --track-fds=yes --log-file=/tmp/v.log ./a.out
$ cat /tmp/v.log 
==6890== Memcheck, a memory error detector
==6890== Copyright (C) 2002-2011, and GNU GPL'd, by Julian Seward et al.
==6890== Using Valgrind-3.7.0 and LibVEX; rerun with -h for copyright info
==6890== Command: ./a.out
==6890== Parent PID: 1927
==6890== 
==6890== 
==6890== FILE DESCRIPTORS: 0 open at exit.
==6890== 
==6890== HEAP SUMMARY:
==6890==     in use at exit: 0 bytes in 0 blocks
==6890==   total heap usage: 0 allocs, 0 frees, 0 bytes allocated
==6890== 
==6890== All heap blocks were freed -- no leaks are possible
==6890== 
==6890== For counts of detected and suppressed errors, rerun with: -v
==6890== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 2 from 2)

ここまですると、pedantic で paranoid な私やあなたでも満足行く結果になったと思います。

もし、あなたの検査対象プログラムが本当に fd を引き継ぐ必要があるのならば、それにはプログラム起動時の引数などで fd の番号を伝えてその fd だけは close() しないように除外するなどの対策が必要でしょうけれども、それはこの記事をここまで読んでくれた読者の知的楽しみのために取っておくことにします。


以上、valgrind で track-fds を使おうとした時に起こりがちな問題を解決するには、検査される側のプログラムにちょっとした対策が必要ですというお話でした。

Eclipse の Tooltip の背景が真っ黒になって文字が読みづらいのを直す方法

おそらく Ubuntu 限定の問題だと思います。

Eclipse(およびその派生プロダクト)を使っていてエラーのある行の波線が引かれているところにカーソルを合わせると出てくる Tooltip があると思いますが、これが背景色が真っ黒なのに文字の色も黒っぽい色でハイパーリンクも濃い青なのでほとんど識別不能という問題がありました。

Eclipse 固有の問題だと思っていたので、Preferences からいろいろ変えたりしてみたのですが全く解決せず、、、
頑張って検索していると、意外な答えが見つかりました。

実はその部分にはシステムワイドな色設定が使われているらしく、Eclipse 内部からは変更できないということのようでした。

これを直すには、gnome-color-chooser というアプリを apt-get 等でインストールして起動し、Specific タブの Tooltip のところにチェックを入れて読みやすい色になるように変更すればよいようです。

デフォルトだと背景が黄色、文字色が黒になるのですが、黄色がちょっときつかったので少し薄めの黄色に変更して快適に使えるようになりました。

WinDBG によるデバッグ方法(ダイジェスト)

Visual Studio のプロジェクトが存在せず、nmake や cl などを使ってビルドされる C/C++ プログラムをデバッグしようとして、いろいろ困ったのでメモ。


1. WinDBG のインストール

Windows SDK をインストールすれば一緒に入ってくる。

2. プログラムは /Zi オプション付きでコンパイルする。(デバッグ情報が .pdb ファイルとして生成される)

3. WinDBG を起動し、File > Open Source File ... でとりあえず main 関数のあるソースファイルを開く

4. File > Symbol File Path ... で .pdb ファイルのあるディレクトリを指定

5. File > Open Executable ... でデバッグ対象の .exe ファイルを開く。この時、ファイルオープンダイアログの左下にコマンドラインオプションや実行時ディレクトリを指定できる。

6. Locals(ローカル変数のウォッチ)、Calls(コールスタック)、Watch、Command などいろいろなビューを開きまくる。ワークスペースを保存しておくと後で嬉しいかも。

7. Command ウインドウで以下のようなコマンドでとりあえず頑張る
bp ブレークポイントを設定。何はともあれ bp main
Debug > Resolve Unqualified Symbols にチェックを入れておいたほうがよいかも
g で実行開始
p で step over
t で step in
ソースウインドウで F9 (Breakpoint 設定) / F10 (Step Over) / F11 (Step In) でもよいかも


8. コマンドラインオプションを変えて起動し直したい(ブレークポイントやウォッチ式などはそのまま残したい)場合や起動時ディレクトリを変えたい場合は、g コマンドなどでプログラムをいったん終了させるか .kill コマンドで強制終了させてから .createdir や .create を使用する。


とここまで頑張ったけど、Visual Studio で快適にデバッグできる方法があったりして・・・ガクブル


pykd とか mona.py を使うための布石だもんね・・・(強がり)

Windows の PATH 環境変数の各パスは ” ” (ダブルクオーテーション)で囲まなくても良い ー むしろ囲っちゃダメ

Visual C++コンパイラコマンドラインから起動しようとして、その準備として vcvarsall.bat を実行しようとしてハマったのでメモ。

vcvarsall.bat は cl.exe などの置かれているディレクトリへのパスを環境変数として設定したりするバッチファイルですが、これを実行したところ、以下のようなエラーになってしまいました。

> vcvarsall.bat
"~~~" の使い方が誤っています。

このあと、PATH 環境変数の中身と思わしきものがダーッと表示されてしまい、cl.exe などへはパスが通りませんでした。

Visual Studio に付属の Developer Command Prompt を立ち上げても同じエラーです。

いろいろ調べたところ、"C:\Program Files (x86)\Hoge Fuga\bin" みたいにパスをダブルクオーテーションで囲んだものを指定していて、かつ、その囲まれたパスの中に ( )(丸カッコ) が含まれているときにこのようなエラーになるようです。

カッコが含まれないパスはダブルクオーテーションで囲んであってもエラーにはならないようですが、そもそも PATH 環境変数はセミコロンで区切るのでパスの中に空白が含まれていても問題はなく、ダブルクオーテーションで囲む意味がないので、この際なのでダブルクオーテーションは全部取ってしまいました。


それにしても、Windows の PATH 環境変数は設定しづらいですよね、、、
設定ダイアログを出すまでの手順が多すぎるし、設定ダイアログの UI が最悪です。(どうして一行しか表示できない小さなテキストボックスで編集しないといけないんだ・・・)

Rapid Environment Editor というソフトを使ってみたところ、らくらく編集できました。

Cygwin の PATH 文字列と Windows の PATH 文字列の相互変換

答えを先に書くと、cygpath コマンドを使います。

Cygwin の形式(/cygdrive/c/... )→ Windows 形式(C:\... )

$ cygpath -w /cygdrive/c
C:\

Windows 形式 → Cygwin 形式

$ cygpath C:\\
/cygdrive/c


Cygwin から Windows のプログラムを起動しようとする場合、そのようなプログラムは Windows 式のパスしか受け付けない可能性が高いので、このように変換してやる必要があります。
逆に Windows 用のプログラムがファイルに書いたパスなどを読み取って Cygwin 側で処理したい場合もこのように変換する必要がありますね。


cygpath コマンドは、ルールに則って文字列を変換するだけのようなので、実在していないパスでも変換してくれるようです。

cygpath -w /a/b/c
C:\CygWin\a\b\c

エレクトロラックス エルゴラピード

コードレス掃除機を探していて、コストコで見つけたのがこちら:

エレクトロラックス エルゴラピード


型番は ZB2901 というものなので一世代前のものだと思いますが、コストコでは 1万2,800円くらいで売っていました。
( ネットで探した最安価格より1,000円以上安いですね。さすがコストコ

価格も手頃だったのですが、数週間使ってみてこれは本当に買ってよかったと思える製品でした。
もともとメインの掃除機(国内メーカー製の紙パック式掃除機)があってサブの掃除機を探していたので、期待値がそれほど高くなかったというのもあるかもしれませんが、メインの掃除機を使わなくなりそうな勢いです。

このエルゴラピードを買った時、我が家ではこんな視点で掃除機を探していました。

コードレスだけどパワフル

我が家は3階建ての戸建て住宅で各階の面積はそれほど広くないのだけど、どこか一箇所のコンセントだけでは家中に掃除機を掛けることができません。各階に移動するたびにコンセントの抜き差しが発生します。各階だけではなく階段にも掃除機を掛けるとなると、階段を下から上まで掃除し終わったあとに元いた階に戻ってコンセントを抜くといった作業が発生してしまいます。それで、コンセント抜き差し問題を解決してくれそうなコードレスという点は必須条件で探していました。

ただ、コードレスのイメージは「吸引力が貧弱」というものでした。
その点、この掃除機はサイクロン式ということもあるのだと思いますが、十分すぎる吸引力です。
メインの掃除機を掛けたあとにこの掃除機をもう一度掛けてもダストカップにしっかりホコリが溜まっているくらいです。

ルンバなどのロボット掃除機にも興味はありましたが、3フロアに分かれていると3台買わないと全フロアをカバーできないわけですが、主に金銭的な理由でそういうわけにもいきません。
また、ホコリやゴミが目についたときとかに結局自分の手で掃除したくなっちゃうと思うので、そういう時は手軽に使える掃除機がやっぱり欲しくなりそうな気がします。
それよりなにより、我が家には1歳の赤ちゃんがいるのでロボット掃除機は時期尚早かなとも思いました。(掃除機と戦って壊しそうという意味でw)

デザインがいい

日本メーカーの白物家電は・・・(以下略
エレクトロラックススウェーデン発祥のメーカーなので、北欧デザインの本体はインテリアとしてもオシャレな感じがします。

この製品を実際に買って使ってみてから気づいた点

  • 2 in 1
    • 買う前に気づけ、と言われてしまうかもしれませんが、このエルゴラピードは掃除機のメインユニット部分だけをカパッと取り外して、ハンディタイプにもなるのです!(本体に書かれている 2 in 1 の由来でもある)ハンディ部分は車の掃除などに使えるので便利です。
  • LED ライト
    • ノズルの前面に LED ライトが付いているので、暗いところを照らしてくれます。隅っこの方に落ちてるゴミなどが見えやすくて意外と便利です。
  • 簡単に使いはじめられる
    • 奥さんが一人で充電ステーションなどをセットアップして使えました。掃除が終わったらダストカップを外してフィルタを掃除したりしないといけないのですが、それもなんの迷いもなくできていました。

結論

というわけで、この掃除機はとってもおすすめです。

xinetd で走らせてるサービス(デーモン)の状態を知る方法

xinetd でどのポートでどのサービスを動かしていたかをお手軽に調べたりしたい場合の方法をメモ。

http://superuser.com/questions/318040/how-to-get-status-information-form-xinetd より。

$ sudo pkill -USR1 -x xinetd
$ cat /var/run/xinetd.dump

USR1 というシグナルを xinetd に送ると /var/run/xinetd.dump にダンプされる。

これで見られる情報は各サービスの設定ファイルに書いた以上のものはあまりないのだけれど、現時点で動いているサービスの情報を一覧して見られるのは便利といえば便利。