インテリジェントデバイスの世界的専門メーカーIntrinsyc Software Internationalが、IntrinsycのCerfCube 405EP基準プラットホームを用いるそのIBM PowerPC 405EP埋込プロセッサの販売に関するIBM マイクロエレクトロニクスとの協力を本日発表した。
サーバ器具、データ収集装置、スキャナ、インターネット用機器のたの理想的にCerfCube 405EP はまた、ネットワーク・ルータとコンセントレータ、LANベースのビデオ、無線ネットワークのアクセスポイント、LAN経由で大量のデータ移動が必要なあらゆるアプリケーションにも適している。新聞発表全文は press release is available online.
ERP5 とCollaborative Portal Server (CPS)チームが、オープンソース/フリーウエアに関する国際会議Libre ソフトウエア会議(LSM)に於いて、全くオープンソース/フリーウエアにみに依存する世界最初の全世界情報システムを両者が力を合わせて作成すると発表した。Collaborative Portal Server (CPS) は、GPLライセンスの下で発表された100以上の製品を大型政府組織及び超大規模産業で実行させているコンテント管理及び共同作業のシステムである。ERP5 は、GPLライセンスの下で発表された最初の企業リソース計画システムで、ヨーロッパ産業で成功している。ERP5 とCPS の同盟は、Zopeオープンソース/フリーアプリケーション・サーバに基づく協同的で量的な継ぎ目のない統合を会社に与えるであろう。
ERP5 により、量的な情報を追跡して管理の流れを実現することが出来る。ERP5の機能には、取引、請求、勘定、製造、補給チェイン、在庫、顧客関係及び製品設計が含まれる。
CPS により、ユーザのグループが多数のバージョンで文書を共有し、管理度と公表のワークフローを実現し、情報とサービスに協力するためアクセスの単一地点を作ることが出来る。
"GONUX" と言うフリーソフトウエア・システムを、フリーソフトウエアの宣伝と商業化が専門の組織Free Software Consortium, が7月1日に立ち上げた。
GONUX は、ブラジル、アルゼンチン、スペインの公共部門事務所で広く使われるプログラムの寄せ集めである。GNU/Linux OSとサーバ、オープンオフィス、e-メールとインスタント・メッセンジャ、カレンダ、データベース、ウェブバラウザ・アプリケーションその他のプログラムを含む。GONUXとは、サーバとクライアント側双方の世界公共部門事務所用共通フリー政府OSプラットホームの意味である。
GONUX の完全版を得るには gonux.fsc.cc を訪ねて登録されたい。
IO Anywhere Inc. が、第一世代製品のリリースを発表した。原価$200以下の器具開発を使命として発足したIO Anywhereは、多数のオンボードI/O、多重シリアルポートを持ち、ブラウザコンフィギュラブルで、超停電力消費、イーサネット有効で、各種のあらゆるデータ捕獲及び制御アプリケーションに容易に適合する必要があった。IO Anywhere器具は、古い装置と先端スタンドアローン装置双方の各種アレーに対し手頃なインターネット/インターネット接続性を提供する。CPLDにおける最新技術を使用しイーサネット有効マイクロプロセッサ・コアモジュールを統合して、広範囲のアプリケーションのため完全にコンフィギュラブルなプラットホームを生産する。
Debian Weekly News highlighted は、DebianをDell Inspiron 8000ネットワークにインストールする方法を述べたNori Heikkinenの howto document を重点にしている。これには、ビデオカード、外部マウスのためのコンフィギュレーション、及びブートCDからシステムを復元する方法が含まれる。これらに関する皆様のご意見、ご教示、改善案を歓迎している。
DWN にはまた、Adam Powellが Debian Beowulf resources 上の文書をDebian Wikiに移したとの情報もある。
IBM DeveloperWorksが creating Debian Linux packages.を案内している。
A Gentoo Linux fork に発表がある。Zach Welch がgentoo-devメールリストの中のGentoo Linux 仲間に、新プロジェクトをZynotと呼ぶと発表した。Linux Weekly News にこの発展の説明がありdiscussion of this development 、背景事情へのリンクもある。
MandrakeSoftの CEO François Bancilhon は、公開状An open letter でMandrakeの最近事情と、年初に11条保護を適用されて以来の進行を説明した。
Register は最近、小売り販売を中止し企業利益を重点とするとのRed Hatの決定を報告したThe Register recently reported 。
SCO は、ALXソフトウエアの使用又は複写に関するIBMの権利を停止し、IBMに対する苦情の改訂を申し入れたと発表した。IBMに対するUNIXシステムVソースコードのコピイ全部の廃棄又は返却の命令、及びALX販売の永久停止を含む。SCOグループは、自分を「ビジネス・ソフトウエア・ソリューションの先端プロバイダ」と称している。
SuSE Linux は、Linux エンタープライズ・サーバ 8 がOracle アプリケーション標準ベンチマーク (OASB)において、 Linux OS を走らせる32-又は64-ビットインテルベースのサーバいずれでも、ノンクラスタード環境で、最高の格付けを得たと発表した。 OASB に関するテストはOracle E-ビジネス・スーツ・バージョン 11.5.6 及びd Oracle-9i データベース・エンタープライズ版リリース 2でおこなった。ベンチマークは、IBM eServer xSeries x440 システム上で走らせた。Oracle アプリケーション標準ベンチマーク (OASB)の詳細は、 http://www.oracle.com/apps_benchmark/
SuSE Linux はまた、産業標準HP ProLiant サーバ及びHPのItaniumベースサーバ上でUnitedLinuxで動くSuSEエンタープライズ・サーバ 8 の再販とサポートを、HPがおこなうことも発表した。
SuSE Linux は、Cray Inc. により、カリフォルニア州 Sandia 国立研究所にあるRed Storm と言う米国エネルギ省の大量平行処理(MPP)スーパーコンピュータの重要部分を駆動するよう撰ばれたと発表した。これは、完成すると、米国最速のスーパーコンピュータとなる。Red Stormは、2004年中には稼働し、Red Stormの高帯域幅、低待ち時間内部切換アーキテクチャと相俟って高転送技術を特徴とするAMD Opteronプロセッサを使用する。Sandia 国立研究所Red Stormスーパーコンピュータは、米国核備蓄のコンピュータ・シミュレーションその他の用途に用いられる。
Kevin Scannell は、Linux/Unixなどの下で働くアイルランド語文法照合Irish Language grammar checker を書いた。これはKevinがispell とGaelspelのためのワードリストを作るのに用いたと同じデータベースの上で構築されており、GPL条項の下で頒布される。
IBM が、新しいLinuxベースサーバ・ソリューション、雇用員職場用IBM統合プラットホームエクスプレスを発表した。これは多忙な事務所環境の中規模企業の強化を目的とする。組織はこのソリューションを用いて、雇用員が事業情報及び協力的職場アプリケーションに全て単一ブラウザを通じてアクセスし、交信し、専用にして運用することが出来るようにして雇用員効率を改善する。
韓国の Softbank Uway が最近、45個のデータベースとウェブサーバを、HPとSunから単一の新IBM z990 "T-Rex" メインフレームに交換した。この会社は、IBMの z/VM仮想化技術を用いてz990上のパーティションで走るLinuxを動かし、それによりシステム管理を劇的に簡略化してソフトウエアコストを軽減する。
SIMPL open source project は v2.2.0をリリースしたばかりだ。元のSIMPLはCで書かれているが、数年の間にTcl/Tk, JAVA, C++を含む目覚ましい多数の言語拡張が加えられ、ここでPytohonが加わった。プロジェクトはこれで、SIMPLメッセージ作成がほぼ全言語で使えると主張する。SIMPLは、元々Linux上で走らせるため開発された。それ以来AIX とMac OSX.に移植された。ONXともインターフェイスする。
SIMPL は、常に、コードがネットワーク・メッセージ作成の詳細と絶縁されているよう設計されて来た。追加UDPを用いるTCP/IPソケット代替物、未加工イーサネット、及び未加工シリアル代替物が開発中である。 IO Anywhereボックスの最近のリリースを用いて、プロジェクトは「シリコン中のSIMPL」を完成し掛けているので、極めて有用なSIMPL有効器具が出来上がるであろう。
Mick はLGの「今月のニュース」 編集者だ。
数年前にアイルランドで生まれたMichaelは、現在ダブリン大学医療工学部で博士論文に取り組んでいる。論文の題名はLamb wavesの非破壊検査への利用だ。この研究に GNU/Linux が極めて有用であったので、 Michael は他の工学にフリーソフトウエア・ソリューションを適用することに強い興味を持った。論文が出来上がったら、 Michael は長い徒歩旅行にでる予定だ。
ソフトウエアを搭載するとき、多くの人が「/usr/sbinに入れるか /usr/localに入れるか /usr/local/packagename に入れるか」で迷う。おまけにソフトウエアを搭載する「一つの正しい方法」の迷信が迷いに輪を掛ける。これらの迷いを取り去り、納得の上で選択が出来るようにしたいと思う。
Filesystem Hierarchy Standard (FHS) は、UNIXファイルシステム又はディレクトリ階層の管理方法に関する良い参考書だ。残念ながら、多くの人は、その綱領に反して、これを基準又は指導書と思っている。FHSは Linux Standard Base (LSB)の一部で、Linuxディストリビューションの間の互換性を増し、ソフトウエア・アプリケーションが任意の基準合致システム上で走ることが出来るようにするため基準一式を普及させる。しかし、意識しようがしまいが、これらの基準は、ソフトウエア・パケージ維持者ではなく、Linuxディストリビューション・ベンダーが取り上げるものである。
例えばSamba.を取り上げる。Sambaの規定値搭載ディレクトリは/usr/local/sambaである。多くの人は、FHS違反であると文句を言うcomplain。これらの人に分かっていないのは、上で言った:FHSの採用はソフトウエア・パケージ維持者ではなくLinuxディストリビューション・ベンダーで奨励されているように思える、と言うことだ。何故かと、国際的か否かについては、幾分不確だ。だが、効果は自分の影におびえるようなものだ。人々は、最も重要になったことはのない事項にいことに文句を言っている。国際的であるか否かは、現在どうなっているかで、せいぜいで議論の余地はあるだけだ。
多くのソフトウエア・パケージに関する搭載位置は、伝統的に先例historical precedenceに習って来た。多くのソフトウエア維持者は、方法論や哲学からでなく、「何時もそうして来たから」だけで/usr/local/packagenameを主張して来た。良く調整されたソフトウエアの世界では、これは破られないとしても、固定されてはいない。
不賛成なのではない。先例は重要な側面だ。代わりに、FHSには、搭載ファイルとディレクトリの位置標準化standardizing the location of installed files and directoriesに向う優れた考えが幾つかある。しかし、これは単に、一致の奨励のない哲学に過ぎない。その哲学をソフトウエア・パケージ維持者にもLinuxディストリビューション・ベンダーにも重点を置いたり奨励することはない点で、FHSに対するインターネット社会からの反応は、ディストリビューション・ベンダーからの反応と思われる。実際これが問題の一部なのだ。.
インターネットであろうがなかろうが、FHS準拠への重点は、ソフトウエア開発者が置かなければならない。これで伝統的問題の幾つかは解決する。例えば:
個人的には、FHS準拠につき間違った角度から眺めていると思う。代わりの将来像はもっと良い筈だ:
来るべきFHSバージョン2.3のリリースでは、正しい問題に重点を置くことがもっと重要になる。インストール可能Linuxソフトウエアの世界における混乱を最小にするのに成功したとき、哲学や方法だけでなく正しいあいてにも焦点を当てなくて済む。この記事が、お手元の問題に気づく切っ掛けになれば幸い。
LFH準拠を維持しようとしているディストリビューションの幾つかは下記である:
David Lechnyr は、オレゴン大学の人的資源学部のネットワーク管理者である。彼は、社会福祉の修士号を MCSE+I, CNE, CCNA認証とともに持っている。過去7年間、Linuxのため、システム・セキュリティ、ネットワーク故障修理、PHP/MySQL統合に関して、働いて来た。 Unofficial Samba HOWTO 及び Linux+Apache+MySQL+PHP HOWTO. の著者でもある。
我々gnu/linux ユーザの多くが経験するのは、ログインして通常通りstartx とタイプしたとき、エラーメッセージだけを受け取ることがある。エラーメッセージの一つは通常/var/log/XFree86.0.logに記憶されている。このログファイルにアクセスすることが出来れば、ファイルの最終行が次のようになっているのに気付くだろう:
Could not init font path element unix/:7100, removing from list! Fatal server error: could not open default font 'fixed'
このメッセージを受け取った最初の数回は正直のところ驚いた。Linuxシステムの中間ユーザとして、モデモダイアルアップとlynxを用いるサーフィンにテキスト・コンソールを使うのは得意ではなかった。そこてで別のボックスの上で大変な時間を費やしウェブ上でヘルプを探すのにGoogle使和なければならなかった。私のような人が沢山いて、ウェブフォーラムとメールリストで答える人は、実際のヘルプでなく同情を寄せているのに驚いた。常識を使いある程度の研究をして、殆どの人がXフォントサーバ何かをすればこの不具合を解決することが出来ると見出す。
もう少し研究した後、この不具合は見掛け程難しいものではないと分かった。以下のステップを踏むと、殆どの場合、Xウインドウが働き始める。
注記: 以下の例は私の Red Hat ボックスでは働く。だが、別のディストリビューションにも十分通用すると思う。
1. X フォントサーバが走っているかをチェック
私のように、これはXフォントサーバの中のバグによると思う人もいるだろうが、Xフォントサーバは極めて頑丈なので成り立たない。/etc/init.d の下で xfs スクリプト走らせてフォントサーバが走っているかを見ることが出来る。
[root@localhost /root]# /etc/init.d/xfs status xfs (pid 1385) is running...
場合によっては、フォントサーバが死んでいるだけが不具合の理由であることがある。そのときは、以下のようにフォントサーバをスタートし直す:
[root@localhost /root]# /etc/init.d/xfs start Starting xfs: [ OK ]
さて、私の貴重な経験ではこの[OK]が与えられない。もう一度走っているかを確かめる必要がある。走っているときは、startxを試してXウインドウがスタートするかを見る。フォントサーバが走っているときでもそれでもXウインドウがスタートしないときは、問題は少し面倒だ。もう少し時間を掛けて以下のステップを読む必要がある:
注記: 奇妙な事例として、私のルート・パーティションが2GB以上の巨大なログファイルで完全に占められたことがある。フォントサーバは /tmpに書き込めないとき死ぬので、簡単な解決策は巨大なファイルを見付けて削除することだった。
2. フォント 'fixed' にアクセス可能かをチェック
フォント 'fixed' にアクセス可能かチェックする時期は今だ。先ず、コマンドfslsfontsを使ってサーチ・パスの中に 'fixed' があるか否かを見る:
[root@localhost alex]# fslsfonts -server unix/:7100 -ll -fn fixed DIR MIN MAX EXIST DFLT ASC DESC NAME --> 0 255 some 0 11 2 fixed FONTNAME_REGISTRY FOUNDRY Misc FAMILY_NAME Fixed WEIGHT_NAME Medium SLANT R SETWIDTH_NAME SemiCondensed ADD_STYLE_NAME PIXEL_SIZE 13 POINT_SIZE 120 RESOLUTION_X 75 RESOLUTION_Y 75 SPACING C AVERAGE_WIDTH 60 CHARSET_REGISTRY ISO8859 CHARSET_ENCODING 1 COPYRIGHT Public domain font. Share and enjoy. CAP_HEIGHT 9 X_HEIGHT 6 FONT -Misc-Fixed-Medium-R-SemiCondensed--13-120-75-75-C-60-ISO8859-1 WEIGHT 10 RESOLUTION 103 QUAD_WIDTH 6
これは 'fixed' が利用出来るときの正常出力である。ここで 'fixed' が実際はフォント '-Misc-Fixed-Medium-R-SemiCondensed--13-120-75-75-C-60-ISO8859-1' の別名であることが分かる。フォント'fixed' がないときは、先ずフォントのためのサーチ・パスに関する知識を得る必要がある。これらのパスを見るには chkfontpath コマンドを使うことが出来る:
[root@localhost alex]# /usr/sbin/chkfontpath Current directories in font path: 1: /usr/X11R6/lib/X11/fonts/misc:unscaled 2: /usr/X11R6/lib/X11/fonts/75dpi:unscaled 3: /usr/X11R6/lib/X11/fonts/100dpi:unscaled 4: /usr/X11R6/lib/X11/fonts/misc 5: /usr/X11R6/lib/X11/fonts/Type1 6: /usr/X11R6/lib/X11/fonts/Speedo 7: /usr/X11R6/lib/X11/fonts/CID 8: /usr/X11R6/lib/X11/fonts/75dpi 9: /usr/X11R6/lib/X11/fonts/100dpi 10: /usr/share/fonts/default/Type1 11: /usr/share/fonts/default/TrueType 12: /usr/share/fonts/ja/TrueType 13: /usr/X11R6/lib/X11/fonts/latin2/100dpi:unscaled 14: /usr/X11R6/lib/X11/fonts/latin2/100dpi 15: /usr/share/fonts/ISO8859-7/misc:unscaled 16: /usr/share/fonts/ISO8859-7/75dpi:unscaled 17: /usr/share/fonts/ISO8859-7/100dpi:unscaled 18: /usr/share/fonts/ISO8859-7/misc 19: /usr/share/fonts/ISO8859-7/Type1 20: /usr/share/fonts/ISO8859-7/75dpi 21: /usr/share/fonts/ISO8859-7/100dpi 22: /usr/share/fonts/ISO8859-9/misc:unscaled 23: /usr/share/fonts/ISO8859-9/100dpi:unscaled 24: /usr/share/fonts/ISO8859-9/misc 25: /usr/share/fonts/ISO8859-9/100dpi 26: /usr/share/fonts/KOI8-R/100dpi:unscaled 27: /usr/share/fonts/KOI8-R/100dpi 28: /usr/share/fonts/zh_CN/TrueType 29: /usr/share/fonts/zh_TW/TrueType 30: /usr/share/AbiSuite/fonts
これらは、私のボックス上のフォント・バスだ。これは、xfs がこれらのパスを覗いて、必要なとき特定のフォントと探すことを示す。二つの型の重要なファイルがある。これらパスのfonts.dir と幾つかのパスのfonts.aliasだ。例えば、 /usr/X11R6/lib/X11/fonts/100dpiに行って、ファイルを開くとする。ファイルは次のように見える:
[fonts.dir] 775 UTI___14.pcf.gz -adobe-utopia-regular-i-normal--19-140-100-100-p-104-iso10646-1 UTBI__14.pcf.gz -adobe-utopia-bold-i-normal--19-140-100-100-p-109-iso10646-1 UTI___12.pcf.gz -adobe-utopia-regular-i-normal--17-120-100-100-p-89-iso10646-1 UTI___24.pcf.gz -adobe-utopia-regular-i-normal--33-240-100-100-p-179-iso10646-1 courO08.pcf.gz -adobe-courier-medium-o-normal--11-80-100-100-m-60-iso10646-1 UTBI__12.pcf.gz -adobe-utopia-bold-i-normal--17-120-100-100-p-93-iso10646-1 ...
最初の行が、現在ディレクトリの中のフォントの数を規定する。続く行は、ファイル名をフォント名に対してマップする。
[fonts.alias] lucidasans-bolditalic-8 -b&h-lucida-bold-i-normal-sans-11-80-100-100-p-69-iso8859-1 lucidasans-bolditalic-10 -b&h-lucida-bold-i-normal-sans-14-100-100-100-p-90-iso8859-1 lucidasans-bolditalic-12 -b&h-lucida-bold-i-normal-sans-17-120-100-100-p-108-iso8859-1 lucidasans-bolditalic-14 -b&h-lucida-bold-i-normal-sans-20-140-100-100-p-127-iso8859-1 lucidasans-bolditalic-18 -b&h-lucida-bold-i-normal-sans-25-180-100-100-p-159-iso8859-1 lucidasans-bolditalic-24 -b&h-lucida-bold-i-normal-sans-34-240-100-100-p-215-iso8859-1 ...
このファイルは、font aliasをフォント名に対してマップする。だから、フォント 'fixed' が必要になると、フォントサーバが各フォント・パスについて一致するfonts.aliasを検索することは明らかだ。一致が存在しないときは、希な場合だが、Xサーバがスタートすることが出来ないのでフォントリストを構築し直さなければならない。再構築処理は新しいfonts.dirとfonts.alias ファイルをを作る。
3. フォントリストの再構築
フォントリストは、/etc/init.dの下でfile xfs スクリプトを使って構築し直すことが出来る。以下はそのスクリプトの抜粋である:
...
buildfontlist() {
pushd . &> /dev/null
for d in $(/usr/sbin/chkfontpath --list | cut -f 2 -d ':') ;do
if [ -d "$d" ]; then
cd $d
# Check if we need to rerun mkfontdir
NEEDED=no
if ! [ -e fonts.dir ]; then
NEEDED=yes
elif [ "$(find . -type f -cnewer fonts.dir 2>/dev/null)" != "" ];then
NEEDED=yes
fi
if [ "$NEEDED" = "yes" ]; then
...
}
...
start() {
if [ -L /usr/X11R6/bin/X ]; then
echo -n $"Starting $prog: "
[ -x /usr/sbin/chkfontpath ] && buildfontlist
rm -fr /tmp/.font-unix
daemon xfs -droppriv -daemon
ret=$?
[ $ret -eq 0 ] && touch /var/lock/subsys/xfs
echo
return $ret
fi
}
...
シェルプログラム作成に慣れていない読者のため解説すると、この抜粋は、xfs スクリプト走らせる度に、fonts.dirがあるか否かを記載されたフォントパス毎にチェックすることを意味する。パスにfonts.dirがないときは、フォントリストを構築し直す必要がある。各パスにfonts.dirが存在するときは、フォントディレクトリの中のファイルのどれかの状態がfonts.dirの最終変更の後変更されたかどうかをチャックする。その通りであれば、フォントリストを構築し直す必要がある。
シェルプログラム作成を勉強する気のない人のため解説すると、サブルーチンbuildfontlist()の中に一寸した仕掛けをした。最初の例で "NEEDED=yes" と設定してフォントリストを構築し直させることが出来る:
4. フォントは本当になくなったのか?
上のステップ全部が失敗したときは、最後の提案は、何かの処理でフォントファイルが本当に削除されていないかをチェックすることだ。そうであれば、フォントをインストールし直す必要がある。
著者紹介:
Yufei はアルバータ大学の大学院生だ。仕事と遊びに GNU/linux を使っている。自分の研究計画のため GNU/linux 上で映像とビデオの圧縮アルゴリズムを開発している。彼のRH9 box@home には Conexant HSF winmodem があり、これがウェブブラウズと流れる音楽の聴取に上手く働く。
「たった一つのサービスを働かせるだけで完全に修復され、規定値で拒否するファイアウォールになる}
「 Ctrl-Alt-Delete を押すと何が起こるのか ? 」
コンピュータ・セキュリティの基本的前提の一つは、アタッカが物理的アクセスを持つ限り、どのマシンも、完全に安全にするのは殆ど不可能だということである。すべての偶然性を網羅することは出来ないけれども、簡単な変更で大通りの露骨な不正使用を捕まえることが出来る。この記事では、無権限の人間が平気で君のマシンをブートし直すのを止める方法を述べる。
Linuxマシンに接続されたキイボードに触る人は誰でも、Control-Alt-Deleteを押せば、ユーザ名やパスワードを入力することなくマシンをブートし直すことが出来る。Windowsマシンでも、有効なログイン(現在ユーザ又は管理者優先権のいずれか)が必要だが、画面がロックしたとき同じことが出来る。これは悪意の問題ではなく、Windows NT 又は Windows 2000に慣れた人に取り、X-Windows活動のときControl-Alt-Deleteを使って、ワークステーションをロックして画面を示そうとするか、又は代わりにタスクマネージャを開いて嫌な「再起動のためシステムをシャットダウンします。データはすべて失われます」とのメッセージを受け取るのは、珍しいことではない。
多くのLinuxディストリビューションで、Control-Alt-Delete の組合せ(ctrl-alt-del 又は「三本指の敬礼」と云うことが多い)は、マシンのブートし直しのため予めコンフィギュアされている。これは家庭用単一ユーザデスクトップには受け入れられるが、実行に認証を必要とするとの重要な事実のため、事務所ワークステーション又はサーバーには不必要な危険である。.
この破壊的行動を防止するため、Control-Alt-Deleteを捕らえて、自分自身のスクリプトで置き換えることにより、この「特性」を無効にする。また、ブートし直しの試みすべてを捕らえて記録するため、監査を付け加える。これをおこなうには、システムに簡単なシェルスクリプトを追加し、 自分自身のハンドラを呼び出すよう'/etc/inittab' コンフィギュレーション・ファイルを変更し、少々のログ・ローテーションを加えてあらゆる事柄を整理する。
実際の仕事の殆どをおこなうシェルスクリプトを 'audit_cad.sh' と呼び、ここhereにある。これは、二つの方法で呼び出すことが出来る。第一の方法は、'-c'アーギュメントを付けて呼び出すこと。このモードで、スクリプトはその外部依存関係全部が存在し実行可能であることをチェックする。これは、システムが前提条件全部を満たしているのを確かめる最良の方法である。
テストのいずれかに失敗したときは、疑わしいバイナリの名称を含むエラーがプリントされ、スクリプトはチェックを全部終わるまで続ける。チェックのいずれかに失敗したときは、スクリプトが実行を完了したとき、 '1' のコードが戻される。依存する外部バイナリは次の通りである:
これらのうち唯一人手編集を必要とするのは basename で、これは'/usr/bin' と'/bin' ディレクトリの間で変動することが多い。一般的に、最初にインストールして、正しく走り脱落がないことことを確認するとき、スクリプトはチェック・モードで走らせる。このスクリプトはルートとして走るので、パーミッションがファイルに何かのアクセスを持つスーパーユーザだけに可能なほど厳重であることを確認するのは良い考えだ。理想的には -rwx------に設定する。これはコマンド'chmod 0700 audit_cad.sh'を用いておこなう。
第二の方法は、アーギュメント無しで走らせることで、この方法で走らせたとき、これは'syslog' (ユーザ規定ファシリティとレベルを持つ)と外部ファイルの双方に対するエントリを記録する。これは'/var/log/shutattempt'を規定値とする。Control-Alt-Deleteを監査するてめ実行する方法を示す。
この記事の目的のため、スクリプトを 'audit_cad.sh'と呼び '/usr/local/sbin/'に置く。これら双方又はいずれかの設定を変更するには、選択したエディタでスクリプトを開いてスクロールする。コンフィギュレーション・オプション全部はコメントしてある。
これでスクリプトが正しい場所に入ったので、'/etc/inittab'の中のControl-Alt-Deleteに関する規定値ハンドラをエディットする。その行にControl-Alt-Deleteイベントに聞き耳を立て、受け取ったとき特定のコマンドを実行するよう命令するため 'init' を命令する。ほとんどのディストリビューションにおいて、id は 'ca' で実際のエントリは"ca:12345:ctrlaltdel:/sbin/shutdown -t1 -a -r now" のようになる。この行の重要部分は'/sbin/shutdown'で始まる最後のフィールドで、システム動作を変更するため現在のコマンドをエディットして我々の'audit_cad.sh' スクリプトに対しポイントする。例の通りにしたがっているときは、完全パスは'/usr/local/sbin/audit_cad.sh'となる。
この変更をしたら、'init' プロセスに、'inittab' が変更されたことを告げる必要がある。これをする最も容易なほうほうは、'telinit q' を走らせることで、これにより再起動することなく 'init' がコンフィギュレーション・ファイルを読み取り始める。
これで、変更をテストする場所に差し掛かった。その前に、GUIや編集作業などシステムに不可欠でないものすべてを閉じることを勧める。例通りにし損ねていると、システムは再ブート寸前なので、著者に文句を言うより安全だ。用意が出来たらCtrl-Alt-Deleteを押すと、何も起こらない筈だ。
この時点でシステムが未だ立ち上がっているときは、'audit_cad.sh' で定義したsyslogファイル(一般的にこれは '/var/log/messages' 又は '/var/log/syslog'である)と外部ログファイルの両方をチェックして、ロギングが成功しているかを確かめる。システムがブートし直されたら、ステップ毎にチェックしてやり直す。
これが働いたら、最終作業として何か自動処理を追加する。これは、'SWATCH' 又は'logwatch'の設定からログローテーションを加える自動警報を与えててファイルサイズを低くするまで変化することが出来る。 'logrotate' がマシン上で働いているときの簡単な例(最近のRedhat とDebian双方に合う)を下と、ここ hereに示す。
dailyrotate 7compressdelaycompress/var/log/shutattempt {nomailnotifemptymissingokcreate 0600 root root}
これを'logrotate' の処理リストに加えるには、audit_cad と云うファイルを自分の 'logrotate' ディレクトリに追加する。これは、上の切れ端又は同様のものと一緒に'/etc/logrotate.d'にあることが多いので、ディスクスペースを心配する必要はない。
この技術は、マシンを再ブートする試みを上手く記録するが、覚えた方が良いことが幾つかある。第一は説明責任だ。このスクリプトだけを使って、誰が実際にマシンを乗っ取ろうとしたか判定することは出来ない。記録のため認証情報を利用することが出来ないからだ。実際にCtrl-Alt-Deleteを扱うプログラム'init'は、ルートとして走るので、呼出ユーザ名を捕らえようとするといつでも 'root' に戻る。
'audit_cad.sh' に一寸した変更をすることにより、ログに対する w 又は who の出力を捕らえることは出来るが、この情報はこの状況下で考えられるほど有用ではない。これらコマンドはログオンの資格認定を与えた有効ユーザを追跡するだけだ。これは、誰かがキイボードに触れてControl-Alt-Deleteを押しただけのときは、与える必要がないので、実際にした人は記録されない人になる。
第二の点は、このスクリプトを明瞭にする方法を考えることだ。狡くてその存在を目立たせたくないなら、これを 'shutdown'と呼んで標準でない位置にセーブすることが出来る。
'inittab' のフォーマットと目的に関する詳細情報については 'man 5 inittab' を、オプション 'telinit' サポートの完全なリストについては 'man 8 telnint'を見られたい。'logrotate' に慣れていなければ 'man 8 logrotate' から始めると良い。
著者紹介:
Dean Wilson は (今週) www.unixdaemon.net にある彼のペイジのシステム管理者兼臨時更新者である。
この文書の主目的は、e-Directoryを通じるLinux認証の設定をおこなうのに必要なステップを説明することである。
Novell e-Directory は、X-500ベース・ディレクトリに対するアクセス・プロトコルの新しい実現である。このプロトコルの別の実現は LDAP, Lightweight Directory Access Protocolとして知られている。 LDAP は RFC2251 "The Lightweight Directory Access Protocol (v3)".の中で定義されている。
ディレクトリはデータベースに似ているが、記述的なアトリビュートに基づく情報をもっと多く含む傾向がある。ディレクトリの中の情報は、一般的に書き込まれるより読み取られる方が多い。ディレクトリは、大容量の検索操作に対し迅速な応答をするよう調整されている。これらは、応答時間を短くしながら利用性と信頼性を増すため、情報を広く複製する能力を有する。ディレクトリ情報が複製されたとき、複製品の間の不一致は、結局同期される限り、構わない。
以下は、Novell e-Directoryを通じるLinux認証とアカウント情報取出の設定に対するクイック・スタートの案内である。
認証プロシージャ設定に必要な基本的ステップを通覧する積もりである。これは、この文書の別の章、マニュアル、規定値ディストリビューションに付いてくるその他の資料と一緒に使わなければならない。
Novell e-Directoryを通じる認証を用いて真剣に作業する積もりであれば、ソフトウエア設定の前に、この文書全体を読まなければならない。
Novell e-Directory認証 を設定するには次のステップを実行しなければならない:
先ず、ldap.conf ファイルを設定しなければならない、これは通常/etc ディレクトリに置かれている。これを見て見よう:
# 自分の Novell e-Directory サーバ IP アドレス
server 192.168.0.1
# base context
base ou=london,o=acme
# 特殊ユーザ、これは NDS ツリー・ブラウズのみに使用し
# 適切な権利を有する
binddn cn=ndsbrowser,ou=london,o=acme
# ユーザのパスワード
bindpw ndspass
# ssl 暗号化を有効にする
ssl yes
# パスワード・モード NDS pam_password nds
# 特殊アトリビュート・マッピング
nss_map_attribute userPassword authPassword
# NDS サーチ・スコープ
scope sub
ここでコンフィギュレーションを PAM (pluggable authentication modules) システム用に変更しなければならない。そのため、RedHat 7.3 ではファイル /etc/pam.d/system-auth. を変更する、以下のように進む:
#%PAM-1.0
auth required /lib/security/pam_env.so
auth sufficient /lib/security/pam_unix.so likeauth nullok
auth sufficient /lib/security/pam_ldap.so try_first_pass
auth required /lib/security/pam_deny.so
account sufficient /lib/security/pam_unix.so
account [default=bad success=ok user_unknown=ignore service_err=ignore system_err=ignore] /lib/security/pam_ldap.so
password required /lib/security/pam_cracklib.so retry=3 type=
password sufficient /lib/security/pam_unix.so nullok use_authtok md5 shadow
password sufficient /lib/security/pam_ldap.so use_authtok
password required /lib/security/pam_deny.so
session required /lib/security/pam_limits.so
session required /lib/security/pam_unix.so
session required /lib/security/pam_mkhomedir.so skel=/etc/skel/ umask=0077
session optional /lib/security/pam_ldap.so
これでパスワード認証を設定した。次の作業に進もう。
ここで、Novell e-DirectoryからLinuxアカウントデータ取出を設定しなければならない。そのため、/etc/nsswitch.confをエディットする。"passwd:", "shadow:" , "group:" から始まる行に語 "ldap"が含まれているかをチェックするだけだ。なければ−−追加しなければならない。私のPCでは次のように見える:
# ローカルファイル次いで ldap でパスワードを探す
passwd: files ldap
# ローカルファイル次いで ldap で shadow を探す
shadow: files ldap
# ローカルファイル次いで ldap で group を探す
group: files ldap
Linuxボックス上で実行する最後のステップは、Novellサーバへの確実な接続を設定することだ。これをおこなうには、ファイル RootCert.der をNovellサーバの SYSボリュームからダウンロードして、certディレクトリ /usr/share/ssl/certs にセーブする。次のコマンドを用いてNovellをルート・サーティフィケートに転換する:
openssl x509 -in /usr/share/ssl/certs/RootCert.der -inform DER -out \
/usr/share/ssl/certs/RootCert.pem -outform PEM
openssl.cnf (RedHat 7.3 では /usr/share/ssl ディレクトリにある) ファイルの中に "value certificate" を設定して RootCert.pem (サーティフィケートはCA サーティフィケートである)にポイントすると、"my private key" が同じサーティフィケートになる。
Linux上の仕事は終わった。Novell サーバに切り換える時期だ。しなければならないことが幾つかある。これからすることは全てConsoleOneツールを通じておこなう。
先ず、NDS <–> LDAP マッピングスキムを変更しなければならない。それをするには、ベースコンテキストを開いて"LDAP Group" 項目を見出す。このオブジェクトのプロパーティを開く。"General" タブで、"Allow Clear Text Passwords"ボックスをチェックする(これはテストが目的)。
ここで "Attribute Map" タブを開く。tab. Click "Add" ボタンをクリックして次のマッピングを追加する:
|
|
|
"LDAP Group" プロバーティ・ダイアログを閉じる.
第二のステップは、ユーザアカウントを正しく設定することだ。そのため、適切なユーザ上で右クリックしてプロパーティを選ぶ。"UNIX Profile" タブを開いて、アカウントデータを入力する:
短く凡例を示す:
ここでは、Novell e-Directory経由のLinux認証の背景に深入りする。これは主として二つの論理部分から構成される。パスワード認証とアカウントデータ取出だ。この処理を理解するとLinuxディストリビューションに記述されていない他の認証を設定することが出来る。
ldap 経由のパスワード認証は、pam_ldap モジュールを用いて実行される。ldap 経由のパスワード認証を組織するのであれば、これをインストールしなければならない。RedHat Linux 7.3用には、ディストリビューションの中の nss_ldap RPM を利用することが出来る。これには、パスワード認証、したがってLinuxアカウントデータ取出に必要なツール、モジュール、ライブラリ全部が含まれている。
LDAP認証に必要なソフトウエアは、オーストラリア、メルボルン市のPADLソフトウエア会社が維持する公開ドメイン・ソフトウエアである。会社は、自分のソフトウエアのユーザが互いにサポートし合えるように、三つのインターネット・メールリスト、nssldap@padl.com, pamldap@padl.com, ldap-nis@padl.comを走らせている。これら三つのメールリストのどれかに加入したければ、メッセージ本文に"subscribe listname" を入れて、majordomo@padl .comにe-メールされたい。
pam_ldap モジュールと libnss_ldap ライブラリのためLDAP-固有情報をコンフィギュアするにはldap.confファイルを用いる。以下のリストは、Novell e-Directory サーバを用いるSSL暗号化通信を作るのにこのファイルに必要な最低レコードを示す:
host <ip アドレス又は eDirectory サーバのホスト名>
base < eDirectory内の情報検索を始めるコンテナ>
scope sub - サブツリー検索を規定
ssl on - tSSL 転送暗号化をオンにする
匿名結合の状況では入手出来ない幾つかのユーザ情報に対するアクセスのため、ユーザ情報を回収するとき個別ユーザとして認証する必要がある。そのため、以下のパラメータを設定しなければならない:
binddn <認証すべきユーザオブジェクトの完全 LDAP DN >
bindpw <上記ユーザのパスワード>
以下のリストは ldap.conf ファイルの例を示す:
server 192.168.0.1
base ou=london,o=acme
binddn cn=ndsbrowser,ou=london,o=acme
bindpw ndspass
ssl yes
pam_password nds
nss_map_attribute userPassword authPassword
scope sub
特殊ファイルのエディットによりPAMがコンフィギュアされる。RedHat Linux 7.3では、 /etc/pam.d ディレクトリにあるsystem-auth と云うファイルをエディットする必要がある。このファイルへの記入が、認証に用いられる認証システム(在来のUNIX 認証、LDAP、スマートカード、など) を定義する。モジュールを積み重ねることが出来る。モジュールの積み重ね方と構成の仕方方によって、多重サービスを使うことが出来る。
コンフィギュレーション・ファイルへの記入毎に必須フィールド三つと任意選択フィールドがある。
Linux-PAM は、認証の仕事を、アカウント管理、認証管理、パスワード管理、セッション管理の、四つの独立の管理グループに分離する。
置くだけて、これらのグループが一般的ユーザの限定的サービスに関する要求の各種側面を処理する:
アカウント - サービスのアカウント検証型を与える:ユーザパスワードは有効か?:このユーザは要求サービスへのアクセスを許されているか?
認証 - ユーザが自分の主張する者であることを確証する。一般的にこれは、ユーザが質疑応答に合格することでおこなう。パスワードを入れて下さい。認証全部がこの型ではない。適切なモジュールを用いるハードウエア・ベースの認証計画もある(スマートカード、生体測定など)。これらは認証のためのもっと標準的な方法で支障なく置き換えることが出来る−これがLinux-PAMの融通性。
パスワード - このグループの担当は認証機構の更新だ。一般的に、このようなサービスは認証グループと密接につながっている。認証機構のあるものは、この機能を用いる更新に力を貸す。標準UN*X パスワード・ベースのアクセスは明白な例だ:代わりのパスワードを入れて下さい。
セッション - このグループの仕事には、サービス提供の前及び撤回の後におこなう事が含まれる。このような仕事には、監査記録の維持及びユーザのホームディレクトリ取付が含まれる。セッション管理グループは、モジュールの開放と閉鎖のフックを提供してユーザが利用出来るサービスに影響するので、重要である。
Linux-PAM が優先権付与アプリケーションの開始を知ったとき、そのアタッチメントをPAM-APIに対して起動する。この起動は多数の課題を実行する。最も重要なのは、コンフィギュレーション・ファイル /etc/pam.confの読み取りだ。代わりに、/etc/pam.d/ ディレクトリの内容になる。
これらのファイルは、このサービスに必要な認証作業をおこなうPAMと、個別PAMが失敗した場合のPAM-APIの適切な行動を記載する。
/etc/pam.conf コンフィギュレーション・ファイルの構文は次の通りである。ファイルはルールのリストから作られており、各リストは一般的に1行に書かれるが `\<LF>' を使って拡張することも出来る。コメントは、前に `#' マークを付けて行末まで伸びる。
各ルールの書式は、トークンを空白で分離した集まりで、最初の三文字は大文字小文字の区別をしない。
サービス型コントロール モジュール・パス モジュール・アーギュメント
/etc/pam.d/ ディレクトリに含まれるファイルの構文は、同様であるがサービス・フィールドがない。この場合、サービスは /etc/pam.d/ ディレクトリの中のファイル名である。このファイル名は小文字でなければならない。.
Linux-PAMの重要な特徴は、与えられた認証作業に関し、多数のルールを積み上げて多数のPAMのサービスを結合することである。
サービスは、一般的に対応するアプリケーションの良く知られた名称である。login やsuが良い例だ。サービス名otherは、規定値ルールを与えるため保留してある。現在サービスを述べる行(それがなければ、別のエントリ)だけが、与えられたサービス−アプリケーションに結び付けられる。
型は、ルールが対応する管理グループである。これは、続くモジュールをどの管理グループに結合するかを規定するため使われる。有効なエントリは、アカウント、認証、パスワード、セッションである。これら各トークンの意味は上述した。
第三フィールド、コントロールは、モジュールがその認証作業の継承に成功しなかったときのPAM-APIの行動を示す。このコントロール・フィールドに関しては二つの型の構文がある。簡単なものは単一の簡単なキイワードを有し、もっと複雑なものは、値=動作対の角括弧選択をおこなう。
単純(歴史的)構文に有効なコントロール値は、必須要件−当該PAMの失敗が認証処理の即時終了を生じる、必要要件−当該PAMの失敗が結局PAM-API戻り不具合を生じるが、残りの(このサービスと型のための)積み重ねモジュールが呼び出された後だけてある、十分要件−当該モジュールの成功(先行要求モジュールが失敗したとき、このものの成功は無視される)がモジュール積み重ねの認証要件を満足する、任意選択要件−このモジュールの成功又は失敗は、このサービス+型と結合する積み重ねの中の唯一のモジュールであるときのみ重要。
もっと複雑な構文に有効なコントロール値は、次の形式を有する:
[値1=動作値2=動作2...]
ここで、値N は、行が定義されているモジュールで呼び出されたファンクションから戻されるコードに相当する。PAMエラーの完全リストは、/usr/include/security/_pam_types.h で入手することが出来る。詳細は自分のローカル・システム文書を参照のこと。
module-path - これは、アプリケーションが使用するPAMの完全ファイル名( '/' で始まる)又は、規定値モジュール位置 /lib/security/ からの相対パス名である。
module-arguments - これらは、与えられたPAMの固有行動を修正するのに使うことの出来るトークンの空白で分離されたリストである。
以下のリストは、Red Hat Linux 7.3における全サービスに関するNDS認証を設定するpam.confファイルのサンプルを示す。このディストリビューションの中のファイル "system-auth" は、サービスモジュール毎に含まれる。示した例は、LDAP経由の認証を与えると同時に、LDPA認証に失敗したときは在来のUNIX認証も与える。このファイルはまた、アカウント承認とパスワードを含むよう設定されている。
このファイルはまた、LDPA経由アカウント承認とパスワード管理も設定するので、LDAPモジュールが失敗すると、失敗する。
#%PAM-1.0
auth required /lib/security/pam_env.so
auth sufficient /lib/security/pam_unix.so likeauth nullok
auth sufficient /lib/security/pam_ldap.so try_first_pass
auth required /lib/security/pam_deny.so
account sufficient /lib/security/pam_unix.so
account [default=bad success=ok user_unknown=ignore service_err=ignore system_err=ignore] /lib/security/pam_ldap.so
password required /lib/security/pam_cracklib.so retry=3 type=
password sufficient /lib/security/pam_unix.so nullok use_authtok md5 shadow
password sufficient /lib/security/pam_ldap.so use_authtok
password required /lib/security/pam_deny.so
session required /lib/security/pam_limits.so
session required /lib/security/pam_unix.so
session required /lib/security/pam_mkhomedir.so skel=/etc/skel/ umask=0077
session optional /lib/security/pam_ldap.so
nsswitch.conf ファイルのサンプルを下記に記載する:
passwd: files ldap
shadow: files ldap
group: files ldap
SSL セキュリティを設定するためには、LinuxシステムにLDAP server's Trusted Root certificateのコピイがなければならない。そこで、自分のNovellサーバのSYS: ボリュームからcerts ディレクトリ /usr/share/ssl/certs に RootCert.der ファイルをダウンロードしなければならない。次いで、コマンド
openssl x509 -in /usr/share/ssl/certs/RootCert.der -inform DER -out \
/usr/share/ssl/certs/RootCert.pem -outform PEM
を用いてNovell root certificateを転換する必要がある。
転換の後、 value certificate を設定して openssl.cnf (RedHat Linux 7.3 では /usr/share/ssl にある)の中の RootCert.pem (証明書は CA 証明書) に対しポイントする。また、my private key が同じ証明書になるよう設定する。
認証に関する闘いの最終ステップは、Novell e-Directoryサーバの設定だ。NDS <–> LDAP マッピング・スキムに幾つかのアトリビュートを追加しなければならない。そのため、ConsoleOne でベース・コンテキスト開き、"LDAP Group" 項目を見出し、マウスで右クリックして"Properties..."を選ぶ。
ここで "Attribute Map" タブを開く。 "uidNumber", "gidNumber" と云う名のLDAPアトリビュートを見出して削除する。壊れたマッピングだからだ。代わりに新しいマッピングを作る。それには "Add" ボタンをクリックして次のマッピングを追加する:
|
|
|
一番最期に、各ユーザの "UNIX Profile" タブに適切な値を入力しなければならない。その後自分のNovell資格認定でLinuxボックスにログインすることが出来る。
幾つか注意しておきたい。第一に、私の調査には、サーバとしてe-Directory 8.6.0 の付いたNovell Netware 6 と、クライアントとしてRedHat 7.3 linuxボックスを使った。ソフトウエアのバージョンが異なる(新しい)と、少し変更すれば働く筈だ。私の知る限りe-Directory 8.6.2以降では、アトリビュート・マッピングに関する問題は解決しているので、該当する部分は省略して構わない。次に、残念ながら完全に安全な認証を設定することは出来なかった。少なくとも私にはその方法が分からない。これは、NDSツリーをブラウズする権利のある特殊ユーザに関係している。ファイル /etc/ldap.conf は全ユーザのため +r を持たなければならない。だから、Linuxボックスにアクセスする権利を持つ者は誰でも、そのパスワードを見ることが出来る。これは、読み取りの権利を与えている間は本当の問題ではない。だが、コマンド行からset/change passwordsを直接使いたいときは、特殊ユーザに書き込みの権利を与えなければならない。ここにセキュリティの穴がある。このような状態をなくするヒントがあれば、私にメールされたい。最後に重要なこと、ここで述べた製品と会社の名は、それぞれの所有者の商標である。
著者紹介:
私は、N-iX Team of Newcomp Computersysteme GmbH で、上級ネットワーク管理者として働いている。現在、Linuxと他のネットワーク・サーバとの通信及び沢山のLinuxサーバのサポートを研究している。余暇にはRussian Linux Gazette projectに参加している。これは、LinuxGazette の公式ロシア語ミラー だ。
この物語は、金曜日の昼食時、日光の下で仕事に戻ろうとぶらぶらしていた時、ユーザからの電話で始まった。話は次のように進んだ。
「今日は、ACMEアプリケーションのためデータベースを見るとき、少し問題があるような気がします。見て頂けますか?」
「勿論、10分でデスクに戻るので、戻り次第電話しよう。そのサーバ上のものは全部ミラーされるので、一番可能性があるのは、アーカイブログがセカンダリ記憶に動かされていないことだ。数分で解決するよ」
そして数分後「数分じゃ駄目だ。数時間掛かりそうだ。ミラーの両側で無くなったディスクがあるようだ」
何を間違ったのだ?ミラー片は別々のコントローラに付属する別々のディスク上にある。大きい電力スパイクや地震はなかった。夜間清掃人がプラグを引き抜いたと文句も言えない。
答えは、両側を同時に無くしたのではないことだ。実際は片側を1週間早く無くしていた。私の会社には、こんな出来事を検出するため優れた監視警報システムがあるが、このサーバが「建設」状態から「生産」状態に移行したのを警備員に通知するのを忘れていた。こんなことを繰り返してはいけない。
数週間前、自宅のワークステーションで、その第二ディスクが半年で故障したのを経験した。勿論保証期間でディスクは交換した。だが、このとき、何も彼も追加ディスクにミラーしようと決心した。
そこで考え始めた。「一つのディスク上のパーティションがオフラインになったのを、どうして知るか?」私の自宅ワークステーションを会社の警報システムにぶら下げる訳には行かない。
誰かが言った「メッセージ・ファイルをチェックしろ、'root' emailを読んだらどうだ?」偉大な理論家だ。問題は、メッセージを先送りノートと考えているパートナがおり、eメールをホットメールと思っていることだ。それで、私が外にいるときは、彼女が私のマシンのユーザになる。
解決策はここで、10秒毎に1秒間隔でScroll-Lockライトを光らせる機構に発展した。パーティションがミラーされなくなったら、ライトは点いたままになる。余計なハードウエ
ア要らない。馬鹿馬鹿しいほど分かり易い。ここにいるのは簡単な番犬で、これが定期的に未だ生きていることを示し、何かが悪くなると吠え続ける。
では、どうやってScroll-Lock ライトを光らせるか? Xwindowsを使っているのであれば、簡単だ。'xset led 3' が点灯し 'xset -led 3' が消灯する。screen-lockを走らせても、モニターの電源を切っても、ログオンしている限り、働く。
誰もログオンしていないか、 Xwindowsを使っていないときは、働こうとしない。その場合は、何か「ブリンカ」プログラムのようなものをインストールする必要がある。これは、 the node.to website.で入手することの出来る "morse2led" 一式の一部としてやって来る。
壊れたミラーを有するマシン上で 'cat /proc/mdstat' に入った時、見られるものを示す:
Personalities : [raid1]
read_ahead 1024 sectors
md2 : active raid1 hda6[0] hdb6[1](F)
1959808 blocks [2/1] [U_]
md1 : active raid1 hda5[0] hdb5[1]
5863616 blocks [2/2] [UU]
md0 : active raid1 hda3[1] hdb3[0]
104320 blocks [2/2] [UU]
unused devices: <none>
#!/bin/sh
# ledblink System monitor. Scroll-lock light will remain on if any faults.
# Graham Jenkins, IBM GSA, July 2003.
PATH=/sbin:/bin:/usr/bin:/usr/X11R6/bin:/usr/local/bin
On=1
while : ; do # 働くなら 'blinker' を使う,
blinker -d `expr $On \* 1000` s 2>/dev/null ||# else use 'xset' to flash the
( xset led 3 && sleep $On && xset -led 3 ) # scroll-lock ライトのオン・オフ
sleep `expr 10 - $On`
On=10 # on-time を10 秒に設定
#
# 襲撃状況
grep blocks /proc/mdstat | grep _ >/dev/null 2>&1 && continue
#
# フィルシステムの容量
df -x iso9660 |tr -d '%'|awk '{if (NR > 1) if ($5 > 90) exit 1}' || continue
#
# スワップの利用
swapon -s | awk '{ if (NR > 1) { Size=Size+$3; Used=Used+$4 } }
END { if (Used*100/Size > 70 ) exit 1 }' || continue
#
On=1 # 問題がないとき
done # on-time を1 秒に設定し直し
誰かがXwindowsを使ってログオンしたとき 'ledblink' が走るだけで良いなら、簡単だ。君のマシンに 'xinitrc.d' ディレクトリがあるときは、次のスクリプトを置く。そうでなければ、アンコメントした行を 'xinitrc' フィルに置く。
#!/bin/sh # ledblink このファイルを: /usr/X11R6/lib/X11/xinit/xinitrc.dに置き # 誰でも読み取り可能で実行可能にする [ -x /usr/local/bin/ledblink ] && /usr/local/bin/ledblink &
#!/bin/sh
# ledblink 'ledblink' システム・モニタ・プログラムをスタート/ストップ
# Graham Jenkins, IBM GSA, July 2003.
#
# chkconfig: 2345 98 7
# description: Start/stops the 'ledblink' system monitor program.
case "$1" in
start) if [ -x /usr/local/bin/ledblink ] ; then
[ -s /var/run/ledblink.pid ] && exit 0
echo "Starting 'ledblink' system monitor program .."
/usr/local/bin/ledblink &
echo $! >/var/run/ledblink.pid
fi ;;
stop) if [ -n "`cat /var/run/ledblink.pid`" ] ; then
echo "Stopping 'ledblink' system monitor program .."
kill `cat /var/run/ledblink.pid`
rm /var/run/ledblink.pid
fi ;;
esac
著者紹介:
Graham は、オーストラリアの IBMグローバルサービスの Unix専門家だ。メルボルンに住んでおり、幾つかのハードウエア・プラットホームで、私有財産及びオープンソースの逸品を構築して管理している。
バージョン1.0
ネットワーク・サポートがLinux kernel本来のものであることは明らかだ。Linuxが現在市場で入手出来る「最も安全確実な」ネットワークOSであることも分かっている。内部的に Linux kernel は、TCP/IPプロトコル・スタックを実行する。ネットワーク・コードを部分に分けることが出来る−一つは実際のプロトコルを実行し(/usr/linux/net/ipv4ディレクトリ)、他は各種ネットワーク・ハードウエアのデバイス・ドライバを実現する(/usr/src/linux/drivers/net )。
TCP/IP 用kernelコードは、ネットワークと移送層コードを余り悩ますことなく、実際(又は仮想)の各種通信チャンネルに、極めて簡単に「滑り込ませる」ように書かれる。標準の方法でモジュールを必要とするだけで、カード・ハードウエアを実際のソフトウエア・インターフェイスに接続する。ハードウエア部分は、LANの場合はイーサネット・カード、インターネットではモデモから構成される。
今日では多数のネットワーク・カードが市販されており、そのうち一つがRTL8139 PCIイーサネットカードである。RTL8139 カードは、PCIバスを通じてcpuに接続されるプラグアンドプレーの装置である。PCIとは周辺部品内部接続の略で、コンピュータの各種部品の相互作用方法を定義する仕様書の完全な一式である。PCIアーキテクチャは、以前のISA規格に代わるものとして設計された。データ転送速度、独立の性質、デバイスの追加削除が容易などの特徴がある。
別の重要な方法は、人手でネットワーク・カードを検出してコンフィギュアすることで、それにはifconfig コマンドを用いる。アーギュメントのないifconfig コマンドの一般的出力を下記に示す(システムの構成により異なる)。
eth0 Link encap:Ethernet HWaddr 00:80:48:12:FE:B2
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:10 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:100
RX bytes:0 (0.0 b) TX bytes:600 (600.0 b)
Interrupt:11 Base address:0x7000
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
UP LOOPBACK RUNNING MTU:16436 Metric:1
RX packets:4 errors:0 dropped:0 overruns:0 frame:0
TX packets:4 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:336 (336.0 b) TX bytes:336 (336.0 b)
これは、それぞれイーサネットカードとループバッ・クインターフェイスを示すeth0 とloに関し稼働中のインターフェイスを有することを示す。ループバックは、完全にソフトウエアに基づいておりネットワークにに対するダミイ・インターフェイスとして用いられる。eth0 は、realtek 8139 ネットワーク・カード用の実際のハードウエア・インターフェイスに与えられたデフォルト名である。このリストはまた、そのハードウエア(HWaddr)、インターネット (inet addr)、ブロードキャスト(Bcast)、マスク(Mask)アドレスを、転送することの出来る最大データ単位 (MTU)、受信パケット数(RX)、送信パケット数(TX)、コリジョンなどの データ転送に関する他の統計情報と共に、告げる。ifconfig コマンドはまた、ブート時にインターフェイスが検出されなかったとき持ち込むににも用いることが出来る。これはまた、次に示すようにIPアドレスと結合することも出来る。
ifconfig eht0 192.9.200.1 up
ifconfig eth0 down
ifconfig lo 192.9.200.1 up ifconfig lo down
参照する必要のある別のコマンドはs netstat だ。これはネットワーク接続、ルート作成テーブル、インターフェイス統計、マスカレード接続、マルチキャスト・メンバーシップをプリントする。マニュアルに大量のオプションがある。
Kernel は普段のとおり、優れたプログラム作成のため平均的プログラマに理解し易い小型だが効率のよいデータ構造体とファンクションを与える。作られたインターフェイスは、高級プロトコルと完全に無関係である。kernelのデータ構造体、ファンクション、ドライバとプロトコルスタックの上層との間の相互作用を一瞥するため、先ずハードウエア無関係ドライバを開発してみる。大まかな絵を掴んだら、実際のプラットホームに入ることが出来る。
kernelメモリにロードされたドライバが何であろうと、それが機能するに必要な I/O ポート、IRQ などのリソースを要求する。同様に、ネットワーク・ドライバが自分を登録するとき、新たに検出したインターフェイス毎にデータ構造体をネットワーク・デバイスの全体リストに挿入する。
各インターフェイスは、struct net_device 項目により定義される。デバイス rtl8139 の宣言は、次のようにおこなう。
struct net_device rtl8139 = {init: rtl8139_init};
struct net_device 構造体は includeファイルlinux/net_device.h で定義されている。上のコードは、初期化ファンクションを持つ単一フィールド 'init' だけを初期化する。登録したデバイスが何であろうと、kernelはこのinitファンクションだけを呼び出し、これがハードウエアを初期化して、struct net_device 項目を満たす。struct net_device は巨大で、ハードウエアの作動に関係するファンクション全部を取り扱う。関連のものを見よう。
name : 先ず説明する必要がのは 'name' フィールドだ。これは、インターフェイスの名称(インターフェイスを識別する文字列)を保持する。我々の場合は "rtl8139" だ。
int (*open) (struct net_device *dev) : このメソッドは、ifconfig が起動したときはいつでも、インターフェイスを開く。openメソッドは、これが必要とするシステムリソースを全て登録する
int (*stop) (struct net_device *dev) : このメソッドは、インターフェイスを開き又は停止する(ifconfigにより停止するように)。
int (*hard_start_xmit) (struct sk_buff *skb, struct net_device *dev) : このメソッドは、デバイス 'dev' を通じる伝送を開始する。データはソケット・バッファ構造体skbに含まれる。構造体skbは、後で定義する。
struct net_device * (*get_status) (struct net_device *dev): アプリケーションがインターフェイスに関する統計を必要とするときはいつでも、このメソッドを呼び出す。これは、 ifconfig 又は netstat -i を走らせるときなどに起こる。
void *priv :ドライバ・ライタがこのポインタを持っていいると勝手に使うことが出来る。このメンバーの用途は、後で説明する。説明すべきメソッドはもっと沢山あるが、その前に、上の議論で構築されたダミイ・ドライバの現用コードの実演を見よう。このコードは、これら要素の間の相互作用を極めて明白にする。
コードのリスト 1
#define MODULE
#define __KERNEL__
#include < linux/module.h >
#include < linux/config.h >
#include < linux/netdevice.h >
int rtl8139_open (struct net_device *dev)
{
printk("rtl8139_open called\n");
netif_start_queue (dev);
return 0;
}
int rtl8139_release (struct net_device *dev)
{
printk ("rtl8139_release called\n");
netif_stop_queue(dev);
return 0;
}
static int rtl8139_xmit (struct sk_buff *skb,
struct net_device *dev)
{
printk ("dummy xmit function called....\n");
dev_kfree_skb(skb);
return 0;
}
int rtl8139_init (struct net_device *dev)
{
dev->open = rtl8139_open;
dev->stop = rtl8139_release;
dev->hard_start_xmit = rtl8139_xmit;
printk ("8139 device initialized\n");
return 0;
}
struct net_device rtl8139 = {init: rtl8139_init};
int rtl8139_init_module (void)
{
int result;
strcpy (rtl8139.name, "rtl8139");
if ((result = register_netdev (&rtl8139))) {
printk ("rtl8139: Error %d initializing card rtl8139 card",result);
return result;
}
return 0;
}
void rtl8139_cleanup (void)
{
printk ("<0> Cleaning Up the Module\n");
unregister_netdev (&rtl8139);
return;
}
module_init (rtl8139_init_module);
module_exit (rtl8139_cleanup);
l
上のプログラムをコンパイルして使ってみよう。ファイルrtl8139.cのコンパイルには以下のように 'cc' をコマンド行で呼び出すだけで十分だ。
[root@localhost modules]# cc -I/usr/src/linux-2.4/include/ -Wall -c rtl8139.c
ダミイ・ネットワーク・ドライバをチェックしよう。私のシステムでは以下の出力が得られた。存在するロード済みモジュールをチェックするため lsmod を使うことが出来る。ismodの出力もまた示す。
(注記:モジュールの脱着をするためには、スーパー・ユーザーでなければならない:)
[root@localhost modules]# insmod rtl8139.o
Warning: loading test.o will taint the kernel: no license
See http://www.tux.org/lkml/#export-tainted for information about tainted modules
Module test loaded, with warnings
[root@localhost modules]# lsmod
Module Size Used by Tainted: P
rtl8139 2336 0 (unused)
mousedev 5492 1 (autoclean)
input 5856 0 (autoclean) [mousedev]
i810 67300 6
agpgart 47776 7 (autoclean)
autofs 13268 0 (autoclean) (unused)
[root@localhost modules]# ifconfig rtl8139 192.9.200.1 up
[root@localhost modules]# ifconfig
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
UP LOOPBACK RUNNING MTU:16436 Metric:1
RX packets:4 errors:0 dropped:0 overruns:0 frame:0
TX packets:4 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:336 (336.0 b) TX bytes:336 (336.0 b)
rtl8139 Link encap:AMPR NET/ROM HWaddr
inet addr:192.9.200.1 Mask:255.255.255.0
UP RUNNING MTU:0 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:10 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:0 (0.0 b) TX bytes:600 (600.0 b)
ネットワーク・インターフェイスは構築したが、カードを探して初期化することは出来ない。PCIインターフェイスをチェックしてPCIデバイスが利用可能になったときのみ可能である。だから、PCIと利用出来るPCIファンクションを良く調べなければならない。
前にも説明したように、PCIハードウエアは、各コンポーネントが互いに相互作用する方法を決める完全なプロトコルである。各PCIデバイスは、バス番号、デバイス番号及びファンクション番号で識別する。PCI仕様により、システムはバス256個の上にシステムを保持することが出来る。各バスは32個のマルチボード・デバイスを保持する容量がある。
PCファームウエアはPCIハードウエアをシステム・ブートの際に、各デバイスのI/O領域を異なるアドレスにマップして初期化する。このI/O領域には、各デバイスに付いて256バイトから構成されるPCIコンフィギュレーション空間からアクセスすることが出来る。PCIレジスタのうち三つが、デバイスvendorID, deviceID, class を識別する。ときには、 Subsystem vendorID とSubsystem deviceID をもまた使うことがある。詳細に見よう。
誰かのLinuxボックス上の完全PCIリストは、コマンドlspciを通じて見ることが出来る。
上記の情報に基づいて、rtl8139_initファンクション自体の中でrtl8139の検出をすることが出来る。修正版は以下のようになる。
コードのリスト 2
#include < linux/pci.h >
static int rtl8139_probe (struct net_device *dev, struct pci_dev *pdev)
{
int ret;
unsigned char pci_rev;
if (! pci_present ()) {
printk ("No pci device present\n");
return -ENODEV;
}
else printk ("<0> pci device were found\n");
pdev = pci_find_device (PCI_VENDOR_ID_REALTEK,
PCI_DEVICE_ID_REALTEK_8139, pdev);
if (pdev) printk ("probed for rtl 8139 \n");
else printk ("Rtl8193 card not present\n");
pci_read_config_byte (pdev, PCI_REVISION_ID, &pci_rev);
if (ret = pci_enable_device (pdev)) {
printk ("Error enabling the device\n");
return ret;
}
if (pdev->irq < 2) {
printk ("Invalid irq number\n");
ret = -EIO;
}
else {
printk ("Irq Obtained is %d",pdev->irq);
dev->irq = pdev->irq;
}
return 0;
}
int rtl8139_init (struct net_device *dev)
{
int ret;
struct pci_dev *pdev = NULL;
if ((ret = rtl8139_probe (dev, pdev)) != 0)
return ret;
dev->open = rtl8139_open;
dev->stop = rtl8139_release;
dev->hard_start_xmit = rtl8139_xmit;
printk ("My device initialized\n");
return 0;
}
お分かりの通り、rtl8139_init ファンクションを通じてprobeファンクションが呼び出されている。probeファンクションの詳細な解析は、struct net_device とstruct pci_dev の種類のポインタを渡されたことを示す。struct pci_dev はpciインターフェイスを保持し、他はそれぞれネットワーク・インターフェイスを保持する。これは前に述べた。
ファンクション pci_present は、利用出来る有効pciサポートをチェックする。これは成功すると値 '0' を返す。その後、pci_find_device ファンクションを通じてRTL8139 が開始される。これは、アーギュメントしてvendor_ID, device_ID 及び 'pdev' 構造体を受け取る。エラーのないリターン、つまりRTL8139 が存在するときは、pdev 構造体を満たして送る。定数PCI_VENDOR_ID_REALTEK, PCI_DEVICE_ID_REALTEK_8139は、realtekカードのvendorID とdevice_ID を定義する。これらは、linux/pci.h.で定義されている。
pci_read_config_byte/word/dword は、コンフィギュレーション・スペースからそれぞれbyte/word/dwordメモリを読み取るファンクションである。rtl8139用pciデバイスを有効にするpci_enable ファンクションに対する呼出もまた、インターフェイスに対する割込番号の登録を助ける。したがって、全部が安全に進んでエラーがないときは、rtl_8139 が検出されて割込番号が割り当てられる。
次の章では、 rtl8139 のハードウエア・アドレスを見出して通信を開始する方法を調べる。
著者紹介:
著者は、Thrissur国立工科大学で工学士課程を完了したばかりだ。
1. 計算機 - 次世代版
これから述べる計算機は、if-then-else とwhile 構文を含んだ変更により遙かに複雑になった。加えて、構文解析中に構文ツリーを構築する。ツリーを横断して出力を得ることが出来る。ツリー横断ルーチンは二つの方法でおこなうことが出来る:
物事をもっと具体的にするため、サンプル・プログラムを示す。
x = 0;
while(x < 3) {
print x;
x = x + 1;
}
解釈的な変形の出力は:
1 2 3
一方、コンパイラ版のそれは:
push 0 push x LC0: push x push 3 complt jz LC1 push x print push x push 1 add pop x jmp LC0 LC1: ret
include file は、構文ツリーと記号表に関する宣言を含む。記号表 sym は、単一文字変数名を許す。構文ツリーの中のノードは、定数即ち整数又は演算子の付いた内部ノードを保持する。ツリー・バリアント全部は、ユニオン nodetype の中に包まれており、我々の持つ構造体はnodetype.typeにより決定することが出来る。
lex input file は、VARIABLE とINTEGER トークンのためのパターンを含む。加えて、トークンは、EQ とNE などの二文字演算子により識別される。単一文字演算子は、それ自体として戻されるだけである。
yacc input file は、YYSTYPE、yylval のタイプを次のように定義する
%union {
int ivalue; /* integer value */
char sIndex; /* symbol table index */
nodeType *nPtr; /* node pointer */
};
これは、以下を y.tab.h の中に生じさせる:
typedef union {
int iValue; /* integer value;
char sIndex; /* symbol table index */
nodeType *nPtr; /* node pointer */
}YYSTYPE;
extern YYSTYPE yylval;
定数、変数及びノードは、パーサーの値スタックの中で yylval によりあらわされる。タイプ定義に注目のこと
%token <iValue> INTEGER %token <nPtr> expr
これは、YYSTYPE ユニオンの中でexpr をnPtr に対し、及びINTEGER をiValue に対して結合する。これは、正しいコードを作成するため不可欠である。例えば、ルール
expr: INTEGER { $$ = con($1); }
は、以下のコードを発生する筈である。
yylval.nPtr = con(yyvsp[0].iValue);
yyvsp は値スタック・ポインタでyyvsp[0] は値スタックのトップを指す、叉はINTEGERにつながる値であることに注意。
次のように、単項演算子は二項演算子より高い優先度を与えられる:
%left GE LE EQ NE '<' '>' %left '+' '-' %left '*' '/' %nonassoc UMINUS
%nonassoc は、結合性を意味しないことを示す。これは、 %prec と併せて使用されルールとして優先を規定するることが多い。
構文ツリーを構築するには下から上への方法を用いる。枝葉ノードは、整数として割り当て変数を節約する。演算子に遭遇すると、ノードが割り当てられ、以前に割り当てられたノードに対するポインタが演算数として入力される。ステートメントを変形するときは、ex を呼び出して、構文ツリーを深いものから横断する。ツリーは下から上に構築されているので、深いものから横断すると、ノードを元々割り当てられた順で巡回することになる。その結果、演算子は構文解析中に遭遇した順序で適用される。
2.includeファイル
typedef enum { typeCon, typeId, typeOpr } nodeEnum;
/* constants */
typedef struct {
nodeEnum type; /* ノードのタイプ*/
int value; /* 定数の値 */
} conNodeType;
/* identifiers */
typedef struct {
nodeEnum type; /* ノードのタイプ */
int i; /* ident アレーに対する添字 */
} idNodeType;
/* operators */
typedef struct {
nodeEnum type; /* ノードのタイプ*/
int oper; /* 演算子 */
int nops; /* 演算数の数 */
union nodeTypeTag *op[1]; /* 演算数(拡張可能) */
} oprNodeType;
typedef union nodeTypeTag {
nodeEnum type; /* ノードのタイプ */
conNodeType con; /* 定数 */
idNodeType id; /* 識別子 */
oprNodeType opr; /* 演算子 */
} nodeType;
extern int sym[26];
3.Lex入力
%{
#include <stdlib.h>
#include "calc3.h"
#include "y.tab.h"
void yyerror(char *);
%}
%%
[a-z] {
yylval.sIndex = *yytext - 'a';
return VARIABLE;
}
[0-9]+ {
yylval.iValue = atoi(yytext);
return INTEGER;
}
[-()<>=+*/;{}.] {
return *yytext;
}
">=" return GE;
"<=" return LE;
"==" return EQ;
"!=" return NE;
"while" return WHILE;
"if" return IF;
"else" return ELSE;
"print" return PRINT;
[ \t\n]+ ; /* 空白を無視 */
. yyerror("Unknown character");
%%
int yywrap(void) {
return 1;
}
4.Yacc入力
%{
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include "calc3.h"
/* prototypes */
nodeType *opr(int oper, int nops, ...);
nodeType *id(int i);
nodeType *con(int value);
void freeNode(nodeType *p);
int ex(nodeType *p);
int yylex(void);
void yyerror(char *s);
int sym[26]; /* 記号表 */
%}
%union {
int iValue; /* 整数値 */
char sIndex; /* 記号表索引 */
nodeType *nPtr; /* ノード・ポインタ */
};
%token <iValue> INTEGER
%token <sIndex> VARIABLE
%token WHILE IF PRINT
%nonassoc IFX
%nonassoc ELSE
%left GE LE EQ NE '>' '<'
%left '+' '-'
%left '*' '/'
%nonassoc UMINUS
%type <nPtr> stmt expr stmt_list
%%
program:
function { exit(0); }
;
function:
function stmt { ex($2); freeNode($2); }
| /* NULL */
;
stmt:
';' { $$ = opr(';', 2, NULL, NULL); }
| expr ';' { $$ = $1; }
| PRINT expr ';' { $$ = opr(PRINT, 1, $2); }
| VARIABLE '=' expr ';' { $$ = opr('=', 2, id($1), $3); }
| WHILE '(' expr ')' stmt
{ $$ = opr(WHILE, 2, $3, $5); }
| IF '(' expr ')' stmt %prec IFX
{ $$ = opr(IF, 2, $3, $5); }
| IF '(' expr ')' stmt ELSE stmt
{ $$ = opr(IF, 3, $3, $5, $7); }
| '{' stmt_list '}' { $$ = $2; }
;
stmt_list:
stmt { $$ = $1; }
| stmt_list stmt { $$ = opr(';', 2, $1, $2); }
;
expr:
INTEGER { $$ = con($1); }
| VARIABLE { $$ = id($1); }
| '-' expr %prec UMINUS { $$ = opr(UMINUS, 1, $2); }
| expr '+' expr { $$ = opr('+', 2, $1, $3); }
| expr '-' expr { $$ = opr('-', 2, $1, $3); }
| expr '*' expr { $$ = opr('*', 2, $1, $3); }
| expr '/' expr { $$ = opr('/', 2, $1, $3); }
| expr '<' expr { $$ = opr('<', 2, $1, $3); }
| expr '>' expr { $$ = opr('>', 2, $1, $3); }
| expr GE expr { $$ = opr(GE, 2, $1, $3); }
| expr LE expr { $$ = opr(LE, 2, $1, $3); }
| expr NE expr { $$ = opr(NE, 2, $1, $3); }
| expr EQ expr { $$ = opr(EQ, 2, $1, $3); }
| '(' expr ')' { $$ = $2; }
;
%%
nodeType *con(int value) {
nodeType *p;
/* allocate node */
if ((p = malloc(sizeof(conNodeType))) == NULL)
yyerror("out of memory");
/* copy information */
p->type = typeCon;
p->con.value = value;
return p;
}
nodeType *id(int i) {
nodeType *p;
/* allocate node */
if ((p = malloc(sizeof(idNodeType))) == NULL)
yyerror("out of memory");
/* copy information */
p->type = typeId;
p->id.i = i;
return p;
}
nodeType *opr(int oper, int nops, ...) {
va_list ap;
nodeType *p;
size_t size;
int i;
/* allocate node */
size = sizeof(oprNodeType) + (nops - 1) * sizeof(nodeType*);
if ((p = malloc(size)) == NULL)
yyerror("out of memory");
/* copy information */
p->type = typeOpr;
p->opr.oper = oper;
p->opr.nops = nops;
va_start(ap, nops);
for (i = 0; i < nops; i++)
p->opr.op[i] = va_arg(ap, nodeType*);
va_end(ap);
return p;
}
void freeNode(nodeType *p) {
int i;
if (!p) return;
if (p->type == typeOpr) {
for (i = 0; i < p->opr.nops; i++)
freeNode(p->opr.op[i]);
}
free (p);
}
void yyerror(char *s) {
fprintf(stdout, "%s\n", s);
}
int main(void) {
yyparse();
return 0;
}
5.インタープリータ
#include <stdio.h>
#include "calc3.h"
#include "y.tab.h"
int ex(nodeType *p) {
if (!p) return 0;
switch(p->type) {
case typeCon: return p->con.value;
case typeId: return sym[p->id.i];
case typeOpr:
switch(p->opr.oper) {
case WHILE: while(ex(p->opr.op[0]))
ex(p->opr.op[1]);
return 0;
case IF: if (ex(p->opr.op[0]))
ex(p->opr.op[1]);
else if (p->opr.nops > 2)
ex(p->opr.op[2]);
return 0;
case PRINT: printf("%d\n", ex(p->opr.op[0]));
return 0;
case ';': ex(p->opr.op[0]);
return ex(p->opr.op[1]);
case '=': return sym[p->opr.op[0]->id.i] =
ex(p->opr.op[1]);
case UMINUS: return -ex(p->opr.op[0]);
case '+': return ex(p->opr.op[0]) + ex(p->opr.op[1]);
case '-': return ex(p->opr.op[0]) - ex(p->opr.op[1]);
case '*': return ex(p->opr.op[0]) * ex(p->opr.op[1]);
case '/': return ex(p->opr.op[0]) / ex(p->opr.op[1]);
case '<': return ex(p->opr.op[0]) < ex(p->opr.op[1]);
case '>': return ex(p->opr.op[0]) > ex(p->opr.op[1]);
case GE: return ex(p->opr.op[0]) >= ex(p->opr.op[1]);
case LE: return ex(p->opr.op[0]) <= ex(p->opr.op[1]);
case NE: return ex(p->opr.op[0]) != ex(p->opr.op[1]);
case EQ: return ex(p->opr.op[0]) == ex(p->opr.op[1]);
}
}
}
6.コンパイラ
#include <stdio.h>
#include "calc3.h"
#include "y.tab.h"
static int lbl;
int ex(nodeType *p) {
int lbl1, lbl2;
if (!p) return 0;
switch(p->type) {
case typeCon:
printf("\tpush\t%d\n", p->con.value);
break;
case typeId:
printf("\tpush\t%c\n", p->id.i + 'a');
break;
case typeOpr:
switch(p->opr.oper) {
case WHILE:
printf("L%03d:\n", lbl1 = lbl++);
ex(p->opr.op[0]);
printf("\tjz\tL%03d\n", lbl2 = lbl++);
ex(p->opr.op[1]);
printf("\tjmp\tL%03d\n", lbl1);
printf("L%03d:\n", lbl2);
break;
case IF:
ex(p->opr.op[0]);
if (p->opr.nops > 2) {
/* if else */
printf("\tjz\tL%03d\n", lbl1 = lbl++);
ex(p->opr.op[1]);
printf("\tjmp\tL%03d\n", lbl2 = lbl++);
printf("L%03d:\n", lbl1);
ex(p->opr.op[2]);
printf("L%03d:\n", lbl2);
} else {
/* if */
printf("\tjz\tL%03d\n", lbl1 = lbl++);
ex(p->opr.op[1]);
printf("L%03d:\n", lbl1);
}
break;
case PRINT:
ex(p->opr.op[0]);
printf("\tprint\n");
break;
case '=':
ex(p->opr.op[1]);
printf("\tpop\t%c\n", p->opr.op[0]->id.i + 'a');
break;
case UMINUS:
ex(p->opr.op[0]);
printf("\tneg\n");
break;
default:
ex(p->opr.op[0]);
ex(p->opr.op[1]);
switch(p->opr.oper) {
case '+': printf("\tadd\n"); break;
case '-': printf("\tsub\n"); break;
case '*': printf("\tmul\n"); break;
case '/': printf("\tdiv\n"); break;
case '<': printf("\tcompLT\n"); break;
case '>': printf("\tcompGT\n"); break;
case GE: printf("\tcompGE\n"); break;
case LE: printf("\tcompLE\n"); break;
case NE: printf("\tcompNE\n"); break;
case EQ: printf("\tcompEQ\n"); break;
}
}
}
}
7.If-Elseの両義性
しばしば起こるシフト−還元競合(パート1で説明済み)に、if-else 構文が含まれる。次のルール:
stmt: IF expr stmt | IF expr stmt ELSE stmt ...
及び次のルールがあるとする:
IF expr stmt IF expr stmt . ELSE stmt
構文解析中に、ELSEに出会ったら何をすべきだろうか。 ELSEをシフトするか、スタックのトップに IF expr stmt を還元するか。
シフトすると、次が得られる
IF expr stmt IF expr stmt . ELSE stmt IF expr stmt IF expr stmt ELSE . stmt IF expr stmt IF expr stmt ELSE stmt . IF expr stmt stmt .
この場合は、第二の ELSE は、第二のIFと対になる。
還元すると、次が得られる
IF expr stmt IF expr stmt . ELSE stmt IF expr stmt stmt . ELSE stmt IF expr stmt . ELSE stmt IF expr stmt ELSE . stmt IF expr stmt ELSE stmt .
この場合は、ELSE は第一の IF と対になる。
近代的プログラム作成言語は、ELSE を最も新しい無対のIFと組み合わせるので、前の行動を予測している。これはyaccで上手く働く。シフト−還元競合が起こったときはいつでも、シフトの規定動作を取る。だがこれにしたがうと、yaccは警告メッセージを出す。メッセージを削除するには、IF-ELSE にIF 単純ステートメントより高い優先度を与える:
%nonassoc IFX %nonassoc ELSE stmt: IF expr stmt %prec IFX | IF expr stmt ELSE stmt
8.結語
優先度で解決された競合は、Yaccの報告するシフト/還元と還元/還元競合の数には計数されない。これは、優先度仕様の間違いが入力文法のエラーを偽装することを意味する。優先度で容赦し、何かの経験が得られるまで、これらを実質的に「詳しい説明書」の形で使うのが良い考えだ。y.output ファイルは、パーサーが目的通り働いているか否かを判定するのに大変役立つ。
Yacc は、通常警告を出す。しかしエラーも生じる。"syntax error"などのメッセージは、エラーが起こった場所とどんなエラーか分からないままに放置する。エラー取扱は遙かに面倒なので、ここでは扱わない。
著者紹介:
私はコンピュータ科学工学の工学士最終試験に合格したばかりの、インドのKerala生まれの人間だ。
Linux Gazette の今月号の体裁が少し変わったのに気付かれたと思う。ロゴやレイアウトの変更のほか、人事の異動もあった。Linux Gazette の編集者がいなくなった。Mike Orrはボランティア編集者として良い仕事をして呉れたが、少しましな就職先を探さなければならない。時々は記事を貰えると望んでいる。
記事の投稿と、発行の確認はSSC webmasterの仕事だ。
サイト全体を改装中なので、e-メールアドレスなど、細かい変更もあるかも知れない。
変更が進んだら、皆様からのご意見のフォーラムも設けたい。
Linux Gazetteがお役に立っていなければ是非お知らせ頂きたい。
SSC Webmaster
著者紹介: Linux Gazette とその他の SC サイトのウェブマスター。コスタリカ在住。