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 :
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.
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 :
ask, qui signifie que le répertoire de base doit toujours être demandé à l'administrateur ;
un nom de chemin absolu ;
un nom de chemin absolu contenant $PKGINST, qui signifie que l'installation doit toujours être effectuée dans un répertoire de base généré à partir de l'instance du package.
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.
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.
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.
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 |
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 :
Un package contenant des noms de chemin paramétriques se comporte généralement comme un package absolu mais est traité par la commande pkgadd comme un package réadressable. Le paramètre BASEDIR doit être défini même s'il n'est pas utilisé.
L'administrateur ne peut pas déterminer la base d'installation du package avec les utilitaires du System V (la commande pkginfo -r ne fonctionne pas).
L'administrateur ne peut pas se servir de la méthode établie pour réadresser le package (il est qualifié d'adressable mais se comporte comme un package absolu).
L'installation de plusieurs architectures ou de plusieurs versions nécessite de prévoir des plans d'urgence pour chacun des répertoires de base cible, ce qui se traduit souvent par l'utilisation de scripts d'action de classe complexes.
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.
# pkginfo file PKG=SUNWstuf NAME=software stuff ARCH=sparc VERSION=1.0.0,REV=1.0.5 CATEGORY=application DESC=a set of utilities that do stuff BASEDIR=/ EZDIR=/usr/stuf/EZstuf HRDDIR=/opt/SUNWstuf/HRDstuf VENDOR=Sun Microsystems, Inc. HOTLINE=Please contact your local service provider EMAIL= MAXINST=1000 CLASSES=none PSTAMP=hubert980707141632 |
: 1 1758 1 d none $EZDIR 0775 root bin 1 f none $EZDIR/dirdel 0555 bin bin 40 773 751310229 1 f none $EZDIR/usrdel 0555 bin bin 40 773 751310229 1 f none $EZDIR/filedel 0555 bin bin 40 773 751310229 1 d none $HRDDIR 0775 root bin 1 f none $HRDDIR/mksmart 0555 bin bin 40 773 751310229 1 f none $HRDDIR/mktall 0555 bin bin 40 773 751310229 1 f none $HRDDIR/mkcute 0555 bin bin 40 773 751310229 1 f none $HRDDIR/mkeasy 0555 bin bin 40 773 751310229 1 d none /etc ? ? ? 1 d none /etc/rc2.d ? ? ? 1 f none /etc/rc2.d/S70dostuf 0744 root sys 450 223443 1 i pkginfo 348 28411 760740163 1 i postinstall 323 26475 751309908 1 i postremove 402 33179 751309945 1 i preinstall 321 26254 751310019 1 i preremove 320 26114 751309865 |
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.
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.
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.
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 :
# pkginfo file PKG=SUNWstuf NAME=software stuff ARCH=sparc VERSION=1.0.0,REV=1.0.5 CATEGORY=application DESC=a set of utilities that do stuff BASEDIR=/opt/SUNWstuf VENDOR=Sun Microsystems, Inc. HOTLINE=Please contact your local service provider EMAIL= MAXINST=1000 CLASSES=none daemon PSTAMP=hubert990707141632 |
: 1 1758 1 d none EZstuf 0775 root bin 1 f none EZstuf/dirdel 0555 bin bin 40 773 751310229 1 f none EZstuf/usrdel 0555 bin bin 40 773 751310229 1 f none EZstuf/filedel 0555 bin bin 40 773 751310229 1 d none HRDstuf 0775 root bin 1 f none HRDstuf/mksmart 0555 bin bin 40 773 751310229 1 f none HRDstuf/mktall 0555 bin bin 40 773 751310229 1 f none HRDstuf/mkcute 0555 bin bin 40 773 751310229 1 f none HRDstuf/mkeasy 0555 bin bin 40 773 751310229 1 d none /etc ? ? ? 1 d none /etc/rc2.d ? ? ? 1 f daemon /etc/rc2.d/S70dostuf 0744 root sys 450 223443 1 i pkginfo 348 28411 760740163 1 i postinstall 323 26475 751309908 1 i postremove 402 33179 751309945 1 i preinstall 321 26254 751310019 1 i preremove 320 26114 751309865 1 i i.daemon 509 39560 752978103 1 i r.daemon 320 24573 742152591 |
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.
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 :
# request script for SUNWstuf to walk the BASEDIR parameter. PATH=/usr/sadm/bin:${PATH} # use admin utilities GENMSG="The base directory $LOCAL_BASE already contains a \ different architecture or version of $PKG." OLDMSG="If the option \"-a none\" was used, press the \ key and enter an unused base directory when it is requested." OLDPROMPT="Do you want to overwrite this version? " OLDHELP="\"y\" will replace the installed package, \"n\" will \ stop the installation." SUSPEND="Suspending installation at user request using error \ code 1." MSG="This package could be installed at the unused base directory $WRKNG_BASE." PROMPT="Do you want to use to the proposed base directory? " HELP="A response of \"y\" will install to the proposed directory and continue, \"n\" will request a different directory. If the option \"-a none\" was used, press the key and enter an unused base directory when it is requested." DIRPROMPT="Select a preferred base directory ($WRKNG_BASE) " DIRHELP="The package $PKG will be installed at the location entered." NUBD_MSG="The base directory has changed. Be sure to update \ any applicable search paths with the actual location of the \ binaries which are at $WRKNG_BASE/EZstuf and $WRKNG_BASE/HRDstuf." OldSolaris="" Changed="" Suffix="0" # # Determine if this product is actually installed in the working # base directory. # Product_is_present () { if [ -d $WRKNG_BASE/EZstuf -o -d $WRKNG_BASE/HRDstuf ]; then return 1 else return 0 fi } if [ ${BASEDIR} ]; then # This may be an old version of Solaris. In the latest Solaris # CLIENT_BASEDIR won't be defined yet. In older version it is. if [ ${CLIENT_BASEDIR} ]; then LOCAL_BASE=$BASEDIR OldSolaris="true" else # The base directory hasn't been processed yet LOCAL_BASE=${PKG_INSTALL_ROOT}$BASEDIR fi WRKNG_BASE=$LOCAL_BASE # See if the base directory is already in place and walk it if # possible while [ -d ${WRKNG_BASE} -a Product_is_present ]; do # There is a conflict # Is this an update of the same arch & version? if [ ${UPDATE} ]; then exit 0 # It's out of our hands. else # So this is a different architecture or # version than what is already there. # Walk the base directory Suffix=`expr $Suffix + 1` WRKNG_BASE=$LOCAL_BASE.$Suffix Changed="true" fi done # So now we can propose a base directory that isn't claimed by # any of our other versions. if [ $Changed ]; then puttext "$GENMSG" if [ $OldSolaris ]; then puttext "$OLDMSG" result=`ckyorn -Q -d "a" -h "$OLDHELP" -p "$OLDPROMPT"` if [ $result="n" ]; then puttext "$SUSPEND" exit 1 # suspend installation else exit 0 fi else # The latest functionality is available puttext "$MSG" result=`ckyorn -Q -d "a" -h "$HELP" -p "$PROMPT"` if [ $? -eq 3]; then echo quitinstall >> $1 exit 0 fi if [ $result="n" ]; then WRKNG_BASE=`ckpath -ayw -d "$WRKNG_BASE" \ -h "$DIRHELP" -p "$DIRPROMPT"` else if [ $result="a" ] exit 0 fi fi echo "BASEDIR=$WRKNG_BASE" >> $1 puttext "$NUBD_MSG" fi fi exit 0 |
# checkinstall script for SUNWstuf to politely suspend grep quitinstall $1 if [ $? -eq 0 ]; then exit 3 # politely suspend installation fi exit 0 |
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.
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 :
# pkginfo file PKG=SUNWstuf NAME=software stuff ARCH=sparc VERSION=1.0.0,REV=1.0.5 CATEGORY=application DESC=a set of utilities that do stuff BASEDIR=/opt SUBBASE=SUNWstuf VENDOR=Sun Microsystems, Inc. HOTLINE=Please contact your local service provider EMAIL= MAXINST=1000 CLASSES=none daemon PSTAMP=hubert990707141632 |
: 1 1758 1 d none $SUBBASE/EZstuf 0775 root bin 1 f none $SUBBASE/EZstuf/dirdel 0555 bin bin 40 773 751310229 1 f none $SUBBASE/EZstuf/usrdel 0555 bin bin 40 773 751310229 1 f none $SUBBASE/EZstuf/filedel 0555 bin bin 40 773 751310229 1 d none $SUBBASE/HRDstuf 0775 root bin 1 f none $SUBBASE/HRDstuf/mksmart 0555 bin bin 40 773 751310229 1 f none $SUBBASE/HRDstuf/mktall 0555 bin bin 40 773 751310229 1 f none $SUBBASE/HRDstuf/mkcute 0555 bin bin 40 773 751310229 1 f none $SUBBASE/HRDstuf/mkeasy 0555 bin bin 40 773 751310229 1 d none /etc ? ? ? 1 d none /etc/rc2.d ? ? ? 1 f daemon /etc/rc2.d/S70dostuf 0744 root sys 450 223443 1 i pkginfo 348 28411 760740163 1 i postinstall 323 26475 751309908 1 i postremove 402 33179 751309945 1 i preinstall 321 26254 751310019 1 i preremove 320 26114 751309865 1 i i.daemon 509 39560 752978103 1 i r.daemon 320 24573 742152591 |
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.
# 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 |
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.
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.
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 :
# pkginfo file PKG=SUNWstuf NAME=software stuff ARCH=sparc VERSION=1.0.0,REV=1.0.5 CATEGORY=application DESC=a set of utilities that do stuff BASEDIR=/opt VENDOR=Sun Microsystems, Inc. HOTLINE=Please contact your local service provider EMAIL= MAXINST=1000 CLASSES=none PSTAMP=hubert990707141632 |
: 1 1758 1 d none SUNWstuf 0775 root bin 1 d none SUNWstuf/EZstuf 0775 root bin 1 f none SUNWstuf/EZstuf/dirdel 0555 bin bin 40 773 751310229 1 f none SUNWstuf/EZstuf/usrdel 0555 bin bin 40 773 751310229 1 f none SUNWstuf/EZstuf/filedel 0555 bin bin 40 773 751310229 1 d none SUNWstuf/HRDstuf 0775 root bin 1 f none SUNWstuf/HRDstuf/mksmart 0555 bin bin 40 773 751310229 1 f none SUNWstuf/HRDstuf/mktall 0555 bin bin 40 773 751310229 1 f none SUNWstuf/HRDstuf/mkcute 0555 bin bin 40 773 751310229 1 f none SUNWstuf/HRDstuf/mkeasy 0555 bin bin 40 773 751310229 1 i pkginfo 348 28411 760740163 1 i postinstall 323 26475 751309908 1 i postremove 402 33179 751309945 1 i preinstall 321 26254 751310019 1 i preremove 320 26114 751309865 |
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.
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.
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 :
: 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.
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.
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 :
# pkginfo file PKG=SUNWstuf NAME=software stuff ARCH=sparc VERSION=1.0.0,REV=1.0.5 CATEGORY=application DESC=a set of utilities that do stuff BASEDIR=/ VENDOR=Sun Microsystems, Inc. HOTLINE=Please contact your local service provider EMAIL= MAXINST=1000 CLASSES=none PSTAMP=hubert990707141632 |
: 1 1758 1 d none opt/SUNWstuf/EZstuf 0775 root bin 1 f none opt/SUNWstuf/EZstuf/dirdel 0555 bin bin 40 773 751310229 1 f none opt/SUNWstuf/EZstuf/usrdel 0555 bin bin 40 773 751310229 1 f none opt/SUNWstuf/EZstuf/filedel 0555 bin bin 40 773 751310229 1 d none opt/SUNWstuf/HRDstuf 0775 root bin 1 f none opt/SUNWstuf/HRDstuf/mksmart 0555 bin bin 40 773 751310229 1 f none opt/SUNWstuf/HRDstuf/mktall 0555 bin bin 40 773 751310229 1 f none opt/SUNWstuf/HRDstuf/mkcute 0555 bin bin 40 773 751310229 1 f none opt/SUNWstuf/HRDstuf/mkeasy 0555 bin bin 40 773 751310229 1 d none etc ? ? ? 1 d none etc/rc2.d ? ? ? 1 f none etc/rc2.d/S70dostuf 0744 root sys 450 223443 1 i pkginfo 348 28411 760740163 1 i postinstall 323 26475 751309908 1 i postremove 402 33179 751309945 1 i preinstall 321 26254 751310019 1 i preremove 320 26114 751309865 |
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.
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.
Deux règles doivent être appliquées lors de la création d'un package composite fonctionnel :
Établir le répertoire de base en fonction de la destination de la majorité des objets du package.
Lorsqu'un objet de package doit être placé dans un répertoire commun autre que le répertoire de base (par exemple, /etc), le spécifier en tant que nom de chemin absolu dans le fichier prototype.
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.
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 :
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.
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.
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.
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.
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.
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.
utilisez la construction ${PKG_INSTALL_ROOT}/etc, ou
utilisez le nom de répertoire d'un fichier transmis par la commande pkgadd (ce que le script fait).
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.
L'exemple suivant illustre les fichiers pkginfo et pkgmap d'un package composite.
PKG=SUNWstuf NAME=software stuff ARCH=sparc VERSION=1.0.0,REV=1.0.5 CATEGORY=application DESC=a set of utilities that do stuff BASEDIR=/opt VENDOR=Sun Microsystems, Inc. HOTLINE=Please contact your local service provider EMAIL= MAXINST=1000 CLASSES=none daemon PSTAMP=hubert990707141632 |
: 1 1758 1 d none SUNWstuf/EZstuf 0775 root bin 1 f none SUNWstuf/EZstuf/dirdel 0555 bin bin 40 773 751310229 1 f none SUNWstuf/EZstuf/usrdel 0555 bin bin 40 773 751310229 1 f none SUNWstuf/EZstuf/filedel 0555 bin bin 40 773 751310229 1 d none SUNWstuf/HRDstuf 0775 root bin 1 f none SUNWstuf/HRDstuf/mksmart 0555 bin bin 40 773 751310229 1 f none SUNWstuf/HRDstuf/mktall 0555 bin bin 40 773 751310229 1 f none SUNWstuf/HRDstuf/mkcute 0555 bin bin 40 773 751310229 1 f none SUNWstuf/HRDstuf/mkeasy 0555 bin bin 40 773 751310229 1 d none /etc ? ? ? 1 d none /etc/rc2.d ? ? ? 1 e daemon /etc/rc2.d/S70dostuf 0744 root sys 450 223443 1 i i.daemon 509 39560 752978103 1 i pkginfo 348 28411 760740163 1 i postinstall 323 26475 751309908 1 i postremove 402 33179 751309945 1 i preinstall 321 26254 751310019 1 i preremove 320 26114 751309865 1 i r.daemon 320 24573 742152591 |
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.
Lorsque vous attribuez un répertoire à une classe, pensez toujours à l'ordre de création et de suppression.
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.
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 |
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 |
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.
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.
Si le système est très complexe, il est recommandé d'établir un système d'identification des patchs qui empêche que deux patchs remplacent le même fichier lorsqu'ils ont pour objectif de corriger des comportements anormaux distincts. Par exemple, des groupes de fichiers qui s'excluent mutuellement sont attribués aux nombres de base des patchs Sun. Ces groupes de fichiers deviennent leur responsabilité.
Un patch doit pouvoir être désinstallé.
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.
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.
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 |
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 |
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 |
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 |
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 |
# checkinstall script to validate backing out a patch. # directory format option. # # @(#)patch_checkinstall 1.2 95/10/10 SMI # # Copyright (c) 1995 by Sun Microsystems, Inc. # All rights reserved # PATH=/usr/sadm/bin:$PATH LATER_MSG="PaTcH_MsG 6 ERROR: A later version of this patch is applied." NOPATCH_MSG="PaTcH_MsG 2 ERROR: Patch number $ACTIVE_PATCH is not installed" NEW_LIST="" # Get OLDLIST . $1 # # Confirm that the patch that got us here is the latest one installed on # the system and remove it from PATCHLIST. # Is_Inst=0 Skip=0 active_base=`echo $ACTIVE_PATCH | nawk ' { print substr($0, 1, match($0, "Patchvers_pfx")-1) } '` active_inst=`echo $ACTIVE_PATCH | nawk ' { print substr($0, match($0, "Patchvers_pfx")+1) } '` for patchappl in ${OLDLIST}; do appl_base=`echo $patchappl | nawk ' { print substr($0, 1, match($0, "Patchvers_pfx")-1) } '` if [ $appl_base = $active_base ]; then appl_inst=`echo $patchappl | nawk ' { print substr($0, match($0, "Patchvers_pfx")+1) } '` result=`expr $appl_inst \> $active_inst` if [ $result -eq 1 ]; then puttext "$LATER_MSG" exit 3 elif [ $appl_inst = $active_inst ]; then Is_Inst=1 Skip=1 fi fi if [ $Skip = 1 ]; then Skip=0 else NEW_LIST="${NEW_LIST} $patchappl" fi done if [ $Is_Inst = 0 ]; then puttext "$NOPATCH_MSG" exit 3 fi # # OK, all's well. Now condition the key variables. # echo "PATCHLIST=${NEW_LIST}" >> $1 echo "Patch_label=" >> $1 echo "PATCH_INFO_$ACTIVE_PATCH=backed out" >> $1 # Get the current PATCH_OBSOLETES and condition it Old_Obsoletes=$PATCH_OBSOLETES echo $ACTIVE_OBSOLETES | sed 'y/\ /\n/' | \ nawk -v PatchObsList="$Old_Obsoletes" ' BEGIN { printf("PATCH_OBSOLETES="); PatchCount=split(PatchObsList, PatchObsComp, " "); for(PatchIndex in PatchObsComp) { Atisat=match(PatchObsComp[PatchIndex], "@"); PatchObs[PatchIndex]=substr(PatchObsComp[PatchIndex], \ 0, Atisat-1); PatchObsCnt[PatchIndex]=substr(PatchObsComp\ [PatchIndex], Atisat+1); } } { for(PatchIndex in PatchObs) { if (PatchObs[PatchIndex] == $0) { PatchObsCnt[PatchIndex]=PatchObsCnt[PatchIndex]-1; } } next; } END { for(PatchIndex in PatchObs) { if ( PatchObsCnt[PatchIndex] > 0 ) { printf("%s@%d ", PatchObs[PatchIndex], PatchObsCnt\ [PatchIndex]); } } printf("\n"); } ' >> $1 # remove the used parameters echo "ACTIVE_OBSOLETES=" >> $1 echo "Obsoletes_label=" >> $1 exit 0 |
# This script deletes the used backout data for a patch package # and removes the deletes file entries. # # directory format options. # # @(#)patch_postinstall 1.2 96/01/29 SMI # # Copyright (c) 1995 by Sun Microsystems, Inc. # All rights reserved # PATH=/usr/sadm/bin:$PATH THIS_DIR=`dirname $0` Our_Deletes=$THIS_DIR/deletes # # Delete the used backout data # if [ -f $Our_Deletes ]; then cat $Our_Deletes | while read path; do if valpath -l $path; then Client_Path=`echo "$CLIENT_BASEDIR/$path" | sed s@//@/@` else # It's an absolute path Client_Path=$path fi rm `removef $PKGINST $Client_Path` done removef -f $PKGINST rm $Our_Deletes fi # # Remove the deletes file, checkinstall and the postinstall # rm -r $PKGSAV/$ACTIVE_PATCH rm -f $THIS_DIR/checkinstall $THIS_DIR/postinstall exit 0 |
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.
# request script control an upgrade installation PATH=/usr/sadm/bin:$PATH UPGR_SCRIPT=/tmp/upgr.$PKGINST UPGRADE_MSG="Do you want to upgrade the installed version ?" UPGRADE_HLP="If upgrade is desired, the existing version of the \ package will be replaced by this version. If it is not \ desired, this new version will be installed into a different \ base directory and both versions will be usable." UPGRADE_NOTICE="Conflict approval questions may be displayed. The \ listed files are the ones that will be upgraded. Please \ answer \"y\" to these questions if they are presented." pkginfo -v 1.0 -q SUNWstuf.\* if [ $? -eq 0 ]; then # See if upgrade is desired here response=`ckyorn -p "$UPGRADE_MSG" -h "$UPGRADE_HLP"` if [ $response = "y" ]; then OldPkg=`pkginfo -v 1.0 -x SUNWstuf.\* | nawk ' \ /SUNW/{print $1} '` # Initiate upgrade echo "PATH=/usr/sadm/bin:$PATH" > $UPGR_SCRIPT echo "sleep 3" >> $UPGR_SCRIPT echo "echo Now removing old instance of $PKG" >> \ $UPGR_SCRIPT if [ ${PKG_INSTALL_ROOT} ]; then echo "pkgrm -n -R $PKG_INSTALL_ROOT $OldPkg" >> \ $UPGR_SCRIPT else echo "pkgrm -n $OldPkg" >> $UPGR_SCRIPT fi echo "rm $UPGR_SCRIPT" >> $UPGR_SCRIPT echo "exit $?" >> $UPGR_SCRIPT # Get the original package's base directory OldBD=`pkgparam $OldPkg BASEDIR` echo "BASEDIR=$OldBD" > $1 puttext -l 5 "$UPGRADE_NOTICE" else if [ -f $UPGR_SCRIPT ]; then rm -r $UPGR_SCRIPT fi fi fi exit 0 |
# postinstall to execute a simple upgrade PATH=/usr/sadm/bin:$PATH UPGR_SCRIPT=/tmp/upgr.$PKGINST if [ -f $UPGR_SCRIPT ]; then sh $UPGR_SCRIPT & fi exit 0 |
Un 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.
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.
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.
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.
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.
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. |