AS/400展望台

IFSのホットな5つのヒント



Mel Beckman著

Michael Otey氏が「IFSアーキテクチャの簡易ガイド」http://www.e-bellnet.com/special/bn_idx_special.html#t_001で解説している通り、IFSはOS/400と他のオペレーティング・システム郡とのやりとりを容易にしてくれます。しかし相互運用性が得られる代わりに複雑性が増大します。IFSはiSeriesのプログラマには直感的ではない動作をすることがあります。ここに紹介する5つのヒントはIFSをより効果的に利用する際に役立つもので、知らぬ間にIFSプログラミングの疑問に答えてくれるものです。今回取りあげた5つのテーマは、IFSの新米ユーザーが最も混乱しやすいものだと思われます。それではご紹介しましょう。順番は特に重要ではありません。

ヒント1: IFSが消費するディスク領域を測定する

OS/400の単一レベル・ストレージ・コンセプトはオペレーティング・システムのアーキテクチャおよびソフトウェア開発にとって重宝な賜物です。データ・オブジェクトが占有する場所と領域を記録するという負荷がアプリケーション・プログラマやシステム・プログラマからオペレーティング・システム自体にシフトされます。これは膨大なディスク領域がある場合には大変有用な機能です。しかしディスクの残り領域がなくなると(外部ストレージの警告メッセージにはいつも脅かされます)、使用されている領域がどこかを調べて整理できるようにしておかなければなりません。

IFSにはリモートのシステムから書き込むことが可能であり、ストリーム・ファイルは急速に増大するので、ディスク領域が少なくなってくるとIFSがよく悪者にされます。理想的には、任意の時点でIFSがどれくらい領域を使用しているのかを確認した上でディスクの整理をいつ開始するのか、ディスク整理プロセス自体をいつ監視するのか、を知りたいわけです。残念ながらIBMはこれに対する答えを即座に提供できません。WRKSYSSTSを実行してすべての外部ストレージが消費している総領域サイズを調べることはできますが、IFSがどれくらい消費しているかはわかりません。OS/400はIFSの使用経過を継続的に把握しているわけではありませんので、IFSのディスク領域使用量を知るには特別なレポート機能を実行する必要があります。

このレポート機能はシステム・レポートと呼ばれており、DSIKTASKSメニューから起動できます。以下にその手順を示します。

・ CLコマンドラインでGO DISKTASKSと入力します。
・ オプション1の「ディスク領域情報の収集」を選択します(図1)。
・ 毎週または毎月レポートを作成するようにスケジュールします。または日時を指定してレポート機能を実行することもできます。
・ レポートが完了するまで1時間強待ちます(完了までの時間は、システム中のオブジェクトの数によって異なります。レポート結果を見るにはDISKTASKSメニューのオプション2の「ディスク領域情報の印刷」を選択します。
ディスク領域の使用状況の概要が1ページにまとめられます(図2)。「ユーザー・ライブラリ」の行はOS/400ネイティブのファイル・システムが使用するディスク領域をメガバイト単位で表示しています。「ユーザー・ディレクトリ」項目はQSYS.LIBファイル・システムとQDLS.LIBファイル・システムを除いたIFSの合計です(QSYS.LIBとQDLS.LIBのファイル・システムは技術的な意味ではIFSの一部ですがこのレポートではIFSディスク領域としてはカウントされません)。

ヒント2: 選択保存

IFSファイルをテープに保存するのは、QSYSファイル・システムおよびQDLSファイル・システムを除いたIFS全体を保存するのであれば簡単そうに見え、しかも事実簡単です。これは以下のコマンドを実行すればできます。

SAV DEV('qsys.lib/tap01.dev') +
    OBJ( +
       ('/*') +
       ('/QSYS.LIB' *OMIT) +
       ('/QDLS.LIB' *OMIT) +
     )

SAVはオブジェクト(OBJ)パラメータ・リストを使用して保存するファイルやファイル・システムを指定します。上述の例では、「/」と「*」のワイルド・カードで指定したルート・ディレクトリ下の、QSYS.LIBファイル・システムとQDLS.LIBファイル・システムを除いたすべてを保存するように指定しています。通常、QSYSとQDLSはOS/400の通常のバックアップで保存されるので、これらについては保存の必要性はないでしょう。このコマンドはフル・システム・バックアップ(オプション21)をGO SAVEメニューから実行したときにOS/400がIFS全体をバックアップするのに使用するコマンドです。また、SAVコマンドではテープ・ドライブを指定するのにOS/400ネイティブの記法(QSYS/TAP01)ではなくIFSの記法(qsys.lib/tap01.dev)を使用しなければならない点に注意してください。

しかしIFSの一部をだけを保存するには注意が必要です。サブ・ディレクトリ全体を保存するにはオブジェクト・リストの最初に唯一のオブジェクトとしてそのディレクトリへのパスを指定するだけで済みます。たとえば、

\SAV DEV('qsys.lib/tap01.dev') +
        OBJ( +
           ('/projects/mel') +
        )


というコマンドは/projects/melというディレクトリを保存します。一方、/projectsディレクトリ中の「mel」で始まるファイルだけを保存したい場合はどうでしょう。その場合、コマンドは以下のようにもっと複雑になります。

SAV DEV('qsys.lib/tap01.dev') +
  OBJ( +
     ('/projects/mel*' *INCLUDE) +
   )

上記のコマンドでは、「mel」で始まるファイルとディレクトリ(たとえば、melfunction.c、melformed.h、meladjusted.o、melcompiled など)が保存されます。ファイル名の一部と一致させるには*INCLUDEが必要であることを知っているIFSの初心者はほとんどいません。でもちょっと待ってください。それだけでは済まないのです。上記の例のうち、「melcompiled」というディレクトリ以外のファイルだけを保存したいとしましょう。その場合は以下のような記法を使用します。

SAV DEV('qsys.lib/tap01.dev') +
    OBJ( +
       ('/projects/mel*' *INCLUDE) +
       ('/projects/melcompiled' *OMIT) +
    )


ここで重要なのは、追加した選択子にはIFSのルートから始まるパスの左側部分がすべて含まれていなければならないということです。この結果、別々の複数のディレクトリを保存するにはそれぞれに対してフルパス名を指定しなければなりません。

SAV DEV('qsys.lib/tap01.dev') +
      OBJ( +
        ('/projects' *INCLUDE) +
        ('/documentation' *INCLUDE) +
        ('/http' *INCLUDE) +
     )


それぞれの選択子は別々にしておきたいわけですから、それぞれの選択子に対して*INCLUDEを指定しなければなりません。*OMIT文は常に*INCLUDEの直前にあるものに適用されますので、*OMITの前に*INCLUDEを指定します。1つのディレクトリ(たとえばルート・ディレクトリ)を保存するのは特別な場合なので、*INCLUDEが必要ないのです。

OBJリストのパターンに対してすべてのサブ・ディレクトリを含めたり含めなかったりするには、SUBTREEパラメータを使用します。このパラメータには*ALL(デフォルト)、*DIR、*OBJ、*NONEの4つの値を指定できます。デフォルトでは*ALLが指定され、オブジェクト・リストに指定されているディレクトリ下のすべてのサブ・ディレクトリのオブジェクトにマッチするすべてのオブジェクトを保存するという意味になります。*DIRは指定されたディレクトリの最初のレベルにあるオブジェクトおよびディレクトリ構造そのものを保存しますが、サブ・ディレクトリ中のオブジェクトは保存しません。*OBJは選択パターンに完全に一致したオブジェクトだけを保存します。*NONEはリストされたディレクトリの中身だけを保存し、サブ・ディレクトリ下はおろかその名前すら保存しません。

サブ・ディレクトリ中に大量の領域を占めるログ・ファイルのような必要不可欠ではないデータがある場合は*DIRオプションを使用するのがよいでしょう。ディレクトリを復元するときは、復元後にはそのディレクトリに最新のログ・ファイルが含まれている方がよいでしょう。

SAVEコマンドにはこの他にもたくさんのオプションがあり、いろいろと調べてみると役に立つでしょう。しかしディレクトリ・パスやワイルド・カードを使ったSAVコマンドの基本的な動作は初心者にはわかりづらいものかもしれません。ある程度経験を積んでから使用するようにしてください。

ヒント3: 自分自身へのFTP、手軽な裏技

IFSファイル・システムのディレクトリをプログラムから読むのはそれほど単純ではありません。確かにRPGプログラムやCプログラムから呼び出すことのできるAPIがありますが、IFSディレクトリのファイルの一覧をちょっと見たいだけという場合でも余計で複雑なコードを書かなければなりません。ここではFTPを使用したCLプログラムにディレクトリの一覧を表示させる手軽な裏技を紹介します。

この裏技は、CLプログラムを実行するマシンと同じマシンに対してそのCLプログラムからFTPを実行させ、続いてFTPのdirサブ・コマンドを実行してディレクトリの一覧を生成するものです。このコマンドにOS/400のオプションを使用すればディレクトリの一覧を物理的なファイルにリダイレクトすることができます。

図3に上記を実行するCLプログラムの例を示します。最初に、「INPUT」という名前のファイルを書き換えて、実行するFTPのサブ・コマンドを提供するソース・メンバーのスクリプトを指すようにします。そのファイル例を図4に示します。次に、カレントのライブラリがディレクトリの出力ファイルを格納したいライブラリを指すように変更します。このライブラリは、CLプログラムが書き込み権限をもっている場所であればどこでも構いません(但しQTEMPライブラリ以外)。最後に宛先IPアドレスに127.0.0.1を指定してFTPを起動します。このアドレスはループバック・アドレスと呼ばれる特別なアドレスで、TCP/IPプログラムが実行されているシステムを常に参照します。これはTCP/IPの標準ですので、すべてのTCP/IPプラットフォーム上で使用できます。

図4のFTPスクリプト・ファイルを見てみると内部の動作がわかります。このファイルの最初の行にはFTPログイン用のユーザーIDとパスワードを空白文字1字をはさんで書いておかなければなりません。FTPはこの行を使ってサーバーにログインしますので、このスクリプトは人目に触れないよう安全な場所に置いておかなければなりません。

次の行が実際に一覧を生成するための行です。一覧を生成したいIFSディレクトリのパス(ディレクトリ名でなければなりません)を指定し、その後に1文字空けて「(DISK」という文字列を指定します。DIRコマンドに(DISK引数を渡すと、CLプログラム中で指定したカレント・ライブラリのDIROUTPUTという名前のファイルにディレクトリを出力するようにOS/400のFTPクライアントに対して指示します。CLOSEとQUITという残りの2つのサブ・コマンドはそれぞれFTPサーバーを切断し、FTPクライアントを終了します。

このテクニックを使った出力例を図5に示します。EBCDICサーバーへFTPしたのでDIR OUTPUTファイルはEBCDICとなり、ファイル・タイプ、パス、日時・スタンプが表示されています。ファイル名だけでよい場合はFTPスクリプトのDIRサブ・コマンドの代わりにLS FTPサブ・コマンドを使用します。

さらにCLコマンドを追加したり、HLLプログラムに読み込ませたりしてこの出力ファイルを処理することもできます。たとえばこのCLプログラムでRPGサブファイル・プログラムを起動してDIROUTPUTの中身を表示させ、ユーザーに1つまたは複数の項目を選択させてさらに処理を進めることもできます。そしてそのRPGプログラムがCLプログラムに対して選択された項目を返します。

このテクニックを使用して他のiSeriesサーバーやiSeries以外のサーバーからもIFSディレクトリの一覧を取り出すことも可能です。ただしiSeries以外のサーバーから一覧を取り出す場合は、DIROUTPUTファイルはEBCDICではなくASCIIファイルとなるので、その出力をCLプログラムやRPGプログラムで使用する前にファイルの中身を変換する必要があります。

ヒント4: ディレクトリや奇妙な名前の削除

IFSのディレクトリやファイルをOS/400から操作するには対話型のWRKLNKコマンドで操作します。このコマンドで、開始ディレクトリを引数で指定していなければ、ルート(/)ディレクトリで始まるIFSディレクトリ構造内を移動することができます。またIFSファイルのコピー、削除、名前の変更、属性の表示が行えます。

残念ながらWRKLNKは空白文字を含んだ名前など奇妙な名前のディレクトリやファイルを削除しようとするとおかしな動作を起こすことがあります。ファイル、シンボリック・リンク、その他のサブ・ディレクトリなどを含むディレクトリを削除しようとするとWRKLNKは「要求の実行を完了できませんでした。ディレクトリにはオブジェクトが含まれています。」というメッセージを返します

同様に、奇妙な名前のファイルの削除、移動、名前の変更を行おうとすると、WRKLNKは指定されたファイルが不正であると返します。 上記のようなディレクトリを削除するには、まずディレクトリ構造で1つ上の階層に移動します。そこからoption 2=Editを使用して親ディレクトリ中のすべてのオブジェクトの一覧を表示する親ディレクトリを表示します。次にoption 9=Recursive deleteを使用して、ファイルやシンボリック・リンクの有無にかかわらず、対象とするディレクトリおよびそのサブ・ディレクトリを削除します。

「奇妙な名前」は(OS/400にとっては)不正なファイル名またはディレクトリ名ですので、OS/400のプログラムではないプログラムで作成できます。空白文字、スラッシュといった特殊文字を含んだ名前はWRKLNKやOS/400のIFSコマンドでは正しく解釈されないため、そうした名前のファイルやディレクトリを削除しようとすると問題が発生します。こうしたファイルはその名前を二重引用符で囲んでQSH RM(remove)コマンドにより削除することができます。引用符を使用すると(引用符以外の)任意の文字をエスケープできますので、RMコマンドでそのようなファイルを探したり削除したりできます。例を次に示します。

qsh
rm "WeIrD FiLe NaMe"


ファイル名に引用符が含まれている場合は、バックスラッシュ文字でその引用符をエスケープすることができます。

rm "Mel \"rotorhead\" Beckman"

チルダ(~)記号のような、EBCDICにはないASCII文字がファイル名に含まれている場合は、16進エスケープ文字\xHHを使用できます。たとえば「time~bandits」という名前のファイルを削除するには以下のように指定します。

rm "time\x98bandits"

ヒント5: 権限規則[Authority Rules]

このヒントのタイトル[Authority Rules]は名詞句[権限規則]にも平叙文[権限による支配]にも読めます。いずれにしろ、既存のOS/400アプリケーションとIFSとをうまく運用していくにはIFSの権限制限を理解しておかなければなりません。

IFSはUnix流の権限を使用しており、ファイルやディレクトリに対して「アクセス・モード」と呼ばれる許可フラグの集合体でこの権限を表現します。許可には読み出し、書き込み、実行の3つがあります。実行フラグは2つの役割を果たします。ファイルに対しては、そのファイルがプログラムとして実行可能であることを示し、ディレクトリに対してはそのディレクトリ内を検索可能であることを示します。

ほとんどの場合、OS/400はこの許可を*のような値で記号として表示するか、または3文字の文字列で表示します。たとえば、*RXと表示されればそれは読み出し許可と実行許可があることを意味し、*Xは実行許可だけがあることを示す、などといった具合です。これらのフラグは2進数の特定の位置のビットを占め、(たとえばFTP経由で)他のシステムからみると10進数値で表示されることがあります。この2進数のビット位置は読み出しフラグは1xx、書き込みフラグはx1x、実行フラグはxx1となっています。したがって5という値(2進数の「101」)は読み出し許可と実行許可があることを示し、1という値(2進数の「001」)は実行許可だけがあることを示します。

所有者、所有者のグループ、一般ユーザーそれぞれに3つの許可フラグがあります。これらを*OWNER、*GROUP、*PUBLICというキーワードで表します。

ある権限範囲にあるオブジェクトを別の権限範囲にコピーしようとすると問題が発生します。たとえば、CPYTOSTMFコマンドを使用してOS/400のデータ・ファイルをIFSにコピーするときは、CPYTOSTMFコマンドがソース・オブジェクトの所有者名や所有者の権限などといった権限情報を取り出して、作成されたIFSファイルにマッピングする必要があるので、OS/400のオブジェクトに対して*OBJMGT(Object Management) 権限を有していなければなりません。プログラムにこの権限がなければCPYTOSTMFコマンドは失敗します。

IFSでは読み込みや操作したいディレクトリのパス中のすべてのディレクトリに対して*RX許可が必要ですが、CDコマンドやchdir()関数でディレクトリ内を移動するには同じパス・ディレクトリに*X許可だけがあれば十分です。つまり、あるディレクトリに移動することはできてもそこにファイルを追加したり削除したり移動したりするための読み出し許可がないという場合がありえるということです。末端のディレクトリに対してRWX(または*ALL)許可を所有していたとしても、そのディレクトリのすべての親ディレクトリに対して*RX許可がないとそのディレクトリに対する操作は行えません。

IFSは新しく作成されたファイルやディレクトリに対して特別な方法で許可を割り当てますが、この方法がわかりづらいという人が多いようです。IFSは新しいオブジェクトの所有者名および所有者グループ名を、その新しいオブジェクトを含んでいるディレクトリの所有者に設定すると考えがちですが、そうではなく、その親ディレクトリの所有者に設定します。ただし*PUBLIC許可はそのオブジェクトを含んでいるディレクトリに設定します。この動作により、自分が作成したオブジェクトに何の許可ももらえないという不本意な副作用が発生します。

もしこの規則が一貫していれば、単にそれは覚えておかなければならない制限事項となるだけです。しかし悲しいかな、個々のプログラムは独自のユニークな動作をすることができるのです。たとえば、CPYTOSTMFはコピー元のOS/400オブジェクトから所有者の権限情報だけをコピーし、グループ名や権限はコピーしないので、*PUBLIC許可を0 (どのビットもオンにせず、したがって*NONEと同じ)に設定します。IFSのディレクトリにリモートからアクセスするWindowsやUnixのプログラムも同様に独自の方法でアクセスします。

このヒントの教訓は、許可の基本とIFSのデフォルトの動作を理解し、許可が自分の望んだ通りになるように常に確認しなければならない、ということです。IFSの問題は誤った許可設定に由来することが多いです。

最初の5つ

IFSの使用に関するヒントは今回ご紹介した5つに留まりませんし、上記の5つのヒントが万人にとって最も重要なものであるというわけでもありません。しかし上記のヒントを心得ておけば、自分のアプリケーションからIFSを上手に利用することができます。さらに次の5つのIFSに関するホットなヒントを近々ご紹介します。

Mel Beckman氏はこのホームページの提携先、Penton Media, Inc. が発行する「iSeries NEWS」誌のシニア・テクニカル・エディタです。)



↑このページのトップへ
TOPPAGE

BELLDATA, Inc. Copyright reserved.