Linux Gazette 2003年8月号 #93
今月のLinux Gazette の主な記事
n今月のニュース
 ・一般ニュース
 ・ディストリビューション関連ニュース
 ・ソフトウエア及び製品関連ニュース
n Linuxインストレーション・パス
n startx/xinit不具合に関する一般の場合
n 3本指の敬礼を監査
n Novell e-Directoryを通じるLinux認証
n パーティション全部をミラーしたのに
n Windows 2k/2003 ターミナル・サービス用Linuxディスクレス・クライアントの創設
n ネットワーク・デバイスドライバの作成−
n Yacc - パーサ・ゼネレータ - パート2
n BackPage
 
(訳者注)
原文を一括して一つのファイルでセーブするには、下記のリンクがあります。
TWDT 1 (gzipped text file)
TWDT 2 (HTML file)
前者はテキスト形式で、後者はHTML形式です。但し、HTML版のリンクが働くとは限りません。
 
 
 
 
 
今月のニュース
▼▼▼一般ニュース▼▼▼

Intrinsyc が Linux-基準 CerfCube PPC 405EPの出荷を開始

インテリジェントデバイスの世界的専門メーカーIntrinsyc Software Internationalが、IntrinsycのCerfCube 405EP基準プラットホームを用いるそのIBM PowerPC 405EP埋込プロセッサの販売に関するIBM マイクロエレクトロニクスとの協力を本日発表した。

サーバ器具、データ収集装置、スキャナ、インターネット用機器のたの理想的にCerfCube 405EP はまた、ネットワーク・ルータとコンセントレータ、LANベースのビデオ、無線ネットワークのアクセスポイント、LAN経由で大量のデータ移動が必要なあらゆるアプリケーションにも適している。新聞発表全文は press release is available online.

 
ERP5とCollaborative Portal Server (CPS)チームが同盟を組んで世界最初の全世界オープンソース情報システムを提供

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 を訪ねて登録されたい。

 
10 Anywhereが新Linux器具を発表

IO Anywhere Inc. が、第一世代製品のリリースを発表した。原価$200以下の器具開発を使命として発足したIO Anywhereは、多数のオンボードI/O、多重シリアルポートを持ち、ブラウザコンフィギュラブルで、超停電力消費、イーサネット有効で、各種のあらゆるデータ捕獲及び制御アプリケーションに容易に適合する必要があった。IO Anywhere器具は、古い装置と先端スタンドアローン装置双方の各種アレーに対し手頃なインターネット/インターネット接続性を提供する。CPLDにおける最新技術を使用しイーサネット有効マイクロプロセッサ・コアモジュールを統合して、広範囲のアプリケーションのため完全にコンフィギュラブルなプラットホームを生産する。

 
 
 
 
 
▼▼▼ディストリビューション関連ニュース▼▼▼
Debian

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.を案内している。

 
Gentoo

A Gentoo Linux fork に発表がある。Zach Welch がgentoo-devメールリストの中のGentoo Linux 仲間に、新プロジェクトをZynotと呼ぶと発表した。Linux Weekly News にこの発展の説明がありdiscussion of this development 、背景事情へのリンクもある。

 
Mandrake

MandrakeSoftの CEO François Bancilhon は、公開状An open letter でMandrakeの最近事情と、年初に11条保護を適用されて以来の進行を説明した。

 
Red Hat

Register は最近、小売り販売を中止し企業利益を重点とするとのRed Hatの決定を報告したThe Register recently reported

 
SCO

SCO は、ALXソフトウエアの使用又は複写に関するIBMの権利を停止し、IBMに対する苦情の改訂を申し入れたと発表した。IBMに対するUNIXシステムVソースコードのコピイ全部の廃棄又は返却の命令、及びALX販売の永久停止を含む。SCOグループは、自分を「ビジネス・ソフトウエア・ソリューションの先端プロバイダ」と称している。

 
SuSE

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スーパーコンピュータは、米国核備蓄のコンピュータ・シミュレーションその他の用途に用いられる。

 
 
 
 
 
▼▼▼ソフトウエア及び製品関連ニュース▼▼▼
Gramadóir

Kevin Scannell は、Linux/Unixなどの下で働くアイルランド語文法照合Irish Language grammar checker を書いた。これはKevinがispell とGaelspelのためのワードリストを作るのに用いたと同じデータベースの上で構築されており、GPL条項の下で頒布される。

 
IBMがLinuxベースの中企業用雇用員職場移植可能ソリューションを明らかに

IBM が、新しいLinuxベースサーバ・ソリューション、雇用員職場用IBM統合プラットホームエクスプレスを発表した。これは多忙な事務所環境の中規模企業の強化を目的とする。組織はこのソリューションを用いて、雇用員が事業情報及び協力的職場アプリケーションに全て単一ブラウザを通じてアクセスし、交信し、専用にして運用することが出来るようにして雇用員効率を改善する。

 
韓国のSoftbank UwayがLinuxを選択

韓国の Softbank Uway が最近、45個のデータベースとウェブサーバを、HPとSunから単一の新IBM z990 "T-Rex" メインフレームに交換した。この会社は、IBMの z/VM仮想化技術を用いてz990上のパーティションで走るLinuxを動かし、それによりシステム管理を劇的に簡略化してソフトウエアコストを軽減する。

 
SIMPLがPython 拡張でv2.2.0を発表

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の「今月のニュース」 編集者だ。

[Picture] 数年前にアイルランドで生まれたMichaelは、現在ダブリン大学医療工学部で博士論文に取り組んでいる。論文の題名はLamb wavesの非破壊検査への利用だ。この研究に GNU/Linux が極めて有用であったので、 Michael は他の工学にフリーソフトウエア・ソリューションを適用することに強い興味を持った。論文が出来上がったら、 Michael は長い徒歩旅行にでる予定だ。

 

Copyright © 2003, Michael Conry.
Copying license http://www.linuxgazette.com/copying.html
Published in Issue 93 of Linux Gazette, August 2003
 
 
 
 
 
Linuxインストレーション・パス
By David Lechnyr

ソフトウエアを搭載するとき、多くの人が「/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準拠への重点は、ソフトウエア開発者が置かなければならない。これで伝統的問題の幾つかは解決する。例えば:

例 1: FHS 出現以前
ユーザがRedHat Linuxをインストールする。暫くして、ソフトウエア・パケージのうち一つを人手で更新しようと決める。各ソフトウエア・パケージに関するRedHat Linux の下のインストール位置は、ソフトウエア・ベンダーが決めるので、ファイル位置の競合はない。/usr/local/packagenameにインストールされたパケージは、同じ位置のファイルを置き換える。
Example 2: After the advent of the FHS
ユーザがRedHat Linuxをインストールする。暫くして、ソフトウエア・パケージのうち一つを人手で更新しようと決める。だが、彼のソフトウエア・パケージは、/var/lib/packagenameにある可変データ・ファイルと一緒に /usr/bin と /usr/sbin にインストールされている。ダウンロードしたばかりのソフトウエア・パケージは、全部を規定値で /usr/local/packagenameにインストールする。平均的Linuxユーザとして、彼は、これが自分のシステムに持ち込むかも知れない競合にまごついて、どう進めて良いか確信がなくなる。

個人的には、FHS準拠につき間違った角度から眺めていると思う。代わりの将来像はもっと良い筈だ:

例 3: 将来
ユーザがRedHat Linuxをインストールする。暫くして、ソフトウエア・パケージのうち一つを人手で更新しようと決める。各ソフトウエア・パケージに関するRedHat Linux の下のインストール位置は、(RedHat ではなく)FHS準拠ソフトウエア・ベンダーが決めるので、ファイル位置の競合はない。RedHat 自体は、各ソフトウエア・パケージに関するインストレーション規定値に対する修正をしない。RPMだろうが人手でコンパイルしようが、システムにインストールされたパケージは、システム内の全く同じ位置のファイルを置き換える。

来るべきFHSバージョン2.3のリリースでは、正しい問題に重点を置くことがもっと重要になる。インストール可能Linuxソフトウエアの世界における混乱を最小にするのに成功したとき、哲学や方法だけでなく正しいあいてにも焦点を当てなくて済む。この記事が、お手元の問題に気づく切っ掛けになれば幸い。

LFH準拠を維持しようとしているディストリビューションの幾つかは下記である:

Debian
Linux From Scratch
Redhat
SCO (formerly Caldera OpenLinux)
Slackware
SuSE
TurboLinux
UnitedLinux
 
著者紹介:

David Lechnyr は、オレゴン大学の人的資源学部のネットワーク管理者である。彼は、社会福祉の修士号を MCSE+I, CNE, CCNA認証とともに持っている。過去7年間、Linuxのため、システム・セキュリティ、ネットワーク故障修理、PHP/MySQL統合に関して、働いて来た。 Unofficial Samba HOWTO 及び Linux+Apache+MySQL+PHP HOWTO. の著者でもある。

Copyright © 2003, David Lechnyr.
Copying license http://www.linuxgazette.com/copying.html
Published in Issue 93 of Linux Gazette, August 2003
 
 
 
 
startx/xinit不具合に関する一般の場合
By Yufei Yuan

我々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 があり、これがウェブブラウズと流れる音楽の聴取に上手く働く。

Copyright © 2003, Yufei Yuan.
Copying license http://www.linuxgazette.com/copying.html
Published in Issue 93 of Linux Gazette, August 2003
 
 
 
 
3本指の敬礼を監査
By Dean WIlson

「たった一つのサービスを働かせるだけで完全に修復され、規定値で拒否するファイアウォールになる}
「 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' のコードが戻される。依存する外部バイナリは次の通りである:

・/usr/bin/logger
・/usr/bin/tr
・/bin/date
・/usr/bin/basename

これらのうち唯一人手編集を必要とするのは 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に示す。

daily
rotate 7
compress
delaycompress

/var/log/shutattempt {
  nomail
  notifempty
  missingok
  create 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 にある彼のペイジのシステム管理者兼臨時更新者である。

Copyright © 2003, Dean WIlson.
Copying license http://www.linuxgazette.com/copying.html
Published in Issue 93 of Linux Gazette, August 2003
 
 
 
 
 
Novell e-Directoryを通じるLinux認証
By Ivan Pesin
 

1. 緒言

この文書の主目的は、e-Directoryを通じるLinux認証の設定をおこなうのに必要なステップを説明することである。

Novell e-Directory は、X-500ベース・ディレクトリに対するアクセス・プロトコルの新しい実現である。このプロトコルの別の実現は LDAP, Lightweight Directory Access Protocolとして知られている。 LDAP は RFC2251 "The Lightweight Directory Access Protocol (v3)".の中で定義されている。

ディレクトリはデータベースに似ているが、記述的なアトリビュートに基づく情報をもっと多く含む傾向がある。ディレクトリの中の情報は、一般的に書き込まれるより読み取られる方が多い。ディレクトリは、大容量の検索操作に対し迅速な応答をするよう調整されている。これらは、応答時間を短くしながら利用性と信頼性を増すため、情報を広く複製する能力を有する。ディレクトリ情報が複製されたとき、複製品の間の不一致は、結局同期される限り、構わない。

2. システム要件

・Novell e-Directory 8.6 以上
・PAM 付きLinuxシステム (サンプルは全部RedHat Linux 7.3用に作成)
・nss_ldap ライブラリ
・pam_ldap モジュール

3. クイック・スタートの指針

以下は、Novell e-Directoryを通じるLinux認証とアカウント情報取出の設定に対するクイック・スタートの案内である。

認証プロシージャ設定に必要な基本的ステップを通覧する積もりである。これは、この文書の別の章、マニュアル、規定値ディストリビューションに付いてくるその他の資料と一緒に使わなければならない。

Novell e-Directoryを通じる認証を用いて真剣に作業する積もりであれば、ソフトウエア設定の前に、この文書全体を読まなければならない。

Novell e-Directory認証 を設定するには次のステップを実行しなければならない:

ldap.conf ファイルを正しくコンフィギュアする
PAM system コンフィギュレーションにいくらか変更を加える
name service switchを設定する
・Novel Netware サーバ SSL Certificate を入手する
・Novell e-Directory コンフィギュレーション

/etc/ldap.conf configuration file

先ず、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

b. PAM システム コンフィギュレーション

ここでコンフィギュレーションを 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

これでパスワード認証を設定した。次の作業に進もう。

c. Name サービス切換コンフィギュレーション

ここで、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

d. SSL セキュリティ コンフィギュレーション

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ツールを通じておこなう。

e. Novell 側のコンフィギュレーション

先ず、NDS <&#8211;> LDAP マッピングスキムを変更しなければならない。それをするには、ベースコンテキストを開いて"LDAP Group" 項目を見出す。このオブジェクトのプロパーティを開く。"General" タブで、"Allow Clear Text Passwords"ボックスをチェックする(これはテストが目的)。

ここで "Attribute Map" タブを開く。tab. Click "Add" ボタンをクリックして次のマッピングを追加する:




 
LDAP Attribute NDS Attribute
loginShell loginShell
uidNumber uidNumber
gidNumber gidNumber

"LDAP Group" プロバーティ・ダイアログを閉じる.

第二のステップは、ユーザアカウントを正しく設定することだ。そのため、適切なユーザ上で右クリックしてプロパーティを選ぶ。"UNIX Profile" タブを開いて、アカウントデータを入力する:

User properties dialog

短く凡例を示す:

・uid (User ID) - 全てのユーザに独特でなければならない
・gid (Group ID) - グループ番号
・login shell - ユーザのログイン・シェル
・comment - 任意の注釈、フルネームなど
・home directory - ユーザのホーム・ディレクトリ

4. 高級な指針

ここでは、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-メールされたい。

Authentication scheme

a. PAM_LDAP と NSS_LDAP.

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

b. PAM システム

特殊ファイルのエディットにより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

c. 名称切り替えサービス

これも/etc ディレクトリに置かれているnsswitch.confファイルは、シャドウ情報(シャドウ・ファイル)とパスワード情報(認証目的のため)のためどのシステムを使うかをコンフィギュアするのに用いられる。ファイルの各エントリは、ファンクション名と、次いで関連するモジュールのリストから構成される。

nsswitch.conf ファイルのサンプルを下記に記載する:

passwd: files ldap
shadow: files ldap
group: files ldap

d. SSL セキュリティ

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 が同じ証明書になるよう設定する。

e. Novell e-Directory コンフィギュレーション

認証に関する闘いの最終ステップは、Novell e-Directoryサーバの設定だ。NDS <&#8211;> LDAP マッピング・スキムに幾つかのアトリビュートを追加しなければならない。そのため、ConsoleOne でベース・コンテキスト開き、"LDAP Group" 項目を見出し、マウスで右クリックして"Properties..."を選ぶ。

ここで "Attribute Map" タブを開く。 "uidNumber", "gidNumber" と云う名のLDAPアトリビュートを見出して削除する。壊れたマッピングだからだ。代わりに新しいマッピングを作る。それには "Add" ボタンをクリックして次のマッピングを追加する:




 
LDAP Attribute NDS Attribute
loginShell loginShell
uidNumber uidNumber
gidNumber gidNumber

一番最期に、各ユーザの "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 の公式ロシア語ミラー だ。

Copyright © 2003, Ivan Pesin.
Copying license http://www.linuxgazette.com/copying.html
Published in Issue 93 of Linux Gazette, August 2003
 
 
 
 
 
パーティション全部をミラーしたのに
By Graham Jenkins
 

ご心配なく、何でもミラーする

この物語は、金曜日の昼食時、日光の下で仕事に戻ろうとぶらぶらしていた時、ユーザからの電話で始まった。話は次のように進んだ。

「今日は、ACMEアプリケーションのためデータベースを見るとき、少し問題があるような気がします。見て頂けますか?」

「勿論、10分でデスクに戻るので、戻り次第電話しよう。そのサーバ上のものは全部ミラーされるので、一番可能性があるのは、アーカイブログがセカンダリ記憶に動かされていないことだ。数分で解決するよ」

そして数分後「数分じゃ駄目だ。数時間掛かりそうだ。ミラーの両側で無くなったディスクがあるようだ」

どうすればミラーの両側を同時に失うか?

何を間違ったのだ?ミラー片は別々のコントローラに付属する別々のディスク上にある。大きい電力スパイクや地震はなかった。夜間清掃人がプラグを引き抜いたと文句も言えない。

答えは、両側を同時に無くしたのではないことだ。実際は片側を1週間早く無くしていた。私の会社には、こんな出来事を検出するため優れた監視警報システムがあるが、このサーバが「建設」状態から「生産」状態に移行したのを警備員に通知するのを忘れていた。こんなことを繰り返してはいけない。

少し家に近く

数週間前、自宅のワークステーションで、その第二ディスクが半年で故障したのを経験した。勿論保証期間でディスクは交換した。だが、このとき、何も彼も追加ディスクにミラーしようと決心した。

そこで考え始めた。「一つのディスク上のパーティションがオフラインになったのを、どうして知るか?」私の自宅ワークステーションを会社の警報システムにぶら下げる訳には行かない。

誰かが言った「メッセージ・ファイルをチェックしろ、'root' emailを読んだらどうだ?」偉大な理論家だ。問題は、メッセージを先送りノートと考えているパートナがおり、eメールをホットメールと思っていることだ。それで、私が外にいるときは、彼女が私のマシンのユーザになる。

簡単な監視機構

解決策はここで、10秒毎に1秒間隔でScroll-Lockライトを光らせる機構に発展した。パーティションがミラーされなくなったら、ライトは点いたままになる。余計なハードウエSimple Watchdogア要らない。馬鹿馬鹿しいほど分かり易い。ここにいるのは簡単な番犬で、これが定期的に未だ生きていることを示し、何かが悪くなると吠え続ける。

では、どうやって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>

また、何かが上手く行かないときを('blocks'を含む行に協調があるのを検索することにより)検出し、それにしたがってscroll-lockライトを起動するする我々のプログラムを示す。これは、ほとんどのBourne-類似シェルの下で走り、余分の警報条件一つか二つを検出するよう拡張された。適切と考えるならそれを追加することが出来る。
#!/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 &

'blinker' 問題があるときは、ブート時に以下のスクリプトを使って '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

 

著者紹介:
[picture] Graham は、オーストラリアの IBMグローバルサービスの Unix専門家だ。メルボルンに住んでおり、幾つかのハードウエア・プラットホームで、私有財産及びオープンソースの逸品を構築して管理している。

 

 

Copyright © 2003, Graham Jenkins.
Copying license http://www.linuxgazette.com/copying.html
Published in Issue 93 of Linux Gazette, August 2003
 
 
 
 
 
Windows 2k/2003 ターミナル・サービス用
Linuxディスクレス・クライアントの創設
By Avinoam Levkovich
Avinoam@mail.staplers.co.il
 

バージョン1.0

私が働いている会社には、今日の普通のアプリケーションには適さない古いコンピュータが沢山ある(32MB RAM付きの P-I 100MHZ 上でOffice XP/2kを走らせて見れば、余り心地よくないのが分かるだろう)。新しいコンピュータを買う金を節約する方法を探し始めた。目標は古いコンピュータを使っても、良い性能を得ることだ。目標にピッタリのLinuxソリューションを見付けた。
未だに古いコンピュータを使っており、必要な唯一の投資はWindows 2K/2003のライセンスをハードウエアを買うことだけだ。
ソリューションは、LTSP, rdesktop とwilisystemのサブシステムを統合することだった。幸いこれらのシステムは、ご覧の通り極めて自然に統合された。
 
LTSP ( http://www.ltsp.org ) :
は、ディスクレス・クライアントにLinuxターミナル・サービスを提供するシステム全部の背骨だ。LTSPをインストールした後、これは /opt/ltsp/i386ディレクトリを作る。
このディレクトリは、我々のディスクレス・クライアントのルート・システムとなる。クライアントをブートするとき、これはtftpを使ってLTSPからkernelを入手し、次いで、そのルートディレクトリとして /opt/ltsp/i386を取り付ける。
だから、君のクライアントがブート処理を完了すると、君は自分のLTSPサーバにログインされて、君のファイルシステムは /opt/ltsp/i386 ディレクトリになり、続いて、Wilisystemが働き始める。
 
Rdesktop :  http://www.rdesktop.org/
マイクロソフトは、RDPと云うプロトコルを開発した。これはクライアントとのターミナル・サーバ通信用に用いられる。
rdesktopパケージは、Windowsサーバを使ってRDPセッションを開くアプリケーションで、これをすることにより、LinuxステーションがWindows ターミナル・クライアントになる。
 
Wilisystem ( http://www.wilisystem.com/ ) :
Wilisystem は、実際はLTSPサーバのためのパッチである。これはWindows ターミナル・サーバに対する接続を出来るだけ容易におこなう。
Wilisystem は、rdesktopを使い、Windows ログイン画面でディスクレス・クライアントのブート処理を完了する。そうすることにより、LTSPセッションをユーザに見えなくし、直接Windows サーバに差し込んだように見せる。
wilisystemの開発者には感謝しなければならない。
 
Rom-O-Matic : www.rom-o-matic.net
これは、自分が選んだブート装置(私はフロッピイを使った)のためブート画像を入手する場所だ。自分のイーサネット・カード・モデルを規定した後、自分のブート画像をダウンロードすることが出来る。
素晴らしい考えの素晴らしい改良だ。
 
上記のウェブサイトからの文書を読まれたい。文書を読めば、オプション全部が分かり、このシステムから得られる利点と、自分の必要に合わせた調整方法が分かる。
 
必要なもの :
1.  Linux サーバ、私は256MB RAM 付きP-III 800 を Red Hat 9.0 で使った。
 
2.  デイスクレス・クライアント、私は P-I 133MHZ , 32MB RAM, Ati - Rage XL (mach64 ファミリ) ディスプレー・アダプタを、intel 100/pro イーサネットで使った。
 
3.  ターミナル・サーバをインストールしたWindows 2K/2003 サーバ、コンフィギュアして、走っているもの。私は256MB RAM付き P-4 1.7MHZ を使った。
 
自分のディスクレス・クライアント環境を作る:
ディスクレス・クライアントをws009と呼ぶ。
 
Linux サーバ側 :
1.  自分のクライアント(ws009 ) ディスプレー・カード・モデルと、そのイーサネットmacアドレスを見出して書き留める。後で必要になる。
 
2.  http://www.ltsp.org/ から以下のパケージをダウンロードしてインストールする。
ltsp_core-X.X-X.rpm
ltsp_kerne-X.X-X.rpm
ltsp_x_core-X.X-X.rpm
ltsp_x_fonts-X.X-X.rpm
 
3.  rdesktopパケージを RedHat CD からインストールするか又は
  http://www.rdesktop.org/ からダウンロードする。
 
4.  Download the wilisystem patch from http://www.wilisystem.com/ から wilisystemをダウンロードしてインストールする。
 
5.  Dhcp,Nfs,Tftp サーバ用のパケージがインストールされたのを確かめる。
 
6.  ファイル /opt/ltsp/install_scripts/CONFIG をエディットして、自分のネットワーク設定に合うよう変更する。
 
7.  /opt/ltsp/templates/ltsp_initialize を走らせる。
# cd /opt/ltsp/templates/ltsp_initialize
# ./ltsp_initialize
 
8.  /etc/dhcpd.conf.example を/etc/dhcpd.conf にコピイして、ネットワーク番号全部が自分のネットワーク・コンフィギュレーションに一致することを確かめる。自分のクライアントのmacアドレスをチェックして、 dhcpd.confファイルにあるクライアント・コンフィギュレーション・セクション(ホストws009 ) を更新する。
 
私の /etc/dhcpd.conf を示す:
 
ddns-update-style none;
 
default-lease-time 21600;
max-lease-time 21600;
 
option subnet-mask 255.255.255.0;
option broadcast-address 192.168.1.255;
option routers 192.168.1.100;
option domain-name-servers 192.168.1.100;
option domain-name "my-domain.com";
option root-path "192.168.1.100:/opt/ltsp/i386";
 
option option-128 code 128 = string;
option option-129 code 129 = text;
 
shared-network WORKSTATIONS {
    subnet 192.168.1.0 netmask 255.255.255.0 {
 
    }
 
 
group {
    use-host-decl-names on;
    option log-servers 192.168.1.100;
 
    host ws009 {
            hardware ethernet
00:02:B3:2D:B0:D2;
            fixed-address 192.168.1.113;
            filename "/lts/vmlinuz-2.4.21-
ltsp-1";
           }
          
        }
 
 
9.  /etc/exportsのチェック:IP 番号が自分のネットワーク・コンフィギュレーションに一致することをチェックする。全部良ければ、下記を走らせる:
        # exportfs -r
        # exportfs -a
 
10. クライアントが /etc/hostsに正しく記載されているかをチェックする。クライアント名がw009 で、自分のドメインが my-domain.com であれば、 /etc/hosts ファイルに次のような行を追加しなければならない:
192.168.1.112    ws009.my-domain.com     ws009
この名称(ws009) は、自分のdhcp.confでコンフィギュアしたクライアント名( ホスト ws009)と同じでなければならない。
 
12. /opt/ltsp/i386/etc/lts.conf をチェックする。ファイルの最後に次がある筈。
  wilisystem configuration
 
私のWilisystem Config を示す、コンフィギュレーション部分に、備考を追加した:
# http://www.wilisystem.com/のためのコンフィギュレーション部分
# W2K/NT4 TSEにアクセスするws009 の例
[ws009]
RDPSERVER = 192.168.1.3       # 自分のW2K/NT4 ターミナル・サーバのip 
RUNLEVEL = 7            # wilisystemについてランレベル7
SERVER = 192.168.1.100        # 自分のLTSPサーバの IP
XSERVER = auto           # 自分のディスプレー・カードの自動検出
 
# ディスプレーが自動モードで失敗したときは、
www.ltsp.org からproper ltsp_x336-XXX をダウンロードして
次のように規定する
XSERVER   = XF86_Mach64
 
X_MODE_0 = 1024x768    # 望みの解像度、( 1024x768 , 800x600 ...)
 
X_COLOR_DEPTH = 15    # 色深度、8 ビット(256)をサポートするのは
               win2k サーバだけだと思う
 
# 以下の行はマウスをコンフィギュアする。別のマウス・タイプのコンフィギュレーションについては、次の文書を参照のこと:
http://www.ltsp.org/documentation/
 
X_MOUSE_PROTOCOL = "PS/2"  
X_MOUSE_DEVICE = "/dev/psaux"
X_MOUSE_RESOLUTION = 400
X_MOUSE_BUTTONS = 3
 
13. tftp サービスが xinetd ディレクトリで有効になっているのを確かめる。
  run :
  # service dhcpd restart
  # service xinetd restart
  # service nfs restart
 
 tftp サーバがrunを走らせていることの確認: netstat -anp | grep ":69 "
 次のようなものが出る筈: udp 0 0 0.0.0.0:69 0.0.0.0:* 799/xinetd
 
 次によりdhcp サーバを検証: netstat -anp | grep ":67 "
 次のようなものが出る筈: udp 0 0 0.0.0.0:67 0.0.0.0:* 2086/dhcpd
 
 デバイスが働いているか否かはスタートし直して試す。
 働いていれば、/etc/xinetd.d/tftpの中のtftpが有効になるので、スタートし直す。
 
14.  /opt/ltsp/i386/etc/lts.conf で規定される規定値のランレベルは、ランレベル5であるが、wilisystem セクションで、このランレベルはランレベル7に上書きされる(/opt/ltsp/i386/etc/inittabを見るとこのランレベルに関するwilisystemコンフィギュレーションが分かる)。
問題があるときは、これを変える。/opt/ltsp/i386/etc/lts.conf にある他のクライアントコンフィギュレーションのうち一つを使ってクライアントをロードしてみる。 ws001が良い。dhcpコンフィギュレーションとブートファイルを変更して、新しいホスト名に合わせランレベル3を選ぶのを忘れないこと。これはだけが、windowsターミナル・サーバに接続しようとしないてlispシステムをロードするので、
システムをデバッグすることが出来る。
 
ディスクレスクライアント側
 
1.  初期クライアント・ブートkernel を http://rom-o-matic.net/ から入手する。
ダウンロードしたイメージからブートフロッピイを作るには、次を走らせる:
# cat eb-5.0.10-yournic.lzdsk > /dev/fd0
ここで "eb-5.0.10-yournic.lzdsk" は、ダウンロードしたROMイメージを記憶した場所である。
 
2.  ブート・イメージから作ってブート・フロッピイを使ってクライアントをブートし直す・
 
ブート処理を完了した後、Windowsログイン画面が出る筈:
 
問題
Xサーバがロードしようとして失敗し "no screens found " のメッセージが出たとき、画面がちらつくのを経験した。システムが私のディスプレー・アダプタ("mach64" ファミリー)を認識しなかったためだ。これは、ltsp サイトから正しいXfree 3.3 ドライバをダウンロードし、lts.conf ファイルの中で " XSERVER = XF86_Mach64 "を使ったところ解決した。
 
Copyright © 2003, Avinoam Levkovich.
Copying license http://www.linuxgazette.com/copying.html
Published in Issue 93 of Linux Gazette, August 2003
 
 
 
 
 
ネットワーク・デバイスドライバの作成−パート1
By Bhaskaran
 

緒言

この記事は、読者がLinuxでイーサネット・カード用ネットワーク・ドライバを理解し開発する助けになるだろう。念のため言うと、ドライバ開発はモジュールとしてCでおこなわれたので、読者はCとLinux環境に熟達していると仮定する。記事は、ネットワーク・カード用ドライバ開発に不可欠の点だけを述べる(熟練者はLinuxソース・リストを見られたい)。

Linux ネットワークと PCI カード

ネットワーク・サポートが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規格に代わるものとして設計された。データ転送速度、独立の性質、デバイスの追加削除が容易などの特徴がある。

ネットワーク作成の基礎

PCをネットワークに接続するには netconfig コマンドを用いる。これは、通信アドレス(8進数4個のIPアドレス)、ネットマスク、ゲートウエイ、主ネームサーバなどを自動処理を通じて構成する。成功すると、Linuxボックスは指定IPアドレスに対するメッセージを聴取する。

別の重要な方法は、人手でネットワーク・カードを検出してコンフィギュアすることで、それには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  
これは、イーサネット・カードがクラスCクライアントであるIPアドレス 192.9.200.1 を聴くようにする。同時に、ifoconfig はまた起動インターフェイスを呈しするため使うことも出来る。これは次のようにする。
	ifconfig eth0 down
同じことがループバックにも当て嵌まる。
	ifconfig lo 192.9.200.1 up
	ifconfig lo down
'ifconfig' には、沢山のオプションがある。マニュアルに記載されている。

参照する必要のある別のコマンドはs netstat だ。これはネットワーク接続、ルート作成テーブル、インターフェイス統計、マスカレード接続、マルチキャスト・メンバーシップをプリントする。マニュアルに大量のオプションがある。

Kernel インターフェイス

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_init_module ファンクションへのそのエントリポイントを定義する。その名称を "rtl8139" としてこのデバイスをkernelに登録する。別の重要なファンクション rtl8139_initが、ダミイ・ファンクション rtl8139_open, rtl8139_stop, rtl8139_xmit をnet_device 構造体に挿入する。ダミイ・ファンクションではあるが、これらは、rtl8139 インターフェイスを果たすときはいつでも、少し仕事をする。rtl8139_open が呼び出されると、このルーチンは、netif_start_queueを呼び出すことによりそのドライバがデータを受け入れる準備を終わったことを知らせる。同様に、netif_stop_queueを呼び出すことにより停止する。

上のプログラムをコンパイルして使ってみよう。ファイル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)
これでダミイ・ドライバの書き方が良く分かった。rtl8139用の実際のドライバ・インターフェイスに移ろう。

PCI カードとそのインストレーション

ネットワーク・インターフェイスは構築したが、カードを探して初期化することは出来ない。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 をもまた使うことがある。詳細に見よう。

・vendorID は、16ビットレジスタで、ハードウエア製造者を識別する。Intelデバイスはvendor ID 0x8086などとなっている。
・deviceID は、別の16ビットレジスタで、製造者が選ぶ。このIDは、vendor ID と対になって、デバイスを特定する。
・各周辺装置はクラスに属する。クラス・レジスタは16ビット値でその最上位バイトが(デバイスの)グループを規定する。例えば、イーサネットはネットワーク・クラスに入る。
・サブシステムvendorID とサブシステム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_devicestruct 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国立工科大学で工学士課程を完了したばかりだ。

Copyright © 2003, Bhaskaran.
Copying license http://www.linuxgazette.com/copying.html
Published in Issue 93 of Linux Gazette, August 2003
 
 
 
 
 
Yacc - パーサ・ゼネレータ - パート2
By Hiran Ramankutty
 

1. 計算機 - 次世代版

これから述べる計算機は、if-then-elsewhile 構文を含んだ変更により遙かに複雑になった。加えて、構文解析中に構文ツリーを構築する。ツリーを横断して出力を得ることが出来る。ツリー横断ルーチンは二つの方法でおこなうことが出来る:

 ・ツリー横断の間にステートメントを実行しするインタープリータ、
 ・スタックを基礎にする仮想マシンのためのコードを作るコンパイラ。

物事をもっと具体的にするため、サンプル・プログラムを示す。

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 は、VARIABLEINTEGER トークンのためのパターンを含む。加えて、トークンは、EQNE などの二文字演算子により識別される。単一文字演算子は、それ自体として戻されるだけである。

yacc input file は、YYSTYPEyylval のタイプを次のように定義する

%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 ユニオンの中でexprnPtr に対し、及びINTEGERiValue に対して結合する。これは、正しいコードを作成するため不可欠である。例えば、ルール

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-ELSEIF 単純ステートメントより高い優先度を与える:

%nonassoc IFX
%nonassoc ELSE

stmt:
	IF expr stmt %prec IFX
	|	IF expr stmt ELSE stmt

8.結語
優先度で解決された競合は、Yaccの報告するシフト/還元と還元/還元競合の数には計数されない。これは、優先度仕様の間違いが入力文法のエラーを偽装することを意味する。優先度で容赦し、何かの経験が得られるまで、これらを実質的に「詳しい説明書」の形で使うのが良い考えだ。y.output ファイルは、パーサーが目的通り働いているか否かを判定するのに大変役立つ。
Yacc は、通常警告を出す。しかしエラーも生じる。"syntax error"などのメッセージは、エラーが起こった場所とどんなエラーか分からないままに放置する。エラー取扱は遙かに面倒なので、ここでは扱わない。

著者紹介:
私はコンピュータ科学工学の工学士最終試験に合格したばかりの、インドのKerala生まれの人間だ。

Copyright © 2003, Hiran Ramankutty. Copying license http://www.linuxgazette.com/copying.html Published in Issue 93 of Linux Gazette, August 2003
 
 
 
 
 
BackPage
By Jeff Tinsler
 
ウェブマスターのキイボードから
(要約)

Linux Gazette の今月号の体裁が少し変わったのに気付かれたと思う。ロゴやレイアウトの変更のほか、人事の異動もあった。Linux Gazette の編集者がいなくなった。Mike Orrはボランティア編集者として良い仕事をして呉れたが、少しましな就職先を探さなければならない。時々は記事を貰えると望んでいる。

記事の投稿と、発行の確認はSSC webmasterの仕事だ。

サイト全体を改装中なので、e-メールアドレスなど、細かい変更もあるかも知れない。

変更が進んだら、皆様からのご意見のフォーラムも設けたい。

Linux Gazetteがお役に立っていなければ是非お知らせ頂きたい。

SSC Webmaster

著者紹介: Linux Gazette とその他の SC サイトのウェブマスター。コスタリカ在住。

Copyright © 2003, Jeff Tinsler. Copying license http://www.linuxgazette.com/copying.html Published in Issue 93 of Linux Gazette, August 2003
 
 
 
  END