アプリケーションパッケージ開発者ガイド

第 6 章 パッケージの作成のための高度な手法

Solaris OS で実装されている System V のパッケージ化機能では、ソフトウェア製品をインストールするための強力なツールが提供されます。パッケージの設計者はこれらの機能を利用できます。Solaris OS の一部ではないパッケージ (アンバンドルのパッケージ) では、クラスメカニズムを使用してサーバーおよびクライアントのインストールをカスタマイズできます。再配置可能パッケージは、管理者の要件に応じて設計できます。複雑な製品は、パッケージの依存関係が自動的に解決される複合パッケージのセットとして配信できます。パッケージの設計者は、アップグレードとパッチをカスタマイズできます。パッチを適用したパッケージは、パッチを適用していないパッケージと同じ方法で配信できます。また、製品にバックアウトアーカイブを含めることもできます。

この章の内容は以下のとおりです。

ベースディレクトリの指定

パッケージがインストールされる場所はさまざまな方法を使用して指定することができ、インストール時に動的にインストールベースを変更できることは重要です。インストール時に動的にインストールベースを変更できる場合、管理者は複数のバージョンと複数のアーキテクチャーを容易にインストールできます。

このセクションでは、最初に一般的な方法について説明してから、異機種システムへのインストールを行うアプローチを説明します。

管理デフォルトファイル

パッケージのインストールを行う管理者は、管理ファイルを使用してパッケージのインストールを制御できます。ただし、パッケージの設計者は、管理ファイルと、設計者が意図するパッケージのインストールを管理者がどのように変更できるかを理解する必要があります。

管理ファイルによって、通常行われるチェックやプロンプトを実行するかどうかが pkgadd コマンドに通知されます。そのため、管理者はパッケージのインストールプロセスと、関連するスクリプトについて理解してから管理ファイルを使用するようにしてください。

基本的な管理デフォルトファイルは、SunOS オペレーティングシステムの /var/sadm/install/admin/default に付属しています。これは、ソフトウェア製品のインストールに関して最も基本的な管理ポリシーを確立するファイルです。このファイルは、出荷時には次のようになっています。

#ident "@(#)default
1.4 92/12/23 SMI"	/* SVr4.0 1.5.2.1	*/ 
mail=
instance=unique
partial=ask
runlevel=ask
idepend=ask
rdepend=ask
space=ask
setuid=ask
conflict=ask
action=ask
basedir=default

管理者は、このファイルを編集して新しいデフォルト動作を確立したり、異なる管理ファイルを作成し、pkgadd コマンドに -a オプションを使用してファイルを指定したりすることができます。

管理ファイルでは 11 個のパラメータを定義できますが、すべてのパラメータを定義する必要はありません。詳細については、admin(4) を参照してください。

basedir パラメータは、パッケージをインストールする場合にベースディレクトリを取得する方法を指定します。ほとんどの管理者はこのパラメータを default のままにしますが、basedir は次のいずれかに設定できます。


注 –

pkgadd コマンドに引数 -a none を付けて呼び出した場合、常に管理者にベースディレクトリを確認します。ただし、この場合にはファイル内のすべてのパラメータがデフォルト値の quit に設定されます。これにより別の問題が発生する可能性があります。


疑問の解決

管理者は、管理ファイルを使用してシステム上のすべてのパッケージのインストールを制御できます。しかし、パッケージの設計者は、しばしば管理者の要望を無視して、代替の管理デフォルトファイルを組み込んでいます。

パッケージの設計者は、管理者ではなく設計者がパッケージのインストールを制御できるように代替管理ファイルを組み込む場合もあります。管理デフォルトファイルの basedir エントリはほかのすべてのベースディレクトリに優先するため、この方法でインストール時に簡単に適切なベースディレクトリを選択することができます。Solaris 2.5 リリースより前のすべてのバージョンの Solaris OS で、これがベースディレクトリを制御するもっとも簡単な方法だと考えられていました。

しかし、製品のインストールに関しては管理者の要望を受け入れる必要があります。インストールを制御するために一時的な管理デフォルトファイルを組み込む方法は、管理者の信用を失うことにつながります。request スクリプトと checkinstall スクリプトを使用して、管理者の監督の下でこれらのインストールを制御するようにしてください。request スクリプトを誠実に使用してプロセスに管理者を関与させることで、System V のパッケージ化は管理者とパッケージの設計者の双方にとって効果的に機能します。

BASEDIR パラメータの使用

すべての再配置可能パッケージの pkginfo ファイルに、次の形式のエントリでデフォルトベースディレクトリを含める必要があります。


BASEDIR=absolute_path

これは唯一のデフォルトベースディレクトリです。管理者はインストール時に変更できます。

複数のベースディレクトリが必要なパッケージもありますが、このパラメータを使用してパッケージを配置する利点は、ベースディレクトリが適切に配置され、インストール開始時に有効なディレクトリとして書き込み可能であることが保証されることです。サーバーとクライアントのベースディレクトリの適切なパスが、予約された環境変数の形式ですべての手続きスクリプトで使用可能になります。また、pkginfo -r SUNWstuf コマンドを使用すると、パッケージの現在のインストールベースを表示できます。

checkinstall スクリプトでは、BASEDIRpkginfo ファイルで定義されたままのパラメータです。まだ条件は付いていません。ターゲットベースディレクトリを検査するには、${PKG_INSTALL_ROOT}$BASEDIR 構成が必要です。つまり、request スクリプトまたは checkinstall スクリプトを使用して、インストール環境の BASEDIR の値を予測可能な結果に変更できます。システムがクライアントの場合でも、preinstall スクリプトを呼び出すときまでに、BASEDIR パラメータは、ターゲットシステム上の実際のベースディレクトリを指す条件付きポインタになります。


注 –

request スクリプトでは、SunOS オペレーティングシステムのリリースごとに異なる BASEDIR パラメータが使用されます。request スクリプトの BASEDIR パラメータをテストするには、次のコードを使用して、実際に使用されるベースディレクトリを判断するようにしてください。

# request script
constructs base directory
if [ ${CLIENT_BASEDIR} ]; then
	  LOCAL_BASE=$BASEDIR
else
	  LOCAL_BASE=${PKG_INSTALL_ROOT}$BASEDIR
fi

パラメータ型ベースディレクトリの使用

パッケージに複数のベースディレクトリが必要な場合、パラメータ型パス名を使用して複数のベースディレクトリを確立できます。この方法は一般的になりましたが、次の欠点があります。

ベースディレクトリを決定するパラメータは pkginfo ファイルで定義されますが、request スクリプトで変更できます。このことが、このアプローチが一般的である主な理由の 1 つです。ただし、欠点は長期にわたるものであるため、この構成は最後の手段として検討するようにしてください。

例 — パラメータ型ベースディレクトリの使用

pkginfo ファイル

# pkginfo file
PKG=SUNWstuf
NAME=software stuff 
ARCH=sparc
VERSION=1.0.0,REV=1.0.5
CATEGORY=application
DESC=a set of utilities that do stuff
BASEDIR=/
EZDIR=/usr/stuf/EZstuf
HRDDIR=/opt/SUNWstuf/HRDstuf
VENDOR=Sun Microsystems, Inc.
HOTLINE=Please contact your local service provider
EMAIL=
MAXINST=1000
CLASSES=none
PSTAMP=hubert980707141632

pkgmap ファイル

: 1 1758
1 d none $EZDIR 0775 root bin
1 f none $EZDIR/dirdel 0555 bin bin 40 773 751310229
1 f none $EZDIR/usrdel 0555 bin bin 40 773 751310229
1 f none $EZDIR/filedel 0555 bin bin 40 773 751310229
1 d none $HRDDIR 0775 root bin
1 f none $HRDDIR/mksmart 0555 bin bin 40 773 751310229
1 f none $HRDDIR/mktall 0555 bin bin 40 773 751310229
1 f none $HRDDIR/mkcute 0555 bin bin 40 773 751310229
1 f none $HRDDIR/mkeasy 0555 bin bin 40 773 751310229
1 d none /etc	? ? ?
1 d none /etc/rc2.d ? ? ?
1 f none /etc/rc2.d/S70dostuf 0744 root sys 450 223443
1 i pkginfo 348 28411 760740163
1 i postinstall 323 26475 751309908
1 i postremove 402 33179 751309945
1 i preinstall 321 26254 751310019
1 i preremove 320 26114 751309865

ベースディレクトリの管理

複数のバージョンまたは複数のアーキテクチャーで使用可能なパッケージは、必要に応じてベースディレクトリを調査して設計するようにしてください。ベースディレクトリの調査とは、以前のバージョンまたは異なるアーキテクチャーのパッケージがすでにベースディレクトリにインストールされている場合に、インストールされるパッケージがこの問題を解決することです。通常は、わずかに異なる名前で新しいベースディレクトリが作成されます。Solaris 2.5 および互換リリースの request スクリプトと checkinstall スクリプトには、BASEDIR 環境変数を変更する機能があります。これより前のバージョンの Solaris OS にはこの機能はありません。

古いバージョンの Solaris OS でも、request スクリプトにはインストールベース内のディレクトリを再定義する権限があります。request スクリプトは、ほとんどの管理設定をサポートするようにディレクトリを再定義できます。

再配置の対応

さまざまなパッケージに対して、アーキテクチャーおよびバージョンごとに一意であることが保証されるベースディレクトリを選択できますが、これによって不要なディレクトリ階層が作成されます。たとえば、SPARC ベースおよび x86 ベースのプロセッサ用の製品では、次のようにプロセッサとバージョンごとにベースディレクトリを編成できます。

ベースディレクトリ 

バージョンおよびプロセッサ 

/opt/SUNWstuf/sparc/1.0

バージョン 1.0、SPARC 

/opt/SUNWstuf/sparc/1.2

バージョン 1.2、SPARC 

/opt/SUNWstuf/x86/1.0

バージョン 1.0、x86 

これでも問題なく動作しますが、名前と数値が管理者にとって意味を持つように扱っています。より適切なアプローチは、管理者に説明して許可された後、これを自動的に実行することです。

つまり、設計者がパッケージのすべてのジョブを実行できます。管理者が手動で実行する必要はありません。設計者は任意のベースディレクトリを割り当て、postinstall スクリプトで透過的に適切なクライアントリンクを確立できます。また、pkgadd コマンドを使用して、パッケージのすべてまたは一部を postinstall スクリプトでクライアントにインストールすることもできます。このパッケージについて通知する必要があるユーザーまたはクライアントを管理者に確認して、PATH 環境変数と /etc ファイルを自動的に更新することもできます。これは、パッケージのインストール時に行った操作が削除時にすべて元に戻される限り許容されます。

ベースディレクトリの調査

インストール時にベースディレクトリを制御する方法は 2 通りあります。1 つ目の方法は、Solaris 2.5 および互換リリースのみに新しいパッケージをインストールする場合に最適です。この方法では、管理者に非常に有用なデータを提供し、複数のバージョンおよびアーキテクチャーのインストールをサポートし、最小限の作業で実行できます。2 つ目の方法は任意のパッケージで使用でき、構築パラメータに対する request スクリプト固有の制御を使用してインストールを実行します。

BASEDIR パラメータの使用

checkinstall スクリプトは、インストール時に適切なベースディレクトリを選択できます。つまり、ベースディレクトリをディレクトリツリー内の低い位置に配置できます。この例では、/opt/SUNWstuf/opt/SUNWstuf.1/opt/SUNWstuf.2 という形式でベースディレクトリを順に増加させます。管理者は、pkginfo コマンドを使用して、各ベースディレクトリにインストールするアーキテクチャーおよびバージョンを決定できます。

SUNWstuf パッケージ (要素となるユーティリティーのセットが含まれる) でこの方法を使用する場合、pkginfo ファイルおよび pkgmap ファイルは次のようになります。

pkginfo ファイル

# pkginfo file
PKG=SUNWstuf
NAME=software stuff 
ARCH=sparc
VERSION=1.0.0,REV=1.0.5
CATEGORY=application
DESC=a set of utilities that do stuff
BASEDIR=/opt/SUNWstuf
VENDOR=Sun Microsystems, Inc.
HOTLINE=Please contact your local service provider
EMAIL=
MAXINST=1000
CLASSES=none daemon
PSTAMP=hubert990707141632

pkgmap ファイル

: 1 1758
1 d none EZstuf 0775 root bin
1 f none EZstuf/dirdel 0555 bin bin 40 773 751310229
1 f none EZstuf/usrdel 0555 bin bin 40 773 751310229
1 f none EZstuf/filedel 0555 bin bin 40 773 751310229
1 d none HRDstuf 0775 root bin
1 f none HRDstuf/mksmart 0555 bin bin 40 773 751310229
1 f none HRDstuf/mktall 0555 bin bin 40 773 751310229
1 f none HRDstuf/mkcute 0555 bin bin 40 773 751310229
1 f none HRDstuf/mkeasy 0555 bin bin 40 773 751310229
1 d none /etc	? ? ?
1 d none /etc/rc2.d ? ? ?
1 f daemon /etc/rc2.d/S70dostuf 0744 root sys 450 223443
1 i pkginfo 348 28411 760740163
1 i postinstall 323 26475 751309908
1 i postremove 402 33179 751309945
1 i preinstall 321 26254 751310019
1 i preremove 320 26114 751309865
1 i i.daemon 509 39560 752978103
1 i r.daemon 320 24573 742152591

例 — BASEDIR を調査する分析スクリプト

x86 版の SUNWstuf がすでにサーバーの /opt/SUNWstuf にインストールされていると仮定します。管理者が pkgadd コマンドを使用して SPARC 版をインストールする場合、request スクリプトは x86 版を検出して、インストールに関して管理者と対話する必要があります。


注 –

checkinstall スクリプトでは管理者と対話しなくてもベースディレクトリを調査できますが、このような勝手な処理が頻繁に実行されると、プロセスに対する管理者の信頼を失います。


この状況を処理するパッケージの request スクリプトおよび checkinstall スクリプトは、次のようになっています。

request スクリプト

# request script
for SUNWstuf to walk the BASEDIR parameter.
 
PATH=/usr/sadm/bin:${PATH}	# use admin utilities
 
GENMSG="The base directory $LOCAL_BASE already contains a \
different architecture or version of $PKG."
 
OLDMSG="If the option \"-a none\" was used, press the  \
key and enter an unused base directory when it is requested."
 
OLDPROMPT="Do you want to overwrite this version? "
 
OLDHELP="\"y\" will replace the installed package, \"n\" will \
stop the installation."
 
SUSPEND="Suspending installation at user request using error \
code 1."
 
MSG="This package could be installed at the unused base directory $WRKNG_BASE."
 
PROMPT="Do you want to use to the proposed base directory? "
 
HELP="A response of \"y\" will install to the proposed directory and continue,
\"n\" will request a different directory. If the option \"-a none\" was used,
press the  key and enter an unused base directory when it is requested."
 
DIRPROMPT="Select a preferred base directory ($WRKNG_BASE) "
 
DIRHELP="The package $PKG will be installed at the location entered."
 
NUBD_MSG="The base directory has changed. Be sure to update \
any applicable search paths with the actual location of the \
binaries which are at $WRKNG_BASE/EZstuf and $WRKNG_BASE/HRDstuf."
 
OldSolaris=""
Changed=""
Suffix="0"
 
#
# Determine if this product is actually installed in the working
# base directory.
#
Product_is_present () {
	  if [ -d $WRKNG_BASE/EZstuf -o -d $WRKNG_BASE/HRDstuf ]; then
		    return 1
	  else
		    return 0
	  fi
}
 
if [ ${BASEDIR} ]; then
	  # This may be an old version of Solaris. In the latest Solaris
	  # CLIENT_BASEDIR won't be defined yet. In older version it is.
	  if [ ${CLIENT_BASEDIR} ]; then
		    LOCAL_BASE=$BASEDIR
		    OldSolaris="true"
	  else	# The base directory hasn't been processed yet
		    LOCAL_BASE=${PKG_INSTALL_ROOT}$BASEDIR
fi
 
WRKNG_BASE=$LOCAL_BASE
 
	# See if the base directory is already in place and walk it if
	# possible
while [ -d ${WRKNG_BASE} -a Product_is_present ]; do
		 # There is a conflict
		 # Is this an update of the same arch & version?
		 if [ ${UPDATE} ]; then
			   exit 0	# It's out of our hands.
		 else
			   # So this is a different architecture or
			   # version than what is already there.
			   # Walk the base directory
			   Suffix=`expr $Suffix + 1`
			   WRKNG_BASE=$LOCAL_BASE.$Suffix
			   Changed="true"
		 fi
done
 
	# So now we can propose a base directory that isn't claimed by
	# any of our other versions.
if [ $Changed ]; then
		 puttext "$GENMSG"
		 if [ $OldSolaris ]; then
			   puttext "$OLDMSG"
			   result=`ckyorn -Q -d "a" -h "$OLDHELP" -p "$OLDPROMPT"`
			   if [ $result="n" ]; then
				     puttext "$SUSPEND"
				     exit 1	# suspend installation
			   else
				     exit 0
			   fi
		 else	# The latest functionality is available
			   puttext "$MSG"
			   result=`ckyorn -Q -d "a" -h "$HELP" -p "$PROMPT"`
			   if [ $? -eq 3]; then
				     echo quitinstall >> $1
				     exit 0
			   fi
 
			   if [ $result="n" ]; then
				     WRKNG_BASE=`ckpath -ayw -d "$WRKNG_BASE" \
				     -h "$DIRHELP" -p "$DIRPROMPT"`
			   else if [ $result="a" ]
				     exit 0
			   fi
		    fi
		    echo "BASEDIR=$WRKNG_BASE" >> $1
		    puttext "$NUBD_MSG"
	  fi
fi
exit 0

checkinstall スクリプト

# checkinstall
script for SUNWstuf to politely suspend
 
grep quitinstall $1
if [ $? -eq 0 ]; then
	exit 3		# politely suspend installation
fi
 
exit 0

このアプローチは、ベースディレクトリが単に /opt だった場合には正常に機能しません。/opt を調査するのは困難であるため、このパッケージは BASEDIR をより正確に呼び出す必要があります。実際、マウントスキーマによっては不可能な場合もあります。この例では、/opt の下に新しいディレクトリを作成してベースディレクトリを調査しています。これによって問題が発生することはありません。

この例では request スクリプトと checkinstall スクリプトを使用しています。ただし、2.5 リリースより前のバージョンの Solaris では checkinstall スクリプトを実行することはできません。この例の checkinstall スクリプトは、quitinstall という文字列形式の非公開メッセージに応答して、インストールをていねいに停止するために使用されます。Solaris 2.3 リリースでこのスクリプトを実行する場合、checkinstall スクリプトは無視され、request スクリプトはエラーメッセージを表示してインストールを停止します。

Solaris 2.5 および互換リリースより前では、BASEDIR パラメータは読み取り専用パラメータであり、request スクリプトで変更することはできません。このため、(条件付きの CLIENT_BASEDIR 環境変数をテストして) 旧バージョンの SunOS オペレーティングシステムが検出された場合、request スクリプトには継続するか終了するかの 2 つのオプションしかありません。

相対パラメータ型パスの使用

ソフトウェア製品が旧バージョンの SunOS オペレーティングシステムにインストールされる可能性がある場合、request スクリプトで必要な作業をすべて実行する必要があります。このアプローチを使用すると、複数のディレクトリを操作することもできます。追加のディレクトリが必要な場合、簡単に管理できる製品を提供するには、単一のベースディレクトリの下にディレクトリを含める必要があります。BASEDIR パラメータでは最新の Solaris リリースで使用できる粒度のレベルは提供されませんが、request スクリプトを使用してパラメータ型パスを操作することで、パッケージからベースディレクトリを調査できます。pkginfo ファイルおよび pkgmap ファイルは次のようになります。

pkginfo ファイル

# pkginfo file
PKG=SUNWstuf
NAME=software stuff 
ARCH=sparc
VERSION=1.0.0,REV=1.0.5
CATEGORY=application
DESC=a set of utilities that do stuff
BASEDIR=/opt
SUBBASE=SUNWstuf
VENDOR=Sun Microsystems, Inc.
HOTLINE=Please contact your local service provider
EMAIL=
MAXINST=1000
CLASSES=none daemon
PSTAMP=hubert990707141632

pkgmap ファイル

: 1 1758
1 d none $SUBBASE/EZstuf 0775 root bin
1 f none $SUBBASE/EZstuf/dirdel 0555 bin bin 40 773 751310229
1 f none $SUBBASE/EZstuf/usrdel 0555 bin bin 40 773 751310229
1 f none $SUBBASE/EZstuf/filedel 0555 bin bin 40 773 751310229
1 d none $SUBBASE/HRDstuf 0775 root bin
1 f none $SUBBASE/HRDstuf/mksmart 0555 bin bin 40 773 751310229
1 f none $SUBBASE/HRDstuf/mktall 0555 bin bin 40 773 751310229
1 f none $SUBBASE/HRDstuf/mkcute 0555 bin bin 40 773 751310229
1 f none $SUBBASE/HRDstuf/mkeasy 0555 bin bin 40 773 751310229
1 d none /etc	? ? ?
1 d none /etc/rc2.d ? ? ?
1 f daemon /etc/rc2.d/S70dostuf 0744 root sys 450 223443
1 i pkginfo 348 28411 760740163
1 i postinstall 323 26475 751309908
1 i postremove 402 33179 751309945
1 i preinstall 321 26254 751310019
1 i preremove 320 26114 751309865
1 i i.daemon 509 39560 752978103
1 i r.daemon 320 24573 742152591

この例は完璧ではありません。pkginfo -r コマンドではインストールベースに /opt が返されますが、これは非常にあいまいです。多くのパッケージが /opt にありますが、少なくともこれは意味のあるディレクトリです。前の例と同様、次の例でも複数のアーキテクチャーおよびバージョンをサポートしています。request スクリプトは、特定のパッケージの要件に合わせて、適切な依存関係を解決することができます。

例 — 相対パラメータ型パスを調査する request スクリプト

# request script
for SUNWstuf to walk a parametric path
 
PATH=/usr/sadm/bin:${PATH}	# use admin utilities
 
MSG="The target directory $LOCAL_BASE already contains \
different architecture or version of $PKG. This package \
could be installed at the unused target directory $WRKNG_BASE."
 
PROMPT="Do you want to use to the proposed directory? "
 
HELP="A response of \"y\" will install to the proposed directory \
and continue, \"n\" will request a different directory. If \
the option \"-a none\" was used, press the <RETURN> key and \
enter an unused base directory when it is requested."
 
DIRPROMPT="Select a relative target directory under $BASEDIR/"
 
DIRHELP="The package $PKG will be installed at the location entered."
 
SUSPEND="Suspending installation at user request using error \
code 1."
 
NUBD_MSG="The location of this package is not the default. Be \
sure to update any applicable search paths with the actual \
location of the binaries which are at $WRKNG_BASE/EZstuf \
and $WRKNG_BASE/HRDstuf."
 
Changed=""
Suffix="0"
 
#
# Determine if this product is actually installed in the working
# base directory.
#
Product_is_present () {
	  if [ -d $WRKNG_BASE/EZstuf -o -d $WRKNG_BASE/HRDstuf ]; then
		    return 1
	  else
		    return 0
 
	  fi
}
 
if [ ${BASEDIR} ]; then
	  # This may be an old version of Solaris. In the latest Solaris
	  # CLIENT_BASEDIR won't be defined yet. In older versions it is.
	  if [ ${CLIENT_BASEDIR} ]; then
		    LOCAL_BASE=$BASEDIR/$SUBBASE
	  else	# The base directory hasn't been processed yet
		    LOCAL_BASE=${PKG_INSTALL_ROOT}$BASEDIR/$SUBBASE
	  fi
 
WRKNG_BASE=$LOCAL_BASE
 
# See if the base directory is already in place and walk it if
# possible
while [ -d ${WRKNG_BASE} -a Product_is_present ]; do
		 # There is a conflict
		 # Is this an update of the same arch & version?
		 if [ ${UPDATE} ]; then
			   exit 0	# It's out of our hands.
		 else
			   # So this is a different architecture or
			   # version than what is already there.
			   # Walk the base directory
			   Suffix=`expr $Suffix + 1`
			   WRKNG_BASE=$LOCAL_BASE.$Suffix
			   Changed="true"
		 fi
done
 
# So now we can propose a base directory that isn't claimed by
# any of our other versions.
if [ $Changed ]; then
		 puttext "$MSG"
		 result=`ckyorn -Q -d "a" -h "$HELP" -p "$PROMPT"`
		 if [ $? -eq 3 ]; then
			   puttext "$SUSPEND"
			   exit 1
		 fi
 
		 if [ $result="n" ]; then
			   WRKNG_BASE=`ckpath -lyw -d "$WRKNG_BASE" -h "$DIRHELP" \
			   -p "$DIRPROMPT"`
 
		    elif [ $result="a" ]; then
			       exit 0
		    else
			       exit 1
		    fi
		    echo SUBBASE=$SUBBASE.$Suffix >> $1
		    puttext "$NUBD_MSG"
	  fi
fi
exit 0

異機種システム混在環境での再配置のサポート

System V のパッケージ化の背後にあるもともとの概念では、システムごとに 1 つのアーキテクチャーを想定していました。サーバーの概念は設計に関与しませんでした。今では当然、単一のサーバーが複数のアーキテクチャーをサポートしています。つまり、1 つのサーバー上に同じソフトウェアが異なるアーキテクチャーごとに複数存在する場合があります。Solaris パッケージは推奨されるファイルシステムの境界内 (例: / および /usr) に隔離されていますが、サーバーおよび各クライアントの製品データベースでは、必ずしもすべてのインストールでこの分割がサポートされているわけではありません。特定の実装では、まったく異なる構造をサポートして、共通製品データベースを含んでいます。クライアントを異なるバージョンに向けることは簡単ですが、実際に System V のパッケージを異なるベースディレクトリにインストールした場合、管理者にとって複雑な状況をもたらす可能性があります。

パッケージを設計する場合、管理者が新しいバージョンのソフトウェアのインストールに使用する一般的な方法についても検討するようにしてください。管理者は、しばしば現在インストールされているバージョンと共存させて最新バージョンをインストールし、テストしようとします。その手順として、現在のバージョンとは異なるベースディレクトリに新しいバージョンをインストールして、少数の重要ではないクライアントをテストとして新しいバージョンにします。確信が得られたら、管理者はより多くのクライアントを新しいバージョンにします。最終的に、管理者は非常時用にのみ旧バージョンを保持して、最後には削除します。

つまり、現代の異機種システムで使用するパッケージは、管理者がファイルシステム上の任意の適切な場所に配置でき、正常に動作するという意味で本当の再配置をサポートする必要があります。Solaris 2.5 および互換リリースでは、多数の有用なツールが提供され、同じシステムに複数のアーキテクチャーおよびバージョンをクリーンにインストールできます。Solaris 2.4 および互換バージョンでも本当の再配置をサポートしていますが、そのための手順は明白ではありません。

従来のアプローチ

再配置可能パッケージ

System V ABI は、再配置可能パッケージの背後にある当初の目的は、パッケージのインストールを管理者にとってより便利にすることだったということを含意しています。今では、再配置可能パッケージの必要性はそれ以上のものになっています。利便性だけの問題ではなく、インストール時にアクティブなソフトウェア製品がすでにデフォルトディレクトリにインストールされている可能性が非常に高くなっています。この状況に対応できないパッケージは、既存の製品を上書きするか、インストールに失敗します。しかし、複数のアーキテクチャーおよび複数のバージョンに対応したパッケージは、スムーズにインストールでき、従来の管理方法と十分に互換性がある幅広いオプションを管理者に提供します。

ある意味で、複数のアーキテクチャーの問題と複数のバージョンの問題は同じです。既存のパッケージのバリアントは、ほかのバリアントと共存させてインストールできる必要があります。また、エクスポートされたファイルシステムのクライアントまたはスタンドアロンのコンシューマは、機能を低下させることなく、いずれかのバリアントに変更できる必要もあります。Sun はサーバー上で複数のアーキテクチャーに対応する方法を確立していますが、管理者はこれらの提案に従わない場合もあります。すべてのパッケージは、管理者のインストールに関する合理的な要望に応じることができるようにする必要があります。

例 - 従来の再配置可能パッケージ

この例では、従来の再配置可能パッケージを示します。パッケージは /opt/SUNWstuf に配置され、pkginfo ファイルおよび pkgmap ファイルは次のようになります。

pkginfo ファイル

# pkginfo file
PKG=SUNWstuf
NAME=software stuff 
ARCH=sparc
VERSION=1.0.0,REV=1.0.5
CATEGORY=application
DESC=a set of utilities that do stuff
BASEDIR=/opt
VENDOR=Sun Microsystems, Inc.
HOTLINE=Please contact your local service provider
EMAIL=
MAXINST=1000
CLASSES=none
PSTAMP=hubert990707141632

pkgmap ファイル

: 1 1758
1 d none SUNWstuf 0775 root bin
1 d none SUNWstuf/EZstuf 0775 root bin
1 f none SUNWstuf/EZstuf/dirdel 0555 bin bin 40 773 751310229
1 f none SUNWstuf/EZstuf/usrdel 0555 bin bin 40 773 751310229
1 f none SUNWstuf/EZstuf/filedel 0555 bin bin 40 773 751310229
1 d none SUNWstuf/HRDstuf 0775 root bin
1 f none SUNWstuf/HRDstuf/mksmart 0555 bin bin 40 773 751310229
1 f none SUNWstuf/HRDstuf/mktall 0555 bin bin 40 773 751310229
1 f none SUNWstuf/HRDstuf/mkcute 0555 bin bin 40 773 751310229
1 f none SUNWstuf/HRDstuf/mkeasy 0555 bin bin 40 773 751310229
1 i pkginfo 348 28411 760740163
1 i postinstall 323 26475 751309908
1 i postremove 402 33179 751309945
1 i preinstall 321 26254 751310019
1 i preremove 320 26114 751309865

これが従来の方法と呼ばれる理由は、すべてのパッケージオブジェクトが pkginfo ファイルの BASEDIR パラメータで定義されるベースディレクトリにインストールされるためです。たとえば、pkgmap ファイルの最初のオブジェクトは /opt/SUNWstuf ディレクトリにインストールされます。

絶対パッケージ

絶対パッケージは、ファイルシステムの特定のルート (/) にインストールされるパッケージです。絶対パッケージは、複数のバージョンおよびアーキテクチャーの立場から対処することが困難です。原則的に、すべてのパッケージを再配置可能にしてください。ただし、再配置可能パッケージに絶対的な要素を含める合理的な理由もあります。

例 - 従来の絶対パッケージ

SUNWstuf パッケージが絶対パッケージの場合、BASEDIR パラメータは pkginfo ファイルでは定義されず、pkgmap ファイルは次のようになります。

pkgmap ファイル

: 1 1758
1 d none /opt ? ? ?
1 d none /opt/SUNWstuf 0775 root bin
1 d none /opt/SUNWstuf/EZstuf 0775 root bin
1 f none /opt/SUNWstuf/EZstuf/dirdel 0555 bin bin 40 773 751310229
1 f none /opt/SUNWstuf/EZstuf/usrdel 0555 bin bin 40 773 751310229
1 f none /opt/SUNWstuf/EZstuf/filedel 0555 bin bin 40 773 751310229
1 d none /opt/SUNWstuf/HRDstuf 0775 root bin
1 f none /opt/SUNWstuf/HRDstuf/mksmart 0555 bin bin 40 773 751310229
1 f none /opt/SUNWstuf/HRDstuf/mktall 0555 bin bin 40 773 751310229
1 f none /opt/SUNWstuf/HRDstuf/mkcute 0555 bin bin 40 773 751310229
1 f none /opt/SUNWstuf/HRDstuf/mkeasy 0555 bin bin 40 773 751310229
1 i pkginfo 348 28411 760740163
1 i postinstall 323 26475 751309908
1 i postremove 402 33179 751309945
1 i preinstall 321 26254 751310019
1 i preremove 320 26114 751309865

この例では、管理者がインストール時に代替ベースディレクトリを指定した場合、pkgadd コマンドでは無視されます。このパッケージは、常にターゲットシステムの /opt/SUNWstuf にインストールされます。

pkgadd コマンドの -R 引数は予期されるとおりに機能します。たとえば、次のように指定します。


pkgadd -d . -R /export/opt/client3 SUNWstuf

オブジェクトは /export/opt/client3/opt/SUNWstuf にインストールされますが、これはこのパッケージが再配置可能になることとほぼ同じです。

pkgmap ファイルの /opt ディレクトリに疑問符 (?) を使用しています。これは、既存の属性を変更できないことを示します。これは「デフォルト属性でディレクトリを作成する」ということではありませんが、特定の状況ではそうなる場合もあります。新しいパッケージに固有のディレクトリは、すべての属性を明示的に指定する必要があります。

複合パッケージ

再配置可能オブジェクトを含むパッケージは、再配置可能パッケージと呼ばれます。再配置可能パッケージは pkgmap ファイルに絶対パスが含まれる場合があるため、これは誤解を招く可能性があります。pkgmap ファイルでルート (/) エントリを使用することで、パッケージの再配置可能な側面を強化できます。再配置可能なエントリとルートエントリの両方が含まれるパッケージは、複合パッケージと呼ばれます。

例 - 従来の解決方法

SUNWstuf パッケージのオブジェクトの 1 つが、実行レベル 2 で実行される起動スクリプトだと仮定します。/etc/rc2.d/S70dostuf ファイルはパッケージの一部としてインストールする必要がありますが、ベースディレクトリに配置することはできません。再配置可能パッケージが唯一の解決方法だとすると、pkginfo および pkgmap は次のようになります。

pkginfo ファイル

# pkginfo file
PKG=SUNWstuf
NAME=software stuff 
ARCH=sparc
VERSION=1.0.0,REV=1.0.5
CATEGORY=application
DESC=a set of utilities that do stuff
BASEDIR=/
VENDOR=Sun Microsystems, Inc.
HOTLINE=Please contact your local service provider
EMAIL=
MAXINST=1000
CLASSES=none
PSTAMP=hubert990707141632

pkgmap ファイル

: 1 1758
1 d none opt/SUNWstuf/EZstuf 0775 root bin
1 f none opt/SUNWstuf/EZstuf/dirdel 0555 bin bin 40 773 751310229
1 f none opt/SUNWstuf/EZstuf/usrdel 0555 bin bin 40 773 751310229
1 f none opt/SUNWstuf/EZstuf/filedel 0555 bin bin 40 773 751310229
1 d none opt/SUNWstuf/HRDstuf 0775 root bin
1 f none opt/SUNWstuf/HRDstuf/mksmart 0555 bin bin 40 773 751310229
1 f none opt/SUNWstuf/HRDstuf/mktall 0555 bin bin 40 773 751310229
1 f none opt/SUNWstuf/HRDstuf/mkcute 0555 bin bin 40 773 751310229
1 f none opt/SUNWstuf/HRDstuf/mkeasy 0555 bin bin 40 773 751310229
1 d none etc	? ? ?
1 d none etc/rc2.d ? ? ?
1 f none etc/rc2.d/S70dostuf 0744 root sys 450 223443
1 i pkginfo 348 28411 760740163
1 i postinstall 323 26475 751309908
1 i postremove 402 33179 751309945
1 i preinstall 321 26254 751310019
1 i preremove 320 26114 751309865

このアプローチと絶対パッケージのアプローチには大きな違いはありません。実際、これは絶対パッケージよりも良い状態です。管理者がこのパッケージの代替ベースディレクトリを指定した場合、このパッケージは機能しません。

このパッケージのファイルは 1 つだけルートと相対的にする必要がありますが、残りは任意の場所に移動できます。複合パッケージを使用してこの問題を解決する方法は、この節の後半で説明します。

従来の方法を超えて

この節で説明するアプローチはすべてのパッケージには適用されませんが、異機種システム混在環境にインストールする場合にパフォーマンスを向上できます。このアプローチは、Solaris OS の一部として提供されるパッケージ (バンドル版のパッケージ) にはほとんど適用されませんが、アンバンドルのパッケージでは従来とは異なるパッケージ化を実行できます。

再配置可能パッケージを奨励する理由は、次の要件をサポートするためです。

パッケージを追加または削除しても、インストールされたソフトウェア製品の既存の動作は変わりません。

アンバンドルのパッケージは、新しいパッケージが既存の製品と干渉しないことを保証できるように、/opt の下に配置するようにしてください。

複合パッケージの別の側面

有効な複合パッケージを構築する場合、次の 2 つの規則に従います。

つまり、「再配置可能」とはオブジェクトを任意の場所にインストールして実行できることを意味するため、ブート時に init で実行される起動スクリプトは再配置可能と見なすことができません。提供されるパッケージで相対パスとして /etc/passwd を指定することに問題はありませんが、配置できる場所は 1 つしかありません。

再配置可能に見える絶対パス名の作成

複合パッケージを構築する場合、インストールされた既存のソフトウェアに干渉しないように絶対パスを処理する必要があります。すべて /opt に含まれるパッケージでは、既存のファイルが存在しないためこの問題を回避できます。/etc のファイルがパッケージに含まれる場合、絶対パス名が相対パス名から予測されるのと同様に機能することを保証する必要があります。次の 2 つの例を考えてみましょう。

例 — ファイルの変更

説明

エントリがテーブルに追加されるか、オブジェクトがほかのプログラムまたはパッケージによって変更される可能性が高い新しいテーブルです。

実装

オブジェクトを、buildawk、または sed クラスに属するファイルタイプ e として定義します。この作業を実行するスクリプトは、自身を追加するのと同程度効率的に自身を削除する必要があります。

新しいソリッドステートのハードディスクをサポートするには、エントリを /etc/vfstab に追加する必要があります。

pkgmap ファイルのエントリは次のようになります。


1 e sed /etc/vfstab ? ? ?

request スクリプトは、パッケージで /etc/vfstab を変更するかどうかをオペレータに確認します。オペレータが "no" と答えると、このジョブを手動で実行する方法が表示され、次の処理が実行されます。


echo "CLASSES=none" >> $1

オペレータが "yes" と答えると、次の処理が実行されます。


echo "CLASSES=none sed" >> $1

これによって、必要な変更を行うクラスアクションスクリプトが起動されます。sed クラスは、パッケージファイル /etc/vfstab が、ターゲットシステム上の同じ名前のファイルに対するインストールおよび削除の両方の処理を含む sed プログラムであることを意味します。

例 — 新しいファイルの作成

説明

オブジェクトはまったく新しいファイルで、後から編集される可能性は高くありません。または、別のパッケージが所有するファイルを置き換えます。

実装

パッケージオブジェクトをファイルタイプ f として定義して、変更を取り消すことができるクラスアクションスクリプトを使用してインストールします。

ソリッドステートのハードディスクをサポートするために必要な情報を提供するには、/etc/etc/shdisk.conf という名前の新しいファイルが必要です。pkgmap ファイルのエントリは、次のようになります。


 
.
.
.
1 f newetc /etc/shdisk.conf
.
.
.

クラスアクションスクリプト i.newetc は、/etc に配置する必要があるファイルのインストールに使用されます。このスクリプトは、所定の場所に別のファイルが存在するかどうかを確認します。存在しない場合は新しいファイルをコピーするだけです。所定の場所にファイルが存在する場合、そのファイルをバックアップしてから新しいファイルをインストールします。スクリプト r.newetc は、必要に応じてこれらのファイルを削除して、元のファイルを復元します。インストールスクリプトの重要な部分を次に示します。

# i.newetc
while read src dst; do
	  if [ -f $dst ]; then
	    dstfile=`basename $dst`
	    cp $dst $PKGSAV/$dstfile
	  fi
	  cp $src $dst
done
 
if [ "${1}" = "ENDOFCLASS" ]; then
	  cd $PKGSAV
	  tar cf SAVE.newetc .
	  $INST_DATADIR/$PKG/install/squish SAVE.newetc
fi

このスクリプトでは、PKGSAV 環境変数を使用して置き換えるファイルのバックアップを格納しています。引数 ENDOFCLASS がスクリプトに渡された場合、これらがこのクラスの最後のエントリであることをスクリプトに通知するのは pkgadd コマンドです。この時点で、パッケージのインストールディレクトリに格納された非公開の圧縮プログラムを使用して、保存されたファイルがアーカイブおよび圧縮されます。

パッケージの更新時には PKGSAV 環境変数の使用は信頼性がありませんが、(たとえばパッチによって) パッケージが更新されない場合、バックアップファイルはセキュリティー保護されています。次の削除スクリプトには、旧バージョンの pkgrm コマンドがスクリプトに PKGSAV 環境変数への正しいパスを渡さないという別の問題に対応するコードが含まれています。

削除スクリプトは次のようになります。

# r.newetc
 
# make sure we have the correct PKGSAV
if [ -d $PKG_INSTALL_ROOT$PKGSAV ]; then
	  PKGSAV="$PKG_INSTALL_ROOT$PKGSAV"
fi
 
# find the unsquish program
UNSQUISH_CMD=`dirname $0`/unsquish
 
while read file; do
	  rm $file
done
 
if [ "${1}" = ENDOFCLASS ]; then
	  if [ -f $PKGSAV/SAVE.newetc.sq ]; then
	     $UNSQUISH_CMD $PKGSAV/SAVE.newetc
	  fi
 
	  if [ -f $PKGSAV/SAVE.newetc ]; then
	     targetdir=dirname $file	# get the right directory
	     cd $targetdir
		    tar xf $PKGSAV/SAVE.newetc
		    rm $PKGSAV/SAVE.newetc
	  fi
fi

このスクリプトでは、パッケージデータベースのインストールディレクトリの非公開アンインストールアルゴリズム (unsquish) が使用されます。これはインストール時に pkgadd コマンドによって自動的に実行されます。pkgadd コマンドによって明確にインストール専用として認識されないスクリプトはすべて、pkgrm コマンドで使用するためにこのディレクトリに残されます。このディレクトリの場所を知ることはできませんが、このディレクトリが平坦で、パッケージの適切な情報ファイルおよびインストールスクリプトがすべて含まれていることは信頼できます。このスクリプトでは、 unsquish プログラムが含まれるディレクトリからクラスアクションスクリプトが実行されることが保証されていることに基づいてディレクトリを検索します。

また、このスクリプトでは、ターゲットディレクトリが /etc だけであるとは仮定していません。実際には /export/root/client2/etc である場合もあります。正しいディレクトリは、2 通りの方法のいずれかで構成できます。

パッケージ内の絶対オブジェクトごとにこのアプローチを使用することで、現在の望ましい動作が変わらないか、少なくとも回復可能であることを保証できます。

例 — 複合パッケージ

次に示すのは、複合パッケージに対して pkginfo ファイルと pkgmap ファイルを使用する例です。

pkginfo ファイル

PKG=SUNWstuf
NAME=software stuff 
ARCH=sparc
VERSION=1.0.0,REV=1.0.5
CATEGORY=application
DESC=a set of utilities that do stuff
BASEDIR=/opt
VENDOR=Sun Microsystems, Inc.
HOTLINE=Please contact your local service provider
EMAIL=
MAXINST=1000
CLASSES=none daemon
PSTAMP=hubert990707141632

pkgmap ファイル

: 1 1758
1 d none SUNWstuf/EZstuf 0775 root bin
1 f none SUNWstuf/EZstuf/dirdel 0555 bin bin 40 773 751310229
1 f none SUNWstuf/EZstuf/usrdel 0555 bin bin 40 773 751310229
1 f none SUNWstuf/EZstuf/filedel 0555 bin bin 40 773 751310229
1 d none SUNWstuf/HRDstuf 0775 root bin
1 f none SUNWstuf/HRDstuf/mksmart 0555 bin bin 40 773 751310229
1 f none SUNWstuf/HRDstuf/mktall 0555 bin bin 40 773 751310229
1 f none SUNWstuf/HRDstuf/mkcute 0555 bin bin 40 773 751310229
1 f none SUNWstuf/HRDstuf/mkeasy 0555 bin bin 40 773 751310229
1 d none /etc	? ? ?
1 d none /etc/rc2.d ? ? ?
1 e daemon /etc/rc2.d/S70dostuf 0744 root sys 450 223443
1 i i.daemon 509 39560 752978103
1 i pkginfo 348 28411 760740163
1 i postinstall 323 26475 751309908
1 i postremove 402 33179 751309945
1 i preinstall 321 26254 751310019
1 i preremove 320 26114 751309865
1 i r.daemon 320 24573 742152591

S70dostufdaemon クラスに属しますが、これにつながるディレクトリ (インストール時に配置済み) は none クラスに属します。ディレクトリがこのパッケージに固有の場合でも、none クラスのままにしてください。この理由は、最初にディレクトリを作成して、最後に削除する必要がありますが、これは none クラスの場合も常に該当するためです。pkgadd コマンドによってディレクトリが作成されます。このディレクトリは、パッケージからコピーされたり、作成されるクラスアクションスクリプトに渡されたりすることはありません。その代わり、pkgadd コマンドで作成してからインストールクラスアクションスクリプトが呼び出され、削除クラスアクションスクリプトの完了後に、pkgrm コマンドによってディレクトリが削除されます。

つまり、特殊クラスのディレクトリに none クラスのオブジェクトが含まれる場合、pkgrm コマンドでディレクトリを削除しようとすると、ディレクトリが時間内に空にならないので失敗します。none クラスのオブジェクトが特殊クラスのディレクトリに挿入される場合、時間内にオブジェクトを受け入れるディレクトリは存在しません。pkgadd コマンドにより、オブジェクトのインストール時にオンザフライでディレクトリが作成され、最終的に pkgmap 定義を確認した場合にそのディレクトリの属性を同期できない場合があります。


注 –

クラスにディレクトリを割り当てる場合は、常に作成と削除の順序を覚えておいてください。


リモートでインストール可能なパッケージの作成

すべてのパッケージをリモートでインストール可能にする必要があります。リモートでインストール可能とは、パッケージをインストールする管理者が、pkgadd コマンドを実行するシステムのルート (/) ファイルシステムにインストールすることを仮定できないということです。手続きスクリプトの 1 つで、ターゲットシステムの /etc/vfstab ファイルを取得する必要がある場合、PKG_INSTALL_ROOT 環境変数を使用する必要があります。つまり、パス名 /etc/vfstab を使用して pkgadd コマンドを実行するシステムの /etc/vfstab ファイルを取得できますが、管理者はクライアントの /export/root/client3 にインストールする場合もあります。パス ${PKG_INSTALL_ROOT}/etc/vfstab は、ターゲットファイルシステムを取得できることが保証されています。

例 – クライアントシステムへのインストール

この例では、SUNWstuf パッケージを、ルート (/) ファイルシステムの /opt で構成された client3 にインストールします。このパッケージのほかのバージョンの 1 つが、すでに client3 にインストールされています。また、ベースディレクトリは管理ファイル thisadmin から basedir=/opt/$PKGINST に設定されています。管理ファイルの詳細については、「管理デフォルトファイル」を参照してください。サーバーで実行する pkgadd コマンドは、次のとおりです。


# pkgadd -a thisadmin -R /export/root/client3 SUNWstuf

次の表は、環境変数と、手続きスクリプトに渡される値の一覧です。

表 6–1 手続きスクリプトに渡される値

環境変数 

値 

PKGINST

SUNWstuf.2

PKG_INSTALL_ROOT

/export/root/client3

CLIENT_BASEDIR

/opt/SUNWstuf.2

BASEDIR

/export/root/client3/opt/SUNWstuf.2

例 – サーバーまたはスタンドアロンシステムへのインストール

前の例と同じ状況でサーバーまたはスタンドアロンシステムにインストールするには、次のコマンドを使用します。


# pkgadd -a thisadmin SUNWstuf

次の表は、環境変数と、手続きスクリプトに渡される値の一覧です。

表 6–2 手続きスクリプトに渡される値

環境変数 

値 

PKGINST

SUNWstuf.2

PKG_INSTALL_ROOT

未定義 

CLIENT_BASEDIR

/opt/SUNWstuf.2

BASEDIR

/opt/SUNWstuf.2

例 – 共有ファイルシステムのマウント

SUNWstuf パッケージにより、サーバーに /export/SUNWstuf/share を作成し、ファイルシステムを共有すると仮定します。パッケージをクライアントシステムにインストールする場合、/etc/vfstab ファイルを更新して、この共有ファイルシステムにマウントする必要があります。これは、CLIENT_BASEDIR 変数を使用できる場合です。

クライアントのエントリは、クライアントのファイルシステムを参照してマウントポイントを指定する必要があります。インストールをサーバーから行う場合でもクライアントから行う場合でも、この行を正確に構成するようにしてください。サーバーのシステム名は $SERVER であるとします。$PKG_INSTALL_ROOT/etc/vfstab に移動して、sed コマンドまたは awk コマンドを使用してクライアントの /etc/vfstab ファイルの次の行を構成します。


$SERVER:/export/SUNWstuf/share - $CLIENT_BASEDIR/usr nfs - yes ro

たとえば、サーバー universe とクライアントシステム client9 の場合、クライアントシステムの /etc/vfstab ファイルは、次の行になります。


universe:/export/SUNWstuf/share - /opt/SUNWstuf.2/usr nfs - yes ro

これらのパラメータを正確に使用して、ローカルで構成する場合でもサーバーから構成する場合でも常にクライアントのファイルシステムをマウントします。

パッケージのパッチ

パッケージのパッチは、元のパッケージの特定のファイルを上書きするためのスパースパッケージです。供給媒体の容量を節約することを除いて、スパースパッケージを出荷することに実質的な理由はありません。少数のファイルを変更して元のパッケージ全体を出荷したり、ネットワーク上で変更されたパッケージにアクセスできるようにしたりすることもできます。実際に異なっているのはこれらの新しいファイルだけである (その他のファイルは再コンパイルされていない) 場合に限り、pkgadd コマンドで差分をインストールできます。パッケージのパッチについては、次のガイドラインを確認してください。

パッチパッケージのバージョン番号を、元のパッケージのバージョン番号と同じにすることが重要です。次の形式の pkginfo ファイルエントリを個別に使用して、パッケージのパッチステータスを管理するようにしてください。


PATCH=patch_number

パッチのためにパッケージのバージョンが変わる場合、パッケージの別のインスタンスを作成します。パッチを適用された製品を管理することは極めて困難になります。この連続的なインスタンスパッチの方法は、Solaris OS の早期リリースで一定の利点をもたらしましたが、複雑なシステムの管理は単調なものとなります。

パッチ内のすべてのゾーンパラメータがパッケージ内のゾーンパラメータと一致している必要があります。

Solaris OS を構成するパッケージに関する限り、パッケージデータベースにはパッケージのコピーは 1 つしかありません。ただし、パッチを適用されたインスタンスは複数ある場合があります。インストールされたパッケージから (removef コマンドを使用して) オブジェクトを削除するには、そのファイルを所有するインスタンスを特定する必要があります。

ただし、(Solaris OS の一部ではない) パッケージが、Solaris OS の一部である特定のパッケージのパッチレベルを決定する必要がある場合は問題になります。この問題の解決方法をここで説明します。インストールスクリプトは、ターゲットファイルシステムに格納されないため、重大な影響を与えることなく大きくすることができます。クラスアクションスクリプトおよびその他のさまざまな手続きスクリプトにより、PKGSAV 環境変数 (またはその他の永続的なディレクトリ) を使用して、変更されたファイルを保存し、インストールされたパッチのバックアウトを可能にすることができます。また、request スクリプトで適切な環境変数を設定して、パッチの履歴を監視することもできます。次の節のスクリプトでは、複数のパッチが存在する可能性があることを仮定しています。パッチの番号付けスキーマは、単一のパッケージに適用する場合に意味を持ちます。この場合、個別のパッチ番号は、パッケージ内の機能的に関連したファイルのサブセットを表します。2 つのパッチ番号が異なる場合、同じファイルを変更することはできません。

通常のスパースパッケージをパッチパッケージにするには、次の節で説明するスクリプトをパッケージに組み込みます。最後の 2 つが patch_checkinstall および patch_postinstall という名前であることを除いて、すべてを標準パッケージコンポーネントとして認識できます。パッチのバックアウト機能が必要な場合には、これら 2 つのスクリプトをバックアウトパッケージに組み込むことができます。スクリプトは非常に単純で、さまざまな作業は明確です。


注 –

このパッチの方法は、クライアントシステムのパッチに使用できますが、サーバー上のクライアントルートディレクトリには、ユーザーの install または nobody で読み取りできる適切な権限が必要です。


checkinstall スクリプト

checkinstall スクリプトを使用して、特定のパッケージについてパッチが適切であることを確認します。確認が終わると、パッチ一覧パッチ情報一覧が作成され、レスポンスファイルに挿入してパッケージデータベースに組み込まれます。

パッチ一覧は現在のパッケージに影響するパッチの一覧です。このパッチ一覧は、インストールされたパッケージの pkginfo ファイルに次のような行で記録されます。

PATCHLIST=patch_id patch_id ...

パッチ情報一覧は、現在のパッチが依存しているパッチの一覧です。パッチ情報一覧も、pkginfo ファイルに次のような行で記録されます。

PATCH_INFO_103203-01=Installed... Obsoletes:103201-01 Requires: \ Incompatibles: 120134-01

注 –

これらの行 (およびその形式) は、公開インタフェースとして宣言されています。Solaris パッケージのパッチを出荷する企業は、この一覧を適切に更新するようにしてください。パッチが提供される場合、パッチ内の各パッケージにはこの作業を実行する checkinstall スクリプトが含まれます。同じ checkinstall スクリプトにより、その他のパッチ固有のパラメータも更新されます。これは、直接インスタンスパッチと呼ばれる新しいパッチアーキテクチャーです。


この例では、元のパッケージとそのパッチの両方が同じディレクトリに存在します。2 つの元のパッケージは、SUNWstuf.v1 および SUNWstuf.v2 という名前です。パッチは、 SUNWstuf.p1 および SUNWstuf.p2 という名前です。これによって、手続きスクリプトでこれらのファイルの元のディレクトリを特定するのは非常に困難になる場合があります。PKG パラメータではパッケージ名の点 (.) の後ろがすべて削除され、PKGINST 環境変数はソースインスタンスではなくインストールされたインスタンスを参照するためです。手続きスクリプトでソースディレクトリを特定するには、checkinstall スクリプト (常にソースディレクトリから実行される) で照会を行い、SCRIPTS_DIR 変数として場所を渡します。SUNWstuf というソースディレクトリにパッケージが 1 つしかなかった場合には、手続きスクリプトで $INSTDIR/$PKG を使用して検出できました。

# checkinstall script to control a patch installation.
# directory format options.
#
#       @(#)checkinstall 1.6 96/09/27 SMI
#
# Copyright (c) 1995 by Sun Microsystems, Inc.
# All rights reserved
#
 
PATH=/usr/sadm/bin:$PATH
 
INFO_DIR=`dirname $0`
INFO_DIR=`dirname $INFO_DIR`    # one level up
 
NOVERS_MSG="PaTcH_MsG 8 Version $VERSION of $PKG is not installed on this system."
ALRDY_MSG="PaTcH_MsG 2 Patch number $Patch_label is already applied."
TEMP_MSG="PaTcH_MsG 23 Patch number $Patch_label cannot be applied until all \
restricted patches are backed out."
 
# Read the provided environment from what may have been a request script
. $1
 
# Old systems can't deal with checkinstall scripts anyway
if [ "$PATCH_PROGRESSIVE" = "true" ]; then
        exit 0
fi
 
#
# Confirm that the intended version is installed on the system.
#
if [ "${UPDATE}" != "yes" ]; then
        echo "$NOVERS_MSG"
        exit 3
fi
 
#
# Confirm that this patch hasn't already been applied and
# that no other mix-ups have occurred involving patch versions and
# the like.
#
Skip=0
active_base=`echo $Patch_label | nawk '
        { print substr($0, 1, match($0, "Patchvers_pfx")-1) } '`
active_inst=`echo $Patch_label | nawk '
        { print substr($0, match($0, "Patchvers_pfx")+Patchvers_pfx_lnth) } '`
 
# Is this a restricted patch?
if echo $active_base | egrep -s "Patchstrict_str"; then
        is_restricted="true"
        # All restricted patches are backoutable
        echo "PATCH_NO_UNDO=" >> $1
else
        is_restricted="false"
fi
 
for patchappl in ${PATCHLIST}; do
        # Is this an ordinary patch applying over a restricted patch?
        if [ $is_restricted = "false" ]; then
                if echo $patchappl | egrep -s "Patchstrict_str"; then
                        echo "$TEMP_MSG"
                        exit 3;
                fi
        fi
 
        # Is there a newer version of this patch?
        appl_base=`echo $patchappl | nawk '
                { print substr($0, 1, match($0, "Patchvers_pfx")-1) } '`
        if [ $appl_base = $active_base ]; then
                appl_inst=`echo $patchappl | nawk '
                        { print substr($0, match($0, "Patchvers_pfx")\
+Patchvers_pfx_lnth) } '`
                result=`expr $appl_inst \> $active_inst`
                if [ $result -eq 1 ]; then
                        echo "PaTcH_MsG 1 Patch number $Patch_label is \
superceded by the already applied $patchappl."
                        exit 3
                elif [ $appl_inst = $active_inst ]; then
                        # Not newer, it's the same
                        if [ "$PATCH_UNCONDITIONAL" = "true" ]; then
                                if [ -d $PKGSAV/$Patch_label ]; then
                                        echo "PATCH_NO_UNDO=true" >> $1
                                fi
                        else
                                echo "$ALRDY_MSG"
                                exit 3;
                        fi
                fi
        fi
done
 
# Construct a list of applied patches in order
echo "PATCHLIST=${PATCHLIST} $Patch_label" >> $1
 
#
# Construct the complete list of patches this one obsoletes
#
ACTIVE_OBSOLETES=$Obsoletes_label
 
if [ -n "$Obsoletes_label" ]; then
        # Merge the two lists
        echo $Obsoletes_label | sed 'y/\ /\n/' | \
        nawk -v PatchObsList="$PATCH_OBSOLETES" '
        BEGIN {
                printf("PATCH_OBSOLETES=");
                PatchCount=split(PatchObsList, PatchObsComp, " ");
 
                for(PatchIndex in PatchObsComp) {
                        Atisat=match(PatchObsComp[PatchIndex], "@");
                        PatchObs[PatchIndex]=substr(PatchObsComp[PatchIndex], \
0, Atisat-1);
                        PatchObsCnt[PatchIndex]=substr(PatchObsComp\
[PatchIndex], Atisat+1);
                }
        }
        {
                Inserted=0;
                for(PatchIndex in PatchObs) {
                        if (PatchObs[PatchIndex] == $0) {
                                if (Inserted == 0) {
                                        PatchObsCnt[PatchIndex]=PatchObsCnt\
[PatchIndex]+1;
                                        Inserted=1;
                                } else {
                                        PatchObsCnt[PatchIndex]=0;
                                }
                        }
                }
                if (Inserted == 0) {
                        printf ("%s@1 ", $0);
                }
                next;
        }        
        END {
                for(PatchIndex in PatchObs) {
                        if ( PatchObsCnt[PatchIndex] != 0) {
                                printf("%s@%d ", PatchObs[PatchIndex], \
PatchObsCnt[PatchIndex]);
                        }
                }
                printf("\n");
        } ' >> $1
        # Clear the parameter since it has already been used.
        echo "Obsoletes_label=" >> $1
 
        # Pass it's value on to the preinstall under another name
        echo "ACTIVE_OBSOLETES=$ACTIVE_OBSOLETES" >> $1
fi
 
#
# Construct PATCH_INFO line for this package.
#                        
 
tmpRequire=`nawk -F= ' $1 ~ /REQUIR/ { print $2 } ' $INFO_DIR/pkginfo `
tmpIncompat=`nawk -F= ' $1 ~ /INCOMPAT/ { print $2 } ' $INFO_DIR/pkginfo `
 
if [ -n "$tmpRequire" ] && [ -n "$tmpIncompat" ]
then
        echo "PATCH_INFO_$Patch_label=Installed: `date` From: `uname -n` \
          Obsoletes: $ACTIVE_OBSOLETES Requires: $tmpRequire \
          Incompatibles: $tmpIncompat" >> $1
elif [ -n "$tmpRequire" ]
then
        echo "PATCH_INFO_$Patch_label=Installed: `date` From: `uname -n` \
          Obsoletes: $ACTIVE_OBSOLETES Requires: $tmpRequire \
Incompatibles: " >> $1
elif [ -n "$tmpIncompat" ]
then
        echo "PATCH_INFO_$Patch_label=Installed: `date` From: `uname -n` \
          Obsoletes: $ACTIVE_OBSOLETES Requires: Incompatibles: \
$tmpIncompat" >> $1
else
        echo "PATCH_INFO_$Patch_label=Installed: `date` From: `uname -n` \
          Obsoletes: $ACTIVE_OBSOLETES Requires: Incompatibles: " >> $1
fi
 
#
# Since this script is called from the delivery medium and we may be using
# dot extensions to distinguish the different patch packages, this is the
# only place we can, with certainty, trace that source for our backout
# scripts. (Usually $INST_DATADIR would get us there).
#
echo "SCRIPTS_DIR=`dirname $0`" >> $1
 
# If additional operations are required for this package, place
# those package-specific commands here.
 
#XXXSpecial_CommandsXXX#
 
exit 0

preinstall スクリプト

preinstall スクリプトは、構成されるバックアウトパッケージの prototype ファイル、情報ファイル、およびインストールスクリプトの初期化を行います。このスクリプトは非常に単純で、この例の残りのスクリプトではバックアウトパッケージに通常のファイルを記述することしかできません。

バックアウトパッケージのシンボリックリンク、ハードリンク、デバイス、および名前付きパイプを復元する場合、pkgproto コマンドを使用するように preinstall スクリプトを変更して、提供される pkgmap ファイルをインストールされたファイルと比較できます。その後、バックアウトパッケージの変更されないファイルごとに prototype ファイルエントリが作成されます。使用する方法は、クラスアクションスクリプトの方法と同様です。

スクリプト patch_checkinstall および patch_postinstall は、preinstall スクリプトからパッケージソースツリーに挿入されます。これら 2 つのスクリプトにより、パッチが取り消されます。

# This script initializes the backout data for a patch package
# directory format options.
#
#       @(#)preinstall 1.5 96/05/10 SMI
#
# Copyright (c) 1995 by Sun Microsystems, Inc.
# All rights reserved
#
 
PATH=/usr/sadm/bin:$PATH
recovery="no"
 
if [ "$PKG_INSTALL_ROOT" = "/" ]; then
        PKG_INSTALL_ROOT=""
fi
 
# Check to see if this is a patch installation retry.
if [ "$INTERRUPTION" = "yes" ]; then
    if [ -d "$PKG_INSTALL_ROOT/var/tmp/$Patch_label.$PKGINST" ] || [ -d \
"$PATCH_BUILD_DIR/$Patch_label.$PKGINST" ]; then
        recovery="yes"
    fi
fi
 
if [ -n "$PATCH_BUILD_DIR" -a -d "$PATCH_BUILD_DIR" ]; then
        BUILD_DIR="$PATCH_BUILD_DIR/$Patch_label.$PKGINST"
else
        BUILD_DIR="$PKG_INSTALL_ROOT/var/tmp/$Patch_label.$PKGINST"
fi
 
FILE_DIR=$BUILD_DIR/files
RELOC_DIR=$BUILD_DIR/files/reloc
ROOT_DIR=$BUILD_DIR/files/root
PROTO_FILE=$BUILD_DIR/prototype
PKGINFO_FILE=$BUILD_DIR/pkginfo
THIS_DIR=`dirname $0`
 
if [ "$PATCH_PROGRESSIVE" = "true" ]; then
        # If this is being used in an old-style patch, insert
        # the old-style script commands here.
 
        #XXXOld_CommandsXXX#
 
        exit 0
fi
 
#
# Unless specifically denied, initialize the backout patch data by
# creating the build directory and copying over the original pkginfo
# which pkgadd saved in case it had to be restored.
#
if [ "$PATCH_NO_UNDO" != "true" ] && [ "$recovery" = "no" ]; then
        if [ -d $BUILD_DIR ]; then
                rm -r $BUILD_DIR
        fi
 
        # If this is a retry of the same patch then recovery is set to
        # yes. Which means there is a build directory already in
        # place with the correct backout data.
 
        if [ "$recovery" = "no" ]; then
                mkdir $BUILD_DIR
                mkdir -p $RELOC_DIR
                mkdir $ROOT_DIR
        fi
 
        #
        # Here we initialize the backout pkginfo file by first
        # copying over the old pkginfo file and themn adding the
        # ACTIVE_PATCH parameter so the backout will know what patch
        # it's backing out.
        #
        # NOTE : Within the installation, pkgparam returns the
        # original data.
        #
        pkgparam -v $PKGINST | nawk '
                $1 ~ /PATCHLIST/        { next; }
                $1 ~ /PATCH_OBSOLETES/  { next; }
                $1 ~ /ACTIVE_OBSOLETES/ { next; }
                $1 ~ /Obsoletes_label/  { next; }
                $1 ~ /ACTIVE_PATCH/     { next; }
                $1 ~ /Patch_label/      { next; }
                $1 ~ /UPDATE/   { next; }
                $1 ~ /SCRIPTS_DIR/      { next; }
                $1 ~ /PATCH_NO_UNDO/    { next; }
                $1 ~ /INSTDATE/ { next; }
                $1 ~ /PKGINST/  { next; }
                $1 ~ /OAMBASE/  { next; }
                $1 ~ /PATH/     { next; }
                { print; } ' > $PKGINFO_FILE
        echo "ACTIVE_PATCH=$Patch_label" >> $PKGINFO_FILE
        echo "ACTIVE_OBSOLETES=$ACTIVE_OBSOLETES" >> $PKGINFO_FILE
 
        # And now initialize the backout prototype file with the
        # pkginfo file just formulated.
        echo "i pkginfo" > $PROTO_FILE
 
        # Copy over the backout scripts including the undo class
        # action scripts
        for script in $SCRIPTS_DIR/*; do
                srcscript=`basename $script`
                targscript=`echo $srcscript | nawk '
                        { script=$0; }
                        /u\./ {
                                sub("u.", "i.", script);
                                print script;
                                next;
                        }
                        /patch_/ {
                                sub("patch_", "", script);
                                print script;
                                next;
                        }
                        { print "dont_use" } '`
                if [ "$targscript" = "dont_use" ]; then
                        continue
                fi
 
                echo "i $targscript=$FILE_DIR/$targscript" >> $PROTO_FILE
                cp $SCRIPTS_DIR/$srcscript $FILE_DIR/$targscript
        done
         #
        # Now add entries to the prototype file that won't be passed to
        # class action scripts. If the entry is brand new, add it to the
        # deletes file for the backout package.
        #
        Our_Pkgmap=`dirname $SCRIPTS_DIR`/pkgmap
        BO_Deletes=$FILE_DIR/deletes
 
        nawk -v basedir=${BASEDIR:-/} '
                BEGIN { count=0; }
                {
                        token = $2;
                        ftype = $1;
                }
                $1 ~ /[#\!:]/ { next; }
                $1 ~ /[0123456789]/ {
                        if ( NF >= 3) {
                                token = $3;
                                ftype = $2;
                        } else {
                                next;
                        }
                }
                { if (ftype == "i" || ftype == "e" || ftype == "f" || ftype == \
"v" || ftype == "d") { next; } }
                {
                        equals=match($4, "=")-1;
                        if ( equals == -1 ) { print $3, $4; }
                        else { print $3, substr($4, 0, equals); }
                }
                ' < $Our_Pkgmap | while read class path; do
                        #
                        # NOTE: If pkgproto is passed a file that is
                        # actually a hard link to another file, it
                        # will return ftype "f" because the first link
                        # in the list (consisting of only one file) is
                        # viewed by pkgproto as the source and always
                        # gets ftype "f".
                        #
                        # If this isn't replacing something, then it
                        # just goes to the deletes list.
                        #
                        if valpath -l $path; then
                                Chk_Path="$BASEDIR/$path"
                                Build_Path="$RELOC_DIR/$path"
                                Proto_From="$BASEDIR"
                        else    # It's an absolute path
                                Chk_Path="$PKG_INSTALL_ROOT$path"
                                Build_Path="$ROOT_DIR$path"
                                Proto_From="$PKG_INSTALL_ROOT"
                        fi
                         #
                        # Hard links have to be restored as regular files.
                        # Unlike the others in this group, an actual
                        # object will be required for the pkgmk.
                        #
                        if [ -f "$Chk_Path" ]; then
                                mkdir -p `dirname $Build_Path`
                                cp $Chk_Path $Build_Path
                                cd $Proto_From
                                pkgproto -c $class "$Build_Path=$path" 1>> \
$PROTO_FILE 2> /dev/null
                                cd $THIS_DIR
                        elif [ -h "$Chk_Path" -o \
                             -c "$Chk_Path" -o \
                             -b "$Chk_Path" -o \
                             -p "$Chk_Path" ]; then
                                pkgproto -c $class "$Chk_Path=$path" 1>> \
$PROTO_FILE 2> /dev/null
                        else
                                echo $path >> $BO_Deletes
                        fi
                done
fi
 
# If additional operations are required for this package, place
# those package-specific commands here.
 
#XXXSpecial_CommandsXXX#
 
exit 0

クラスアクションスクリプト

クラスアクションスクリプトにより、既存のファイルを置き換えるファイルごとにコピーを作成して、バックアウトパッケージの prototype ファイルに対応する行を追加します。この処理はすべて、非常に単純な nawk スクリプトを使用して実行します。クラスアクションスクリプトは、対応するインストール済みファイルに一致しない通常のファイルからなるソースとターゲットのペアの一覧を受け取ります。シンボリックリンクおよびその他のファイル以外のものは、preinstall スクリプトで対応する必要があります。

# This class action script copies the files being replaced
# into a package being constructed in $BUILD_DIR. This class
# action script is only appropriate for regular files that
# are installed by simply copying them into place.
#
# For special package objects such as editable files, the patch
# producer must supply appropriate class action scripts.
#
# directory format options.
#
#       @(#)i.script 1.6 96/05/10 SMI
#
# Copyright (c) 1995 by Sun Microsystems, Inc.
# All rights reserved
#
 
PATH=/usr/sadm/bin:$PATH
 
ECHO="/usr/bin/echo"
SED="/usr/bin/sed"
PKGPROTO="/usr/bin/pkgproto"
EXPR="/usr/bin/expr"    # used by dirname
MKDIR="/usr/bin/mkdir"
CP="/usr/bin/cp"
RM="/usr/bin/rm"
MV="/usr/bin/mv"
 
recovery="no"
Pn=$$
procIdCtr=0
 
CMDS_USED="$ECHO $SED $PKGPROTO $EXPR $MKDIR $CP $RM $MV"
LIBS_USED=""
 
if [ "$PKG_INSTALL_ROOT" = "/" ]; then
        PKG_INSTALL_ROOT=""
fi
 
# Check to see if this is a patch installation retry.
if [ "$INTERRUPTION" = "yes" ]; then
        if [ -d "$PKG_INSTALL_ROOT/var/tmp/$Patch_label.$PKGINST" ] || 
\
[ -d "$PATCH_BUILD_DIR/$Patch_label.$PKGINST" ]; then
                recovery="yes"
        fi
fi
 
if [ -n "$PATCH_BUILD_DIR" -a -d "$PATCH_BUILD_DIR" ]; then
        BUILD_DIR="$PATCH_BUILD_DIR/$Patch_label.$PKGINST"
else
        BUILD_DIR="$PKG_INSTALL_ROOT/var/tmp/$Patch_label.$PKGINST"
fi
 
FILE_DIR=$BUILD_DIR/files
RELOC_DIR=$FILE_DIR/reloc
ROOT_DIR=$FILE_DIR/root
BO_Deletes=$FILE_DIR/deletes
PROGNAME=`basename $0`
 
if [ "$PATCH_PROGRESSIVE" = "true" ]; then
        PATCH_NO_UNDO="true"
fi
 
# Since this is generic, figure out the class.
Class=`echo $PROGNAME | nawk ' { print substr($0, 3)  }'`
 
# Since this is an update, $BASEDIR is guaranteed to be correct
BD=${BASEDIR:-/}
 
cd $BD
 
#
# First, figure out the dynamic libraries that can trip us up.
#
if [ -z "$PKG_INSTALL_ROOT" ]; then
        if [ -x /usr/bin/ldd ]; then
                LIB_LIST=`/usr/bin/ldd $CMDS_USED | sort -u | nawk '
                        $1 ~ /\// { continue; }
                        { printf "%s ", $3 } '`
        else
                LIB_LIST="/usr/lib/libc.so.1 /usr/lib/libdl.so.1 
\
/usr/lib/libw.so.1 /usr/lib/libintl.so.1 /usr/lib/libadm.so.1 \
/usr/lib/libelf.so.1"
        fi
fi
 
#
# Now read the list of files in this class to be replaced. If the file
# is already in place, then this is a change and we need to copy it
# over to the build directory if undo is allowed. If it's a new entry
# (No $dst), then it goes in the deletes file for the backout package.
#
procIdCtr=0
while read src dst; do
        if [ -z "$PKG_INSTALL_ROOT" ]; then
                Chk_Path=$dst
                for library in $LIB_LIST; do
                        if [ $Chk_Path = $library ]; then
                                $CP $dst $dst.$Pn
                                LIBS_USED="$LIBS_USED $dst.$Pn"
                                LD_PRELOAD="$LIBS_USED"
                                export LD_PRELOAD
                        fi
                done
        fi
 
        if [ "$PATCH_PROGRESSIVE" = "true" ]; then
                # If this is being used in an old-style patch, insert
                # the old-style script commands here.
 
                #XXXOld_CommandsXXX#
                echo >/dev/null # dummy
        fi
 
        if [ "${PATCH_NO_UNDO}" != "true" ]; then
                #
                # Here we construct the path to the appropriate source
                # tree for the build. First we try to strip BASEDIR. If
                # there's no BASEDIR in the path, we presume that it is
                # absolute and construct the target as an absolute path
                # by stripping PKG_INSTALL_ROOT. FS_Path is the path to
                # the file on the file system (for deletion purposes).
                # Build_Path is the path to the object in the build
                # environment.
                #
                if [ "$BD" = "/" ]; then
                        FS_Path=`$ECHO $dst | $SED s@"$BD"@@`
                else
                        FS_Path=`$ECHO $dst | $SED s@"$BD/"@@`
                fi
 
                # If it's an absolute path the attempt to strip the
                # BASEDIR will have failed.
                if [ $dst = $FS_Path ]; then
                        if [ -z "$PKG_INSTALL_ROOT" ]; then
                                FS_Path=$dst
                                Build_Path="$ROOT_DIR$dst"
                        else
                                Build_Path="$ROOT_DIR`echo $dst | \
                                    sed s@"$PKG_INSTALL_ROOT"@@`"
                                FS_Path=`echo $dst | \
                                    sed s@"$PKG_INSTALL_ROOT"@@`
                        fi
                else
                        Build_Path="$RELOC_DIR/$FS_Path"
                fi
 
                if [ -f $dst ]; then    # If this is replacing something
                        cd $FILE_DIR
                        #
                        # Construct the prototype file entry. We replace
                        # the pointer to the filesystem object with the
                        # build directory object.
                        #
                        $PKGPROTO -c $Class $dst=$FS_Path | \
                            $SED -e s@=$dst@=$Build_Path@ >> \
                            $BUILD_DIR/prototype
 
                        # Now copy over the file
                        if [ "$recovery" = "no" ]; then
                                DirName=`dirname $Build_Path`
                                $MKDIR -p $DirName
                                $CP -p $dst $Build_Path
                        else
                                # If this file is already in the build area skip it
                                if [ -f "$Build_Path" ]; then
                                        cd $BD
                                        continue
                                else
                                        DirName=`dirname $Build_Path`
                                        if [ ! -d "$DirName" ]; then
                                                $MKDIR -p $DirName
                                        fi
                                        $CP -p $dst $Build_Path
                                fi        
                        fi
 
                        cd $BD
                else    # It's brand new
                        $ECHO $FS_Path >> $BO_Deletes
                fi
        fi
 
        # If special processing is required for each src/dst pair,
        # add that here.
        #
        #XXXSpecial_CommandsXXX#
        #
 
        $CP $src $dst.$$$procIdCtr
        if [ $? -ne 0 ]; then
                $RM $dst.$$$procIdCtr 1>/dev/null 2>&1
        else
                $MV -f $dst.$$$procIdCtr $dst
                for library in $LIB_LIST; do
                        if [ "$library" = "$dst" ]; then
                                LD_PRELOAD="$dst"
                                export LD_PRELOAD
                        fi
                done
        fi                       
        procIdCtr=`expr $procIdCtr + 1`
done      
 
# If additional operations are required for this package, place
# those package-specific commands here.
 
#XXXSpecial_CommandsXXX#
 
#
# Release the dynamic libraries
#
for library in $LIBS_USED; do
        $RM -f $library
done
 
exit 0

postinstall スクリプト

postinstall スクリプトにより、その他のスクリプトで提供される情報を使用して、バックアウトパッケージを作成します。pkgmk コマンドおよび pkgtrans コマンドではパッケージデータベースは必要ではないため、パッケージのインストール内で実行できます。

例では、(PKGSAV 環境変数を使用して) 保存ディレクトリにストリーム形式パッケージを作成することで、パッチの取り消しが可能になります。明白ではありませんが、pkgadd 処理の際に保存ディレクトリが移動されるため、このパッケージはストリーム形式にする必要があります。パッケージ自体の保存ディレクトリで pkgadd コマンドをパッケージに適用する場合、任意の時点でのパッケージソースの場所に関する想定の信頼性が非常に低くなります。ストリーム形式のパッケージは一時ディレクトリに展開され、一時ディレクトリからインストールされます。ディレクトリ形式のパッケージでは、保存ディレクトリからインストールが開始され、pkgadd 復旧処理時に突然再配置されます。

パッケージに適用するパッチを決定するには、次のコマンドを使用します。


$ pkgparam SUNWstuf PATCHLIST

Sun の公開インタフェースである PATCHLIST を除いて、この例のパラメータ名には意味はありません。PATCH の代わりに、従来の SUNW_PATCHID および PATCH_EXCL などのほかの一覧を使用して、それに合うように PATCH_REQD の名前を変更することができます。

特定のパッチパッケージが、同じ媒体から利用できるほかのパッチパッケージに依存している場合、checkinstall スクリプトでこれを決定して、アップグレードの例 (「パッケージのアップグレード」を参照) と同じ方法で postinstall スクリプトから実行されるスクリプトを作成できます。

# This script creates the backout package for a patch package
#
# directory format options.
#
# @(#) postinstall 1.6 96/01/29 SMI
#
# Copyright (c) 1995 by Sun Microsystems, Inc.
# All rights reserved
#
 
# Description:
#       Set the TYPE parameter for the remote file
#
# Parameters:
#       none
#
# Globals set:
#       TYPE
 
set_TYPE_parameter () {
        if [ ${PATCH_UNDO_ARCHIVE:?????} = "/dev" ]; then
                # handle device specific stuff
                TYPE="removable"
        else
                TYPE="filesystem"
        fi
}
 
#
# Description:
#       Build the remote file that points to the backout data
#
# Parameters:
#       $1:     the un/compressed undo archive
#
# Globals set:
#       UNDO, STATE
 
build_remote_file () {
        remote_path=$PKGSAV/$Patch_label/remote
        set_TYPE_parameter
        STATE="active"
 
        if [ $1 = "undo" ]; then
                UNDO="undo"
        else
                UNDO="undo.Z"
        fi
 
        cat > $remote_path << EOF
# Backout data stored remotely
TYPE=$TYPE
FIND_AT=$ARCHIVE_DIR/$UNDO
STATE=$STATE
EOF
}
 
PATH=/usr/sadm/bin:$PATH
 
if [ "$PKG_INSTALL_ROOT" = "/" ]; then
        PKG_INSTALL_ROOT=""
fi
 
if [ -n "$PATCH_BUILD_DIR" -a -d "$PATCH_BUILD_DIR" ]; then
        BUILD_DIR="$PATCH_BUILD_DIR/$Patch_label.$PKGINST"
else
        BUILD_DIR="$PKG_INSTALL_ROOT/var/tmp/$Patch_label.$PKGINST"
fi
 
if [ ! -n "$PATCH_UNDO_ARCHIVE" ]; then
        PATCH_UNDO_ARCHIVE="none"
fi
 
FILE_DIR=$BUILD_DIR/files
RELOC_DIR=$FILE_DIR/reloc
ROOT_DIR=$FILE_DIR/root
BO_Deletes=$FILE_DIR/deletes
THIS_DIR=`dirname $0`
PROTO_FILE=$BUILD_DIR/prototype
TEMP_REMOTE=$PKGSAV/$Patch_label/temp
 
if [ "$PATCH_PROGRESSIVE" = "true" ]; then
        # remove the scripts that are left behind
        install_scripts=`dirname $0`
        rm $install_scripts/checkinstall \
$install_scripts/patch_checkinstall $install_scripts/patch_postinstall
 
        # If this is being used in an old-style patch, insert
        # the old-style script commands here.
 
        #XXXOld_CommandsXXX#
 
        exit 0
fi
#
# At this point we either have a deletes file or we don't. If we do,
# we create a prototype entry.
#
if [ -f $BO_Deletes ]; then
        echo "i deletes=$BO_Deletes" >> $BUILD_DIR/prototype
fi
 
#
# Now delete everything in the deletes list after transferring
# the file to the backout package and the entry to the prototype
# file. Remember that the pkgmap will get the CLIENT_BASEDIR path
# but we have to actually get at it using the BASEDIR path. Also
# remember that removef will import our PKG_INSTALL_ROOT
#
Our_Deletes=$THIS_DIR/deletes
if [ -f $Our_Deletes ]; then
        cd $BASEDIR
 
        cat $Our_Deletes | while read path; do
                Reg_File=0
 
                if valpath -l $path; then
                        Client_Path="$CLIENT_BASEDIR/$path"
                        Build_Path="$RELOC_DIR/$path"
                        Proto_Path=$BASEDIR/$path
                else    # It's an absolute path
                        Client_Path=$path
                        Build_Path="$ROOT_DIR$path"
                        Proto_Path=$PKG_INSTALL_ROOT$path
                fi
 
                # Note: If the file isn't really there, pkgproto
                # doesn't write anything.
                LINE=`pkgproto $Proto_Path=$path`
                ftype=`echo $LINE | nawk '{ print $1 }'`
                if [ $ftype = "f" ]; then
                        Reg_File=1
                fi
 
                if [ $Reg_File = 1 ]; then
                        # Add source file to the prototype entry
                        if [ "$Proto_Path" = "$path" ]; then
                                LINE=`echo $LINE | sed -e s@$Proto_Path@$Build_Path@2`
                        else
                                LINE=`echo $LINE | sed -e s@$Proto_Path@$Build_Path@`
                        fi
 
                        DirName=`dirname $Build_Path`
                        # make room in the build tree
                        mkdir -p $DirName
                        cp -p $Proto_Path $Build_Path
                fi
 
                # Insert it into the prototype file
                echo $LINE 1>>$PROTO_FILE 2>/dev/null
 
                # Remove the file only if it's OK'd by removef
                rm `removef $PKGINST $Client_Path` 1>/dev/null 2>&1
        done
        removef -f $PKGINST
 
        rm $Our_Deletes
fi
 
#
# Unless specifically denied, make the backout package.
#
if [ "$PATCH_NO_UNDO" != "true" ]; then
        cd $BUILD_DIR   # We have to build from here.
 
        if [ "$PATCH_UNDO_ARCHIVE" != "none" ]; then
                STAGE_DIR="$PATCH_UNDO_ARCHIVE"
                ARCHIVE_DIR="$PATCH_UNDO_ARCHIVE/$Patch_label/$PKGINST"
                mkdir -p $ARCHIVE_DIR
                mkdir -p $PKGSAV/$Patch_label
        else
                if [ -d $PKGSAV/$Patch_label ]; then
                        rm -r $PKGSAV/$Patch_label
                fi
                STAGE_DIR=$PKGSAV
                ARCHIVE_DIR=$PKGSAV/$Patch_label
                mkdir $ARCHIVE_DIR
        fi
                 
        pkgmk -o -d $STAGE_DIR 1>/dev/null 2>&1
        pkgtrans -s $STAGE_DIR $ARCHIVE_DIR/undo $PKG 1>/dev/null 2>&1
        compress $ARCHIVE_DIR/undo
        retcode=$?
        if [ "$PATCH_UNDO_ARCHIVE" != "none" ]; then
                if [ $retcode != 0 ]; then
                        build_remote_file "undo"
                else
                        build_remote_file "undo.Z"
                fi
        fi
        rm -r $STAGE_DIR/$PKG
          
        cd ..
        rm -r $BUILD_DIR
        # remove the scripts that are left behind
        install_scripts=`dirname $0`
        rm $install_scripts/checkinstall $install_scripts/patch_\
checkinstall $install_scripts/patch_postinstall
fi
 
#
# Since this apparently worked, we'll mark as obsoleted the prior
# versions of this patch - installpatch deals with explicit obsoletions.
#                       
cd ${PKG_INSTALL_ROOT:-/}
cd var/sadm/pkg
 
active_base=`echo $Patch_label | nawk '
        { print substr($0, 1, match($0, "Patchvers_pfx")-1) } '`
 
List=`ls -d $PKGINST/save/${active_base}*`
if [ $? -ne 0 ]; then
        List=""
fi
 
for savedir in $List; do
        patch=`basename $savedir`
        if [ $patch = $Patch_label ]; then
                break
        fi
 
        # If we get here then the previous patch gets deleted
        if [ -f $savedir/undo ]; then
                mv $savedir/undo $savedir/obsolete
                echo $Patch_label >> $savedir/obsoleted_by
        elif [ -f $savedir/undo.Z ]; then
                mv $savedir/undo.Z $savedir/obsolete.Z
                echo $Patch_label >> $savedir/obsoleted_by
        elif  [ -f $savedir/remote ]; then
                `grep . $PKGSAV/$patch/remote | sed 's/STATE=.*/STATE=obsolete/
' > $TEMP_REMOTE`
                rm -f $PKGSAV/$patch/remote
                mv $TEMP_REMOTE $PKGSAV/$patch/remote
                rm -f $TEMP_REMOTE
                echo $Patch_label >> $savedir/obsoleted_by
        elif  [ -f $savedir/obsolete -o -f $savedir/obsolete.Z ]; then
                echo $Patch_label >> $savedir/obsoleted_by
        fi
done
 
# If additional operations are required for this package, place
# those package-specific commands here.
 
#XXXSpecial_CommandsXXX#
 
exit 0

patch_checkinstall スクリプト

# checkinstall script to validate backing out a patch.
# directory format option.
#
#       @(#)patch_checkinstall 1.2 95/10/10 SMI
#
# Copyright (c) 1995 by Sun Microsystems, Inc.
# All rights reserved
#
 
PATH=/usr/sadm/bin:$PATH
 
LATER_MSG="PaTcH_MsG 6 ERROR: A later version of this patch is applied."
NOPATCH_MSG="PaTcH_MsG 2 ERROR: Patch number $ACTIVE_PATCH is not installed"
NEW_LIST=""
 
# Get OLDLIST
. $1
 
#
# Confirm that the patch that got us here is the latest one installed on
# the system and remove it from PATCHLIST.
#
Is_Inst=0
Skip=0
active_base=`echo $ACTIVE_PATCH | nawk '
        { print substr($0, 1, match($0, "Patchvers_pfx")-1) } '`
active_inst=`echo $ACTIVE_PATCH | nawk '
        { print substr($0, match($0, "Patchvers_pfx")+1) } '`
for patchappl in ${OLDLIST}; do
        appl_base=`echo $patchappl | nawk '
                { print substr($0, 1, match($0, "Patchvers_pfx")-1) } '`
        if [ $appl_base = $active_base ]; then
                appl_inst=`echo $patchappl | nawk '
                        { print substr($0, match($0, "Patchvers_pfx")+1) } '`
                result=`expr $appl_inst \> $active_inst`
                if [ $result -eq 1 ]; then
                        puttext "$LATER_MSG"
                        exit 3
                elif [ $appl_inst = $active_inst ]; then
                        Is_Inst=1
                        Skip=1
                fi
        fi
        if [ $Skip = 1 ]; then
                Skip=0
        else
                NEW_LIST="${NEW_LIST} $patchappl"
        fi
done
 
if [ $Is_Inst = 0 ]; then
        puttext "$NOPATCH_MSG"
        exit 3
fi
 
#
# OK, all's well. Now condition the key variables.
#
echo "PATCHLIST=${NEW_LIST}" >> $1
echo "Patch_label=" >> $1
echo "PATCH_INFO_$ACTIVE_PATCH=backed out" >> $1
 
# Get the current PATCH_OBSOLETES and condition it
Old_Obsoletes=$PATCH_OBSOLETES
 
echo $ACTIVE_OBSOLETES | sed 'y/\ /\n/' | \
nawk -v PatchObsList="$Old_Obsoletes" '
        BEGIN {  
                printf("PATCH_OBSOLETES=");
                PatchCount=split(PatchObsList, PatchObsComp, " ");
 
                for(PatchIndex in PatchObsComp) {
                        Atisat=match(PatchObsComp[PatchIndex], "@");
                        PatchObs[PatchIndex]=substr(PatchObsComp[PatchIndex], \
0, Atisat-1);
                        PatchObsCnt[PatchIndex]=substr(PatchObsComp\
[PatchIndex], Atisat+1);
                }
        }
        {
                for(PatchIndex in PatchObs) {
                        if (PatchObs[PatchIndex] == $0) {
                                PatchObsCnt[PatchIndex]=PatchObsCnt[PatchIndex]-1;
                        }
                }
                next;
        }        
        END {
                for(PatchIndex in PatchObs) {
                        if ( PatchObsCnt[PatchIndex] > 0 ) {
                                printf("%s@%d ", PatchObs[PatchIndex], PatchObsCnt\
[PatchIndex]);
                        }
                }
                printf("\n");
        } ' >> $1
 
        # remove the used parameters
        echo "ACTIVE_OBSOLETES=" >> $1
        echo "Obsoletes_label=" >> $1
 
exit 0

patch_postinstall スクリプト

# This script deletes the used backout data for a patch package
# and removes the deletes file entries.
#
# directory format options.
#
#       @(#)patch_postinstall 1.2 96/01/29 SMI
#
# Copyright (c) 1995 by Sun Microsystems, Inc.
# All rights reserved
#
PATH=/usr/sadm/bin:$PATH
THIS_DIR=`dirname $0`
 
Our_Deletes=$THIS_DIR/deletes
 
#
# Delete the used backout data
#
if [ -f $Our_Deletes ]; then
        cat $Our_Deletes | while read path; do
                if valpath -l $path; then
                        Client_Path=`echo "$CLIENT_BASEDIR/$path" | sed s@//@/@`
                else    # It's an absolute path
                        Client_Path=$path
                fi
                rm `removef $PKGINST $Client_Path`
        done
        removef -f $PKGINST
 
        rm $Our_Deletes
fi
 
#
# Remove the deletes file, checkinstall and the postinstall
#
rm -r $PKGSAV/$ACTIVE_PATCH
rm -f $THIS_DIR/checkinstall $THIS_DIR/postinstall
 
exit 0

パッケージのアップグレード

パッケージのアップグレードのプロセスは、パッケージの上書きのプロセスとは異なっています。Solaris OS の一部として提供される標準パッケージのアップグレードをサポートする特殊ツールはありますが、アンバンドルのパッケージは独自のアップグレードをサポートするように設計できます。前のいくつかの例で、先を見越して、管理者の管理下でインストールの正確な方法を制御するパッケージについて説明しました。同様に、パッケージの直接アップグレードをサポートする request スクリプトを設計できます。管理者が、古いファイルが残らないように、あるパッケージをすべて置き換えて別のパッケージをインストールすることにした場合、パッケージスクリプトでこの処理を行うことができます。

この例の request スクリプトおよび postinstall スクリプトでは、単純なアップグレード可能パッケージを提供しています。request スクリプトは管理者と対話して、古いパッケージインスタンスを削除するための簡単なファイルを /tmp ディレクトリに設定します。request スクリプトはファイルを作成します (これは禁止されている) が、/tmp には全員がアクセスできるため、問題ありません。

postinstall スクリプトは、/tmp のシェルスクリプトを実行します。このスクリプトは、古いパッケージに対して必要な pkgrm コマンドを実行してから、自分自身を削除します。

この例では基本的なアップグレードについて説明します。いくつかの非常に長いメッセージを含めて、コードは 50 行未満です。設計者の要求により、アップグレードのバックアウトを拡張したり、パッケージにほかの大きな変換を行ったりすることができます。

アップグレードオプションのユーザーインタフェースの設計時には、管理者がプロセスについてはっきり認識して、並列インストールではなくアップグレードを積極的に要求していることを確実に確認する必要があります。ユーザーインタフェースによって操作が明確になっている限りは、アップグレードのような汎用的で複雑な処理を実行しても問題はありません。

request スクリプト

# request script
control an upgrade installation
 
PATH=/usr/sadm/bin:$PATH
UPGR_SCRIPT=/tmp/upgr.$PKGINST
 
UPGRADE_MSG="Do you want to upgrade the installed version ?"
 
UPGRADE_HLP="If upgrade is desired, the existing version of the \
	package will be replaced by this version. If it is not \
	desired, this new version will be installed into a different \
	base directory and both versions will be usable."
 
UPGRADE_NOTICE="Conflict approval questions may be displayed. The \
	listed files are the ones that will be upgraded. Please \
	answer \"y\" to these questions if they are presented."
 
pkginfo -v 1.0 -q SUNWstuf.\*
 
if [ $? -eq 0 ]; then
	  # See if upgrade is desired here
	  response=`ckyorn -p "$UPGRADE_MSG" -h "$UPGRADE_HLP"`
	  if [ $response = "y" ]; then
		    OldPkg=`pkginfo -v 1.0 -x SUNWstuf.\* | nawk ' \
		    /SUNW/{print $1} '`
		    # Initiate upgrade
		    echo "PATH=/usr/sadm/bin:$PATH" > $UPGR_SCRIPT
		    echo "sleep 3" >> $UPGR_SCRIPT
		    echo "echo Now removing old instance of $PKG" >> \
		    $UPGR_SCRIPT
		    if [ ${PKG_INSTALL_ROOT} ]; then
			      echo "pkgrm -n -R $PKG_INSTALL_ROOT $OldPkg" >> \
			      $UPGR_SCRIPT
		    else
			      echo "pkgrm -n $OldPkg" >> $UPGR_SCRIPT
		    fi
		    echo "rm $UPGR_SCRIPT" >> $UPGR_SCRIPT
		    echo "exit $?" >> $UPGR_SCRIPT
 
		    # Get the original package's base directory
		    OldBD=`pkgparam $OldPkg BASEDIR`
		    echo "BASEDIR=$OldBD" > $1
		    puttext -l 5 "$UPGRADE_NOTICE"
	   else
		     if [ -f $UPGR_SCRIPT ]; then
			       rm -r $UPGR_SCRIPT
		     fi
	   fi
fi
 
exit 0

postinstall スクリプト

# postinstall
to execute a simple upgrade
 
PATH=/usr/sadm/bin:$PATH
UPGR_SCRIPT=/tmp/upgr.$PKGINST
 
if [ -f $UPGR_SCRIPT ]; then
	  sh $UPGR_SCRIPT &
fi
 
exit 0

クラスアーカイブパッケージの作成

クラスアーカイブパッケージは、アプリケーションバイナリインタフェース (ABI) の拡張機能です。これは、特定のファイルセットが単一のファイル (アーカイブ) に結合され、オプションで圧縮または暗号化されたパッケージです。クラスアーカイブ形式は、アクティブな可能性があるファイルシステムに対して、最初のインストールの速度を最大 30% 向上し、パッケージおよびパッチのインストール時の信頼性が改善されます。

次の節では、アーカイブパッケージディレクトリの構造、キーワード、および faspac ユーティリティーについて説明します。

アーカイブパッケージディレクトリの構造

次の図に示すパッケージエントリは、パッケージファイルが含まれるディレクトリを表します。このディレクトリは、パッケージと同じ名前にする必要があります。

図 6–1 パッケージディレクトリ構造

図には、パッケージディレクトリの直下に  pkginfo、pkgmap、reloc、root、および install の 5 つのサブディレクトリがあります。その下にもサブディレクトリがあります。

パッケージディレクトリに含まれるファイルおよびディレクトリの機能を次に示します。

項目 

説明 

pkginfo

特別な環境変数およびインストール命令を含めて、パッケージ全体を記述するファイル 

pkgmap

インストールされる各オブジェクト (ファイル、ディレクトリ、パイプなど) を記述するファイル 

reloc

ベースディレクトリから相対的にインストールされるファイル (再配置可能オブジェクト) が含まれる、任意のディレクトリ 

root

root ディレクトリから相対的にインストールされるファイル (ルートオブジェクト) が含まれる、任意のディレクトリ

install

スクリプトおよびその他の補助的なファイルが含まれる、任意のディレクトリ (pkginfo および pkgmap を除き、すべての ftype i ファイルはここに含まれる)

クラスアーカイブ形式では、パッケージビルダにより reloc および root の各ディレクトリからアーカイブにファイルを結合できます。アーカイブは、インストールの速度の向上、パッケージサイズの縮小、またはパッケージのセキュリティの向上のために、圧縮、暗号化、またはその他の任意の方法で処理できます。

ABI により、パッケージ内の任意のファイルをクラスに割り当てることができます。特定のクラス内のすべてのファイルは、クラスアクションスクリプトで定義されるカスタムメソッドを使用してディスクにインストールできます。このカスタムメソッドでは、ターゲットシステムで使用できるプログラムまたはパッケージとともに提供されるプログラムを使用できます。結果の形式は、標準 ABI 形式によく似ています。次の図に示すように、別のディレクトリが追加されます。アーカイブ用ファイルのすべてのクラスは、そのまま単一のファイルに結合され、archive ディレクトリに配置されます。アーカイブされたすべてのファイルが reloc および root の各ディレクトリから削除され、インストールクラスアクションスクリプトが install ディレクトリに配置されます。

図 6–2 アーカイブパッケージディレクトリの構造

図の構造では、図 6-1 と同じパッケージディレクトリ構造に archive サブディレクトリが追加されています。

クラスアーカイブパッケージをサポートするキーワード

この新しいクラスアーカイブ形式をサポートするために、pkginfo ファイル内で特殊な意味を持つキーワード形式の新しいインタフェースが 3 つあります。これらのキーワードを使用して、特殊な処理が必要なクラスを指定します。各キーワード文の形式は、 keyword=class1[class2 class3 ...] です。各キーワードの値は、次の表で定義されています。

キーワード 

説明 

PKG_SRC_NOVERIFY

これは、提供されるパッケージの reloc または root の各ディレクトリ内のファイルが指定されたクラスに属する場合に、pkgadd でファイルの存在とプロパティーを確認しないように指定します。アーカイブされたクラスではファイルが reloc または root のディレクトリ内に存在しないため、このキーワードが必要です。それらのファイルは、archive ディレクトリの非公開形式のファイルです。

PKG_DST_QKVERIFY

これらのクラスのファイルは、インストール後にテキスト出力がほとんどまたはまったくない簡易アルゴリズムを使用して確認されます。簡易確認では、最初に各ファイルの属性を正確に設定して、処理が正常に実行されたかどうかを確認します。pkgmap に対して、ファイルサイズと変更時間のテストも行われます。checksum 検証は実行されず、エラー復旧は標準の検証メカニズムのエラー復旧よりも非力です。インストール時に停電またはディスク障害が発生した場合には、コンテンツファイルがインストールされたファイルと一致しないことがあります。.この不一致は、どのような場合でも pkgrm で解決できます。

PKG_CAS_PASSRELATIVE

通常、インストールクラスアクションスクリプトは、インストールするファイルを指定するソースとターゲットのペアの一覧を、stdin から受け取ります。PKG_CAS_PASSRELATIVE に割り当てられたクラスでは、ソースとターゲットのペアが取得されません。その代わりに単一の一覧を受け取ります。この一覧の最初のエントリはソースパッケージの場所で、一覧の残りはターゲットのパスです。これはアーカイブからの抽出を単純化するためです。ソースパッケージの場所から archive ディレクトリのアーカイブを検索できます。ターゲットのパスは、アーカイブのコンテンツを抽出する機能に渡されます。各ターゲットパスは、元のパスが root または reloc のどちらであったかに応じて、絶対パスまたはベースディレクトリからの相対パスのいずれかで指定されます。このオプションを選択すると、相対パスと絶対パスの両方を単一のクラスに結合することは困難な場合があります。

アーカイブされたクラスごとにクラスアクションスクリプトが必要です。これは Bourne シェルコマンドが含まれたファイルで、アーカイブから実際にファイルをインストールするために pkgadd から実行されます。パッケージの install ディレクトリにクラスアクションスクリプトが検出された場合、pkgadd からそのスクリプトにインストールのすべての責任が委任されます。クラスアクションスクリプトは root 権限で実行され、ターゲットシステムの任意の場所にファイルを配置できます。


注 –

クラスアーカイブパッケージを実装するために絶対に必要なキーワードは、PKG_SRC_NOVERIFY だけです。ほかのキーワードは、インストールの速度を向上したりコードを保護したりするために使用できます。


faspac ユーティリティー

faspac ユーティリティーは、標準 ABI パッケージを、バンドル版のパッケージで使用されるクラスアーカイブ形式に変換します。このユーティリティーでは、cpio を使用してアーカイブを行い、compress を使用して圧縮を行います。結果のパッケージには、最上位のディレクトリに archive というディレクトリが追加されています。このディレクトリには、クラスごとに名前が付けられたすべてのアーカイブが含まれます。install ディレクトリには、各アーカイブの展開に必要なクラスアクションスクリプトが含まれます。絶対パスはアーカイブされません。

faspac ユーティリティーの形式は次のとおりです。


faspac [-m Archive Method] -a -s -q [-d Base Directory] /
[-x Exclude List] [List of Packages]

次の表で、faspac コマンドの各オプションについて説明します。

オプション 

説明 

-m Archive Method

 

アーカイブまたは圧縮の方法を示します。bzip2 はデフォルトで使用される圧縮ユーティリティーです。zip または unzip に切り替えるには、-m zip を使用します。cpio または compress の場合は、-m cpio を使用します。

-a

属性を固定します (ルートで実行する必要がある)。 

-s

標準 ABI 型のパッケージ変換を示します。このオプションは、cpio または圧縮されたパッケージを取り、標準 ABI 準拠のパッケージ形式にします。 

-q

非出力モードを示します。 

-d Base Directory

コマンド行で要求される場合にすべてのパッケージの基準になるディレクトリを示します。これは List of Packages エントリとは相互排他的です。

-x Exclude List

処理から除外するパッケージの、コンマ区切りまたは引用符付きスペース区切りの一覧を示します。 

List of Packages

処理されるパッケージの一覧を示します。