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.
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.
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:
ask: significa que debe pedir siempre al administrador un directorio base
Un nombre de ruta absoluta
Un nombre de ruta absoluta que contenga la construcción $PKGINST, lo cual significa que debe hacer siempre la instalación en un directorio base derivado de la instancia del paquete
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.
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.
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.
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 |
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:
Un paquete con nombres de ruta paramétricos se comporta normalmente como un paquete absoluto pero el comando pkgadd lo considera un paquete reubicable. El parámetro BASEDIR debe definirse aunque no se use.
El administrador no puede establecer la base de instalación para el paquete mediante las utilidades de System V (el comando pkginfo -r no funcionará).
El administrador no puede usar el método establecido para reubicar el paquete (se llama reubicable pero actúa de forma absoluta).
Las instalaciones de varias versiones o arquitecturas necesitan planificar las contingencias para cada uno de los directorios base de destino, lo cual significa a menudo diversas secuencias de comandos complejas de acción de clase.
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.
# 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 |
: 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 |
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.
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.
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.
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.
# 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 |
: 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 |
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.
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.
# request script for SUNWstuf to walk the BASEDIR parameter. PATH=/usr/sadm/bin:${PATH} # use admin utilities GENMSG="The base directory $LOCAL_BASE already contains a \ different architecture or version of $PKG." OLDMSG="If the option \"-a none\" was used, press the \ key and enter an unused base directory when it is requested." OLDPROMPT="Do you want to overwrite this version? " OLDHELP="\"y\" will replace the installed package, \"n\" will \ stop the installation." SUSPEND="Suspending installation at user request using error \ code 1." MSG="This package could be installed at the unused base directory $WRKNG_BASE." PROMPT="Do you want to use to the proposed base directory? " HELP="A response of \"y\" will install to the proposed directory and continue, \"n\" will request a different directory. If the option \"-a none\" was used, press the key and enter an unused base directory when it is requested." DIRPROMPT="Select a preferred base directory ($WRKNG_BASE) " DIRHELP="The package $PKG will be installed at the location entered." NUBD_MSG="The base directory has changed. Be sure to update \ any applicable search paths with the actual location of the \ binaries which are at $WRKNG_BASE/EZstuf and $WRKNG_BASE/HRDstuf." OldSolaris="" Changed="" Suffix="0" # # Determine if this product is actually installed in the working # base directory. # Product_is_present () { if [ -d $WRKNG_BASE/EZstuf -o -d $WRKNG_BASE/HRDstuf ]; then return 1 else return 0 fi } if [ ${BASEDIR} ]; then # This may be an old version of Solaris. In the latest Solaris # CLIENT_BASEDIR won't be defined yet. In older version it is. if [ ${CLIENT_BASEDIR} ]; then LOCAL_BASE=$BASEDIR OldSolaris="true" else # The base directory hasn't been processed yet LOCAL_BASE=${PKG_INSTALL_ROOT}$BASEDIR fi WRKNG_BASE=$LOCAL_BASE # See if the base directory is already in place and walk it if # possible while [ -d ${WRKNG_BASE} -a Product_is_present ]; do # There is a conflict # Is this an update of the same arch & version? if [ ${UPDATE} ]; then exit 0 # It's out of our hands. else # So this is a different architecture or # version than what is already there. # Walk the base directory Suffix=`expr $Suffix + 1` WRKNG_BASE=$LOCAL_BASE.$Suffix Changed="true" fi done # So now we can propose a base directory that isn't claimed by # any of our other versions. if [ $Changed ]; then puttext "$GENMSG" if [ $OldSolaris ]; then puttext "$OLDMSG" result=`ckyorn -Q -d "a" -h "$OLDHELP" -p "$OLDPROMPT"` if [ $result="n" ]; then puttext "$SUSPEND" exit 1 # suspend installation else exit 0 fi else # The latest functionality is available puttext "$MSG" result=`ckyorn -Q -d "a" -h "$HELP" -p "$PROMPT"` if [ $? -eq 3]; then echo quitinstall >> $1 exit 0 fi if [ $result="n" ]; then WRKNG_BASE=`ckpath -ayw -d "$WRKNG_BASE" \ -h "$DIRHELP" -p "$DIRPROMPT"` else if [ $result="a" ] exit 0 fi fi echo "BASEDIR=$WRKNG_BASE" >> $1 puttext "$NUBD_MSG" fi fi exit 0 |
# checkinstall 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.
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.
# 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 |
: 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.
# 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 |
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.
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.
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.
# 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 |
: 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.
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.
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.
: 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.
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.
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.
# 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 |
: 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.
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.
Hay dos normas que seguir a la hora de construir un paquete compuesto funcional:
Establecer el directorio base según donde va la amplia mayoría de los objetos del paquete.
Si un objeto del paquete va a un directorio común que no es el directorio base (por ejemplo, /etc), especifíquelo como nombre de ruta absoluta en el archivo prototype.
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.
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.
Se agrega una entrada a una tabla, o bien el objeto es una tabla nueva que probablemente modificarán otros programas o paquetes.
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.
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.
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.
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.
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.
Use la construcción ${PKG_INSTALL_ROOT}/etc, o bien.
Tome el nombre de directorio de un archivo aprobado por el comando pkgadd (lo que esta secuencia de comandos hace).
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.
Éste es un ejemplo de los archivos pkginfo y pkgmap para un paquete compuesto.
PKG=SUNWstuf NAME=software stuff ARCH=sparc VERSION=1.0.0,REV=1.0.5 CATEGORY=application DESC=a set of utilities that do stuff BASEDIR=/opt VENDOR=Sun Microsystems, Inc. HOTLINE=Please contact your local service provider EMAIL= MAXINST=1000 CLASSES=none daemon PSTAMP=hubert990707141632 |
: 1 1758 1 d none SUNWstuf/EZstuf 0775 root bin 1 f none SUNWstuf/EZstuf/dirdel 0555 bin bin 40 773 751310229 1 f none SUNWstuf/EZstuf/usrdel 0555 bin bin 40 773 751310229 1 f none SUNWstuf/EZstuf/filedel 0555 bin bin 40 773 751310229 1 d none SUNWstuf/HRDstuf 0775 root bin 1 f none SUNWstuf/HRDstuf/mksmart 0555 bin bin 40 773 751310229 1 f none SUNWstuf/HRDstuf/mktall 0555 bin bin 40 773 751310229 1 f none SUNWstuf/HRDstuf/mkcute 0555 bin bin 40 773 751310229 1 f none SUNWstuf/HRDstuf/mkeasy 0555 bin bin 40 773 751310229 1 d none /etc ? ? ? 1 d none /etc/rc2.d ? ? ? 1 e daemon /etc/rc2.d/S70dostuf 0744 root sys 450 223443 1 i i.daemon 509 39560 752978103 1 i pkginfo 348 28411 760740163 1 i postinstall 323 26475 751309908 1 i postremove 402 33179 751309945 1 i preinstall 321 26254 751310019 1 i preremove 320 26114 751309865 1 i r.daemon 320 24573 742152591 |
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.
Al asignar un directorio a una clase, recuerde siempre el orden de creación y eliminación.
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.
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 |
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 |
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.
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.
Si el sistema es lo suficientemente complejo, es aconsejable establecer un sistema de identificación de parches que asegure que dos parches no sustituyan al mismo archivo en un intento de corregir comportamientos aberrantes diferentes. Por ejemplo, a los números base de parches de Sun se les asignan conjuntos de archivos mutuamente excluyentes de los que son responsables.
Es necesario que sea posible anular un parche.
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.
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 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 |
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 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 |
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 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 |
# checkinstall script to validate backing out a patch. # directory format option. # # @(#)patch_checkinstall 1.2 95/10/10 SMI # # Copyright (c) 1995 by Sun Microsystems, Inc. # All rights reserved # PATH=/usr/sadm/bin:$PATH LATER_MSG="PaTcH_MsG 6 ERROR: A later version of this patch is applied." NOPATCH_MSG="PaTcH_MsG 2 ERROR: Patch number $ACTIVE_PATCH is not installed" NEW_LIST="" # Get OLDLIST . $1 # # Confirm that the patch that got us here is the latest one installed on # the system and remove it from PATCHLIST. # Is_Inst=0 Skip=0 active_base=`echo $ACTIVE_PATCH | nawk ' { print substr($0, 1, match($0, "Patchvers_pfx")-1) } '` active_inst=`echo $ACTIVE_PATCH | nawk ' { print substr($0, match($0, "Patchvers_pfx")+1) } '` for patchappl in ${OLDLIST}; do appl_base=`echo $patchappl | nawk ' { print substr($0, 1, match($0, "Patchvers_pfx")-1) } '` if [ $appl_base = $active_base ]; then appl_inst=`echo $patchappl | nawk ' { print substr($0, match($0, "Patchvers_pfx")+1) } '` result=`expr $appl_inst \> $active_inst` if [ $result -eq 1 ]; then puttext "$LATER_MSG" exit 3 elif [ $appl_inst = $active_inst ]; then Is_Inst=1 Skip=1 fi fi if [ $Skip = 1 ]; then Skip=0 else NEW_LIST="${NEW_LIST} $patchappl" fi done if [ $Is_Inst = 0 ]; then puttext "$NOPATCH_MSG" exit 3 fi # # OK, all's well. Now condition the key variables. # echo "PATCHLIST=${NEW_LIST}" >> $1 echo "Patch_label=" >> $1 echo "PATCH_INFO_$ACTIVE_PATCH=backed out" >> $1 # Get the current PATCH_OBSOLETES and condition it Old_Obsoletes=$PATCH_OBSOLETES echo $ACTIVE_OBSOLETES | sed 'y/\ /\n/' | \ nawk -v PatchObsList="$Old_Obsoletes" ' BEGIN { printf("PATCH_OBSOLETES="); PatchCount=split(PatchObsList, PatchObsComp, " "); for(PatchIndex in PatchObsComp) { Atisat=match(PatchObsComp[PatchIndex], "@"); PatchObs[PatchIndex]=substr(PatchObsComp[PatchIndex], \ 0, Atisat-1); PatchObsCnt[PatchIndex]=substr(PatchObsComp\ [PatchIndex], Atisat+1); } } { for(PatchIndex in PatchObs) { if (PatchObs[PatchIndex] == $0) { PatchObsCnt[PatchIndex]=PatchObsCnt[PatchIndex]-1; } } next; } END { for(PatchIndex in PatchObs) { if ( PatchObsCnt[PatchIndex] > 0 ) { printf("%s@%d ", PatchObs[PatchIndex], PatchObsCnt\ [PatchIndex]); } } printf("\n"); } ' >> $1 # remove the used parameters echo "ACTIVE_OBSOLETES=" >> $1 echo "Obsoletes_label=" >> $1 exit 0 |
# This script deletes the used backout data for a patch package # and removes the deletes file entries. # # directory format options. # # @(#)patch_postinstall 1.2 96/01/29 SMI # # Copyright (c) 1995 by Sun Microsystems, Inc. # All rights reserved # PATH=/usr/sadm/bin:$PATH THIS_DIR=`dirname $0` Our_Deletes=$THIS_DIR/deletes # # Delete the used backout data # if [ -f $Our_Deletes ]; then cat $Our_Deletes | while read path; do if valpath -l $path; then Client_Path=`echo "$CLIENT_BASEDIR/$path" | sed s@//@/@` else # It's an absolute path Client_Path=$path fi rm `removef $PKGINST $Client_Path` done removef -f $PKGINST rm $Our_Deletes fi # # Remove the deletes file, checkinstall and the postinstall # rm -r $PKGSAV/$ACTIVE_PATCH rm -f $THIS_DIR/checkinstall $THIS_DIR/postinstall exit 0 |
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.
# request script control an upgrade installation PATH=/usr/sadm/bin:$PATH UPGR_SCRIPT=/tmp/upgr.$PKGINST UPGRADE_MSG="Do you want to upgrade the installed version ?" UPGRADE_HLP="If upgrade is desired, the existing version of the \ package will be replaced by this version. If it is not \ desired, this new version will be installed into a different \ base directory and both versions will be usable." UPGRADE_NOTICE="Conflict approval questions may be displayed. The \ listed files are the ones that will be upgraded. Please \ answer \"y\" to these questions if they are presented." pkginfo -v 1.0 -q SUNWstuf.\* if [ $? -eq 0 ]; then # See if upgrade is desired here response=`ckyorn -p "$UPGRADE_MSG" -h "$UPGRADE_HLP"` if [ $response = "y" ]; then OldPkg=`pkginfo -v 1.0 -x SUNWstuf.\* | nawk ' \ /SUNW/{print $1} '` # Initiate upgrade echo "PATH=/usr/sadm/bin:$PATH" > $UPGR_SCRIPT echo "sleep 3" >> $UPGR_SCRIPT echo "echo Now removing old instance of $PKG" >> \ $UPGR_SCRIPT if [ ${PKG_INSTALL_ROOT} ]; then echo "pkgrm -n -R $PKG_INSTALL_ROOT $OldPkg" >> \ $UPGR_SCRIPT else echo "pkgrm -n $OldPkg" >> $UPGR_SCRIPT fi echo "rm $UPGR_SCRIPT" >> $UPGR_SCRIPT echo "exit $?" >> $UPGR_SCRIPT # Get the original package's base directory OldBD=`pkgparam $OldPkg BASEDIR` echo "BASEDIR=$OldBD" > $1 puttext -l 5 "$UPGRADE_NOTICE" else if [ -f $UPGR_SCRIPT ]; then rm -r $UPGR_SCRIPT fi fi fi exit 0 |
# postinstall 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 |
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.
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.
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.
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.
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 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. |