portmasterによるPortsのアップグレード手順

portmasterやportupgradeを使わず、portauditによる対象portsのアップグレードを行ってきたマシンにおいて、portmasterを使い始めるには色々注意点があるので、いろいろ纏めて見る。

一番大きなリスクは、共通の依存先portsに関する問題で、このことを何も考えずにportmasterを動かすと痛い目に遭う可能性がある。portmasterは依存先のportsが古い場合には、アップデート対象に指定したportsより先にアップグレードを行う。このとき依存先のportsが共有ライブラリでバージョンアップにより互換性が失われるケースがごく稀にある*1。

こういった依存先portsがアップデートされたportsも(バイナリ依存性が失われている場合には)、再ビルドが必要になる。もしバイナリ依存性が失われていない場合でも、デーモンの類なら再起動しておいた方が望ましい。

こういた問題をフォローするには、portmasterを動かす前にUPDATINGをきちんと読んでバイナリ互換性が失われているものがないかどうかチェックし、portmasterでアップグレードされるports一つ一つについて、UPDATINGに上げられたportsがないかどうか、あるいは依存するportsがないかどうかチェックしてやる必要がある。

このあたりをフォローした作業手順を以下に纏めて見る。

まずソースを最新にして、インデックスを更新する
 # csup ports-supfile
 # (cd /usr/ports; make fetchindex)

まず、依存関係をマトモにする。恐らく何度か走らせる必要がある。

 # portmaster --check-depends

この過程で、メンテナが居なくなったり既存のportsにマージされて既に無くなっているportsがいくつか出てくる。こういったportsは pkg_delete で消す。インストール先のファイルが別のportsで上書きされているので、大概実際にファイルは消されず、パッケージ登録だけが抹消される。一つの目安は、pkg_tree で怪しいエラーが無くなれば万々歳。portmaster -L で問題がでないのが望ましい。

次にportupgradeの設定ファイルを /usr/local/etc/portmaster.rc に置く。現在の手元のファイル設定はこんな感じ。interplinkerのにっき [FreeBSD] portmaster (1)では、どのportsをアップグレードするのかの確認もかねて FORCE_CONFIG を付けていたけど外した。

# -b
BACKUP=yes
# --force-config
# FORCE_CONFIG=yes
# don't delete dist-files
DONT_SCRUB_DISTFILES=yes

次にアップグレードしたい ports に対してportmasterを -F オプション付きで起動させる。-F オプションを付けると、依存関係のチェックとdistfileのダウンロードだけを行う。

# portmaster -F -p hogehoge/foobar | grep 'to update'
===>>> Launching child to update libiconv-1.9.2_2 to libiconv-1.13.1
===>>> Launching child to update libtool-1.5.22_2 to libtool-1.5.26
===>>> Launching child to update libexecinfo-1.1_1 to libexecinfo-1.1_3
===>>> Launching child to update popt-1.7_1 to popt-1.14
===>>> Launching child to update gettext-0.14.5_2 to gettext-0.17_1

これらの依存先のportsについて、一つ一つチェックする。

# pkg_info -r gettext-0.14.5_2
Information for gettext-0.14.5_2:

Depends on:
Dependency: libiconv-1.9.2_2

# pkg_info -R gettext-0.14.5_2
Information for gettext-0.14.5_2:

Required by:
(snip)
ja-samba-3.0.28,1
postgresql-server-8.0.15
subversion-1.6.4

このgettextの場合、相当の昔に UPDATING に出ているように、バイナリ依存性が失われている。そのため、postgresql-serverやsubversionもアップグレードしてやる必要がある*2。もしアップグレードを怠ると、portmasterで纏めて入れ替えられた後に、共有ライブラリが見つからなくてバイナリが動かない!という自体に遭遇する*3。

ここまで準備ができればOK。あとは -F オプションを外して

 portmaster -p hogehoge/foobar

で無事に終わるのを待つ。

そして、デーモンなら再起動して動作チェックを行う。共通の依存先を持ち影響を受けるportsも動作チェックをする。もしうまく動かないなら、パッチを書くなりなんなり。ま、もっとも普段からちゃんと UPDATING を読んでいればここで書いたような問題を含めてたいがいの問題は自然とクリアできているはずではあるのだが。

*1:例: gettext, libgcrypt

*2:で、portmasterを使う場合には同じようにチェックすることが望ましい

*3:デーモンの類でしかも動作中に入れ替えてたりすると、マシンの再起動するまで気付かないとかもありそう

opensshの豆知識

opensshクライアントからssh接続しているとき、「ローカルホストへ実行中のsshコマンド」へ指示を出すことができる。たとえばssh接続自体を切断して、手元のマシンに戻ることができる。リモートサーバが無反応になってしまった場合に使う。

opensshは、改行直後に以下のキーシーケンスを受け付ける。

~. ssh接続の強制的な切断
~C port-forwardの追加
~^z ローカルのsshコマンドをバックグラウンドに移行
~# forward中のコネクションの一覧を表示
~& sshコマンドをバックグラウンドに移行(forwarding中のトンネルが終了次第、sshコネクションを切断し終了)
~? このヘルプを表示する
~~ 「~」キー自体を出力

sshコマンドでの接続先において、改行直後に「~」を入力してもすぐに画面に表示されない*1理由は、このキーシーケンスがあるから。このキーシーケンスにない文字を入力した時点で、纏めてリモートへ送信される。

「~.」は、特にいうことなし。ssh接続をぶったぎって強制的に終了させるだけ。

「~^z」はssh接続をバックグラウンドに移行して、ローカルでコマンドを実行した後にフォアグラウンドに戻るための機能。忘れられがちだが、sshコマンドそれ自体もforegroundとbackgroundに移行できるコマンドです*2。注意点は、ここでの「^z」は、Ctrl-zなこと。加えて、-e^zzをコマンドキーとしているGNU Screenの中からこれをやる場合には、「~^z^z」として、エスケープを重ねる必要がある。

「~?」はコマンドを思い出せなくとも、これさえ覚えておけば後は、その場で確認できるので必須。

「^C」。Cは大文字なので注意。こいつはその場でsshのport forwardingを設定するコマンド。以下のように使う。

[hogehoge@hostA ~]$
ssh> help
Commands:
      -L[bind_address:]port:host:hostport    Request local forward
      -R[bind_address:]port:host:hostport    Request remote forward
      -KR[bind_address:]port                 Cancel remote forward

[hogehoge@hostA ~]$
[hogehoge@hostA ~]$
ssh> -L1052:localhost:22
Forwarding port.

このとき設定したport forwardingによるトンネル経由で張られているコネクションの一覧を表示するには、「~#」を使う。

[hogehoge@hostA ~]$ ~#
The following connections are open:
  #0 client-session (t4 r0 i0/0 o0/0 fd 4/5 cfd -1)
  #5 direct-tcpip: listening port 1500 for localhost port 22, connect from 127.0.0.1 port 59538 (t4 r1 i0/0 o0/0 fd 11/11 cfd -1)

#5のdirect-tcpipがforwarding中のコネクションを示している。このコネクションを張ったまま、「~&」でsshをbackgroundに移行させると、シェル自体は終了するがport-forwarding自体はそのまま維持する。forwarding中のコネクションが全て無くなると自動的に終了する。残念ながら、port-forwardの設定自体の一覧は出せないように見える。

ただ、昨今はWindowsなマシンからPuTTYなりのターミナルエミュレータで接続することが多いのであまり使う機会そのものがなくなりつつあるようにも思う。

*1:リモートサーバにすら送信されていない

*2:最もコネクションの関係があるので、あまり実用的/セキュリティ的に好ましいとは思わない

GNU Screenでのクセ

GNU Screenを起動するとき、GNU Screen自体にコマンドを発行するcommand charactorを指定しておくといくつか御利益がある。設定ファイルがないマシンでGNU Screen を使うとcommand charactorがデフォルトの「^a(C-a)」になるため、シェルやEmacsで行頭に戻ろうとしたとき、予想外の動きを見るはめに。

これの回避方法として、GNU Screenの起動時にcommand charactorを常に指定しておくクセを付けておくと楽になれます。たとえば command charactor として、^zzを使っている場合には、以下のようにすればOK。

 $ screen -e^zz

複数のGNU Screenを起動しスイッチする可能性がある場合、-S オプションで名前も指定しておくと「あれ、どれだっけ?」という自体を避けることができる。

 $ screen -S hogehoge -e^zz

SQL Server 2008へSQLをたたいて結果を得る。

SQL Server2008をインストールすると、専用のスナップインがインストールされて利用できるようになる。このスナップインに含まれる Invoke-Sqlcmdを使うとSQLコマンドを直接たたくことできる。sqlcmdというコマンドもあるのだが、これはどうもデフォルトでは入らないらしく、その場合「Native Client」をインストールしろと言われる。

デフォルトではこれらのスナップインは使えないので、「Get-PsSnapin -Registered」で使えるかどうかの確認→「Pss-Pssnapin」という流れを踏む。詳細は[PowerShell]SQL PowerShellとスナップインを参照。こうすると Invoke-Sqlcmd が使えるようになる。

Invoke-Sqlcmdコマンドレットは、MySQLやPostgreSQLのコマンドラインツールとよく似ていて、ユーザー名、データベース名、(必要ならパスワード)、クエリを指定して投げてその結果を纏めて受け取ることができる。

  $sql = "select count(*) from TABLE_SAMPLE";
  $cnt = Invoke-Sqlcmd -Database hoge -U foo -P bar -Query $sql
  $count = $cnt.Item(0)

みたいなスクリプト*1を書くと、テーブルの行数をPowerShellから取得できる。

とはいえ、これだけだとうれしくない。実際にはテーブルからある程度のデータを拾いたいはず。そういうときにはこうする。

  $sql = [String]::Format("select top 2 column1,column2,column3 from TABLE_SAMPLE");
  $it = Invoke-Sqlcmd -Database hoge -U foo -P bar -Query $sql
  foreach($ii in $it){
    $format = [String]::Format("{1},{2},{3}", $ii, $ii.Item(0), $ii.Item(1), $ii.Item(2))
    $format
  }

とすればOK。

もうちょい頭のよい書き方もあるんだろうけど、開発中のちょっとした確認にはこれで十分だった。

*1:本来はパスワードをこんなところに書いてはいけない。書かずに済むよう環境をセットアップするなりなんなりするべき。パーミッションに気を使うのは当然として

コネクション数をモニターする。

一秒おきにコネクション数と時刻を書き出しながら、コンソールにも出力する。リアルタイムで監視ながら記録もしたい、というケースがあったので書いてみた。

while($true){
  $count = netstat -an | select-string 443 | measure-object -line
  $now = get-date
  $format = [String]::Format("{0},  {1}", $now, $count.Lines)
  $format >> a.csv
  $format
  sleep 1
}

終わらせるときには、人間系でCtrl-C。もうちょっとスマートに書けそうだし、監視項目を増やせるはず。本格的に運用中のサーバを監視するならNagiosなりを仕込むべきだが、開発やちょっとだけ監視したい、という場合に有用かな。

findに相当するコマンド(2) でかいファイルを探す

ls(Get-ChildItem)に-Rオプションを渡して、後続のwhere-object('?'でもOK)で条件を付けてマッチしたファイルの情報を表示すればOK

PS> ls -Recurse | ?{ $_.Length -gt 100000000} | Select-Object Name,length