| ナビゲーションリンクをスキップ | |
| 印刷ビューの終了 | |
|
アプリケーションパッケージ開発者ガイド Oracle Solaris 10 1/13 Information Library (日本語) |
パッケージのパッチは、元のパッケージの特定のファイルを上書きするためのスパースパッケージです。供給媒体の容量を節約することを除いて、スパースパッケージを出荷することに実質的な理由はありません。少数のファイルを変更して元のパッケージ全体を出荷したり、ネットワーク上で変更されたパッケージにアクセスできるようにしたりすることもできます。実際に異なっているのはこれらの新しいファイルだけである (その他のファイルは再コンパイルされていない) 場合に限り、pkgadd コマンドで差分をインストールできます。パッケージのパッチについては、次のガイドラインを確認してください。
複雑なシステムでは、パッチ識別システムを確立して、別々の異常な動作を訂正する場合に 2 つのパッチが同じファイルを置き換えることがないようにします。たとえば、Sun のパッチベース番号は、ターゲットファイルの相互排他的なセットに割り当てられます。
パッチをバックアウトできるようにする必要があります。
パッチパッケージのバージョン番号を、元のパッケージのバージョン番号と同じにすることが重要です。次の形式の pkginfo ファイルエントリを個別に使用して、パッケージのパッチステータスを管理するようにしてください。
PATCH=patch_number
パッチのためにパッケージのバージョンが変わる場合、パッケージの別のインスタンスを作成します。パッチを適用された製品を管理することは極めて困難になります。この連続的なインスタンスパッチの方法は、Oracle Solaris OS の早期リリースで一定の利点をもたらしましたが、複雑なシステムの管理では面倒になります。
パッチ内のすべてのゾーンパラメータがパッケージ内のゾーンパラメータと一致している必要があります。
Oracle Solaris OS を構成するパッケージに関するかぎり、パッケージデータベースにはパッケージのコピーは 1 つしかないはずです。ただし、パッチを適用されたインスタンスは複数ある場合があります。インストールされたパッケージから (removef コマンドを使用して) オブジェクトを削除するには、そのファイルを所有するインスタンスを特定する必要があります。
ただし、(Oracle Solaris OS の一部ではない) パッケージが、Oracle Solaris OS の一部である特定のパッケージのパッチレベルを決定する必要がある場合、これは解決すべき問題になります。インストールスクリプトは、ターゲットファイルシステムに格納されないため、重大な影響を与えることなく大きくすることができます。クラスアクションスクリプトおよびその他のさまざまな手続きスクリプトにより、PKGSAV 環境変数 (またはその他の永続的なディレクトリ) を使用して、変更されたファイルを保存し、インストールされたパッチのバックアウトを可能にすることができます。また、request スクリプトで適切な環境変数を設定して、パッチの履歴を監視することもできます。次のセクションのスクリプトでは、複数のパッチが存在する可能性があることを仮定しています。パッチの番号付けスキームは、単一のパッケージに適用する場合に意味を持ちます。この場合、個別のパッチ番号は、パッケージ内の機能的に関連したファイルのサブセットを表します。2 つのパッチ番号が異なる場合、同じファイルを変更することはできません。
通常のスパースパッケージをパッチパッケージにするには、次のセクションで説明するスクリプトをパッケージに組み込みます。最後の 2 つが patch_checkinstall および patch_postinstall という名前であることを除いて、すべてを標準パッケージコンポーネントとして認識できます。パッチのバックアウト機能が必要な場合には、これら 2 つのスクリプトをバックアウトパッケージに組み込むことができます。スクリプトは非常に単純で、さまざまなタスクは明確です。
注 - このパッチの方法は、クライアントシステムのパッチに使用できますが、サーバー上のクライアントルートディレクトリには、ユーザーの install または nobody で読み取りできる適切な権限が必要です。
checkinstall スクリプトを使用して、特定のパッケージについてパッチが適切であることを確認します。確認が終わると、パッチ一覧とパッチ情報一覧が作成され、レスポンスファイルに挿入してパッケージデータベースに組み込まれます。
パッチ一覧は現在のパッケージに影響するパッチの一覧です。このパッチ一覧は、インストールされたパッケージの pkginfo ファイルに次のような行で記録されます。
PATCHLIST=patch_id patch_id ...
パッチ情報一覧は、現在のパッチが依存しているパッチの一覧です。パッチ情報一覧も、pkginfo ファイルに次のような行で記録されます。
PATCH_INFO_103203-01=Installed... Obsoletes:103201-01 Requires: \ Incompatibles: 120134-01
注 - これらの行 (およびその形式) は、公開インタフェースとして宣言されています。Oracle 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 スクリプトは、構成されるバックアウトパッケージの 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スクリプトにより、その他のスクリプトで提供される情報を使用して、バックアウトパッケージを作成します。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
# 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
# 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