Guía del desarrollador para la creación de paquetes de aplicaciones

Capítulo 6 Técnicas avanzadas para la creación de paquetes

Las amplias posibilidades de creación de paquetes de System V que se implementan en el sistema operativo Solaris ofrecen una herramienta potente para instalar productos de software. Como diseñador de paquetes, puede beneficiarse de estas posibilidades. Los paquetes que no forman parte del sistema operativo Solaris (paquetes no integrados) pueden usar el mecanismo de clase para personalizar las instalaciones de servidor o de cliente. Es posible diseñar paquetes reubicables para satisfacer los deseos del administrador. Se puede entregar un producto complejo como un conjunto de paquetes compuestos que resuelven automáticamente las dependencias de los paquetes. La actualización y la aplicación de parches se puede personalizar mediante el diseñador de paquetes. Los paquetes con parches se pueden entregar del mismo modo que los paquetes sin parches, y los archivos de almacenamiento de recuperación también se pueden incluir en el producto.

A continuación puede ver una lista de la información general que se ofrece en este capítulo.

Especificación del directorio base

Puede usar diversos métodos para especificar dónde se instalará un paquete; es importante que se pueda cambiar la base de instalación dinámicamente en el tiempo de la instalación. Si se lleva a cabo correctamente, un administrador puede instalar varias versiones y varias arquitecturas sin problemas.

En esta sección se tratan en primer lugar los métodos habituales, seguidos de las aproximaciones que mejoran la instalación en sistemas heterogéneos.

El archivo administrativo predeterminado

Los administradores responsables de la instalación de los paquetes pueden usar los archivos de administración para controlar la instalación de los paquetes. Sin embargo, como diseñador de paquetes, debe conocer los archivos de administración y cómo un administrador puede modificar la instalación deseada del paquete.

Un archivo de administración indica al comando pkgadd si se debe efectuar alguna de las comprobaciones o solicitudes que normalmente realiza. En consecuencia, los administradores deben comprender completamente el proceso de instalación de un paquete y las secuencias de comandos implicadas antes de usar los archivos de administración.

Se distribuye un archivo administrativo predeterminado básico con el sistema operativo SunOS en /var/sadm/install/admin/default. Éste es el archivo que establece el nivel más básico de directiva de administración respecto a la instalación de productos de software. El archivo tiene este aspecto al distribuirlo:

#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

El administrador puede editar este archivo para establecer nuevos comportamientos predeterminados, o bien para crear un archivo de administración diferente y especificar su existencia mediante el uso de la opción -a en el comando pkgadd.

Es posible definir once parámetros en un archivo de administración, aunque no es necesario definirlos todos. Para obtener más información, consulte admin(4).

El parámetro basedir especifica cómo se derivará el directorio base cuando se instale un paquete. La mayoría de los administradores lo dejan como default, pero basedir se puede establecer con uno de los valores siguientes:


Nota –

Si se llama al comando pkgadd con el argumento -a none, siempre pide al administrador un directorio base. Desafortunadamente, de este modo se configuran todos los parámetros del archivo con el valor predeterminado de quit, lo cual puede suponer problemas adicionales.


Familiarización con la incertidumbre

Un administrador tiene control sobre todos los paquetes que se instalan en un sistema mediante el uso de un archivo de administración. Desafortunadamente, el diseñador de paquetes proporciona a menudo un archivo administrativo alternativo predeterminado, independientemente de los deseos del administrador.

Los diseñadores de paquetes contienen en ocasiones un archivo de administración alternativo, por lo que ellos, no el administrador, controlan la instalación de un paquete. Debido a que la entrada basedir del archivo administrativo predeterminado anula los demás directorios base, ofrece un método sencillo para seleccionar el directorio base adecuado en el tiempo de la instalación. En todas las versiones del sistema operativo Solaris anteriores a Solaris 2.5, éste se consideraba el método más sencillo de controlar el directorio base.

Sin embargo, es necesario que acepte los deseos del administrador respecto a la instalación del producto. La distribución de un archivo administrativo temporal predeterminado con el fin de controlar la instalación conduce a desconfianza por parte de los administradores. Debe usar las secuencias de comandos request y checkinstall para controlar estas instalaciones bajo la supervisión del administrador. Si la secuencia de comandos request implica fielmente al administrador en el proceso, la creación de paquetes de System V servirá a los diseñadores de paquetes y los administradores.

Uso del parámetro BASEDIR

El archivo pkginfo para cualquier paquete reubicable debe incluir un directorio base predeterminado en forma de entrada como la siguiente:


BASEDIR=absolute_path

Éste es únicamente el directorio base predeterminado; el administrador puede cambiarlo durante la instalación.

Mientras algunos paquetes requieren más de un directorio base, la ventaja de usar este parámetro para colocar el paquete se debe a que se garantiza que el directorio base estará en su lugar y será modificable como directorio válido en el momento en el que comience la instalación. La ruta correcta al directorio base para el servidor y el cliente está disponible para todas las secuencias de comandos de procedimientos en forma de variables de entorno reservadas, y el comando pkginfo -r SUNWstuf muestra la instalación actual base para el paquete.

En la secuencia de comandos checkinstall, BASEDIR es el parámetro definido exactamente en el archivo pkginfo (aún no se ha acondicionado). Con el fin de inspeccionar el directorio base de destino, se precisa la construcción ${PKG_INSTALL_ROOT}$BASEDIR. Esto significa que la secuencia de comandos request o checkinstall puede cambiar el valor de BASEDIR en el entorno de instalación con resultados predecibles. En el tiempo de llamar a la secuencia de comandos preinstall, el parámetro BASEDIR es el puntero completamente acondicionado al directorio base real en el sistema de destino, incluso si el sistema es un cliente.


Nota –

La secuencia de comandos request utiliza el parámetro BASEDIR de forma diferente según las versiones del sistema operativo SunOS. Con el fin de probar un parámetro BASEDIR en una secuencia de comandos request, se debe usar el código siguiente para determinar el directorio de base real en uso.

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

Uso de directorios base paramétricos

Si un paquete necesita diversos directorios base, puede establecerlos con nombres de ruta paramétricos. Este método se ha vuelto bastante popular, aunque tiene los siguientes inconvenientes:

Mientras los parámetros que determinan los directorios base se definen en el archivo pkginfo, se pueden modificar mediante la secuencia de comandos request. Ésta es una de las razones fundamentales para la popularidad de esta aproximación. Sin embargo, los inconvenientes son crónicos y debe considerar esta configuración como último recurso.

Ejemplos: uso de directorios base paramétricos

El archivo 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

El archivo 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

Administración del directorio base

Cualquier paquete que esté disponible en diversas versiones o para diversas arquitecturas se debe diseñar para recorrer el directorio base, si fuera necesario. Recorrer un directorio base significa que si una versión anterior o una arquitectura diferente del paquete que se está instalando ya existe en el directorio base, el paquete que se está instalando resuelve este problema, quizá mediante la creación de un nuevo directorio base con un nombre ligeramente diferente. Las secuencias de comandos request y checkinstall en Solaris 2.5 y versiones compatibles tienen la posibilidad de modificar la variable de entorno BASEDIR. Esto no se aplica a versiones anteriores del sistema operativo Solaris.

Incluso en versiones anteriores del sistema operativo Solaris, la secuencia de comandos request tenía la autoridad de redefinir directorios en la base de instalación. La secuencia de comandos request puede hacerlo de modo que todavía admita las preferencias más administrativas.

Posibilidad de reubicación

Al tiempo que puede seleccionar directorios base para diversos paquetes que se garantizan como exclusivos para una arquitectura y versión, esto conduce a niveles innecesarios de jerarquía de directorios. Por ejemplo, para un producto diseñado para procesadores basados en SPARC y x86, puede organizar los directorios base por procesador y versión tal como se muestra a continuación.

Directorio base 

Versión y procesador 

/opt/SUNWstuf/sparc/1.0

Versión 1.0, SPARC 

/opt/SUNWstuf/sparc/1.2

Versión 1.2, SPARC 

/opt/SUNWstuf/x86/1.0

Versión 1.0, x86 

Es correcto y funciona, pero considera los nombres y los números como si significaran algo para el administrador. Una mejor aproximación es hacerlo automáticamente después de explicarlo al administrador y obtener un permiso.

Esto significa que puede hacer todo el trabajo en el paquete sin que necesite que el administrador lo haga manualmente. Puede asignar el directorio base de forma arbitraria y después establecer de forma transparente los vínculos al cliente adecuado en una secuencia de comandos postinstall. También puede usar el comando pkgadd para instalar el paquete total o parcialmente en los clientes de la secuencia de comandos postinstall. Incluso puede preguntar al administrador qué usuarios o clientes necesitan conocer este paquete y actualizar automáticamente las variables de entorno PATH y los archivos /etc. Esto es completamente aceptable siempre que, haga lo que haga el paquete tras la instalación, lo deshaga tras la eliminación.

Recorrido de directorios base

Puede beneficiarse de dos métodos para controlar el directorio base en el tiempo de la instalación. Lo primero es mejor para los nuevos paquetes que se instalarán sólo en Solaris 2.5 y versiones compatibles; ofrece información muy útil al administrador, admite varias arquitecturas y versiones instaladas, y requiere una cantidad mínima de trabajo específico. Cualquier paquete puede usar el segundo método y utiliza el control inherente de la secuencia de comandos request sobre los parámetros de generación para asegurar instalaciones correctas.

Uso del parámetro BASEDIR

La secuencia de comandos checkinstall puede seleccionar el directorio base apropiado en el tiempo de la instalación, lo que significa que el directorio base se puede situar en una posición muy baja del árbol de directorios. Este ejemplo aumenta el directorio base secuencialmente, lo que lleva a directorios con el formato /opt/SUNWstuf, /opt/SUNWstuf.1 y /opt/SUNWstuf.2. El administrador puede usar el comando pkginfo para determinar qué arquitectura y versión se instalan en cada directorio base.

Si el paquete SUNWstuf (que contiene un conjunto de utilidades que hacen el trabajo) usa este método, los archivos pkginfo y pkgmap tendrían este aspecto.

El archivo 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

El archivo 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

Ejemplo: secuencias de comandos de análisis que recorren un BASEDIR

Suponga que la versión x86 de SUNWstuf ya está instalada en el servidor en /opt/SUNWstuf. Cuando el administrador use el comando pkgadd para instalar la versión SPARC, la secuencia de comandos request debe detectar la existencia de la versión x86 e interactuar con el administrador respecto a la instalación.


Nota –

El directorio base se puede recorrer sin interacción del administrador en una secuencia de comandos checkinstall, pero si las operaciones arbitrarias como ésta ocurren con demasiada frecuencia, los administradores pierden confianza en el proceso.


Las secuencias de comandos request y checkinstall de un paquete que gestionan esta situación pueden tener este aspecto.

La secuencia de comandos 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

La secuencia de comandos checkinstall

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

Esta aproximación no funcionaría muy bien si el directorio base fuera simplemente /opt. Este paquete debe indicar el BASEDIR de forma más precisa, puesto que /opt sería difícil de recorrer. De hecho, según el esquema de montaje, puede que no sea posible. El ejemplo recorre el directorio base mediante la creación de un directorio en /opt, lo cual no presenta problemas.

Este ejemplo usa las secuencias de comandos request y checkinstall aunque las versiones de Solaris anteriores a 2.5 no pueden ejecutar una secuencia de comandos checkinstall. La secuencia de comandos checkinstall de este ejemplo se usa para detener correctamente la instalación, en respuesta a un mensaje privado en forma de cadena quitinstall. ”. Si esta secuencia de comandos se ejecuta en la versión Solaris 2.3, la secuencia de comandos checkinstall se ignora y la secuencia de comandos request detiene la instalación con un mensaje de error.

Recuerde que antes de Solaris 2.5 y versiones compatibles, el parámetro BASEDIR es de sólo lectura y no se puede cambiar por la secuencia de comandos request. Por este motivo, si se detecta una versión antigua del sistema operativo SunOS (mediante la prueba de una variable de entorno CLIENT_BASEDIR), la secuencia de comandos request sólo tiene dos opciones: continuar o salir.

Uso de rutas paramétricas relativas

Si el producto de software puede instalarse en versiones anteriores del sistema operativo SunOS, la secuencia de comandos request debe hacer todo el trabajo necesario. Esta aproximación también se puede usar para manipular varios directorios. Si se necesitan directorios adicionales, se deben incluir en un único directorio base con el fin de ofrecer un producto de fácil administración. Mientras el parámetro BASEDIR no ofrezca el nivel de granularidad disponible en la última versión de Solaris, el paquete todavía puede recorrer el directorio base mediante el uso de la secuencia de comandos request para manipular las rutas paramétricas. Éste es el aspecto que podrían tener los archivos pkginfo y pkgmap.

El archivo 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

El archivo 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

Este ejemplo no es perfecto. Un comando pkginfo -r devuelve /opt para la base de instalación, que es bastante ambigua. Muchos paquetes se encuentran en /opt, pero al menos se trata de un directorio con sentido. Al igual que el ejemplo anterior, el siguiente admite completamente diversas arquitecturas y versiones. La secuencia de comandos request se puede ajustar a las necesidades del paquete específico y resolver las dependencias aplicables.

Ejemplo: una secuencia de comandos request que recorra una ruta paramétrica relativa

# 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

Admisión de la reubicación en un entorno heterogéneo

El concepto original tras la creación de paquetes de System V ha supuesto una arquitectura por sistema. El concepto de un servidor no representa una función en el diseño. Ahora, por supuesto, un único servidor puede ofrecer compatibilidad para diversas arquitecturas, lo cual significa que puede haber varias copias del mismo software en un servidor, cada una para una arquitectura diferente. Mientras que los paquetes de Solaris se retiran dentro de los límites recomendados del sistema de archivos (por ejemplo, / y /usr), con bases de datos de productos en el servidor, así como cada cliente, no todas las instalaciones tienen por qué admitir esta división. Determinadas implementaciones admiten una estructura completamente diferente e implican una base de datos de productos habitual. Mientras que dirigir a los clientes a diferentes versiones es algo sencillo, la instalación de paquetes de System V en diversos directorios base puede presentar problemas para el administrador.

Cuando diseña el paquete, también debe tener en cuenta los métodos habituales que los administradores usan para introducir nuevas versiones de software. Los administradores buscan con frecuencia instalar y probar la última versión, de forma paralela a la versión actualmente instalada. El procedimiento implica la instalación de la nueva versión en un directorio base diferente de la versión actual y la orientación de un determinado número de clientes que no sean fundamentales a la nueva versión como prueba. A medida que crece la confianza el administrador redirige cada vez más clientes a la nueva versión. Finalmente, el administrador conserva la versión anterior sólo para emergencias y después, finalmente, la suprime.

Lo que esto significa es que los paquetes destinados a sistemas heterogéneos modernos deben admitir la reubicación total, en el sentido de que el administrador pueda colocarlos en un lugar razonable del sistema de archivos y ver todavía todas sus funciones. Solaris 2.5 y las versiones compatibles ofrecen diversas herramientas que permiten varias arquitecturas y versiones para realizar la instalación sin problemas en el mismo sistema. Solaris 2.4 y las versiones compatibles también admiten la reubicación completa pero la ejecución de la tarea no es tan sencilla.

Aproximación tradicional

Paquetes reubicables

System V ABI implica que la intención original del paquete reubicable era facilitar la instalación del paquete al administrador. En estos momentos, la necesidad de paquetes reubicables va mucho más allá. La comodidad no es la única cuestión; es muy probable que durante la instalación ya haya instalado un producto de software activo en el directorio predeterminado. Un paquete que no esté diseñado para lidiar con esta situación sobrescribe el producto existente o no consigue instalarse. Sin embargo, un paquete diseñado para gestionar diversas arquitecturas y versiones puede instalarse sin problemas y ofrecer al administrador una amplia gama de opciones que sean totalmente compatibles con las tradiciones administrativas existentes.

En algunos aspectos, el problema de varias arquitecturas y el de varias versiones es el mismo. Debe ser posible instalar una variante del paquete existente junto a otras variantes, así como dirigir a los clientes o los consumidores autónomos de sistemas de archivos exportados a una de esas variantes, sin que las funciones se vean comprometidas. Mientras Sun ha establecido métodos para lidiar con varias arquitecturas en un servidor, es posible que el administrador no pueda seguir esas recomendaciones. Todos los paquetes deben ser capaces de cumplir con los deseos razonables de los administradores respecto a la instalación.

Ejemplo: paquete reubicable tradicional

Este ejemplo muestra el aspecto que puede tener un paquete reubicable tradicional. Este paquete se debe ubicar en /opt/SUNWstuf, y los archivos pkginfo y pkgmap pueden tener este aspecto.

El archivo 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

El archivo 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

Este método se conoce como tradicional porque cada objeto del paquete se instala en el directorio base definido por el parámetro BASEDIR del archivo pkginfo. Por ejemplo, el primer objeto del archivo pkgmap se instala como directorio /opt/SUNWstuf.

Paquetes absolutos

Un paquete absoluto es el que se instala en un sistema de archivos raíz concreto (/). Estos paquetes son difíciles de gestionar desde el punto de vista de varias versiones y arquitecturas. Como norma general, todos los paquetes deben ser reubicables. Sin embargo, hay muy buenos motivos para incluir elementos absolutos en un paquete reubicable.

Ejemplo: paquete absoluto tradicional

Si el paquete SUNWstuf fuera absoluto, el parámetro BASEDIR no se debería definir en el archivo pkginfo, y el archivo pkgmap tendría este aspecto.

El archivo 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

En este ejemplo, si el administrador ha especificado un directorio base alternativo durante la instalación, el comando pkgadd lo ignoraría. Este paquete siempre se instala en el directorio /opt/SUNWstuf del sistema de destino.

El argumento -R del comando pkgadd funciona según lo esperado. Por ejemplo,


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

instala los objetos en /export/opt/client3/opt/SUNWstuf, pero esto es lo más cerca que puede estar este paquete de ser reubicable.

Observe el uso del signo de interrogación (?) para el directorio /opt en el archivo pkgmap. Indica que los atributos existentes no se deben cambiar. No significa “crear el directorio con atributos predeterminados” aunque en determinadas circunstancias esto pueda ocurrir. Cualquier directorio que sea específico del nuevo paquete debe especificar todos los atributos de forma explícita.

Paquetes compuestos

Un paquete que contenga objetos reubicables es un paquete reubicable. Esto puede llegar a ser confuso porque un paquete reubicable puede contener rutas absolutas en su archivo pkgmap. El uso de una entrada raíz (/) en un archivo pkgmap puede mejorar los aspectos reubicables del paquete. Los paquetes que tienen entradas raíz y reubicables reciben el nombre de paquetes compuestos.

Ejemplo: solución tradicional

Suponga que un objeto del paquete SUNWstuf es una secuencia de comandos de inicio que se ejecuta en el nivel de ejecución 2. El archivo /etc/rc2.d/S70dostuf se debe instalar como parte del paquete, pero no se puede colocar en el directorio base. Si se supone que un paquete reubicable es la única solución, los archivos pkginfo y pkgmap podrían tener este aspecto.

El archivo 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

El archivo 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

No hay mucha diferencia entre esta aproximación y la de un paquete absoluto. En realidad, resultaría mejor como paquete absoluto: si el administrador proporcionara un directorio base alternativo para este paquete, no funcionaría.

De hecho, sólo un archivo de este paquete debe estar relacionado con la raíz; el resto se puede mover a cualquier lugar. La forma de solucionar este problema mediante el uso de un paquete compuesto se trata a lo largo de esta sección.

Más allá de la tradición

La aproximación que se describe en esta sección no se aplica a todos los paquetes, pero mejora el rendimiento durante la instalación en un entorno heterogéneo. Sólo una pequeña parte se aplica a los paquetes que se han entregado como parte del sistema operativo Solaris (paquetes integrados); sin embargo, los paquetes no integrados pueden practicar una creación de paquetes no tradicional.

El motivo que se esconde tras el fomento de los paquetes reubicables es apoyar a este requisito:

Cuando un paquete se agrega o se suprime, los comportamientos deseables existentes de los productos de software instalados quedarán sin cambios.

Los paquetes no integrados deben residir en /opt para asegurar que el nuevo paquete no interfiera con productos existentes.

Otra mirada a los paquetes compuestos

Hay dos normas que seguir a la hora de construir un paquete compuesto funcional:

En otras palabras: puesto que "reubicable" significa que el objeto se puede instalar en cualquier lugar y que siga funcionando, ninguna secuencia de comandos de inicio ejecutada por init en el tiempo del inicio se puede considerar reubicable. Mientras no haya nada incorrecto en la especificación de /etc/passwd como ruta relativa en el paquete entregado, sólo hay un lugar al que puede ir.

Cómo conseguir que los nombres de rutas absolutas tengan el aspecto de reubicables

Si va a construir un paquete compuesto, las rutas absolutas deben funcionar de forma que no interfieran en el software instalado existente. Un paquete que se puede incluir por completo en /opt evita este problema porque no hay archivos en la ruta. Cuando un archivo de /etc se incluye en el paquete, debe asegurarse de que los nombres de la ruta absoluta se comportan del mismo modo que se espera de los nombres de rutas relativa. Observe los dos ejemplos siguientes.

Ejemplo: modificación de un archivo

Descripción

Se agrega una entrada a una tabla, o bien el objeto es una tabla nueva que probablemente modificarán otros programas o paquetes.

Implementación

Defina el objeto como tipo de archivo e y perteneciente a la clase build, awk o sed. La secuencia de comandos que ejecuta esta tarea debe suprimirse igual de eficazmente que cuando se agrega.

Ejemplo

Se debe agregar una entrada al archivo /etc/vfstab en apoyo del nuevo disco duro de estado sólido.

La entrada del archivo pkgmap podría ser


1 e sed /etc/vfstab ? ? ?

La secuencia de comandos request pregunta al operador si el paquete debe modificar el archivo /etc/vfstab. Si el operador responde “no”, la secuencia de comandos de solicitud imprimirá las instrucciones para hacer el trabajo manualmente y ejecutará


echo "CLASSES=none" >> $1

Si el operador responde "sí" se ejecuta


echo "CLASSES=none sed" >> $1

que activa la secuencia de comandos de acción de clase que realizará las modificaciones necesarias. La clase sed significa que el archivo de paquete /etc/vfstab es un programa sed que contiene las operaciones de instalación y eliminación para el archivo con el mismo nombre en el sistema de destino.

Ejemplo: creación de un nuevo archivo

Descripción

El objeto es un archivo completamente nuevo que no es probable que se modifique posteriormente, o bien sustituye a un archivo propiedad de otro paquete.

Implementación

Defina el objeto del paquete como tipo de archivo f e instálelo mediante una secuencia de comandos de acción de clase capaz de deshacer el cambio.

Ejemplo

Se precisa un archivo completamente nuevo en /etc para proporcionar la información necesaria con el fin de que se pueda admitir el disco duro de estado sólido, que recibe el nombre de /etc/shdisk.conf . La entrada del archivo pkgmap podría tener este aspecto:


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

La secuencia de comandos de acción de clase i.newetc es responsable de la instalación de éste y otros archivos que deben ir en /etc. Hace comprobaciones para asegurarse de que no haya otro archivo allí. Si no hay, simplemente copiará el archivo nuevo en su lugar. Si ya hay un archivo en su lugar, hará una copia de seguridad de él antes de instalar el archivo nuevo. La secuencia de comandos r.newetc suprime estos archivos y restaura los originales, si fuera necesario. Aquí se encuentra el fragmento clave de la secuencia de comandos de instalación.

# 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

Observe que esta secuencia de comandos usa la variable de entorno PKGSAV para almacenar una copia de seguridad del archivo que se debe sustituir. Cuando el argumento ENDOFCLASS pasa a la secuencia de comandos, se trata del comando pkgadd que informa a la secuencia de comandos de que éstas son las últimas entradas de esta clase; en ese momento la secuencia de comandos archiva y comprime los archivos que se guardaron mediante un programa de compresión privado almacenado en el directorio de instalación del paquete.

Mientras el uso de la variable de entorno PKGSAV, no es fiable durante la actualización de un paquete; si el paquete no se actualiza (mediante un parche, por ejemplo) el archivo de copia de seguridad es seguro. La siguiente secuencia de comandos de eliminación incluye un código para gestionar los demás problemas: el hecho de que versiones más antiguas del comando pkgrm no pasen a las secuencias de comandos la ruta correcta a la variable de entorno PKGSAV.

La secuencia de comandos de eliminación podría tener este aspecto.

# 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

Esta secuencia de comandos usa un algoritmo desinstalado privado (unsquish) que se encuentra en el directorio de instalación de la base de datos del paquete. Esto se hace de manera automática mediante el comando pkgadd en el tiempo de la instalación. Todas las secuencias de comandos que no estén específicamente reconocidas como de sólo instalación por parte del comando pkgadd quedan en este directorio para que lo pueda usar el comando pkgrm. No puede determinar dónde se encuentra ese directorio, pero puede confiar en que está completamente disponible y que contiene todas las secuencias de comandos de instalación y los archivos de información adecuados para el paquete. Esta secuencia de comandos busca el directorio por virtud del hecho de que se garantiza la ejecución de la secuencia de comandos de acción de clase a partir del directorio que contiene el programa unsquish.

Tenga en cuenta, asimismo, que esta secuencia de comandos no sólo supone que el directorio de destino sea /etc. Puede que en realidad sea /export/root/client2/etc. El directorio correcto se puede construir de una de estas dos formas.

Mediante el uso de esta aproximación para cada objeto absoluto del paquete, puede estar seguro que el comportamiento deseable actual permanece sin cambios o al menos es recuperable.

Ejemplo: un paquete compuesto

Éste es un ejemplo de los archivos pkginfo y pkgmap para un paquete compuesto.

El archivo 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

El archivo 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

Mientras S70dostuf pertenece a la clase daemon, los directorios que llevan hasta él (que ya estén en posición en el tiempo de la instalación) pertenecen a la clase none. Incluso si los directorios eran exclusivos para este paquete, debe dejarlos en la clase none. El motivo es que los directorios se deben crear en primer lugar y después suprimir; siempre ocurre así en el caso de la clase none. El comando pkgadd crea directorios; no se copian del paquete y no se pasan a una secuencia de comandos de acción de clase que se deba crear. En su lugar, los crea el comando pkgadd antes de que llame a la secuencia de comandos de acción de clase de instalación; el comando pkgrm suprime directorios después de terminar de suprimir la secuencia de comandos de acción de clase.

Significa que si un directorio de una clase especial contiene objetos de la clase none, cuando el comando pkgrm intenta suprimir el directorio, se produce un error porque el directorio no estará vacío en ese momento. Si se va a insertar un objeto de clase none en un directorio de alguna clase especial, ese directorio no existirá a tiempo de aceptar el objeto. El comando pkgadd creará el directorio de forma paralela a la instalación del objeto y puede que no sea capaz de sincronizar los atributos de ese directorio cuando finalmente vea la definición pkgmap.


Nota –

Al asignar un directorio a una clase, recuerde siempre el orden de creación y eliminación.


Creación de paquetes de instalación remota

Todos los paquetes deben ser instalables a distancia. Instalable a distancia significa que no supone que el administrador que instala el paquete esté llevando a cabo la instalación en el sistema de archivos raíz (/) del sistema que ejecuta el comando pkgadd. Si en una de las secuencias de comandos de procedimientos necesita acceder al archivo /etc/vfstab del sistema de destino, debe usar la variable de entorno PKG_INSTALL_ROOT. En otras palabras, el nombre de ruta /etc/vfstab le conducirá al archivo /etc/vfstab del sistema que ejecuta el comando pkgadd, pero es posible que el administrador lleve a cabo la instalación en un cliente en /export/root/client3. Se garantiza que la ruta ${PKG_INSTALL_ROOT}/etc/vfstab le llevará al sistema de archivos de destino.

Ejemplo: instalación en un sistema cliente

En este ejemplo, el paquete SUNWstuf se instala en client3, que se configura con /opt en su sistema de archivos raíz (/). Ya hay otra versión de este paquete instalada en client3, y el directorio base está configurado en basedir=/opt/$PKGINST desde un archivo de administración, thisadmin. (Para obtener más información sobre los archivos de administración, consulte El archivo administrativo predeterminado.) El comando pkgadd ejecutado en el servidor es:


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

La tabla siguiente muestra las variables de entorno y sus valores que pasan a las secuencias de comandos de procedimientos.

Tabla 6–1 Valores pasados a secuencias de comandos de procedimientos

Variable de entorno 

Valor 

PKGINST

SUNWstuf.2

PKG_INSTALL_ROOT

/export/root/client3

CLIENT_BASEDIR

/opt/SUNWstuf.2

BASEDIR

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

Ejemplo: instalación en un servidor o sistema autónomo

Para llevar a cabo la instalación en un servidor o sistema autónomo en las mismas circunstancias que el ejemplo anterior, el comando es:


# pkgadd -a thisadmin SUNWstuf

La tabla siguiente muestra las variables de entorno y sus valores que pasan a las secuencias de comandos de procedimientos.

Tabla 6–2 Valores pasados a secuencias de comandos de procedimientos

Variable de entorno 

Valor 

PKGINST

SUNWstuf.2

PKG_INSTALL_ROOT

Sin definir. 

CLIENT_BASEDIR

/opt/SUNWstuf.2

BASEDIR

/opt/SUNWstuf.2

Ejemplo: montaje de sistemas de archivos compartidos

Suponga que el paquete SUNWstuf crea y comparte un sistema de archivos en el servidor en /export/SUNWstuf/share. Cuando el paquete se instala en los sistemas cliente, sus archivos /etc/vfstab se deben actualizar para montar este sistema de archivos compartido. En esta situación puede usar la variable CLIENT_BASEDIR.

La entrada en el cliente debe presentar el punto de montaje en referencia al sistema de archivos del cliente. Esta línea se debe construir correctamente si la instalación parte del servidor o del cliente. Suponga que el nombre del sistema del servidor es $SERVER. Puede ir a $PKG_INSTALL_ROOT/etc/vfstab y, mediante el comando sed o awk, construir la línea siguiente para el archivo /etc/vfstab del cliente.


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

Por ejemplo, en el caso del servidor universe y el sistema cliente client9, la línea del archivo /etc/vfstab del sistema cliente tendría este aspecto:


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

Si se usan estos parámetros correctamente, la entrada siempre monta el sistema de archivos del cliente, independientemente de si se construye desde el servidor o localmente.

Paquetes de parches

Un parche para un paquete es simplemente un paquete suelto diseñado para sobrescribir determinados archivos del original. No hay un motivo real para la inclusión de un paquete suelto excepto guardar espacio en el medio de entrega. También es posible distribuir todo el paquete original con unos cuantos archivos cambiados, o bien proporcionar acceso al paquete modificado en una red. Siempre que esos archivos nuevos sean de hecho diferentes (los demás archivos no se recompilaron), el comando pkgadd instala las diferencias. Revise las directrices siguientes relacionadas con los paquetes de parches.

Es vital que el número de versión del paquete de parches sea el mismo que el del paquete original. Debe hacer un seguimiento del estado del parche del paquete mediante una entrada aparte del archivo pkginfo con el formato.


PATCH=patch_number

Si se cambia la versión del paquete de un parche, cree otra instancia del paquete para que sea extremadamente difícil administrar el producto con el parche. Este método de parches de instancias progresivos comportaban ciertas ventajas en las primeras versiones del sistema operativo Solaris, pero hace que la administración de los sistemas más complicados sea tediosa.

Todos los parámetros de zona del parche deben coincidir con los parámetros de zona del paquete.

Por lo que respecta a los paquetes que componen el sistema operativo Solaris, debe haber una única copia del paquete en la base de datos de paquetes, aunque puede haber varias instancias de parches. Con el fin de suprimir un objeto de un paquete instalado (mediante el comando removef) debe imaginarse qué instancias son propietarias de ese archivo.

Sin embargo, si el paquete (que no forma parte del sistema operativo Solaris) debe determinar el nivel de parches de un paquete concreto que forma parte del sistema operativo Solaris, se convierte en un problema que debe resolverse aquí. Las secuencias de comandos de instalación pueden ser bastante grandes sin un impacto significativo puesto que no se almacenan en el sistema de archivos de destino. Gracias a las secuencias de comandos de acción de clase y otras secuencias de comandos de procedimientos, puede guardar archivos cambiados mediante la variable de entorno PKGSAV (o en otros directorios, más permanentes) con el fin de permitir la anulación de los parches instalados. También puede supervisar el historial de parches si configura las variables de entorno pertinentes a través de las secuencias de comandos request. Las secuencias de comandos de las secciones siguientes asumen que puede haber varios parches cuyo esquema de numeración conlleve algún significado al aplicarse a un único paquete. En este caso, el número de cada parche representa un subconjunto de archivos con funciones relacionadas en el paquete. Dos números de parches diferentes no pueden cambiar el mismo archivo.

Con el fin de convertir un paquete disperso regular en un paquete de parches, las secuencias de comandos descritas en las secciones siguientes pueden doblarse sencillamente en el paquete. Todas ellas son reconocibles como componentes de paquete estándar con la excepción de las dos últimas, patch_checkinstall y patch_postinstall. Esas dos secuencias de comandos pueden incorporarse al paquete de anulación, si desea incluir la posibilidad de anular el parche. Las secuencias de comandos son bastante sencillas y sus diversas tareas son sencillas.


Nota –

Este método de parches se puede usar para sistemas cliente de parches, pero los directorios raíz cliente del servidor deben contar con los permisos correctos para permitir la lectura al usuario install o nobody.


La secuencia de comandos checkinstall

La secuencia de comandos checkinstall verifica que el parche es el adecuado para este paquete concreto. Una vez que se haya confirmado, genera la lista de parches y la lista de información de parches; después las inserta en el archivo de respuesta para su incorporación a la base de datos de paquetes.

Una lista de parches es aquella donde se enumeran los que tienen afectado el paquete actual. Esta lista de parches se registra en el paquete instalado en el archivo pkginfo con una línea que podría tener este aspecto:

PATCHLIST=patch_id patch_id ...

Una lista de información de parches es aquella de la que depende el parche actual. Esta lista de parches también se registra en el archivo pkginfo con una línea que podría tener este aspecto:

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

Nota –

Estas líneas (y su formato) se declaran como interfaz pública. Las empresas que distribuyan parches para los paquetes de Solaris deben actualizar esta lista de forma pertinente. Cuando se entrega un parche, cada paquete del parche contiene una secuencia de comandos checkinstall que lleva a cabo esta tarea. Esa misma secuencia de comandos checkinstall también actualiza otros parámetros específicos de los parches. Ésta es la nueva arquitectura de parches que recibe el nombre de Direct Instance Patching.


En este ejemplo, tanto los paquetes originales como sus parches existen en el mismo directorio. Los dos paquetes originales reciben el nombre de SUNWstuf.v1 y SUNWstuf.v2, y sus parches reciben el nombre de SUNWstuf.p1 y SUNWstuf.p2. Esto significa que puede ser muy difícil para una secuencia de comandos de procedimientos imaginarse de qué directorio vienen estos archivos, puesto que todo lo que sigue en el nombre del paquete al punto (“.”) se elimina en el parámetro PKG, y la variable de entorno PKGINST se refiere a la instancia instalada, no la instancia de origen. Por lo tanto, las secuencias de comandos de procedimientos pueden encontrar el directorio de origen, la secuencia de comandos checkinstall (que siempre se ejecuta desde el directorio de origen) lleva a cabo la consulta y pasa la ubicación como variable SCRIPTS_DIR. Si hubiese habido un solo paquete en el directorio de origen llamado SUNWstuf, las secuencias de comandos de procedimientos podrían haberla encontrado mediante $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

La secuencia de comandos preinstall

La secuencia de comandos preinstall inicializa el archivo prototype, los archivos de información y las secuencias de comandos de instalación para que se genere el paquete de anulación. Esta secuencia de comandos es muy sencilla y las secuencias restantes de este ejemplo sólo permiten un paquete de anulación para describir archivos regulares.

Si quisiera restaurar vínculos simbólicos, vínculos físicos, dispositivos y conducciones con nombre en un paquete de anulación, podría modificar la secuencia de comandos preinstall para usar el comando pkgproto con el fin de comparar el archivo pkgmap entregado con los archivos instalados, y después crear una entrada de archivo prototype para cada elemento que no sea un archivo que se deba cambiar en el paquete de anulación. El método que debe usar es parecido al de la secuencia de comandos de acción de clase.

Las secuencias de comandos patch_checkinstall y patch_postinstall se insertan en el árbol de origen del paquete desde la secuencia de comandos preinstall. Estas dos secuencias de comandos deshacen lo que el parche hace.

# 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

Secuencia de comandos de acción de clase

La secuencia de comandos de acción de clase crea una copia de cada archivo que sustituye a un archivo existente y agrega una línea correspondiente al archivo prototype para el paquete de anulación. Todo esto se lleva a cabo con secuencias de comandos nawk bastante sencillas. La secuencia de comandos de acción de clase recibe una lista de pares de origen/destino que se compone de archivos ordinarios que no coinciden con los archivos instalados correspondientes. Los vínculos simbólicos y otros elementos que no sean archivos deben gestionarse en la secuencia de comandos 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

La secuencia de comandos postinstall

La secuencia de comandos postinstall crea el paquete de anulación mediante la información proporcionada por las demás secuencias de comandos. Puesto que los comandos pkgmk y pkgtrans no precisan la base de datos de paquetes, se pueden ejecutar en la instalación de un paquete.

En este ejemplo se permite deshacer el parche mediante la construcción de un paquete de formato de flujo en el directorio para guardar (mediante la variable de entorno PKGSAV). No es obvio, pero este paquete debe tener formato de flujo, porque el directorio para guardar cambia de posición durante una operación de pkgadd. Si se aplica el comando pkgadd a un paquete en su propio directorio para guardar, las suposiciones sobre dónde está el origen del paquete en un momento concreto se vuelven muy poco fiables. Un paquete con formato de flujo se desempaqueta en un directorio temporal y se instala desde allí. (Un paquete con formato de directorio comenzaría la instalación desde el directorio para guardar y se encontraría repentinamente reubicado durante una operación a prueba de fallos de pkgadd.)

Para determinar qué parches se aplican a un paquete, use este comando:


$ pkgparam SUNWstuf PATCHLIST

Con la excepción de PATCHLIST, una interfaz pública de Sun, no hay nada significativo en los nombres de parámetros en este ejemplo. En lugar de PATCH, podría usar la SUNW_PATCHID tradicional y se podría cambiar en consonancia el nombre de otras listas como PATCH_EXCL y PATCH_REQD.

Si determinados paquetes de parches dependen de otros que están disponibles en el mismo medio, la secuencia de comandos checkinstall podría determinar esto y crear una secuencia de comandos que se ejecutara mediante la secuencia de comandos postinstall del mismo modo que el ejemplo de actualización (consulte Actualización de paquetes).

# 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

La secuencia de comandos 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

La secuencia de comandos 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

Actualización de paquetes

El proceso para actualizar un paquete es muy diferente del proceso para sobrescribirlo. Aunque hay herramientas especiales para admitir la actualización de paquetes estándar distribuidos como parte del sistema operativo Solaris, se puede diseñar un paquete no integrado para que admita su propia actualización; en diversos ejemplos anteriores se ha informado sobre paquetes que van más allá y controlan el método exacto de instalación bajo la dirección del administrador. Puede diseñar la secuencia de comandos request para que admita también la actualización directa de un paquete. Si el administrador elige la instalación de un paquete para que sustituya a otro completamente, sin que queden archivos obsoletos residuales, las secuencias de comandos de paquetes permiten esta posibilidad.

Las secuencias de comandos request y postinstall de este ejemplo ofrecen un único paquete actualizable. La secuencia de comandos request se comunica con el administrador y, a continuación, configura un único archivo en el directorio /tmp para suprimir la instancia de paquete anterior. (Aunque la secuencia de comandos request cree un archivo (lo cual está prohibido), no hay ningún problema, ya que todos tienen acceso a /tmp).

La secuencia de comandos postinstall ejecuta a continuación la secuencia de comandos de shell en /tmp que ejecuta el comando pkgrm necesario relacionado con el paquete anterior y después se suprime.

Este ejemplo ilustra una actualización básica. Son menos de 50 líneas de código, incluidos algunos mensajes bastante largos. Se podría ampliar para anular la actualización o llevar a cabo otras transformaciones principales en el paquete, según lo requiera el diseñador.

El diseño de la interfaz de usuario para una opción de actualización debe estar completamente seguro de que el administrador tiene plena conciencia del proceso y que ha solicitado activamente la actualización en lugar de una instalación paralela. No hay problemas en llevar a cabo una operación compleja bien comprendida como una actualización siempre que la interfaz del usuario deje la operación clara.

La secuencia de comandos 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

La secuencia de comandos 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

Creación de paquetes de archivo de almacenamiento de clase

Un paquete de archivo de almacenamiento de clase, una mejora en la Application Binary Interface (ABI, Interfaz binaria de aplicaciones), es aquel en que determinados conjuntos de archivos se han combinado en archivos de almacenamiento o archivos sencillos, y que de forma optativa se han comprimido o cifrado. Los formatos de archivos de almacenamiento de clase aumentan la velocidad de instalación inicial en un 30% y mejora la fiabilidad durante la instalación de paquetes y parches en sistemas de archivos potencialmente activos.

Las secciones siguientes ofrecen información sobre la estructura de directorios de paquetes de archivos de almacenamiento, palabras clave y la utilidad faspac.

Estructura del directorio de paquetes de archivos de almacenamiento

La entrada de paquete que aparece en la figura siguiente representa el directorio que contiene los archivos de paquetes. Este directorio debe tener el mismo nombre que el paquete.

Figura 6–1 Estructura del directorio de paquetes

El diagrama muestra cinco subdirectorios directamente por debajo del directorio de paquetes: pkginfo, pkgmap, reloc, root e install. También muestra los subdirectorios.

A continuación se enumeran las funciones de los archivos y directorios que se incluyen en el directorio de paquetes.

Elemento 

Descripción 

pkginfo

Archivo que describe el paquete en conjunto que incluye variables de entorno especiales y directivas de instalación 

pkgmap

Descripción de archivo de cada objeto que instalar, como un archivo, directorio o conducción 

reloc

Directorio optativo que contiene los archivos que se van a instalar relacionados con el directorio base (objetos reubicables) 

root

Directorio optativo que contiene los archivos que se van a instalar relacionados con el directorio root (objetos raíz)

install

Directorio optativo que contiene secuencias de comandos y otros archivos auxiliares (excepto en el caso de pkginfo y pkgmap, todos los archivos ftype i hasta aquí)

El formato de archivo de almacenamiento de clase permite al creador de paquetes combinar archivos de los directorios reloc y root en archivos de almacenamiento que se pueden comprimir, cifrar o procesar del modo que se desee para aumentar la velocidad de la instalación, reducir el tamaño del paquete o aumentar la seguridad del paquete.

La ABI permite asignar cualquier archivo de un paquete a una clase. Todos los archivos de una clase específica se pueden instalar en el disco mediante un método personalizado definido por una secuencia de comandos de acción de clase. Este método personalizado puede usar programas disponibles en el sistema de destino o programas distribuidos con el paquete. El formato resultante se parece mucho al formato estándar de la ABI. Tal como se muestra en la ilustración siguiente, se agrega otro directorio. Cualquier clase de archivos diseñados como archivo de almacenamiento se combina en un único archivo y se coloca en el directorio archive. Todos los archivos que se hayan archivado se suprimen de los directorios reloc y root y se coloca una secuencia de comandos de acción de clase de instalación en el directorio install.

Figura 6–2 Estructura de directorios de paquetes de archivos de almacenamiento

El diagrama muestra la misma estructura de directorio de paquetes en la Figura 6-1 con la adición del subdirectorio de archivos de almacenamiento.

Palabras clave para admitir paquetes de archivo de almacenamiento de clase

Con el fin de admitir este nuevo formato de archivo de almacenamiento de clase, tres nuevas interfaces con formato de palabras clave tienen un significado especial en el archivo pkginfo. Estas palabras clave se usan para designar clases que precisen un tratamiento especial. El formato de cada instrucción de palabra clave: keyword=class1[class2 class3 ...]. Los valores de cada palabra clave se definen en la tabla siguiente.

Palabra clave 

Descripción 

PKG_SRC_NOVERIFY

Indica a pkgadd que no verifique la existencia ni las propiedades de los archivos en los directorios reloc o root del paquete distribuido si pertenecen a la clase nombrada. Esto es necesario en todas las clases archivadas, porque esos archivos ya no se encuentran en un directorio reloc o root. Son un archivo de formato privado en el directorio archive.

PKG_DST_QKVERIFY

Los archivos de estas clases se verifican después de la instalación mediante un algoritmo rápido con poca o ninguna salida de texto. La verificación rápida configura primero los atributos de cada archivo correctamente y después comprueba si la operación ha sido satisfactoria. Después hay una prueba de la hora de modificación y el tamaño del archivo con el pkgmap. No se lleva a cabo una verificación checksum y la recuperación de errores es más deficiente que la ofrecida por el mecanismo estándar de verificación. En el caso de interrupción de la alimentación o fallo en el disco durante la instalación, es posible que falte coherencia al archivo de contenido respecto a los archivos instalados. Esta falta de coherencia se puede solucionar siempre con un comando pkgrm.

PKG_CAS_PASSRELATIVE

Por lo general, la secuencia de comandos de acción de clase de instalación recibe de stdin una lista de pares de origen y de destino para indicar qué archivos se deben instalar. Las clases asignadas a PKG_CAS_PASSRELATIVE no obtienen los pares de origen y de destino. En su lugar reciben una lista única, cuya primera entrada es la ubicación del paquete de origen y el resto son las rutas de destino. La finalidad específica es simplificar la extracción de un archivo de almacenamiento. A partir de la ubicación del paquete de origen, puede buscar el archivo de almacenamiento en el directorio archive. Las rutas de destino pasan a la función responsable de extraer el contenido de un archivo de almacenamiento. Cada ruta de destino proporcionada es absoluta o relativa en relación al directorio base, según si la ruta se encontraba originalmente en root o reloc. Si se elige esta opción, puede que sea difícil combinar las rutas relativas y absolutas en una única clase.

Se precisa una secuencia de comandos de acción de clase para cada clase archivada. Se trata de un archivo que contiene comandos de shell Bourne, ejecutado por pkgadd para instalar los archivos desde el archivo de almacenamiento. Si se encuentra una secuencia de comandos de acción de clase en el directorio install del paquete, pkgadd entrega toda la responsabilidad de la instalación a esa secuencia de comandos. La secuencia de comandos de acción de clase se ejecuta con permisos de usuario root y puede situar sus archivos en cualquier lugar del sistema de destino.


Nota –

La única palabra clave que es absolutamente necesaria para implementar un paquete de archivo de almacenamiento de clase es PKG_SRC_NOVERIFY. Las demás se pueden usar para aumentar la velocidad de la instalación o conservar el código.


La utilidad faspac

La utilidad faspac convierte un paquete ABI estándar en un formato de archivo de almacenamiento de clase utilizado para paquetes integrados. Esta utilidad realiza tareas de archivado mediante cpio y tareas de compresión mediante compress. El paquete resultante tiene un directorio adicional en el directorio superior llamado archive. En este directorio se encuentran todos los archivos de almacenamiento nombrados por clase. El directorio install contendrá las secuencias de comandos de acción de clase necesarias para desempaquetar cada archivo de almacenamiento. Las rutas absolutas no se archivan.

La utilidad faspac tiene el formato siguiente:


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

Cada opción del comando faspac se describe en la tabla siguiente.

Opción 

Descripción 

-m método_archivado

 

Indica un método para el archivado o la compresión. bzip2 es la utilidad de compresión predeterminada que se ha utilizado. Para conmutar el método de compresión o descompresión, utilice -m zip; para cpio o compress use - m cpio.

-a

Corrige atributos (debe ser root para ello). 

-s

Indica la traducción de paquetes de tipo ABI estándar. Esta opción toma un paquete comprimido o cpio y lo convierte en formato estándar de paquete compatible con ABI. 

-q

Indica el modo silencioso. 

-d directorio_base

Indica el directorio donde se actuará sobre todos los paquetes presentes según lo requiera la línea de comandos. Esto es incompatible con la entrada lista_paquetes.

-x lista_exclusión

Indica una lista de paquetes separados por espacios, entre comillas o separados por comas para excluirlos del proceso. 

Lista de paquetes

Indica la lista de paquetes que se van a procesar.