ruby でランダムな文字列を生成

“ランダムなパスワードを生成する” の ruby バージョン。
[2005-04-25] (JavaScript 版)
[2005-05-31] (PHP 版)

# ランダムな文字列を生成する。
# 引数 _length_ を指定すると生成桁数を指定することができます(デフォルト 8 桁)。
def getRandomString (length = 8)
  source=(“a”..”z”).to_a + (“A”..”Z”).to_a + (0..9).to_a + [“_”,”-“,”.”]
  key=””
  length.times{ key+= source[rand(source.size)].to_s }
  return key
end
 
# 10 桁の文字列を取得
p getRandomString 10

FreeBSD6 + jail + httpd22 + fcgid/fastcgi + Ruby on Rails

久しぶりにものすごくはまったのでメモ。
 
目的:
FreeBSD jail 上の httpd + suexec 環境に ruby on rails を入れたが、
CGI で動かすと遅いので fcgi 対応にしたい。
 
手順:
– jail host の /etc/rc.conf に以下の記述を追加

sysvipc_enable=”YES”
jail_sysvipc_allow=”YES” # jail 環境で httpd を動かしている場合のみ追加

– fastcgi を追加(ruby_fcgi 用)

$ wget http://www.fastcgi.com/dist/fcgi-2.4.1-SNAP-0311112127.tar.gz # http://www.fastcgi.com/dist/ の fastcgi の最新版
$ tar xvzf fcgi-2.4.1-SNAP-0311112127.tar.gz
$ cd fcgi-2.4.1-SNAP-0311112127
$ ./configure –prefix=/usr/local/fastcgi # /usr/local/fastcgi 以下に展開(*1)
$ sudo make install

– ruby_fcgi を追加(gem install fcgi では each_cgi がないと怒られる場合があるため、ソースからビルド)

$ wget http://rubyforge.org/frs/download.php/11368/ruby-fcgi-0.8.7.tar.gz
$ tar xvzf ruby-fcgi-0.8.7.tar.gz
$ cd ruby-fcgi-0.8.7
$ ruby install.rb config — –with-fcgi-dir=/usr/local/fastcgi # (*1) で指定したフォルダ。(*1)で –prefix を指定しなかった場合、ここで config を実行しなくてよい。
$ sudo ruby install.rb

– mod_fcgid または mod_fastcgi をビルド/インストール
mod_fastcgi の場合:

$ wget http://www.fastcgi.com/dist/mod_fastcgi-2.4.6.tar.gz
$ tar xvzf mod_fastcgi-2.4.6.tar.gz
$ cd mod_fastcgi-2.4.6
$ cp Makefile.AP2 Makefile
$ make
$ sudo make install
$ # httpd2 が /usr/local/apache2 になければ Makefile を編集して top_dir を変更するか、次のようにする
$ sudo make top_dir=/opt/httpd/2.0.40
$ sudo make install top_dir=/opt/httpd/2.0.40

mod_fcgid の場合:

$ wget http://downloads.sourceforge.net/mod-fcgid/mod_fcgid.2.2.tgz?modtime=1185976592&big_mirror=0
$ tar xvzf mod_fcgid.2.2.tgz
$ cd mod_fcgid.2.2
$ make
$ sudo make install
$ # httpd2 が /usr/local/apache2 にない場合はmod_fastcgi の場合と同様の手法で top_dir 変数を変更する。

– mod_fcgid または mod_fastcgi を httpd にロード/設定
httpd.conf:

# mod_fastcgi を使う場合コメントアウト:
#LoadModule fastcgi_module modules/mod_fastcgi.so
<IfModule fastcgi_module>
   AddHandler fastcgi-script .fcgi
# ソケットの場所(省略時は httpd の log/fastcgi/ )
# FastCgiIpcDir /var/run/fastcgi
   FastCgiConfig -autoUpdate -idle-timeout 20 -killInterval 3600 -maxClassProcesses 2
   # suexec を使う場合必要
   FastCgiWrapper /usr/local/apache2/bin/suexec
</IfModule>
# mod_fcgid を使う場合コメントアウト:
#LoadModule fcgid_module modules/mod_fcgid.so
<IfModule fcgid_module>
   AddHandler fcgid-script .fcgi
   SocketPath /tmp/fcgidsock
   SharememPath /tmp/fcgidshm
   IPCCommTimeout 40
   IPCConnectTimeout 10
   # suexec を使う場合も使わない場合も FCGIWrapper は設定しなくてよい
</IfModule>
 
# suexec 例(SuexecUserGroup が肝):
<VirtualHost 192.168.10.123>
    ServerAdmin [email protected]
    DocumentRoot /usr/local/apache2/htdocs/
    ServerName example.com
    SuexecUserGroup john web
</VirtualHost>

 
– rails の設定を変更
{rails_root}/public/.htaccess

– AddHandler fastcgi-script .fcgi
– RewriteRule ^(.*)$ dispatch.cgi [QSA,L]
+ RewriteRule ^(.*)$ dispatch.fcgi [QSA,L]
– DefaultInitEnv RAILS_ENV development
+ SetEnv RAILS_ENV development

DefaultInitEnv とか SetEnv で変数がわたらない環境の場合は
{rails_root}/config/environment.rb の次の項目をコメントアウトして編集する

# Uncomment below to force Rails into production mode when
# you don’t control web/app server and can’t set it the proper way
#ENV[‘RAILS_ENV’] ||= ‘production’

 
– エラーが出る場合のヒント
http://ontherails.jp/2007/10/13/25 などを参考に。
ログファイルを見る:

httpd の error_log, suexec_log
rails の log/fastcgi.crash.log, log/development.log, log/production.log

など。
特に fastcgi/fcgid をかませた時のみ

Application error
Rails application failed to start properly

とページ表示される場合は rails の fastcgi のログを見るのが有効そうです。
 
参考:
– configuration – The mod_fcgid Home Page
Apache2 + fcgid + Ruby on Railsメモ – sakuramateo
FreeBSD + Apache2 + mod_fcgid + Ruby On Rails(ふわふわな毎日)
_ fcgid(valda’s diary)
FastCGI 化(ふぇみにん日記)
– Rails Apache + FastCGI 環境構築のはまりパターン
– lighttpd + fcgi で each_cgi なるメソッドは知らないといわれる(Don’tStopMusic)

tips – 実行時に共有ライブラリの優先順位を変える(シンボル重複時の動作)

Linux では複数の共有ライブラリ(*.so)に同じ関数が定義されている場合、重複する関数については先に読み込まれた共有ライブラリが利用され、その他のライブラリで定義される重複シンボルについては無視されます。
 
共有ライブラリのロード順序は ld でのリンク順になります。
また、既存の実行可能ファイルのロード順序を調べるには ldd を使います。

$ gcc src.c -o foo -lc -lm # libc.so, libm.so の順にロード
$ ldd foo # foo では libc.so が優先されていることを確認
        libc.so.6 => /lib/tls/libc.so.6 (0x00c07000)
        libm.so.6 => /lib/tls/libm.so.6 (0x00d35000)
        /lib/ld-linux.so.2 (0x00bed000)
$ gcc src.c -o bar -lm -lc # 同じソースに対してリンク順序を入れ替えて bar 作成。
$ ldd bar # bar では libm.so が優先されていることを確認
        libm.so.6 => /lib/tls/libm.so.6 (0x00d35000)
        libc.so.6 => /lib/tls/libc.so.6 (0x00c07000)
        /lib/ld-linux.so.2 (0x00bed000)

 
今回の本題、どうやって共有ライブラリを優先するかを実行時に決めるか?ですが、
LD_PRELOAD を使うことでコンパイル時のロード順を入れ替えることができます。
 

>

$ # LD_PRELOAD に /lib/tls/libc.so.6 (libc.so へのパス)を指定
$ LD_PRELOAD=/lib/tls/libc.so.6
$ ldd bar # 優先順位が変わっていることを確認
        /lib/tls/libc.so.6 (0x00c07000)
libm.so.6 => /lib/tls/libm.so.6 (0x00d35000)
        /lib/ld-linux.so.2 (0x00bed000)

ちなみに、LD_PRELOAD を設定すると、(setuid/setgid されたプログラムなど)一部を除くほとんどのプログラムで任意のライブラリを事前ロードできます。
これを利用すると任意のプログラムのライブラリ定義関数を置き換えることが可能です(参考:hook_tcp.so)。
 
参考:
共有ライブラリの作成(HP テクニカルドキュメント)
 
– hook_tcp.so(チームチドリ)

What is hook_tcp.so:
LD_PRELOADを利用して、プログラム中で実行される connect()の接続先をsyslogへ記録するプログラムです。

とのことで、libc.so の CONNECT(2) を hook して動作します。
 
– 4.17. LIDS を使う時は、LD_PRELOAD 環境変数に注意した方がいいですか?(LIDS FAQ)

カテゴリ別記事一覧ページを生成する

chalow で出力したページ用にカテゴリ別記事一覧ページがほしくなったので、
chalow の ChangeLogReader.pm を使い ChangeLog から自動生成するスクリプトを即興で書いてみました。
 
ソース
 
結果サンプル(装飾用 CSS)
 
色々だいぶ適当さがあるのはご愛嬌です。

デッドロックのテスト用コード

test_lock.php:

<?php
error_reporting(E_ALL);
$f = array();
$f[0] = null;
$f[] = fopen(“lock_1”, “r+”);
$f[] = fopen(“lock_2”, “r+”);
 
if(@intval($_SERVER[‘argv’][1]) >= 2){
$task = array(2, 1);
}else{
$task = array(1 ,2);
}
 
foreach($task as $n){
echo “Locking $n … “;
 
echo flock($f[$n], LOCK_EX, $t=true)? “OK”: “Fail”;
echo “\n”;
echo “waiting some seconds…”;
sleep (5);
echo “OK\n”;
}
echo “Finished!\n”;

実行:

$ php test_lock.php &
$ php test_lock.php 2 &

 
ひとつのみ起動した場合 Finished! と表示されますが、上のように並列で実行した場合は正しく動作しなくなります。
 
手元の環境では FreeBSD 6.2 と Windows XP SP2 の場合はデッドロックして固まり、Linux 2.4.21-50.ELsmp の場合は 2番目のロックに fail し、デッドロックにはなりませんでした。
 
参考:
– flock のモード切替え時の挙動は環境によって異なる[2008-01-08-1]

flock のモード切替え時の挙動は環境によって異なる

flock() でロック獲得中にロック状態を切り替える(LOCK_SH から LOCK_EX にする、など)と、環境や状況によってロックが保持されない場合があります。
 
検証用コード:
A… ロック切り替えプロセス(keeper.php )

<?php
$f=fopen(“t.txt”,”r+”);
for($i = 0; $i < 10; $i++){
  // ロック切り替えまたは取得(LOCK_EX -> LOCK_SH)
  echo “shared($i)\n”;
  flock($f, LOCK_SH);
  sleep(3);
  // ロック切り替え(LOCK_SH -> LOCK_EX)
  echo “exclusive($i)\n”;
  flock($f, LOCK_EX);sleep(3);
}
echo “Done! the treasure was protected!\n”; // ここまで theif.php にロックがとられなければ期待通り。
?>

B…ロック奪取プロセス(thief.php)

<?php
$f=fopen(“t.txt”, “r+”);
flock($f, LOCK_EX); // ロック待ち
// ロック奪取成功
echo “lock obtained!\n”;
echo “im doing something, hehehe.”;
for($i=0;$i<10;$i++){
  sleep(1);
  echo “.”;
}
echo “\nfinished! bye ;P\n”;’
fclose($f); // ロック開放
?>

実行:

$ touch t.txt
$ nice php locker.php &
$ php thief.php

結果:
Windows XP SP2 + Cygwin + PHP 5.1.2 (FS: NTFS) … ロック保持されない(thief won)
Linux 2.4.21-50.ELsmp + PHP 4.4.6 (FS: ext3) … ロック保持される(keeper won)
FreeBSD 6.2 + PHP 5.2.5 (FS: ufs) … ロック保持される(keeper won)
 
Windows XP (FS: NTFS) はロック自体はできますが、LOCK_EX <-> LOCK_SH の切り替えでいったんロックが解除されるという挙動になりました。
 
なお、PHP マニュアルの flock() の項にもあるとおりファイルシステムが FAT の場合など同じ Windows でも環境によっては結果が変わるため、この結果を鵜呑みにせず必ずご自身の環境でテストしてください。


追記(2008-01-09):
ちなみに、PHP 5.2.5 でソースをたどってみたところ PHP の flock() は ext/standard/flock_compat.c で flock (2) ではなく fcntl (2) を使って実装されていました。Linux や BSD など fcntl でロック変換がアトミックにできる場合は問題なく動作しそうです。
なお Windows で、かつ fcntl がない(Cygwin など UNIX 擬似環境ビルドではない)場合は、 UNIX と互換性があるように LockFileEx() で実装されています。

FreeBSD で FUSE

FreeBSD 6 で仮想ファイルシステム(VFS) を使いたくなり、ports から FUSE をインストールしました。 emulator/fuse ではなく, sysutils/fusefs-kmod が正解。 FUSE 用のファイルシステムも sysutils-fusefs-* にあります。
 
参考:
Google SoC 2005からFUSE for FreeBSDなど – 若者に与えられた活躍の場

CUI 上の日本語表示/入力関係の ports

FreeBSD の CUI 環境から(X 一切なしで)コンソールで日本語入力ができないものか、と試行錯誤した結果次のような構成で落ち着きました。
  
OS: FreeBSD 6.2
日本語入力サーバ(Canna): japanese/canna (/etc/rc.conf で canna_enable=”YES” とする)
Canna 用辞書: japanese/cannadic (インストール方法は /usr/local/share/doc/cannadic/README.ja を参照)
日本語表示: japanese/kon2-16dot または japanese/kon2-14dot
日本語入力(UIM + Canna): japanese/uim-canna
  
CUI での日本語入力は kinput2 が主流ですが、X サーバが必要だったので今回は UIM を選択しました。
  
– その他あると便利なもの:

w3m: www/w3m-m17n
jless(less): japanese/jless
jvim (vi,vim): japanese/jvim3-canna
emcws (emacs): japanese/emacs-emcws

  
– 使い方:

$ kon
$ uim-fep
$ echo “ハローワールド”

とし、 canna[ C – R] のような文字列が下に表示されたら Ctrl-\ で日本語入力ができます。また、uim-fep は tty に依存しないのでリモートからも使えます。
 
ちなみに kon 以外の選択肢として, Linux の Framebuffer を用いた jfbtermがあり、FreeBSD 版も Yusuke Baba 氏により公開されています。)。
jfbterm と w3m-img for FreeBSD framebufferと組み合わせることで画像も表示できるようですが、jfbterm の画面切り替え時のオーバーヘッドに耐え切れず利用は断念しました。

ひこにゃんに学ぶ著作権

今朝ニュースを見ていたら、第二のおふくろさん騒動ともいえるニュースが流れていました。
 
ひこにゃんピンチ!…作者、彦根市に使用中止求める(YOMIURI ONLINE) より引用:

もへろんさん(22)が「適正なキャラクター管理を怠った」などとして、市と同祭実行委員会に祭終了後の使用中止を求める調停を彦根簡裁に申し立てたが、市は9日、ひこにゃんを今後も市のマスコットとして使用すると発表した。
 
 実行委は祭のキャラクターとして2006年1月、もへろんさんが応募したネコをモチーフにした3種類の図柄を採用。実行委が許可した団体の出版物などへの利用を許可してきた。
 
 しかし、申立書によると、実行委は「お肉が好物」「特技はひこにゃんじゃんけん」など作者の意図しないひこにゃんの性格づけをしたと主張。粗悪品が出回りかねないのに無制限に使用を承認しているなどとしている。

 
財産権である著作権を持つ彦根市に対して、作者のもへろん氏が著作者人格権のうちの同一性保持権を行使している形ですね。
 
著作権は譲渡可能ですが、著作者人格権は Wikipedia の言葉を借りると「一身専属性を有する権利であるため他人に譲渡できない」権利であるとされているため、勝手な性質の追加に対して異義を唱える事は妥当である、と思います。
 
しかし、前述の記事のように「祭終了後の使用中止を求め」たり、スポニチアネックスの記事にあるように、営利目的の利用や対して「相当額の支払いを求め」たりということまで要求できるかは、祭以外の利用や営利目的の利用が、著作者の名誉声望を害するかは微妙なところではないでしょうか。
 
今回の事例が教えてくれることは、クリエイター、デザイナー、エンジニアなど個人と企業の間での契約では、個人が作成した成果物の著作権は企業が所有する、という契約が多いと思いますが、この契約上でも個人が著作物に対して著作者人格権を行使することができるということです。
 
 ちなみに、プログラムについては「特定のコンピュータで利用できるようにしたり、より効果的に利用し得るようにするために必要な改変(Wikipedia)」であれば同一性保持権でいう改変にはあたりません。
 
とりあえず彦根市の問題については、ひこにゃんは個人的にも好きなキャラクターですし、町興し成功の好例なので、当事者間でうまく話がまとまるといいなと思っています。
参考:
著作権法(Wikipedia)
著作者人格権

Highslide JS で簡単にサムネイル画像ポップアップ

 
Highslide JS
 
近頃は汎用的で高機能な Ajax JavaScript ライブラリが充実してきましたが、ただサムネイル拡大表示をスマートに行いたい、という時はこちらのほうがこれを使うのがよさそうです。
一番単純な例は次のようなものです。

<!– ヘッダで定義しておく –>
<script type=”text/javascript” src=”my-highslide-dir/highslide.js”></script>
<!– 実際にサムネイル表示する –>
<a href=”拡大画像のURL” class=”highslide” onclick=”return hs.expand(this)”>
    <img src=”サムネイル画像のURL” />
</a>

JavaScript 非対応の時はただ拡大画像へのリンクになるあたりがスマートです。
画像のポップアップだけではなく、ポップアップ画像に任意の説明を付与も比較的簡単にでき、機能面でも素晴らしいですね。
 
参考サイトを参照すると詳しい使い方や利用例があります。
 
参考:
Highslide JS でサムネイル画像を拡大表示する(小粋空間)
Highslide JS のサンプルページ(caramel-tea.com)