環境に優しい難読コード

ぼちぼち忘年会やクリスマス会のシーズンとなってきた。

そんなパーティーの1つに出欠の連絡をしなければならない場面があったのだけど、どうやらネタ回答を期待されているらしかったので次のように回答した。

puts [[->(&f){->(n){f[f[f[f[f[f[f[f[f[f[f[f[f[f[n]]]]]]]]]]]]]]}},->(&f){->(n){f[f[f[f[f[n]]]]]}},
->(&f){->(n){f[f[f[f[f[f[f[f[n]]]]]]]]}},->(&f){->(n){f[f[f[f[f[f[f[f[f[f[f[f[f[f[f[n]]]]]]]]]]]]]]]}},
->(&f){->(n){f[f[f[f[f[f[f[f[n]]]]]]]]}},->(&f){->(n){f[f[n]]}},->(&f){->(n){f[f[f[f[f[f[f[f[f[f[f[f[f[f[n]]]]]]]]]]]]]]}},
->(&f){->(n){f[f[f[f[f[n]]]]]}},->(&f){->(n){f[f[f[f[f[f[f[f[n]]]]]]]]}},->(&f){->(n){f[f[f[f[f[f[f[f[f[f[n]]]]]]]]]]}},
->(&f){->(n){f[f[f[f[f[f[f[f[f[f[n]]]]]]]]]]}},->(&f){->(n){n}}].map{|x|x[&:succ][0]}.map(&("%x".method("%"))).join].
pack("H*").unpack("U*").pack("U*").encode(Encoding.default_external)

難解コードとかゴルフとかは苦手なんだけど、相手のためを思って知恵を絞ればできるもんだね。

難読コーディングとしては割と定番の素材を使っていて読解難度はそう高くない。ただ、呼び出し可能オブジェクト技法の数々や、表示側のエンコーディングに依存しない環境(env(1)的な意味で)に優しい設計でありつつ"Encoding::UTF_8"と書くのはあくまでも避けたあたりについては我ながら満足している。

Ubuntu 12.04 preciseをaufs rootにした

表題のようにaufsをroot filesystemとしてマウントしてみたので、手順をメモする。

経緯

最近 DNA940 という面白い機器を手に入れた。なんでも本来は産業用機器のベースとして使用することを想定した機体で、中身はx86ベースの基板にGbE×4やらコンソールポートやらいろいろついている。 Debianが動いたという話も耳にする。

これにソフトウェアルーターを組み合わせて自宅ネットワークのルーターを好きなように組む、という野望を抱いたのがそもそもの動機である。

ところで、DNA940は2.5in HDDを組み込めるのでそれをメインディスクにしても良いのだけど、可動部品は可能な限りなくしたいのでCFのほうが嬉しい。しかしながら、普通にDebianUbuntuのシステムをCFで動かすとすぐに書き込み上限に引っかかるのは目に見えている。 そこでaufsでext4の上にtmpfsをオーバーレイしたものをroot fsにしたい、というのが今回の話だ。

いきなり実機は怖いので、まずはVMWare Fusion上の仮想マシンでやってみる。

手順

同じような需要は各所に有ると見えて、手順は Ubuntuのヘルプサイト にまとまっている。意外と簡単だった。

  1. 仮想マシンを作成する。メモリを1GB、ディスクを2GB割り振って、 ディスクは丸ごとext4のルートファイルシステムとした。Swap領域は作成しない。

  2. Ubuntu Precise (x86-64 Server Edition)をインストールする。 前述のヘルプページではLive CDからインストールするように書いてあるが、 これだとデスクトップ版がインストールされるような気がした。 そこで、普通にサーバー版のインストールディスクを用いた。

  3. 以下はヘルプページの手順に従った。

    • % sudo aptitude install aufs-tools
    • % sudo bash -c "echo aufs >> /etc/initramfs-tools/modules"

    ここでヘルプページに書いてあるrootaufs Scriptを /etc/initramfs-tools/scripts/init-bottom/__rootaufs に保存した上で、

    • % sudo chown root:root /etc/initramfs-tools/scripts/init-bottom/__rootaufs
    • % sudo chmod 0755 /etc/initramfs-tools/scripts/init-bottom/__rootaufs
    • % sudo update-grub
    • % sudo-initramfs -u

    とする。

    initrdまわりはあまり詳しくなかったのだけど、要はこの scripts ディレクトリ以下にあるスクリプト群はinitrd.imgの中にコピーされて、起動時にinitrdで動いている段階で実行されるということらしい。 スクリプトを見る感じ、実行時の ${rootmnt} 変数とかが見慣れないものの大体やってることは予想通りだ。tmpfsをマウントして、元のrootを他のマウントポイントにどかしてreadonlyでremountして、それからaufsで両者を重ねる。

  4. 再起動する。 さっきのスクリプトカーネルの引数にaufs=tmpfsを渡したときのみ発動するように書かれているので、起動時に引数を手入力した。

  5. 起動後 mount が期待通りであることを確認する。

    なお、ヘルプページにも書かれているように、rootaufsだとdhclient3がapparmorに引っかかって動かないようだ。おまけにDHCPを何度か再試行する間、起動を待たされる。私の用途ではDHCPは必要ないのでIPはstaticに割り振ることにした。 ログを見る限り、この問題って起動タイミングの関係上rootfsの移動によってdhclient3のリンクされるライブラリのパスがapparmorが思ってるやつとずれてしまうのが原因みたいね。dhclient3をprelinkとかすれば解決するんだろうか。まー今回は関係ない。

  6. 次は、常にaufs=tmpが渡るようにGrubを設定する。

    ヘルプページに書いてあるのはたぶんGrub1の設定だ。今回の環境の場合はGrub2なので少し手順が異なる。 といっても、やることは簡単で /boot/grub/menu.lst の代わりに /etc/default/grubGRUB_CMDLINE_LINUX_DEFAULT に"aufs-tmpfs"を設定するだけだ。 設定した後は sudo update-grub/boot/grub/grub.cfg を再生成する。

    以上により、起動時に自動的にaufs-tmpfsが引数に渡るように /boot/grub/grub.cfg が設定され、かつカーネルを入れ替えたりして grub.cfg が再生成されても設定が保たれるようになった。

さよならピアソン

ピアソン桐原のピアソングループ離脱にともない、 ピアソンの技術書和書は書店在庫限り だそうだ。

聞いたとき、これは日本のソフトウェア開発にとってとんでもないことだと思った。それ以前に私にとっても困ったことだ。だから、在庫限りであるならばそれを押さえなければならないということで急ぎ書店へと向かった。 しかし、見渡しても買うべき本をそれほど見つけられない。これは何故だろう。

なるほど、古典的名著は数多くある。『達人プログラマ』『アナリシスパターン』『リファクタリング』『計算機プログラムの構造と解釈』『Effective C++』『Effective Java』『人月の神話』『テスト駆動開発』『詳解UNIXプログラミング』『プログラミング言語の概念と構造』『モダン オペレーティング システム』『分散システム―原理とパラダイム』『Java仮想マシン仕様』。どれもその技術分野を触る人なら最低限読んでおく必要のある本ばかりだ。そして、『Modern C++ Design』。

Modern C++ Design―ジェネリック・プログラミングおよびデザイン・パターンを利用するための究極のテンプレート活用術 (C++ In‐Depth Series)

Modern C++ Design―ジェネリック・プログラミングおよびデザイン・パターンを利用するための究極のテンプレート活用術 (C++ In‐Depth Series)

これはC++の歴史をかえた本だ。それに個人的にも、この本をたまたまふらりと入った六本木の青山ブックセンターの新刊棚で手に取らなかったら私はソフトウェア開発を職業にしてない。 そうだとも、あの華々しいC++翻訳書の数々を覚えているだろうか。だからこそ私だって、この度のニュースを「とんでもないことだ」と戦慄したのだった。

だが、買うべき本がない。私に関して言えば上のような基本中の基本の本はもう買ってある、というのもあるけど、それだけではない。

  • C++とかCORBAがそこら中で使われてる時代でもないし
  • Effective Javaとか、開発文化じゃなくて純粋技術の話は読みやすいから原書でもいいし
  • SICPとか原書の方が読みやすいとすら言われるし
  • タネンバウム先生の本は分厚いから、まー売れなそうだし、それを仕事で触るのでなければ必須でもないし
  • そして、Javaオブジェクト指向デザインもコンピュータサイエンスも、ピアソンのラインナップの後続にあたる最近の「must have」な本はみんな翔泳社オライリージャパンが翻訳している

これは売れなかろう。技術書から撤退という判断はやむなしなのかもしれぬ。

英語が苦手な人でも読んでほしくて惜しまれるのは

ぐらいか。

『東京市制概要』

東京市制概要 表紙

ふらりと立ち寄った古書店で昭和十年版『東京市制概要』というのを見つけて買ってきた。結構役に立ちそうだ。

アメリカ系の会社で地図をやっていると「なんでTokyo Cityってないの?」みたいな知識がたまに必要になる。なんでかというと戦時体制がどうたらという話になるけど、この辺の知識は全部二次、三次の資料に基づく受け売りだ。実際のところ府市統合以前がどうで、その後どうなってという正確な知識には欠けている。その辺きちんと知りたいよなーと思っていたところにこの本との出会いである。これだから古書店巡りはやめられない。ぼちぼち読んでいこうと思う。

ぐんまRuby会議01で発表した

ぐんまRuby会議01 で発表してきた。

講演依頼では、「Rubyを通じて見てきた世界、ソフトウェア開発者としての世界観を語ってほしい」とのことであった。そうすると、私がRubyに関わっている理由は2つだ。

  • 個人的にRubyが好きで手に馴染んでいて、これからも継続してほしいから
  • 私が望む世界が実現されるための手段としてRubyは有効であり、Rubyに発展してほしいから

上についていえば好きなものを好きなのにそんなに理由はない。たぶん「プログラマのあるサブセットにとって自然で親しみやすく」というMatzの言語デザイン意図にうまくはめられたというだけだろう。 下についていうと、Rubyはあくまでも手段であり話題の主役ではない。が、Matzの意図についてはMatzがすでに多くを語っているし、私は下について話すことにした。内容は 過去の記事 +α。

ある人の世界観を共有する手段としては、背景にある読書歴というのが欠かせない。またそれらの書籍を通じてよりハイコンテキストな情報を限られた時間で伝達できる。だから今回はいろいろな書籍を挙 げながらMad web programmerと私の望む世界とそこに至るための私自身の取り組みについて話した。

スライドだけ見ても意味不明で、むしろ誤解を招きかねない部分もあるのでスライドの公開予定はない。ただ、その中では次のような書籍に言及した

正直なところ、あの内容を話すのも準備するのもかなりしんどい。それで若干準備し切れていない部分もあった。需要があればまたどこかで話したいと思う。

光目覚まし時計

光目覚まし時計というものを初めて買った。騒音でなく光によって目覚めを図るというものだ。2ヶ月ばかり使っている限りではなかなか好印象だ。OKIROという直球な名前も一周回ってセンスよくすら感じる。定価は39,000円だけど、Amazonではもっと安く売ってたし。

私はもともと睡眠時間が長いたちで、日常生活を送っているとなかなかその体質に足るだけの睡眠時間を毎日とることは難しい。 それで起きられなくて目覚まし時計に頼る訳だけれども、生半可なものでは起きられない。新しい目覚まし時計を買うとしばらくは起きられるが、一週間ぐらい経って新しい機体の操作に慣れると半ば眠ったまま無意識に止めてそのまま寝続けてしまう。そういうわけで、爆音目覚ましだとか音色が豊富な(=その音に慣れるのを防ぐ)目覚ましだとかをいろいろと試してそれなりに効果は得たものの完璧とはいかなかった。

それに比べると現在はOKIROによって次のように改善されている。

  • 指定した時刻よりも少し前から徐々に明るくなって日の出を再現する。明るくなったら起きるという自然な仕組みに基づいているので目覚めがすっきりする。どのぐらいの時間をかけて明るくしていくかは調整できる。
  • 従来は、目覚まし時計の音がまだ眠っている他の人に五月蝿くて迷惑だろうと考えて、早めに音を止めてしまっていた。しかし、それが為に二度寝を防げないことがあった。光であれば音波よりも遥かに指向性が強いので自分にしか影響しない。だから安心して、起き上がって着替えて顔を洗うまで目覚まし時計を放置しておける。目覚まし時計を止めた状態で二度寝という最悪のパターンを避けられる。
  • 個人的には音よりも光の方が目覚めやすい模様。これは体質によるだろうけれども、私は慣れればある程度大きな音が鳴っていても寝られる。けれども1時間明るい光を間近で照らされるとさすがに目が覚める。

ちなみにメーカーは読書灯としても使用可能とか時差ぼけの解消に有効とか謳っているけれども、こちらは試していないのでわからない。Amazonでの評を見ると読書灯としては光がどぎつくて目に厳しいとかいう意見もある。 光の照射面積が狭いという意見にはあまり賛同しない。私も寝相は良くないけれども、上下逆さになるとかベッドから落ちて寝ているような寝相でなければ有効範囲内には頭があるだろうと思われる。

SSD/Linuxをvirsh+kvm+qemuにインストールする

OpenMicroServerカーネルビルド環境としてSSD/Linuxを用意しようと思う。 VMWare用のイメージが提供されているので以前はVMWare Fusionでそれを動かしたことがある。 今回は故あってKVM+qemu環境で動かすことになった。

インストール

サポートサイト からVMWare実行イメージをダウンロードする。zipで固められているのでこれを展開する。

% unzip ssdlinux-1.0.0-20121220.zip

このイメージは3つのディスクイメージから成っている。

% ls
hda.vmdk  hdb.vmdk  ssdlinux.vmx  vmboot.fs

hda.vmdkがルートファイルシステム, hdb.vmdkがホームディレクトリらしい。 それでvmboot.fsがext2のrawイメージで起動用FDのイメージだ。

最初hda.vmdkの中にbootセクタを探そうとしたり、hda.vmdkをqcow2に変換したら動かなかったりといろいろ苦労した。幸いなことにqemuがそのままvmdkを読めるので特に変換はせずに使用する。

VMWare用のssdlinux.vmxを参考に、virsh用に次のようなドメインを定義した。 virt-managerの手も借りたので下記は最小セットではない。

<domain type='kvm'>
  <name>v254</name>
  <description>Build Environment for OMS firmware</description>
  <memory>262144</memory>
  <currentMemory>262144</currentMemory>
  <vcpu>1</vcpu>
  <os>
    <type arch='i686' machine='pc-0.12'>hvm</type>
    <boot dev='fd'/>
    <bootmenu enable='yes'/>
  </os>
  <features>
    <acpi/>
    <apic/>
    <pae/>
  </features>
  <cpu>
  </cpu>
  <clock offset='utc'/>
  <on_poweroff>destroy</on_poweroff>
  <on_reboot>restart</on_reboot>
  <on_crash>restart</on_crash>
  <devices>
    <emulator>/usr/bin/kvm</emulator>
    <disk type='file' device='floppy'>
      <driver name='qemu' type='raw'/>
      <source file='/var/lib/libvirt/images/ssdlinux/vmboot.fs'/>
      <target dev='fda' bus='fdc'/>
      <alias name='fdc0-0-0'/>
      <address type='drive' controller='0' bus='0' unit='0'/>
    </disk>
    <disk type='file' device='disk'>
      <driver name='qemu' type='vmdk'/>
      <source file='/var/lib/libvirt/images/ssdlinux/hda.vmdk'/>
      <target dev='hda' bus='ide'/>
      <alias name='ide0-0-0'/>
      <address type='drive' controller='0' bus='0' unit='0'/>
    </disk>
    <disk type='file' device='disk'>
      <driver name='qemu' type='vmdk'/>
      <source file='/var/lib/libvirt/images/ssdlinux/hdb.vmdk'/>
      <target dev='hdb' bus='ide'/>
      <alias name='ide0-0-1'/>
      <address type='drive' controller='0' bus='0' unit='1'/>
    </disk>
    <controller type='ide' index='0'>
      <alias name='ide0'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1'/>
    </controller>
    <controller type='fdc' index='0'>
      <alias name='fdc0'/>
    </controller>
    <interface type='bridge'>
      <mac address='52:54:00:99:cf:fe'/>
      <source bridge='br0'/>
      <target dev='vnet0'/>
      <model type='e1000'/>
      <alias name='net0'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
    </interface>
    <serial type='pty'>
      <source path='/dev/pts/1'/>
      <target port='0'/>
      <alias name='serial0'/>
    </serial>
    <console type='pty' tty='/dev/pts/1'>
      <source path='/dev/pts/1'/>
      <target type='serial' port='0'/>
      <alias name='serial0'/>
    </console>
    <input type='mouse' bus='ps2'/>
    <graphics type='vnc' port='5900' autoport='yes' listen='127.0.0.1' keymap='en-us'>
      <listen type='address' address='127.0.0.1'/>
    </graphics>
    <video>
      <model type='cirrus' vram='9216' heads='1'/>
      <alias name='video0'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/>
    </video>
    <memballoon model='virtio'>
      <alias name='balloon0'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x07' function='0x0'/>
    </memballoon>
  </devices>
 </domain>

このXMLをssdlinux.xmlに保存して、

% virsh define ssdlinux.xml

と定義する。

ここでvirt-managerを起動して、GUIからこのドメインを起動した。

シリアルコンソール

さて、何をするにせよvirt-managerのターミナルエミュレーション経由では不便極まる。 デフォルトでDHCPクライアントとSSHdが立ち上がるので、起動してからの作業ならSSHでも良い。でも できればシリアルコンソールから操作したい。

そこでbootディスクをマウントして修正してやることにする。幸いなことに起動ディスクに入っているのは独自のブートローダーとかではなくGRUBなので、勝手は分かっている。

% mkdir /mnt/floppy
% mount -t ext2 /dev/fd0 /mnt/floppy
% cd /mnt/floppy/boot/grub

で、menu.lstの中身を編集してカーネルオプションとしてconsoleの指定を足してやる。

kernel          (hd0,0)/vmlinuz root=/dev/hda1 clock=pit nosmp noapic nolapic console=tty0 console=ttyS0,9600n8

そうしたらアンマウントして再起動でOKだ。

% cd /
% umount /mnt/floppy
% shutdown -r now

virt-managerのView -> Text Consoles -> Serial1を選択すると仮想シリアルポートに起動中のメッセージが出るのが分かる。

これだけだとシリアルからはログインできないのでgettyも設定してやる。Graphical Console VNCの方に戻してログインしてから、

  • /etc/inittab にttyS0のエントリを足す

    c7:2345:respawn:/sbin/agetty ttyS0 9600

  • /etc/securetty のttyS0の行をuncommentする。
  • kill -HUP 1 する。

これでホスト環境で virsh console v254 とすればログインできるようになった。