Slackware 9.0がリリースされた released.。新規事項は ChangeLog をチェックされたい。
Keioはまた、e-メール中のウィルスと戦うため、Sophos と提携した。
Michelは数年前にアイルランドで生まれ、現在ダブリン大学機械工学部で博士論文に取り組んでいる。論文の題目は、非破壊検査におけるLamb波の使用だ。この仕事にGNU/Linuxが大変役立ったので、Michelは、他の工学分野への無料ソフトウエア利用に強い関心を持った。論文を仕上げたら、長い徒歩旅行に出る積もりでいる。
qtopia-free-1.X.X-1.i386.rpm−Linuxインテル用Qtopia。最新版をTrolltech's web site.から入手。
binutils-cross-arm-2.11.2-0.i386.rpm −Linuxインテル用Arm バイナリ・ユティリティ
gcc-cross-sa1100-2.95.2-0.i386.rpm −Linuxインテル用 Arm クロスコンパイラ
glibc-arm-2.2.2-0.i386.rpm− Arm glibc
linux-headers-arm-sa1100-2.4.6-3.i386.rpm − Arm ヘッダ・ファイル
上記四つのファイルは、インストール方法の指導書と一緒に the Zaurus Documentation web site から入手することが出来る。
始めるには、C++プログラムコンパイルのため、InrteディストリビューションでLinuxと一緒に来る標準内容を必要とする。次に、Qtopia SDK (ソフトウエア開発キット)が必要。無料SDKの他に市販SDKもある。無料SDKを使うとプログラム使用許可範囲が制限される。これに関するTrolltech'の情報を読むこと。これをインストールすると、Intelボックス上のLinuxでコンパイル、ラン及びデバッグをすることが出来る。それが仕上がったら、上記最後の四つのrpmをインストールするのに必要なプログラムをテストする準備が整う。これでStrong ARMプロセッサ用に自分のプログラムをクロスコンパイルすることが出来る。
開発
開発設定が出来上がったので、開発をすることが出来る。前に開発をしたことがなければ、シャープ・ザウラスは理想的な環境だ。メモリが制限されているので、簡単なプログラムが最良のプログラムだ。機能完備のオフィス一式は必要でない。私が示す以上の考えが必要なら、Palm及びMicrosoft OS PDAに関するプログラム検索エンジンを見られたい。次いでザウラスPDA検索エンジンを見る。ザウラスにはなくて他に使えるアプリケーションが見つかったら、それを選ぶ良い機会だ。自分に興味のあるプログラムを選んでもよい。
開始する前に、Intelボックス上のLinuxで開発するため環境変数を設定する必要がある。ソフトウエア・パケージをデフォルト位置に置いたとすると、bashシェルで以下を設定する必要がある:
QPEDIR=/opt/Qtopia
QTDIR=/opt/Qtopia
TMAKEPATH=/opt/Qtopia/tmake/lib/qws/linux-x86-g++/
PATH=$QTDIR/bin:$QPEDIR/bin:${PATH}:/opt/Embedix/tools/bin
LD_LIBRARY_PATH=$QTDIR/lib:${LD_LIBRARY_PATH}
export QPEDIR QTDIR PATH TMAKEPATH LD_LIBRARY_PATH
通常のQtアプリケーション開発と同じように、次の数ステップが必要である。既に沢山の記事があるので、ここでは述べない。この問題の良い書物は、Matthias Kalle Dalheimer著、O'Reilly出版の"Programming with Qt" である。簡単に言うと、デザイナを使ってGUIを作る。ディスプレーは240x320であるのを忘れないこと。次いで、uiファイルを作る。次に、プロジェクト・ファイルを作る。通常プロジェクト名は dot pro(即ち例示pro)と言う。 ヘルプが必要ならSDKの中のディレクトリ /opt/Qtopia/exampleを見る。これは、プログラム構成に必要なコンポーネント殆どを含む例示プログラムである。このproファイルを開始点として使う。proファイルが出来上がったら、次により自分のプログラムを作る:
tmake -o Makefile yourprogram.pro
ここでコード作成を始める。通常のQtプログラム作成のように、クラスとスロットと接続を作る。完成したら、"make"とタイプしてプログラムを構築する。エラーを修正して構築を終えたら、エニュメレータでプログラムを走らせる。シャープ・ザウラスには、Xサーバがないので、シャープ・ザウラスの環境をシミュレートするにはエミュレータが必要だ。先ず、Qt埋込仮想X11フレームバッファを走らせるひつようがある。同じシェルでつぎのようにタイプする:
qvfb &
これでエミュレータが走らせるX11アプリケーションが得られた。Windowマネージャの環境で走らせる必要がある。それには同じシェルでつぎのようにタイプする:
qpe &
全部上手く行ったら、シャープ・ザウラスPDAのエミュレーションが見える筈だ。プログラムをテストしてデバッグすることが出来るのはこの環境だ。プログラムが必要なこと全部をするのを見なくとも、走らせるには開発ディレクトリから始める。普通にプログラムを走らせるだけだ。デバッガで走らせることも出来る。これでアプリケーションを完全にテストすることが出来る。
次のステップは、PDAにロードしてインストールすることの出来るipkgフォーマットを作ることだ。ipkgファイルは、シャープ・ザウラスPDA上で使うフォーマットだ。これをするには、先ず、上のセクションでインストールしたクロスコンパイラとツールを使って、プログラムをStrong ARMプロセッサ用にコンパイルしなければならない。これでスタートするには新しいシェルをスタートするのが最良だ。このシェルに入ったら次の環境変数を設定する:
CROSSCOMPILE=/opt/Embedix/tools
QPEDIR=/opt/Qtopia/sharp
QTDIR=/opt/Qtopia/sharp
PATH=$QTDIR/bin:$QPEDIR/bin:$CROSSCOMPILE/bin:${PATH}
TMAKEPATH=/opt/Qtopia/tmake/lib/qws/linux-sharp-g++/
LD_LIBRARY_PATH=$QTDIR/lib:${LD_LIBRARY_PATH}
export QPEDIR QTDIR PATH LD_LIBRARY_PATH TMAKEPATH
Next you need to generate a new Makefile that is for the Strong ARM processor. So type:
tmake -o Makefile yourprogram.pro
ここで "make clean" をして、古いオブジェクトファイル全部を削除する。続いて "make"すると、クロスコンパイラが全てを構築する。PDAが保持するサイズには限りがあるので、実行可能ファイルをstripすることを薦める。だが、私のような間違いをしないこと。この場合は、クロスコンパイルしたstripを使う必要がある。
これで実行可能ファイルが得られたので、全てをipkファイルに纏める必要がある。先ずトップレベル・ディレクトリを作る。この礼ではprogを用いる。次に次のディレクトリ・ツリーを作る:
prog/opt/QtPalmtop/bin prog/opt/QtPalmtop/lib (if needed) prog/opt/QtPalmtop/apps/Applications prog/opt/QtPalmtop/help/en/html prog/opt/QtPalmtop/pics prog/CONTROL
先ず、実行可能ファイル全部をbinディレクトリに入れる。ライブラリもあれば、それをlibディレクトリに入れる。helpファイルはhtmlフォーマットなので、慣れたエディタを使ってhtmlファイルを作り、htmlディレクトリに入れる。名称は実行名ドットhtmlとする。上に示したディレクトリは、英語(即ちen)htmlファイルと仮定している。他の言語w使うならen以外のディレクトリを使う必要がある。picsディレクトリにはpngフォーマットつまり、32 X 32ピクセルのイメージファイルを置く。これはこのアプリケーションで使うアイコンを示す。これで、CONTROLとApplications,のディレクトリ二つが残る。CONTROLには、contorolと言う名のファイルを置く。これはipk用に使う。Applicationsの中に、自分のプログラム名.desktopと言うファイルを作る。
私の走行距離プログラムでは、次のエントリを持つcontorlファイルを使う:
Package: mileage Priority: optional Section: Misc Version: 2.0 Architecture: arm Maintainer: Bruce Forsberg forsberg@tns.net Description: A Car Mileage Calculator Program
Packageフィールドにはパケージの名が入る。他のアプリケーション殆どに関しPriorityは任意である。Sectionは今のところMiscとするが、後で適当な値に変える。Versionはアプリケーションのバージョンである。Architectureは、SL-5000とSL-5500シャープ・ザウラスPDAにはarmとなる。Maintaineは、パケージの保守を担当する者の名とメールアドレスである。Descriptionは、プログラムの簡単な説明。Dependは、アプリケーションが既存のたのプログラムに依存するときの任意選択フィールドである。IPKGフォーマットに関する詳細は、この記事の参考資料を参照されたい。
自分のアイコンをQtopiaデスクトップに出したいときは、Applications ファイルに desktopファイルを追加する必要がある。私の走行距離Pるプログラム用のdesutopファイルには、下記のエントリを用いる。フィールドは自明であろう。
[Desktop Entry] Comment=A Car Mileage Calculator Program Exec=mileage Icon=mileage Type=Application Name=Mileage Calculator
これで、これらファイル全部が出来上がって、プログラムのサブツリーにパケージ構築の準備が終わった。このスクリプト script を使って "ipkg-build.sh prog" とタイプする。ipkファイルが得られる。単純に普通のソフトウエアロード方法を使ってザウラス上プログラムをインストールし、それをテストする。プログラムを立ち上げて何も起こらないとき試すことの一つは、qpeターミナルアプリケーションをインストールすることだ。これもまたxtermと同じものをザウラス上に示す。ターミナル・アプリケーションとをスタートしてこのビュー・ウインドウからアプリケーション名を入力し、エラーメッセージが出るるかどうかを確かめる。dmesgとタイプしても良い。これでエラーログに送られたメッセージが表示される。
参考資料
シャープ・ザウラスの使い方: http://docs.zaurus.com/
シャープ・ザウラスに関するIPKGの 使い方: http://docs.zaurus.com/ipkg_howto.shtml
IPKG ホームペイジ: http://www.handhelds.org/z/wiki/iPKG
IPKG ビルドスクリプト: http://docs.zaurus.com/downloads/ipkg-build.sh
Qtブックを用いるプログラム作成: http://www.oreilly.com/catalog/prowqt2
シャープSL-5500 :http://www.sharpusa.com/products/ModelLanding/0,1058,698,00.html
シャープSL-5600: http://www.sharpusa.com/products/ModelLanding/0,1058,1016,00.html
ザウラス・ディベロッパ・サイト: http://www.zaurus.com/dev
ザウラス・プログラム・サーチ・エンジン: http://www.killefiz.de/zaurus
ザウラス・ハードウエア及びソフトウエア必携:Linux Journal 2003年1月号記事 、オンラインでは入手不能
Linuxdevices.com 記事: http://www.linuxdevices.com/articles/AT6553340334.html
走行距離 PDA 計算器ホームペイジ: http://mileage.sourceforge.net/
著者紹介:
Bruseは、平均的Linuxファンだ。オープンソース・オーディオライプラリ・プロジェクト( Open Source Audio Library Project)の創始者でもある。無料ウエアのプログラムは Windows 3.1で始めた。団結してしなければならないことはメッセージに返事をしないことそうすればOS全体を潰れると気付いたとき、良い方法があると考えた。Linuxが答えだった。
ウーマートとフリンクは、足音をチタンの壁に響かせながら、長いVPN連絡トンネルを歩いて来たばかりだった。目的システムの心地よい広大な環境に達したとき、フリンクは、気持ちの良い変数を置いて疲れた脚を休めたいと思ったのだが、ウーマートはドンドン歩き続けた。やっとウーマートが向きを変えて "/var/log/apache" と書かれた部屋に入った。
フリンクは、磨き上げられた床(最近 "cruft" で掃除した)を歩いて、綺麗な椅子に座り、分厚いログファイルをうっとりと見つめた。
有名な探偵は、言い訳のように微笑んだ。
−「仕事中はつい夢中になる癖がある。知っているだろう。ところで−ここに悪いことがある。そう、顧客に何かが起こっているのはここだ。ナプキン縁飾り産業で働く経理担当者のため蹄鉄型溶接スプロケット作るのが専門の小会社が、自分のウエブサイトで起こっている古い幾つかの変な事柄について、疑いを持ったと言う訳だ。例えば、応答時間が瞬間的に天井を突き抜けることがあり、「サーバ話し中」のメッセージが普通に較べると遙かに多い回数で送り返される。仕事量が極端に増えた訳ではなく、近頃は経済状態が悪くて、彼らの製品のような贅沢品の需要が減ってむしろ、少なくなっているのだが・・」
フリンクが頷いた。
−「DoS(サービス拒否)アタックのようですね」
ここで少し試験をしよう。先ず、無理に押し込まないで済む場所にこのファイルのコピイを作ろう。ここだ、両方とも `/home/woomert' に入れたよ。一つのファイルを偶然傷つけたり壊したりしても、データは全く失われないようにしたい、そうだね?さて、実際のログを0にして、サーバをスタートし直そう・・・素晴らしい。ファイルを調べている。DoSを疑っているとして−私もだが−君なら何を探すかね?」
フリンクは、頭を抱え、眉を潜めて考えを集中した。
−自信はありませんが、IP毎の平均ヒット数を書き出して、多分、同じものの記録リストを調べます。それで、誰かが本当にこのサーバを攻撃しているか、どこからか、が分かるのではありませんか?」
ウーマートは楽しそうに微笑んだ。
−「それ素晴らしい考えだと思う。よし、平均を見てみよう:
perl -wlne'/^(\S+)/;$h{$1}++}{$a=@a=values%h;map{$b+=$_}@a;print$b/$a' access.log
12.30830039525692
−「うむ、面白い。極めて大きいDoS入力のため数が大きくなることを考えに入れると−未だにそう考えているのだが、当然だろう−あり得ない数ではない。誰でも買う前には見本を調べるだろう。結局、生涯に一度の買い物なのだ。実際、この会社は、生涯保証の提案がきっかけになった。よし、分類リストを調べてみよう:
perl -wlne'/^(\S+)/;$h{$1}++}{print"$h{$}\t$"for sort{$h{$a}<=>$h{$b}}keys%h' access.log
... 22 users.osceola.k12.fl.us 26 152.31.2.221 26 modem-140.nyc-tc01a.fcc.net 28 62.84.228.7 31 209.106.1.124 103 bdsl.66.13.44.110.gte.net 112 24-164-141-122.si.rr.com 611 nyny01hsiapat.everestbroadband.com 1085 162.66.50.6 2817 web-05.segfl.ifl.net 55055 wsip66-210-242-2.ph.ph.cox.net 71031 205.213.111.53 85120 pc-80-193-117-84-cw.blueyonder.co.uk 97000 151.138.254.21 111092 168.11.225.251 122101 syr-24-92-242-3.twcny.rr.com 155017 212.85.1.1 175990 pool-68-161-90-99.ny325.east.verizon.net 181222 1cust185.tnt15.nyc9.da.uu.net 315078 pool-141-155-115-168.ny5030.east.verizon.net
フリンクは、画面を暫く見つめて、頷いた。確信に満ちた声で話した。
ウーマートは考え込んでから、頷いた。
−「何を目的にしているか分かったよ、理に叶った可能性だ。さて、これは、示されたIPに関する一番長い入力を示している:
perl -lne'/^(\S+).*?"(.*?)"/;length$h{$1}>length$2or$h{$1}=$2}{print"@a"while@a=each%h' access.log
... pool-68-161-90-99.ny325.east.verizon.net GET /default.ida?XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX%u9090%u6858%ucbd3%u7801%u9090%u6858%ucbd3%u7801%u9090%u685 8%ucbd3%u7801%u9090%u9090%u8190%u00c3%u0003%u8b00%u531b%u53ff%u0078%u0000%u00=a HTTP/1.0 syr-24-92-242-3.twcny.rr.com GET /default.ida?XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX%u9090%u6858%ucbd3%u7801%u9090%u6858%ucbd3%u7801%u9090%u6858% ucbd3%u7801%u9090%u9090%u8190%u00c3%u0003%u8b00%u531b%u53ff%u0078%u0000%u00=a HTTP/1.0 1cust185.tnt15.nyc9.da.uu.net GET /default.ida?XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX%u9090%u6858%ucbd3%u7801%u9090%u6858%ucbd3%u7801%u9090%u6 858%ucbd3%u7801%u9090%u9090%u8190%u00c3%u0003%u8b00%u531b%u53ff%u0078%u0000%u00=a HTTP/1.0 212.85.1.1 GET /default.ida?XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX%u9090%u6858%ucbd3%u7801%u9090%u6858%ucbd3%u7801%u9090%u6858%ucbd3%u7801%u9090%u90 90%u8190%u00c3%u0003%u8b00%u531b%u53ff%u0078%u0000%u00=a HTTP/1.0 ...
ウーマートとフリンクは、画面とお互いを眺めて、手を打ち合わせた。フリンクは、更に指を鳴らした。
−「正しく呼び出しましたよ、どうですか?」
−「全く上手くやった。ありふれた虫Code Redの変形のようだ。特別に腕前のよいアタッカを相手にしていないのは良い知らせだが、Code Red感染攻撃は、それがこれだが、Code Red DoSと同じものではない。Code Red DoSは、特定IPのネットワーク・スラムに過ぎず−それに古いOSに対してだけ働き−このサイトで走らせているLinuxのような新しいものには何もしない。奴らに成功させるのは帯域幅で、特別悪いものではない。クライアントがこれらのIPをブロックして関係IPに連絡すると、全く問題でなくなる。事実、この種の事柄を追跡して解析と対応を自動的におこなうことの出来るユティリティがあるので、クライアントにはそれを推薦する。これだ−」
ウーマートは素早く、結果とクライアントに対する自分のコメントを"mail" プログラムにパイプして送信し、フリンクに振り返った。
「どうだい、数分で準備が出来るPaglia e Fieno con Pollo e Funghi があるんだが、デザート用に私自身のレシピで作ったチラミスだ。全く素晴らしい'97 Rosso di Cerbaiona ワインもある。そいつに良く合うよ。女友達のプライオリティ・インタラプトも参加するよ」
−「お邪魔になりませんか?」
−「馬鹿な!歓迎するよ」
食事の後で、フリンクは大きい肘掛け椅子で休んだ。プライオリティはウールマートの膝に丸まってトスカノ葉巻に火を付けた。それで二重の、ときには三重の煙の輪を作るのが常だ。ウーマートがいぶかし気に見つめると、彼女は手を伸ばして彼の唇に銜えさせた。
−「ああ、気分が良い」ウーマートは背をそらせて幾つかの輪を吹き出し、プライオリティの輪に絡ませた。「さて、フリンク君−質問は?答えは?推量は?あれば言い給え」
−「ええ、ワンライナが分かり掛けました。でも・・少し助けが要ります。今、貴方がタイプしたのは、これです。 Zaurusにコピイしました。−:
perl -wlne'/^(\S+)/;$h{$1}++}{$a=@a=values%h;map{$b+=$_}@a;print$b/$a' access.log
/^(\S+)/
は、スペースでない文字全部を行の初めから捕まえるレゲーです。 `access.log' の中から典型的な行
127.0.0.1 - - [09/Mar/2003:22:14:46 -0500] "GET / HTTP/1.0" 200 50000 "http://localhost/" "Lynx/2.8.4rel.1 libwww-FM/2.14" webcache-01.segfl.ifl.net - - [01/Apr/2003:05:45:27 -0500] "GET / HTTP/1.0" "-" 200 5238
を見ると、いずれもスペースで終わるIP又はホスト名を捕まえているのが分かります。次に、貴方が前にした
$h{$1}++
があります。これは頻度計数ではありませんか?」
ウーマートは先を促した。
−「 '$1' is はPerl が作った変数で、最初に捕まえたものを保存します。つまりレゲーの中の最初の一対の内容で、この場合はIPです。そこで、そのIPを'%H' ハッシュのキイとして使って、それが出る度にそのIPに関連する値をインクレメントし、それが新しいIPであれば、新しいキイを入手します。
次に・・・ええと、次に、大括弧が勝手に閉じていますが・・・何をするのか良く分かりません。何故このコードが働くのかも分かりません、シンタクスエラーのような気がしますが?」
ウーマートはニヤリとした。
「普通は、そうだ。だが、そこの "perldoc perlrun" をもう一度引き出して、'-p' のところを読んで見給え:
# "perldoc perlrun" から
while (<>) {
... # your program goes here
} continue {
print or die "-p destination: $!\n";
}
フリンクは、コードを熱心に検討した。不意に、顔を上げた。
よしよし、これが分かったら、残りは余り難しくありません。
$a=@a=values%h;
これは、値−とその計数−のリストをハッシュ抽出して、'$a' を戻った値の数に設定します。これは、スカラーコンテキストでリストを見たとき入手したものです(これより少し難しいが、今重要な部分)。続いて、これらの値を合計します:
map{$b+=$_}@a;
`map' ファンクションは `@a' を繰り返し、`$b' を各要素数だけ増加します。大事なことは−
print$b/$a
で、その合計の要素計数に対する比をプリントし−それにより、ヒット全数をIP数で割っています。どうですか?」
ウーマートとプライオリティが手を叩いて褒め、フリンクは赤くなってお辞儀した。
−「有り難う御座います。ウーマートさんに教えても立って勉強した甲斐がありました。あとのものは、似たようなものです:
perl -wlne'/^(\S+)/;$h{$1}++}{print"$h{$_}\t$_"for sort{$h{$a}<=>$h{$b}}keys%h' access.log
初めの部分はもう分かりました−IPの頻度計数です。だが、ブロックの終わりで、違ったことをしています。ウーマートさんに教わったように右から左に解析しましょう:
sort{$h{$a}<=>$h{$b}}keys%h
−今度はキイを抽出しました。そして・・・分かった。ハッシュを値でソートしようとしています。だが、古い ``for ( values %h ){ ... }'' は働きません。値を示されてキイを検索する方法がないからです。値は必ずしも独特ではないかです。そこで、'sort' ルーチンを ``perldoc -f sort'' が説明する通りに変更し、キイを値に基づいてソートします。これを行うには、`sort' が現在比較している要素を保持するのにPerlが使う変数、`$a' と`$b' 、を使います。値でソートされ、キイも見られるリストが戻されます。凄い!次に、そのリストを少しフォーマットしてプリントします:
print"$h{$_}\t$"for ...
"for" オペレータを使って、戻されたキイのリストをループします。ループの中のデフォルト変数、$_' には、代わりに各キイが含まれ、 `$h{$_}' は、その関連値を返します。そこで、タブとキイをプリントします。これでIPと−関連ヒット数−のリストが得られます。
最後に重要なのがあります:
perl -lne'/^(\S+).*?"(.*?)"/;length$h{$1}>length$2or$h{$1}=$2}{print"@a"while@a=each%h' access.log
/^(\S+).*?"(.*?)"/
これは、前のようにIPを捕まえますが、今度は、最初の二重引用符まであらゆる文字とマッチさせます− '*' に続く '?' 修飾子は、それが最初のものであるように表現を見易くし−次の二重引用符まで全部を同じ見易い方法で捕らえます。最初の二重引用符−これはHTTP要求文字列で、正に見たかったものです。次に、うーん・・・助けてください」
ウーマートは、面倒そうに、シャツのポケットからレザーポインタを出して指した。
−「これのことか?
length$h{$1}>length$2or$h{$1}=$2
必要だったのは、ここで最も長い文字列を値としてセーブすることだ。そのため、与えられたIPに関する現在値を、これから来るそのIPに関する値と比較しなければならなかった。しかし、新しいキイの初期値は定義されていない−何かを未定義と比較すると、Perlはエラーメッセージを出す。これは、終端に "@a"を挿入するのと同様に、Perlに致命的でない警告を出させる−そこで、 `-w' スイッチを飛ばして警告を切る。その影響全部を理解しているのでない限りしてはいけないことだ(詳細は``perldoc perllexwarn'' を読むこと)。方法自体は簡単だ。キイに現在割り当てられている値を比較し、もしそれが大きければ、古い値を(`$2' に含まれた)今のものと交換する。ソフト `or' 演算子を使ったことに注意。論理 `or' (||) は、周辺要素に強く束縛されるのでここでは役立たない。
次は、分かるかね?」
フリンクが頷いた。
−「易しいと思います。
print"@a"while@a=each%h
前にしたのを見ましたよ・・・。ハッシュからキイ値対を回収する ``while each'' ループです。これらをアレーに割り当てて、アレーをプリントします。アレー名を囲む二重引用符を使って挿入したので、要素の間にスペースが開きます−これで読み易くなります。全体で、これがハッシュをプリントする。多かれ少なかれ無作為の順になるが、何が入っているか分かれば用ので気にしません。そうですね?」
−「大変よろしい。良くやったよ。これからは君の応援を期待しよう。大丈夫だね?」
−「そうなりたいですね」フリンクは見上げた。「最善を尽くしますよ。これで失礼します。お二人で楽しい夜を!」
フリンクが出てドアが閉まると、プライオリティはウーマートに微笑み掛けた。
−「フリンクにお休みを上げたのね。良い褒美だわ」
−「その価値があるよ。随分勉強した。良い男だ。それにプライオリティ」ウーマートのレーザーポインタがステレオに向けて送られ、エラ・リッツジェラルド/ルイ・アームストロング演奏の``Can Anyone Explain''を再生し始めた「フリンクやプログラム作りより遙かに重要なことがあるよ・・」
[1]これについては、私の秘密の記者が「これは銀行のセキュリティ対策に対し引き続き秘密を保つ必要のある事件である。何時の日か、偉大な探偵とその助手の輝かしい、断固とした、それに何をおいても勇敢な行為を世界中が知ることになるだろう。」と記している。
[2]ウーマートは、私の記者が記すところでは、この特定のPerlハックについて自分の手柄にしていない。これは、comp.lang.perl.miscの中でAbigailが作ったもので、少なくともある程度は、慣用句になったようだ。事実、Abigailの才気溢れた作品−ワンライナは、偶にウーマートを困らせるのが知られている。
著者紹介
Benは1962年モスコーで生まれた。6才で、フォークをコンセントに突っ込んで火花を散らした時以来、電気に興味を持った。長じて、プリント板に部品を半田付けし4kメモリに合わせるプログラムをして以来、コンピュータの仕事をした。夜、うなされるのを治して呉れる心理学者がいれば、大金を払う。
| 書名: | システム管理用Perl |
| 著者: | David N Blank-Edelman |
| 出版社: | O'Reilly & Associates |
| 発行: | 2000年7月 |
| 定価: | $34.95 |
Perl は、素晴らしいプログラム言語である。美しいとも構造が厳格だとも云えないが、強力で、融通性に富み、ネットワーク世界に普及しそうな言語だ。システム管理者にとって、Perlは、ツール言語として重要な役割を果たす。その能力は、Windows とUNIX双方で働く。
Perlでは、ユーザへのメッセージ送付、割当調整、ログファイルとイベントログの監視など、色々有用なことをすることが出来る。Windows では、これらの多くをWindows Scripting Host (WSH)でおこなうことが出来、UNIXには長い間これらの仕事をするツールがあった。しかしPerlは、中規模から大規模システムの管理の主役で、Perlを用いると異なるシステムの管理を高レベルで統合することが出来る。
200年にO'Reilly社がDavid N Blank-Edelman著 "Perl for System Administration," (システム管理者用Perl)を発行した。この書物は、発行以来二年経っても、Windows とUNIXのシステム管理者用の優れた参考書である。更に良いのは、混合環境を管理しているとき、Blank-Edelmanの本は、UNIX, Windows, それに Macさえの管理を助けるプラットホーム横断ツールとしてPerlの使用を強調しているので、更に役に立つ。
418ペイジもの厚さの「システム管理者用Perl」には、広範囲の話題が含まれている。「緒言」、「ファイルシステム」、「ユーザアカウント」、「ユーザ活動」、「TCP/IP名サーバ」、「ディレクトリ・サービス」、「SQLデータベース管理」、「電子メール」、「ログファイル」、「セキュリティとネットワーク監視」、の十章が、システムをまたぐ構築問題の確固たる基礎となる。
この本に関して最も興味があるのは、Windows とUNIX いずれのクロス・プラットホームに対しても、各題目について同じ詳しさで説明していることである。例えば、第9章で「ログ監視」を説明するとき、Blank-Edelman はWindows イベントログと UNIX ログエントリ双方を通じるフィルタ方法を説明している。この章で示された情報を用いて、自分のネットワークのクロス・プラットホーム・ログ監視を作り始めることが出来る。
Perlのクロス・プラットホーム側面に重点を置くのは、Windows- 又はUNIX- いずれかだけに重点を置きたいユーザに取っては問題だ。しかし、いずれかのプラットホームへの視点を欠くのが「システム管理者用Perl」を次のレベルに進めると主張する(Windowsの下でのPerl使い方をしりたいなら、同じくO'Reillyの"Learning Perl on Win32 Systems,"(Win32上でPerlを学ぶ)が良い参考書だ)基本的に、この本を読み終えると、各種管理問題の高レベルの検討を習得し、Windows又はUNIXいずれをも統一感のある解決策で 扱うことが出来るようになるだろう。最後に、この種の高レベル設計は、頑丈で拡張性のある解決策を示す。
ご注意までに言うと、「システム管理者用Perl」は読者が中間的なPerlユーザであることを必要とする。この本はPerl入門書ではないので、Perl初心者はこの本に取り組む前に入門書を読んで置かれたい。また、この本で言及しシステムにインストールしなければならないPerlモジュールは、各賞の終わりにポインタがあるけれども、見付けるのが難しいのに気付いた。
少なからぬサーバー又はワークステーションの管理を担当するのであれば、この本を推薦する。誰もがSQLサーバを管理に使う訳ではないように−この本で示されたテクニックや解決策のすべてを使わないかも知れないが、自分の固有Perl解決策を長い将来に渡って考え続けるのに十分過ぎる程の情報が含まれている。
著者紹介:
Windows と UNIX システムの権威者 Dustin Puryear は、Puryear 情報技術会社の創立者件政策顧問である。情報技術産業におけるコンサルタントに加え、Dustin は、各種技術問題についてコンファレンスでも講演したり、記事を書いたりする。著書には、Windows環境にLinuxソリューションを組み込むことを重点とした"Integrate Linux Solutions into Your Windows Network," (WindowsネットワークにLinuxソリューションを組み込む)がある。
C言語の中で実行されるマクロのセットsetjmp/longjmp は、パーフェクト・プラットホームに複雑なフロー・コントロールを与えるが、実際にそれを使う前に、十分な知識があることと確かないと、プログラムが複雑になって見分けられなくなる。
setjmpファンクションはプログラムの状態をセーブする。プログラムの状態とは、詳しく言うと、sp(スタック・ポインタ),、fp(フレーム・ポインタ)、pc(プログラム・カウンタ)の値である。プログラムは状態は、ヒープとスタックを含むこれらレジスタのセットにより完全に定義される。次の疑問は、これらの状態をセーブする理由だ。簡単には後でlongjumpを通じて復元するためだ。だからこれらのファンクションは、対になって働く。つまりsetjumpがセーブしてlongjumpが復元する。
構文....
構文は極めて簡単だ。setjumpは状態をjmp_buf型変数(ヘッダファイルsetjmp.hで定義)で記憶する。このファンクションを働かせる間常にヘッダファイルをインクルードする:
int setjmp (jmp_buf env);
int longjmp(jmp_buf env , int val);
longjmp ファンクションは、envに記憶されたプログラム状態を復元する。パラメータ値の目的は後で説明する。これらが加えるものは何か?、簡単に言うと、longjumpファンクションは、決して返さない(実行後は別のもの)。longjumpに出会う前に、envに状態をセーブして値0を戻すsetjumpがなければならない。次にlongjumpに出会うと、envに記憶された状態が復元されて、プログラムはsetjumpの後の命令を再開する。longjumpはsetjumpを通じて復元するように見える。この復帰は値を生じ、その値は次のパラメータ値により規定される。
i = setjmp (env);//状態を env に記憶して 0 を返す
........... // longjmp 呼出の後、恰も setjmp 呼出が返されたかのようにこ
....... //の点から実行を再開する
longjmp(env,val)
最後の点として、iの値をプリントして見ると、二つの値が得られる。最初のものはsetjmp が状態をセーブしたとき得たもので、常に0である。第二のものはvalパラメータを通じてlingjmpに渡した値である。だからsetjmpの後のコードは、一度以上実行されると想われる。これは幾らか探求する要がある。そこで、最初のコードと面白いものif-else.cとを示す。
(訳者注:読者の便のためif-else.cを下記にダウンロードしました)
#include<setjmp.h>
これをコンパイルして走らせると、ifとelse両方の条件が実行されるのが分かる!これはif-else条件の働き方ではない。(ifを親に、elseを子、又は逆の)fork()に似ている。forkには、二つの異なる実行のスレッドがあり、それがこの場合だ。setjmp呼出は状態をセーブして0を返す。if条件は真を評価するので、最初のメッセージが与えられる。コードの後の方でlongjmpを実行したとき、状態が復元されて、setjumpに続くステートメントに戻り値2を返す。
この戻り値は、longjmp呼出の中で指定される。if条件が満たされずelseが実行される訳が分かったであろう。加えて、このプログラムは最後の行を実行しないことにより、相違を示した。前に言ったようにlongjmpは決して返さないので、最後の行が実行されないのは明らかだ。これをコードするのにexitステートメントを使うと、elseとlongjumpとの間で交代する無限ループになる。
もっと有用な何か Plese.....
プログラマとしては、コードをファンクション又はサブルーチンに分けて書いた筈だ(プログラム作製の基礎を学んでいないとき、私はプログラムを大きいmainファンクションとして書いたが、次第にファンクションに分けることが出来るようになった。理由は、デバッグが易しいからだ)。プログラムをファンクションとして実行するとき、ファンクション呼出が入れ子になるとの限界がある。これはまた大変複雑なフローも持っている。エラーが起こったときはいつでも、それを起こしたファンクションを見出さなければならない。こうしてプログラムのデバッグが容易になる。 nest.cのコードは、このようなプログラムのデバッグに setjmp/longjmpを使う方法を示す。
(訳者注:読者の便のためnest.cを下記にダウンロードしました)
/*1 4 7 for no error
Enter values (integer) for l m and n please
1
4
7
The functions executed normally
Enter values (integer) for l m and n please
0
0
0
There is an error in function 1 exiting..
Enter values (integer) for l m and n please
1
1
2
There is an error in function 2 exiting..
Enter values (integer) for l m and n please
0
1
2
There is an error in function 3 exiting..
Enter values (integer) for l m and n please
1
2
3
There is an error in function 4 exiting..
予想通り役立った。エラーメッセージは、エラーの起こった場所を告げる。コードを追って見よう。mainファンクションの中のsetjumpは、プログラム状態をセーブして0を返す。if条件は偽になるので実行されない。次のステートメントはパラメータenv, l, m, nを用いてファンクションfun1を呼び出し、fun1は順にfun2などを呼び出す。これらファンクションでエラーが起こると、longjmpが実行され、valパラメータはlongjmp の実行されたファンクション番号になる。プログラムは、longjmp が実行されたときいつでもmainファンクション(のsetjump後のステートメント)に戻る。ここでの値はlongjmpが行われた場所により、1, 2, 3, 4のいずれかになる。ここではif条件は真になるので、エラーの起こったファンクションを示す適切なメッセージが出る。プログラム実行中にエラーが起こらないとき、ファンクションはnormallyに戻って、mainファンクションの最後のステートメントが実行される。エラー中のジャンプをさせるのに、gotoを使わなかった理由については、下記の goto.c.と比較されたい。目を付けられたエラーは、gotoのためローカルジャンプにだけ使うことが出来る。前のプログラムでlongjmp が行ったジャンプは、ローカルでないので、gotoはローカル・ラベルを探すので、ローカルでないジャンプは出来ない。
(訳者注:読者の便のためgoto.c.を下記にダウンロードしました)
#include<setjmp.h>
プログラマの弱点.....
setjmp/longjmpには油断の出来ぬバグがある。実行にではなく、使い方にだ。殆どの人はプログラムを書くときスタック状態を正しく認識していない。エラーがあって(gdbを通じる)スタックの検査により追跡するときだけだ。ファンクション呼出があるときはいつでも、スタックを操作する。先ず、呼び出されたファンクションの引数が逆順でプッシュされる。次いで、JSRが呼び出されて、戻りアドレス(pc)とfpがプッシュされ、続いてfpとspが空にされて呼び出されたファンクションのためあたら言いスタックフレームを作る。呼び出されたファンクションは直ちに、ファンクション内で宣言されるローカル変数用のスタックを作る。これでスタック構造が分かったところで、下記のコードseg.cを走らせて見る。コンパイルは上手く行くが、ランには完全に失敗し、フォールトになる。理由がお分りだろうか?
(訳者注:読者の便のためseg.cを下記にダウンロードしました)
#include<setjmp.h>
コードを追って見よう。mainファンクションは、引数二つを使ってme_firstを呼び出す。引数はスタックenvにプッシュされ、"IC-Labs"が後に続く、次いでJSRが、そのスタックにpc値とfp値をプッシュする。エントリでは、ファンクションがローカル変数iをスタック上に作る。続いてsetjumpファンクションが呼び出され、これがme_first ファンクションの現在状態をセーブする。ローカル変数は現在、setjumpが戻す値0を含む。me_first から戻った後、スタックは元の状態、mainファンクションの中に残したもの、に戻る。次に i_followファンクションが、値3とenv変数を用いて、呼び出される。スタックは、上述のme_firstを呼び出したときのように修正される。ファンクション内では、envに記憶された状態が、 longjmpにより復元される。スタック内の値は変わらないまま、つまり、ファンクションi_follow実行中と同じだ。しかしその状態はファンクションme_firstのものだ。この状態のスタック・フレームは、前に文字列 "IC-Labs" の持っていた (char * )型の変数を持っている。ここで、状態が復元された後変数sが保持する値は3だ( i_followがmainから渡された値)。longjumpの結果、me_first でsetjumpに続くステートメントが実行される。setjmp 後のステートメント (printf)の実行に当たって、プログラムがsをプリントしようとしてメモリ位置 0x3 に文字列を探そうとするので、メモリー保護エラーを起こしプログラムに障害をおこす違法なメモリーアクセスが生じる。バグは極めて難解なので、気付かれないことが多い。両ファンクションのスタックフレームがほとんど同じに見えるためである。スタックフレームが同じであるときは、このようなエラーは起こらない。引数 "char *" をint型の一つで置き換えて戻して見ると良い。フォールトするか?
(訳者注:読者の便のため sig.cの内容を下記に示します)
mainファンクションは、signalシステム呼出を用いてシグナル。ハンドラを呼び出す。パラメータはsigno(SIGALRM)で、これはハンドラを設定しているシグナルと、シグナルが起こったとき実行されるハンドラ・ルーチンを示す。アラーム呼出はSIGALRMシグナルを毎秒プログラムに送る。アラーム・ハンドラは、基本的に8秒経過すると、longjmps する。
著者紹介:
コンピュータ科学工学の卒業論文を殆ど仕上げたところです。神の国 Kerala の小さい町 Trichur からご挨拶しています。文体と内容に関する建設的なご意見を歓迎します。e-メールで連絡して下さい。
CUPS印刷システムは、名前の通り共通Unix印刷システム( Common Unix Printing System)である。これは、各コンピュータの印刷システムの相違を隠して、ローカル・ネットワークをまたぐ印刷インターフェイスを提供することを目的とする。標準Berkely LPDがこの機能を提供する純粋Linux環境でこんなシステムが本当に必要なのか不明だが、CUPSはSMB とWindows プリンタに相互作用性を与える。CUPSにより、動的プリンタ検出と、グループ分けもまた出来るようになる。
CUPS は、Easy Software Productsと言う会社がGPLの下でライセンスしている。CUPS自体を無料ソフトウエアとして提供する一方、商業アドオンとサポートも提供する。
http://www.linuxgazette.com/www.cups.org,からか、又は殆どのディストリビューションから RPM パケージとして、入手することが出来る(Mandrake、RedHat 、SuSEで見られる).
その働き
CUPSは、LPD印刷システムの代替と考えることが出来る。lprコマンドを自分のものと置き換え、LPDプリンタを自分のもので置き換える。しかし、ペイジ記述の基礎としてPostScript に基づく点でLPDに似ている。Linux (及びUnix)プログラムにはCUPS とLPDとの違いは分からない。
これには、パラレルポート、USB及びシリアル接続のプリンタ殆どを含むプリンだドライバのリストがある。シリアル−プリンタをヌルモデモ・シリアル・ラインでつなぐのはパラレル・ラインより遅くて難しいが−−大量印刷又は複数コピイ用の−−、マトリクス・プリンタには十分で、古いハードウエアの在庫からプリントサーバ構築する方法が易しくなる。学校へのヒント!
動的プリンタ検出
CUPSには、Unixの世界では余りないWindowsシステムの特徴がある。これは、ローカル・コンピュータで利用出来るプリンタをネットワーク上の他のコンピュータに放送する。こうして、ローカルIPセグメントにいる各コンピュータは、リアルタイムで利用出来るプリンタとその状態を知ることができる。
当然、Windowsと違って、コンフィギュアすることが出来る。CUPSに(cupsd.confコンフィギュレーションファイルで)放送するか否かと、その場所を命令し、更新の頻度を指定することが出来る。
プリンタのグループ分け
印刷グループ−CUPSではクラスと言う−は、ユーザ・プログラムが単一プリンタ見なすプリンタのグループだ。例えば、カーラープリンタ全部を含むColorPrintersと言うグループを作ることが出来る。ユーザが、プログラムにColorPrintersで印刷と命じると、これらプリンタのうち一つに出力される。どれになるかはユーザの権利又は今使えるプリンタによる。
プリンタがグループの一員であることそれ自体は、ユーザが直接そのプリンタを使うことが出来ないとの意味ではない。しかし、CUPSアクセス制御レベルでは、グループが承認しても、プリンタにジョブを拒絶させることが出来る。最終結果は、ユーザはプリンタでなくぷりんた・グループを使うこととなる。これはある程度、自分の考えるプリンタ使用方針に左右される。
Linux下のコンピュータ五台のある作業所があり、全部CUPSを走らせている。そのうち一つのプリンタを変えるとき、CUPSウエブインターフェイスを通じ、30秒いかで、:
これがコンフィギュレーションに必要な全部だ−別のコンピュータはデフォルト印刷ルートを、別の30秒以内で更新される。全部の変更は1分以内で、レーザープリンタの余熱時間より短い。.
学校ネットワークに:
を作りたい。これらのプリンタの大部分はWindowsボックスから外れていて、Windows下の他のコンピュータで直接使うことが出来る。しかし、それらを中央ブリッジ/ルータ上でCUPSを通じて提供することにより:
Windowsとの統合
Linuxの下でWindows プリンタを使うか又はその逆のためには、稼働中のSambaサーバを必要とする。前に進む前にそれを設定すること(通常ユーザとして、試しにLinuxコンピュータうえのディレクトリをWindowsボックスから眺める)。Windows 98以降のバージョンを使っているときは、 /etc/samba/smb.conf にあるパスワード暗号化を参照するのをわすれないこと。.
CUPS は、Windowsの下で共有されているプリンタと、SMBプロトコルを使っているネットワーク・プリンタを使うことが出来る。「Sambaを使うWindowsプリンタ」をコンフィギュアする。基本的に、CUPSに告げなければならなのは、smb://server/printerにあるようなプリンタのアドレスがすべてだ。
Windows は、Sambaが共有するCUPSプリンタを使うことが出来る。プリンタをSambaと共有するには、普通に進める。即ち、何もしない。プリンタは普通デフォルトで共有されている。そうでない場合は、smb.conf tをエディットして必要な共有を作る。Samba共有オプションを適用することが出来る。これはSambaがCUPSプリンタをLPDプリンタと同じ方法で扱うからである。
ネットワーク・プリンタ
ネットワーク・プリンタ−つまり、ホスト・コンピュータをネットワークで利用出来るようにする必要のないネットワーク・インターフェイスを有するプリンタ−は、任意の各種プトロコルを使うことが出来る:
初めの二つの場合は、コンピュータがホストするプリンタのように進める。3番目の場合は、多分行き詰まるだろう。私はLexmark:で経験した。結局Windowsボックスで共有した。
コンフィギュレーション
CUPSをコンフィギュレーションするには二つの方法がある。一つは、コンフィギュレーション・ファイル /etc/cups/cupsd.confをエディットすること。他は、ポート631でアクセスすることの出来る古典的なウェブベースのインターフェイスである。これは、ネットワーク機能のある多くのプリンタのうぇぶ・ベース・コンフィギュレーションと同様なので、誰にも分かる筈だ。
一般的に、ウエブ・インターフェイスには、別のコンピュータからでなくローカル・ホスト・インターフェイスからだけアクセスすることが出来る。しかし、コンフィギュレーション・ファイルcupsd.conf の次の行を変えてCUPSを再起動すると、これを変えることが出来る:
<Location /> # この location は主画面
Order Deny, Allow
Deny From All
Allow From 127.0.0.1 # ローカル・ホストからのコンフィギュレーションを許す
Allow From 192.168.1.* # 192.168.1.0/24 サブネット上で任意のマシンからの
# コンフィギュレーションを許す
Allow From mybox.mydomain # これは別のセグメントにあうる私のデスクトップ
</Location>
特定のIPアドレスからアクセス出来るメニュー項目(CUPS用語では Locations と言う)を一つ宛指定することも出来る。これは、別のコンピュータがサーバに接続出来ないことを意味しない−内容にアクセスすることが出来ないだけだ。
Linuxボックスがプリントサーバ及び二つ以上のIPセグメントのブリッジとして働いているときは、リクエストを聞くネットワーク・インターフェイスを規定することが出来る:
Listen 127.0.0.1:631 # ここに既存の筈 Listen servename:631 # ここに自分のサーバー名を加える Listen 192.168.1.1:631 # 自分のIPアドレスを使うことも出来る
上の例では、IPアドレス192.168.1.1を持つ私のeth0インターフェイスをを通じてウェブ・インターフェイスを見ることは出来ないが、IP アドレス 172.16.0.1 を持つeth1引火ーフェイスを通じてなら見ることが出来る。
基本のログイン/パスワード認証を通じてユーザ識別が必要であるけれども、http保護プロトコルを通じてウェブ・インターフェイスに接続するのにSSLを使うことができるのに注意。これはまた、cupsd.conf ファイルでのコンフィギュアが比較的容易である。
ウェブ・インターフェイスには、CUPSの作用とコンフィギュアの仕方についての沢山の文書がある分かり易いヘルプ・システムがある。
追記:この記事を翻訳する人へ:GPLソフトウエア・ライセンスの精神、つまり、コピイ、掲載、翻訳は自由−で書いたが、どうかe-メールで私に通知されたい。翻訳には絶えず注意したい−カリキュラムに役立つ。
著者紹介:
Alan は、Andorra の高校と大学レベルでCSを教えている。趣味は、(デジタルとフィルムの)科学写真、山歩き、ロック及びプロセッサ収集だ。
緒言
インストレーション
稼働
例 1: ネットワーク作製
例 2: システム呼出
例 3: デバイス・ドライバ
例 4: SysV IPC
コード
参考資料
TUN/TAP を得る最初のステップはuml_utilitiesのインストールだ。これはUMLウェブサイトから入手出来る。ユティリティをインストールするにはファイルをuntarして作ったディレクトリにcdし、'make install' とタイプする。これで我々の関心があるuml_net をそのうち一つとして五つのプログラムを /usr/bin にインストールする。uml_net は、ホストをUMLが連絡出来るようにするセットアップに役立つ。この方法の唯一の欠点は、uml_net がsetuidプログラムでセキュリティが弱点になるかも知れないことだ。uml_net プログラムの出来る設定は、ホストユーザとしてのホストマシンでも出来る。これは後の追加で説明する。
この例に関しては、ホストをipを10.0.0.1 に、UMLを10.0.0.2に設定する。ホストマシン上で、'ifconfig eth0 10.0.0.1' を用いeth0に対しipを割り当てる。ここで、コマンド './linux eth0=tuntap,,,10.0.0.1'.を用いてUMLマシンをブートする。eth0のため規定することの出来るパラメータは四つあるが、今は最初のものと4番目のものに関心がある。最初のものはUMLに使うトランスポートを告げ、最後のパラメータはホストマシンのipを規定する。多くの人が混乱するのは、最後のパラメータだ。これはホストマシンのipでUMLに与えたいものではない。ログインをブートした後、UML上で 'ifconfig eth0 10.0.0.2' を走らせる。ここでUMLからホストマシンに、またその逆にping, ssh, ftp,などが出来る筈だ。
UML kernel ディレクトリにある三つのファイルを変更する必要がある。UMLkernel ディレクトリから出発して、これらはinclude/asm/arch/unistd.h, arch/um/kernel/sys_call_table.c, arch/um/kernel/Makefileである。システム呼出のためのコードはarch/um/kernelディレクトリに入る。コード・セクションからのコードを例として使い、次をおこなう:
共有メモリ
共有メモリによち、未使用メモリを多重プロセスで使うようマップすることが出来る。共有メモリセグメントの設定と使用のため使われる四つのファンクション、 shmget(), shmat(), shmdt(), shmctl()、がある。これらのファンクションは、システム呼出を通じて実行されるので、それぞれのファンクションに対し基礎になるsys_shmget(), sys_shmat(), sys_shmdt(), sys_shmctl() のシステム呼出を予想することが出来る。UMLでの共有メモリは、ホストkernelと同じようにおこなわれる。共有メモリのセグメントを使う二つのプログラムのソースコードに関しては、shrmem1_sysV.c とshrmem2_sysV.cを調べられたい。gccを用いて各プログラムをコンパイルし、バックグラウンドでshrmem2_sysVをスタートすると、shrmem1_sysVが走る。
メッセージ引き渡し
プログラムの間でデータを共有する別の方法は、メッセージ引き渡しAPIを通じることである。共有メモリのように、メッセージ引き渡しAPIもまた基礎になるシステム呼出と共に四つのファンクションを有する。ファンクションはmsgget(), msgsnd(), msgrcv(), msgctl()で、システム呼出はsys_msgget(), sys_msgsnd(), sys_msgrcv(), sys_msgctl である。メッセージ引き渡しの例として、二つのソースファイルrecvmsg_sysV.c と sendmsg_sysV.c をコンパイルする。メッセージ引き渡しが働くのを見るには、バックグラウンドで recvmsg_sysVをスタートし、次いでsendmsg_sysVを走らせる。
#include <linux/kernel.h>
asmlinkage int sys_my_new_call(void) {
printk(KERN_ALERT "sys_my_new_call at your service\n");
return 0;
}
#include <sys/types.h>
#include <linux/unistd.h>
static inline _syscall0(int, my_new_call);
int main() {
int result;
result = my_new_call();
}
#define true 1
#define false 0
/* これはデバイスのため選んだ名になる。これをfile_operations structにあらわれるエントリポイントなどファンクションの添え字としても用いる. */
#define DEV_NAME "pp"
static int Major;
/* これらは file_operations structのレジデントに関するプロトタイプである */
static ssize_t pp_read(struct file *, char *, size_t, loff_t *);
static ssize_t pp_write(struct file *, const char *, size_t, loff_t *);
static int pp_open(struct inode *, struct file *);
static int pp_close(struct inode *, struct file *);
/* これはfile_operations structである。init_module ファンクションがこれをkernelに登録するので、kernelはその中のエントリポイント全部を理解する. */
struct file_operations Fops = {
owner: THIS_MODULE,
read: pp_read,
write: pp_write,
open: pp_open,
release: pp_close,
};
/* pp_probe ファンクションは、ここでは何もしないが、ハードウエア・リソースのため「実際の」ドライバを探す必要があることを指摘する。これらのリソースは、後に init_moduleの中で割り当てられる。 */
static int pp_probe(void){
return 0;
}
/* pp_read ファンクションは半端だが、呼び出されたとき、追跡の目的で、少なくともprintk をおこなう。 */
static ssize_t pp_read(struct file *file, char *buff, size_t ctr, loff_t *woof) {
printk(KERN_ALERT "\npp_read active.\n");
return 0;
}
/* pp_write ファンクションは半端だが、呼び出されたとき、追跡の目的で、少なくともprintk をおこなう。*/
static ssize_t pp_write(struct file *file, const char *buff, size_t ctr, loff_t *woof) {
printk(KERN_ALERT "\npp_write active.\n");
return 0;
}
/* pp_open ファンクションは、追跡の目的で、printk をおこなう */
static int pp_open(struct inode *inode, struct file *file) {
printk(KERN_ALERT "\nAn instance of %s has been opened.\n", DEV_NAME);
return 0;
}
/* pp_closeファンクションは、追跡の目的で、printk をおこなう. */
static int pp_close(struct inode *inode, struct file *file) {
printk(KERN_ALERT "\nOne instance of %s has been closed.\n", DEV_NAME);
return 0;
}
/* 次に init_moduleが次のことをするのを見る
* file_operations struct をレジスタするので、kernelがその中のエントリポイントを理解する
* 主な数値を取り戻す
* pp_probeを呼び出して、ハードウエア・リソースを探す
ハードウエア・リソースが見つかると、多分 init_moduleの範囲内で、このドライバが使うため割り当てられる必要がある。*/
int init_module(void) {
Major = register_chrdev( 0, DEV_NAME, &Fops);
if (Major < 0) {
printk("Registration Failure!\n");
return Major;
}
if (pp_probe() < 0) {
unregister_chrdev(Major, DEV_NAME);
printk(KERN_ALERT "pp_probe() failure!\n");
return -1;
}
printk(KERN_ALERT "\nRegistered %s, at major number = %d.\n\n", DEV_NAME, Major);
printk("To use %s, you must create a device file.\n", DEV_NAME);
printk("If this has not already been done, then enter:\n");
printk(" mknod /dev/%s c %d 0\n\n", DEV_NAME, Major);
printk("Also set appropriate permissions for /dev/%s.\n\n", DEV_NAME);
return 0;
}
/* cleanup_module ファンクションは、ドライバをアンレジスタし、 init_moduleを用いて「実際の」ドライバの中で割り当てられたリソース全部を解放する */
void cleanup_module(void) {
int ret;
ret = unregister_chrdev(Major, DEV_NAME);
if (ret < 0)
printk(KERN_ALERT "\nUnregistration problem where ret = %d\n\n", ret);
else
printk(KERN_ALERT "\nUnregistered %s, at major number = %d\n\n", DEV_NAME, Major);
}
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#define DEVICE "/dev/pp"
int main() {
int ddfd = 0;
int ret = 0;
ddfd = open(DEVICE, O_RDWR);
if (ddfd < 0) {
printf("\nOpen of %s failed.\n", DEVICE);
exit(-1);
}
printf("\nOpen of %s succeeded.\n", DEVICE);
ret = close(ddfd);
if (ret < 0) {
printf("\nClosing %s failed.\n", DEVICE);
exit(-1);
}
printf("\n Close of %s succeeded.\n", DEVICE);
exit(0);
}
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#define MEM_SZ 4096
struct shared_use_st {
int writ_by_you;
char some_text[BUFSIZ];
};
int main() {
int run = 1;
void *shared_mem = (void *) 0;
struct shared_use_st *shared_stuff;
char buffer[BUFSIZ];
int shmid;
shmid = shmget( (key_t)1234, MEM_SZ, 0666 | IPC_CREAT);
if (shmid == -1) {
perror("shmget in shrmem1_sysV failed");
exit(EXIT_FAILURE);
}
shared_mem = shmat(shmid, (void *)0, 0);
if (shared_mem == (void *)-1) {
perror("shmat in shrmem1_sysV failed");
exit(EXIT_FAILURE);
}
printf("memory attached at %X\n", (int)shared_mem);
shared_stuff = (struct shared_use_st *)shared_mem;
while (run) {
while (shared_stuff->writ_by_you == 1) {
sleep(3);
printf("Waiting for client ...\n");
}
printf("Enter some text: ");
fgets(buffer, BUFSIZ, stdin);
strcpy(shared_stuff->some_text, buffer);
shared_stuff->writ_by_you = 1;
if (strncmp(buffer, "end", 3) == 0) {
run = 0;
}
}
if (shmdt(shared_mem) == -1) {
perror("shmdt in shrmem1_sysV failed");
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
}
shrmem2_sysV.c
/* sysV IPC 共有メモリ−共有メモリからの読込
shrmem2_sysV.c
がshrmem1_sysVで働くようになっている:
バックグラウンドで shrmem2_sysV をスタート:
続いてt shrmem1_sysVがスタート
*/
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#define MEM_SZ 4096
struct shared_use_st {
int writ_by_you;
char some_text[BUFSIZ];
};
int main() {
int run = 1;
void *shared_mem = (void *) 0;
struct shared_use_st *shared_stuff;
int shmid;
shmid = shmget( (key_t)1234, MEM_SZ, 0666 | IPC_CREAT);
if (shmid == -1) {
perror("shmget in shrmem2_sysV failed");
exit(EXIT_FAILURE);
}
shared_mem = shmat(shmid, (void *)0, 0);
if (shared_mem == (void *)-1) {
perror("shmat in shrmem2_sysV failed");
exit(EXIT_FAILURE);
}
printf("memory attached at %X\n", (int)shared_mem);
shared_stuff = (struct shared_use_st *)shared_mem;
shared_stuff->writ_by_you == 0;
while (run) {
if (shared_stuff->writ_by_you == 1) {
printf("You_wrote: %s", shared_stuff->some_text);
sleep(rand() % 4);
shared_stuff->writ_by_you = 0;
if (strncmp(shared_stuff->some_text, "end", 3) == 0) {
run = 0;
}
}
}
if (shmdt(shared_mem) == -1) {
perror("shmdt in shrmem2_sysV failed");
exit(EXIT_FAILURE);
}
if (shmctl(shmid, IPC_RMID, 0) == -1) {
perror("shmctl in shrmem2_sysV failed");
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
}
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#define BUF 1024
struct my_msg_st {
long int my_msg_type;
char some_text[BUFSIZ];
};
int main() {
int run = 1;
struct my_msg_st some_data;
int msqid;
char buffer[BUF];
msqid = msgget( (key_t)1234, 0666 | IPC_CREAT);
if (msqid == -1) {
perror("msgget in sendmsg_sysV failed");
exit(EXIT_FAILURE);
}
while (run) {
printf("Enter some text:");
fgets(buffer, BUF, stdin);
some_data.my_msg_type = 1;
strcpy(some_data.some_text, buffer);
if (msgsnd(msqid, &some_data, BUF, 0) == -1) {
perror("msgsnd in sendmsg_sysV failed");
exit(EXIT_FAILURE);
}
if (strncmp(buffer, "end", 3) == 0) {
run = 0;
}
}
exit(EXIT_SUCCESS);
}
recmsg_sysV.c
/* sysV IPC メッセージ引き渡し−受け手: recvmsg_sysV.c が sendmsg_sysVで働くようになっている:バックグラウンドで recvmsg_sysV をスタート:続いてsendmsg_sysV がスタート*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
struct my_msg_st {
long int my_msg_type;
char some_text[BUFSIZ];
};
int main() {
int run = 1;
struct my_msg_st some_data;
int msqid;
long int msg_to_recv = 1;
msqid = msgget( (key_t)1234, 0666 | IPC_CREAT);
if (msqid == -1) {
perror("msgget in recvmsg_sysV failed");
exit(EXIT_FAILURE);
}
while (run) {
if (msgrcv(msqid, &some_data, BUFSIZ, msg_to_recv, 0) == -1) {
perror("msgrcv in recvmsg_sysV failed");
exit(EXIT_FAILURE);
}
printf("You wrote: %s", some_data.some_text);
if (strncmp(some_data.some_text, "end", 3) == 0) {
run = 0;
}
}
if (msgctl(msqid, IPC_RMID, 0) == -1) {
perror("msgctl in recvmsg_sysV failed");
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
}
Mathew, Neil, Richard Stones Beginning Linux Programming. 2版、Wrox Press, Inc., 1999年9月。
Rubini, Alessandro, Jonathan Corbert. Linux Device Drivers. 2版、O'Reilly Associates, Incorporated, July 2001年7月。
Russell, Rusty. "User Mode Linux HOWTO"。オンライン。インターネット2002年6月18日、user-mode-linux.sourceforge.net/UserModeLinux-HOWTO.html.で入手可能
著者紹介:
私は現在、米国ワシントン州チェニィの東ワシントン大学で、コンピュータ科学の大学院学位を得る勉強をしている。