Linux Gazette 2003年5月号 #90
今月のLinux Gazette の主な記事
n今月のニュース
 ・一般ニュース
 ・ディストリビューション関連ニュース
 ・ソフトウエア及び製品関連ニュース
n シャープ・ザウラス SL-5500 Linux PDA用ソフトウエア開発
n 今月のPerlワンライナ:Red Wormの謎
n 書評:システム管理用Perl
n setjmp/longjmp 解説
n CUPS印刷システム
n ユーザ・モードLinuxを用いるプログラム作成
 
(訳者注)
原文を一括して一つのファイルでセーブするには、下記のリンクがあります。
TWDT 1 (gzipped text file)
TWDT 2 (HTML file)
前者はテキスト形式で、後者はHTML形式です。但し、HTML版のリンクが働くとは限りません。
 
 
 
 
今月のニュース
 
▼▼▼一般ニュース▼▼▼
Linuxテスト・プロジェクト
Linux Test Project ltp-2003Dがリリースされた。これは1000を超えるGNU/Linux OS試験を含む。
 
Eventide
デジタル・ロギング技術の作成者Eventide Inc.が、GNU/Linuxの安定性と信頼性を基にLinuxベースのデジタル・ロギング・アーカイブ・システムをリリースした。公衆の安全が安全が必須の市場ではこのような信頼性が不可欠である。
Eventide VR778 デジタル・ロギング・アーカイブ・システムの仕様 specifications は、pdfフォーマットで入手することが出来る。Eventideによれば、Linux O/Sをデジタル・ロガーに使用したのはVR778が初めてである。これにより、Eventideは「他のマイクロソフト・サーバシステムのような」ライセンス要件もアプリケーション費用もなく、極めて高級なデジタルシステムを提供することが出来る。
 
ActivateStateが迷惑メール撃退対策委員会を設置
e-メール内容選別ソフトウエアの生産者ActiveState Corp.が、世界最先端の迷惑メール研究者からなる社内ブルーリボン・チームの創設をを発表したannounced 。対策委員会には、Perlベースの有名なオープンソースBayesianメール分類機、POPfileを作ったJohn Graham Cumming博士、SpamBayesの作者、PytonベースのオープンソースBayesianメール分類機の作者Tim Peters、自動e-メール分類システム出るオープンソース・ツール、ifileの作成者MIT人工知能研究所のJason Rennie 、共同選別の発明者Gary Robinsonが含まれる。対策委員会の重点は、企業に影響を与える迷惑メール撃退問題である。対策委員会は次のような企業e-メール送付を最適化する技術問題数件に取り組む。
・e-メール内容を解析して迷惑とそうでないものとをもっと厳密に区別する「次世代方法」の開発。
・企業生産性向上のため、迷惑メール無しの玄関口選別機能開発の先駆者となること。
・メッセージ交換産業内の協力を認識して促進し、規格とe-メール政策を実現すること。s
 
 
 
 
 
▼▼▼ディストリビューション関連ニュース▼▼▼
Ark
Ark Linux H20:簡単で(ほぼ)完全Ark Linux H20: Simple and (Nearly) Complete
 
Knoppix
Knoppix 3.2 がリリースされた。
 
最初からのLinux(LFS)
最新版LFS (4.1) を印刷本形式printed-book form.で入手することが出来る。書物は CheapBytes.からの付属CDRと一緒でも別でも良い。
LFS 4.1システムを立ち上げて走らせるとき、バージョン1.0に更新されたばかりのBFLS(超LFS)にのめり込んでしまうことがある。
 
Lindows
LindowsOS 3.0 審査LindowsOS 3.0 Review.
 
Mandrake
Mandrake Linux リリース9.1.Mandrake Linux releases 9.1.。これはOSニュースに解説がある reviewed at OSNews (Linuxの常套)
 
PCQLinux
Newsforgeの報道では、インド月刊誌PCQuestが、Red Hat Linux 8.0を基に自分の変形LinuxディストリビューションをリリースしたNewsForge reports on PCQLinux
 
Peanut
Peanu Linuxに移動中 Moving to Peanut Linux.
 
Slackware

Slackware 9.0がリリースされた released.。新規事項は ChangeLog をチェックされたい。

このリリースはTinyMinds.orgで審査された一方で、OSニュースもディストリビューションを巡る謎を解明している(Linux Todayの常套手段)。
 
UnitedLinux
UnitedLinux は、資金提供四社が特別支援計画と、OracleのUnbreakable Linux Partner Initiativeの ISV 参加者に対し割引を提案すると発表した。
 
YellowDog
Yellow Dog Linux 3.0 Review.
 
 
 
 
 
▼▼▼ソフトウエア及び製品関連ニュース▼▼▼
 
Pheonix がFirebirdで生き返る
Mozillaから分かれたブラウザPhoenix の名がFirebirdに変わった。
 
Kerioが最新のメールサーバ・リリースに迷惑メール撃滅(SpamAssassin)を追加
セキュリティ対策ソフトウエア開発者Kerio Technologiesが、そのマルチ・プラットホーム企業向けメッセージ交換ソリューションの新版、迷惑メール防護強化のKerio MailServer 5.6 、を立ち上げた。既存の迷惑メール撃退ツールを、認証取得迷惑メール検出 SpamAssassin.で強化した。
 

Keioはまた、e-メール中のウィルスと戦うため、Sophos と提携した。

CourseForum 2.1/ProjectForum 2.1
CourseForum Technologies は、CourseForum 2.1とProjectForum 2.1が利用出来ると発表した。これらウェブベースのアプリケーションは、オンライン又は対面コース、学生グループ、ワークグループ・プロジェクト、ビジネスチーム、及び企業内部に対する、会話、連携、連絡を強化するのが目的である。CourseForum とProjectForumはMac OS X、Windows、Linux 及び FreeBSDでホストすることが出来る。ユーザに必要なのは、標準ウェブブラウザだけだ。
 
iConductor がシェアウェアに
Apacheサーバ上でルール・ベースのウェブ・アプリケーションの開発を簡単にする目的のiConductor サーバ・モジュールが、Apacheバージョン2.0を含めシェアウェアとして利用出来るようになった。iConductorの作成者Farpointer Technologies,は、ディストリビューション・モデルを変更して、商業外目的用iConductorモジュールの無制限ディストリビューションが出来るように下。目標とする市場は、LinuxベースのApacheサーバユーザである。
 
その他のソフトウエア
Nvidiaが、そのグラフィックカード用にLinuxドライバ Linux driversの新バージョンを発表した。
 
LG「今月のニュース」はこれから新編集者Mickが担当する。

[Picture] Michelは数年前にアイルランドで生まれ、現在ダブリン大学機械工学部で博士論文に取り組んでいる。論文の題目は、非破壊検査におけるLamb波の使用だ。この仕事にGNU/Linuxが大変役立ったので、Michelは、他の工学分野への無料ソフトウエア利用に強い関心を持った。論文を仕上げたら、長い徒歩旅行に出る積もりでいる。

 

 

Copyright © 2003, Michael Conry. Copying license http://www.linuxgazette.com/copying.html
Published in Issue 90 of Linux Gazette, May 2003
 
 
 
 
 
シャープ・ザウラス SL-5500 Linux PDA用ソフトウエア開発
By Bruce Forsberg
 
今、私は幾つかの条件を満たすMP3プレーヤを探している。一つはLinuxで使えること、次は古き時代(OTR)のラジオショウに使えることだ。私は米国で古き時代のラジオと言われるものが好きだ。1930年代、40年代、50年代のラジオショウだ。ショウがMP3フォーマットで一杯入ったCD-Rを買うことが出来る。OTRショウは普通、サンプルレート22050のモノフォーマットの24, 32又は48 kbps でエンコードされているので、長さは1時間が30分だ。これらの条件では、MP3プレーヤ全部が働くとは限らない。そこで対策を探した。結局Linux PDA が最適との結論に達した。ここには、必要な機能を備えたソフトウエアを自分で書くことが出来る。シャープ・ザウラス SL-5500は、埋込システム用QT、QtopiaにLinuxを使う。既にLinux上でQtプログラム作成を知っていたので、当然の選択となった。
シャープのウェブサイトを見ると、米国で売っているLinux PDA モデルは二つある。SL-5500 とSL-5600だ。この記事を書いている時点で、SL-5600は売り出したばかりだ。二つのモデルには大きい違いが幾つかあるが、その一つは、SL-5600 には400MhzインテルXスケールプロセッサが入っているのに対し、Sl-5500には206Mhz ARM SA-1100プロセッサが入っている。買うときにはそれしかなかったので、Sl-5500を買った。400Mhzの方が良いがオーディオには不要だ。ビデオが欲しければ5600を待ったかも知れない。装置にはLinux 2.4 Embedix kernelが16 MBフラッシュROMの中に他の多くの標準アプリケーションと共に入っている。64 MB SDRAM が入っていて、その半分はプログラム・メモリ用、残り半分はユーザプログラム記憶用だ。アクセサリその他将来のためのホストも含んでいる。
シャープ・ザウラス SL-5500は、$300プラス送料$200で買うことが出来た。USBコネクタの付いたドッキングステーションとMSウインドウズ用ソフトウエアも付いて来た。数ヶ月前のことだ。SL-5600が出たのでSL-5500は新品が$200-$300で買える。
開発のための設定
このプラットホーム上でプログラムを作る方法を考えるため、OTR MP3 プロジェクトは最初の計画として大き過ぎると思ったので、似たようなプロジェクトを選んだ。自動車走行距離計算機だ。トヨタ・プリウス・ハイブリッド車を買った。45-50 MPGほど走ったので、走行距離を追跡したかった。プログラム要件幾つかを書き出して、SL-5500にプログラムする方法を考えた。見出したのは次のような事項だ。
先ずソフトウエアが幾つか必要だ。シャープ・ザウラスを開発するとき、二段階で開発する。GUIレイアウト、コード作成、デバッグ、Linuxボックス上でのテスト、全部を実行する。これらを終わったら、Strong ARM アーキテクチャを使って、ソフトウエアをシャープ・ザウラスPDA用にクロスコンパイルして纏める。これをするにはPRMが幾つか必要だ。

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とタイプしても良い。これでエラーログに送られたメッセージが表示される。

この記事によりシャープ・ザウラスPDA用のプログラム作成を始める気になられると良いと思う。大変面白くて、オープンソースとLinuxの成功に貢献する。また、新しいPDAを使って、どんなに興奮するかに驚くだろう。計画を完成してリリースの準備ができたらsourceforge.netをチェックされたい。君の計画を主催するにふさわしい場所だ。次に、君のipkを http://www.killefiz.de/zaurus にあるザウラスPDA検索エンジンにアップロードする。最初のリリースの後、一,二週間で別のバージョンをリリースする準備をすること。バグが見つかったら、このリリースで修正して、プログラムを使えるものにする。プログラムを作るときはユーザの身になって、出来るだけ使い易いものにする。例えば私の走行距離プログラムには、GUIキイパッドを追加して積算計と燃料計を入力することにし、ボタンを追加して日付を入れるようにした。ザウラスにはキイボードがあるが、GUIキイボードで入力が大変容易になる。ザウラスで開発を開始して楽しまれたい。
 

参考資料

シャープ・ザウラスの使い方: 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が答えだった。

Copyright © 2003, Bruce Forsberg. Copying license
http://www.linuxgazette.com/copying.html
Published in Issue 90 of Linux Gazette, May 2003
 
 
 
 
今月のPerlワンライナ:Red Wormの謎
By Ben Okopnik
 
−「ここまで来ると、一寸遠いね。フリンク君」

ウーマートとフリンクは、足音をチタンの壁に響かせながら、長いVPN連絡トンネルを歩いて来たばかりだった。目的システムの心地よい広大な環境に達したとき、フリンクは、気持ちの良い変数を置いて疲れた脚を休めたいと思ったのだが、ウーマートはドンドン歩き続けた。やっとウーマートが向きを変えて "/var/log/apache" と書かれた部屋に入った。

「やっと着いたよ。 '/var/log/apache/access.log' はここだ。然も見たところどうやら間に合ったらしい。かわいそうな奴は400MBまでで、ほとんどパーティション一杯に詰まっている。それに転がされてからほんの数日しか経っていない」

フリンクは、磨き上げられた床(最近 "cruft" で掃除した)を歩いて、綺麗な椅子に座り、分厚いログファイルをうっとりと見つめた。

−「一体ここで何があったのですか?金満銀行のデータベース紛失の謎[1]に対する貴方の解決を持ち上げてほめた最近の新聞記事についてお知らせしようと入って来ただけなのに、いきなり私を引き摺って、それがいけないと言うのではなく・・・」

有名な探偵は、言い訳のように微笑んだ。

−「仕事中はつい夢中になる癖がある。知っているだろう。ところで−ここに悪いことがある。そう、顧客に何かが起こっているのはここだ。ナプキン縁飾り産業で働く経理担当者のため蹄鉄型溶接スプロケット作るのが専門の小会社が、自分のウエブサイトで起こっている古い幾つかの変な事柄について、疑いを持ったと言う訳だ。例えば、応答時間が瞬間的に天井を突き抜けることがあり、「サーバ話し中」のメッセージが普通に較べると遙かに多い回数で送り返される。仕事量が極端に増えた訳ではなく、近頃は経済状態が悪くて、彼らの製品のような贅沢品の需要が減ってむしろ、少なくなっているのだが・・」

フリンクが頷いた。

−「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

−「よしよし。見てごらん。君の考えはどうだ?」

フリンクは、画面を暫く見つめて、頷いた。確信に満ちた声で話した。

−「これはDoSですよ。誰かが数日かそこら掛けて、ブラウズしたと思いたいですね、だから103と112が境い目のケースですが−31万5000ヒットも?私はそれを、マシンの数が少ないので、DDoS(分散DoS、多くのマシンが一時に示されたネットワーク又はホストに押し掛ける)と言って良いかどうか判りませんが、絶対にもっと侵入して来ますよ−多分これらドメインのISPに連絡して−一時的にファイアウォールでブロックすることです。別のヒットに関するサンプル入力が見られますか?それに着いての理論があります。もし長い `GET' ストリングなら・・・考えがあります」

ウーマートは考え込んでから、頷いた。

−「何を目的にしているか分かったよ、理に叶った可能性だ。さて、これは、示された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


で、−`-wlne' スイッチは警報を起動します。”ラインモード”で全部を読み取って印刷します。これはあららじめEOL文字を削除し後で付け加えます。ファイル全部を、1行毎にループしてそれにつながるコードを実行ます。これは易しい部分です−最近 "pelrdoc perlrun" 勉強しました。さて、コード

/^(\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";

   }

"your program goes here'' コメントを見給え。ここに閉じ大括弧を入れたら何が起こるかね?」

フリンクは、コードを熱心に検討した。不意に、顔を上げた。

−「分かりましたよ!閉じ括弧でwhileステートメント終わります・・・だから次の開き台括弧は、渡されたばかりのブロックを作ります。したとこは、'while'ループを出ることで、中括弧の後の全部は、一度実行されるだけです。'END {}' ブロックを使うのと同じです。凄いですね![2]

よしよし、これが分かったら、残りは余り難しくありません。

$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はLGの寄稿編集者でAnswer Gangのメンバーだ。

picture Benは1962年モスコーで生まれた。6才で、フォークをコンセントに突っ込んで火花を散らした時以来、電気に興味を持った。長じて、プリント板に部品を半田付けし4kメモリに合わせるプログラムをして以来、コンピュータの仕事をした。夜、うなされるのを治して呉れる心理学者がいれば、大金を払う。

Benの次の経験は、十数個の言語によるプログラム、ネットワーク台風接近中のデータベース維持、及び航海雑誌から技術誌に渡る記事執筆である。帆船による七年間の大西洋/カリブ海の航海を最近終わった。今はバルチモアに停泊しており、サン・マイクロシステムの技術インストラクタとして働いている。
Ben は1997年以来Linuxの仕事をしている。北西太平洋の一部の核戦争遂行に完全に興味を失ったお陰だ。

 

Copyright © 2003, Ben Okopnik. Copying license
http://www.linuxgazette.com/copying.html
Published in Issue 90 of Linux Gazette, May 2003
 
 
 
 
書評:システム管理用Perl
By Dustin Puryear
書名: システム管理用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ソリューションを組み込む)がある。

 

Copyright © 2003, Dustin Puryear. Copying license
http://www.linuxgazette.com/copying.html
Published in Issue 90 of Linux Gazette, May 2003
 
 
 
 
setjmp/longjmp 解説
By Raghu J Menon

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>

 
main()
{
jmp_buf env;
int i;
i=setjmp(env);
printf("i= %d\n",i);
if(i==0)
printf("I am in if ..\n");
else{
printf("I am in else too...\n");
exit(0);
}
longjmp(env,2);
printf("Grrr... why am i not getting printed\n");
}
 

これをコンパイルして走らせると、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

 0 0 0 for error in 1
 1 1 2 for error in 2
 0 1 2 for error in 3
 1 2 3 for error in 4*/
#include<setjmp.h>
#include<stdio.h>
 
int fun4(jmp_buf env ,int i){
if(i==0) longjmp(env,4);
return 10;
}
int fun3(jmp_buf env,int j){
if(j==3) longjmp(env,3);
return fun4(env,j+1);
}
int fun2(jmp_buf env,int p,int q){
if(p==2) longjmp(env,2);
return fun3(env,p+q)+fun3(env,p-q);
}
int fun1(jmp_buf env,int l,int m, int n){
if((l+m+n)==0) longjmp(env,1);
return fun2(env,l+m,l+n);
}
 
main(){
jmp_buf env;
int s,l,m,n;
printf("Enter values(integer) for l m and n please\n");
scanf("%d%d%d",&l,&m,&n);
s=setjmp(env);
if(s!=0){
printf("There is an error in function %d exiting..\n",s);
exit(0);
}
fun1(env,l,m,n);
printf("The functions executed normally\n");
 
}
 
このプログラムは、優雅なエラー取扱を示す以外、何の役にも立たない。コードは四つのファンクションを定義する。その各々は、規定数の整数パラメータを受け取る他に、envをパラメータとして持つ。envはmainファンクションのsetjump呼出にセーブされたプログラム状態を保持する。各ファンクションの実行時のエラーは、if条件で規定される。プログラムをコンパイルして実行し、次の値のセットを l, m, n.に入力する。

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>

#include<stdio.h>
 
 
int fun4(jmp_buf env ,int i){
if(i==0) goto abc;
return 10;
}
int fun3(jmp_buf env,int j){
return fun4(env,j+1);
}
int fun2(jmp_buf env,int p,int q){
return fun3(env,p+q)+fun3(env,p-q);
}
int fun1(jmp_buf env,int l,int m, int n){
return fun2(env,l+m,l+n);
}
 
main(){
jmp_buf env;
int s,l,m,n;
printf("Enter values(integer) for l m and n please\n");
scanf("%d%d%d",&l,&m,&n);
fun1(env,l,m,n);
abc: printf("There is an error exiting gracefully\n");
exit(0);
}
 

プログラマの弱点.....

setjmp/longjmpには油断の出来ぬバグがある。実行にではなく、使い方にだ。殆どの人はプログラムを書くときスタック状態を正しく認識していない。エラーがあって(gdbを通じる)スタックの検査により追跡するときだけだ。ファンクション呼出があるときはいつでも、スタックを操作する。先ず、呼び出されたファンクションの引数が逆順でプッシュされる。次いで、JSRが呼び出されて、戻りアドレス(pc)とfpがプッシュされ、続いてfpとspが空にされて呼び出されたファンクションのためあたら言いスタックフレームを作る。呼び出されたファンクションは直ちに、ファンクション内で宣言されるローカル変数用のスタックを作る。これでスタック構造が分かったところで、下記のコードseg.cを走らせて見る。コンパイルは上手く行くが、ランには完全に失敗し、フォールトになる。理由がお分りだろうか?

(訳者注:読者の便のためseg.cを下記にダウンロードしました)

#include<setjmp.h>

#include<stdio.h>
 
int me_first(char *s,jmp_buf env){
int i;
i=setjmp(env);
printf("me_first:I am returning after a setjmp:%s\n",s);
return i;
}
 
int i_follow(int i,jmp_buf env){
printf("i_follow:I'm gonna do a longjmp...\n");
    longjmp(env,i);
}
 
 
main()
{
jmp_buf env;
if(me_first("IC-Labs",env)!=0) exit(0);
i_follow(3,env);
}

コードを追って見よう。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型の一つで置き換えて戻して見ると良い。フォールトするか?

シグナルの取り扱い.....
これらファンクションの美しさの一つは、シグナルハンドラからlongjmpしてプログラムに戻り、これらシグナルを再度捕捉することが出来ることである。下のプログラム sig.cをチェックされたい。

(訳者注:読者の便のため sig.cの内容を下記に示します)

#include <signal.h>
#include <setjmp.h>
 
int i, j;
long T0;
jmp_buf Env;
 
void alarm_handler(int dummy)
{
 long t1;
 
 t1 = time(0) - T0;
 printf("%d second%s has passed: j = %d. i = %d\n", t1,
   (t1 == 1) ? "" : "s", j, i);
 if (t1 >= 8) {
  printf("Giving up\n");
  longjmp(Env, 1);
 }
 alarm(1);
}
 
main()
{
 
 signal(SIGALRM, alarm_handler);
 alarm(1);
 
 if (setjmp(Env) != 0) {
  printf("Gave up: j = %d, i = %d\n", j, i);
  exit(1);
 }
 
 T0 = time(0);
 
 for (j = 0; j < 10000; j++) {
  for (i = 0; i < 1000000; i++);
 }
}
 

mainファンクションは、signalシステム呼出を用いてシグナル。ハンドラを呼び出す。パラメータはsigno(SIGALRM)で、これはハンドラを設定しているシグナルと、シグナルが起こったとき実行されるハンドラ・ルーチンを示す。アラーム呼出はSIGALRMシグナルを毎秒プログラムに送る。アラーム・ハンドラは、基本的に8秒経過すると、longjmps する。

 

著者紹介:

コンピュータ科学工学の卒業論文を殆ど仕上げたところです。神の国 Kerala の小さい町 Trichur からご挨拶しています。文体と内容に関する建設的なご意見を歓迎します。e-メールで連絡して下さい。

 

Copyright © 2003, Raghu J Menon. Copying license
http://www.linuxgazette.com/copying.html
Published in Issue 90 of Linux Gazette, May 2003
 
 
 
 
CUPS印刷システム
By Alan Ward
 

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アクセス制御レベルでは、グループが承認しても、プリンタにジョブを拒絶させることが出来る。最終結果は、ユーザはプリンタでなくぷりんた・グループを使うこととなる。これはある程度、自分の考えるプリンタ使用方針に左右される。

実施例 1

Linux下のコンピュータ五台のある作業所があり、全部CUPSを走らせている。そのうち一つのプリンタを変えるとき、CUPSウエブインターフェイスを通じ、30秒いかで、:

・古いプリンタを CUPSから外し、,
・新プリンタを入れる。

これがコンフィギュレーションに必要な全部だ−別のコンピュータはデフォルト印刷ルートを、別の30秒以内で更新される。全部の変更は1分以内で、レーザープリンタの余熱時間より短い。.

実施例 2

学校ネットワークに:

・誰でも印刷出来る白黒プリンタクラス
・誰でも印刷出来るが−量に制限がある下書きカラークラス
・私の監督下で開放される精密カラークラス

を作りたい。これらのプリンタの大部分はWindowsボックスから外れていて、Windows下の他のコンピュータで直接使うことが出来る。しかし、それらを中央ブリッジ/ルータ上でCUPSを通じて提供することにより:

・プリンタ集中化の手段が得られる−ユーザは一つの場所でプリンタを探さなければならない;
・通常のWindows放送通信にネットワーク帯域幅を占領させて一杯にすることなく、別のイーサネット・セグメントに印刷手段を与える;
・1階ににある部門別プリンタに用紙がなくなったため、別の建物の4階にある教室から印刷している教師が立ち往生しないことを確実にする−印刷作業を待機プリンタに移す。.

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プリンタと同じ方法で扱うからである。

ネットワーク・プリンタ

ネットワーク・プリンタ−つまり、ホスト・コンピュータをネットワークで利用出来るようにする必要のないネットワーク・インターフェイスを有するプリンタ−は、任意の各種プトロコルを使うことが出来る:

・SMB プロトコル−自分のWindows環境ネットワークブラウズ画面で見ることが出来る。
・LPD プロトコル−エプソン・プリンタの幾つかのモデルは、TPC/IP スタックと LPD プロトコルを組み込んでいる。ポート515で、Linuxボックスのようにアクセスすることが出来る。規定値キュー lpを試すこと。
・所有権付きプロトコル(良くない!)

初めの二つの場合は、コンピュータがホストするプリンタのように進める。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を教えている。趣味は、(デジタルとフィルムの)科学写真、山歩き、ロック及びプロセッサ収集だ。

 

Copyright © 2003, Alan Ward. Copying license
http://www.linuxgazette.com/copying.html
Published in Issue 90 of Linux Gazette, May 2003
 
 
 
 
ユーザ・モードLinuxを用いるプログラム作成
By Nick Weber

緒言
インストレーション
稼働
例 1: ネットワーク作製
例 2: システム呼出
例 3: デバイス・ドライバ
例 4: SysV IPC
コード
参考資料

緒言

ユーザモードLinux(UML)は、Linux からLinuxへのポートである。これは、現存Linuxインストレーションの上で走る仮想Linuxマシンを作る。この仮想マシンはユーザモードで走らせることが出来る。これは、仮想マシンのlinux kernelに 通常のユーザのように完全なアクセスをすることが出来る。この型の能力と融通性により、ホストマシンにルートしたりホストマシンを再ルートすることなく、仮想マシンのkernelで物事を試すことが出来る。テストはUMLの主な用途である。この記事では、OSクラスでおこなう共通のこと幾つかを探って、UMLを用いてこれらをおこなう方法を眺める。UMLプロジェクトは、Jeff Dikeの維持するuser-mode-linux.sourceforge.netで見出すことが出来る。UMLプロジェクトには、ユーザ・リストと開発リストの二つのメールリストがある、

インストレーション

始める前に、これらの指導は2G/2Gホストでは役立たないことに注意されたい。UMLインストレーションは、簡明直裁なので短時間でおこなうことが出来る。UMLインストールに成功するには三つのものが必要である:
・Linux kernel
・kernelと同じバージョンのUML パッチ
・ルート・ファイル・システム
Linux kernelは、ミラー又はwww.kernel.orgに行って入手することが出来る。kernelのバージョンはUMLバージョンと同じでなければならない。この記事の執筆時、 Linux 2.4.19 kernel をuml-patch-2.4.19-45.bz2 パッチと共に使っている。UMLパッチとルート・ファイル・システムは、user-mode-linux.sourceforge.net/UserModeLinux-HOWTO-2.htmlにあるUML sourceforge から取得することが出来る。勧告:UMLウエブさいとから最新のskasパッチをホスト(自分のマシン)kernelに適用すること。SKASとは、separate kernel address space(分離kernelアドレス空間)の略である。このパッチがないと、UMLは規定値でttモードを使う。このモードはUML用に稼働する極めて少数のスレッドしか作らない。skasモードの主な利点は、UMLインスタンスが極めて速く走ることである。ここから、インストレーション完了まで四つのステップがある:
1.Linux kerneliをディレクトリにアンパックする。メインkernelが記憶されているものとは別のディレクトリ(Russell)に設定することを薦める。結局、重要な点は、これをユーザモードで走らせると、ルートでない限り、Linux kernel を/usr/src/linuxに作ることが出来なくなることである。.
2.UMLパッチ (Russell)を適用する。 cat uml-patch-2.4.19-45.bz2 | bunzip2 - | patch -p1 (Russell)
3.ステップ1でアンパックしたソースから Linux config file を作る。 make xconfig ARCH=um (Russell, p.2). 最初は規定値で十分。
4. 'make linux ARCH=um' (Russell)を用いてkernelをコンパイルする。

UMLの稼働

kernelをコンパイルしたら、コマンド 'linux' (Russell)を使って走らせるだけだ。これは、ルート・ファイルシステムを、root_fsと言うカレント・ディレクトリに持っていると仮定している。そうでなければ、コマンド 'linux ubd0=name-of-root-filesystem' (Russell)を使う。Linuxマシンが通常のように、だが作業中のターミナルで、ブートする筈だ。UMLウエブサイトにあるルート・ファイルシステムが、ルートとゲストのアカウントそれぞれのため、ルート/ルートとゲスト/ゲストのログイン/パスワード全部を持つ。

例 1: ネットワーク作成

これで多重UMLを走らせることが出来るので、互いに会話をさせる。UMLの連絡には六つの方法がある:スイッチ・デーモン、イーサータップ、TUN/TAP、マルチキャスト、slip、slirp、pcapだ。各方法の設定はuser-mode-linux.sourceforge.net/networking.htmlに説明がある。設定が最も容易なのはTUN/TAPだ。

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,などが出来る筈だ。

例 2: システム呼出

kernelで出来る面白いことは、自分のシステム呼出を付け加えることだ。これは通常、システム呼出を使うため、マシンに対するルートアクセスと再ブートを必要とする。UMLは再ブートが容易で、それに対するルート・アクセスがあるので、ホストマシンを再ブートしたり、それにルート・アクセスする必要がなくて新しいシステム呼出を実行するのに必要なあらゆるものがある。

UML kernel ディレクトリにある三つのファイルを変更する必要がある。UMLkernel ディレクトリから出発して、これらはinclude/asm/arch/unistd.h, arch/um/kernel/sys_call_table.c, arch/um/kernel/Makefileである。システム呼出のためのコードはarch/um/kernelディレクトリに入る。コード・セクションからのコードを例として使い、次をおこなう:

1. unistd.h に次を加える:
#define __NR_my_new_call 243
__NR_my_new_callの後の数字は、場合により異なるが、#defineセクションの最後の数字に1を加えたものである。
2.sys_call table.c では、以下の変更が必要である (Karypidis):
extern syscall_handler_t sys_my_new_call;
#define LAST_GENERIC_SYSCALL __NR_my_new_call
[ __NR_my_new_call ] = sys_my_new_call,
3. Make file に次を追加する:
構築されたターゲットのリストに対しmy_new_call.o :
4.ここでシステム呼出のためのソースコードを arch/um/kernel ディレクトリに追加
5. UML kernelをコンパイル

UML内でシステム呼出を使うには次をおこなう:
1. UMLに対しブートしてログイン
2.ユーザ・プログラムを作って新しい呼出を使う。これはシステム呼出用ライブラリ・ラッパーも含む
3. 'mount none /mnt -t hostfs' を使ってホストをマウントする。
4.'gcc -I/mnt/path-to-uml-code/include testprogram.c' を使ってテスト・プログラムをコンパイルする。
5.テスト・プログラムを走らせる。
ホストmasinをUMLにマウントしなければならない理由は、システム呼出用のコードがUMLファイルシステムの外に置かれていることである。これはシステム呼出をUML内とホストマシン上で使う唯一の相違である。

例 3: デバイス・ドライバ

UMLで出来る別の有用なことは、デバイス・ドライバのためコードをテストすることである。UML kernelにドライバを追加するのは、ホストkernelに追加するのと同じ処理である。先ず、UMLをブートしてログインする。コードセクションにあるファイルpp.cを使って、'gcc -Wall -c -O2 pp.c' によりpp.cをコンパイルする。これでpp.oが出来上がるので、これを稼働中のUML kernelにロードする。ドライバをコンパイルするのに使ったkernelとUML root_fsのためのファイルシステムを作るのに使ったものとの間で異なるkernelバージョンについてドライバをinsmodするためタイプするとき、殆どの場合、エラーメッセージが出るだろう。-fスイッチを 'insmod -f pp.o' のように使ってドライバを無理にロードすることが出来る。ドライバが使えるようになるまで、/var/log/messagesチェックして、正しいドライバを/devに追加するコマンドを見付ける必要がある。ドライバをテストするには、'gcc testprogram.c' を使ってテストプログラムをコンパイルして、実行可能ファイルを走らせる。/var/log/messagesを点検してプログラムが正しく走ったことw確認する。上手くいっていれば、デバイスが開かれたとのメッセージと、続いてデバイスを閉じるとのメッセージが出る筈だ。この節のコードと情報は、Alessandro Rubinの書物、 Linux Device Driversに依存した。

例 4: SysV IPC

これらの例は、書物 Beginning Linux Programming(Linuxプログラム作成初歩)から取った:.

共有メモリ
共有メモリによち、未使用メモリを多重プロセスで使うようマップすることが出来る。共有メモリセグメントの設定と使用のため使われる四つのファンクション、 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を走らせる。

コードの例

例 2: システム呼出コード

my_new_call.c

#include <linux/kernel.h>

asmlinkage int sys_my_new_call(void) {
printk(KERN_ALERT "sys_my_new_call at your service\n");
return 0;
}

testprogram.c

#include <sys/types.h>
#include <linux/unistd.h>

static inline _syscall0(int, my_new_call);
int main() {
int result;
result = my_new_call();
}

例 3: デバイス・ドライバ・コード

pp.c
#define __KERNEL__
#define MODULE
#include <linux/module.h>
#include <linux/version.h>
#include <linux/wrapper.h>
#include <linux/fs.h>
#include <linux/sched.h>
#include <linux/ioport.h>
#include <linux/delay.h>
#include <linux/param.h>
#include <linux/interrupt.h>
#include <linux/time.h>
#include <linux/timer.h>
#include <asm/uaccess.h>
#include <asm/io.h>

#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);
}

testprogram.c

#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);
}

例 4: 共有メモリ

shrmem1_sysV.c
/* sysV IPC 共有めもり−共有メモリへの書込
shrmem1_sysV.c
がshrmem2_sysVで働くようになっている:
バックグラウンドで shrmem2_sysV をスタート:
続いて 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;
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);
}

例 4(続き): メッセージ引き渡し

sendmsg_sysV.c
/* sysV IPCメッセージ引き渡し−送り手
sendmsg_sysV.c
が recvmsg_sysVで働くようになっている:
バックグラウンドで rcvmesg_sysV をスタート:
続いて sendmsg_sysVがスタート
*/

#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);
}

参考資料

Karypidis, Alexandros. "Adding a System Call"。オンライン。インターネット2002年3月25日: user-mode-linux.sourceforge.net/lksct.で入手可能

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.で入手可能

 

著者紹介:

私は現在、米国ワシントン州チェニィの東ワシントン大学で、コンピュータ科学の大学院学位を得る勉強をしている。

 

Copyright © 2003, Nick Weber. Copying license
http://www.linuxgazette.com/copying.html
Published in Issue 90 of Linux Gazette, May 2003
 
 
 
 
END