フタなしカンヅメ

徒然なるままに @happytar0

OpenCVをいじってみた【前編】

しばらくぶりの更新となってしまった…少しずつでも書いていかなきゃだめですね。
物体認識を試してみたかったので有名なOpenCVを使ってみた記録。

OpenCVのインストール

Mac環境なのでMacPortsを利用して、OpenCVとObjectMakerをインストールした。ObjectMarkerは画像から必要な部分を切り出せるツールらしい。

# port install opencv objectmarker


ちなみにWindows環境にもインストールしてみたが少し面倒だった。
ここのインストールガイドを参考にするといいようだ。
InstallGuide - OpenCV Wiki

まず、OpenCVをコンパイルする環境が何も入っていなかったので、
VisualStudioC++ 2010 Expressってのをインストール。
Microsoft Visual Studio Express

CMakeも必要なようなので、以下のサイトからCMakeをインストール。
CMake - Cross Platform Make

CMakeGUIでOpenCVのパスを指定して、Configureを実行することで、VisualStudioで開けるファイルが生成されるようだ。
コンパイラにVisualStudio2010 Win64を指定したところ、Expressバージョンには64bitのコンパイラが含まれていないようで、Windows SDK 7.1のインストールも必要になった。
この際、マルチコア環境ならばTBBを有効化した方がいいと思う。(「USE TBB: ON」にする)

あとは、VisualStudioでOpenCVのプロジェクトファイルを開いてコンパイルするだけ。

物体検出するための分類器を作る

人間の顔や目などを検出するための分類器は、サンプルとしてもう用意されているようで、それらをそのまま使えばいいだけのようだ。
それだと面白くないので、カレーライスを検出する分類器を作ってみることにした。

分類器を作る流れをおおまかに説明すると以下のようになる。

  1. ネガティブサンプル(検出対象物が写っていない画像)を用意する。3000枚ほどあると効率的らしい。
  2. ポジティブサンプル(検出対象物が写っている画像)を用意する。こちらは7000枚ほどあると効率的とのこと…多いな。
  3. opencv_traincascadeコマンドを使って分類器を作る。

ここで問題になってくるのは学習させるための画像をどうやって集めてくるかだ。
あまりよくないかもしれないが、Google画像検索などを利用すればそれほど苦労しないと思う。
他には、opencv_createsamplesコマンドを利用する方法があるようで、ネガティブサンプルと一つのポジティブサンプル画像を組み合わせることで、ポジティブサンプル画像をたくさん作り出すことができるようだ。

サンプル画像を集める

あまり大きい声では言えないが、画像検索を使ってサンプル画像を集めることにした。
さすがに手作業では面倒なため、簡易的なスクリプトを組んで一気に処理しようと思ってAPIがあるか調べて見ることに。

Google Image Search APIというのを見つけたが、ずいぶん昔に廃止されたようだ。
Custom Search APIというのもあるようだが、こちらは使用用途が違うようだし、一日100リクエスト?までのようでだめっぽい。

Yahooを調べたところ、画像検索用のAPIを公開していた。
検索:画像検索API - Yahoo!デベロッパーネットワーク
通常は一日1000リクエストまでだが、プレミアム会員だと5万リクエストに緩和されるらしい。プレミアム会員であったのでこれを利用することにした。
(他にはFlickrAPIを利用するのもアリだと思う)

"風景 -カレーライス"
こんな感じのクエリを投げれば、カレーライスを含まないネガティブサンプル画像を集めることが出来るはずなので、
作ったスクリプトを回して3000枚ほど用意することができた。

ポジティブサンプルの用意が少しむずかしい。
検出対象物を含んだものを用意するのは同じ手順でいいはずだが、対象物のみを切り出す必要があるはずで、それが非常にめんどくさい…。
こういう時のためにopencv_createsamplesコマンドがあるのか?と思って使ってみることにした。

長くなりそうなので今回はこのへんで終わり。。。次回へつづく。

MT4iのDoS攻撃されるセキュリティホール

MT4iのベータ版である3.1系をのぞく全てのバージョンで、DoS攻撃されうるセキュリティーホールがあるようです。細工されたリクエストを送信するか、もしくは特定の状況下で無限ループしてしまう事が原因で、HTTPプロセスが常駐し続けてしまいます。

原因

記事本文を分割する際に利用する midb_euc 関数の欠陥が原因のようです。分割位置をGETパラメータとして渡すため、「記事本文の文字数より大きい値が渡された時」に分割が終了せずに無限ループに陥ります。なお、記事本文を分割するバイト数として、初期値では「4096」バイトが設定されています。

以下のように sprtbyte に分割位置がカンマ区切りで渡されます。

http://www.example.com/m/mt4i.cgi?mode=individual&eid=1&sprtpage=1&sprtbyte=0,4096

どういう状況でおこりうるか

MT4iはMovableTypeを携帯で見やすいように変換・表示するためのプログラムです。携帯向けに表示するため、記事本文の表示を分割する必要があります。記事本文が分割バイト数ずつ分割表示されるわけですが、それぞれの分割された記事の位置をGETパラメータで制御しているため、後から記事本文を更新した場合に分割位置が一致せずに、無限ループする可能性があります。
クローラーなどが更新前のURLでアクセスしてきて…なんて事もあるかもしれません。

再現方法

sprtbyte パラメータに記事本文より大きい値を渡すことで再現できます。

問題の箇所

midb_euc 関数のコードを抜き出したものです。2系、3.0系ともに同様の関数が使われているようです。
記事本文より大きい開始位置が指定された場合、43行目の while 文内の substr 関数が常に開始位置より小さい値を返すために無限ループし、さらに68行目の while 文内の substr 関数で、開始位置と終了位置が記事本文より大きい場合、常に空文字を返すので無限ループしてしまいます。

sub midb_euc {
    my $llen1;
    my $llen2;
    my $lstr;
    my $lstart;

    # 先ず正しい開始位置を求めないと
    if ($_[1] == 0) {
        $lstart = 0;
    } else {
        $llen1 = $_[1];
        $lstr = substr($_[0], 0, $llen1);
        $llen2 = MT4i::Func::lenb_euc($lstr);
        my $llen3 = $llen1;
        while ($_[1] > $llen2) {
            $llen3 = $llen1;
            $llen3 += $lstr=~s/(\x8E[\xA1-\xDF])/$1/g;                   # 半角カナ数をプラス
            $llen3 += ($lstr=~s/(\x8F[\xA1-\xFE][\xA1-\xFE])/$1/g)*2;    # 3バイト文字数*2をプラス
            $lstr = substr($_[0], 0, $llen3);
            $llen2 = MT4i::Func::lenb_euc($lstr);
        }
        $llen1 = $llen3;

        # 最後の文字が途切れているか判定する
        if ($lstr =~ /\x8F$/ || $lstr =~ tr/\x8E\xA1-\xFE// % 2) {
            chop $lstr;
            $llen1--;
            if($lstr =~ /\x8F$/){
                $llen1--;
            }
        }
        $lstart = $llen1;
    }

    # 文字列の切り出し
    $llen1 = $_[2];
    $lstr = substr($_[0], $lstart, $llen1);
    $llen2 = MT4i::Func::lenb_euc($lstr);
    my $llen3;
    while ($_[2] > $llen2) {
        $llen3 = $llen1;
        $llen3 += $lstr=~s/(\x8E[\xA1-\xDF])/$1/g;                   # 半角カナ数をプラス
        $llen3 += ($lstr=~s/(\x8F[\xA1-\xFE][\xA1-\xFE])/$1/g)*2;    # 3バイト文字数*2をプラス
        $lstr = substr($_[0], $lstart, $llen3);
        $llen2 = MT4i::Func::lenb_euc($lstr);
    }
    $llen1 = $llen3;

    # 最後の文字が途切れているか判定する
    if ($lstr =~ /\x8F$/ || $lstr =~ tr/\x8E\xA1-\xFE// % 2) {
        chop $lstr;
        if($lstr =~ /\x8F$/){
            chop $lstr;
        }
    }
    return $lstr;
}

対応方法

3.1系では問題となっている関数が置き換わっているため、3.1系を利用することで回避できるようですが、まだベータ版なのでそのあたりも考慮する必要がありそうです。

簡単な Func.pl に対するパッチを作ってみました。各 while 文で記事本文より大きい場合と、空文字の場合にループを抜ける処理を追加しただけです。

※2月5日訂正
while 文でループする意味がよく分からなかったので、一度で抜けるように変更しました。

--- Func.pl.org	2011-02-03 16:43:57.000000000 +0900
+++ Func.pl	2011-02-03 16:19:58.000000000 +0900
@@ -46,6 +46,7 @@
             $llen3 += ($lstr=~s/(\x8F[\xA1-\xFE][\xA1-\xFE])/$1/g)*2;    # 3バイト文字数*2をプラス
             $lstr = substr($_[0], 0, $llen3);
             $llen2 = MT4i::Func::lenb_euc($lstr);
+            last;
         }
         $llen1 = $llen3;
 
@@ -71,6 +72,7 @@
         $llen3 += ($lstr=~s/(\x8F[\xA1-\xFE][\xA1-\xFE])/$1/g)*2;    # 3バイト文字数*2をプラス
         $lstr = substr($_[0], $lstart, $llen3);
         $llen2 = MT4i::Func::lenb_euc($lstr);
+        last;
     }
     $llen1 = $llen3;

実はそんなにたいした事じゃないのかも

共有サーバのほとんどは、長時間実行されているプロセスは強制終了されるものかと思われますので、それほど影響はないのかもしれません。


デタラメ書いてるんじゃねーってことがあれば連絡ください。

ひかりoneギガ得プランのHGW(BL190HW)の性能とその後

ひかりoneのギガ得プランを使い始めて1年が経ちました。実質固定IPという噂でしたが、まさにその通りで一度も変わったことはありません。

一つ問題が出てきたのはルータの性能についてです。ルータについては、このブログに記載してあるようにBL190HWというルータが指定されおり、変更することは一切できません。ひかりoneでは、ルータの事をHGW(ホームゲートウェイ)と呼称しています。

  1. 自分で用意したルータに置き換えることはできない。どうしても使いたい場合は、BL190HWのDMZ機能をブリッジのように使うしかない。
  2. グローバルIPアドレスDHCPを使って払い出される。
  3. MACアドレスとIEEE802.1xを使って認証している。


Webサーバを動作させている状態で、同時接続数300で100Mbpsを超えたあたりからレスポンスがかなり悪くなりました。この状態でルータの管理画面にアクセスすると開くのにも時間がかかっており、やはり負荷が原因だと思いました。

## こんな感じで調べてみた
$ netstat -t | grep "ESTABLISHED" | grep http | wc -l

しかし、ルータが認証の役割も担っているため、そう簡単に交換することはできません。


上述した通り、認証にはMACアドレスとIEEE802.1xが使われています。MACアドレスの偽装については比較的簡単なのですが、IEEE802.1x認証をクリアするのは現状厳しいようです。IEEE802.1x認証でシリアル番号も送信している?
IEEE802.1x認証は、24時間に一度確認しているようなので、一度認証されれば他のルータに置き換える事はできますが、24時間後に切断されます。


どうしようかと考えていた所、もう一台ルータをレンタルする方法がある事を発見しました。
電話サービスの追加など、ホームゲートウェイを複数台ご利用になる場合 | auひかり(auの光ファイバーサービス)

合計2台までのようですが、これでとりあえず問題は解決できそうです。ちなみに2台目のルータにもグローバルIPアドレスが割り当てられます。

  1. HGWは合計2台までしかレンタルできない。
  2. 電話サービスを二つ契約する必要がある。
  3. 2台目のルータにもグローバルIPアドレスがもう一つ払い出される。


もう一台レンタルするためには、電話サービスを二つ契約する必要があるため、525円+472円が月額費用に加算される点は注意が必要です。申込手数料が650円くらいかかりますが、サポートセンターに電話経由で申し込み、三日くらいで新しいルータが到着しました。


現在2台のルータで運用していますが、レスポンスも改善したようです。

HyperMacのバッテリーセルを交換してみた

先日バッテリーリフレッシュさんにお願いしたHyperMacのMBP-060が戻ってきました。

15日に注文して、17日には作業完了のメールが着ていました。到着したのが18日という事を考えるとかなり早いです。
かかった金額は11890円と送料の740円だけでしたので、海外から直接購入するよりずいぶん安くなります。

f:id:happytar0:20100918105400j:image
段ボール箱に入って返送されてきました。

f:id:happytar0:20100918105500j:image
しっかり緩衝材で梱包されていました。

f:id:happytar0:20100918105600j:image
二つ入っていると思ったら、見積りをお願いしたMBP-150でした。

交換したバッテリーは無事に使うことができたのか

このバッテリーセル交換サービスは、動作保証までしていないため、本当に動くのかどうかは使ってみるまで分かりません。

f:id:happytar0:20100918105700j:image
端子がある側面にシールを剥がした跡がありましたので、恐らくここから開腹したのでしょう。通常ならまったく気にならないレベルでした。

さっそくACアダプタを通して充電してみる事にしました。

f:id:happytar0:20100919172100j:image
無事に充電のLEDが点灯してほっとしました。

MacBookProに接続した所、充電中のアイコンになり正常に充電されました。うれしい誤算としては、充電中にあれだけ熱くなっていたHyperMacが、ほとんど熱くならなくなった事です。
長時間使ってみた所、交換前と同じように熱くなりました…

バッテリーリフレッシュサービスは使えるのか

今回利用した限りだと、とても満足できる結果だったので今後も利用してみたいと思いました。もちろん、メリット・デメリットがありますので、デメリットが許容できる範囲内であれば、利用してみてもいいのではないでしょうか。


メリット

  1. 純正品を海外から購入するよりも安い
  2. バッテリーセルが日本製になる(純正品は中国製だと思う)
  3. バッテリーの容量がアップする
  4. バッテリーセルの交換作業も国内なので安心できる


デメリット

  1. 動作が保証されていない
  2. 既にHyperMacを持っている必要がある(当たり前)
  3. 交換するHyperMacを送らないといけない

※バッテリーリフレッシュサービスを利用する際は自己責任でお願いします

今回利用させていただいたバッテリーリフレッシュさんはこちらからどうぞ。
http://www.batt.jp/

Mac専用バッテリーHyperMacを復活させる

HyperMacの寿命はどのくらいなのか

1年ほど前に購入したHyperMacですが、フル充電しているにも関わらず1分くらいでバッテリーが無くなってしまうようになりました。
そんなに使用回数は多くなかった気がします。少なくとも1000回は使っていないでしょう。
使用中は、火傷しそうなくらい熱くなったりしたので色々気になる所はありました。


こんな記事もあるようです。
http://blog.goo.ne.jp/portaledge/e/a3b352cf4e20f7d16ad37d548e5b9809


しかし、Macで使用出来る外部バッテリーはほとんどありません。自分が知っている限り、まともに使えるのはHyperMacくらいなのではないでしょうか。
ちなみにMBP-060とMBP-150を同じ時期に購入しましたが、偶然なのかどちらも使えなくなってしまいました。

まともな外部バッテリーが出てこないのはなぜか

どうしてまともな外部バッテリーが出てこないのか、それはMac独自の電源コネクタ「MagSafe」によるものです。Apple社は、この「MagSafe」の特許を取得しており、他社に対してライセンスする気がないようです。

ではなぜ、HyperMacは「MagSafe」を使用できているのか。Apple社からライセンスを受けている訳ではありません。純正品のMagSafe電源アダプタを加工し、流用することで、ライセンスの問題をクリアしているという事のようです。


中国企業らしいアイディアではありますが、ついにApple社から目をつけられたようです。
Apple、外部バッテリーメーカーを訴える|KODAWARISAN


今後、HyperMacはどうなってしまうのか心配ですが、現在持っているHyperMacを大事に使っていきたい所です。純正の外部バッテリーが出てくれれば、それが一番いいような気もしますが・・・。

外部バッテリーの寿命を延ばすには

大事に使っていきたい所ですが、所詮バッテリーは消耗品なので、時間が経てば使えなくなってしまうのは当然です。ではどうすれば、バッテリーの寿命を少しでも延ばす事ができるのでしょうか。


まず自分の反省を踏まえ、どうしてこんなに早くバッテリーがダメになってしまったのかを考えてみました。

  1. 日差しが入ってくるような室温が高い場所に放置していた。
  2. すぐ使えるように充電コネクタを挿し、いつもフル充電状態にしていた。
  3. 実は1000回近く使っていた。
  4. バッテリーセルが中国クオリティ。


さすがに購入して1年程度で毎日使うような事もしませんでしたので、3.はないでしょう。4.については、中国企業なので、中国製のバッテリーセルを使っていてもおかしくありません。中国製と日本製のものでどこまで品質に差があるのかというのも、素人の僕としては分かりません。


バッテリーの保存環境や使い方によって寿命に変化があるのかが一番気になる所ですが、下記のような衝撃的なサイトを発見しました。

リチウムイオンバッテリー考

「この(リチウムイオン電池の)劣化は満充電で保存すると激しくなり、また保存温度が高いほど劣化が早くすすみます。リチウムイオン電池を長期保存するときにはできるだけ冷暗所に保存し、あまり充電しない状態で保存することをお勧めします。」

長期保管
 例えば、iBookラボを学校で管理していて、夏休み中は使わないなど、ノートブックコンピュータをしばらく使う予定がない場合、アップルではバッテリーを50%充電した状態で保管しておくことをお勧めします。

 もし、バッテリーが完全にゼロになった状態でノートブックコンピュータを保管すると、深い放電状態となり、充電ができなくなってしまう可能性があります。

 逆に、フル充電の状態で長期保管すると、バッテリー容量が失われる、つまり、バッテリーの耐用年数が短くなる可能性があるのです。それを防ぐには、PowerBookiBookのバッテリーを取り出して、適温範囲内で保管しましょう。


自分の使っていた環境と合致します。一番衝撃的だったのは「満充電で保存すると劣化が激しくなる」という記述です。外部バッテリーという性質上、常にフル充電状態にして保存している人は多いと思いますので、一番気をつけなくてはいけない所でしょう。


どうすれば少しでも寿命が延ばすことができるかをまとめると

  1. 温度が高い場所で保存せず、涼しい冷暗所で保存する。
  2. フル充電状態にして放置しない。
  3. 使用頻度に間がある場合は、50%程度充電し使用する際にフル充電するようにする。
  4. 過放電を防止するために長期間使用していなかった時は、たまに充電してあげる。

色々気を使わなくてはいけないようで少したいへんそうですね・・・。

バッテリーの寿命を復活させる方法はあるのか

どうすれば寿命を延ばせるかという観点で書いてきましたが、自分のバッテリーは既にお亡くなりになっているので、今さら寿命がどうとか言っても仕方ありません。
円高なのでまた海外から買ってもいいのですが、「バッテリーセルが中国クオリティ」という不安要素を排除することはできません。
そこでバッテリーを復活させる事ができないか調べた所、バッテリーセルを交換することで復活させる事ができるようです。

そもそもバッテリーセルとは何なのか

自分も詳しくないので分かりませんが調べた感じだと、セルというのは電池の事であり、バッテリーとはこのセルの集合体という事のようです。
要するにセルを交換するという事は、バッテリー内部の電池を新しい物に交換するという事になります。
電池なら自分で替えられるのではないか、と思う人もいるかもしれません。バッテリーの内部は若干複雑になっており、リチウムイオンの場合、充電・放電に対して制御を必要とし、制御基板と繋がっているようです。
自己責任で替えておられる方がいるようでしたが、とても怖くて自分で交換する事はできませんでした。


バッテリーセルを購入する場合、数千円程度で購入できるようです。
※自分で交換をする事を推奨しているわけではありません。自分で交換する場合は、必ず自己責任でおこなってください。
ロワジャパン バッテリーバンク  デジカメ携帯パソコンバッテリー・充電器

バッテリーセルを交換してみる事に

そこで今回はバッテリーリフレッシュサービスを利用する事にしました。バッテリーリフレッシュサービスとは、バッテリーのセルを新しい物に交換してくれるサービスで、ベイサンという所が最大手のようです。
ソフマップなどでも受付代行をおこなっているようです。

今回は利用したのはベイサンではなく、バッテリーリフレッシュという別の業者にお願いしてみる事にしました。
バッテリーリフレッシュ・セル交換の専門店


当然HyperMacは一覧に載っておりませんでしたので、見積りをお願いしてみることに。掲載されているバッテリーを見てみると、純正品と大差がない物もありましたので、海外から購入するより安ければいいなという感じでした。その後、ベイサンでも交換可能か問い合わせた所、対応不可との事でした。


実際に見積りをお願いしてみた結果を踏まえてまとめてみました。

直接購入(Cableなし$-30.95) バッテリーリフレッシュ ベイサン
MBP-060 14,365円 11,890円 対応不可
MBP-150 31,365円 29,890円 対応不可

※$1=85円で計算

送料などを考慮するとバッテリーセルを交換した方が安く済むようです。また、バッテリーリフレッシュさんでセルを交換した場合、元の単セルあたり2200mAhに対して、日本製のセルになり2600mAhと容量までアップします。

このサービスで一点注意しないといけないのは、「バッテリーセル」のみを交換するサービスだという事です。動作確認や保証はおこなっておらず、動作を保証してくれるわけではないという事に注意しなくてはいけません。
※リフレッシュサービスにお願いする際も必ず自己責任でおこなってください。

HyperMacのmAhとは

HyperMacのバッテリー容量(mAh)ですが、公式サイトを調べても一切記載されていません。おそらく、充電する端末ごとに使われる電圧が違うため記載されていないのかもしれません。
ここでふと気づいたのですが、外部バッテリーでよく書いてある「8000mAh」などの記載は、電圧ごとに変わるのであって、これはアテにならないと今ごろ気づきました。多くの場合は、3.7V換算での値を表記しているみたいです。


以下のような計算で求められるようです。
Wh x 1000 / V = mAh

とりあえず、3.7V換算で計算してみました。

Energizer XP18000 68Whくらい? 約18000mAh
MBP-060 60Wh 約16000mAh
MBP-100 100Wh 約27000mAh
MBP-150 150Wh 約40000mAh
MBP-222 222Wh 約60000mAh


こうして見てみると、HyperMacはすごいバッテリー容量です。
ちなみにMacBookPro13インチで、システムプロファイラの「電源」から確認した所、12494mV(12Vくらい?)で、4951mAhと表示されていました。MBP-060の公称では、1.0倍長く使えるとの事なので合っているのか計算してみました。


60Wh x 1000 / 12V = 5000mAh

4951mAhと近い数字が出たので計算方法は間違っていないようです。このような感じで、使用する端末ごとに使われる電圧を調べて計算してみると、どのくらいバッテリーが持つのか計算することもできるでしょう。

バッテリーリフレッシュしたバッテリーはちゃんと使うことができるのか

まだ交換したバッテリーが届いていないため、ちゃんと使うことができるかは分かりませんが、届き次第またレポしたいと思います。HyperMacのこれからが分からない状況なので、少しでも寿命を延ばせるように使ったり、使えなくなってしまったらどうすれば良いかを考えるいい機会になりました。
HyperMacを使っている人は参考にしてみてはどうでしょうか。
※バッテリーセルを交換する場合は、くれぐれも自己責任でお願いします。


実際に交換してみた記事はこちらから。
HyperMacのバッテリーセルを交換してみた - フタなしカンヅメ

tarボールソースからインストールしたソフトを管理する「Graft」を使ってみる

ソースインストールした物を管理するツール「Graft」をインストールして使ってみたので、記録として残しておきます。

インストールと言っても簡単で、配布元サイトのドキュメント通りに実行すれば問題ありません。
配布元サイト
graft.html - peters

$ wget -O graft-2.4.tar.gz "http://peters.gormand.com.au/Home/tools/graft/graft-2.4.tar.gz?attredirects=0"
$ tar zxvf graft-2.4.tar.gz
$ cd graft-2.4
## ここでエラーがでます。
$ make -f Makefile.dist
    ######################################################
    #                                                    #
    #       You'll now need to modify the Makefile       #
    #      variables to suit your local conditions.      #
    #                                                    #
    ######################################################
 
    make: *** [Makefile] Error 1
## エラーが出るので、Makefileを編集する必要があるようです。

Makefile

このPACKAGEDIRがパッケージ管理用のディレクトリになり、ここにソースからインストールします。
PACKAGEDIR	= /pkgs
TARGETDIRは、通常インストールしたい場所、つまり/usr/localなどを指定します。
# TARGETDIR	= /pkgs
TARGETDIR	= /usr/local

Perlコマンドの場所を指定します。/pkgs/bin/perl となっていますが、ほとんどの場合、/usr/bin/perl に設置されていると思いますので変更します。
# PERL		= /pkgs/bin/perl
PERL		= /usr/bin/perl

あらためてビルドします。

$ make clean
$ make
# sudo make install
## graftがインストール出来ていることを確認。
$ ls /pkgs
graft-2.4
## graft自身を/usr/local/bin配下にインストール
# /pkgs/graft-2.4/bin/graft -i graft-2.4
## シンボリックリンクされていることがわかる
$ ls -l /usr/local/bin
lrwxrwxrwx  1 root root 25 7月 30日 09:23 /usr/local/bin/graft -> /pkgs/graft-2.4/bin/graft

これでインストールは無事に完了しましたので、さっそく使ってみます。
今回は、試しにrubyをインストールしてみました。

$ wget ftp://ftp.ruby-lang.org/pub/ruby/1.8/ruby-1.8.7-p299.tar.gz
$ tar zxvf ruby-1.8.7-p299.tar.gz
$ cd ruby-1.8.7-p299
$ ./configure --prefix=/pkgs/ruby-1.8.7-p299 && make
# make install
## 無事にインストール出来たことを確認
$ ls /pkgs
graft-2.4  ruby-1.8.7-p299
## graftコマンドでインストール
# graft -i ruby-1.8.7-p299
$ ls -l /usr/local/bin
lrwxrwxrwx  1 root root 30 7月 30日 09:27 /usr/local/bin/ruby -> /pkgs/ruby-1.8.7-p299/bin/ruby

rubyをアンインストールしてみる。

# graft -d ruby-1.8.7-p299
EMPTY        /usr/local/lib/ruby/1.8/bigdecimal/ is now empty. Delete manually if necessary.
EMPTY        /usr/local/lib/ruby/1.8/cgi/session/ is now empty. Delete manually if necessary.
...

一部ディレクトリが残ってしまっていますが、-Dオプションで実行することで、空のディレクトリも削除してくれるようです。

アップデートを想定して、ruby1.9系を入れてみることにしました。
アンインストール後に、インストールしても問題ないかと思いますが、今回はPruneという機能を使ってみます。これは既存のファイル群との衝突を回避するために、末尾に.prunedを付けたファイル名にリネームしてくれるものです。

## まず1.8.7をインストール
# graft -i ruby-1.8.7-p299
$ /usr/local/bin/ruby -v
ruby 1.8.7 (2010-06-23 patchlevel 299) [i686-linux]

## 1.9.1をダウンロード、インストール
$ wget ftp://ftp.ruby-lang.org/pub/ruby/1.9/ruby-1.9.1-p429.tar.gz
$ tar zxvf ruby-1.9.1-p429.tar.gz
$ cd ruby-1.9.1-p429
$ ./configure --prefix=/pkgs/ruby-1.9.1-p429 && make
# make install

## graftコマンドでrubyを1.8.7から1.9.1にアップデートします
## アンインストール前に新しいバージョンの物をインストールしようとすると、衝突としてエラーが表示されます
# graft -i ruby-1.9.1-p429
CONFLICT     /usr/local/bin/erb is linked to something other than /pkgs/ruby-1.9.1-p429/bin/erb (/usr/local/bin/erb -> /pkgs/ruby-1.8.7-p299/bin/erb)

# graftコマンドを-pオプションで実行してみると、ファイル名の後ろに.prunedとリネームされているのがわかる
# graft -p ruby-1.8.7-p299
$ ls -l /usr/local/bin
lrwxrwxrwx  1 root root 30 7月 30日 09:39 /usr/local/bin/ruby.pruned -> /pkgs/ruby-1.8.7-p299/bin/ruby
# あらためてインストール
$ graft -i ruby-1.9.1-p429
## 1.9.1がインストールできていることを確認
$ ls -l /usr/local/bin
lrwxrwxrwx  1 root root 30 7月 30日 10:02 /usr/local/bin/ruby -> /pkgs/ruby-1.9.1-p429/bin/ruby

いくつか気になった点がありました。

  • 衝突回避のためにリネームされた.prunedファイルを消せない。

 (-pオプションで実行させる度に、上書きされるようなので問題なし?)

  • 設定ファイルも一緒に上書きされそうなので、.graft-exclude

や.graft-includeなどを使って、必要なものだけインストールするように調整する必要があるかもしれません。(未検証)

非常にシンプルに出来ていて簡単に使うことが出来るので、ごちゃごちゃとした余計な機能はいらない、という人にとってはオススメです。
あとは、ソースからインストールしたものが/pkgsに溜まっていくので、前のバージョンにすぐに切り替えたりといった事もできます。

tarボールからインストールしたものを管理

最近はほとんどのものがパッケージで提供されており、ソースからわざわざインストールする機会もずいぶん減った気がします。
しかし、中にはソースからインストールしないといけない場合もあるかと思います。
自分はApachePHPなど主要なソフトは、ソースからインストールする事が多いです。

今までは、バージョンアップさせる度にバカの一つ覚えと言わんばかりに、make && make installをひたすら叩きまくっていたわけです。
バージョアップしたはいいけど、おかしくなったらすぐ戻せる環境がベストだと思い、ちょっと色々調べてみました。

僕が理想とする機能は、

  • ソースから入れたファイル群を管理できる
  • バージョン毎にインストールしたものが管理できる
  • 前のバージョンに戻せる
  • コマンドから削除ができる

paco

まず最初に見つけたのがpacoです。
これはほぼ理想通りで、欲しい機能がほとんど揃っていました。なにより、使っている人が多くて、実績という点でも安心できそうです。
一つ気になった点は、前のバージョンに戻すような履歴管理が簡単ではなかった点です。
軽く調べた感じだと、pacoballというコマンドで、今のバージョンをtarボール化し、新しいバージョンの物を入れるという感じになりそうです。

インストール

## -Dオプションでカレントディレクトをパッケージ名として利用します
# paco -D make install
## -pオプションでパッケージ名の指定が可能
# paco -p "app-1.4.1" make install

アンインストール

# paco -r app-1.4.1

その他

## インストール済みソフトの一覧表示
# paco -a
## 共有ファイルの表示
# paco -fc app
app-1.4.1:
/usr/local/app/conf/local.conf
## インストールした日を表示
# paco -dd app
01-Sep-2008 18:46  app-1.4.1
## configureオプションの表示
# paco -o app
--disable-hoge --enable-extension
## 現在のバージョンをtarボール化
# pacoball -b app-1.4.1
app-1.4.1.paco.tar.bz2
## tarボール化したものに戻す
# tar jtvf app-1.4.1.paco.tar.bz2

参考
Pacoでソースからインストールした物を管理する - WapBox
paco - a source code pacKAGE oRGANIZER for Unix/Linux
pacoでソースから導入したパッケージを管理する | Glide Note - グライドノート

Graft

次に見つけたのがこのGraftです。
pacoより機能面では劣るものの、ずいぶん昔から存在していたようです。
しかし、使ってる人の情報がほとんどない・・・。非常にシンプルが故に簡単に使うことができます。
衝突回避のためのPruneという機能がユニークです。

インストール

# graft -i app-1.4.1

アンインストール

# graft -d app-1.4.1

その他

## 衝突回避のためのPrune機能。既存ファイルが.pruned拡張子にリネームされる
# graft -p app-1.4.1

Graftの詳細記事はこちら
tarボールソースからインストールしたソフトを管理する「Graft」を使ってみる - フタなしカンヅメ

Stow

次は、Stow(すとーんと読むのかな?)です。
これもけっこう有名な物のようで、色々なサイトで紹介されていました。
モデルとしてはGraftと似ているようですが、Graftより機能が少ないようです。
たぶんこっちのStowのほうが古い。

インストール

# stow -t /usr/local/bin app-1.4.1

アンインストール

# stow -D app-1.4.1

その他

## 既存のファイルを更新した時の再処理(再読込)
# stow -R app-1.4.1

調べてみた感じだと、paco >> Graft >> Stowという印象です。後発であるpocoは機能面で優れており、色々便利な機能がたくさんあるので、新しく使うならpocoが良さそうです。
シンプルで最小限の機能だけで十分ということであれば、Graftがよさそうです。