本节描述的方法不适用于所有软件包,但是,在将软件包安装到异构环境期间该方法确实能够改善性能。该方法很少适用于作为 Solaris OS 的一部分提供的软件包(随附的软件包);然而,非随附软件包可以实行非传统打包。
鼓励采用可重定位软件包的原因是支持以下需求:
在添加或删除软件包时,已安装的软件产品的现有理想行为将保持不变。
非随附软件包应该驻留在 /opt 下,以便保证新软件包不会干扰现有产品。
根据软件包对象的绝大部分的安装位置来建立基目录。
如果某个软件包对象安装到基目录以外的其他公共目录(例如 /etc),请在 prototype 文件中将其指定为绝对路径名。
换句话说,因为“可重定位”意味着该对象可以安装到任何位置而仍然能够正常工作,所以不能将 init 在引导时运行的任何启动脚本视为可重定位的!尽管在提供的软件包中将 /etc/passwd 指定为相对路径没有任何问题,但它只有一个安装位置。
如果您要构建一个复合软件包,绝对路径必须以不干扰已安装的现有软件的方式工作。可以完全包含在 /opt 中的软件包可避免此问题,因为不存在形成阻碍的现有文件。当 /etc 中的一个文件包括在软件包中时,您必须确保绝对路径名的行为方式与相对路径名的预期行为方式相同。请考虑下面两个示例。
将一个条目添加到表中,或者对象是可能要由其他程序或软件包修改的一个新表。
将该对象定义为文件类型 e 并定义为属于 build、awk 或 sed 类。执行此任务的脚本必须可与添加自身一样高效地删除自身。
需要将一个条目添加到 /etc/vfstab 中,以便支持新的固态硬盘。
pkgmap 文件中的条目可能是
1 e sed /etc/vfstab ? ? ? |
request 脚本询问操作员 /etc/vfstab 是否应该由软件包修改。如果操作员回答“否”,那么 request 脚本将列出有关如何手动完成该工作的说明,并将执行:
echo "CLASSES=none" >> $1 |
如果操作员回答“是”,那么它将执行:
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。可以用以下两种方式之一构建正确的目录。
使用 ${PKG_INSTALL_ROOT}/etc 构造,或者。
获取由 pkgadd 命令传递的文件目录名(就是此脚本的作用)。
通过对软件包中的每个绝对对象使用此方法,您可以确信当前的理想行为保持不变或者至少是可恢复的。
以下是复合软件包的 pkginfo 和 pkgmap 文件的示例。
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 |
: 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 |
尽管 S70dostuf 属于 daemon 类,但指向它的目录(这些目录在安装时已经就位)属于 none 类。即使这些目录对于此软件包是唯一的,您也应该将它们保留在 none 类中。这样做的原因是,这些目录需要首先被创建而且最后删除,而对于 none 类而言始终如此。pkgadd 命令创建这些目录;它们不是从软件包复制的,而且不会传递给将创建的类操作脚本。相反,这些目录由 pkgadd 命令在调用安装类操作脚本之前创建,而 pkgrm 命令会在删除类操作脚本完成之后删除这些目录。
这意味着,如果一个特殊类中的目录包含 none 类中的对象,pkgrm 命令在尝试删除该目录时会失败,因为该目录无法及时变成空目录。如果类 none 的一个对象将插入到某个特殊类的目录中,该目录不会及时出现以便接受该对象。pkgadd 命令将在对象安装期间动态创建该目录,并且可能无法在最终看到 pkgmap 定义时同步该目录的属性。
在将目录指定给类时,请一定记住创建和删除顺序。