Guide du développeur pour l'empaquetage d'applications

Chapitre 6 Techniques avancées de création de packages

Toutes les possibilités offertes par le package System V tel qu'il est implémenté dans le système d'exploitation Solaris représentent un outil puissant d'installation de produits logiciels. En tant que concepteur de package, vous pouvez bénéficier de ces capacités. Les packages ne faisant pas partie du système d'exploitation Solaris (packages non fournis en standard) peuvent utiliser le mécanisme de classes pour personnaliser les installations serveur/client. Les packages réadressables peuvent être conçus de sorte à répondre aux besoins de l'administrateur. Un produit complexe peut être livré sous forme de packages composites capables de résoudre automatiquement les dépendances des packages. La mise à niveau et l'application de patchs peuvent être personnalisées par le concepteur de package. Les packages auxquels des patchs ont été appliqués peuvent être livrés de la même manière que les packages sans patchs et les archives de désinstallation peuvent aussi être incluses dans le produit.

La liste suivante répertorie les informations fournies dans ce chapitre :

Spécification du répertoire de base

Plusieurs méthodes sont disponibles pour spécifier l'emplacement de l'installation d'un package et il est important de pouvoir modifier le répertoire de base de l'installation dynamiquement lors de la phase d'installation. Lorsque cette spécification est effectuée correctement, un administrateur peut installer plusieurs versions et plusieurs architectures sans difficulté.

Cette section aborde les méthodes courantes avant de passer à des démarches permettant d'améliorer les installations sur des systèmes hétérogènes.

Fichier de valeurs d'administration par défaut

Les administrateurs chargés de l'installation des packages peuvent se servir des fichiers d'administration pour contrôler l'installation des packages. Toutefois, en tant que concepteur de package, vous devez savoir ce qu'est un fichier d'administration et de quelle manière un administrateur peut modifier l'installation prévue d'un package.

Un fichier d'administration indique à la commande pkgadd si elle doit ou non effectuer les contrôles et afficher les invites qu'elle effectue/affiche habituellement. Les administrateurs doivent pour cette raison maîtriser la procédure d'installation d'un package et les scripts qui lui sont associés avant de se servir des fichiers d'administration.

Le système d'exploitation SunOS est livré avec un fichier de valeurs d'administration par défaut que vous trouverez dans /var/sadm/install/admin/default. Il s'agit du fichier établissant le niveau de politique d'administration le plus basique en matière d'installation de produits logiciels. Le fichier tel qu'il est livré est comme suit :

#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

L'administrateur peut modifier ce fichier afin d'établir de nouveaux comportements par défaut ou, créer un autre fichier d'administration et spécifier son existence à l'aide de l'option -a dans la commande pkgadd.

Onze paramètres peuvent être définis dans un fichier d'administration ; toutefois, certains sont facultatifs. Pour plus d'informations, reportez-vous à admin(4).

Le paramètre basedir spécifie la manière dont le répertoire de base est généré à l'installation d'un package. La plupart des administrateurs conservent la valeur default mais le paramètre basedir peut prendre une des valeurs suivantes :


Remarque –

Si la commande pkgadd est appelée avec l'argument - a none, elle demande systématiquement le répertoire de base à l'administrateur. Malheureusement, cette commande définit également tous les paramètres du fichier sur la valeur par défaut quit qui est susceptible d'engendrer des problèmes supplémentaires.


S'habituer à l'incertitude

Un administrateur contrôle tous les packages installés sur un système via l'utilisation d'un fichier d'administration. Un autre fichier de valeurs d'administration par défaut est malheureusement souvent fourni par le concepteur du package ; ce fichier ignore en effet les souhaits de l'administrateur.

Les concepteurs de package incluent parfois un autre fichier d'administration qui leur permet (et non pas à l'administrateur) de contrôler l'installation d'un package. Étant donné que l'entrée basedir du fichier de valeurs d'administration par défaut ignore tous les autres répertoires de base, elle représente une méthode simple de sélection du répertoire de base lors de la phase d'installation. Dans toutes les versions du système d'exploitation Solaris antérieures à Solaris 2.5, ceci était considéré comme la méthode la plus simple de contrôle du répertoire de base.

Toutefois, vous devez tenir compte des souhaits de l'administrateur relatifs à l'installation du produit. La présence d'un fichier temporaire de valeurs d'administration par défaut destiné à contrôler l'installation induit la méfiance chez les administrateurs. Utilisez un script request et un script checkinstall pour contrôler ces installations sous la direction de l'administrateur. Si le script request implique véritablement l'administrateur dans la procédure, l'empaquetage du System V bénéficiera à la fois aux administrateurs et aux concepteurs de package.

Utilisation du paramètre BASEDIR

Le fichier pkginfo de tout package réadressable doit contenir une entrée spécifiant le répertoire de base par défaut dans le format suivant :


BASEDIR=absolute_path

Il ne s'agit que du répertoire de base par défaut et peut de ce fait être remplacé par l'administrateur au cours de l'installation.

Bien que certains packages requièrent plusieurs répertoires de base, l'avantage que présente ce paramètre pour le placement du package est que le répertoire de base est déjà créé et prêt à être utilisé dès le lancement de l'installation. Le chemin d'accès approprié au répertoire de base du serveur et du client est mis à la disposition de tous les scripts de procédure sous la forme de variables d'environnement réservées. La commande pkginfo -r SUNWstuf affiche la base d'installation actuelle du package.

Dans le script checkinstall, BASEDIR est le paramètre tel qu'il a été défini dans le fichier pkginfo (non encore déterminé). Afin de vérifier le répertoire de base cible, la construction ${PKG_INSTALL_ROOT}$BASEDIR est nécessaire. Ceci signifie que le script request ou checkinstall peut remplacer la valeur de BASEDIR dans l'environnement d'installation avec des résultats prévisibles. Le temps que le script preinstall soit appelé, le paramètre BASEDIR a été remplacé par le pointeur entièrement conditionné du répertoire de base actuel sur le système cible, même si le système est un client.


Remarque –

Le script request se sert du paramètre BASEDIR différemment selon la version du système d'exploitation SunOS. Afin de tester un paramètre BASEDIR dans un script request, le code suivant doit être utilisé pour déterminer le répertoire de base alors utilisé.

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

Utilisation des répertoires de base paramétriques

Si un package nécessite plusieurs répertoires de base, vous pouvez les créer à l'aide de noms de chemin paramétriques. Cette méthode est devenue assez populaire bien qu'elle présente les inconvénients suivants :

Bien que les paramètres qui déterminent les répertoires de base soient définis dans le fichier pkginfo, ils peuvent être modifiés par le script request. Cette caractéristique est une des raisons principales de la popularité de cette approche. Les inconvénients sont cependant chroniques et il est recommandé de n'utiliser cette configuration qu'en dernier ressort.

Exemples : Utilisation des répertoires de base paramétriques

Fichier pkginfo

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

Fichier pkgmap

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

Gestion du répertoire de base

Tout package disponible en plusieurs versions ou destiné à plusieurs architectures doit être conçu de sorte à pouvoir, le cas échéant, parcourir le répertoire de base. Le parcours d'un répertoire de base signifie que si une version précédente ou une architecture différente du package sur le point d'être installée se trouve déjà dans le répertoire de base, ce package résout le problème, en créant par exemple un nouveau répertoire de base sous un nom légèrement différent. Les scripts request et checkinstall de Solaris 2.5 et des versions compatibles sont en mesure de modifier la variable d'environnement BASEDIR. Ceci n'est pas le cas des versions précédentes du système d'exploitation Solaris.

Même dans les versions plus anciennes du système d'exploitation Solaris, le script request pouvait redéfinir les répertoires au sein de la base d'installation. Le script request est en mesure d'effectuer cette opération d'une manière prenant en charge la plupart des préférences d'administration.

Prise en compte du réadressage

La possibilité de sélectionner un répertorie de base unique à une architecture et à une version pour chaque package installé se traduit malheureusement par des niveaux hiérarchiques de répertoires superflus. Par exemple, pour un produit conçu pour les processeurs SPARC et x86, vous pouvez organiser les répertoires de base par processeur et par version comme illustré ci-dessous.

Répertoire de base 

Version et processeur 

/opt/SUNWstuf/sparc/1.0

Version 1.0, SPARC 

/opt/SUNWstuf/sparc/1.2

Version 1.2, SPARC 

/opt/SUNWstuf/x86/1.0

Version 1.0, x86 

Cette organisation est faisable. Elle suppose toutefois que ces noms et numéros aient une signification pour l'administrateur. Une meilleure approche consiste à effectuer automatiquement cette opération après avoir fourni des explications à l'administrateur et avoir obtenu son autorisation.

Ceci vous permet d'effectuer toute l'opération dans le package sans que l'administrateur ait besoin de le faire manuellement. Vous pouvez attribuer le répertoire de base de manière arbitraire, puis établir clairement les liens client appropriés dans un script postinstall. Vous pouvez également utiliser la commande pkgadd pour installer tout au partie du package sur les clients dans le script postinstall. Vous pouvez même demander à l'administrateur la liste des utilisateurs ou clients devant connaître l'existence de ce package et mettre automatiquement à jour les variables d'environnement PATH et les fichiers /etc. Ceci est tout à fait acceptable tant que toutes les opérations effectuées au cours de l'installation du package sont annulées lors de sa désinstallation.

Parcours des répertoires de base

Vous pouvez vous servir de deux méthodes pour contrôler le répertoire de base lors de la phase d'installation. La première est la mieux adaptée aux nouveaux packages qui ne peuvent être installés que sur Solaris 2.5 et des versions compatibles ; elle offre à l'administrateur des données très utiles ; elle prend par ailleurs en charge l'installation de plusieurs versions et architectures et ne nécessite qu'un minimum de travail particulier. La deuxième méthode peut être utilisée par tous les packages et fait appel au contrôle des paramètres de développement inhérent aux scripts request pour assurer le bon déroulement des installations.

Utilisation du paramètre BASEDIR

Le script checkinstall peut sélectionner le répertoire de base approprié lors de la phase d'installation, ce qui permet de placer le répertoire de base très près de la racine de l'arborescence de répertoires. L'exemple suivant incrémente le répertoire de base de manière séquentielle, ce qui se traduit par des répertoires aux formats /opt/SUNWstuf, /opt/SUNWstuf.1 et /opt/SUNWstuf.2. L'administrateur peut se servir de la commande pkginfo pour déterminer quelles architecture et version sont installées dans chaque répertoire de base.

Si le package SUNWstuf utilise cette méthode, ses fichiers pkginfo et pkgmap ressemblent aux suivants :

Fichier pkginfo

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

Fichier pkgmap

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

Exemple : Analyse de scripts parcourant un BASEDIR

Supposons que la version x86 de SUNWstuf est déjà installée sur le serveur dans /opt/SUNWstuf. Lorsque l'administrateur utilise la commande pkgadd pour installer la version SPARC, le script request doit détecter l'existence de la version x86 et interagir avec l'administrateur pour l'installation.


Remarque –

Le répertoire de base peut être parcouru sans l'interaction de l'administrateur dans un script checkinstall ; toutefois, lorsque des opérations arbitraires de ce type se produisent trop souvent, les administrateurs n'ont plus confiance dans la procédure.


Les scripts request et checkinstall d'un package gérant cette situation peuvent ressembler aux suivants :

Script request

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

Script checkinstall

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

Cette approche ne serait pas très efficace si le répertoire de base était simplement /opt. Ce package doit faire référence à BASEDIR de manière plus précise car le parcours de /opt pourrait s'avérer difficile. En fait, selon le schéma de montage, l'opération peut même s'avérer impossible. L'exemple parcourt le répertoire de base en créant un nouveau répertoire sous /opt, ce qui ne crée aucun problème.

Cet exemple utilise un script request et un script checkinstall, bien que les versions antérieures à Solaris 2.5 ne puissent pas exécuter de script checkinstall. Le script checkinstall de cet exemple est utilisé afin de suspendre poliment l'installation en réponse à un message privé sous la forme d'une chaîne quitinstall ». Si ce script s'exécute sous Solaris 2.3, le script checkinstall est ignoré et le script request suspend l'installation en affichant un message d'erreur.

N'oubliez pas que pour les versions antérieures à Solaris 2.5 et versions compatibles, le paramètre BASEDIR est un paramètre en lecture seule qui ne peut pas être modifié par le script request. Pour cette raison, lorsqu'une ancienne version du système d'exploitation SunOS est détectée (en recherchant une variable d'environnement CLIENT_BASEDIR conditionnée), le script request n'a que deux possibilités : poursuivre ou abandonner l'opération.

Utilisation de chemins paramétriques relatifs

Si votre produit logiciel a des chances d'être installé sur d'anciennes versions du système d'exploitation SunOS, le script request doit effectuer toutes les opérations requises. Cette approche peut également être utilisée pour manipuler plusieurs répertoires. Si des répertoires supplémentaires sont nécessaires, ils doivent toutefois être inclus dans un seul répertoire de base afin que le produit reste simple à gérer. Bien que le paramètre BASEDIR n'offre pas le niveau de granularité offert par la toute dernière version de Solaris, votre package peut malgré tout parcourir le répertoire de base à l'aide du script request pour manipuler les chemins paramétriques. L'exemple suivant illustre un fichier pkginfo et un fichier pkgmap :

Fichier pkginfo

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

Fichier pkgmap

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

Cet exemple n'est pas parfait. Une commande pkginfo -r renvoie /opt comme base d'installation, ce qui est assez ambigu. Bon nombre de packages se trouvent en effet dans /opt mais il s'agit au moins d'un répertoire précis. Tout comme l'exemple précédent, l'exemple suivant prend parfaitement en charge plusieurs architectures et plusieurs versions. Le script request peut être personnalisé afin de répondre aux besoins d'un package spécifique et de résoudre toute dépendance applicable.

Exemple : Script request parcourant un chemin paramétrique relatif

# 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

Prise en charge du réadressage dans un environnement hétérogène

Le concept d'origine sur lequel repose l'empaquetage du System V présumait une architecture par système. Le concept d'un serveur ne jouait aucun rôle dans la conception. De nos jours, bien entendu, un seul serveur peut prendre en charge plusieurs architectures, ce qui peut se traduire par la présence de plusieurs copies d'un logiciel sur un même serveur, chacune étant destinée à une architecture différente. Bien que les packages Solaris soient isolés dans la limite des systèmes de fichiers recommandés (par exemple, / et /usr), les bases de données des produits étant stockées à la fois sur le serveur et sur chaque client, les installations ne prennent pas toutes nécessairement en charge cette division. Certaines implémentations prennent en charge une structure entièrement différente et impliquent une base de données de produits commune. Bien que diriger les clients vers des versions différentes soit très simple, installer des packages System V dans des répertoires de base différents peut s'avérer complexe pour l'administrateur.

Lors de la conception de votre package, vous devez également prendre en considération les méthodes courantes employées par les administrateurs pour introduire la nouvelle version d'un logiciel. Les administrateurs souhaitent souvent installer et tester la toute dernière version parallèlement à la version déjà installée. La procédure consiste à installer la nouvelle version dans un répertoire de base autre que celui dans lequel la version actuelle est installée et à rediriger une poignée de clients non importants vers la nouvelle version afin de la tester. À mesure que sa confiance augmente, l'administrateur redirige de plus en plus de clients vers la nouvelle version. Après un certain temps, l'administrateur ne conserve l'ancienne version que pour des cas d'urgence et finit par la supprimer.

En d'autres termes, les packages destinés aux systèmes hétérogènes modernes doivent prendre en charge le vrai réadressage au sens où l'administrateur peut être amené à les placer à tout endroit raisonnable du système de fichiers et s'attendre à pouvoir utiliser toutes leurs fonctionnalités. L'environnement Solaris 2.5 et les versions compatibles offrent divers outils très utiles qui permettent d'installer correctement plusieurs architectures et versions sur un même système. Solaris 2.4 et les versions compatibles prennent également en charge le vrai réadressage mais leur procédure n'est pas aussi évidente.

Approche traditionnelle

Packages réadressables

L'ABI du System V suggère que le premier objectif d'un package réadressable était de simplifier l'installation du package pour l'administrateur. De nos jours, la nécessité des packages réadressables va plus loin. Il n'est plus seulement question de commodité puisqu'il arrive souvent lors de l'installation qu'un produit logiciel actif se trouve déjà dans le répertoire par défaut. Un package non conçu dans l'optique de gérer cette situation peut soit remplacer le produit existant, soit suspendre l'installation. Par contre, un package conçu pour gérer plusieurs architectures et plusieurs versions peut procéder à l'installation correctement et offrir à l'administrateur diverses options entièrement compatibles avec les habitudes d'administration déjà en place.

D'une certaine manière, le problème lié à l'existence de plusieurs architectures et celui lié à plusieurs versions est le même. Il faut pouvoir installer une variante du package actuel parallèlement à d'autres variantes et pouvoir diriger les clients ou les utilisateurs de systèmes autonomes de fichiers exportés vers n'importe laquelle de ces variantes sans y perdre en fonctionnalité. Bien que Sun ait établi des méthodes permettant de gérer plusieurs architectures sur un serveur, les administrateurs ne se conforment pas toujours à ces recommandations. Tous les packages doivent pouvoir se conformer aux souhaits raisonnables des administrateurs en matière d'installation.

Exemple : Package réadressable traditionnel

L'exemple suivant illustre l'apparence d'un package réadressable traditionnel. Le package doit être placé dans /opt/SUNWstuf et ses fichiers pkginfo et pkgmap peuvent s'afficher comme suit :

Fichier pkginfo

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

Fichier pkgmap

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

On parle ici de méthode traditionnelle car chaque objet de package est installé dans le répertoire de base défini par le paramètre BASEDIR du fichier pkginfo. Par exemple, le premier objet du fichier pkgmap est installé comme répertoire /opt/SUNWstuf.

Packages absolus

Un package absolu est un package qui s'installe sur un système de fichiers root (/) particulier. Ces packages sont difficiles à gérer du point de vue de plusieurs versions et architectures. En règle générale, tous les packages doivent être réadressables. Il existe cependant de très bonnes raisons d'inclure des éléments absolus dans un package réadressable.

Exemple : Package absolu traditionnel

Si le package SUNWstuf était un package absolu, le paramètre BASEDIR ne devrait pas être défini dans le fichier pkginfo et le fichier pkgmap serait comme suit :

Fichier pkgmap

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

Dans cet exemple, si l'administrateur a spécifié un autre répertoire de base lors de l'installation, il est ignoré par la commande pkgadd. Ce package s'installe toujours dans /opt/SUNWstuf du système cible.

L'argument -R de la commande pkgadd fonctionne comme prévu. Par exemple,


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

installe les objets dans /export/opt/client3/opt/SUNWstuf ; toutefois, il s'agit du seul semblant de réadressage de ce package.

Notez l'emploi du point d'interrogation (?) pour le répertoire /opt du fichier pkgmap. Il indique que les attributs actuels ne doivent pas être modifiés. Cela ne signifie pas « créer le répertoire à partir des attributs par défaut », bien que cela puisse se produire dans certaines situations. Tout répertoire spécifique au nouveau package doit spécifier tous les attributs de manière explicite.

Packages composites

Tout package contenant des objets réadressables est appelé un package réadressable. Ceci peut porter à confusion puisque le fichier pkgmap du package réadressable peut contenir des chemins absolus. L'utilisation d'une entrée racine (/) dans un fichier pkgmap peut améliorer les aspects réadressables du package. Les packages contenant à la fois des entrées réadressables et des entrées racines sont appelés des packages composites.

Exemple : Solution traditionnelle

Supposons qu'un objet dans le package SUNWstuf soit un script de démarrage exécuté au niveau d'exécution 2. Vous devez installer le fichier /etc/rc2.d/S70dostuf en tant que partie du package mais vous ne pouvez pas le placer dans le répertoire de base. Supposons qu'un package réadressable soit l'unique solution ; les fichiers pkginfo et pkgmap seraient comme suit :

Fichier pkginfo

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

Fichier pkgmap

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

Il n'existe pas de grandes différences entre cette approche et celle utilisée pour le package absolu. Un package absolu est en fait plus approprié car si l'administrateur a spécifié un autre répertoire de base, cette solution ne fonctionne pas.

En fait, seul un fichier de ce package doit être relatif à la racine ; les autres peuvent être placés n'importe où. L'utilisation d'un package composite comme solution à ce problème est abordée dans la suite de cette section.

Au-delà de la tradition

L'approche décrite dans cette section n'est pas applicable à tous les packages mais elle permet d'améliorer les performances lors de l'installation sur un environnement hétérogène. Les packages fournis dans le cadre du système d'exploitation Solaris (packages fournis en standard) sont peu concernés par cette approche ; par contre, les packages non fournis en standard peuvent se servir de l'empaquetage non traditionnel.

La raison pour laquelle les packages réadressables sont recommandés est la prise en charge de la spécification suivante :

Lorsqu'un package est ajouté ou supprimé, les comportements actuels souhaités des produits logiciels restent inchangés.

Les packages non fournis en standard doivent résider dans /opt pour s'assurer que le nouveau package n'interfère pas avec les produits existants.

Informations supplémentaires sur les packages composites

Deux règles doivent être appliquées lors de la création d'un package composite fonctionnel :

En d'autres termes, puisque qu'un objet réadressable peut par définition être installé à tout endroit et fonctionner correctement ainsi, aucun script de démarrage exécuté par init lors de l'initialisation ne peut être considéré comme réadressable. Bien que spécifier /etc/passwd en tant que chemin relatif dans le package livré n'est en soi pas incorrect, il ne peut y avoir qu'une destination.

Noms de chemins absolus à l'apparence réadressable

Lorsque vous créez un package composite, les chemins absolus doivent fonctionner sans interférer avec les logiciels déjà installés. Un package pouvant être intégralement contenu dans /opt évite ce problème puisque aucun fichier ne représente un obstacle. Lorsqu'un fichier placé dans /etc est inclus dans le package, vous devez vous assurer que les noms de chemins absolus se comportent comme des noms de chemins relatifs. Réfléchissez aux deux exemples suivants :

Exemple : Modification d'un fichier

Description

Une entrée est ajoutée à un tableau ou l'objet est un nouveau tableau susceptible d'être modifié par d'autres programmes ou packages.

Implémentation

Définissez l'objet comme ayant le type de fichier e et appartenant à la classe build, awk ou sed. Le script effectuant cette opération doit se supprimer aussi efficacement qu'il s'ajoute.

Exemple

Une entrée doit être ajoutée à /etc/vfstab pour prendre en charge le nouveau disque dur électronique.

L'entrée dans le fichier pkgmap pourrait être :


1 e sed /etc/vfstab ? ? ?

Le script request demande à l'opérateur si /etc/vfstab doit être modifié par le package. Si l'opérateur répond par la négative, le script request imprime les instructions de la procédure manuelle et exécute :


echo "CLASSES=none" >> $1

Si l'opérateur répond par l'affirmative, il exécute :


echo "CLASSES=none sed" >> $1

Ceci active le script d'action de classe qui doit apporter les modifications requises. La classe sed indique que le fichier de package /etc/vfstab est un programme sed qui contient les procédures d'installation et de suppression du fichier du même nom sur le système cible.

Exemple : Création d'un fichier

Description

L'objet est un fichier entièrement nouveau peu susceptible d'être modifié ultérieurement ou un fichier qui en remplace un autre appartenant à un package différent.

Implémentation

Définissez l'objet de package comme ayant le type de fichier f et installez-le à l'aide d'un script d'action de classe capable d'annuler la modification.

Exemple

Un tout nouveau fichier est nécessaire dans /etc afin de fournir les informations requises pour la prise en charge du disque dur électronique, appelé /etc/shdisk.conf . L'entrée dans le fichier pkgmap peut être :


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

Le script d'action de classe i.newetc est chargé d'installer ce fichier ainsi que tout autre fichier devant être placé dans /etc. Il vérifie qu'aucun autre fichier ne s'y trouve. Si le répertoire est vide, il y copie tout simplement le fichier. S'il contient déjà un fichier, il le sauvegarde avant d'installer le nouveau fichier. Le script r.newetc supprime ces fichiers et le cas échéant, rétablit les originaux. Vous trouverez ci-après le fragment clé du script d'installation.

# 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

Notez que ce script utilise la variable d'environnement PKGSAV pour stocker une sauvegarde du fichier à remplacer. Lorsque l'argument ENDOFCLASS est transmis au script, autrement dit lorsque la commande pkgadd informe le script qu'il s'agit des dernières entrées de cette classe, le script archive et compresse les fichiers enregistrés à l'aide d'un programme de compression privé stocké dans le répertoire d'installation du package.

Bien que l'utilisation de la variable d'environnement PKGSAV ne soit pas fiable pendant la mise à jour d'un package, si le package n'est pas mis à jour (à l'aide d'un patch par exemple), le fichier de sauvegarde est sécurisé. Le script de suppression suivant inclut un code permettant de résoudre le deuxième problème, à savoir, le fait que dans les anciennes versions, la commande pkgrm ne transmet pas aux scripts le bon chemin d'accès à la variable d'environnement PKGSAV .

Le script de suppression peut être comme suit :

# 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

Ce script utilise un algorithme de désinstallation privé (unsquish) situé dans le répertoire d'installation de la base de données des packages. Ceci est automatiquement effectué par la commande pkgadd lors de la phase d'installation. Tous les scripts non spécifiquement reconnus comme ayant l'attribut d'installation seule par la commande pkgadd sont stockés dans ce répertoire afin d'être utilisés par la commande pkgrm. Vous ne pouvez pas compter sur l'emplacement de ce répertoire mais vous pouvez être sûr qu'il est plat et qu'il contient toutes les informations et scripts d'installation appropriés du package. Ce script trouve le répertoire en raison du fait que le script d'action de classe s'exécute systématiquement à partir du répertoire contenant le programme unsquish.

Notez également que ce script ne suppose pas simplement que le répertoire cible est /etc. Il peut en fait s'agir de /export/root/client2/etc . Le répertoire approprié peut être créé de deux façons.

L'utilisation de cette approche pour chaque objet absolu du package vous assure que le comportement actuel souhaité reste inchangé ou qu'il est au moins récupérable.

Exemple : Package composite

L'exemple suivant illustre les fichiers pkginfo et pkgmap d'un package composite.

Fichier pkginfo

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

Fichier pkgmap

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

Alors que S70dostuf appartient à la classe daemon, les répertoires qui y accèdent (déjà en place lors de la phase d'installation) appartiennent eux à la classe none. Même si les répertoires étaient uniques à ce package, vous devriez les laisser dans la classe none. Ceci, parce que les répertoires doivent être créés en premier et supprimés en dernier, ce qui est toujours vrai de la classe none. La commande pkgadd crée des répertoires qui ne sont ni copiés à partir du package, ni transmis à un script d'action de classe afin d'être créés. Ils sont par contre créés par la commande pkgadd avant qu'elle n'appelle le script d'action de classe ; la commande pkgrm par ailleurs supprime les répertoires une fois le script d'action de classe de suppression terminé.

De ce fait, lorsqu'un répertoire d'une classe spéciale contient des objets de la classe none, la tentative de suppression du répertoire par la commande pkgrm échoue car le répertoire n'est pas vidé à temps. Si un objet de la classe none doit être inséré dans un répertoire d'une classe spéciale, le répertoire en question n'est pas créé à temps pour recevoir l'objet. La commande pkgadd crée le répertoire à la volée au cours de l'installation de l'objet et ne parvient parfois pas à synchroniser les attributs de ce répertoire lorsqu'elle trouve la définition pkgmap.


Remarque –

Lorsque vous attribuez un répertoire à une classe, pensez toujours à l'ordre de création et de suppression.


Création de packages pouvant être installés à distance

Tous les packages doivent pouvoir être installés à distance. Pouvoir être installé à distance signifie que vous ne pouvez pas présumer que l'administrateur va installer votre package sur le système de fichiers racine (/) du système exécutant la commande pkgadd. Pour accéder au fichier /etc/vfstab du système cible dans l'un de vos scripts de procédure, la variable d'environnement PKG_INSTALL_ROOT doit être utilisée. En d'autres termes, le nom de chemin /etc/vfstab vous permet d'accéder au fichier /etc/vfstab du système exécutant la commande pkgadd, mais l'administrateur peut effectuer l'installation sur un client dans /export/root/client3. Le chemin ${PKG_INSTALL_ROOT}/etc/vfstab vous garantit l'accès au système de fichiers cible.

Exemple : Installation sur un système client

Dans cet exemple, le package SUNWstuf est installé dans client3, qui est configuré avec /opt dans son système de fichiers racine (/). Une autre version de ce package est déjà installée dans client3 et le répertoire de base est défini sur basedir=/opt/$PKGINST à partir d'un fichier d'administration (thisadmin). Pour plus d'informations sur les fichiers d'administration, reportez-vous à Fichier de valeurs d'administration par défaut. La commande pkgadd exécutée sur le serveur est :


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

Le tableau suivant répertorie les variables d'environnement et les valeurs transmises aux scripts de procédure :

Tableau 6–1 Valeurs transmises aux scripts de procédure

Variable d'environnement 

Valeur 

PKGINST

SUNWstuf.2

PKG_INSTALL_ROOT

/export/root/client3

CLIENT_BASEDIR

/opt/SUNWstuf.2

BASEDIR

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

Exemple : Installation sur un serveur ou un système autonome

Pour effectuer l'installation sur le serveur ou un système autonome dans les mêmes circonstances que l'exemple précédent, la commande est la suivante :


# pkgadd -a thisadmin SUNWstuf

Le tableau suivant répertorie les variables d'environnement et les valeurs transmises aux scripts de procédure :

Tableau 6–2 Valeurs transmises aux scripts de procédure

Variable d'environnement 

Valeur 

PKGINST

SUNWstuf.2

PKG_INSTALL_ROOT

Non définie. 

CLIENT_BASEDIR

/opt/SUNWstuf.2

BASEDIR

/opt/SUNWstuf.2

Exemple : Montage de systèmes de fichiers partagés

Supposons que le package SUNWstuf crée et partage un système de fichiers sur le serveur dans /export/SUNWstuf/share. Lorsque le package est installé sur les systèmes client, leurs fichiers /etc/vfstab doivent être mis à jour pour monter ce système de fichiers partagé. Cette situation est un exemple d'application de la variable CLIENT_BASEDIR.

L'entrée sur le client doit présenter le point de montage en référence au système de fichiers du client. Cette ligne doit être créée correctement, que l'installation s'effectue à partir du serveur ou du client. Supposons que le nom du système du serveur soit $SERVER. Vous pouvez accéder à $PKG_INSTALL_ROOT/etc/vfstab puis, à l'aide de la commande sed ou de la commande awk, créer la ligne suivante pour le fichier /etc/vfstab du client.


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

Par exemple, pour le serveur universe et le système client client9, la ligne figurant dans le fichier /etc/vfstab du système client serait :


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

Lorsque ces paramètres sont utilisés correctement, l'entrée monte toujours le système de fichiers du client, qu'il soit créé localement ou à partir du serveur.

Application de patchs à des packages

Un patch n'est en fait qu'un package creux conçu pour remplacer certains fichiers dans le package d'origine. La seule raison de livrer un package creux est de faire des économies d'espace sur le support de livraison. Vous pouvez aussi livrer le package d'origine dans son intégralité, avec certains fichiers modifiés, ou fournir l'accès au package modifié sur le réseau. Tant que seuls ces nouveaux fichiers sont différents (les autres fichiers n'ont pas été recompilés), la commande pkgadd installe les différences. Consultez les instructions suivantes concernant l'application de patchs à des packages.

Il est essentiel que le numéro de version du package du patch soit identique à celui du package d'origine. Vous devez conserver une trace de l'état du patch du package via une entrée dans le fichier pkginfo du type :


PATCH=patch_number

Lorsque vous modifiez la version du package pour un patch, vous créez en fait une autre instance du package et il devient dès lors extrêmement compliqué de gérer le produit auquel les patchs ont été appliqués. Cette méthode d'application de patchs par instance progressive comporte certains avantages pour les premières versions du système d'exploitation Solaris mais elle rend la gestion de systèmes plus complexes fastidieuse.

Tous les paramètres de zone du patch doivent correspondre aux paramètres de zone du package.

En ce qui concerne les packages formant l'environnement d'exploitation Solaris, une seule copie du package doit figurer dans la base de données des packages, bien qu'il puisse y avoir plusieurs instances auxquelles des patchs ont été appliqués. Afin de supprimer un objet d'un package installé (à l'aide de la commande removef), vous devez déterminer à quelles instances appartient le fichier.

Toutefois, si votre package (non fourni dans le cadre du système d'exploitation Solaris) doit déterminer le niveau de patch d'un package donné fourni dans le cadre du système d'exploitation Solaris, cela pose un problème qui doit être résolu ici. Les scripts d'installation peuvent être assez volumineux sans pour autant avoir un impact significatif puisqu'ils sont stockés sur le système de fichiers cible. Grâce à l'utilisation de scripts d'action de classe et de divers autres scripts de procédure, vous pouvez enregistrer les fichiers modifiés avec la variable d'environnement PKGSAV (ou dans un autre répertoire plus permanent) afin de pouvoir, le cas échéant, désinstaller les patchs. Vous pouvez également surveiller l'historique des patchs en définissant les variables d'environnement appropriées via des scripts request. Les scripts des sections suivantes présument l'existence de plusieurs patchs dont la numérotation a un sens lorsqu'ils sont appliqués à un même package. Dans ce cas, les numéros de patch individuels représentent un sous-groupe de fichiers de fonctionnalités associés au sein du package. Deux numéros de patch différents ne peuvent pas modifier un même fichier.

Afin de transformer un package creux standard en package de patch, les scripts décrits dans les sections suivantes peuvent tout simplement être intégrés au package. Tous sont reconnus en tant que composants de package standard à l'exception des deux derniers, patch_checkinstall et patch_postinstall. Ces deux scripts peuvent être incorporés au package de désinstallation si vous souhaitez inclure la fonction de désinstallation du patch. Les scripts sont relativement simples et les opérations qu'ils effectuent faciles à comprendre.


Remarque –

Cette méthode d'application de patchs peut être utilisée pour appliquer des patchs aux systèmes client ; toutefois, les répertoires racine des clients disponibles sur le serveur doivent disposer des droits appropriés pour autoriser la lecture par l'utilisateur install ou nobody.


Script checkinstall

Le script checkinstall vérifie que le patch concerne bien le package en question. Une fois qu'il en a la confirmation, il crée la liste de patchs et la liste d'informations sur les patchs, puis les insère dans le fichier réponse à incorporer dans la base de données des packages.

La liste de patchs contient tous les patchs qui ont été appliqués au package actuel. Cette liste de patchs est enregistrée sur une ligne du fichier pkginfo du package installé, comme suit :

PATCHLIST=patch_id patch_id ...

La liste d'informations sur les patchs contient le nom des patchs desquels dépendent le patch actuel. Cette liste de patchs est également enregistrée sur une ligne du fichier pkginfo, comme suit :

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

Remarque –

Ces lignes (et leur format) sont déclarées en tant qu'interface publique. Toute société fournissant des patchs destinés aux packages Solaris doit mettre cette liste à jour en conséquence. Lorsqu'un patch est fourni, chaque package présent dans le patch contient un script checkinstall qui effectue cette opération. Ce même script checkinstall met également à jour d'autres paramètres spécifiques au patch. Il s'agit d'une nouvelle architecture de patchs appelée « application de patch d'instance directe » (Direct Instance Patching).


Dans cet exemple, les packages d'origine et leurs patchs se trouvent dans le même répertoire. Les deux packages d'origine se nomment SUNWstuf.v1 et SUNWstuf.v2, et leurs patchs, SUNWstuf.p1 et SUNWstuf.p2. Pour cette raison, un script de procédure pourrait avoir des difficultés à déterminer de quel répertoire proviennent ces fichiers, puisque toutes les informations concernant le nom du package placées après le point (« . ») sont coupées pour le paramètre PKG, et la variable d'environnement PKGINST se réfère à l'instance installée et non pas à l' instance source. Les scripts de procédure peuvent donc déterminer le répertoire source, le script checkinstall (qui est toujours exécuté à partir du répertoire source) lance la requête et transmet l'emplacement sous forme de variable SCRIPTS_DIR. Si le répertoire source ne contenait qu'un seul package appelé SUNWstuf, les scripts de procédure auraient pu le trouver à l'aide de $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

Script preinstall

Le script preinstall initialise le fichier prototype, les fichiers d'information et les scripts d'installation du package de désinstallation à créer. Ce script est très simple et les autres scripts de cet exemple ne permettent au package de désinstallation que de décrire les fichiers standard.

Pour rétablir les liens symboliques, les liens physiques, les périphériques et les canaux nommés d'un package de désinstallation, vous pouvez modifier le script preinstall afin d'utiliser la commande pkgproto pour comparer le fichier pkgmap fourni aux fichiers installés, puis créer une entrée de fichier prototype pour chaque élément autre qu'un fichier à modifier dans le package de désinstallation. La méthode à utiliser est similaire à la méthode employée dans le script d'action de classe.

Les scripts patch_checkinstall et patch_postinstall sont insérés dans l'arborescence source du package à partir du script preinstall. Ces deux scripts annulent les opérations effectuées par le patch.

# 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

Script d'action de classe

Le script d'action de classe crée une copie de chaque fichier de remplacement et ajoute une ligne correspondante dans le fichier prototype pour le package de désinstallation. Ces opérations sont effectuées à l'aide de scripts nawk relativement simples. Le script d'action de classe reçoit une liste de paires source/destination comprenant des fichiers ordinaires qui ne correspondent pas aux fichiers installés. Les liens symboliques et éléments autres que des fichiers doivent être traités dans le script 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

Script postinstall

Le script postinstall crée le package de désinstallation à partir des informations fournies par les autres scripts. Étant donné que les commandes pkgmk et pkgtrans n'ont pas besoin de la base de données des packages, elles peuvent être exécutées au sein de l'installation du package.

Dans l'exemple, la désinstallation du patch peut être effectuée en créant un package au format flux de données dans le répertoire d'enregistrement (à l'aide de la variable d'environnementPKGSAV). Ceci n'est pas évident mais le package doit être au format flux de données parce que le répertoire d'enregistrement est déplacé pendant une opération pkgadd. Si la commande pkgadd est appliquée à un package dans son propre répertoire d'enregistrement, l'emplacement supposé de la source du package à un moment donné s'avère très peu fiable. Un package au format flux de données est placé dans un répertoire temporaire et installé à partir de celui-ci. (Un package au format répertoire commencerait l'installation à partir du répertoire d'enregistrement et serait soudainement déplacé au cours d'une opération pkgadd à sécurité intégrée.)

Pour déterminer quels patchs sont appliqués à un a package, utilisez la commande suivante :


$ pkgparam SUNWstuf PATCHLIST

À l'exception de PATCHLIST, qui est une interface publique Sun, les noms de paramètre de cet exemple ne contiennent rien de significatif. PATCH peut être remplacé par la liste traditionnelle SUNW_PATCHID et les diverses autres listes telles que PATCH_EXCL et PATCH_REQD peuvent être renommées en conséquence.

Si certains packages de patchs dépendent d'autres packages de patchs se trouvant sur le même support, le script checkinstall peut le déterminer et créer un script à exécuter par le script postinstall comme dans l'exemple de mise à niveau (reportez-vous à Mise à niveau des packages).

# 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

Script patch_checkinstall

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

Script patch_postinstall

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

Mise à niveau des packages

La procédure de mise à niveau d'un package est très différente de la procédure de remplacement d'un package. Bien qu'il existe des outils particuliers prenant en charge la mise à niveau des packages standard fournis dans le cadre du système d'exploitation Solaris, un package non fourni en standard peut être conçu pour prendre en charge sa propre mise à niveau ; plusieurs des exemples précédents décrivent des packages qui prévoient et contrôlent minutieusement la méthode d'installation sous la direction de l'administrateur. Vous pouvez concevoir le script request pour qu'il prenne aussi en charge la mise à niveau directe d'un package. Si l'administrateur décide d'installer un package en remplacement intégral d'un autre package, ne laissant aucun fichier obsolète, les scripts du package peuvent se charger de l'opération.

Le script request et le script postinstall de cet exemple fournissent un package simple pouvant être mis à niveau. Le script request communique avec l'administrateur et définit ensuite un fichier simple dans le répertoire /tmp pour supprimer l'ancienne instance du package. Bien que le script request crée un fichier (ce qui est interdit), l'opération est passée outre car tous les utilisateurs ont accès au fichier /tmp.

Le script postinstall exécute ensuite le script shell dans /tmp, lequel exécute la commande pkgrm requise sur l'ancien package avant de s'auto-supprimer.

Cet exemple illustre une mise à niveau de base. Il se compose de moins de cinquante lignes de code et contient d'assez longs messages. Il pourrait être étendu afin de désinstaller la mise à niveau ou d'apporter d'autres transformations majeures au package en fonction des besoins du concepteur.

Le concepteur de l'interface utilisateur d'une option de mise à niveau doit être certain que l'administrateur connaît la procédure et qu'il a expressément demander une mise à niveau plutôt qu'une installation en parallèle. La réalisation d'une opération complexe bien comprise telle qu'une mise à niveau est tout à fait acceptable tant que l'interface utilisateur clarifie l'opération.

Script request

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

Script postinstall

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

Création de packages d'archives de classe

Un package d'archive de classe, qui est une amélioration par rapport à l'ABI (Application Binary Interface), est un package dans lequel certains fichiers ont été regroupés en un seul fichier (ou archive) puis compressés ou chiffrés. Les formats d'archive de classe augmentent la vitesse initiale d'installation de 30 % et améliorent la fiabilité de la procédure d'installation des packages et des patchs sur des systèmes de fichiers potentiellement actifs.

Les sections suivantes fournissent des informations sur la structure du répertoire d'un package d'archive, les mots clés et l'utilitaire faspac.

Structure du répertoire d'un package d'archive

L'entrée du package illustrée sur la figure suivante représente le répertoire contenant les fichiers du package. Ce répertoire doit porter le même nom que le package.

Figure 6–1 Structure du répertoire d'un package

Le diagramme suivant représente cinq sous-répertoires directement placés sous le répertoire du package : pkginfo, pkgmap, reloc, root et install. Il indique également leurs propres sous-répertoires.

Le tableau suivant répertorie les fonctions des fichiers et répertoires contenus dans le répertoire du package.

Élément 

Description 

pkginfo

Fichier décrivant le package dans son ensemble, y compris les variables spéciales d'environnement et la procédure d'installation. 

pkgmap

Fichier décrivant chaque objet à installer, tel qu'un fichier, un répertoire ou un tube. 

reloc

Répertoire facultatif contenant les fichiers à installer par rapport au répertoire de base (objets réadressables). 

racine

Répertoire facultatif contenant les fichiers à installer par rapport au répertoire root (objets racine).

install

Répertoire facultatif contenant les scripts et autres fichiers auxiliaires (à l'exception de pkginfo et de pkgmap, tous les fichiers ftype i sont inclus).

Le format d'archive de classe permet au développeur du package de regrouper des fichiers provenant des répertoires reloc et root dans des archives qui peuvent être compressées, chiffrées ou autrement traitées afin d'accélérer l'installation, de réduire la taille du package ou de renforcer la sécurité du package.

L'ABI permet à tout fichier d'un package d'être attribué à une classe. Tous les fichiers d'une classe donnée peuvent être installés sur le disque à l'aide d'une méthode personnalisée définie par un script d'action de classe. Cette méthode personnalisée peut faire appel à des programmes installés sur le système cible ou à des programmes fournis avec le package. Le format résultant ressemble de près au format ABI standard. Comme l'illustre la figure suivante, un autre répertoire est ajouté. Toute classe de fichiers destinée à l'archivage est tout simplement convertie en un seul fichier et placée dans le répertoire archive. Tous les fichiers archivés sont supprimés des répertoires reloc et root, et un script d'action de classe d'installation est placé dans le répertoire install.

Figure 6–2 Structure du répertoire d'un package d'archive

Le diagramme représente la même structure de répertoire d'un package que celle de la Figure 6-1, à laquelle a été ajouté le sous-répertoire archive.

Mots clés de prise en charge des packages d'archive de classe

Pour prendre en charge ce nouveau format d'archive de classe, trois nouvelles interfaces représentées par des mots clés ont une signification particulière dans le fichier pkginfo. Ces mots clés sont utilisés pour désigner les classes requérant un traitement particulier. Le format de la déclaration de chaque mot clé est le suivant : keyword=class1[class2 class3 ...]. Chaque valeur de mot clé est définie dans le tableau suivant :

Mot-clé 

Description 

PKG_SRC_NOVERIFY

Ce mot clé indique à pkgadd de ne pas vérifier l'existence ni les propriétés des fichiers figurant dans les répertoires reloc ou root du package fourni s'ils appartiennent à une classe nommée. Il est obligatoire pour toutes les classes archivées car ces fichiers ne se trouvent plus dans un répertoire reloc ni un répertoire root. Il s'agit de fichiers au format privé stockés dans le répertoire archive.

PKG_DST_QKVERIFY

Les fichiers appartenant à ces classes sont vérifiés après l'installation à l'aide d'un algorithme rapide ne nécessitant pas ou peu de données. Cette vérification rapide définit en premier lieu les attributs de chaque fichier puis vérifie que l'opération s'est déroulée correctement. Un test est ensuite effectué pour comparer la taille du fichier et le temps de modification au fichier pkgmap. Aucune somme de contrôle n'est effectuée et la reprise sur erreur est moins efficace que celle offerte par le mécanisme de vérification standard. Dans l'éventualité d'une coupure de courant ou d'une défaillance du disque pendant l'installation, le fichier contenu risque de ne pas concorder avec les fichiers installés. Cette incohérence peut toujours être résolue avec pkgrm.

PKG_CAS_PASSRELATIVE

Le script d'action de classe de l'installation reçoit en général de la part du fichier stdin une liste de paires source/destination lui indiquant quels fichiers installer. Les classes attribuées à PKG_CAS_PASSRELATIVE ne reçoivent pas ces paires source/destination. Elles reçoivent à la place une seule liste dont la première entrée correspond à l'emplacement du package source et les autres correspondent aux chemins de destination. Ceci sert spécifiquement à simplifier l'extraction d'une archive. À partir de l'emplacement du package source, vous pouvez trouver l'archive dans le répertoire archive. Les chemins de destination sont ensuite transmis à la fonction chargée d'extraire le contenu de l'archive. Chaque chemin de destination fourni est absolu ou relatif au répertoire de base selon que son emplacement d'origine se trouve dans root ou dans reloc. Lorsque cette option est sélectionnée, il peut être difficile d'utiliser des chemins relatifs et des chemins absolus dans une même classe.

Un script d'action de classe est nécessaire pour chaque classe archivée. Il s'agit d'un fichier contenant des commandes Bourne shell qui est exécuté par pkgadd pour installer les fichiers à partir de l'archive. Si un script d'action de classe est détecté dans le répertoire install du package, pkgadd délègue toute la responsabilité de l'installation au script. Le script d'action de classe est exécuté avec les droits d'accès à root et peut placer ses fichiers à tout endroit du système cible.


Remarque –

Le seul mot clé essentiel à l'implémentation d'un package d'archive de classe est PKG_SRC_NOVERIFY. Les autres peuvent être utilisés pour accélérer l'installation ou conserver le code.


Utilitaire faspac

L'utilitaire faspac convertit un package ABI standard en format d'archive de classe utilisé pour les packages fournis en standard. Cet utilitaire archive des fichiers à l'aide de cpio et compresse à l'aide de compress. Le package obtenu dispose d'un répertoire supplémentaire qui est stocké dans le répertoire supérieur archive. Ce répertoire doit contenir toutes les archives nommées par classe. Le répertoire install doit contenir les scripts d'action de classe nécessaires à la décompression de chaque archive. Les chemins absolus ne sont pas archivés.

L'utilitaire faspac a le format suivant :


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

Toutes les options de la commande faspac sont décrites dans le tableau suivant :

Option 

Description 

-m Méthode d'archivage

 

Spécifie une méthode d'archivage ou de compression. bzip2 est l'utilitaire de compression utilisé par défaut. Pour utiliser à la place la méthode zip/unzip, utilisez -m zip ou pour utiliser la méthode cpio/compress, utilisez -m cpio.

-a

Corrige les attributs (seul l'utilisateur root peut effectuer cette opération). 

-s

Indique la conversion des packages de type ABI standard. Cette option convertit un package cpio ou compressé en package conforme ABI standard. 

-q

Spécifie le mode silencieux. 

-d Répertoire de base

Indique le répertoire contenant tous les packages concernés par l'opération de la ligne de commande. Cette option et l'entrée Liste de packages s'excluent mutuellement.

-x Liste d'exclusions

Spécifie une liste de packages, séparés par des virgules ou entre guillemets, à exclure de l'opération. 

Liste de packages

Spécifie la liste des packages à traiter.