HT-03Aのroot化

docomoAndroid携帯HT-03Aですが、root権限がないため自由に出来ないのが不満でした。

My daylife in virtualworldさんを見て、そのままやったらrootになれました。
最初のパラメータが謎ですが (何かファイルが要るのかと思った)。

とりあえず

# mount -o remount,rw /dev/block/mtdblock3 /system
# cd /system/bin
# cat sh >rootshell  #cpがなかったので
# chmod 4755 rootshell

とやっておいて、いつでも

$ rootshell

でrootになれるようにしておきました。

さあ何しよう。

8/20追記
当然ながら、上記のrootshellをsuとすれば、標準的なコマンド名となり、巷にあるroot用アプリも使えたりするようです (Overclockできました)。
しかし同時に、ダウンロードしたアプリに対して完全な制御権を渡すことでもあるため、必要ない限りはsuにしないほうがいいというのが私の考えです。

あと謎のパラメータは、単なるテンポラリファイル名のテンプレートでした。テンポラリといってもダミーのsendfile()の入力なのですが。
ここにソースがありました。zero pageに貼られるコード内で何気にcurrentとか参照しちゃうあたりがおもしろいです。

GeoIPでSSHに接続できる国を制限する

自分たちの管理するシステムは日本国内からしかログインしないので、国外からのSSH接続を拒否するのは理に適っている*1

Debianベースのシステムでは/etc/hosts.allowでaclexecオプションを使うことにより、外部コマンドを実行してアクセス可否を判定することができる。今回はこれを使ってGeoIPデータベースで接続元の国を判別する方法を実装してみた。

まずはGeoIPデータベースのアップデートから。フリーのデータベースは月に1度更新されるらしい。このスクリプトをcronで毎日実行し、更新されていたら取得する。(スクリプトと同じディレクトリに保存される)

/etc/hosts.allowは以下のように設定する

ALL: 無条件に許可するIPがあればここに記述
sshd: ALL: aclexec /usr/local/geoip/check %a

/etc/hosts.denyは以下のようにして、許可されなかった接続を拒否する。

sshd: ALL

aclexecで読んでいるスクリプトこれ
rule関数でルールを決める。ここでは日本と判定不能なケースを許可している。
どちらのスクリプトもsyslogにログを出力する。

ftpdなども同じ方法で国別に制限をかけることが可能。

*1:brute force対策としてはパスワードでのログインを禁止するのがベストだが、いろんな事情で禁止できないケースもある。またiptables -m recentで一定時間内に接続試行できる回数を制限するのも有効。

rdiffを使ったSQLiteのバックアップ

稼働中のWebアプリのSQLiteデータベースを定期的にバックアップしたい (単なるファイルコピーではデータの一貫性を保証できない…コピー中に更新されたら?)。
従来は

sqlite3 データベース .dump > バックアップ

をcronでまわしてダンプをとっていた。

小規模なうちはこれでよかったが、データベースのサイズが100MB単位になると1分以上かかるケースもあり、その間にアプリからの更新がブロックされタイムアウトしてエラーが頻発していた。

LVM上であればスナップショットを使ってロックなしでバックアップすることができるが、通常のパーティションの上で稼働しているシステムでは (reflinkもまだないし) ロックをするほかない。

いろいろ調査・実験した結果、rdiffを使うとロック時間を最小化することができた。
rdiffはバイナリ差分をとるツールで、前回のバックアップからの差分をとるという形で使えばバックアップに使える。
rsyncアルゴリズムを使用していて、2つのファイルを直接比較するのではなく、

  1. 旧ファイルからsignatureを作る
  2. signatureと新ファイルから差分を作る

という2ステップにわけて使えるのが特徴。

SQLiteのバックアップに適用する場合、

  1. 前回のバックアップのsignatureを作る
  2. データベースをロック
  3. signatureとデータベースから差分(delta)を作る
  4. ロック解除
  5. 前回のバックアップと差分(delta)から新バックアップを作成

という手順で行えば、ロック中は現行データベースのread以外の巨大I/Oをしないので、他の方式より高速化が期待できる。

実際に試したところ、cpコマンドによるベタコピーでは30秒近くかかったデータベースに対し、rdiff方式では数秒で差分を取ることが出来た。

ロックは以下のようなPythonスクリプトを使った (シェルスクリプトでも書いてみたが、あまり堅牢にできそうにないので断念)。

#!/usr/bin/python

import sys, os
try:
    import sqlite3
except ImportError:
    from pysqlite2 import dbapi2 as sqlite3

if len(sys.argv) < 3:
    print >>sys.stderr, "Usage: %s DB CMDLINE..." % sys.argv[0]
    print >>sys.stderr, "Executes CMDLINE while locking DB"
    sys.exit(1)

src = sys.argv[1]
cmdline = sys.argv[2:]

db = sqlite3.connect(src, timeout=60.0, isolation_level=None)
db.execute("BEGIN DEFERRED")
db.execute("SELECT COUNT(*) FROM sqlite_master") # This creates SHARED lock
retval = os.spawnvp(os.P_WAIT, cmdline[0], cmdline)
db.execute("COMMIT")
if retval != 0:
    print >>sys.stderr, "Command returned %d" % retval
sys.exit(retval)

このスクリプトsqlite-lockとして

rdiff signature $LATEST $SIG
sqlite-lock rdiff delta $SIG $DB $DELTA
rdiff patch $DELTA $LATEST $NEW
ln -f $NEW $LATEST

のような感じでバックアップを行っている。
実際にはデータセンターからローカルにSSH経由でバックアップしているのだが、signatureとdeltaだけしかネットワークを通らないので高速。(rsyncがやっていることを分解したようなもの)

Jauntyにアップグレード

UbuntuJauntyにアップグレードしてからはまったこと。

画面がプチフリーズ or 完全フリーズ

昔のnVIDIAドライバでよく出ていた症状が再発している?
nVIDIAドライバーをダウングレードしたら直った(180→173)

sudo apt-get install nvidia-glx-173 nvidia-173-kernel-source nvidia-173-modaliases

これは64ビット機でしか出なかったがカードの違いかもしれない。

テンキーで入力できない

「マウスキー」がONになっている。
[システム]-[設定]-[キーボード]-[マウス・キー] でチェックを外したら直った。
http://ubuntuforums.org/showthread.php?p=7154515

端末で記号の文字幅が狂う

日本語でUTF-8のとき、gnome-terminalでの★や●や罫線など(CJK ambiguous)の文字幅が、デフォルトで全角になったようだ。(以前のバージョンでは半角で表示されていた)

vimmuttやscreenなど、アプリケーション側のデフォルトでは半角のことが多いので、自分としては半角の方が好みだ。(ssh先のマシンまで全部設定を変えるのは大変)

というわけで、~/.gnomerc に

export VTE_CJK_WIDTH=0

と書き加えて半角に設定。

La FoneraのGPIOでAVRに書き込む


La Foneraは安価なWiFiルータですが、自分でプログラムを作って動かすことのできる、小さな無線デバイスでもあります。
シリアルポートや5本の未使用GPIOがあり、情報はネットに出回っていますから、何かハードウェアを接続して値を取ったり制御したりもできます。

そこにAVRなどのマイクロコントローラをつなげれば、ADコンバータやPWM、多くのIOポートなど、さらに用途を広げることもできます。
AVRから見ると、Foneraはシリアルインターフェース付きの安価なWiFiカードとも言えます。

さて、FoneraとAVRを接続するなら、AVRへのファームウェアの書き込み(プログラミング)も、Foneraからできないでしょうか?

AVRのプログラミングは、シリアル方式(ISP)を使えば4本のIO (SCK,MISO,MOSI,RESET) だけでできます。FoneraのGPIOは5本ありますから十分です。(さらにSSピンを接続すれば、実行時にハードウェアSPIで通信することもできます)

AVRのデータシートを読むと、ISPプログラミングの手順は、さほど難しくないことがわかります。

というわけで、Foneraで動くAVRライタ fonasp を作成しました。

このようなコマンドラインでPCから書き込みできます。

ssh root@fonera /jffs/fonasp - < firmware.bin

(このFoneraDD-WRTに入れ替えSSHとJFFSを有効にしてあります)

このプログラムではカーネルモードのドライバを使わず、ユーザスペースから直接ハードウェアのレジスタを読み書きすることで、高速にbit-bangingを行っています。

詳細およびダウンロードはこのページからどうぞ。

GPIOにぶら下がっているコンデンサは除去します。
シリアルポートヘッダの未使用ピンにGPIOを接続して、AVRボードと接続しやすくしました。