<?xml version="1.0" encoding="EUC-JP"?>
<rss version="2.0">
   <channel>
      <title>tec-q note</title>
      <link>http://www.tec-q.com/note/</link>
      <description>Technical Note : 調べた技術情報の覚え書き</description>
      <language>ja</language>
      <copyright>Copyright 2008</copyright>
      <lastBuildDate>Thu, 15 Nov 2007 15:15:05 +0900</lastBuildDate>
      <generator>http://www.sixapart.com/movabletype/</generator>
      <docs>http://blogs.law.harvard.edu/tech/rss</docs> 

            <item>
         <title>ファイルまたはディレクトリのみへの chmod コマンド</title>
         <description><![CDATA[ファイルまたはディレクトリのみへの chmod コマンド

chmod で再帰的にパーミッションを設定するときにいつも思うのが、
「ディレクトリだけとかできないかなぁ・・・」
普通にやるとファイルにも x が付いちゃって実行ファイルになっちゃいますよね。

で、探してみたらありました。
<a href="http://technique.sonots.com/index.php?UNIX%2F%E3%82%B3%E3%83%9E%E3%83%B3%E3%83%89%2F%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E7%AE%A1%E7%90%86%2Fchmod" target="_blank">chmod - ファイルのアクセス権の変更</a>

find を利用してファイルまたはディレクトリだけにして、chmod するという手法。

ファイルの場合<blockquote><code>find . -type f -print | xargs chmod 644
</code></blockquote>
ディレクトリの場合<blockquote><code>find . -type d -print | xargs chmod 755
</code></blockquote>
こりゃ便利だ。]]></description>
         <link>http://www.tec-q.com/note/2007/11/_chmod.html</link>
         <guid>http://www.tec-q.com/note/2007/11/_chmod.html</guid>
                  <category domain="http://www.sixapart.com/ns/types#category">Linux</category>
        
        
         <pubDate>Thu, 15 Nov 2007 15:15:05 +0900</pubDate>
      </item>
            <item>
         <title>シェルで、自身のスクリプトファイル名を取得する</title>
         <description><![CDATA[シェルスクリプト内ではパラメータを使用して、自身のスクリプトファイル名を取得できます。

例えば<blockquote><code>#!/bin/sh

FILE=${0}
</code></blockquote>とかすると、変数：FILE にはスクリプトのファイル名が入ります。
要はパラメータの最初（インデックス0）には自身のファイル名が渡されるってことです。

これ結構使えるんですけど、シェルスクリプトの実行の仕方でパラメータの中身が変わってしまうのがネックでした。
フルパス指定で実行すればフルパスで、相対パスで実行すれば相対パスで渡されてくる。
つまり、<strong>"自身のスクリプトファイル名がパラメータで渡される"</strong>んじゃなくて、<strong>"コマンドラインがそのままパラメータで渡される"</strong>ってこと。

私はスクリプトの実行内容のログを取るときに、
<blockquote><code>LOG_DIR=/var/log
LOG_FILE=${LOG_DIR}/${0}.log

echo `date` > ${LOG_FILE}
</code></blockquote>みたいなことしてコマンドの実行結果を変数：LOG_FILE で示されるファイルにリダイレクトしたりしてます。
これおわかりの通り、カレントからの相対パスでの実行でしか通用しません。

なんとかならないかなーって探してたら見つけましたよ。
<a href="http://sonic64.com/2006-02-27.html" target="_blank">シェルのパラメータ展開でスクリプト自身のファイル名を取得する</a>

私の例だと、
<blockquote><code>LOG_DIR=/var/log
LOG_FILE=${LOG_DIR}/<span class="cl-red">${0##*/}</span>.log
</code></blockquote>で、スクリプトファイル名だけがゲットできます。

詳しい原理はリンク先で解説してますので割愛。
こりゃ便利だ。]]></description>
         <link>http://www.tec-q.com/note/2007/06/post_1.html</link>
         <guid>http://www.tec-q.com/note/2007/06/post_1.html</guid>
                  <category domain="http://www.sixapart.com/ns/types#category">Linux</category>
        
        
         <pubDate>Fri, 01 Jun 2007 10:01:14 +0900</pubDate>
      </item>
            <item>
         <title>わかりずらい Java の参照渡し (3/3)</title>
         <description><![CDATA[参照に対する勘違いを起こす理由として、Java のメソッドには「オブジェクトを操作するメソッド」と「オブジェクトを生成するメソッド」の 2 タイプあり、最もよく使われる String クラスに「オブジェクトを生成するメソッド」しかないことが挙げられると思います。

結論から言ってしまうと、String クラスに用意されているメソッドは、どのメソッドを使ってもオブジェクトそのものの値は変わりません。
言い換えると、オブジェクトそのものの値を変えることができません。そのようなメソッドが存在しないからです。
String クラスにはオブジェクトの値を元にした新しいオブジェクトを生成するメソッドしか存在しません。

先のサンプルＡの test1 メソッドの内容を変えたサンプルＣを例とします。<blockquote>サンプルＣ
<code>public class SampleC
{
　public static void main(String[] args)
　{
　　String s1 = "main メソッド実行";

　　SampleC sampleC = new SampleC();
　　sampleC.test1(s1);

　　System.out.println(s1);　　　　　<span class="cl-red">・・・４</span>
　}

　public void test1(String s2)
　{
　　s2.toUpperCase();　　　　　　　　<span class="cl-red">・・・１</span>
　　s2.replaceAll("main", "test1");　<span class="cl-red">・・・２</span>
　　s2.concat("？");　　　　　　　　　<span class="cl-red">・・・３</span>
　}
}</code></blockquote>このサンプルＣを実行した時、<span class="cl-red">４</span>の部分でコンソールには<blockquote><code>&gt; java SampleC
main メソッド実行</code></blockquote>と出力されます。

test1 メソッド内では変数：s2 の String オブジェクトのメソッドを実行しています。
<span class="cl-red">１</span> の toUpperCase() は文字列を大文字に変換するメソッド、<span class="cl-red">２</span> の replaceAll(String, String) は文字列内にある第1引数の文字を第2引数の文字に置き換えるメソッド、<span class="cl-red">３</span> の concat(String) は引数に指定した文字列を末尾に追加するメソッドです。
しかし、このどれを実行しても、変数：s2 が参照している String オブジェクト（これは変数：s1 が参照しているオブジェクトと同じ）は変わりません。
それはこれらのメソッドが「オブジェクトを生成する」タイプのメソッドだからです。

これに対しサンプルＢで使用した Vector#add(Object) メソッドは「オブジェクトを操作するメソッド」なので、元のオブジェクトの内容が変更されます。

メソッドの結果として生成されたオブジェクトは戻り値として返りますので、変数で受けてやる必要があります。<blockquote><code>　public void test1(String s2)
　{
　　String s3 = s2.toUpperCase();
　　String s4 = s2.replaceAll("main", "test1"");
　　String s5 = s2.concat("？");
　}</code></blockquote>こうすると、変数：s3, s4, s5 のそれぞれに結果オブジェクト（の参照）が格納されます。
具体的には変数：s3 には "MAIN メソッド実行"、変数：s4 には "test1 メソッド実行"、変数：s5 には "main メソッド実行？" が入ります。
この時、もちろん変数：s2 が参照しているオブジェクトは変更されません。

この String クラスの「オブジェクトを生成するメソッド」に慣れてしまい、
"メソッドを実行しても元のオブジェクトは変わらない"
＝ "渡した元のオブジェクトは操作されない"
＝ "参照渡しってどういうこと？"
という混乱に繋がっているのだと思います。
そして、たまに使用する「オブジェクトを操作するメソッド」のせいで、渡したオブジェクトが変わる時と変わらない時があり、さらに混乱してしまいます。

Java には「オブジェクトを操作するメソッド」や、渡されたバッファに値を格納するようなメソッドが少ないです。
ほとんどがこの「オブジェクトを生成するメソッド」です。
ポインタ＝参照渡しを意識させないための工夫でしょうが、これだけでは限界があったのか結果的に「オブジェクトを操作するメソッド」が存在することによって混乱を招いていると思います。

使用するクラスのメソッドが<strong>「オブジェクトを生成するメソッド」</strong>なのか、<strong>「オブジェクトを操作するメソッド」</strong>なのか − 意識して使用していくことで、混乱は防げると思います。

<blockquote><span class="cl-red">私は Sun の人間ではありませんし、VM やメモリをハックしたわけでもありませんので、記載された内容は厳密には事実と異なる部分があるかもしれません。
ですが、「納得できて理解できればいいな」という考えで公開しています。この点はご了承ください。</span></blockquote>]]></description>
         <link>http://www.tec-q.com/note/2007/04/_java_33.html</link>
         <guid>http://www.tec-q.com/note/2007/04/_java_33.html</guid>
                  <category domain="http://www.sixapart.com/ns/types#category">Java</category>
        
        
         <pubDate>Tue, 17 Apr 2007 16:23:17 +0900</pubDate>
      </item>
            <item>
         <title>わかりずらい Java の参照渡し (2/3)</title>
         <description><![CDATA[String クラスの話の前に "オブジェクト参照" であることの説明を続けます。

先のサンプルＡの String クラスを Vector クラスに変えたサンプルＢを例とします。<blockquote>サンプルＢ
<code>public class SampleB
{
　public static void main(String[] args)
　{
　　Vector v1 = new Vector();　　　　<span class="cl-red">・・・１</span>

　　SampleB sampleB = new SampleB();
　　sampleB.test1(v1);　　　　　　　<span class="cl-red">・・・２</span>

　　System.out.println(v1.size());　<span class="cl-red">・・・４</span>
　}

　public void test1(Vector v2)
　{
　　v2.add("test1 メソッド実行");　<span class="cl-red">・・・３</span>
　}
}</code></blockquote><span class="cl-red">３</span>の Vector#add(Object) メソッドは Vector に要素を追加するメソッドで、<span class="cl-red">４</span>で使用している Vector#size() メソッドは Vector に格納されている要素数を取得するメソッドです。
このサンプルＢを実行した時、<span class="cl-red">４</span>の部分でコンソールには<blockquote><code>&gt; java SampleB
1</code></blockquote>と出力されます。

<span class="cl-red">１</span>の段階ではオブジェクトが生成されたばかりで要素を持っていませんので、Vector#size() メソッドを実行しても出力は 0 です。
ところがサンプルＡと違い、test1 メソッド内で操作した内容が main メソッドの変数：v1 のオブジェクトに反映されています。

これは、サンプルＡでは変数：s2 を操作していたのに対し、サンプルＢでは "オブジェクトの参照" で渡されたオブジェクトを操作しているからです。
もしサンプルＢの test1 メソッドが、<blockquote><code>　public void test1(Vector v2)
　{
　　v2 = new Vector();
　　v2.add("test1 メソッド実行");
　}</code></blockquote>このような内容であれば、変数：v2 が操作されて参照するオブジェクトが変わっているので <span class="cl-red">４</span> での出力は 0 になります。

簡単に言ってしまえば、<strong>"=" で変数に代入している</strong>か、<strong>オブジェクトのメソッドを使っている</strong>かの違いです。

<strong>引数は独立した変数</strong>ということを覚えておきましょう。

じゃぁサンプルＡでも代入じゃなくてメソッドを使えば結果は変わるのか − いいえ。変わりません。
これは「String クラスにはオブジェクトそのものを操作するメソッドがない」というもう一つの落とし穴が存在するからです。

3/3 へ続く]]></description>
         <link>http://www.tec-q.com/note/2007/04/_java_23.html</link>
         <guid>http://www.tec-q.com/note/2007/04/_java_23.html</guid>
                  <category domain="http://www.sixapart.com/ns/types#category">Java</category>
        
        
         <pubDate>Tue, 17 Apr 2007 15:58:03 +0900</pubDate>
      </item>
            <item>
         <title>わかりずらい Java の参照渡し (1/3)</title>
         <description><![CDATA[Java の引数はプリミティブ型であれば値渡し、オブジェクトであれば参照渡しというのは周知の事実です。
その参照渡しは "オブジェクトの参照" を渡すのですが、広く知られている "変数の参照" を渡す方法と区別されていないためか、しばしば混乱する場合があります。

例を挙げるとわかりやすいと思います。下のソースを見てください。<blockquote>サンプルＡ
<code>public class SampleA
{
　public static void main(String[] args)
　{
　　String s1 = "main メソッド実行";　<span class="cl-red">・・・１</span>

　　SampleA sampleA = new SampleA();
　　sampleA.test1(s1);　　　　　　　　<span class="cl-red">・・・２</span>

　　System.out.println(s1);　　　　　<span class="cl-red">・・・４</span>
　}

　public void test1(String s2)
　{
　　s2 = "test1 メソッド実行";　　　　<span class="cl-red">・・・３</span>
　}
}</code></blockquote>このサンプルＡを実行した時、<span class="cl-red">４</span>の部分でコンソールに何が出力されるでしょうか？
答えは<blockquote><code>&gt; java SampleA
main メソッド実行</code></blockquote>となります。

勘違いしやすいのは、
「<span class="cl-red">２</span>で test1 メソッドを実行するので、変数：s1 は "test1 メソッド実行" に書き変わり、出力は "test1 メソッド実行" になる」
と考えるパターンです。
これは Java の参照渡しが、"オブジェクトの参照" を渡す方法なのに、"変数の参照" を渡す方法と勘違いしているためです。

メモリをイメージした図にすると、<span class="cl-red">１</span> の段階では以下の様になります。
左の変数名は変数のメモリ空間を表すアドレスで数字はオブジェクトのメモリ空間を表すアドレス、右の罫線内が格納されている値と思ってください。<blockquote><span class="cl-red">１</span>の段階
<code>　　├───────────
ｓ１│５０
　　├───────────
　　│　　　・
　　　　　　・
　　│　　　・
　　├───────────
５０│main メソッド実行
　　├───────────</code></blockquote>変数：s1 にはアドレス 50 への参照が入り、アドレス 50 に実際の値である "main メソッド実行" が入っています。
そして<span class="cl-red">２</span>で test1 メソッドに引数を渡した時が以下の状態です。<blockquote><span class="cl-red">２</span>の段階
<code>　　├───────────
ｓ１│５０
　　├───────────
ｓ２│５０
　　├───────────
　　│　　　・
　　　　　　・
　　│　　　・
　　├───────────
５０│main メソッド実行
　　├───────────</code></blockquote>test1 メソッドに "オブジェクトの参照" が渡されているのが解るでしょうか？
重要なのは、変数：s1 と変数：s2 は全く別のメモリ空間ということです。
test1 メソッドに変数：s1 そのもの（変数の参照）が渡されているわけではありません。

その後、<span class="cl-red">３</span>の段階では以下の様になります。<blockquote><span class="cl-red">３</span>の段階
<code>　　├───────────
ｓ１│５０
　　├───────────
ｓ２│５１
　　├───────────
　　│　　　・
　　　　　　・
　　│　　　・
　　├───────────
５０│main メソッド実行
　　├───────────
５１│test1 メソッド実行
　　├───────────</code></blockquote><span class="cl-red">３</span>では変数：s2 が参照するオブジェクトを変更しただけに過ぎません。
渡されたオブジェクト自体、ましてや 変数：s1 を操作したわけではありません。

ここまでだけだと理解できると思います。
では、何故勘違いしてしまうのか？

それは、最もよく使われる String クラスにオブジェクトそのものを操作するメソッドがないからです。

2/3 へ続く]]></description>
         <link>http://www.tec-q.com/note/2007/04/_java_13.html</link>
         <guid>http://www.tec-q.com/note/2007/04/_java_13.html</guid>
                  <category domain="http://www.sixapart.com/ns/types#category">Java</category>
        
        
         <pubDate>Tue, 17 Apr 2007 15:50:32 +0900</pubDate>
      </item>
            <item>
         <title>RPM データベースの修復</title>
         <description><![CDATA[RPM データベースが破損して rpm コマンドがハングして応答しなくなるのは良く聞く話。
破損したデータベースの修復方法もそこらへんでよく見ます。

だけど、その修復方法が微妙に違ってたりするので、自分がやったメモを残しておきます。
<hr/><strong>１．破損したデータベースのバックアップ</strong>

RPM データベースは /var/lib/rpm にある<ul><li>__db.001</li><li>__db.002</li><li>__db.003</li></ul>の 3 つのファイルです。
これを他のディレクトリにコピーしておきましょう。

とは言え、本当に破損している場合、バックアップしておいたところで使い物になりません。

<strong>２．破損したデータベースの削除</strong>

バックアップしたらデータベースファイルは /var/lib/rpm 内から削除します。
これが重要で、破損した RPM データベースが残ってると修復のコマンドを実行しても、そのコマンド自体がハングします。

<strong>３．RPM データベースの修復</strong>

以下のコマンドを使って RPM データベースを修復します。
破損したファイルは削除されているので、修復というより再構築ですが。
<blockquote><code># rpm --rebuilddb</code></blockquote>コマンドが終了すると、
<blockquote><code>エラー: db4 error(16) from dbenv-&gt;remove: デバイスもしくはリソースがビジー状態です</code>※日本語環境の場合</blockquote>というメッセージが表示されますが、再構築自体は正常に完了してます。
<hr/>

以上で完了です。
rpm コマンドを試してみてください。]]></description>
         <link>http://www.tec-q.com/note/2007/04/rpm.html</link>
         <guid>http://www.tec-q.com/note/2007/04/rpm.html</guid>
                  <category domain="http://www.sixapart.com/ns/types#category">Linux</category>
        
        
         <pubDate>Fri, 13 Apr 2007 11:50:50 +0900</pubDate>
      </item>
            <item>
         <title>BigSister の Web インターフェースを無効に</title>
         <description><![CDATA[OS : RedHat 9
Software : BigSister 1.02-4

検証しきれてないんで結果論になるんですけど、Web インターフェースを使わずに監視だけ行う方法です。

RPM からインストールすると（おそらく）全ての機能が有効な状態になります。
RRDtool によるグラフ作成とか。

使用する機能を指定するファイルは /usr/share/bigsister/etc/bsmon.cfg です。
Web インターフェースを使わない場合は、以下の様に不要な機能をコメントアウトしてやります。<blockquote>/usr/share/bigsister/etc/bsmon.cfg
<code>bs_evgen
history         logfile=var/display.history
<strong>#BBLog           statedir=www/logs
#HTMLLog         immediate=no
#DisplayCFG
#grouping
#Display
#Rsync
#Grapher
#RRDi
#RRDs</strong>
TrackLast
StatusTrap

#
# Include all *.cfg files in etc/mondef
#
include etc/mondef/*.cfg

include bsmon_site.cfg</code></blockquote>あと、Apache の httpd.conf に /etc/bigsister/httpd.conf が Include されていると思うので、それをコメントアウトします。

これで完了。]]></description>
         <link>http://www.tec-q.com/note/2007/04/bigsister_web.html</link>
         <guid>http://www.tec-q.com/note/2007/04/bigsister_web.html</guid>
                  <category domain="http://www.sixapart.com/ns/types#category">BigSister</category>
        
        
         <pubDate>Fri, 13 Apr 2007 11:30:22 +0900</pubDate>
      </item>
            <item>
         <title>BigSister のデザインをカスタマイズする</title>
         <description><![CDATA[OS : RedHat 9
Software : BigSister 1.02-4, 0.99c3

Web インターフェースのデザインを変えたり、警告メールの文章を変えたい場合は、使用しているスキンを変更します。

使用中のスキン名は /etc/bigsister/bb-display.cfg 内の %skin と %Logskin に書いてあります。
スキンのデータは /var/lib/bigsister/www/kins にスキン名のフォルダ毎であります。

スキンデータには色々な箇所で使用されるものがありますが、各スキンに置いてあるデータはその一部です。
無い部分のスキンには default のものが使用されます。
例えば警告メール用のスキンは default にしかありませんので、他のスキンを使用していても default で定義されているメール文書が使用されます。

デザインを変える場合はスキン名のディレクトリ内のソースを書き換えればいいんですが、それだけでは使用できません。
プログラム中で実際に使用されるスキンデータは <var>スキン名ディレクトリ</var>/cache というコンパイルされたファイルなので、ソースを書き換えた後にコンパイルする必要があります。

コンパイルは簡単で、/usr/share/bigsister/bin/compile_skin というスクリプトにスキン名を渡すだけです。
デフォルトのスキンをコンパイルする場合は、<blockquote><code># compile_skin default</code></blockquote>でOKです。]]></description>
         <link>http://www.tec-q.com/note/2007/03/post.html</link>
         <guid>http://www.tec-q.com/note/2007/03/post.html</guid>
                  <category domain="http://www.sixapart.com/ns/types#category">BigSister</category>
        
        
         <pubDate>Mon, 26 Mar 2007 10:40:48 +0900</pubDate>
      </item>
            <item>
         <title>Tomcat のデフォルトエラーページを変更する</title>
         <description><![CDATA[Software : Tomcat 4.1, 5.0, 5.5, 6.0

Tomcatのデフォルトのエラー画面って、スタックとレースとか情報が出すぎてる気がしませんか？
もちろんデバッグ用途なら問題ないんですけどね。
私はこのエラー画面を Apache ライクにしたいと思って色々調べてみました。

方法は、<ul><li>エラーページを生成しているクラス：org.apache.catalina.valves.ErrorReportValve を改変する</li><li>エラーページを生成しているクラス：org.apache.catalina.valves.ErrorReportValve を継承したカスタムコンポーネントを作って使用する</li></ul>の2通りありますが、前者はソースをダウンロードして改変するだけと簡単なので後者の説明を。
<hr/><strong>１．カスタムコンポーネントの作成</strong>

org.apache.catalina.valves.ErrorReportValve を継承したカスタムコンポーネントを作成します。
protected メソッドの report(Request request, Response response, Throwable throwable) が実際にエラーページを生成しているメソッドです。
このメソッドをオーバライドして好きなソースを吐くようにします。

このクラスは Tomcat コンテナ部分だけあって、バージョンによって中身が違います。
はた目には同じように見えますが、実は report メソッドの引数の型が違ってたりしますので、ちゃんとバージョンに合ったクラスを使うように。

<strong>２．MBeans 記述子の作成</strong>

作成したカスタムコンポーネントを Tomcat に登録するために MBeans 記述子を作成します。
Tomcat 付属のファイルにカスタムコンポーネントを追記するか、独自のファイルを作ります。
Tomcat 付属のファイルは、Tomcat 4.1 は org/apache/catalina/mbeans、Tomcat 5.0, 5.5, 6.0 は org/apache/catalina/valves にある mbeans-descriptors.xml です。
ErrorReportValve の記述がありますので、それを参考にすればわかると思います。

ちなみに、作ったカスタムコンポーネントのクラス名を ErrorReportValve にすると、このファイルがなくても動作してくれます。
クラス名しか見てないようで、元々ある ErrorReportValve の記述を使って動いてくれます。

<strong>３．ファイルを配備</strong>

カスタムコンポーネントクラスと（作成した場合）MBeans記述子を Tomcat コンテナのクラスパスに置きます。
Tomcat 4.1, 5.0, 5.5 は ${TOMCAT_HOME}/server/lib or classes、Tomcat 6.0 は ${TOMCAT_HOME}/lib です。

<strong>４．Tomcat に設定</strong>

server.xml にカスタムコンポーネントを使うように設定します。
Host 要素の errorReportValveClass 属性にカスタムコンポーネントを指定します。
<blockquote>${TOMCAT_HOME}/conf/server.xml
<code>&lt;Host ・・・
　　errorReportValveClass="<strong>カスタムコンポーネント</strong>"&gt;</code></blockquote>MBeans記述子を作成した場合はそれも設定します。
org.apache.catalina.mbeans.ServerLifecycleListener クラス設定用の Listener 要素の descriptors 属性にファイルパスを指定します。
<blockquote>${TOMCAT_HOME}/conf/server.xml
<code>&lt;Listener
　　className="org.apache.catalina.mbeans.ServerLifecycleListener"
　　・・・
　　descriptors="<strong>MBeans記述子のパス</strong>"/&gt;</code></blockquote>ファイルパスは Tomcat コンテナのクラスパスからの絶対パスになりますので注意してください。

<hr/>以上で完了です。
Tomcat をリスタートすれば設定が有効になって、オリジナルのエラーページが表示されるようになります。]]></description>
         <link>http://www.tec-q.com/note/2007/03/tomcat.html</link>
         <guid>http://www.tec-q.com/note/2007/03/tomcat.html</guid>
                  <category domain="http://www.sixapart.com/ns/types#category">Tomcat</category>
        
        
         <pubDate>Fri, 16 Mar 2007 13:56:40 +0900</pubDate>
      </item>
            <item>
         <title>Tomcat 5/6のサービスを共存させる</title>
         <description><![CDATA[OS : Windows 2000, XP, 2003
Software : Tomcat 5.x, 6.x

Windows Service Installer を使って Tomcat のサービスへ登録すると、先にインストールしたバージョンのサービスが邪魔をしてエラーが出てしまい、他のバージョンのサービスが登録できません。
これは Tomcat 5 と Tomcat 6 でサービス名は違う（それぞれ "Tomcat5"、"Tomcat6"）のに、その表示名がどちらも "Apache Tomcat" と同じためです。（Tomcat 4.1 は "Apache Tomcat 4.1" で入ってくれます。）

こんな時は、既にインストールされている Tomcat のサービス表示名を sc コマンドで変更すればインストールできるようになります。
（Windows 2000 の場合、sc コマンドはリソースキットに入っています。）
コマンドは<blockquote><code>&gt; sc config <var>サービス名</var> DisplayName= "<var>サービス表示名</var>"</code>※ DisplayName= と "<var>サービス表示名</var>" の間はスペースが必要です。"=" まで含んでオプション名だそうです。 </blockquote>です。
Tomcat 5がインストールされている場合は、サービス名を "Tomcat5" にして、サービス表示名を "Apache Tomcat 5" にでもしてやれば、Tomcat 6 のサービスがインストーラからインストールできるようになります。

ちなみにマイナーバージョン違いの Tomcat をサービス登録する場合は、サービス名（と、それに伴って実行ファイルの引数）から変えてやる必要があります。
例えば Tomcat 5.0.30 と 5.5.23 だったら、それぞれサービス名を "Tomcat5030" と "Tomcat5523" に変更します。
そのためには sc コマンドの create/delete、または Tomcat 付属の service.bat の install/remove を使ってサービスを登録しなおすことになるのですが、これをやるとアンインストーラからキレイに削除できなくなるので私はやりません。

そもそも共存させる目的なんて開発やテスト目的でしかないんだから、多少面倒でもインストーラ無しを使ってバッチで起動/停止すればよいかと。]]></description>
         <link>http://www.tec-q.com/note/2007/03/tomcat_56.html</link>
         <guid>http://www.tec-q.com/note/2007/03/tomcat_56.html</guid>
                  <category domain="http://www.sixapart.com/ns/types#category">Tomcat</category>
        
        
         <pubDate>Mon, 12 Mar 2007 14:15:32 +0900</pubDate>
      </item>
            <item>
         <title>Tomcat 4.1 で Ajp13Connector を使う</title>
         <description><![CDATA[OS : RedHat 9, Windows XP
Software : Tomcat 4.1.34

Tomcat 4.1 でも mod_jk を使用できます。

server.xml に Ajp13Connector を使用する設定を追加するだけです。
<blockquote>${TOMCAT_HOME}/conf/server.xml
<code>　　・・・
　&lt;Service ・・・&gt;
　　・・・
　　<strong>&lt;Connector
　　　　　className="org.apache.ajp.tomcat4.Ajp13Connector"
　　　　　port="8009" debug="0"
　　　　　minProcessors="5" maxProcessors="75"/&gt;</strong>
　　・・・
　　&lt;Engine ・・・&gt;
　　・・・</code></blockquote>ただし、これだけだと Tomcat 起動時に<blockquote><code>ServerLifecycleListener: createMBeans: MBeanException
java.lang.Exception: ManagedBean is not found with Ajp13Connector
　　　　at ・・・
</code></blockquote>という例外が発生します。（出るだけで使用はできますが・・・）

これは、Tomcat 4.1 から Tomcat コンテナが使用するクラスは登録が必要になっていて、（何故か）Ajp13Connector は登録されていないためです。

クラスを登録するには catalina.jar に含まれている org/apache/catalina/mbeans/mbeans-descriptors.xml に Ajp13Connector を追加すれば OK です。
ファイルには CoyoteConnector の記述があるので、それを参考に追加してください。

もしくは別の mbeans-descriptors.xml を作成して使用しても OK です。

別の mbeans-descriptors.xml を使用する場合は、server.xml で ServerLifecycleListener に教えてあげます。
ファイルを ${TOMCAT_HOME}/server/classes/mbeans-descriptors.xml とすると、<blockquote>${TOMCAT_HOME}/conf/server.xml
<code>・・・
&lt;Server ・・・&gt;
　・・・
　&lt;Listener
　　　className="org.apache.catalina.mbeans.ServerLifecycleListener"
　　　debug="0"
　　　<strong>descriptors="/mbeans-descriptors.xml"</strong>/&gt;
　・・・</code></blockquote>このように descriptors 属性に記述します。

参考までに私が作成した mbeans-descriptors.xml を <a href="http://www.tec-q.com/note/files/com_tec-q_ajp_tomcat41.jar">jar ファイル</a>で置いておきます。

このファイルをそのまま使用する場合はダウンロードしたファイルを
${TOMCAT_HOME}/server/lib に置いてください。
mbeans-descriptors.xml の場所は
"/com/tec_q/ajp/tomcat41/mbeans-descriptors.xml" になります。]]></description>
         <link>http://www.tec-q.com/note/2007/03/tomcat_41_ajp13connector.html</link>
         <guid>http://www.tec-q.com/note/2007/03/tomcat_41_ajp13connector.html</guid>
                  <category domain="http://www.sixapart.com/ns/types#category">Tomcat</category>
        
        
         <pubDate>Mon, 12 Mar 2007 11:50:19 +0900</pubDate>
      </item>
            <item>
         <title>RRDtool の RPM を作成</title>
         <description><![CDATA[OS : RedHat 9
Software : RRDtool 1.0.49

<a href="http://bigsister.sourceforge.net/" target="_blank">BigSister</a> のために <a href="http://oss.oetiker.ch/rrdtool/" target="_blank">RRDtool(Round Robin Database Tool)</a> をインストールしました。

現時点での最新は 1.2.19 だったけど、1.2.x は RedHat 9 だと必要なパッケージのバージョンが低いのでパス。
1.0.x にしました。

1.0.x での最新は 1.0.50 なんだけど、こいつは tcl-develop という変なパッケージを要求してくるのでパス。
結局 1.0.49 にしました。

RRDtool の tar ボールには SPEC ファイルが入っているので RPM を作れますが、そこでちょっと引っかかった。という話し。

普通に rpmbuild で RPM を作ろうとすると、
<blockquote><code>RPM build errors:
　　Installed (but unpackaged) file(s) found:
　　/usr/contrib/README
　　/usr/contrib/trytime/README
　　/usr/contrib/trytime/trytime.c
　　/usr/doc/RRDp.txt
　　/usr/doc/RRDs.txt
　　/usr/doc/bin_dec_hex.pod
　　/usr/doc/bin_dec_hex.txt
　　/usr/doc/・・・
　　　　・
　　　　・
　　　　・
　　/usr/examples/bigtops.pl
　　/usr/examples/・・・
　　　　・
　　　　・
　　　　・
　　/usr/html/RRDp.html
　　/usr/html/RRDs.html
　　/usr/html/・・・
　　　　・
　　　　・
　　　　・
　　/usr/lib/librrd.la</code></blockquote>といったエラーが出て RPM が作れません。
「パッケージに入ってないファイルが残ってるよ。」的なメッセージみたいですが、これらのファイルはちゃんと入ってます。

そこでコンパイルを実行するユーザのホームディレクトリに .rpmmacros ファイルを作成して、以下の様に記述。
<blockquote>~/.rpmmacros<code>%_unpackaged_files_terminate_build 0</code></blockquote>これをやると、このエラーは警告に変わるので RPM が作れます。]]></description>
         <link>http://www.tec-q.com/note/2007/03/rrdtool_rpm.html</link>
         <guid>http://www.tec-q.com/note/2007/03/rrdtool_rpm.html</guid>
                  <category domain="http://www.sixapart.com/ns/types#category">RRDtool</category>
        
        
         <pubDate>Tue, 06 Mar 2007 12:34:38 +0900</pubDate>
      </item>
            <item>
         <title>resources の設定が有効にならない</title>
         <description>OS : RedHat 9
Software : BigSister 1.02-4, 0.99c3

/etc/bigsister/resources ファイルは、BigSister が使用する PATH やログ出力先を設定するファイルのハズなんですが、このファイルに記述しても設定が有効になりません。

実はこのファイルは /usr/share/bigsister/etc にも resources という名前で存在しており、こちらにデフォルトの設定が記述してあって、ここでの設定は有効になります。</description>
         <link>http://www.tec-q.com/note/2007/03/resources.html</link>
         <guid>http://www.tec-q.com/note/2007/03/resources.html</guid>
                  <category domain="http://www.sixapart.com/ns/types#category">BigSister</category>
        
        
         <pubDate>Mon, 05 Mar 2007 16:50:46 +0900</pubDate>
      </item>
            <item>
         <title>Webの管理画面からホストをグループに追加できない</title>
         <description><![CDATA[OS : RedHat 9
Software : BigSister 1.02-4, 0.99c3

Web インターフェースの "Admin" → "Hosts/Groups" から、ホストをグループに追加しようとすると、名前に数字を含んでいるホストだと CGI が正常に動作せず、追加することができませんでした。

どうしてもホスト名の数字部分から後ろが無い名前で動作してしまいます。
例えば "TEST01234" という名前だと、"TEST" という名前で扱われてしまいます。

そこで CGI のソースを見たところ、、/usr/share/bigsister/bin/bscgi.pm に原因となる場所を見つけました。

以下はファイルの 40〜49 行目です。
<blockquote><code>40:　　　　my $len = 0 + $ENV{'CONTENT_LENGTH'};
41:　　　　if($len > 0) {
42:　　　　　　　　my $i;
43:　　　　　　　　for($i = 0; $i < $len; $i++) {
44:　　　　　　　　　　　　my $ch;
45:　　　　　　　　　　　　$ch = getc(STDIN);
46:　　　　　　　　　　　　last unless( $ch );
47:　　　　　　　　　　　　$data .= $ch;
48:　　　　　　　　}
49:　　　　}</code></blockquote>43〜48 行目のループで POST されたデータを 1 文字ずつを読み込んでいます。
「読み込むデータが無い場合にループを抜ける」という意図と思われる処理が 46 行目なんですが、これが問題になります。

読み込んだ $ch が false だと last でループを抜けますが、Perl だと変数が空の場合以外にも数値で false と判定されてしまいます。
つまり、例であげたホスト名だと "TEST" を読み込んだ後の "0" でループを抜けてしまい、それ以降のデータを読み込んでいませんでした。

そこで、46 行目を
<blockquote><code>40:　　　　my $len = 0 + $ENV{'CONTENT_LENGTH'};
41:　　　　if($len > 0) {
42:　　　　　　　　my $i;
43:　　　　　　　　for($i = 0; $i < $len; $i++) {
44:　　　　　　　　　　　　my $ch;
45:　　　　　　　　　　　　$ch = getc(STDIN);
46:　　　　　　　　　　　　<strong>last if length( $ch ) == 0;</strong>
47:　　　　　　　　　　　　$data .= $ch;
48:　　　　　　　　}
49:　　　　}</code></blockquote>と変えてやることで正常に動くようになりました。
そもそも $len には CONTENT_LENGTH が入ってるから、この処理は不要にも思えるけど・・・。]]></description>
         <link>http://www.tec-q.com/note/2007/03/web.html</link>
         <guid>http://www.tec-q.com/note/2007/03/web.html</guid>
                  <category domain="http://www.sixapart.com/ns/types#category">BigSister</category>
        
        
         <pubDate>Mon, 05 Mar 2007 15:56:34 +0900</pubDate>
      </item>
      
   </channel>
</rss>
