Linux Gazette 8月号
今月のLinux Gazette の内容
n今月のニュース
n仮想コンソールログインの自動化
n PCスピーカ用Kernelドライバの作成
n PerlとPostgreSQLの結合、パート2
n Perl の学習、パート5
nDCMAニュース:ロシア人プログラマ逮捕
nLinuxにトムキャットを搭載
n数値ワークベンチ
 
 
 
 
今月のニュース
▼▼▼ディストリビューション関連ニュース▼▼▼
SuSE
32ビットアーキテクチャ用SuSE Linux Enterprise Server インテルにより「ySAP.com用に普通に使用出来る」と認証 awardedされた。この資格獲得により世界中の会社がSuSE Linux 企業サーバー上でmySAP.comを利用しSAP AGからのサービスとサポートを受けることが出来るようになった。詳細は http://www.sap.com/linux/ を参照

SuSE Linuxは、ドイツ、シャットガルトのLinuxTag expoに専門的展開用新規Linuxソリューションを展示 presented した。"SuSE Linux Firewall on CD"はインターネットに接続された会社の重要データ及びITインフラストラクチャの保護を提供する。SuSE Linux Firewall はアプリケーション・レベルのゲートウエイでハードウエア・ソリューションの高安全性をソフトウエア・ファイヤウォールの柔軟性と組み合わせた。SuSE Linux Firewall はライブシステムと呼ばれ、OSをハードディスクにインストールする代わりに、読取専用CD-ROMから直接ブートすることが出来る。ファイアウォール・ソフトウエアをCD-ROM上で操作することは出来ないので、ライブシステムの安全性は高い。 ipchains チェイン・パケット・フィルタ設定のようなファイアウォール用コンフィギュレーション・ファイル書込禁止コンフィギュレーション・フロッピイ上に置かれる。

 

▼▼▼その他のニュース▼▼▼
今後の行事予定
 0'Reilly オープンソース会議          2001年7月23-27日
   カリフォルニア州サンディエゴ  http://conferences.oreilly.com/
 第10回USENIX セキュリティ・シンポジウム  2001年8月13-17日
   ワシントンDC         http://www.usenix.org/events/sec01/
 HP ワールド2001 コンファレンス & Expo    2001年8月20-24日
   シカゴ             http://www.hpworld.com/
 Computerfest                 2001年8月25-26日
   オハイオ州デイトン       http://www.computerfest.com/
 LinuxWorld コンファレンス & Expo    2001年8月 27-30日
   サンフランシスコ        http://www.linuxworldexpo.com/
 ブラッセルRed Hat テクワールド     2001年9月 17-18日
   ベルギー、ブラッセル      http://www.europe.redhat.com/techworld
 Linux Lunacy  Linux Journal、Geek Cruises共催  2001年10月21-28日
   東カリブ            http://www.geekcruises.com/
 LinuxWorld コンファレンス & Expo    2001年10月30日 - 11月1日
   ドイツ、フランクフルト     http://www.linuxworldexpo.de/
 第5回Linux年次ショーケース&コンファレンス   2001年11月6-10日
   カリフォルニア州オークランド  http://www.linuxshowcase.org/
 純粋e−ビジネス・ソリューションExpo  2001年12月7-8日
   テキサス州ヒューストン     http://www.strictlyebusinessexpo.com/
 Linuxビジネス Expo           2001年12月12-16日
   ネバダ州ラスベガス       http://www.linuxbusinessexpo.com/
 第15回システム管理コンファレンス/LISA 2001   2001年12月 2-7日
   カリフォルニア州サンディエゴ http://www.usenix.org/events/lisa2001/
 
Teamware とCelestix が協力
Linuxベースのサーバー装置供給者Teamware Group, と Celestix Networks GmbH., 全面的協定に署名した signed 。これによってLinuxグループウエア用、Teamware Office-99 が Celestix の" Aries" マイクロサーバーと共に販売される。新システムは無線規格をサポートするので小企業に提供される始めての無線グループウエアとなる。
PostgreSQL:象は忘れない

Open Docs Publishing は、本日6冊目の" PostgreSQL: The Elephant Never Forgets"と題するブックを8月第1週に出荷すると発表した。内容にはPostgreSQLの大衆版、PostgreSQL 企業リプリケーションサーバー(eRserver) とLXP アプリケーションが含まれる。これは会社に従来は高価なリレーショナル・データベース・マネージメント・システム(RDBMS)パケージに限られていたリプリケーション・サーバー、データバックアップサービス、災害復旧、及びビジネスコンティニュィティ・ソリューションを提供する。これ以上を望むのは無理だろう。ブックにはPostgreSQLの搭載手順、管理技術、利用法、基本プログラミング・インターフェイス、リプリケーション能力が含まれている。ブックは現在開発概観及びフィードバック用にオンライン online となっている。

Total Impactの新 "briQ"ネットワーク利用
 Total Impactの新ネットワーク利用コンピュータthe briQ 、重さ32オンス、がIBM の一番目のPowerPC Linux スポットライト特色製品 feature productとして選ばれたselected。特色ある製品としてbinQとその長所がIBMのMicroprocessing and PowerPC Linuxウェブサイト7月号に述べてある。ここ又はTotal Impactの websiteを見られたい。
LinuxWorldサンフランシスコの目玉は埋め込みLinuxソリューション

IDG World Expo の発表によれば、来る8月28-30日サンフランシスコで開催のLinuxWorld Conference & Expoの目玉は、埋め込みLinuxパビリヨンで入場者に埋め込み計算を教えることである。このパビリヨンのスポンサーは、Linux OSを埋め込み計算を通じて販売するベンダー中立販売会社Embedded Linux Consortium (ELC)である。

Linux Links

the Duke of URL に興味のありそうな以下がある:

・Pogo の$1000未満ペンティアム4Linux ボックス Pogo Verona P4の概観 review
・Trustix製Linux 、Windows用ハイエンドファイヤウォールTrustix XSentry Firewall 1.5の 概観 review 。この概観にはファイアウォールなどの技術が含まれる。
・Red Hat Linux 7.1 上のPromise FastTrak 66/100 に関するハウツー HowTo
・AbitのSiluro MX400 (GeForce2 MX400 チップセットに基づく) の概観 review 。概観にはLinux とWindows双方の性能のベンチマークを含む。
・セキュリティ、e−コマース、サーバーに重点をおいたEnGarde Secure Linux 1.0.1の概観 review
・Red Hat 7.0 に基づきPowerPC 用に設計されたYellow Dog Linux 2.0 の概観 review

ONLamp.com がApache 1.3から2.0までのサイト migrating に記事を出した。

The Wall Street JournalPersonal Technology セクションにWindows XP の不備に関するニュース News と論説discussion がある。

別の Microsoft ニュースはMSがLinux用NET作成に協力 help と報じる。マイクロソフト、オープンソース開発を用いるNETのLinux及びUNIX用バージョンを開発するMono Projectに関する事業につき Ximian Inc. に技術協力するとComputerWire に告げた。

 
▼▼▼ソフトウエア関連ニュース▼▼▼
Linux NetworX がClusterWorX 2.0 クラスタ管理ソフトウエアを立ち上げ
Linuxクラスタ計算ソリューションのプロバイダLinux NetworX,がクラスタ管理ソフトウエアClusterWorX 2.0の打ち上げを発表announcedした。 ClusterWorX の最新版は確実なリモートアクセス、徹底したノード監視とイベント監視、及び容易なカスタマイズのなどの特徴を備える。
IBM データベースニュース
IBM が、先ず三つのデータベースの権利を主張したclaimed 。Industryの First Database Software Supporting InfiniBand、 Direct Access File System; 及び、新しいイタリア語ベースのSystemsDB2 Universal Database バージョン7.2である。これらは、Linux上で走る DB2の上でデモンストレートされている。
DocParse HTMLから XML/SGMLへのコンバータ

Command Prompt, Inc. は、大量のHTMLベース文書を保管する技術者用のツール DocParse 0.2.6. をリリースした。DocParseは、どんなHTML文書でも、有効な記録文書XML/SGMLに転換する。ユーザーは、文書をXML又はSGMLフォーマットから、XHTML, HTML, RTF(MS Word のフォーマット)に転換することが出来る。Docparseは現在、x86 Linux上のみで働いている。近くYellowDog Linux (PPC) とMacOS Xを発表する。.

Linux及び Solaris 用StuffIt 出荷

Aladdin Systems, は、Linux及びSunのSolaris 用の圧縮ソフトウエアStuffIt を出荷した。これで、StuffIt がWindows, Macintosh, Linux, Solarisのプラットホームで使えるようになった。Linux及びSolaris 用StuffItは、Zip, StuffIt, Binhex, MacBinary, Uuencode, Unix Compress自動拡張アーカイブをWindows 又はMacintoshプラットホーム用に作ることが出来るので、上記全部の他にbzip ファイル, gzip, arj, lha, rar, BtoAtext 、Mime.を拡張することが出来る。Linux用Stuffltは http://www.stuffit.com/からダウンロード出来る。

Great Bridge が強化 PostgreSQL 7.1 パケージを発表

Great Bridge, は本日、世界最大のオープンソース・データベースGreat Bridge PostgreSQL 7.1 の立ち上げを発表した。Great Bridgeは、リリースには、グラフィカルインストーラ、主なデータベース管理ツール、専門文書、インストレーションとコンフィギュレーションのサポートパケージがパケージになっていて、アプリケーション開発者がPostgreSQLの威力を迅速且つ容易にデータベース駆動アプリケーションに発揮出来るようになっている。

Timesynchro
Timesynchro.com は、システム時間を管理するのに使われる無料ユティリティをダウンロード用に持っている。これは本質的に、ダイアログと若干の標準スタッフを用いたnetdate用コンフィギュレーション・スクリプトである。サーバー100個のデータベースを組み合わせて接続し、そのプログラムがサーバーを試験して、実際に使用する前に加除する。'timesynchro' をスタートすると、ドイツ語でスタートするが、"Sprache" を選ぶと英語に切り替わる。タイムサーバーを選ぶ簡単なメニュー構造もある。
Surveyor Webcamsat
webcam ソフトウエアWebCam 32のメーカーSurveyor Corporation,は、webcamサーバーのファミリーを発表した。Webコンテント制御のニーズが高まったの応じたものである。webcamサーバーのファミリーSurveyorのWebcamsatにより、ウェブサイト管理者は、その上を流れるオーディオ及びビデオの管理が容易になる。
Kaspersky Labs ウイルス防止ソフトウエア

Kaspersky ウイルス防止の最新版により、カスタマは、OpenBSD (バージョン 2.8) とSolaris 8 (Intelプロセッサ用)上で働くファイルサーバー及びアプリケーションサーバー用、及びe-メール検査ゲートウエイ用に、集中ウイルス防止を追加してインストールすることが出来る。このウイルス防止パケージの開発は、UNIX特にLinuxを使う中規模、大規模企業の要請による。

現在, Kaspersky Anti-Virus は、Linux, FreeBSD, BSDi, OpenBSD, Solaris のOS上で使うことが出来、sendmail, qmail, postfix, 及びexim e-mail gateways用の既製ソリューションを含む。パケージは、スキャナ、daemon及びモニターウイルス防止技術を含み、インターネットを通じるウイルス防止データベース自動更新、統計データ作成処理用相互作用パラメータ設定シェルをも含む。http://www.kaspersky.com/ (ロシア)

 

Copyright © 2001, Michael Conry and the Editors of Linux Gazette.
Copying license http://www.linuxgazette.com/copying.html
Published in Issue 69 of Linux Gazette, August 2001
 
 
 
 
仮想コンソールを自動的にログインしよう

By Bryan Henderson

 

Linuxをブートするとき、使用者が自分一人のときでも、沢山の仮想コンソール上の "login:"プロンプトで、毎回使用者名やパスワードを入力していないか? 止めようじゃないか? ブート毎にコンソールをログオンすることが出来る。

安全のためパスワード入力が必要と思うなら、考え直せ。君のコンソールにアクセスする奴は、フロッピイディスクにもアクセスして、自分のシステムディスクを入れれば、忽ちログオン出来る。パスワードは魚に傘をさしてやるようなものだ。

緒言

これから述べるコンソール自動ログイン法は、あるソフトウエアの搭載と、/etc/inittabに数行追加することから成る。その前に、Unixがログインを受け入れる方法を説明して、君の目を覚まして貰う。

先ず明らかにしたいのは、私が仮想コンソールを問題にしていることだ。これは、君が普通にALT-F2 やCTL-ALT-F2 などを押して切り換えるテキストコンソールだ。グラフィックデスクトップのウインドウで見るシェルとは、全く違う。これらのウインドウは自動的に出て来るが、プロセスは全く違うので、この記事では扱わない。

また、シリアルターミナルを扱う。仮想コンソールについてこの記事で述べると同じ技術が、シリアルターミナルにも通用するが、ターミナルにはボーレートやパリティなどが必要なので、一寸したひねりが必要だ。。

ログインの働き

歴史的背景

古いUnixシステムでは、コンピュータは鍵の掛かった部屋にあり、ユーザーは、シリアルポートに繋がれた別の部屋のターミナルからアクセスした。システムが現れると最初に、識別情報を(我々はCRTの後ろにいますと、本当だよ!)プリントして、ログインを催促した。コンピュータを使いたい人は、これらターミナルの一つをウエークアップさせ、使用者名、パスワードを入れて、はじめてシェルプロンプトを得、ログイン出来た。

今でも、Linux仮想コンソール上で同じものを見るが、歴史を知らないと意味が分からない。

Getty

ここでLinuxのブートプロセスと、ログインプロンプトの出る方法を調べる。

最初にLinuxをブートすると、Kernelが init プロセスを作る。これはどのLinuxシステムにもある最初で最後のプロセスだ。Linuxシステムのあらゆるプロセスは init 又は init の子孫のいずれかを用いて作られる。

init プロセスは、通常 Sysvinit などと呼ばれるプログラムを走らせる。任意の実行可能プログラムをLinuxブートパラメータの中で指定して、 init として走らせられることは、覚える価値がある。だが、規定値は実行可能 /sbin/initで、通常はSysvinitである。Sysvinitはその命令をファイル /etc/inittabから受ける。

init の働きを見るには、 man initman inittab をおこなう。.

/etc/inittab を覗くと、各仮想コンソールに1プロセス宛て、gettyプログラムを走らせる沢山のプロセス開始を告げる命令が見られる。下記の例は、/etc/inittab の中の、仮想コンソール/dev/tty5上でgettyを走らせるプロセスのスタートを init に告げる行である。



   c5:235:respawn:/sbin/agetty 38400 tty5 


この場合、特定のgettyプログラムは /sbin/agettyである。君は多分、/sbin/mingettyか又は別のプログラムの束の何れかを使っているだろう。(プログラムが何であろうと、名前は "getty" の筈だ。 "get teletype" から来ている。)

Gettyは規定のターミナルを、そのプロセス用に、標準入力、標準出力及び標準エラーファイルとして開く。また、そのターミナルを、プロセスの「制御用ターミナル」として指定し、安全のためターミナル装置の所有権と許可を設定する。

これで、仮想コンソール /dev/tty5 がログインプロンプトを得る方法が分かった。Kernelは、Sysvinitを走らせて init プロセスを作る。Sysvinitは、 /dev/tty5を識別するパラメータを用いて、/etc/inittabファイルの指示通りgettyプログラムを走らせる別のプロセスを開始する。gettyプログラムは /dev/tty5上に「login」をプリントして、誰かが何かをタイプするのを待つ。

Login

gettyのログインプロンプトに応答した後、gettyはプログラムloginを実行する。(実際は、自分で選んだ勝手なプログラムをgettyに実行させることができるが、/bin/loginが普通である)つまり、getty 自体が login に代わるが、同じプロセスである。

このプロセスは、スーパーユーザーの所有する init が作ったことに留意されたい。だから、loginを走らせるプロセスもスーパーユーザーが所有している。

login が先ずおこなうのは、パスワードを聞くことである。タイプすると、login は正否を判断する。正しいとすると、loginは次のことをおこなう。

・プロセスの所有ユーザーidを君に対して設定
・プロセスの所有グループidを君のグループに対して設定
・ユーザー・アカウント・データベース( "utmp"ファイル)に、君がログインしたことを記録。このデータベースは、今日では技術的に不要だが、whoのような古いプログラムで、誰がどのターミナルにログしたかを告げるため使われている。
・プロセスの補助グループを、君の所属するすべてのグループに設定。
・プロセスの現在作動中ディレクトリを、君のホームディレクトリに設定。
・君をターミナル装置の所有者にし、その許可を適切に設定。

次ぎに login がおこなうことは、君のシェルプログラムの実行だ。(これは実際はどんなプログラムでもよいが、通常はコマンドシェル、つまり/bin/bash)つまり、自分をシェルプログラムで置き換える。

loginはファイル /etc/passwdの中の君の名を見て、パスワード、ID、シェルプログラムのような必要情報を見出す。

シェル

シェルは進んで、システムシェルプロファイル(/etc/profile) と君の個人プロファイル(一般的には君のホームディレクトリのファイル .profile)を走らせ、最後にコマンドプロンプト($または%)をターミナル上に示す。ここまでが、ログインと君が考えることで、説明はここで終わる。

ログインの自動化

よし、分かった。だが、この記事の目的は新型の自動ログインだ。

目標は、使用者名とパスワードプロンプト無しで、init, getty, login,とシェルがおこなうこと全部をやらせることだ。

それには沢山の方法があるが、私は簡単にするためプログラムqloginを書いた。qloginは、gettylogin.の機能を果たす。これはgettyのようにinit,に呼び出され、最後の作用はlogin.のようにシェルプログラムを呼び出すことだ。

そこで、これをセットアップするためなすべきすべては、上に示した /etc/inittab 行を、次のようなものに置き換えることだ。



   c4:235:respawn:/sbin/qlogin /dev/tty5 bryanh 


これはブート時に、使用者名 bryanh を仮想コンソール /dev/tty5 に、プロンプトからの入力に代えてログインする。
上の行の "respawn" は、プロセスが終わる時期を示し、init がこれに代わるものを作ることに注意。昔のUnixシステムでは、君が君のシェルからログアウトした時期を意味し、これでプロセスが終わり、新しいgettyが走って、ターミナルは新しいユーザーのためログインプロンプトを得た。 qlogin の場合は、君が君のシェルからログアウトした時期を意味し、直ちに新しい人が来て置き換わる。したがって、君のログイン中の沢山の仕事をリセットしたいときは、logoutとタイプすれば良い。

ゆっくりとスタート

多分 qlogin を搭載する必要はなく、そのときは/etc/inittab の中で、君のgettyをqlonginのものに変え、再ブートして結果を見れば良い。少し楽観的だが、

多様なのが良い

先ず最初に、君の仮想コンソール全部を決して qlogin に変えないことを薦める。少なくとも一つのコンソールで、試行錯誤でgetty/login を決め、qloginに何か不都合があったら、別の仮想コンソールに移って修復するようにする。また getty またはloginで不都合があったら、qlogin 経由で別の仮想コンソールに入ることが出来るようにする。

シェルから走らせる

/etc/inittab をエディットしてinit 問題で悩む前に、 qlogin をシェルから走らせて、何をしているか信じなければならない。 qlogin の働きを自分の目で確かめること。init,に伴う問題は、壊したくない重要なプロセスであることの他に、思った通りに動かない理由を告げるメッセージを出す標準エラーファイルがないことだ。

通常、何か不具合だとの init からの情報は、「"id X spawning too fast. Disabled for 5 minutes." だ。その意味は、君が走らせるよう init に命じたプログラム(例えばqlogin)が不具合なので、直ちに終わる、だ。これは「再生産」登録なので、 init は同じプログラムを走らせる新プロセスを単純に作る。このプロセスが繰り返しスタートして衝突する。initはそれに気付いて「再生産」を5分保留して、誰かが問題を解決するのを待つ。だが、何故直ぐに衝突したが、プログラム以外は誰も知らない。だから通知はない。

だから、 qlogin をシェルプロンプトから、init 呼出と同じアーギュメントで呼び出すだけにすると、衝突があったとき qlogin はエラーメッセージを出す。

勿論、 qlogin を呼び出すシェルは、スパーユーザー・シェルであるのが望ましい。でないと、どんなメッセージが出るかを、ここで述べる。

一つの違い − ターミナルの制御

qlogin をシェルから走らせるカラクリは、ターミナル制御の問題だ。qlogin を使ってログインするプロセスは、入出力ターミナルとして指定したターミナルを使が、その制御ターミナルは、正に" qlogin"とタイプしたターミナルだ

違いの理由はこうだ。君がLinuxプロセスであると、入力用にターミナルを開いて、まだ制御ターミナルを持っていないとき、そのターミナルが君の制御ターミナルになり、それを保つ。init は制御ターミナルを持たないし、qlogin チャイルドプロセスもそれを作らない。しかし、ログインシェルはそれを持っている。だからシェルプロンプトでコマンド(qlogin など)をタイプして作ったチャイルドプロセスも同じだ。

違いの分かる場所は、Control-Cをタイプしたときだ。何もしない。標準入力装置でタイプしたControl-Cは、入力流にControl-Cを含む以外何もしない。だが、制御ターミナルのControl-Cは、ターミナルにつながるフォアグラウンド・プロセスに、おなじみのプログラム終了効果を生じる、SINGINT信号を得させる。

言っていることは、/dev/tty1 上で qlogin /dev/tty5 ... とタイプして /dev/tty5 にログインするのであれば、 /dev/tty5 上の Control-C は何の効果もない。同じqlogin /dev/tty5 ... コマンドを/etc/inittab に入れてから /dev/tty5 上に Control-Cを入れると働く。

注記:偉そうに言うと、Control-Cと言ったとき、ターミナルのTTY特性が「Control-Cは中断文字であると設定してあると仮定した。中断文字を他のものにするか、または全く持たないに stty をを用いることが出来る。

Qloginについて

qlogin は、 ibiblio.org から入手したインストールする必要がある。簡単なインストラクションがついている。必須要件は User::Utmpと呼ばれるPerl拡張だ。これも無いだろうから、インストラクションしたがって入手の上インストールする必要がある。

qlogin はPerlで書いてあるので、簡単にユーザーログインのステップが分かる筈だ。自分の好きなように改訂も出来る筈だ。

qlogin が素晴らしい点の一つは、基本的なのでコンフィギュレーションファイルが要らないことだ。コマンド行パラメータだけで、ささせたいことを命令することが出来る。/etc/passwd ファイルを上書きしても良いし /etc/passwdにないユーザーでもログイン出来る。君の自由だ。

qlogin のオプションを見よう:

--command
"command" (プログラムやアーギュメントを言うややずぼらな方法)は qlogin を出た後走らせる。 /bin/bash が典型的。
--arg0
qlogin を出た後走るプログラムのためのアーギュメント0で、 ps ディスプレイに示すもの。
--uid
プロセス用数値ユーザー id 。
--gid
プロセス用数値グループ id 。
--homedir
プロセス用ホームディレクトリ及び初期カレント実働ディレクトリ
--utmp/--noutmp
ユーザー計数データベース(utmp file)のセッションで qlogin がログするか否かを決定。

また qlogin アーギュメントは、プロセスのため使うターミナル装置を規定する。

qlogin 使用上の詳細は一緒いついて来る文書にある。

Qlogin を使って出来る他のこと

各種仮想コンソール上にログインシェルを自動的に出す方法が分かった。だが一寸手を加えると、一定の仮想コンソール上またはシリアルターミナル上で、他のプログラムを走らせることが出来る。常に top システムモニタを走らせる仮想コンソールを考えて見よう。



  qlogin /dev/tty5 root --command=/bin/top --noutmp


と言うだけだ。システムが店頭のPOSシステムであるとすると、ターミナルは勘定場のシリアルターミナルになる。勘定人は、Linuxへのログインもシェルを見ることもしたくない。POSプログラムが /usr/local/bin/pos であるなら、次のようにする。



  qlogin /dev/ttyS1 cashier --uid=500 --gid=500 --command=/usr/local/bin/pos


      --arg0=POS --homedir=/


この場合、pos プログラムは多分、ボーレートの設定など、いくらかシリアルポートを初期化しなければならないだろう。在来のUnixログインモデルでは、ログインプロンプトを出す前に getty がこれをおこなう。
フォアグラウンド・プロセス
[エディタが Bryan に聞いた「システムには、フォアグラウンド・プロセスの考えが無いようだ。それはシェルの幻想だI。答はここにある。 --Iron]

Bash文書を読んだ故か、私はこう考えていたが、Linux kernelは「フォアグラウンド・プロセス・グループ」を定義しており、制御ターミナルはすべてフォアグラウンド・プロセス・グループを持っている。規定値では、最初にターミナルを開いたプロセスのプロセス。グループだ。しかし、プロセスは、iocltを用いて、任意のプロセスグループに、セッションの中で、フォアグラウンド・プロセス・グループを設定することが出来る。

記事の中で私は「フォアグラウンド・プロセス」を「フォアグラウンド・プロセス・グループの中のプロセス」と勝手に解釈して引用した。

フォアグラウンド・プロセス・グループ(Kernelエンティティ)の唯一の重要性は、そのプロセスグループの中のプロセスが、control-C を受けて信号をハングアップすることだと考える。

Bashのジョブコントロールは、君の「フォアグラウンド・ジョブ」が何であろうと、この ioctl を君のターミナルのフォアグラウンド・プロセス・グループ作成用に使う。君がバックグラウンドに、"grep abc * &"のような何かを置いたとき、control-Cがそれを殺さないのは、この理由による。殺したければ、"fg" をして、Bashにそれをフォアグラウンドにioctlさせ、それからControl-Cとしなければならない。

数年前に、Webの前でターミナルがもっと重要であったとき、私は、Kernelコードと格闘してプロセス・グループ、セッション、制御ターミナル、ジョブコントロール、SIGINT, SIGHUPなどを経験した。これには、長い記事が書けるが、難しいだけだと思う。

 

Copyright © 2001, Bryan Henderson.
Copying license http://www.linuxgazette.com/copying.html
Published in Issue 69 of Linux Gazette, August 2001
 
 
 
 
PC スピーカ用 Kernelドライバの作成

By Cherry George Mathew

Originally published at Linux.com (article URL)
Reprinted with permission from Linux.com and with revisions by the author

 

自分で何かを作ることに興味のある人のため、この記事を書く。

PCスピーカからロックミュージックを出そうと決心した。(スピーカはPCの箱の中にあって外から見えず、馬鹿なことをしたときビープする奴)本当の音楽を演奏させたかったが、音符を書いて、mp3などにコード化する気はなかった。そこで怠けて、Linux用ゲームを演奏することにした。

初めての町をうろつくようにさまよった末、ダウンロード出来るPCスピーカドライバに辿り付いた。ftp://ftp.uk.linux.org/pub/people/dwmw2/pcsp/(Michael Beck作。David Woodhouse 保守 http://linux-patches.rock-projects.com/v2.2-d/pcsp.html 参照)。Kernel再コンパイルが必要と理解した。

PCスピーカ:背景

内部スピーカは、すべてのPC上8254タイマーチップのバッファ付き出力に接続されている。チャートで示すと、次の通りと考える。

PICがプログラマブル・インタラプト・コントローラに代わる

8254の基本クロック周波数は、今のところ、標準NTSC周波数の1/4の1193180Hzである。カウンタは、除数の値を持っており、乱暴に言うと、基本周波数分割に使われる。だから、カウンタ0=1であれば、チャンネル0の出力は周波数1193180Hz、=2なら596590Hz などとなる。したがって、カウンタ=0 =>PICがプロセッサにインタラプトする正確な周波数18.2Hzである。DOSでは、PICはベクトル8にあるインタラプト・サービスルーチン(ISR)を呼び出すプログラムになっている。

効果の上で、これは、カウンタ0の値がタイマーISR(DOS内のベクトル8)が呼び出される周波数を定めることを意味する。カウンタ0を変えると、タイマーISR呼出速度が変わる。したがって同一人物がISR用と、8254タイマーチップのカウンタ0プログラム用のコードを書くと、そのISRは、望みのままに所定の速度で呼び出される。

これらすべてが、別の脇道に導く。

脇道:デジタル・オーディオ

音には音源があって、音源は振動する。音源がスピーカの場合は、振動電圧が加わる。デジタルとは1と0の数字を意味する。これらからデジタル・オーディオが出来上がる。

ブーンと言う音を想像すると、それは下図のような連続正弦波である。

数字は、各瞬間の音の強さを示す。この数値が必要な波を作る値のサンプルである。1-3-7-から-6-3-1の全部の数値を1秒間に発生すると1Hzの音が出来る。正弦波の形を滑らかにするにはサンプルの数を増やす。サンプル数を44000にすると、CDプレーヤがDAC(デジタルアナログコンバータ)に吐き出す数になる。これは1と0のバイナリ数を、時間と共に代わる電圧に変える装置だ。ここまでの方法は、パルスコード変調と呼ばれる。パルスのコード化には他の方法もあって、PCM、ADPCMなどがある。上の波形はサンプルレート「14Hz、4ビット、符号付きモノPCM」と呼ばれる。

1ビットDAC

これらがPCスピーカに、どんな意味を持つか? これはタイマーISRを44000Hzに設定すると品質の良い音が聞けることを意味する。各サンプルを対応するアナログ電圧に変えるDACがあれば良い。実際パラレルポートDACはこれを行っている。抵抗のR-2Rラダーネットワークを組んで出力をまたいでコンデンサを結び、任意のアンプ、マイクでもよい、に繋ぐだけでデジタル音楽が得られる。

PCスピーカではこれ程簡単ではない。PCスピーカはDACではなく、タイマーチップに接続されているからだ。タイマーチップの、例えば正弦波に関する出力を見てみよう。

一つは+5V、他は0vの二つの値があり、その間はない。どうやってアナログ波形を得るか? 不可能だ。IBM技術者でも出来まい。

だが、かすかな解決策がある。技術用語では、1ビットDAC、チョッピングなどだ。

アイデアは、PCスピーカコーンを、マークまでスムーズに動かせない時のバーストで動かすことである。22kcでは、コーンは全く怠け者で、なかなかマークまで上がらないのを思い出されたい。真ん中を過ぎると、やり過ぎてコーンがオーバーシュートロードになったように少し休む。元に戻るのに時間が掛かる。自動車のアンチロックブレーキのようなものだ。ブレーキペダルを半分だけ踏むと、メカニズムがブレーキを交互に踏んだり離したりする。ペダルの上に立っていると、ブレーキシューは車輪ドラムに着かないで、変なペースで叩いている。だから車輪はロックされない。同じように、君が+5vパルスで、スピーカコーンを頻繁に叩くほど、センターラインから遠くに動く。当たり!パルスの周波数を必要な振幅にしたがって変えて見よう。このアイデアが全く新しいことを覚えるため、私はこれをDOS版 fm.com と名付ける。

ここで最初の図に戻って、8254のカウンタ2を見てみよう。何処に行っている?勿論、PCスピーカだ。そこで、リアルな音を得るためなすべきことは、サンプル値(値=>PCM内振幅)に比例した大きさ(1<カウンタ値<65535を思い出せ)に減衰することだ。平凡なタイマーISRの中から、誰がこれをやるか? myaudio.hの中のmyhandler()ファンクションを見てみよう。

クイズタイム!!!
smpl1  smpl2  smpl3
_______  ___    _
|       | |   |   |  |
|       | |   |   |  |
|       |_|   |___|  |_____

smpl1, smpl2 ,smpl3 の値を当てられるかな?

Linux、やっと辿り着いた!

Linux kernel は、うまく出来た面白いプログラム作品で、アセンブリ言語を殆ど知らない人でも沢山のKernelコードが書ける(Kernelの99%は"C"で書いてある)。またこれは、デバイスドライバを書く人に、現在の環境とコードを書くのに余すところのないインターフェイスを与える。

kernelコードは移植可能だ。つまり色々なマシン(i86, alpha, sparcなど)でコンパイル出来る。コードのテンプレートを書くのが合理的だと思う。それをハードウエア毎に磨き上げればよい。例えば、選択の手順を1)洗濯機の電源コードをコンセントに指す。・・・・・n)洗濯物を取り出して、物干し竿に掛ける。と書くようなものだ。

.1)からn)までの手順は、縦型か横型か、自動脱水か否かなど、洗濯機の型により違うだろうが、君の洗濯手順は一つで良い。だが、あらゆる型の洗濯機を含む、万人向けマニュアルを書くとしたらどうだろう。

PCM(パルスコード変調)及びコード化PCM音源の規定インターフェイス、 /dev/dspデバイス・インターフェイスの場合を考える。Hannu SavolainenがAlan Coxの協力で沢山のインターフェイスを設計した。だが、彼らはPCスピーカと言う小さい部品に、AWE64などを利用する余地を与えなかった。DSP装置はすべて最低でもDMA(Direct Memory Access は周辺装置がプロセッサを介しないでRAMと直接データのやりとりをする技術)サポート又はボードバッファを持つと想定した。だから、OSS APIの主要部品としてDMA登録コードを置いた。OSS APIは、soundcore.oが移出するものと、sound.oが移出して設定するものと、二つのレベルの移出ファンクションを持つ。

sound.oはsoundcore.oのトップに積み上げられ、他のデバイスドライバと殆ど同様の移出ファンクションを用いる。これは移植可能デバイスドライバに容易なインターフェイスを提供しDMAアクセスのような最新ファンクションをサポートする。(最新サウンドカードは少なくともDMAをサポートする)

ここから我々の腕前を発揮する。標準OSSインターフェイスを無視して、サウンドコア・インターフェイスを直接利用しなければならない。つまり別の技術論議−Linuxのキャラクタ・デバイス−が始まる

Linuxのキャラクタ・デバイス

Linuxには2種類の主なデバイスがある。ブロックとキャラクタだ(ネットワーク・デバイスは無視する、デバイスより、インターフェイスに近いからだ)

ブロック・デバイスは、ブロックでの読取書込、バッファ、パーテティションのような特性を持つと思われる。固定ディスクドライブはブロックデバイスの完全な例だ。アプリケーションはファイルシステムドライバを通じてハードドライブにアクセスする。これがUNIXのディスクドライブを取り付けて、セクター毎にアクセスしない理由だ。

キャラクタ・デバイスは、一時に1バイトだけ読取書込をするが(例えばシリアルポート)、システムのスループット改善のため透明にバッファされる手段だ。アプリケーションは、通常、対応するデバイスノード上でこれらにファイル操作をおこなって、アクセスする。デバイスノードは、通常のパストリーを通じてアクセスすることの出来る特別の「ファイル」だ。だから、音響デバイスに書き込むときは、慣習上/dev/dspがそのための公表デバイスノードとなる。そのドライバにアクセスするには、ドライバが登録したデバイス番号に相当する任意のデバイスノードを使えることに注意。例えば、/dev/dspノードはデバイス番14/3に付着している(君のシステムでファイル/dev/dspを試してご覧)/dev/mynodeが14/3を指していると、/dev/mynodeを経由してアクセスすることが出来る。正確な文法は mknod マニュアルを参照されたい。

さて、特殊なフォーマット、例えば16ビット、ステレオ、raw pcmの .wav ファイルをシステムサウンドデバイスで演奏させようとするとき、オープン・ システム呼出を用いて /dev/dsp ノードを開いて.wav ファイルを開き、それそれ読取書込システム呼出を用いて.wav ファイルからブロックで読取って、/dev/dsp に書込むだろう。あーあ!どんなクライアントが、これを容易くやってのけるだろう。それに、余程運が良くない限り、正しい音は聞けない。サウンドドライバに、生データのフォーマットを告げる必要があるからだ。44khz、16-ビットステレオファイルを8khz、8-ビットモノラル・ドライバで演奏するなど、良くあるが、LPディスクも間違ったターンテーブルに乗せるようなようなものだ。

デバイスドライバに告げるには、/dev/dsp上で ioctl (input/output controlの略) システム呼出を使う。残念ながら、ioctlの正確な文法はデバイスドライバを書く人の自由だ。DOSソフトウエア市場のカオスみたいなものだ。有り難いことに、Linuxでは少ないながら認められた慣習がある。最も有名なのはOSSつまりOpen Sound Systemだ。これはSavolainen & CoがLinux上で実行した。だから、我々はアプリケーション側でOSS用XMMSプラグインがあり、Kernel側にデバイスドライバのスコアを持っている。

Kernel

アプリケーションがシステムコールをすると、確かに何かを呼び出す。その何かは、Kernelルーチンだ。Kernelは、相当するドライバに呼出を送る。Linux kernel の素晴らしいところは、Kernelに特定のデバイス番号で君のルーチンの呼出を命じられることだ。登録と呼ばれ、Kernelモードの呼出だ。つまりこれら呼出をおこなうアプリケーション書くことも、ターミナルから走らせることも出来ない。同様に、自分のカスタム登録ファンクションを設計し移出すれば、Kernelを遊ばせてユーザー呼出を追加ルーチンに渡すことが出来る。これは正に、soundcore.o がregister_sound_dsp()経由でおこなっていることだ。(今はお聞き召さるな、OSSサウンドモジュールに飛び込んで見れば、プールに水があることが分かる)。それにはinsmodを使って、Kernelモジュールと呼ばれる特別プログラムを書く。このinsmodをKernelスペースにロードしてKernelシステム呼出にリンクすることが出来る。システム呼出とKernel呼出の主な違いは、システム呼出は、Unix部品として認められたかとの一般慣習に合致しなければならないことだ(Linux とは何かFAQを思い出せ)。他方、KernelはLinuxだ。だから、KernelプログラミングでしたがうのはLinux慣習で、Linux Kernel慣習はKernelリリースにより何回も変わっている。多くのモジュールバイナリのリリースに「pre-x.xx.xバージョンコンパイルのみ」の警告があるのはそのためだ。オープンとクローズの他に、最小限、読取と書込の各呼出ルーチンを持たなければならない。Linux Kernelはinit_module と言うルーチンとcleanup_moduleと言うルーチンを規定し、モジュールの挿入と削除にはKernelがこれらを呼び出す。(ユーザースペース内のmain()に似ている)言い換えると、init_moduleルーチンを書くときは、システムポート、メモリなどを完全に制御していることと、、利用出来るKernelファンクション全部を呼び出せることを確認する。別の面白いことは、Kernel又はモジュールファンクションはいずれも、Kernelシンボルテーブル(リストについてはinit_moduleを調べよ)移出できることだ。だから、別のKernelファンクション又はモジュールから呼び出せる。言い換えると、Kernelプログラムファイル、/boot/vmlinuzは、皆がCプログラムを書くときのように、main()から始まるCプログラムであった。括弧の後の行は、 Linus Torvaldsと呼ばれる天才的システムプログラマだけが満たした。

我々のドライバの登録

全体のうち最も重要な部分は勿論コード自体だ。ドライバ登録はsoundcore.o モジュールが移出したregister_sound_dspファンクションを用いておこなう。これは、前に説明したが、標準OSSディストリビューションの一部だ。やることは、ユーザースペース・アプリケーションからのオープン呼出を通過させることだ。多くのコードは自明だ。GNUアセンブラ(元はAT&Tアセンブラフォーマット)は、フッキングと共にタイマーインタラプトをしなければならない。setvect とgetvect ファンクションはDOSと殆ど同じことをする。

実働デバイスドライバに向けて

目的は、8254タイマーポートを通じてPCスピーカにアクセス出来る実働デバイスドライバを作って、アプリケーションの音響データをPCスピーカにバイト毎にコピイする作用をさせることだ。

OSSは /dev/dsp と言うデバイスノードを我々のために作る。myaudio.oと呼ばれる我々のドライバはinsmod myaudio.oを使って実働Kernelにロードし、rmmod myaudioを用いて削除することが出来る。 /dev/dspはinsmodの後、我々のドライバを指す。

プログラム構造を見よう。しなければならないステップは:

1) 我々の捏造 dsp デバイスの登録. 2) タイマー・インタラプト・ベクトルをフックしてインタラプトを実働サンプリングレートに設定. 3)チェッ! と言うメッセージをプリントする。 何かしくじったときKernelはそれを告げる。多くの場合システムを再ブートする。

デバイスをアンロードしたときは、次のステップでシステムを前の状態に復元する:

4)タイマー・インタラプト・ベクトルをアンロックして、インタラプトを元の状態に戻す5) dsp デバイスの登録解除 6) 成功メッセージをプリント。

myhandler()の一瞥

サンプルコードは、myaudio.c とmyaudio.hと言う二つのファイルに入っている。myaudio.c は、上述の課題全部をおこなうデバイス登録ルーチンを含む。myaudio.hは、ISR (Interrupt Service Routine)という極めて重要なルーチンを含む。これをmyhandler()と名付ける。上述のステップは myaudio.cのコード解読に役立つと思う。myaudio.h詳しくはmyhandler()を説明する。

上のステップ2)は「タイマー・インタラプト・ベクトルをフック」となっている。これは、ISRが、目的とするサンプリングレートで正確に実行されるように設定されることを意味する。これは、コードをISRに書くとき、以下を合理的に確信出来ることを意味する。a)ユーザーアプリケーションからの次のデータが、入手出来れば、取り出される、b)これは8254カウンタ2の値(詳細は上述)で進行する必要がある、3)このカウンタ値は8254カウンタ2レジスタにダンプされる、つまりPCスピーカのための遅延が取り出したデータの値にしたがって設定される、d)システムスケジューラは未だ呼び出されていない!呼び出すか否かを決める。

ステップ d) は他に下記を必要とする:

myaudio.cの中のsetvect()を読むと、setvectが幾つかのカラクリを使ってmyhandlerをシステムベクトルテーブルに入れているのが分かるだろう。これは、インテル386+特有だ。8086作動のリアルモードでは、ISRを再ベクトルするのに必要なのは、メモリアドレスで0000:0000から4バイト増し分で増加する(8086で完全に有資格のポインタは32ビットだから)インタラプトベクトルテーブル(IVT)内に対応する登録をセーブすることである。言い換えると、PICの、IRQ7に関する規定値BIOS設定である、インタラプト8のため、0000:0020にあるポインタ値をmyhandler()の完全アドレスに変えるだけである。物事はここで一寸複雑になる。Linux Kernelの走る368+プロテクトモードでは、IVTはIDT(Interrupt Descriptor Table)と呼ばれる。IDTの説明は膨大になるが、博士論文でも書くつもりなら368+プロテクトモードを知っている筈だ。本当に知らなければならないのは、myhandlerへのポインタは8バイト領域に分散されていることだ。この情報は、優れたGNUアセンブラステートメントを用いてまとめて、元のISRメモリポインタを作り、これが今やmyhandler()を指すシステムSCHEDULER (多目的OSに必要な特別プログラムルーチン) を実際に指す。SCHEDULERの役目は、制限時間が来たとき一つのプログラムから制御を剥ぎ取って、次ぎに制御を渡すことだ。これをプリエンプティブマルチタスクと言う。Linuxでは、プロセスに与えられる時間制限は10ミリ秒だ。タイマーが呼び出される規定値レートを当てられるかな?Linux KernelでHZと呼ばれる値だ。

ここでの収穫は。元のISR(scheduler) が100Hzで呼び出されるのに対し、我々のISRはサンプリングレートでの呼出。通常22Khz、を必要とすることだ。また、元のISR呼出を無視すると、全部がルーズになろうとする。簡単な解決策待機がある。君が呼び出されたレートと、元のISRを呼び出すレートを知っていれば、一度宛て何度も呼び出せばよい。言い換えると、22Khzで、その度にカウンタを増やして、カウンタが220になったとき古いISRを呼び出すか、そうでなければ、EOI(End Of Interrupt)をPICに送る。こうして古いISRは正確に100Hzで呼び出される。レートの補償を忘れたらどうなるか、興味のあるところだ。私のシステムでは、xclockの秒針がルーレットのように廻りだした。

上図を見ると、8254のインタラプト方法を示すものがPICにフックされている。8254がインタラプトしようとしたとき、IRQ7ライン(マザーボードに埋め込まれた銅線)を通じてPICに告げる。PCIはプロセッサを何時インタラプトするかを決める。これはインタラプト共有の標準方法で、PICの唯一の目的である。Linuxでは、PICを再プログラムして、タイマーISR(IRQ7)用ベクトル20を呼び出すようにしている。DOSではBIOSがベクトル8に設定さる。各インタラプトの後、対応するISRは、実質的にoutportb(0x20,0x20) であるEOIを実行する。だから、君からとISRからと、EOIを二重に送らない注意が必要だ。

最後に一点

最後に、myaudio.x でおこなったサンプルについて一寸述べたい。デバイスドライバのためインタラプトを要求する公式方法を持っている。問題は、モジュールをロードするとき、スケジューラが既にタイマーインタラプトを請求していることである。だから、少し戻ってスケジューラからそれを盗まなければならない。IDT等々を述べたのはそのためだ。コードに書いたOSSインターフェイスはpre-alphaだ。実際に、 -D SPKDBG をmyaudio.mak の中のコンパイラオプション変数に加えると、mpg123のようなアプリケーションを走らせることが出来るので、超多重OSでのイベント同期の中を覗くことが出来る。-D SPKDBGは、デバグメッセージを出す。だが、君のマシンは、ログ記録のオーバーヘッドを扱うことは出来ないことに注意。だから、何をしているか分かっているときだけ、何かをすること。TODOリストのOSSを洗練したことがある。完成して貰えば有り難い。

ドライバを使うには以下をおこなうこと:ルートユーザーとして、ソースファイル myaudio.c, myaudio.h, myaudio.makをコピイしたディレクトリにchdir して、Run:



make -f myaudio.mak


君のマシンに標準OSSディストリビューションがあるとして
(バスはs /usr/src/linux/drivers/sound。点検のこと)


modprobe sound


insmod myaudio.o


ここでドライバが働く:



lsmod


を使って点検する。

リストのトップにmyaudioがあるのを楽しみにしている。mpg123が普通に働く筈だ。

上記のアプリケーションのどれも働かない時は、下記を使ってmp3音楽を聴いてみること。



mpg123 -m -r 22000 --8bit -w /dev/dsp x.mp3 #this should playx.mp3


楽しみ給え!!!!


注記: これらの操作全部はユーザールートとしておこなう必要がある。自分のマシンを使っており、任意のポートを、多分永久に、廃棄出来ると仮定している。私のコードのため何が起こっても責任は負い兼ねる。だから、自分自身の危険負担でやって欲しい。私は自分のサンプルをCeleron 366/64MB RAM上で働く Redhat 7.1 システム上で試した。本当に、真面目に興味があって、マシンを壊したくない人は、Michael Beckが作ったパッチを使われたい。だが、その位ならこの記事は読まないだろうね?


君の答が、smpl1>smpl2>smpl3 の順で、smpl2=127 ならば、合格だ。

Creative labs に申し込める


プログラムリスト
myaudio.h
myaudio.c
Makefile
Copyright © 2001, Cherry George Mathew and Linux.com.
Copying license http://www.linuxgazette.com/copying.html
Published in Issue 69 of Linux Gazette, August 2001
 
 
 
Perl とPostgreSQLの結合, パート2:
PL/pgSQLを用いるプロシージャ

By Mark Nielsen

1.緒言
2.テーブル、プロシージャ、バックアップテーブル及びシーケンスを作るPerlスクリプト
3.Perl scriptの実行
4.探求すべき問題
5.結語
6.参考文献

緒言

PostgreSQL, Perl の搭載とPostgreSQLの Perへの埋め込みを扱った後、テーブル、シーケンス、記憶プロシージャ、バックアップテーブルの作成をしたくなった。他人はこれらの良いGUIソリューションを持っているだろうが、見たことがない。あれば教えて欲しい。
私の目標は:
1.何があろうと常にデータをバックアップする。
2.挿入、更新、削除、コピイ又はテーブル上でデータを変更する何かをするのに、常に記憶プロシージャを使う。データ選択用プロシージャも作る。
3.テーブル、シーケンス、記憶プロシージャ、バックアップテーブルを作るPerlスクリプトと、データを取り扱う記憶プロシージャを持つ。
4.Perlを用いてデータをクリーンする記憶プロシージャを持つ。
5.誰かが活システム上でPerlを走らせたときデータをバックアップする。
6.テーブル内の活性、不活性列を規定出来るような活性行がなければならない。テーブルのどの列が活性かを見るビューを作らなければならない。
7.記憶プロシージャは、最新更新作成日付を記録しなければならない。
8.全部の列が独特のidを持つ。それらを使わなくても、有る。唯一のの列を得るのにidを使うのが良いとは限らない。
9.追放プロシージャを用いて不活性列の削除が出来る。削除プロシージャは、それを不活性にするだけ。また、最新追放データを伴う不追放には独特のid。これは賢い方法。
10.pl/sql プロシージャから戻された負数はすべて、不具合と見なす。正数(0を含む)は、エラー無しの成功と見なす。0は何も起こらなかったこと、0より大きい数字は、数字の項目又はid番号が影響を受けたことを示す。
将来の目標は:
1.GUIインターフェイスの作成。出来れば、GNOME 又はKDEライブラリに依存しないもの。Pythonはよい。Pythonバイナリは容易に作れるので、 Python/TKが好きだ。
2.以下のいずれかにより、活テーブルを変更するGUI設計が出来る。
・全効力を持って実際に起こる更新をおこなう。幾つかの変更はすべてのオプションを許すことが出来ない(少なくとも昔は)
・新テーブルを作って、旧テーブルを見ながら旧テーブルから新テーブルにすべてのデータをダンプする。
3.履歴を見るため、すべてのデータベース変更を記録する。
テーブル、プロシージャ、バックアップテーブル及びシーケンスを作るPerlスクリプト
筆者の使うPerlスクリプトを示す。Create_Functions.pl.txt.からコピイも入手出来る。


#!/usr/bin/perl


#              Perl/PostgreSQL version 0.1用ファンクションの作成


#                       著作権2001, Mark Nielsen


#                            全権保留.


#    本著作権通告はPerlから複写して変更した


#    著作権通告


#    本プログラムは、無料ソフトウエアにつき、以下いずれかの条件で




#    再配布及び/又は修正してよい


#        a) 無料ソフトウエア基金1版又は(任意選択で)ぞれより


#        新しい任意の版で、発表のGNU 一般公開ライセンス、又は




#        b)このキットに付属の "Artistic License"、


#    このプログラムは有用であることを望んで配布するもので、


#    何の保証もない。商業性及び特定目的への合致につき




#    暗黙の保証もない。 詳細は




#    GNU 一般公開ライセンス又は Artistic Licenseの何れかを参照のこと


#    本キットと共に "Artistic" と言うファイルの中で


#    Artistic License を受領した筈である。無ければ備えられたい


#    このプログラムと共にGNU 一般公開ライセンスもまた"Copying" と言う




#    ファイルの中で受領したはずである。無ければ下記に問い合わせられたい。




#   Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 


#    02111-1307, USA 又は、インターネットWebペイジ




#    http://www.gnu.org/copyleft/gpl.html.





use strict;





  ### 幾つかの変数を定義するが、自分自身のコンピュータ用に変更のこと




my $Home = "/tmp/testdir";


my $File = "$Home/Tables.txt";


my $Template = "$Home/Generic.fun";


my $Custom = "$Home/Custom.sql";


my $Database = "testdatabase";


 


#------------------------------------------------------------------------





my @List = @ARGV;





  ## 無いときは、必要なディレクトリ二つを作成する




if (!(-e "$Home/Tables")) {system "mkdir -p $Home/Tables"}


if (!(-e "$Home/Backups")) {system "mkdir -p $Home/Backups"}





  ### ファンクション用テンプレートテーブル作成情報を含むファイルを開く




open(FILE,$Template); my @Template = <FILE>; close FILE;


open(FILE,$File); my @File = <FILE>; close FILE;


open(FILE,$Custom); my @Custom = <FILE>; close FILE;





  ### 番号又は文字のない行を篩い分け


@File = grep($_ =~ /[a-z0-9]/i, @File);


  ### 一つだけ # を含む行を除去


@File = grep(!($_ =~ /\#/), @File);


  ### newlineを除去 


grep(chomp $_, @File);


  ### タブを除去してスペースと置き換え 


grep($_ =~ s/\t/ /g, @File);


  ### 複数スペースを一つに転換


grep($_ =~ s/  +/ /g, @File);


  ### 次の二行は、スペース及び、始と終わりを除去




grep($_ =~ s/^ //g, @File);


grep($_ =~ s/ $//g, @File);


  ### 終わりのコンマを全部除去、後で戻す


grep($_ =~ s/\,$//g, @File);





my $Tables = {};


my $TableName = "";


  ### ファイル内各行について、テーブル用新アレーを作成、又は




  ### 行をテーブル用アレーに記憶 


foreach my $Line (@File)  


  {


  my $Junk = "";


    ### 行が "TABLENAME" で始まるときは、新アレーを作成


  if ($Line =~ /^TABLENAME/) 


    {


    ($Junk,$TableName, $Junk) = split(/ /,$Line);


       ### これがテーブル用アレーを作成 


    $Tables->{$TableName} = [];


    }


  else 


    {


       ### テーブル用に行を記憶. 


    push (@{$Tables->{$TableName}}, $Line) ;


    }


  }





    ### 特定テーブルをリストしたときは、これらのみをおこなう




  if (@List) 


    {


    foreach my $TableName (sort keys %$Tables)


      { if (!(grep($_ eq $TableName, @List))) {delete $Tables->{$TableName};} }


    }





  ### アレー$Tablesに対するリファレンスのキイを入手し、


  ### そのアレー用データを入手、our fileを作って、そのファイルを使用




foreach my $TableName (sort keys %$Tables) 


  {


  my @Temp = @{$Tables->{$TableName}};





  my $Backup_Columns = "";  my $Backup_Values = ""; my $Update_Fields = "";


  my $Field_Copy_Values = "";  my $FieldTypes = "";


  my $CleanVariables = ""; my $RemakeVariables = ""; 


    ###二つのテーブルは、バックアップテーブルは単一性を要しないし




    ### シーケンスを使用しない、との点で異なる




  my $Table = qq($TableName\_id int4 NOT NULL UNIQUE DEFAULT nextval('$TableName\_sequence'),


    date_updated  timestamp NOT NULL default CURRENT_TIMESTAMP,


    date_created  timestamp NOT NULL default CURRENT_TIMESTAMP,


    active int2 CHECK (active in (0,1)) DEFAULT 0,


);


    ## idとして0の変わりに null を許すが、シーケンスは1から始まるので、




    ### 0をnullとして使う。nullは嫌いだ。


  my $Table_Backup = qq(backup_id int4 NOT NULL UNIQUE DEFAULT nextval('$TableName\_sequence_backup'), 


    $TableName\_id int4 NOT NULL DEFAULT 0,


    date_updated  timestamp NOT NULL default CURRENT_TIMESTAMP,


    date_created  timestamp NOT NULL default CURRENT_TIMESTAMP,


    active int2 CHECK (active in (0,1)) DEFAULT 0,


    );





  print "Creating functions for table '$TableName'\n";


  my $No = 1;


    ### このテーブルの各行について、これをおこなう


    ### テンプレートに入れようとする変数を幾つか作る




  foreach my $Line (@Temp) 


    {


    $Table .= "$Line,\n";


    $Table_Backup .= "$Line,\n";


    my ($Name,$Type,$Ext) = split(/ /,$Line,3);


      ### バックアップ列


    $Backup_Columns .= ", $Name"; 


      ### 更新フィールド


    $No++; $Update_Fields .= ", $Name = var_$No"; 


      ### バックアップ値


    $Backup_Values .= ", record_backup.$Name";


      ### ここでフィールドは中身をコピイするときcyop ファンクションを詰める




    $Field_Copy_Values .= ", clean_text(record2.$Name)";


      ### ここでフィールドはupdate ファンクションのためタイプ




    $FieldTypes .= ", $Type";


      ### 更新ファンクション用変数を定義する必要がある




    $CleanVariables .= "          var_$No $Type;\n";


      ### タイプを定義する必要がある、今は、テキストとint4 のみをチェック




    my $Temp = "\$$No";  


    if ($Type eq "int4") {$Temp = "clean_numeric($Temp)";}


    elsif  ($Type eq "text") {$Temp = "clean_text($Temp)";}


      ### ここで変数を設定する必要がある


    $RemakeVariables .= "         var_$No := $Temp;\n";





     ### ファンクションを追加して、提出までに変数をクリアする必要がある




    }


   ### 列が幾つあるか記録。試験のため更新コマンド用の行を作る 


  my $Number_Of_Rows = $No;


  my $Update_Test = "1";


  for (my $i = 1; $i < $Number_Of_Rows - 1; $i++) {$Update_Test .= ",$i";}





    ### 最後のコンマを切り取る必要がある


  chomp $Table; chop $Table; chomp $Table_Backup; chop $Table_Backup;


    ### テーブルとバックアップテーブルのドロップと作成を設定




  my $Tables = qq(drop table $TableName;\ncreate table $TableName (\n$Table\n);); 


  $Tables .= "drop table $TableName\_backup;\n";


  $Tables .= "create table $TableName\_backup (\n$Table_Backup, error_code text NOT NULL DEFAULT ''\n);\n";


    ### テーブル内の有効な中身に関するビューを作成




  $Tables .= "drop view $TableName\_active;\n";


  $Tables .= "create view $TableName\_active as select * from $TableName


        where active = 1;\n";


    ### 無効又は削除項目に関するビューを作成 


  $Tables .= "drop view $TableName\_deleted;\n";


  $Tables .= "create view $TableName\_deleted as select * from $TableName


        where active = 0;\n";


    ### 単一バックアップidのリスト関するビューを作成


  $Tables .= "drop view $TableName\_backup_ids;\n";


  $Tables .= "create view $TableName\_backup_ids as 


           select distinct $TableName\_id from $TableName\_backup;\n";


    ### 追放データのリストを作成 (id毎の最新データ).  


  $Tables .= "drop view $TableName\_purged;\n";


  $Tables .= "create view $TableName\_purged as


   select * from $TableName\_backup where oid = ANY (


     select max(oid) from $TableName\_backup where $TableName\_id = ANY


        (


        select distinct $TableName\_id from $TableName\_backup


          where $TableName\_backup.error_code = 'purge'


           and NOT $TableName\_id = ANY (select $TableName\_id from $TableName)


        )


        group by $TableName\_id


     )


    ;\n";





     ### アレーに関する中身の検索と交換にgrep コマンドを用いる




     ### マップを使うこともできるが、筆者は grepを好む 


  my @Temp = @Template;


     ### ここでカスタムsql コマンドを加える 


  push (@Temp,@Custom);





  grep($_ =~ s/TABLENAME/$TableName/g, @Temp);


  grep($_ =~ s/BACKUPCOLUMNS/$Backup_Columns/g, @Temp);


  grep($_ =~ s/BACKUPVALUES/$Backup_Values/g, @Temp);


  grep($_ =~ s/UPDATEFIELDS/$Update_Fields/g, @Temp);


  grep($_ =~ s/COPYFIELDS/$Field_Copy_Values/g, @Temp);


  grep($_ =~ s/FIELDS/$FieldTypes/g, @Temp);


  grep($_ =~ s/HOME/$Home/g, @Temp);


  grep($_ =~ s/CLEANVARIABLES/$CleanVariables/g, @Temp);


  grep($_ =~ s/REMAKEVARIABLES/$RemakeVariables/g, @Temp);





    ### ここで中身をアレー @Temp から @Template_Copyに移す


  my @Template_Copy = @Temp;





    ### ここでファイルをセーブする。何をしたか分かるように 


    ### (このスクリプトを再度走らせない限り) 削除はしない


  open(FILE,">$Home/Tables/$TableName\.table_functions");


    ### テーブルに関するシーケンスを作成


  print FILE "drop sequence $TableName\_sequence;\n";


  print FILE "create sequence $TableName\_sequence;\n";


  print FILE "drop sequence $TableName\_sequence_backup;\n";


  print FILE "create sequence $TableName\_sequence_backup;\n";


    ### テーブルとバックアップテーブルをプリントアウト


  print FILE $Tables;


    ### 四つのファンクション insert, delete, update, copyをプリントアウト


  foreach my $Temp (@Template_Copy) {print FILE "$Temp";} 





  close FILE;





    ### 活きたサーバー上で初心者がこれを実行する場合は、


    ### 実行前に, テーブルをバックアプする。


  my $Backup_File = "$Home/Backups/$TableName\_0.backup";


  my $No = 0;


  while (-e $Backup_File)


    {$No++; $Backup_File = "$Home/Backups/$TableName\_$No\.backup";} 


    ### ここでバックアップを記憶するファイル名が分かったので実行する。




  system ("pg_dump -t $TableName -f $Backup_File $Database");


  


   ### ファイルシステム内に何があるかを知りたいときのこのオプションには


  ###  ノーコメント ("cat $Home/Tables/$TableName\.table_functions");





  ### テーブルとファンクションをドロップして、
  ### テーブルとファンクションとバックアップテーブルを作成
 system ("psql -d $Database -c '\\i $Home/Tables/$TableName\.table_functions'");
 print "Check the file\n $Home/Tables/$TableName\.table_functions.\n";

 }

この perl スクリプトを"Create_Functions.pl.txt"と再命名する。働かせるために必要なことを示す:
・点線より上のオプションを変更すること、
・Perl を埋め込んでインストールしたPostgreSQLがなければならない。
・コマンド"psql template1"を入力。次いで、 "create database testdatabase;" 又はデータベースに付けた名前をタイプする。enterを押す。途中でエラーがあるのは、許可を設定していないため。ルートとしてログインし、次いで"su -l postgres"を実行。次いで"createuser"とタイプしてenterを押す。これでpostgresqlデータベース内にユーザーが作られる。使用者名を入力して、使用者名に完全優先権を与える。その上で君の通常アカウントを用いて再試行する。

Perl scriptの実行

幾つか追加のファイル、Tables.txt ファイル、が必要である。


TABLENAME contact


question_id int4 NOT NULL DEFAULT 0


company_name text NOT NULL default ''


first  text NOT NULL default ''


middle text NOT NULL default ''


last text NOT NULL default ''


email  text NOT NULL default ''


work_phone text NOT NULL default ''


home_phone text NOT NULL default ''


address_1 text NOT NULL default '',


address_2 text NOT NULL default ''


city text NOT NULL default ''


state text NOT NULL default ''


zip text NOT NULL default ''





TABLENAME account


username text NOT NULL DEFAULT '',


password text not NULL DEFAULT '',





TABLENAME contact_lists


account_id int4 not null default 0,


contact_id int4 not null default 0,


筆者のファイルを一例として使用することは出来るが、自分用に変更することを薦める。これは三つのテーブルを作ることをシミュレートしている。一つは使用者名とパスワードを含み、他は使用者名を内容目次に結合し、別に必要なのは Generic.funである。


---              Generic Functions for Perl/Postgresql version 0.1


---                       著作権2001, Mark Nielsen


---                            全権保留.


---    T本著作権通告はPerlから複写して変更した 


---    著作権通告


---    本プログラムは、無料ソフトウエアにつき、以下いずれかの条件で


---    再配布及び/又は修正してよい:




---       a) 無料ソフトウエア基金1版又は(任意選択で)ぞれより


---      新しい任意の版で、発表のGNU 一般公開ライセンス、又は




---       b)このキットに付属の "Artistic License"、


---   このプログラムは有用であることを望んで配布するもので、


---   何の保証もない。商業性及び特定目的への合致につき




---   暗黙の保証もない。 詳細は




---   GNU 一般公開ライセンス又は Artistic Licenseの何れかを参照のこと



---  本キットと共に "Artistic" と言うファイルの中で
---  Artistic License を受領した筈である。無ければ備えられたい

---  このプログラムと共にGNU 一般公開ライセンスもまた"Copying" と言う


---   ファイルの中で受領したはずである。無ければ下記に問い合わせられたい。




---   Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 


---   02111-1307, USA 又は、インターネットWebペイジ




---   http://www.gnu.org/copyleft/gpl.html.





-- 一項目だけ追放しない方法を作ること


-- 一項目だけ追放する方法を作ること


--  \i HOME/TABLENAME.table


---------------------------------------------------------------------





drop function sql_TABLENAME_insert ();


CREATE FUNCTION sql_TABLENAME_insert () RETURNS int4 AS '


DECLARE


    record1 record;  oid1 int4; id int4 :=0; record_backup RECORD;


BEGIN


   insert into TABLENAME (date_updated, date_created, active)


        values (CURRENT_TIMESTAMP,CURRENT_TIMESTAMP, 1);


     -- 挿入したばかりの列の独自oidを入手


   GET DIAGNOSTICS oid1 = RESULT_OID;


     -- TABLENAME id. を入手 


   FOR record1 IN SELECT TABLENAME_id FROM TABLENAME where oid = oid1


      LOOP


      id := record1.TABLENAME_id;


   END LOOP;


   


     -- id がNULLのときは、挿入の失敗か又は何か間違っている


   IF id is NULL THEN return (-1); END IF;


     -- これもまた0 より大きい筈、でなければ何か間違っている


   IF id < 1 THEN return (-2); END IF;





      -- ここでデータをバックアップ


    FOR record_backup IN SELECT * FROM TABLENAME where TABLENAME_id = id


       LOOP


       insert into TABLENAME_backup (TABLENAME_id, date_updated, date_created, 


           active, error_code) 


         values (id, record_backup.date_updated, record_backup.date_created,


            record_backup.active, ''insert'');


    END LOOP;





     -- すべて合格、idを TABLENAME_id として返す


   return (id);


END;


' LANGUAGE 'plpgsql';


---------------------------------------------------------------------





drop function sql_TABLENAME_delete (int4);


CREATE FUNCTION sql_TABLENAME_delete (int4) RETURNS int2 AS '


DECLARE


    id int4 := 0;


    id_exists int4 := 0;


    record1 RECORD; 


    record_backup RECORD;


    return_int4 int4 :=0;





BEGIN


     -- id が0より大きくないときはエラーに戻る


   id := clean_numeric($1);


   IF id < 1 THEN return -1; END IF;





     -- idを見出したら、 active = 0 に設定 


   FOR record1 IN SELECT TABLENAME_id FROM TABLENAME 


          where TABLENAME_id = id


      LOOP


      update TABLENAME set active=0, date_updated = CURRENT_TIMESTAMP


           where TABLENAME_id = id;  


      GET DIAGNOSTICS return_int4 = ROW_COUNT;       


      id_exists := 1;


   END LOOP;


      


     -- id を見出さないときは、abort してreturn -2.  


   IF id_exists = 0 THEN return (-2); END IF;





   FOR record_backup IN SELECT * FROM TABLENAME where TABLENAME_id = id


      LOOP


      insert into TABLENAME_backup (TABLENAME_id, date_updated, date_created,


          active BACKUPCOLUMNS ,error_code)


           values (record_backup.TABLENAME_id, record_backup.date_updated, 


             record_backup.date_updated, record_backup.active


             BACKUPVALUES , ''delete''


      );


   END LOOP;





     -- id_exists == 0であれば、error を返す


     -- これは実行されないことを意味する


   IF id_exists = 0 THEN return (-1); END IF;





     -- We got this far, it must be true, return ROW_COUNT.   


   return (return_int4);


END;


' LANGUAGE 'plpgsql';





---------------------------------------------------------------------


drop function sql_TABLENAME_update (int4 FIELDS);


CREATE FUNCTION sql_TABLENAME_update  (int4 FIELDS) 


  RETURNS int2 AS '


DECLARE


    id int4 := 0;


    id_exists int4 := 0;


    record_update RECORD; record_backup RECORD;


    return_int4 int4 :=0;


    CLEANVARIABLES


BEGIN


    REMAKEVARIABLES


     -- id が0より大きくないときは、error を返す


   id := clean_numeric($1);


   IF id < 1 THEN return -1; END IF;





   FOR record_update IN SELECT TABLENAME_id FROM TABLENAME


         where TABLENAME_id = id


      LOOP


      id_exists := 1;


   END LOOP;





   IF id_exists = 0 THEN return (-2); END IF;





   update TABLENAME set date_updated = CURRENT_TIMESTAMP


      UPDATEFIELDS 


        where TABLENAME_id = id;


   GET DIAGNOSTICS return_int4 = ROW_COUNT;





   FOR record_backup IN SELECT * FROM TABLENAME where TABLENAME_id = id


      LOOP


     insert into TABLENAME_backup (TABLENAME_id,


         date_updated, date_created, active


         BACKUPCOLUMNS, error_code)


       values (record_update.TABLENAME_id, record_backup.date_updated,


         record_backup.date_updated, record_backup.active


         BACKUPVALUES, ''update''


      );


   END LOOP;





     -- ここまできた以上、正しい筈、ROW_COUNTに戻る  


   return (return_int4);


END;


' LANGUAGE 'plpgsql';


---------------------------------------------------------------------





drop function sql_TABLENAME_copy (int4);


CREATE FUNCTION sql_TABLENAME_copy (int4) 


  RETURNS int2 AS '


DECLARE


    id int4 := 0;


    id_exists int4 := 0;


    record1 RECORD; record2 RECORD; record3 RECORD;    


    return_int4 int4 := 0;


    id_new int4 := 0;


    TABLENAME_new int4 :=0;


BEGIN


     -- id が0より大きくないときは、error を返す


   id := clean_numeric($1);


   IF id < 1 THEN return -1; END IF;





   FOR record1 IN SELECT TABLENAME_id FROM TABLENAME where TABLENAME_id = id


      LOOP


      id_exists := 1;


   END LOOP;


   IF id_exists = 0 THEN return (-2); END IF;





     --- 新id を入手


   FOR record1 IN SELECT sql_TABLENAME_insert() as TABLENAME_insert


      LOOP


      TABLENAME_new := record1.TABLENAME_insert;


   END LOOP;


     -- If the TABLENAME_new が0より大きくないときは、errorを返す


   IF TABLENAME_new < 1 THEN return -3; END IF;





   FOR record2 IN SELECT * FROM TABLENAME where TABLENAME_id = id


      LOOP





     FOR record1 IN SELECT sql_TABLENAME_update(TABLENAME_new COPYFIELDS)


        as TABLENAME_insert


      LOOP


        -- これを通過させるだけのため勝手なコマンドを実行


      id_exists := 1;


     END LOOP;


   END LOOP;





     -- ここまで来た限り、正しい筈、new idに戻る 


   return (TABLENAME_new);


END;


' LANGUAGE 'plpgsql';





------------------------------------------------------------------


drop function sql_TABLENAME_purge ();


CREATE FUNCTION sql_TABLENAME_purge () RETURNS int4 AS '


DECLARE


    record_backup RECORD; oid1 int4 := 0;


    return_int4 int4 :=0;


    deleted int4 := 0;


    delete_count int4 :=0;


    delete_id int4;





BEGIN 





     -- ここで一個宛て削除


   FOR record_backup IN SELECT * FROM TABLENAME where active = 0


      LOOP


         -- 削除したいid を記録


      delete_id = record_backup.TABLENAME_id;





      insert into TABLENAME_backup (TABLENAME_id, date_updated, date_created,


          active BACKUPCOLUMNS ,error_code)


           values (record_backup.TABLENAME_id, record_backup.date_updated, 


             record_backup.date_updated, record_backup.active


             BACKUPVALUES , ''purge''


          );





        -- 今挿入した列の独自idを取得


      GET DIAGNOSTICS oid1 = RESULT_OID;





        -- oid1 が1より小さいときは、return -1


      IF oid1 < 1 THEN return (-2); END IF;


        -- これをメインテーブルから削除


      delete from TABLENAME where TABLENAME_id = delete_id;





        -- 削除したばかりの列計数を取得。1の筈


      GET DIAGNOSTICS deleted = ROW_COUNT;


        -- 1より少なく削除したときは、return -3


      IF deleted < 1 THEN return (-3); END IF;


      delete_count := delete_count + 1;





    END LOOP;





     -- ここまで来たかぎり、正しい筈、取得したものの数を返す 


   return (delete_count);


END;


' LANGUAGE 'plpgsql';





------------------------------------------------------------------


drop function sql_TABLENAME_purgeone (int4);


CREATE FUNCTION sql_TABLENAME_purgeone (int4) RETURNS int4 AS '


DECLARE


    record_backup RECORD; oid1 int4 := 0;


    record1 RECORD;


    return_int4 int4 :=0;


    deleted int4 := 0;


    delete_count int4 :=0;


    delete_id int4;


    purged_no int4 := 0;





BEGIN





    delete_id := $1;


        -- purged_id が1より小さいときは、return -4


    IF delete_id < 1 THEN return (-4); END IF;





   FOR record1 IN SELECT * FROM TABLENAME 


      where active = 0 and TABLENAME_id = delete_id 


      LOOP


      purged_no := purged_no + 1;


   END LOOP;





        -- purged_no 1より小さくないときは、return -1


   IF purged_no < 1 THEN return (-1); END IF;





     -- ここで1個宛て削除


   FOR record_backup IN SELECT * FROM TABLENAME where TABLENAME_id = delete_id


      LOOP





      insert into TABLENAME_backup (TABLENAME_id, date_updated, date_created,


          active BACKUPCOLUMNS ,error_code)


           values (record_backup.TABLENAME_id, record_backup.date_updated,


             record_backup.date_updated, record_backup.active


             BACKUPVALUES , ''purgeone''


          );





        -- 今挿入した列の独自oid を取得


      GET DIAGNOSTICS oid1 = RESULT_OID;





        -- oid1 が1より小さいときは、 return -2


      IF oid1 < 1 THEN return (-2); END IF;


        -- これをメインテーブルから削除


      delete from TABLENAME where TABLENAME_id = delete_id;





        -- 今削除した列の列計数を取得。1の筈


      GET DIAGNOSTICS deleted = ROW_COUNT;


        -- 1より少なく削除したときは、, return -3


      IF deleted < 1 THEN return (-3); END IF;


      delete_count := delete_count + 1;





    END LOOP;





     -- ここまで来た限り、正しい筈、取得したものの数を返す


   return (delete_count);


END;


' LANGUAGE 'plpgsql';





------------------------------------------------------------------------


drop function sql_TABLENAME_unpurge ();


CREATE FUNCTION sql_TABLENAME_unpurge () RETURNS int2 AS '


DECLARE


    record1 RECORD;


    record2 RECORD; 


    record_backup RECORD;


    purged_id int4 := 0;


    purge_count int4 :=0;


    timestamp1 timestamp;


    purged_no int4 := 0;


    oid1 int4 := 0;


    oid_found int4 := 0;


    highest_oid int4 := 0;





BEGIN





     -- ここで追放された独自idを取得


   FOR record1 IN select distinct TABLENAME_id from TABLENAME_backup 


       where TABLENAME_backup.error_code = ''purge''


          and NOT TABLENAME_id = ANY (select TABLENAME_id from TABLENAME)


      LOOP





      purged_id := record1.TABLENAME_id;


      timestamp1 := CURRENT_TIMESTAMP;


      purged_no := purged_no + 1;


      oid_found := 0;


      highest_oid := 0;





        -- 独自idを取得したので、その最新日付を見出す。





      FOR record2 IN select max(oid) from TABLENAME_backup 


          where TABLENAME_id = purged_id and error_code = ''purge''


        LOOP 


          -- 取得した日付を記録し、最高日付もまた記録する


        oid_found := 1; 


        highest_oid := record2.max;


      END LOOP;


 


         -- oid_foundが 0であるときは、errorを返す 


      IF oid_found = 0 THEN return (-3); END IF;





        --最新日付を取得したので、値を取得して挿入する


      FOR record_backup IN select * from TABLENAME_backup 


          where oid = highest_oid


        LOOP 





      insert into TABLENAME_backup (TABLENAME_id, date_updated, date_created,


          active BACKUPCOLUMNS ,error_code)


           values (purged_id, record_backup.date_updated, 


             timestamp1, record_backup.active


             BACKUPVALUES , ''unpurge''


          );





        -- Get the unique oid of the row just inserted. 


      GET DIAGNOSTICS oid1 = RESULT_OID;


        -- oid1 が1より小さいときは、 return -1


      IF oid1 < 1 THEN return (-1); END IF;





      insert into TABLENAME (TABLENAME_id, date_updated, date_created,


          active BACKUPCOLUMNS)


           values (purged_id, timestamp1,


             timestamp1, record_backup.active


             BACKUPVALUES );


        -- 今挿入した列の独自oid を取得


      GET DIAGNOSTICS oid1 = RESULT_OID;


        -- oid1 より小さいときは、return -2


      IF oid1 < 1 THEN return (-2); END IF;





      END LOOP;





   END LOOP;





     -- ここまで来た限り、正しい、影響された数を返す 


   return (purged_no);


END;


' LANGUAGE 'plpgsql';





---------------------------------------------------------------------


drop function sql_TABLENAME_unpurgeone (int4);


CREATE FUNCTION sql_TABLENAME_unpurgeone (int4) RETURNS int2 AS '


DECLARE


    record_id int4;


    record1 RECORD;


    record2 RECORD;


    record_backup RECORD;


    return_int4 int4 :=0;


    purged_id int4 := 0;


    purge_count int4 :=0;


    timestamp1 timestamp;


    purged_no int4 := 0;


    oid1 int4 := 0;


    oid_found int4 := 0;


    highest_oid int4 := 0;





BEGIN





      purged_id := $1;


        -- If purged_id less than 1, return -1


      IF purged_id < 1 THEN return (-1); END IF;


        --- 現在時刻スタンプを取得


      timestamp1 := CURRENT_TIMESTAMP;





   FOR record1 IN select distinct TABLENAME_id from TABLENAME_backup


       where TABLENAME_backup.error_code = ''purge''


          and NOT TABLENAME_id = ANY (select TABLENAME_id from TABLENAME)


          and TABLENAME_id = purged_id


      LOOP


      purged_no := purged_no + 1;





   END LOOP;





        -- purged_no 1がより小さくないときは, return -1


   IF purged_no < 1 THEN return (-3); END IF;





        -- ここで最高 oid を見出す 


   FOR record2 IN select max(oid) from TABLENAME_backup


          where TABLENAME_id = purged_id and error_code = ''purge''


        LOOP


          -- 取得日付を記録しまた最高日付を記録する


        oid_found := 1;


        highest_oid := record2.max;


    END LOOP;





         -- oid_found が0 であるときは、errorを返す


    IF oid_found = 0 THEN return (-4); END IF;





        -- ここでdataを取得しそれを記憶


    FOR record_backup IN select * from TABLENAME_backup 


          where oid  = highest_oid


        LOOP 


        -- 追放されなかったことをバックアップに挿入 


      insert into TABLENAME_backup (TABLENAME_id, date_updated, date_created,


          active BACKUPCOLUMNS ,error_code)


           values (purged_id, timestamp1, 


             record_backup.date_created, record_backup.active


             BACKUPVALUES , ''unpurgeone''


          );





        -- 今挿入した列の独特 oid を取得 


      GET DIAGNOSTICS oid1 = RESULT_OID;


        -- oid1 が1より小さいときは、return -1


      IF oid1 < 1 THEN return (-1); END IF;


        -- 活きているテーブルに挿入


      insert into TABLENAME (TABLENAME_id, date_updated, date_created,


          active BACKUPCOLUMNS)


           values (record_backup.TABLENAME_id, timestamp1,


             record_backup.date_updated, record_backup.active


             BACKUPVALUES );


        -- 今挿入した列の 独特oid を取得


      GET DIAGNOSTICS oid1 = RESULT_OID;


        -- oid1 が1より小さいときは、return -2


      IF oid1 < 1 THEN return (-2); END IF;





      END LOOP;





     -- ここまで来た限り、正しい筈、影響を受けた数(1)を返す




   return (purged_no);


END;


' LANGUAGE 'plpgsql';





最後は Custom.sql. だ。




---          Custom Sample SQL for Perl/PostgreSQL version 0.1




---                       著作権2001, Mark Nielsen


---                            全権保留.


---    T本著作権通告はPerlから複写して変更した 


---    著作権通告


---    本プログラムは、無料ソフトウエアにつき、以下いずれかの条件で


---    再配布及び/又は修正してよい:




---       a) 無料ソフトウエア基金1版又は(任意選択で)ぞれより


---      新しい任意の版で、発表のGNU 一般公開ライセンス、又は




---       b)このキットに付属の "Artistic License"、


---   このプログラムは有用であることを望んで配布するもので、


---   何の保証もない。商業性及び特定目的への合致につき




---   暗黙の保証もない。 詳細は




---   GNU 一般公開ライセンス又は Artistic Licenseの何れかを参照のこと



---  本キットと共に "Artistic" と言うファイルの中で
---  Artistic License を受領した筈である。無ければ備えられたい

---  このプログラムと共にGNU 一般公開ライセンスもまた"Copying" と言う


---   ファイルの中で受領したはずである。無ければ下記に問い合わせられたい。




---   Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 


---   02111-1307, USA 又は、インターネットWebペイジ




---    http://www.gnu.org/copyleft/gpl.html.





drop function clean_text (text);


CREATE FUNCTION  clean_text (text) RETURNS text AS '


  my $Text = shift;


    # 前の空白を除去 


  $Text =~ s/^\\s+//;


    # 最後の空白を除去


  $Text =~ s/\\s+$//;


    # テキストでないものを除去


  $Text =~ s/[^ a-z0-9\\/\\`\\~\\!\\@\\#\\$\\%\\^\\&\\*\\(\\)\\-\\_\\=\\+\\\\\\|\[\\{\\]\\}\\;\\:\\''\\"\\,\\<\\.\\>\\?\\t\\n]//gi;


    # 複数空白をスペース1個で置き換える


  $Text =~ s/\\s+/ /g;


  return $Text;


' LANGUAGE 'plperl';


 -- 何をクリーンアップするかを告げるだけ


select clean_text ('       ,./<>?aaa aa      !@#$%^&*()_+| ');





drop function clean_alpha (text);


CREATE FUNCTION  clean_alpha (text) RETURNS text AS '


  my $Text = shift;


  $Text =~ s/[^a-z0-9_]//gi;


  return $Text;


' LANGUAGE 'plperl';


 -- Just to show you what this function cleans up. 


select clean_alpha ('       ,./<>?aaa aa      !@#$%^&*()_+| ');





drop function clean_numeric (text);


CREATE FUNCTION  clean_numeric (text) RETURNS int4 AS '


  my $Text = shift;


  $Text =~ s/[^0-9]//gi;


  return $Text;


' LANGUAGE 'plperl';


 -- Just to show you what this function cleans up.


select clean_numeric ('       ,./<>?aaa aa      !@#$%^&*()_+| ');





drop function clean_numeric (int4);


CREATE FUNCTION  clean_numeric (int4) RETURNS int4 AS '


  my $Text = shift;


  $Text =~ s/[^0-9]//gi;


  return $Text;


' LANGUAGE 'plperl';


 -- このファンクションがクリーンアップするものを示すだけ


select clean_numeric (1111);





perl スクリプトをセーブした後、"chmod 755 Create_Functions.pl" 及び、次いで "./Create_Functions.pl" を実行する。うまく行く筈。

PostgreSQL とPerl を正しくインストールしており、データベース及び君のアカウントがそのデータベースに対するパーミッションを持っていれば、すべてうまく働く筈。

探求すべき問題
TCL、Pythonその他の言語と同時に、標準プロシージャをテストしたい。 MySQLを使っておられたら、これが記憶プロシージャを有するとは思わないが、私のスタイルをお好みなら、PostgreSQLを検討したい筈だ。テーブルを作りテーブルに変更を加える良いGUIアプリケーションがあると素晴らしい。最後に、これら記憶プロシージャを使用するためデータベースサーバーを(Perl, Python, PHP, TCL, C, などを使って)接続する方法の例も素晴らしい。

結語

PostgreSQL とPerl の組合せは人を動揺させる。私はPerlを三つのこと、記憶プロシージャ、自分のデータベースの設定、及びPostgreSQLデータベースに接続するApache用Perlモジュールの作成、に使うことが出来る。同様のことは、Pyathon、TCLなどのような他のプログラム言語を用いても、達成することが出来る。PostgreSQLに関するベータから出たときPythonに取り組みたい。

すべてのデータベースサーバーは、データ変更専用のプロシージャを使用しなければならない。データ選択用にもまたカスタム記憶プロシージャを作らなければならないことに不満があるだろう。これが重要な理由は、Webプログラマ(又は他の型のプログラマ)データ取扱に関し知る必要がないことだ。彼らは、変数をプロシージャに提出するだけだ。これにより、プログラマはデータベースの行動を変更することなく、望みのままのプログラム言語を使用することが出来る。データベースとその使用法は抽象論になる。

私のPerlスクリプトがおこなう変なことの一つは、各テーブルにつきカスタムsqlコードを実行することだ。大変まずい。後で解決しなければならない。以下のコマンドで私の中身をテストしたいと思われるだろう:。



select sql_account_insert();


select sql_account_delete(1);


select sql_account_insert();


select sql_account_update(2,'mark','nielsen');


select sql_account_purge();


select sql_account_unpurge();


select * from account_backup;


select sql_account_delete(2);


select sql_account_insert();


select sql_account_update(1,'john','nielsen');


select sql_account_purge();


select * from account_backup;


参考文献
1.My Previous PostgreSQL article.
2.この記事の変更はhttp://www.gnujobs.com/Articles/22/Perl_PostgreSQL2.htmlで入手可能。
 
Copyright © 2001, Mark Nielsen.
Copying license http://www.linuxgazette.com/copying.html
Published in Issue 69 of Linux Gazette, August 2001
 
 
 
Perlの学習、パート5

By Ben Okopnik

概観

今月扱う問題はPerlの一般問題、実際生活で使う方法、O.P.C.(他人のコード)をパワーアップする方法、眺める。 Modules を使うと、前に書かれたコードを、時間を掛けずに自分のスクリプトに組み込める。これは、この初歩的シリーズのまとめとなる。Perlとは何かにつき、アイデアを得られたことを望む。

訂正

読者の一人(匿名希望)から、先月号に、パラメータなしの"close"はすべてのファイル取扱をクローズすると述べてあるのは間違いだとの、ご指摘を頂いた。調べたところ、ご指摘通りで、現在選択されているファイル取扱(規定値ではSTDOUT).をクローズするだけだ。ご指摘有り難う。

演習

前の記事で、習ったことを練習するため、スクリプトの問題を二、三示した。Tjabo氏が解答を呉れた。うまく出来ていた。

問題は、"/etc/services"を読み取り、UDPとTCPポートをカウントし、別のファイルに書き込むことだ。Tjabo氏の解答を示す。(###の後はコメント)


#!/usr/bin/perl -w
### 優秀; コンピュータにスクリプトをでバックさせよう!

$udp = $tcp = 0;
### 不要: Perl は変数宣言を必要としない.

# open target files:
open (TCP, ">>tcp.txt") or die "Arghh #1 !";
open (UDP, ">>udp.txt") or die "Arghh #2 !";

### これは私の失敗だ: 前の記事で示したクイックハックの中で
### ストリングを "die" するのに同じ用語を使った。

### その通りにつかっているが、正しい使用法は下記の通りだ:
###
### open TCP, ">tcp.txt" or die "Can't open tcp.txt: $!\n";
###
### '$!' 変数は、システムが返すエラーを示すので

### 絶対に使用しなければならない; "die" ストリング最後の"\n"は

### エラー行がプリントされないようにする。また、">>" (append) 修飾子は

### 不適当だ。これがあると、スクリプト内容を一回以上実行して、

### これらファイルの内容を追加(上書きでなく)する

# open data source:
open (SERV, "</etc/services") or die "Arghh #3 !";

while( <SERV> ) {
 if (/^ *([^# ]+) +(\d+)\/([tcpud]+)/) {

### 上の regex には幾つか問題がある。大したことでないもの

### (不要な要素)もあるが、一つは重大だ:これは

### 行の殆どを無効にする。犯人は最初のキャプチャの後の ' +' だ:

### "/etc/services" は、その要素を分離するのに、

### スペースと *tabs* を使う。

  $name  = $1;
  $port  = $2;
  $tcpudp = $3;
  $tmp = "$name ($port)\n";

### 上の指定は不要だ; $1, $2, などは、その値を、
### 次に一致するまで保つ。上の全部を削除して
### "if" ステートメントを、次のように書き直せば
###
### if ( $3 eq "udp" ) { print UDP "$1 ($2)\n"; $udp++; }
###
### うまく働く。

  if ($tcpudp eq "udp") {
   print UDP $tmp;
   $udp++;
  }

  if ($tcpudp eq "tcp") {
   print TCP $tmp;
   $tcp++;
  }
 }
}

# just learned :-) :
for ( qw/SERV TCP UDP/ ) { close $_ or die "can't close $_: $!\n"; }

print "TCP: $tcp, UDP: $udp\n";


上のスクリプトは、私の"/etc/services" の中でTCP 14個とUDP 11個を数えた(これは実際に一方を185個、他方を134個含む)。少し改善出来るか、検討しよう。


#!/usr/bin/perl -w

open SRV, "</etc/services" or die "Can't read /etc/services: $!\n";
open TCP, ">tcp.txt"    or die "Can't write tcp.txt: $!\n";
open UDP, ">udp.txt"    or die "Can't write udp.txt: $!\n";

for ( <SRV> ) {
  if ( s=^([^# ]+)(\s+\d+)/tcp.*$=$1$2= ) { print TCP; $tcp++; }
  if ( s=^([^# ]+)(\s+\d+)/udp.*$=$1$2= ) { print UDP; $udp++; }
}

close $_ or die "Failed to close $_: $!\n" for qw/SRV TCP UDP/;

print "TCP: $tcp\t\tUDP: $udp\n";


「実際の」作業をおこなう "for" ループの中で、次のマッチ/置換をおこなっている。
行頭から初めて、($1への捕獲で開始)"#"またはスペースでない文字全部のマッチが一回以上起こる(捕獲終了)。($2への捕獲で開始)一つ以上の桁(捕獲終了)が続き一回以上起こる任意の空白文字、前向きスラッシュ、及び任意の数の任意の文字の続く"tcp"が続くもの全部を、行末までマッチする。マッチ文字列(つまり行全部)を $1$2で置き換える。(これはサービス名、空白、及びポート番号を含む)。結果をTCPファイルハンドルに収容し、"$tcp" 変数を一つ増やす。これを "$ucp" 回繰り返す。

's///' ファンクションの中のデリミタに '=' 記号を使ったことに注意されたい。 '=' に特別の作用はない;regex の一部にあらわれる '/' 文字と'#' 文字(通常デリミタとして用いられる)と衝突しないようにしたのと、近くの市場に'=' があっただけである。別の文字または記号は同様に作用する。

他の二つの模範解答をも以下に示す:

1. 二つのファイルを開いてその内容を交換する。


#!/usr/bin/perl -w
# 内容を交換すべきファイルを "a" 及び "b" と命名する

for ( A, B ) { open $_, "<\l$_" or die "Can't open \l$_: $!\n"; }
@a = <A>; @b = <B>;

for ( A, B ) { open $_, ">\l$_" or die "Can't open \l$_: $!\n"; }
print A @b; print B @a;


極めて保守的で基本的な中身だ。一寸したカラクリは、ファイル名を小文字にするのに '\l' を使った。filehandleを再オープンすると、自動的にクローズする − 違う「オープン」の間でクローズする必要はない − ことに注意。また、ファイルの明確なクローズは常に不要である:Perlは、スクリプトを出るときハンドルをクローズする(OSによってはオープンのままにするものもあるので要注意)。それはともかく、Perlの現バージョン(5.6.1)は、上におこなったことを、もっと上手く行うスマートなメカニズムを持っている。


...
$FN = "/usr/X11R6/include/X11/Composite.h";
open FN or die "I choked on $FN: $!\n";
# "FN" is now open as a filehandle to "Composite.h".
...


今のディストリビューションは、Perl バージョン5.005.003 を搭載して来る。CPAN (下記参照)から 5.6.1.を入手して搭載されることを薦める。バージョンの異なるPerlは、同一マシン上で快適に共存する。(ディストリビューション以外のバージョンのPerlとの置換は、システム中身のPerl依存度によっては、難しい)

ファイルの名を変えれば同じ効果があると指摘したが、それは演習の目的はそんなことではない。


#!/usr/bin/perl -w
%h = qw/a $$.$$ b a $$.$$ b/;
rename $x, $y while ($x, $y) = each %h


ここでは、ファイル名のリストと一時変数 − "$$"は、シェル内のように、Perl内の実働プロセスIDで、"$$.$$" は殆ど確かに独自のファイル名である − を使い、"each"コマンドを用いてそれを循環させて、ハッシュを作った。これはキイ/値のペアをハッシュから回収する。"round-robin renaming"と呼んでよいだろう。

2. Read "/var/log/messages" を読み取って単語 "fail", "terminated/terminating", または" no " を含む行をプリントする。それを「大文字小文字の区別なし」にする。

これは簡単な一行スクリプトだ。


perl -wne 'print if /(fail|terminat(ed|ing)| no )/i' /var/log/messages


ここで面白いのは、マッチにおける "alternation" 機構だ:これにより "(abc|def|ghi)" のような文字列を、上の任意のものと行毎にマッチすることが出来る。

クイックツールの構築

数日前、テキストファイルを等価音声字母に転換する必要がおきた。多分プログラムはないので、自分で出来るだけ手軽に作ることにした。

1)音声字母のコピイをWebから入手してファイルにセーブした。ファイルを"phon"と名付けたが、次のようなものだ:

Alpha
Bravo
Charlie
Delta
Echo
Foxtrot
Golf
...

2)続いて、次のコマンドを出した。


perl -i -wple's/^(.)(.*)$/\t"\l$1" => "$1$2",/' phon


マジックだ! (置換作用の分解は下記を参照) ファイルは次のようになっている:

    "a" => "Alpha",
    "b" => "Bravo",
    "c" => "Charlie",
    "d" => "Delta",
    "e" => "Echo",
    "f" => "Foxtrot",
    "g" => "Golf",
    ...

3)数秒後に、必要なツール − 正確に1ファンクションと1データを構造内に含む − を獲得した。


#!/usr/bin/perl -wlp
# 2001年5月27日13:07:49、Benjamin Okopnik 作

s/([a-zA-Z])/$ph{"\l$1"} /g;

BEGIN {
  %ph = (
    "a" => "Alpha",
    "b" => "Bravo",
    "c" => "Charlie",
    "d" => "Delta",
    "e" => "Echo",
    "f" => "Foxtrot",
    "g" => "Golf",
    "h" => "Hotel",
    "i" => "India",
    "j" => "Juliet",
    "k" => "Kilo",
    "l" => "Lima",
    "m" => "Mike",
    "n" => "November",
    "o" => "Oscar",
    "p" => "Papa",
    "q" => "Quebec",
    "r" => "Romeo",
    "s" => "Sierra",
    "t" => "Tango",
    "u" => "Uniform",
    "v" => "Victor",
    "w" => "Whisky",
    "x" => "X-ray",
    "y" => "Yankee",
    "z" => "Zulu",
  );
}


上記のスクリプトは、キイボード入力でもファイルでもコマンド行アーギュメントとして受け付け、テキストの等価音声字母を返す。
これ − 特定の仕事をこなすのに必要なツールを手軽に作る − が、私の最も普通のPerl活用法である。他の人には他の用途があるだろう−TMTOWTDI [1] −だが私にはPerlのないコンピュータは興味半減だ。さらに薦めたい人は<http://language.perl.com/ppt/> を見られたい。

上手に書かれたPerlコードの見付かる場所は殆どない。プロジェクトが進行中だからだ。しかしUnicesは既に始めたし、Solaris 8 はシステムの一部として実行可能Perlスクリプト多数を持っており、

file /sbin/* /usr/bin/* /usr/sbin/*|grep -c perl

の中に、82個のPerlスクリプトを有して 、少なくともDebian "potato" ディストリビューションに示す。

さてそこで、上の s///'s 二つを説明しよう。先ず「マジック」コンバータだ。

perl -i -wple's/^(.)(.*)$/\t"\l$1" => "$1$2",/' phon

"-i", "-w", "-p", "-e"スイッチは、このシリーズのパート2で説明した。簡単に言うと、ファイルをループして各行に働きかけ、内容を編集する。Perl "warn"機構を起動するので、実行すべきスクリプトが、コマンド行から走る。"-l"は、行末処理を起動する。効果は、キャリッジリターンを持たない行にそれを加える。置換regexは次のように進む:

行頭からスタートして、($1への捕捉を開始)1文字をマッチ(捕捉終了、$2への捕捉を開始)。行末まで、任意の数の任意の文字を捕捉(捕捉終了)。

文字列置換は次のように進む:

タブをプリント、二重引用符で囲った小文字*の$1内容を続ける。スペースをプリントして、スペース、'=>' ダイグラフ、別のスペース、二重引用符で囲った$1$2、コンマを続ける.

* これは "\l"(次の文字を小文字に) オペレータが行う。

2番目のものは勉強の価値がある。置換の中でハッシュ値を使う(引き際のキイ変更を含む)との面白い特性を示すからだ。極めて有用だ:

s/([a-zA-Z])/$ph{"\l$1"} /g;

先ず、regex:

($1への捕捉で開始) 'a-zA-Z' の範囲内の任意文字をマッチ(捕捉終了)

次ぎに、文字列置換:

"%ph" hash から$1の内容の小文字版をキイとして使って、値を返しスペースを続ける。

BEGIN { ... }ブロックは、スクリプトが数千回ループするのに関わらず、ハッシュを1回限り事象に移す。ここでの機構は、前に述べたAwkと同じである。なすべきことのすべては、各文字を "%ph" ハッシュ内のキイとして用いて、そのキイに結び付く値をプリントすることである。

ハッシュはPerlの中の極めて有用な構造なので、勉強して理解するのが良い。

モジュラー構築

Perl − 生きて成長する言語 − について驚くべきことの一つは、それを取り巻いて成長する共同体である。数多くの人がコードの有用な断片に寄与し、それらが再使用されてPerlを地球上で最も有力な言語に育てている。

Webに出ていって、サーバーを繋ぎ、地域の天気や予報を返してプリントするプログラムを考えて見よう。Perlスクリプトたった1行を要するだけだ。

perl -MGeo::WeatherNOAA -we 'print print_forecast( "Denver", "CO" )'

これで全部だ。どうしたら出来るのか?

(注記:これは'Geo::WeatherNOAA'モジュールをシステムに搭載していないと働かない)

CPAN (包括的 Perl アーカイブ・ネットワーク)は、君の友達だ。 <http://cpan.org/> に行って探検すると、想像出来るプログラム課題の殆ど全部を行う設計のモジュールが沢山見付かる。PerlスクリプトをKlingonに転換したければ、Deutsche Bank Gruppe fundsから引き出せば良い。SMSメッセージを送るのは面倒かな?問題はない。文字通り数秒で出来る容易い仕事だ。

標準Perlディストリビューションは、多数の有用なモジュール(これらの簡単な説明は'perldoc perlmodlib'の "Standard Modules"を参照)を付けて来る。そのうち一つはCPANモジュールで、これはモジュールのダウンロード、構築、搭載を自動化する。これを使うには

perl -MCPAN -eshell

とタイプするだけで、プロンプトが続く。やり方を知るには少し複雑だが、手作業はCPAN 、<http://http://cpan.org/modules/INSTALL.html>の "How to install" に書いてある。これを読むことを薦める。二つのプロセスの間の相違は、"apt" (Debian)又は "rpm" (RedHat)を使うか、手でtarballを搭載するかの相違と似ている。'CPAN' は要求したものをサポートするすべての必要モジュールを取得し、すべてのテストとインストレーションをおこなうが、手作業では少し難しい。CPANモジュールを使うに特別のことは、

perldoc CPAN

とタイプするだけだ。

システムに搭載されたあらゆるモジュールに関する完全な情報に、同じ方法でアクセス出来る。ここで想像されるように、 コマンド行スイッチ"-M"が、特定モジュールの使用をPerlに告げる。スクリプトで入手したければ、シンタクスは下記:


#!/usr/bin/perl -w

use Finance::Quote;

$q = Finance::Quote->new;
my %stocks = $q->fetch("nyse","LNUX");
print "$k: $v\n" while ($k, $v) = each %stocks;


上記プログラム(働かせるには "Finance::Quote" が必要)はニューヨーク株式取引所のVA linux のすべてを告げる。5行にしては悪くない。

上記は、モジュールの、普及しつつある、オブジェクト−オリエント型の例である。Perlにモジュールの使用を告げた後、"Finance::Quote" クラスからオブジェクト新インスタンスを作成し、それを$qに割り当てる。次いで、"nyse" と"LNUX" 変数を用いて、"fetch" メソッド(メソッドはモジュールの文書に記載してある)を呼び出して、返されたハッシュに記憶された結果をプリントする。

多くのモジュールは、所謂 exporting 型で、これらは、プログラムに「プラグイン」したとき、簡単に追加ファンクションを与える。


#!/usr/bin/perl -w
use LWP::Simple;

$code = mirror( "http://slashdot.org", "slashdot.html" );
print "Slashdot returned a code of $code.\n";


この場合、"mirror" は LWP::Simple から来た新モジュールである。ある程度明らかなのは、与えられたWeb ペイジを、規定のファイルにコピイ("mirror")してコード(例えば、 'RC_NOT_FOUNDについては '404' )に戻ることである。
総まとめ

Perlの興味ある部分を駆け足で回った。もっと習いたいとの刺激になり、その能力を少しでも示していれば幸い。Perlの知識を伸ばしたい人のため、読む本を推薦する:

Learning Perl, 3rd Edition (coming out in July)
Randal Schwartz and Tom Phoenix

Programming Perl, 3rd Edition
Larry Wall, Tom Christiansen & Jon Orwant

Perl Coookbook
By Tom Christiansen & Nathan Torkington

Data Munging with Perl
By David Cross

Mastering Algorithms with Perl
By Jon Orwant, Jarkko Hietaniemi & John Macdonald

Mastering Regular Expressions
By Jeffrey E. F. Friedl

Elements of Programming with Perl
by Andrew Johnson

参考書:

Perl 関連マニュアル( pro-Perl-y 構成のシステムで利用可能):

perl   - overview       perlfaq  - Perl FAQ
perltoc  - doc TOC        perldata - data structures
perlsyn  - syntax        perlop  - operators/precedence
perlrun  - execution       perlfunc - builtin functions
perltrap - traps for the unwary perlstyle - style guide

"perldoc", "perldoc -q" and "perldoc -f"

 

Copyright © 2001, Ben Okopnik.
Copying license http://www.linuxgazette.com/copying.html
Published in Issue 69 of Linux Gazette, August 2001
 
 
 
 
DCMAニュース:ロシア人プログラマ逮捕

By Mike Orr

 

Digital Millennium Copyright Act (DMCA、著作権法)は、その最初の逮捕者を出した。ロシア人プログラマDmitry Sklyarovが、7月16日ラスベガスのDEF CON で講演した後、 Adobeのeブックフォーマットに関するセキュリテイが不適切の容疑で、FBIに逮捕された。講演のためだけでなく、本人の会社ElcomSoftが、前記eブックフォーマットを普通にPDFに転換する製品を販売したためである(本人も関与)。これは、コピイ防止の形で役立つ暗号を回避することを禁止したDCMAの回避規定に反する。売ったのが、このような法律のないロシア(カナダ又はヨーロッパにも未だない)なのは考慮しない。公平使用権の行使又は盲人が言語合成器に書物を読ませたときなど、ElcomSoft製品の合法的使用があることも考慮しない。

1週間後、幾つかの米国都市で反対運動が起こり、Dmitryの釈放を要求しAdobeとボイコットして、DCMAの撤回を求めた。電子フロンティア基金(EFF)がAdobeと話し合ってDmitryに対する訴追を撤回させ、釈放を要求した。しかし、Dmitryは依然としてオクラホマ監獄に抑留されており、その運命は米国司法省と裁判に委ねられている。一週間後(7月30日)司法省にDmitryの釈放を求め、議会にDCMAの撤回を求める別の反対運動が起こった。

DCMAは、技術者やコンピュータ初心者でなくとも、アメリカ人全部にとり重要問題だ。この法律は人々が認識するより遙かに早く変わり、常に持っていた権利が消滅して、読みたいときに読みたいものを読む権利−読んで批判する権利も−がなくなるからだ。

これはまた、米国人以外にとっても、重要問題だ。カナダは既に類似の法律を論議している。ヨーロッパでも、目を離した隙に企業ロビイストが代議士を手なづけないかと、心配している。既に、アメリカの技術者はカナダとヨーロッパに、自分達の仕事が非合法でると宣言されたここの場合のレジメを送り始めた。

Sklyarov とDMCAについては、余りに多くが書かれ語られているので、ここで繰り返すことはしないが、幾つかのリンクを指摘する。

Jail Time in the Digital Age (NYタイムスの優れた記事で、多くの問題を扱う。一週間無料、その後オンラインで買うか又は図書館で2001年7月30日分を見る)。
Arrest Raises Stakes in Battle Over Copyright (別の優れた NY タイムス記事、幾つかの問題点を解説する。オンラインで買うか又は図書館で2001年7月23日分を見る)
Wired and The Register (英国) シリーズ記事を書いた
We're Not Your Enemies; We're Your Customers ( 7月24日のSeattle protestに関する Linux Journal web 記事に、DCMAのプログラマに対する影響、いま、なすべきことがかいてある)
nodmca.org
http://www.freesklyarov.org/
http://www.anti-dmca.org/
Electronic Frontier Foundation (EFF)
Felten vs RIAA
The Right to Read (1997年の短編)
Linux Weekly News editorial ("DMCA"へのスクロールダウン)
http://www.freedmitry.org/
http://www.boycottadobe.org/ (e-ブック事件に関する技術的参考事項)

 

Copyright © 2001, Mike Orr.
Copying license http://www.linuxgazette.com/copying.html
Published in Issue 69 of Linux Gazette, August 2001
 
 
 
 
Linuxにトムキャットを搭載

By Allan Peda

 

Javaの利用が広まっている。幸い、Jakarta-Tomcat (以下Tomcatと呼ぶ)と言う、無料アScreencap of the Tomcat Demo Webプリケーションサーバーがある。これをダウンロードしてインストールしたので、その経験を報告する。Tomcatは、SuSE 7.2 を走らせるビンテージペンチアム2/2000上に搭載したが、ここに述べたステップは、Javaがソースをコンパイル出来る限り、最近のどのマシンにも通用すると思われる。

applet サーバーの搭載には、明らかに必要な Java とTomcatに加えて、幾つかのパケージをダウンロードしてコンパイルする必要がある。

Jakarta-Tomcat設定に必要なパケージ
パケージ ソース 
Java SDK 1.3.1  Sun 
XML Parser Library 1.1  Sun 
Java 1.0.2 用Secure Sockets Sun 
Java Servlet API 3.2.3  Apache Foundation 
Jakarta Ant 1.3  Apache Foundation 
Jakarta Tomcat 3.2.3  Apache Foundation 

 

Javaをインストールする

Javaのインストールは何度も記載されているので、繰り返す必要はないが、完全を期するため、RPMを使うステップを駆け足で復習する。SDK(JDKとも言う)のバージョン1.3をJava web siteからダウンロードしたが、1.4はベータだったので、今は出ているかも知れない。 Secure Sockets ライブラリには、1.4に含まれると書いてあるので、搭載がいくらか楽になるかも知れない。

Linux用には、JavaはRPMパケージを囲むスクリプトとして来るので、RPMを実際に搭載する前に、それを実行同意して搭載しなければならない。シェルスクリプトをアンパックしてRPMを生じた後、ルートとしての標準インストレーションに進む。

Java用RPM インストール (アンパック後)
  moby:~ > sudo rpm -Uv jdk-1.3.1.i386.rpm

 

JDKを含むようパスを変更したが、SuSE上でこれをおこなうには、/etc/profile.local をエディットすることを薦めが、他のディストリビューションでは /etc/profileをエディットする。$JAKARTA_HOMEと$TOMCAT_HOME用の環境変数は、搭載の一部として早晩必要になるので、今の内に設定する方が容易だ。最初はCLASSPATHを設定しなかったが、必要になる筈だ。Javaがライブラリを見出すことが出来るのを確認するため、次のステップを踏んだ。

必要環境変数
  #!/bin/bash
  JAVA_HOME=/usr/java/jdk1.3.1
  JAKARTA_HOME=/opt/jakarta
  ANT_HOME=$JAKARTA_HOME/jakarta-ant
  TOMCAT_HOME=$JAKARTA_HOME/build/tomcat
  PATH=$JAVA_HOME/bin:$PATH

  export JAVA_HOME JAKARTA_HOME ANT_HOME PATH TOMCAT_HOME
 
Java XML Parser ライブラリのインストール
ライブラリ拡張ディレクトリに(ルートとして)必要ライブラリをアンジップしてコピイすることによりXMLパーシング用ライブラリをインストールした。最初にこのファイルをホームディレクトリにアンジップした。Javaがインストールしたファイルを見付け出せるかぎり、ここにファイルをアンジップするのに問題はない:
XML Parser Library