郵便番号データは自分で加工しない

結論を先に。

以下各論。

*1:かつ zip 形式圧縮ということで Unix 系もうれしい。

*2:なお2010年はじめあたりまで事業所の個別郵便番号と一般の郵便番号に矛盾のあるレコードが1件あった気がする。現在はまだたしかめていない。

Compiz を Python からあやつる

タイトルは大袈裟。


ここ半年ほど Compiz のワークスペース切替器にキューブではなくデスクトップの壁(wall)を使っています。こっちのほうがキビキビ動くし。

んでこの wall plugin ですが,システム起動直後だと,ワークスペース切替時に壁紙がスクロールしないんです。まぁそんな仕様だと思えばいいんですけど,CompizConfig 設定マネージャを立ち上げて,「デスクトップの壁」プラグインを一度無効化して有効にすると,壁紙もスクロールするようになります。じゃあそういう仕様じゃないじゃん。

いままでいちいち起動後に CompizConfig 設定マネージャを立ち上げて修正していたんですけど,めんどくさい。CompizConfig 設定マネージャ*1Python で書かれているっぽいので Python から Compiz の挙動を操作できるんじゃね,と思ってやってみました。

import time
import compizconfig
ccs = compizconfig

context = ccs.Context()
wall = ccs.Plugin(context, 'wall')

wall.Enabled = False

time.sleep(1)

wall.Enabled = True

いちいち compizconfig.Context() って書いてもいいんだけど長ったらしいので ccs = compizconfig ってしてます((まぁ本気で短く書こうと思ったら compizconfig のままやったほうが今回は短いと思う。Context オブジェクトもわざわざ変数に代入する必要ないし。))。って実は CompizConfig 設定マネージャのソースの真似。Python ってこういう書き方もできるのねと勉強になりました。

time.sleep() なしでもうまく動くかなと思ったけど,ムリだったので入れてる。1秒も待たされるのはアレだけど,まぁ実害ないというか設定マネージャ立ち上げるより百倍はやいので。


ソース見ると相当たいしたことないでしょ。でも API ドキュメントとかが全然なくて結構苦労しました。

Compiz の Git レポジトリは Compiz Git repository browser とかで見られるんだけど,libcompizconfig のソースから[http://cgit.compiz.org/compiz/compizconfig/libcompizconfig/tree/include/ccs.h:title=include/ccs.h] とか Python バインディングのソースから[http://cgit.compiz.org/compiz/compizconfig/compizconfig-python/tree/src/compizconfig.pyx:title=compizconfig.pyx] とか見ながら書いた。

*1:よくよく考えたら変な名前ですよね。まぁ英語でももともと CompizConfig Setting Manager ですけど。

電源連動 USB HDD の切断・再接続を CLI で

さいきんの外付けハードディスクは電源連動機能とかついてたりしますね。んで,たとえば REGZA とかにつなぐと,テレビの電源を on にしたときだけハードディスクの電源が on になったりします。

同じようなことを Linux からもやってみたい。

といっても PC の電源を切ったらハードディスクの電源が切れるのは当たり前。PC の電源を入れっぱなし HDD 接続しっぱなしで,ソフトウェア的に HDD の電源を入れたり切ったりできたらいいなぁと思いやってみました。

もしうまくできれば,たとえば定時バックアップの際だけハードディスクの電源を入れて,バックアップが終わったら電源を切るとかできそう。かえって寿命が落ちるかもしんないけど。

調べてみたら,またたびりなっくす UbuntuでのUSBメディアの安全な取り外し とかその元ネタの Yan Li's Words: Safely remove an USB hard drive in Linux とかですでにやられてました。再接続までコミでやってるのはなかったので一応記事におこしておきます。


実験環境は下記の通り。

切断編

前提として,アンマウント済みになってるとする。

1. 下調べ

いくつか知っておく必要のある ID がある。

udevadm というコマンドを使うと,デバイスノードパスからこれらの情報を取得することができる。今回の例だと HDD が /dev/sdc にぶらさがっているとする。

$ sudo udevadm info --query=path --name=/dev/sdc

/devices/pci0000:00/0000:00:1d.7/usb1/1-8/1-8:1.0/host3/target3:0:0/3:0:0:0/block/sdc

出力結果のうち

  • 1-8 ってところが,USB のバス ID = 1, デバイス ID = 8 であることを示している
  • 3:0:0:0 ってところが SCSI のホスト ID = 3, チャネル = 0, デバイス ID = 0, LUN = 0 であることを示している


ちなみに,SCSIバイスとしての各種 ID を知りたいだけなら /proc/scsi/scsi の中身を見てもわかる。

$ cat /proc/scsi/scsi

Attached devices:
Host: scsi0 Channel: 00 Id: 00 Lun: 00
  Vendor: ATA      Model: WDC WD1600BEVT-7 Rev: 11.0
  Type:   Direct-Access                    ANSI  SCSI revision: 05
Host: scsi2 Channel: 00 Id: 00 Lun: 00
  Vendor: Generic- Model: Multi-Card       Rev: 1.00
  Type:   Direct-Access                    ANSI  SCSI revision: 00
Host: scsi3 Channel: 00 Id: 00 Lun: 00
  Vendor: I-O DATA Model: HDCR-U           Rev:     
  Type:   Direct-Access                    ANSI  SCSI revision: 02
2. HDD へのフラッシュ(強制書込)

OS 側がアンマウントしていても,HDD 内部のキャッシュ内容がフラッシュされていない可能性がある(らしい)ので強制的にフラッシュする。非標準コマンドの sdparm というコマンドを使うので apt-get などでインストールしておくこと。

$ sudo sdparm --command=sync /dev/sdc

    /dev/sdc: I-O DATA  HDCR-U            

んー。非同期で実行されている気もする。フラッシュが終了してるという確証はどうやったら得られるのだろう。

ちなみにたいていのディストリビューションで標準的にインストールされてる hdparm-f コマンドも同じようなことができそうだけど,man 読んだ感じだと,あれは OS 側のバッファキャッシュをフラッシュするためのコマンドのような気がする。


さらに,同じコマンドを使ってデバイス(HDD)のスピンダウンを行うこともできるらしい。

$ sudo sdparm --command=stop /dev/sdc

だけど,手持ちの IO-DATA の HDCR-U だと,一度スピンダウンするもののそのあと再びすぐにスピンアップしてしまい意味がなかった。逆に壊れるんじゃないかと怖くなった。

3. SCSI サブシステムから切り離し

んで,いままでのコマンドはデバイスノードパス対象のコマンドだったんだけど,もう必要ない,というかデバイスノード経由でアクセスできると危ないので,切り離す。

切り離す前。

$ ls /dev/sd*

/dev/sda  /dev/sda1  /dev/sda2  /dev/sda3  /dev/sdb  /dev/sdc  /dev/sdc1

いままでの実行例でわかるとおり,USB HDD のデバイス名は /dev/sdc*

さきほど調べた SCSIバイスとしてのホスト ID 等をパラメータとして指定しつつ /proc ファイルシステムに下記のようなテキストを書き込む。

$ echo 'scsi remove-single-device 3 0 0 0' | sudo tee /proc/scsi/scsi

あ,tee コマンドを使っているのは,今回の環境例が Ubuntu であり root 権限でコマンドを実行するには sudo 使うから。簡単に言うと,root 権限で

# echo 'scsi remove-single-device 3 0 0 0' > /proc/scsi/scsi

というのを実行しているのとほぼ同義。これをそのまま sudo でラップしてもリダイレクトしているのは一般ユーザ権限になってしまいうまくいかないので,tee コマンドを利用して root 権限でパイプ書込をしている。


ともかく,このようにすると,

$ ls /dev/sd*

/dev/sda  /dev/sda1  /dev/sda2  /dev/sda3  /dev/sdb

見事 /dev/sdc* のデバイスノードが消えた。

4. USB パワーを落とす

いよいよ USB デバイスのパワーを落とす。

$ echo 'suspend' | sudo tee /sys/bus/usb/devices/1-8/power/level

これを実行したしばらくのち((IO-DATA の USB HDD の場合,だからかと思ったんだけど,ひょっとすると /sys/bus/usb/devices/*/power/autosuspend のデフォルト値 2 が影響したのかもしれない。ちょっと未検証でわからん。see Manual driver binding and unbinding [LWN.net]))に実際にパワーが切れた。感動。

一番最初にあげた文献の例だとこれを行うまえに次で例示してある「USB サブシステムからの切り離し」をおこなっているんだけど,実際にはこの順序にしないと,後述する再接続ができなかった。


あと,この suspend というコマンドトークンで USB 電源を切るのは,カーネルバージョン 2.6.32(つまり Ubuntu Lucid のカーネルバージョンだ)以下でしか使えないらしい。

2.6.33 以上だと /sys/bus/usb/devices/*/remove というノードが新設されたのかな*1。ちょっとよくわからんです。

5. USB サブシステムから切り離し

OS の USB サブシステムから切り離す(ってこういう表現で合っているかもわかんないけど)。

$ echo -n '1-8' | sudo tee /sys/bus/usb/drivers/usb/unbind

再接続編

以上のようにして切断した USB HDD をつないだまま再接続(パワー on)するには,いままでの過程の逆をおこなえばよい。

まず USB サブシステムへの再接続(再登録)を行う。

$ echo -n '1-8' | sudo tee /sys/bus/usb/drivers/usb/bind

このとき以下のようなカーネルメッセージを吐くことがある。

usb 1-8: configuration #1 chosen from 1 choice
usb 1-8: can't set config #1, error -1

対処方法がわかんないので無視する。IO-DATA の USB HDD だから出たってこともないみたい。たしか USB メモリスティックでも出力された気がする。

次に USB パワーを上げる。

$ echo 'on' | sudo tee /sys/bus/usb/devices/1-8/power/level

なおいままでのシーケンスの順序(USB サブシステムからの切断とパワーオフの順序とか)がよくないと下記のようなカーネルメッセージを吐いてうまくいかないことがある。

/sys/bus/usb/devices/1-8/power/level: Transport endpoint is not connected

そんなときは物理的に USB から外して再接続してやり直してみること。


SCSI サブシステムへ再接続する。

$ echo 'scsi add-single-device 3 0 0 0' | sudo tee /proc/scsi/scsi

すると(通常 HDD を USB で接続したときのように)下記のようなカーネルメッセージが表示される。

scsi 3:0:0:0: Direct-Access     I-O DATA HDCR-U                PQ: 0 ANSI: 2 CCS
sd 3:0:0:0: Attached scsi generic sg2 type 0
sd 3:0:0:0: [sdc] 1953525168 512-byte logical blocks: (1.00 TB/931 GiB)
sd 3:0:0:0: [sdc] Write Protect is off
sd 3:0:0:0: [sdc] Mode Sense: 3c 00 00 00
sd 3:0:0:0: [sdc] Assuming drive cache: write through
sd 3:0:0:0: [sdc] Assuming drive cache: write through
 sdc: sdc1
sd 3:0:0:0: [sdc] Assuming drive cache: write through
sd 3:0:0:0: [sdc] Attached SCSI disk

で,実際にデバイスノードも生成される。

$ ls /dev/sd*
/dev/sda  /dev/sda1  /dev/sda2  /dev/sda3  /dev/sdb  /dev/sdc  /dev/sdc1

あとはマウントするなりなんなり。めでたしめでたし。

課題

再接続編を見ればわかるとおり,再接続時においてもともと接続されていたときの SCSI サブシステム上のバス ID や USB サブシステム上のバス ID とかがわかっていることが前提となっている。これらをなんとか sysfs や procfs 経由で取得できればなぁと思う。


今回使った USB HDD。ファンレスなのはうれしいけど,電源投入後スピンアップするまでがちょっと遅いのとうるさい(ゴゴゴゴっていう)気がする。採用ドライブの個性で個体差ありそうだけど。

本文と関係ないけど,センチュリーの裸族のお立ち台って電源連動機能なかったなぁ(実際にはクーリングファンつきの eSATA プラスには電源連動機能がついてる),電源連動機能つきのああいうのがあれば REGZA 用に使いたいなぁ,と思ってたら,玄人志向のやつは電源連動があるっぽい。レビューがほとんどないのが不安。あと,HDD にアダプタつける形になるのかな?よくわからん。

SHDocVw で表示中のページをファイルに保存

せめて月イチくらいでは何かかきたいので書く。

んで,ブラウザコンポーネント(SHDocVw)で,表示中のページをファイルに保存する方法。ただし画像等のリソースファイルの保存(Web ページ、完全)や Web アーカイブとしての保存はできない。「Web ページ、HTML のみ」のイメージ。リソース込みで保存したい場合の方策はあるのかな。

ほぼ how to save html file in VC++ で引用されているサンプルのまま。

ほんとはフォームの pas ファイルからの切り出しなので FWebBrowser が外在化してたりおかしいけど,サンプルなので。

uses
  OleCtrls, ActiveX, SHDocVw;

var
  FWebBrowser: TWebBrowser;

procedure SaveWebPage(AFileName: string);
var
  PFile: IPersistentFile;
  WFileName: PWideChar;
begin
  PFile := FWebBrowser.Document as IPersistFile;

  WFileName := StringToOleStr(AFileName);

  try
    PFile.Save(WFileName, False);
  finally
    SysFreeString(WFileName);
  end;
end;

独立したプロシジャになってるけど,ほんとは NavigateComplete2 イベントが発火したあとに実行するなど,いろいろ考えなくてはいけない。

メリット
  • Cookie 等について考える必要がない
デメリット
  • エンコードミスマッチで文字化けしていた場合はどうなる?
  • Excel や Word などが内部で開かれた場合はどうなる?
  • エラー(5xx や 4xx 系)がおきた場合のハンドリングがめんどう(イベントドリブンなので)

つまり。
すでに SHDocVw コンポーネントを(オートパイロット的に)使っている場合には使ってもいい(価値がある)。そうでなくて wget 的ことがしたいときにわざわざ SHDocVw を使うのは意味がない。そのような場合たとえば WinInet などを使えばよい(.Net だと webClient を使うほうがお気楽かな)。WinInet で Cookie 込みで使うノウハウはまだもってないので,暇ができたらやってみたい。

Ubuntu 10.04 (Lucid) でスプラッシュスクリーンをなんとかする

なんとかするってなんだ。

わたしが使っているマシンの VGANVIDIAGeForce 7600 GS です。結構古いですね。んで Ubuntu Lucid から NVIDIA のカードのデフォルトグラフィックドライバが nouveau というのにかわったんだけど,これから nvidia プロプラドライバに変更したら,起動時のスプラッシュスクリーンの表示が解像度が低くなってしまった。

実害はないんだけど,なんとなく気持ち悪いので直してみました。

[Lucid][Ubuntu 10.04] High resolution Plymouth & Virtual Terminal for ATI/NVIDIA cards with proprietary/restricted driver | Tux's idyllic life. がとても参考になった。英語に抵抗感のないひとはこちらを読んだらいいと思う。とてもわかりやすい構造で書いているので。

概要だけいうと,カーネルフレームバッファを uvesafb というドライバモジュール*1を利用するように変更する。なおスプラッシュスクリーンは Plymouth という機構にかわったらしいんだけど,そのへんのカスタマイズとかには興味ないので触れません。



まず,必要となるソフトをインストールする。uvesafb カーネルモジュール自体はもともと入ってるが,uvesafb には v86d というコンポーネントが必要になるのでインストールする。また,使っているグラフィックカードBIOS レベルで利用可能な画面解像度を調べるために hwinfo というパッケージもインストールする(こちらは必ずしも必要ない)。

$ sudo aptitude install v86d hwinfo

さっそく hwinfo コマンドを使って,使っているグラフィックカードでサポートされている VESA BIOS ビデオモードを確認する。sudo つけなくても怒られないけど,下記のような結果を得ることができないのでつける。

$ sudo hwinfo --framebuffer

02: None 00.0: 11001 VESA Framebuffer                           
  [Created at bios.464]
  Unique ID: rdCR.XJVGY3Zr0S5
  Hardware Class: framebuffer
  Model: "NVIDIA G73 Board - p345h0b "
  Vendor: "NVIDIA Corporation"
  Device: "G73 Board - p345h0b "
  SubVendor: "NVIDIA"
  SubDevice: 
  Revision: "Chip Rev"
  Memory Size: 256 MB
  Memory Range: 0xd0000000-0xdfffffff (rw)
  Mode 0x0300: 640x400 (+640), 8 bits
  Mode 0x0301: 640x480 (+640), 8 bits
  Mode 0x0303: 800x600 (+800), 8 bits
  Mode 0x0305: 1024x768 (+1024), 8 bits
  Mode 0x0307: 1280x1024 (+1280), 8 bits
  Mode 0x030e: 320x200 (+640), 16 bits
  Mode 0x030f: 320x200 (+1280), 24 bits
  Mode 0x0311: 640x480 (+1280), 16 bits
  Mode 0x0312: 640x480 (+2560), 24 bits
  Mode 0x0314: 800x600 (+1600), 16 bits
  Mode 0x0315: 800x600 (+3200), 24 bits
  Mode 0x0317: 1024x768 (+2048), 16 bits
  Mode 0x0318: 1024x768 (+4096), 24 bits
  Mode 0x031a: 1280x1024 (+2560), 16 bits
  Mode 0x031b: 1280x1024 (+5120), 24 bits
  Mode 0x0330: 320x200 (+320), 8 bits
  Mode 0x0331: 320x400 (+320), 8 bits
  Mode 0x0332: 320x400 (+640), 16 bits
  Mode 0x0333: 320x400 (+1280), 24 bits
  Mode 0x0334: 320x240 (+320), 8 bits
  Mode 0x0335: 320x240 (+640), 16 bits
  Mode 0x0336: 320x240 (+1280), 24 bits
  Mode 0x033d: 640x400 (+1280), 16 bits
  Mode 0x033e: 640x400 (+2560), 24 bits
  Config Status: cfg=new, avail=yes, need=no, active=unknown

このカードでは BIOS レベルでは 1920x1080 とかサポートされてない。がーん。

以上で下準備おわり。


早速設定をしていく。GRUB2 の場合,/etc/default/grub の該当部分を下記のように変更する。

GRUB_CMDLINE_LINUX_DEFAULT="quiet splash nomodeset video=uvesafb:mode_option=1280x1024-24,mtrr=2,scroll=ywrap"

GRUB_GFXMODE=1280x1024

GRUB_GFXMODE のほうは別に指定しなくてもいいと思う。

キモは GRUB_CMDLINE_LINUX_DEFAULT のほうなんだけど,quiet splash はもともと設定されていると思う。

nomodeset は KMS (Kernel Mode Setting) を無効にするという意味。今回のようにカーネルフレームバッファドライバとしては uvesafb を使うばあい,Kernel Mode Setting は使えない(フレームバッファドライバと X.Org ドライバが一致しないからね)んで指定しているみたい。たぶんわざわざ書かなくても自動的に KMS は無効になると思うんだけど。

で,video=uvesafbフレームバッファドライバとして uvesafb を使うという意味で以降その設定が続く。どんなオプションを指定できるのかは fb/uvesafb.txt 参照。

mode_option=1280x1024-24 というのは,さきほど hwinit で調べた指定しうる解像度(と色深度)を指定する。

mtrr=2 というのは,MTRR レジスタ*2に設定する内容。わたしの環境では 2 を指定しているけど,とりあえず 3 を指定しておくとよい。後述。

scroll=ywrap は,端的に言うと仮想ターミナル画面でのスクロールの実現方法を設定している。ywrap, ypan, redraw を指定することができて,頭のほうから順にパフォーマンスがいい((わたしの GeForce 7600 GS だと scroll=ywrap でひととおり問題なく動くんだけど,デュアルスクリーンの場合にセカンダリモニタの表示内容がスクロール時におかしくなる。実害ないのでそのままにしてるけど。))。


んで,カーネル起動時に uvesafb モジュールを読み込んでもらうために initramfs のほうにも指定しておく必要があるみたい。具体的には /etc/initramfs-tools/modules に,

uvesafb mode_option=1280x1024-24 mtrr=2 scroll=ywrap

のように追記する。書式がちょっと違うけど,指定している内容はさきほどと同じ。

あと,/etc/initramfs-tools/conf.d/splash というファイルを作成して

FRAMEBUFFER=y

という内容にする(もしすでにあれば追記する)。


以上のプロセスで GRUB2 や initramfs の設定を更新する準備ができたので,順次更新していく。

$ sudo update-grub2

$ sudo update-initramfs -u


これでうまくいったら Plymouth の解像度があがる。わたしはあがった。でも黒ブランク画面の時間が短くなった気はしなかった(そもそも KMS disabled だから nouveau より不利だけど)。

あと,関係ないけど Lucid になって起動ちょっぱやになったっていう報告をいくつかみるけど,自分の環境ではそんな感じでもないですね。たんにマシンパワーのおかげで Karmic の時点でもはやかっただけかもだけど。

んで,副作用?で,仮想ターミナルの解像度もあがりました。やったね。jfbterm とかいれると仮想ターミナルもなかなか快適。jfbterm 抜ける時に画面がフリーズしちゃうけど。

MTRR について

fb/uvesafb.txt によると

mtrr:n  Setup memory type range registers for the framebuffer
        where n:
              0 - disabled (equivalent to nomtrr) (default)
              1 - uncachable
              2 - write-back
              3 - write-combining
              4 - write-through

        If you see the following in dmesg, choose the type that matches
        the old one.  In this example, use "mtrr:2".
...
mtrr: type mismatch for e0000000,8000000 old: write-back new: write-combining
...

nomtrr  Do not use memory type range registers.
fb/uvesafb.txt

のように設定できる。

で,たぶん write-combining > write-back > write-through > uncachable の順にパフォーマンスがよくなる。パフォーマンスといっても今回の例では uvesafb ドライバ部分の話であって,X.Org が立ち上がったあとは話が別(たぶん nvidia プロプラドライバがよしなに設定してくれる)。

どのモードをサポートしているかはグラフィックチップやグラフィックカードによって異なるみたい。だけど,どれを指定すればいいかはやってみなきゃわかんなさそう((X.Org が立ち上がっている状態で /proc/mtrr とかみてみたけどわかんなかった。uncachable になってたし。))。指定してみて間違っていると起動時の dmesg で教えてくれる。

以下は write-back (2) しかサポートしていないグラフィックカードmtrr=3 (write-combining) を指定した時の dmesg の例。

mtrr: type mismatch for d0000000,800000 old: write-back new: write-combining
mtrr: type mismatch for d0000000,400000 old: write-back new: write-combining
mtrr: type mismatch for d0000000,200000 old: write-back new: write-combining
mtrr: type mismatch for d0000000,100000 old: write-back new: write-combining
mtrr: type mismatch for d0000000,80000 old: write-back new: write-combining
mtrr: type mismatch for d0000000,40000 old: write-back new: write-combining
mtrr: type mismatch for d0000000,20000 old: write-back new: write-combining
mtrr: type mismatch for d0000000,10000 old: write-back new: write-combining
mtrr: type mismatch for d0000000,8000 old: write-back new: write-combining
mtrr: type mismatch for d0000000,4000 old: write-back new: write-combining
mtrr: type mismatch for d0000000,2000 old: write-back new: write-combining
mtrr: type mismatch for d0000000,1000 old: write-back new: write-combining

このようにいわれるので mtrr=2 に設定をかえた。

かえたあとの dmesg は以下のとおり。

uvesafb: NVIDIA Corporation, G73 Board - p345h0b , Chip Rev   , OEM: NVIDIA, VBE v3.0
uvesafb: protected mode interface info at c000:c2e0
uvesafb: pmi: set display start = c00cc316, set palette = c00cc380
uvesafb: pmi: ports = 3b4 3b5 3ba 3c0 3c1 3c4 3c5 3c6 3c7 3c8 3c9 3cc 3ce 3cf 3d0 3d1 3d2 3d3 3d4 3d5 3da 
uvesafb: VBIOS/hardware supports DDC2 transfers
uvesafb: monitor limits: vf = 76 Hz, hf = 83 kHz, clk = 210 MHz
uvesafb: scrolling: ywrap using protected mode interface, yres_virtual=2048
uvesafb: framebuffer at 0xd0000000, mapped to 0xf8700000, using 10240k, total 262144k

MTRR まわりで文句はいわれなくなった。

用語など

あとで書くかも。

*1:旧来の vesafb をつかってもいけるらしいんだけど,blacklist 入りしてるみたいなので uvesafb を使うほうがいいと思う。

*2:ほんとは MTR レジスタなので「馬から落馬」なんだけど

collectd のフロントエンドとして Cacti を使う

  • リソースデータ収集は collectd がとてもいい
  • だが collectd にはプレゼンテーション層が欠けている
  • Cacti のデータ閲覧 UI は(この手のフリーのもののなかでは)かなり良い
  • でも Cacti のデータソース管理 UI をいじるのは相当面倒

端的に言うと「Cacti の UI で collectd のデータを閲覧できたらなぁ」

collectdのデータをKDEデスクトップ上に表示したい場合は、kcollectdの利用を検討するとよい。誕生して間もないプロジェクトだが、すでに有用性が認められている。また、生成されたRRDtoolファイルはCactiでも利用できる。ただし、非常に長々とした設定をグラフ別に行う必要がある。

Webインタフェースでマシンを監視する4つの方法 (2/5) - ITmedia エンタープライズ

collectd は膨大な rrd ファイルを生成するので、これを手作業で Cacti にインポートしてってやるのも面倒だよなぁと思っていました。

すると Cacti のフォーラム Cacti • View topic - Cacti as a frontend for collecd? にて、collectd のデータを Cacti から閲覧できるようにするスクリプトがあったので、やってみました。Python 2.6 が必要と書いてあったけど、CentOS 5 に付属の Python 2.4.3 でもうまく動きました。

その結果がこちら。

んーずいぶんお手軽にできるものだなぁ。

ただ、このスクリプトにもいいところもあればわるいところもあります。

良い点
  • 設定いらず*1で collectd で扱っているデータをすべて*2グラフ化してくれる
  • 監視データの polling は collectd 側がやってくれるので Cacti 側の負荷は増えない(閲覧時にグラフを生成しているだけ)
  • Tree Mode にわざわざ Collectd というツリーをホストごとに掘ってくれる; 同一ホスト内の情報も適宜グループ化してくれる
イマイチな点
  • すべてのグラフの縦軸の項目名が「vertical_label」になってしまう(これは RRD ファイルに値の単位が記載されていないというしくみ上どうしようもないか; Cacti の管理画面で変更していけばいい)
  • collectd のデータ上、同じディレクトリに存在する rrd ファイルの値がまとめられてしまう(たとえば cpu の場合、idle, interrupt, nice, softirq, steal, system, user, wait)
    • このため、たとえば vmem のように vmpage_number-file_pages の値だけ突出しているグラフの場合、その他の値がグラフの下にべったり張り付いてしまい傾向をみることができなくなってしまう
  • 全部線グラフとなり、(適宜項目数におうじて色を変えてくれる*3が)塗りつぶし表現などなく平板な印象になってしまう
  • あとからある項目を追加したり、あるホストを追加したり、ということができない(もちろんスクリプトを書き換えればいけると思うけど)

とはいえ、これ一つで collectd のデータを簡単に見ることができるようになるのは事実。

Python で書かれているのが個人的にはちょっとつらいのだけれど、がんばって読み込んでみようかなぁ。

*1:実際には rrd ファイルの場所や Cacti のデータベース情報などの設定は必要だけど

*2:といっても irq と df はデフォルトで除外されるようになっています。それらも使うためにはちょこっと書き換えが必要。

*3:なにげによくできた機能ですが。

Linux で 4096 バイトセクタ HDD を fdisk

Linux でも 4096 バイトセクタのハードディスクを使うときには注意が必要らしいということを 4096 バイトセクタの HDD と Linux - daily dayflower で書きました。でも fdisk のエキスパートモードってどんなんだろうと思いつつ実際に触っていなかったので、今回はちゃんと触ってみました(でもベンチマークはとってないよ)。

今回のおはなしは(前回と同様)、物理セクタサイズ 4096 バイトの 512 バイトセクタエミュレーションモードのハードディスク、つまり 2010 年現在において 4K セクタとして売られている HDD がターゲット*1です。

CentOS 5.4 で動作確認を行いました。fdisk のバージョンはこんな感じです。

# fdisk -v
fdisk (util-linux 2.13-pre7)

以降の例では 1TB のディスクを3つのパーティションにわけます。

  • 128GB
  • 256GB
  • 残り全部

を、全部基本パーティションとして切ってみました。

方法 1. エキスパートモードを使って開始セクタを微調整する

エキスパートモードと銘打っていますが、後述する方法 2 より簡単です。ただし、複数パーティションを切る場合、(最終パーティション以外の)パーティション末尾のセクタがいくらか無駄になります。

ですが単一パーティションで使う場合は無駄が発生しないので、こちらの方法のほうが楽*2でしょう。

fdisk の起動
# fdisk /dev/sdb 
Device contains neither a valid DOS partition table, nor Sun, SGI or OSF disklabel
Building a new DOS disklabel. Changes will remain in memory only,
until you decide to write them. After that, of course, the previous
content won't be recoverable.


The number of cylinders for this disk is set to 121601.
There is nothing wrong with that, but this is larger than 1024,
and could in certain setups cause problems with:
1) software that runs at boot time (e.g., old versions of LILO)
2) booting and partitioning software from other OSs
   (e.g., DOS FDISK, OS/2 FDISK)
Warning: invalid flag 0x0000 of partition table 4 will be corrected by w(rite)

Command (m for help): 

現在パーティションテーブルが存在しないため、いろいろいわれていますが無視してください。

立ち上げ当初の基本コマンドモードでは以下のコマンドが使えます。

Command action
   a   toggle a bootable flag
   b   edit bsd disklabel
   c   toggle the dos compatibility flag
   d   delete a partition
   l   list known partition types
   m   print this menu
   n   add a new partition
   o   create a new empty DOS partition table
   p   print the partition table
   q   quit without saving changes
   s   create a new empty Sun disklabel
   t   change a partition's system id
   u   change display/entry units
   v   verify the partition table
   w   write table to disk and exit
   x   extra functionality (experts only)

いろいろありますが、今回の例で使うのはおもに下記のコマンドだけです。

   d   delete a partition
   n   add a new partition

   p   print the partition table

   q   quit without saving changes
   w   write table to disk and exit

fdisk の場合、いろいろパーティション情報等をいじっても w で書き込まない限り、q コマンドや Ctrl+C で抜けてしまえばディスクには反映されないので気楽に試すことができます。

ざっくりとパーティションを切っていく

現在のパーティションテーブルを見てみます。

Command (m for help): p

Disk /dev/sdb: 1000.2 GB, 1000204886016 bytes
255 heads, 63 sectors/track, 121601 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes

   Device Boot      Start         End      Blocks   Id  System

空っぽです。

まずは n コマンドで第1パーティションを作成します。

Command (m for help): n
Command action
   e   extended
   p   primary partition (1-4)
p
Partition number (1-4): 1
First cylinder (1-121601, default 1): <CR>
Using default value 1
Last cylinder or +size or +sizeM or +sizeK (1-121601, default 121601): +128G

開始シリンダ(≠セクタ)は、デフォルトにしておきます。エンターを押すだけでデフォルト値の 1 が採用されます。

終了シリンダを絶対値で指定するか、サイズを与えることができます。例示ではメガバイト+sizeM)やキロバイト+sizeK)しかありませんが、ギガバイト+sizeG)でも指定することができます。

同様にして第2、第3パーティションも切っていきます。

Command (m for help): n
Command action
   e   extended
   p   primary partition (1-4)
p
Partition number (1-4): 2
First cylinder (15564-121601, default 15564): <CR>
Using default value 15564
Last cylinder or +size or +sizeM or +sizeK (15564-121601, default 121601): +256G

Command (m for help): n
Command action
   e   extended
   p   primary partition (1-4)
p
Partition number (1-4): 3
First cylinder (46689-121601, default 46689): <CR>
Using default value 46689
Last cylinder or +size or +sizeM or +sizeK (46689-121601, default 121601): <CR>
Using default value 121601

第3パーティションはディスクを最後まで使い切るので、終了シリンダをデフォルト値(末尾シリンダ)のままにしています。

どのようなパーティションテーブルになったのか、p コマンドで見てみます。

Command (m for help): p

Disk /dev/sdb: 1000.2 GB, 1000204886016 bytes
255 heads, 63 sectors/track, 121601 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes

   Device Boot      Start         End      Blocks   Id  System
/dev/sdb1               1       15563   125009766   83  Linux
/dev/sdb2           15564       46688   250011562+  83  Linux
/dev/sdb3           46689      121601   601738672+  83  Linux

ご覧のとおり、単位がシリンダ単位なので、セクタ単位ではどのようになっているかわかりません。

セクタ単位の微調整を行うために、エキスパートモードに入ることにします。

エキスパートモードで開始セクタを調整する

x コマンドをもちいるとエキスパートモードに入ることができます。

Command (m for help): x

Expert command (m for help): 

エキスパートモードのコマンドは下記のとおりです。

Command action
   b   move beginning of data in a partition
   c   change number of cylinders
   d   print the raw data in the partition table
   e   list extended partitions
   f   fix partition order
   g   create an IRIX (SGI) partition table
   h   change number of heads
   m   print this menu
   p   print the partition table
   q   quit without saving changes
   r   return to main menu
   s   change number of sectors/track
   v   verify the partition table
   w   write table to disk and exit

ディスクの CHS(シリンダ/ヘッド/セクタ数)を変更することもできますが、BigDrive の現在ほとんど意味がありません(し危険です)。なので、今回使うコマンドは、

   b   move beginning of data in a partition

   p   print the partition table

だけです。

まずはエキスパートモードでパーティションテーブルを確認してみましょう。

Expert command (m for help): p

Disk /dev/sdb: 255 heads, 63 sectors, 121601 cylinders

Nr AF  Hd Sec  Cyl  Hd Sec  Cyl     Start      Size ID
 1 00   1   1    0 254  63 1023         63  250019532 83
 2 00 254  63 1023 254  63 1023  250019595  500023125 83
 3 00 254  63 1023 254  63 1023  750042720 1203477345 83
 4 00   0   0    0   0   0    0          0          0 00

ノーマルモードにくらべて、いろいろ複雑な情報がでてきました。

実は DOS パーティションテーブルは、各パーティションの開始位置・終了位置を、CHS と LBA(セクタインデックス)の両者でもっています。テーブル左側にかいてあるのが CHS による開始・終了位置です*3。右側が LBA による位置(とサイズ)情報です。

これを見ると第1・第2パーティションについては残念ながら、開始セクタ番号が 8 の倍数になっていないことがわかります。第3パーティションはラッキーにも 8 の倍数になっています。

さきほどあげた b コマンドを使うと、この開始セクタ番号をいじることができます。

Expert command (m for help): b
Partition number (1-4): 1
New beginning of data (63-500023124, default 63): 64

もともと 63 だったところを 64 にしました。

パーティションテーブルを見てみます。

Expert command (m for help): p

Disk /dev/sdb: 255 heads, 63 sectors, 121601 cylinders

Nr AF  Hd Sec  Cyl  Hd Sec  Cyl     Start      Size ID
 1 00   1   1    0 254  63 1023         64  250019531 83
 2 00 254  63 1023 254  63 1023  250019595  500023125 83
 3 00 254  63 1023 254  63 1023  750042720 1203477345 83
 4 00   0   0    0   0   0    0          0          0 00

第1パーティションの開始セクタ番号が 8 の倍数である 64 になったこと、(終了セクタ番号をいじれないために)サイズが 1 セクタ分少なくなったことがわかります。


シングルパーティションで使う場合なら、ここまでの作業で OK です。あとは w コマンドで今回編集したパーティションテーブルをディスクに書き込みます。


今回は3つパーティションを切ったので、同様にして第2パーティションの開始セクタについてもいじっていきます。

Expert command (m for help): b
Partition number (1-4): 2
New beginning of data (250019595-750042719, default 250019595): 250019600

8 の倍数にアラインするには、下 3 桁が 8 で割りきれるようにします。

第 3 パーティションについてはもともと 8 の倍数だったのでそのままで大丈夫です。さて、最終的にどのようなパーティションテーブルになったのかを確認します。

Expert command (m for help): p

Disk /dev/sdb: 255 heads, 63 sectors, 121601 cylinders

Nr AF  Hd Sec  Cyl  Hd Sec  Cyl     Start      Size ID
 1 00   1   1    0 254  63 1023         64  250019531 83
 2 00 254  63 1023 254  63 1023  250019600  500023120 83
 3 00 254  63 1023 254  63 1023  750042720 1203477345 83
 4 00   0   0    0   0   0    0          0          0 00

無事、各パーティションの開始セクタ番号が 8 の倍数になりました。

なおさきほど述べたように、エキスパートモードにおいてすら終了セクタ番号を編集することはできません。ですので、今回の場合、第 1 パーティションの末尾が 5 セクタほど使えない状態になっています。これはこの方法 1 ではどうしようもありません。

方法 2. セクタモードを使って開始セクタ・終了セクタを設定する

一番最初のノーマルモードパーティションを切った際、パーティション開始位置等はシリンダ番号単位で与えていました。だからエキスパートモードにわざわざ入って開始セクタの位置を調整することになりました。

ですが、実は fdisk はパーティションの開始・終了位置を最初からセクタ単位で指定することもできます。そこで、方法 2 ではエキスパートモードを使わず、セクタ単位で一から指定してみます。

セクタ単位モードに切り替える

u コマンドを使うと、単位系をシリンダ単位とセクタ単位の両者で切り替えることができます。

# fdisk /dev/sdb
......

Command (m for help): u
Changing display/entry units to sectors

なにもコマンドラインオプションをつけない場合、デフォルトではシリンダ単位になっています。ですので、u コマンドを一度実行すると、セクタ単位モードになります。

また、起動時に -u オプションをつけて fdisk を実行すると、最初からセクタ単位モードになります。

パーティションをざっくり切る

自力で全パーティション境界を計算してもいいのですが、桁数も多くめんどくさいので、まずはパーティション境界にこだわらずざっくりと切ってみます。

Command (m for help): n
Command action
   e   extended
   p   primary partition (1-4)
p
Partition number (1-4): 1
First sector (63-1953525167, default 63): <CR>
Using default value 63
Last sector or +size or +sizeM or +sizeK (63-1953525167, default 1953525167): +128G

Command (m for help): n
Command action
   e   extended
   p   primary partition (1-4)
p
Partition number (1-4): 2
First sector (250000064-1953525167, default 250000064): <CR>
Using default value 250000064
Last sector or +size or +sizeM or +sizeK (250000064-1953525167, default 1953525167): +256G

Command (m for help): n
Command action
   e   extended
   p   primary partition (1-4)
p
Partition number (1-4): 3
First sector (750000065-1953525167, default 750000065): <CR>
Using default value 750000065
Last sector or +size or +sizeM or +sizeK (750000065-1953525167, default 1953525167): <CR>
Using default value 1953525167

ではパーティションテーブルを確認してみましょう。

Command (m for help): p

Disk /dev/sdb: 1000.2 GB, 1000204886016 bytes
255 heads, 63 sectors/track, 121601 cylinders, total 1953525168 sectors
Units = sectors of 1 * 512 = 512 bytes

   Device Boot      Start         End      Blocks   Id  System
/dev/sdb1              63   250000063   125000000+  83  Linux
/dev/sdb2       250000064   750000064   250000000+  83  Linux
/dev/sdb3       750000065  1953525167   601762551+  83  Linux

残念ながら今回は第1・3パーティションの開始セクタが 8 の倍数ではありません。そもそもなぜか終了セクタが指定した容量 + 1セクタになっているのが不可解です。まあいずれにせよ今回の情報をもとにパーティションを切り直すのであまり深く考えないようにします。

きちんとパーティションを切る

さきほどのパーティションテーブルをもとに、開始セクタを 8 の倍数にしつつ容量もきちんとするなら下記のようになるでしょう。

/dev/sdb1              64   250000063
/dev/sdb2       250000064   750000063
/dev/sdb3       750000064  1953525167

この方針でパーティションを手動できっていきます。

といっても、いままで開始セクタ番号をおまかせで決めさせたり、終了セクタ番号を容量で指定していたところを絶対セクタ番号で指定するように変更するだけです。

まず、o コマンドでパーティションテーブルを初期化します。

Command (m for help): o
Building a new DOS disklabel. Changes will remain in memory only,
until you decide to write them. After that, of course, the previous
content won't be recoverable.


The number of cylinders for this disk is set to 121601.
There is nothing wrong with that, but this is larger than 1024,
and could in certain setups cause problems with:
1) software that runs at boot time (e.g., old versions of LILO)
2) booting and partitioning software from other OSs
   (e.g., DOS FDISK, OS/2 FDISK)
Warning: invalid flag 0x0000 of partition table 4 will be corrected by w(rite)

あとはパーティションを切っていきます。

Command (m for help): n
Command action
   e   extended
   p   primary partition (1-4)
p
Partition number (1-4): 1
First sector (63-1953525167, default 63): 64
Last sector or +size or +sizeM or +sizeK (64-1953525167, default 1953525167): 250000063

Command (m for help): n
Command action
   e   extended
   p   primary partition (1-4)
p
Partition number (1-4): 2
First sector (63-1953525167, default 63): 250000064
Last sector or +size or +sizeM or +sizeK (250000064-1953525167, default 1953525167): 750000063

Command (m for help): n
Command action
   e   extended
   p   primary partition (1-4)
p
Partition number (1-4): 3
First sector (63-1953525167, default 63): 750000064
Last sector or +size or +sizeM or +sizeK (750000064-1953525167, default 1953525167): <CR>
Using default value 1953525167

最初の開始セクタを 64 にしたせいで、あとあとのパーティションの開始位置のデフォルト値が 63 になってしまい、いちいち手入力しないといけないのがめんどうですが、メモをもとに作業すればまあ間違わないでしょう。

パーティションテーブルを確認します。

Command (m for help): p

Disk /dev/sdb: 1000.2 GB, 1000204886016 bytes
255 heads, 63 sectors/track, 121601 cylinders, total 1953525168 sectors
Units = sectors of 1 * 512 = 512 bytes

   Device Boot      Start         End      Blocks   Id  System
/dev/sdb1              64   250000063   125000000   83  Linux
/dev/sdb2       250000064   750000063   250000000   83  Linux
/dev/sdb3       750000064  1953525167   601762552   83  Linux

無事開始セクタが 8 の倍数になりました。

雑多な話題

方法 1 と方法 2 でパーティションの開始位置などが異なる

方法 1 の場合は(大枠で)シリンダ境界に沿うようにパーティションが自動的に切られていたのに対して、方法 2 ではシリンダ境界にとらわれることなくパーティションを切ることができるからです。

本来シリンダ境界に沿うようにしたほうが旧来のシステムとの互換性が高いのですが、開始セクタ番号をずらしている(シリンダ境界でなくなっている)時点で互換は保たれていないので方法 2 の切り方でも問題はないでしょう。そもそもさきほどみたように CHS ではとっくにオーバーフローしてますしね。

第 1 パーティションの開始位置は 64 じゃないといけないのか

方法 2 で、さらに c コマンドによって DOS コンパチビリティをオフにすると、開始セクタの位置を 63 より前に設定することができます(セクタ番号 0 は MBR およびパーティションテーブル自体なので、設定できない)。

ですが、古典的に第 1 パーティションは(シリンダ境界から)第 63 セクタから開始することになっていました。で、ブートローダーによってはこの 1〜62 セクタの間にコードや情報をおくことがあります。たとえば GRUB の場合(パーティションに置くのでなければ)、stage 1.5 のローダーはこの部分におかれます。

なので、少なくともシステムディスクの場合、開始セクタは 64 としたほうがよいでしょう。データとしてしか使わないのなら開始セクタを 8 としてもいいかもしれませんが、増やせる容量はたかだか 32K bytes 程度です。

他のパーティションツールではどうすればいいか

面倒なので調べていません。

cfdisk はもう使っている人はいないと思います。

sfdisk でもセクタ単位で設定できそうですが、あれを操れる人は自力でなんとでもできるでしょう。

parted はコマンドを実行した瞬間にパーティションテーブルが変更されそうで怖くてためしていません。マニュアルを読む限りセクタ単位で編集することもできそうですが、今回の方法 2 のように一度(容量や割合で)サイズを指定しておまかせで切ったあとに手動で切り直す必要がありそうです。

gparted もためしていません。基本的に容量単位でパーティションを生成するので細かいセクタ単位の指定はできなさそうです。一応、シリンダ単位にパーティション境界をもってくるかどうかというフラグはあるみたいですが。

*1:旧来の物理セクタサイズ 512 バイトの HDD に対して今回の作業を行ってもパフォーマンスなどの問題はありません。

*2:Western Digital のドライブの場合、単一パーティションならジャンパを使うのが一番楽と思いますが。

*3:ごらんのとおり、BigDrive のためもはや CHS によるパーティション記述はオーバーフローしており意味をなしていないことがわかります。