Guia do Desenvolvedor de Empacotamento de Aplicativos

Capítulo 6 Técnicas avançadas para a criação de pacotes

As capacidades completas de empacotamento System V quando implementadas no sistema operacional Solaris oferecem uma poderosa ferramenta para a instalação de produtos de software. Como um criador de pacotes, você pode tirar vantagem dessas capacidades. Os pacotes que não fazem parte do sistema operacional Solaris (pacotes não incorporados) podem usar o mecanismo de classe para personalizar as instalações de servidor/cliente. Os pacotes relocáveis podem ser criados para satisfazer os desejos do administrador. Um produto complexo pode ser entregue como um conjunto de pacotes compostos que resolve automaticamente as dependências de pacote. As atualizações e patches podem ser personalizados pelo criador do pacote. Os pacotes com patch podem ser entregues da mesma forma que os pacotes sem patch, e os arquivos de backout também podem ser incluídos no produto.

A lista abaixo traz as informações gerais encontradas neste capítulo.

Especificando o diretório base

Você pode usar vários métodos para especificar onde um pacote será instalado e é importante poder alterar a base de instalação dinamicamente no tempo de instalação. Se isto for atingido satisfatoriamente, um administrador pode instalar várias versões e várias arquiteturas se complicações.

Esta seção trata primeiro dos métodos comuns, depois das abordagens que melhoram as instalações em sistemas heterogêneos.

O arquivo de padrões administrativos

Os administradores responsáveis pela instalação de pacotes podem usar arquivos de administração para controlar a instalação do pacote. No entanto, como criador de pacotes, você precisa conhecer os arquivos de administração e saber como um administrador pode alterar a instalação pretendida do pacote.

Um arquivo de administração diz ao comando pkgadd se ele deve realizar as verificações ou solicitações que normalmente realiza. Conseqüentemente, os administradores devem entender por completo o processo de instalação do pacote e os scripts envolvidos antes de usar os arquivos de administração.

Um arquivo de padrões administrativos é entregue com o sistema operacional SunOS em /var/sadm/install/admin/default. Trata-se do arquivo que estabelece o nível mais básico de regras administrativas com relação à instalação de produtos de software. O arquivo apresenta a seguinte aparência quando entregue:

#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

O administrador pode editar este arquivo para estabelecer novos comportamentos padrões, ou criar um arquivo de administração e especificar sua existência usando a opção -a no comando pkgadd.

Podem ser definidos onze parâmetros no arquivo de administração, mas nem todos precisam ser definidos. Para obter mais informações, consulte admin(4).

O parâmetro basedir especifica como o diretório base será obtido quando um pacote for instalado. A maioria dos administradores o mantém como default, mas basedir pode ser definido como:


Observação –

Se o comando pkgadd for chamado com o argumento - a none, ele sempre pede que o administrador indique um diretório base. Infelizmente, isso também define todos os parâmetros do arquivo com o valor padrão quit, que pode causar problemas adicionais.


Conformando-se com a incerteza

Um administrador tem controle sobre todos os pacotes que estão sendo instalados em um sistema usando o arquivo de administração. Infelizmente, um arquivo de padrões administrativos alternativo é, com freqüência, fornecido pelo criador de pacotes, ignorando os desejos do administrador.

Os criadores de pacotes incluem, às vezes, um arquivo de administração alternativo para que eles, e não o administrador, controlem a instalação de um pacote. Por substituir todos os diretórios base, a entrada basedir do arquivo de padrões administrativos proporciona um método simples para selecionar o diretório base apropriado no tempo de instalação. Em todas as versões do ambiente operacional Solaris anteriores ao Solaris 2.5, isso era considerado o método mais simples para controlar o diretório base.

Entretanto, é necessário aceitar os desejos do administrador com relação à instalação do produto. Proporcionar um arquivo de padrões administrativos temporário para fins de controle de instalação leva a uma desconfiança por parte dos administradores. Você deve usar um script request e um script checkinstall para controlar estas instalações sob a supervisão do administrador. Se o script request envolver fielmente o administrador no processo, o empacotamento System V servirá tanto aos administradores como aos criadores de pacotes.

Usando o parâmetro BASEDIR

O arquivo pkginfo de qualquer pacote relocável deve incluir um diretório base padrão em forma de entrada como esta:


BASEDIR=absolute_path

Este é o único diretório base padrão. Ele pode ser alterado pelo administrador durante a instalação.

Enquanto alguns pacotes requerem mais de um diretório base, a vantagem de usar este parâmetro para posicionar o pacote está no fato de que garante que o diretório base esteja na sua posição e seja gravável como um diretório válido no momento em que a instalação começar. O caminho correto para o diretório base do servidor e do cliente está disponível para todos os scripts de procedimento na forma de variáveis de ambiente reservadas, e o comando pkginfo -r SUNWstuf exibe a base de instalação atual do pacote.

No script checkinstall, BASEDIR é o parâmetro exatamente conforme definido no arquivo pkginfo (ele ainda foi condicionado). A fim de inspecionar o diretório de destino base, a construção ${PKG_INSTALL_ROOT}$BASEDIR é necessária. Isso significa que o script request ou checkinstall podem alterar o valor de BASEDIR no ambiente de instalação com resultados previsíveis. Neste momento o script preinstall é chamado, o parâmetro BASEDIR é o indicador completamente condicionado do diretório base real no sistema de destino, mesmo que o sistema for um cliente.


Observação –

O script request utiliza o parâmetro BASEDIR de forma diferente em diferentes versões do sistema operacional SunOS. A fim de testar um parâmetro BASEDIR em um script request, o seguinte código deve ser usado para determinar o diretório base real em uso.

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

Usando diretórios base paramétricos

Se um pacote precisar de vários diretórios base, você pode estabelecê-los com nomes de caminho paramétricos. Este método tem se tornado muito popular, embora apresente as desvantagens seguintes.

Embora os parâmetros que determinam os diretórios base sejam definidos no arquivo pkginfo, eles podem ser modificados pelo script request. Esta é uma das principais razões da popularidade desta abordagem. As desvantagens, entretanto, são crônicas e esta configuração deve ser levada em consideração em último caso.

Exemplos — Usando diretórios base paramétricos

O arquivo pkginfo

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

O arquivo pkgmap

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

Gerenciando o diretório base

Os pacotes disponíveis em várias versões ou de várias arquiteturas devem ser criados para deslocar o diretório base, se necessário. Deslocar um diretório base significa que, se já existir uma versão anterior ou uma arquitetura diferente do pacote que estiver sendo instalado no diretório base, o pacote resolve este problema, criando talvez um novo diretório base com um nome levemente diferente. Os scripts request e checkinstall do Solaris 2.5 e versões compatíveis têm a capacidade de modificar a variável de ambiente BASEDIR. Isso não é válido para as versões anteriores do sistema operacional Solaris.

Mesmo em versões mais antigas do sistema operacional Solaris, o script request tem a autoridade para redefinir os diretórios que estão na base de instalação. O script request pode fazê-lo de uma forma que ainda oferece suporte à maioria das preferências administrativas.

Acomodando a relocação

Embora você possa selecionar os diretórios base de vários pacotes que são exclusivos de uma arquitetura ou versão, esse procedimento cria níveis desnecessários de hierarquia de diretórios. Por exemplo, em um produto criado para processadores baseados em SPARC e em x86, você poderia organizar os diretórios base por processador e versão conforme ilustrado abaixo.

Diretório base 

Versão e processador 

/opt/SUNWstuf/sparc/1.0

Versão 1.0, SPARC 

/opt/SUNWstuf/sparc/1.2

Versão 1.2, SPARC 

/opt/SUNWstuf/x86/1.0

Versão 1.0, x86 

Esse procedimento está bem e funciona, mas você está tratando os nomes e os números como se eles tivessem algum significado para o administrador. Uma abordagem mais apropriada é fazê-lo automaticamente depois de explicar ao administrador e pedir permissão.

Isso significa que você pode realizar todo o trabalho no pacote sem pedir ao administrador que o faça manualmente. Você pode atribuir o diretório base arbitrariamente e, a seguir, estabelecer com clareza os links de cliente apropriados em um script postinstall. Você também pode usar o comando pkgadd para instalar todo o pacote ou parte dele nos clientes do script postinstall. Você pode, até mesmo, perguntar ao administrador quais os usuários ou clientes que precisam ter informações sobre este pacote e atualizar automaticamente as variáveis de ambiente PATH e os arquivos /etc. Isso é totalmente aceitável contanto que qualquer ação realizada pelo pacote na instalação seja desfeita durante a remoção.

Deslocando diretórios base

Você pode tirar vantagem dos dois métodos para controlar o diretório base no momento da instalação. O primeiro é melhor para novos pacotes que serão instalados somente no Solaris 2.5 e versões compatíveis. Ele oferece dados muito úteis para o administrador e oferece suporte a várias versões e arquiteturas instaladas, além de exigir pouco trabalho especial. O segundo método pode ser usado por qualquer pacote e faz uso do controle inerente do script request sobre os parâmetros de construção para garantir que as instalações sejam bem-sucedidas.

Usando o parâmetro BASEDIR

O script checkinstall pode selecionar o diretório base apropriado no tempo de instalação, o que significa que o diretório base pode ser posicionado bem abaixo na árvore de diretórios. Este exemplo aumenta o diretório base seqüencialmente, levando a diretórios na forma /opt/SUNWstuf, /opt/SUNWstuf.1 e /opt/SUNWstuf.2. O administrador pode usar o comando pkginfo para determinar que arquitetura e versão são instalados em cada diretório base.

Se o pacote SUNWstuf (que contém um conjunto de utilitários que realizam ações) usasse este método, os arquivos pkginfo e pkgmap teriam a seguinte aparência.

O arquivo pkginfo

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

O arquivo pkgmap

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

Exemplo — Scripts de análise que deslocam um BASEDIR

Suponha que a versão x86 de SUNWstuf já esteja instalada no servidor em /opt/SUNWstuf. Quando o administrador usa o comando pkgadd para instalar a versão SPARC, o script request precisa detectar a existência da versão x86 e interagir com o administrador em relação à instalação.


Observação –

O diretório base pode ser deslocado sem a interação do administrador em um script checkinstall, mas se operações arbitrárias como essa ocorrerem constantemente, os administradores perdem a confiança no processo.


Os scripts request e checkinstall de um pacote que manipula esta situação podem ter a seguinte aparência.

O script request

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

O script checkinstall

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

Esta abordagem não funcionaria muito bem se o diretório base fosse simplesmente /opt. Este pacote tem que chamar mais precisamente o BASEDIR visto que /opt seria difícil de deslocar. De fato, dependendo do esquema de montagem, isso pode não ser possível. O exemplo desloca o diretório base criando um novo diretório em /opt, que não apresenta nenhum problema.

Este exemplo usa um script request e um script checkinstall embora as versões do Solaris anteriores à versão 2.5 não possam executar o script checkinstall. O script checkinstall deste exemplo é usado a fim de interromper educadamente a instalação em resposta a uma mensagem privada na forma da seqüência quitinstall. Se este script for executado no Solaris 2.3, o script checkinstall é ignorado e o script request interrompe a instalação com uma mensagem de erro.

Lembre-se que nas versões anteriores ao Solaris 2.5 e versões compatíveis, o parâmetro BASEDIR é um parâmetro somente de leitura e não pode ser alterado pelo script request. Por essa razão, se uma versão antiga do sistema operacional SunOS for detectada (através do teste de uma variável de ambiente CLIENT_BASEDIR condicionada), o script request tem apenas duas opções — continuar ou sair.

Usando caminhos paramétricos relativos

Se o seu produto de software puder ser instalado em versões antigas do sistema operacional SunOS, o script request precisa realizar todas as ações necessárias. Esta abordagem também pode ser usada para manipular vários diretórios. Se forem necessários diretórios adicionais, estes ainda precisam ser incluídos em um único diretório base a fim de oferecer um produto facilmente administrável. Embora o parâmetro BASEDIR não ofereça o nível de granularidade disponível na última versão do Solaris, seu pacote ainda pode deslocar o diretório base usando o script request para manipular caminhos paramétricos. Os arquivos pkginfo e pkgmap podem ter a aparência seguinte.

O arquivo pkginfo

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

O arquivo pkgmap

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

Este exemplo não é perfeito. Um comando pkginfo -r retorna /opt para a base de instalação, que é um pouco ambíguo. Muitos pacotes estão em /opt, mas pelo menos é um diretório significativo. Igual ao exemplo anterior, o próximo exemplo oferece suporte completo a várias arquiteturas e versões. O script request pode ser adaptado às necessidades de determinado pacote e resolver quaisquer dependências aplicáveis.

Exemplo — Um script request que desloca um caminho paramétrico relativo

# 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

Oferecendo suporte a relocação em um ambiente heterogêneo

O conceito original do empacotamento System V pressupõe uma arquitetura por sistema. O conceito de um servidor não tinha um papel importante na criação. Agora, é claro, um único servidor pode oferecer suporte a várias arquiteturas, o que significa que pode haver várias cópias de um mesmo software em um servidor, cada uma de uma arquitetura diferente. Embora os pacotes do Solaris estejam isolados dentro dos limites do sistema de arquivos recomendado (por exemplo, / e /usr), com os bancos de dados do produto no servidor, bem como em cada cliente, nem todas as instalações oferecem necessariamente suporte a esta divisão. Determinadas implementações oferecem suporte a uma estrutura completamente diferente e abrangem um banco de dados comum do produto. Embora seja simples indicar aos clientes diferentes versões, instalar pacotes System V em diferentes diretórios base pode realmente causar complicações ao administrador.

Ao criar seu pacote, você deve também levar em consideração os métodos comuns usados pelos administradores para introduzir novas versões de software. Os administradores procuram freqüentemente instalar e testar a última versão lado-a-lado com a versão atualmente instalada. O procedimento envolve a instalação da nova versão em um diretório base diferente do diretório da versão atual e o envio de uma nova versão a um grupo de clientes não-críticos como teste. Assim como as construções de confiança, o administrador reenvia a mais e mais clientes a nova versão. Eventualmente, o administrador retém a versão antiga somente para emergências e, em seguida, finalmente a exclui.

Isso significa que os pacotes destinados a sistemas heterogêneos modernos devem oferecer suporte a relocações verdadeiras, o quer dizer que o administrador pode colocá-los em qualquer lugar razoável do sistema de arquivos e ainda obter total funcionalidade. O Solaris 2.5 e versões compatíveis oferecem várias ferramentas úteis que permitem a instalação perfeita de várias arquiteturas e versões no mesmo sistema. O Solaris 2.4 e versões compatíveis também oferecem suporte à relocação verdadeira, mas a conclusão das tarefas não é tão evidente.

Abordagem tradicional

Pacotes relocáveis

A ABI do System V dá a entender que a intenção original do pacote relocável era tornar a instalação do pacote mais fácil para o administrador. Agora, a necessidade em ter pacotes relocáveis vai mais além. A facilidade não é o único fim, é mais apropriado dizer que é bem possível que, durante a instalação, um produto de software ativo já esteja instalado no diretório padrão. Um pacote que não está desenhado para lidar com este tipo de situação, ou substitui o produto existente ou falha ao instalar. Entretanto, um pacote desenhado para manipular várias arquiteturas e versões pode ser instalado tranqüilamente e oferece ao administrador uma grande variedade de opções totalmente compatíveis com as tradições administrativas existentes.

De alguma forma, o problema das arquiteturas e versões múltiplas é o mesmo. Deve ser possível instalar uma variante do pacote existente lado-a-lado com outras variantes, e conduzir os clientes e os consumidores independentes de sistemas de arquivos exportados a qualquer uma destas variantes sem perda de funcionalidade. Embora a Sun tenha estabelecido métodos para lidar com várias arquiteturas em um servidor, o administrador pode não se ater a tais recomendações. Todos os pacotes precisam ser capazes de satisfazer os desejos sensatos dos administradores em relação à instalação.

Exemplo - Um pacote relocável tradicional

Este exemplo mostra a aparência de um pacote relocável tradicional. O pacote será colocado em /opt/SUNWstuf, e os arquivos pkginfo e pkgmap podem ter a seguinte aparência.

O arquivo pkginfo

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

O arquivo pkgmap

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

A isso se refere como método tradicional porque cada objeto de pacote é instalado no diretório base definido pelo parâmetro BASEDIR do arquivo pkginfo. Por exemplo, o primeiro objeto do arquivo pkgmap é instalado como o diretório /opt/SUNWstuf.

Pacotes absolutos

Um pacote absoluto é aquele que é instalado em um determinado sistema de arquivos raiz (/). É difícil lidar com estes pacotes do ponto de vista de arquiteturas e versões múltiplas. Como regra geral, todos os pacotes devem ser relocáveis. Há, no entanto, razões muito boas para incluir elementos absolutos em um pacote relocável.

Exemplo - Um pacote absoluto tradicional

Se o pacote SUNWstuf fosse um pacote absoluto, o parâmetro BASEDIR não deveria estar no arquivo pkginfo e o arquivo pkgmap teria a seguinte aparência.

O arquivo pkgmap

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

Neste exemplo, se o administrador tivesse especificado um diretório base alternativo durante a instalação, ele seria ignorado pelo comando pkgadd. Este pacote é instalado sempre no /opt/SUNWstuf do sistema de destino.

O argumento -R do comando pkgadd funciona conforme o previsto. Por exemplo,


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

instala os objetos em /export/opt/client3/opt/SUNWstuf. Porém, isso é o mais perto que este pacote chega de ser um pacote relocável.

Observe o uso do ponto de interrogação (?) no diretório /opt do arquivo pkgmap. Isso indica que os atributos existentes não devem ser alterados. Não significa “criar o diretório com atributos padrão”, embora sob certas circunstâncias isso possa ocorrer. Qualquer diretório específico de um novo pacote deve especificar todos os atributos explicitamente.

Pacotes compostos

Qualquer pacote que contenha objetos relocáveis é denominado de pacote relocável. Isso pode induzir a erros porque um pacote relocável pode conter caminhos absolutos em seu arquivo pkgmap. O uso de uma entrada raiz (/) em um arquivo pkgmap pode melhorar os aspectos relocáveis do pacote. Os pacotes que possuem entradas raiz e relocáveis são denominados pacotes compostos.

Exemplo - Uma solução tradicional

Suponha que um objeto do pacote SUNWstuf seja um script de início executado no nível de execução 2. O arquivo /etc/rc2.d/S70dostuf precisa ser instalado como parte do pacote, mas não pode ser colocado no diretório base. Pressupondo que um pacote relocável seja a única solução, os arquivos pkginfo e pkgmap podem ter a seguinte aparência.

O arquivo pkginfo

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

O arquivo pkgmap

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

Não há muita diferença entre esta abordagem e a abordagem do pacote absoluto. De fato, estaria melhor como um pacote absoluto — se o administrador fornecesse um diretório base alternativo a este pacote, ele não funcionaria!

Na verdade, somente um arquivo deste pacote precisa estar relacionado à raiz, o restante pode ser movido para qualquer lugar. Como resolver este problema através do uso de um pacote composto é um tema tratado no restante desta seção.

Não tradicional

A abordagem descrita nesta seção não se aplica a todos os pacotes, mas tem como resultado melhor desempenho durante a instalação em um ambiente heterogêneo. Uma pequena parte se aplica a pacotes entregues como parte do sistema operacional Solaris (pacotes incorporados). Entretanto, os pacotes avulsos podem praticar empacotamento não tradicional.

A razão pela qual se encoraja o uso de pacotes relocáveis é oferecer suporte a este requisito:

Quando um pacote é adicionado ou removido, os comportamentos desejáveis existentes dos produtos de software instalados não serão alterados.

Os pacotes avulsos devem estar em /opt de modo a garantir que o novo pacote não interfira nos produtos existentes.

Outra consideração sobre os pacotes compostos

Há duas regras a seguir ao construir um pacote composto funcional:

Em outras palavras, visto que “relocável” significa que o objeto pode ser instalado em qualquer parte e ainda funcionar, nenhum script de início executado por init no tempo de inicialização pode ser considerado relocável! Embora não exista nada de errado em especificar /etc/passwd como um caminho relativo no pacote entregue, há somente um lugar para o qual ele pode ir.

Fazendo nomes de caminho absolutos parecer relocáveis

Se for construir um pacote composto, os caminhos absolutos devem operar de modo que não interfiram no software instalado. Um pacote que pode estar totalmente contido em /opt contorna este problema, já que não há arquivos existentes no meio do caminho. Quando um arquivo em /etc estiver incluído no pacote, você deve garantir que nomes de caminho absolutos se comportem da mesma forma que os nomes de caminho relativos. Leve em consideração os dois exemplos seguintes.

Exemplo — Modificando um arquivo

Descrição

Uma entrada está sendo adicionada a uma tabela, ou o objeto é uma nova tabela que será provavelmente modificada por outros programas ou pacotes.

Implementação

Defina o objeto como tipo de arquivo e e pertencente à classe build, awk ou sed. O script que realiza esta tarefa deve remover a si mesmo de maneira tão eficaz como quando se adiciona.

Exemplo

Uma entrada precisa ser adicionada a /etc/vfstab em apoio ao novo disco rígido de estado sólido.

A entrada no arquivo pkgmap pode ser


1 e sed /etc/vfstab ? ? ?

O script request pergunta ao operador se /etc/vfstab deve ser modificado pelo pacote. Se o operador responder “não”, então o script request imprimirá as instruções sobre como realizar o trabalho manualmente e executará


echo "CLASSES=none" >> $1

Se o operador responder “sim”, então ele executa


echo "CLASSES=none sed" >> $1

que ativa o script de ação de classe que fará as modificações necessárias. A classe sed significa que o arquivo de pacote /etc/vfstab é um programa sed que contém as operações de instalação e remoção do arquivo com o mesmo nome no sistema de destino.

Exemplo — Criando um novo arquivo

Descrição

O objeto é um arquivo totalmente novo que provavelmente não será editado mais adiante ou está substituindo um arquivo de outro pacote.

Implementação

Defina o objeto de pacote como tipo de arquivo f e o instale usando um script de ação de classe capaz de desfazer alterações.

Exemplo

Um novo arquivo de marca é requerido em /etc para proporcionar as informações necessárias para suportar o disco rígido de estado sólido, denominado /etc/shdisk.conf . A entrada no arquivo pkgmap pode ter esta aparência:


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

O script de ação de classe i.newetc é responsável pela instalação e por qualquer outro arquivo que precise ir para /etc. Ele faz a verificação para se certificar de que não exista outro arquivo lá. Se não existir, ele simplesmente copia o novo arquivo no local. Se já existir um arquivo no local, ele fará o backup do arquivo existente antes de instalar o novo arquivo. O script r.newetc remove estes arquivos e restaura os originais, se requerido Abaixo se encontra o fragmento principal do script de instalação.

# i.newetc
while read src dst; do
	  if [ -f $dst ]; then
	    dstfile=`basename $dst`
	    cp $dst $PKGSAV/$dstfile
	  fi
	  cp $src $dst
done
 
if [ "${1}" = "ENDOFCLASS" ]; then
	  cd $PKGSAV
	  tar cf SAVE.newetc .
	  $INST_DATADIR/$PKG/install/squish SAVE.newetc
fi

Observe que este usa a variável de ambiente PKGSAV para armazenar o backup do arquivo que será substituído. Quando o argumento ENDOFCLASS é passado para o script, isso quer dizer que o comando pkgadd informa o script que estas são as últimas entradas desta classe, momento em que o script arquiva e compacta os arquivos salvos usando um programa privado de compactação armazenado no diretório de instalação do pacote.

Embora o uso da variável de ambiente PKGSAV não seja confiável durante a atualização de um pacote, se o pacote não for atualizado (através de um patch, por exemplo), o arquivo de backup é seguro. O seguinte script de remoção inclui o código para lidar com outros problemas — o fato de que as versões antigas do comando pkgrm não passem para os scripts o caminho correto da variável de ambiente PKGSAV.

O script de remoção pode ter esta aparência.

# 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

Este script usa um algoritmo privado desinstalado (unsquish) que está no diretório de instalação do banco de dados do pacote. Isso é feito automaticamente pelo comando pkgadd no tempo de instalação. Todos os scripts não reconhecidos especificamente como somente de instalação pelo comando pkgadd são deixados neste diretório para serem usados pelo comando pkgrm. Você não pode saber onde tal diretório está, mas pode ter certeza de que está fixo e contém todos os arquivos de informação e scripts de instalação necessários do pacote. O script encontra o diretório devido ao fato de que o script de ação de classe está com certeza sendo executado a partir do diretório que contém o programa unsquish.

Observe, também, que este script não apenas supõe que o diretório de destino é /etc. Ele pode realmente estar em /export/root/client2/etc . O diretório correto pode ser construído de duas formas.

Usando esta abordagem para cada objeto absoluto do pacote, você pode ter certeza de que o comportamento atual desejável é inalterado ou, pelo menos, recuperável.

Exemplo — Um pacote composto

Abaixo se encontra um exemplo dos arquivos pkginfo e pkgmap de um pacote composto.

O arquivo pkginfo

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

O arquivo pkgmap

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

Enquanto S70dostuf pertence à classe daemon, os diretórios que lidam com ele (que já estão no local no tempo de instalação) pertencem à classe none. Mesmo se os diretórios forem exclusivos deste pacote, você deve deixá-los na classe none. A razão disso é que os diretórios precisam ser criados primeiro e excluídos por último, e tal ação é sempre válida para a classe none. O comando pkgadd cria diretórios. Eles não são copiados do pacote e não são passados a um script de ação de classe a ser criado. Em vez disso, eles são criados pelo comando pkgadd antes que ele chame o script de ação de classe de instalação, e o comando pkgrm exclui os diretórios após a conclusão do script de ação de classe de remoção.

Isso significa que, se um diretório de uma classe especial contiver objetos na classe none, quando o comando pkgrm tenta remover o diretório, ele falha porque o diretório não estará vazio a tempo. Se um objeto de classe none estiver para ser inserido em um diretório de alguma classe especial, tal diretório não existirá a tempo para aceitar o objeto. O comando pkgadd não criará o diretório instantaneamente durante a instalação do objeto e pode não ser capaz de sincronizar os atributos de tal diretório quando exibir finalmente a definição de pkgmap.


Observação –

Ao atribuir um diretório a uma classe, lembre-se sempre da ordem de criação e exclusão.


Tornando os pacotes instaláveis remotamente

Todos os pacotes devem ser remotamente instaláveis. Instalável remotamente significa que você não pressupõe que o administrador que está instalando seu pacote esteja instalando no sistema de arquivos raiz (/) do sistema que está executando o comando pkgadd. Se, em um dos seus scripts de procedimento, você precisar obter o arquivo /etc/vfstab do sistema de destino, será necessário usar a variável de ambiente PKG_INSTALL_ROOT. Em outras palavras, o nome de caminho /etc/vfstab o levará ao arquivo /etc/vfstab do sistema que estiver executando o comando pkgadd, mas o administrador pode estar instalando em um cliente em /export/root/client3. O caminho ${PKG_INSTALL_ROOT}/etc/vfstab com certeza o leva ao sistema de arquivos de destino.

Exemplo – Instalando em um sistema cliente

Neste exemplo, o pacote SUNWstuf está instalado no client3, que está configurado com /opt no sistema de arquivos raiz (/). Outra versão deste pacote já está instalada no client3, e o diretório base está definido como basedir=/opt/$PKGINST de um arquivo de administração, thisadmin. (Para obter mais informações sobre arquivos de administração, consulte O arquivo de padrões administrativos.) O comando pkgadd executado no servidor é:


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

A tabela abaixo lista as variáveis de ambiente e os valores passados aos scripts de procedimento.

Tabela 6–1 Valores passados aos scripts de procedimento

Variável de ambiente 

Valor 

PKGINST

SUNWstuf.2

PKG_INSTALL_ROOT

/export/root/client3

CLIENT_BASEDIR

/opt/SUNWstuf.2

BASEDIR

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

Exemplo – Instalando em um sistema servidor ou independente

Para instalar em um sistema servidor ou em um sistema independente sob as mesmas circunstâncias do exemplo anterior, o comando é:


# pkgadd -a thisadmin SUNWstuf

A tabela abaixo lista as variáveis de ambiente e os valores passados aos scripts de procedimento.

Tabela 6–2 Valores passados aos scripts de procedimento

Variável de ambiente 

Valor 

PKGINST

SUNWstuf.2

PKG_INSTALL_ROOT

Não definido. 

CLIENT_BASEDIR

/opt/SUNWstuf.2

BASEDIR

/opt/SUNWstuf.2

Exemplo – Montando sistemas de arquivos compartilhados

Suponha que o pacote SUNWstuf crie e compartilhe um sistema de arquivos no servidor em /export/SUNWstuf/share. Quando o pacote for instalado no sistema cliente, seus arquivos /etc/vfstab precisam ser atualizados para montar este sistema de arquivos compartilhado. É neste caso que a variável CLIENT_BASEDIR pode ser usada.

A entrada do cliente precisa apresentar o ponto de montagem com relação ao sistema de arquivos do cliente. Esta linha deve ser construída corretamente se a instalação for do servidor ou do cliente. Suponha que o nome do sistema do servidor seja $SERVER. Você pode ir a $PKG_INSTALL_ROOT/etc/vfstab e, usando os comandos sed ou awk, construir a seguinte linha no arquivo /etc/vfstab do cliente.


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

Por exemplo, para o servidor universe e o sistema cliente client9, a linha no arquivo /etc/vfstab do sistema cliente se assemelharia a:


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

Ao usar corretamente este parâmetro, a entrada sempre monta o sistema de arquivos do cliente, tanto se estiver sendo construído localmente quanto a partir do servidor.

Atualizando com patches os pacotes

Um patch de um pacote é apenas um pacote pequeno criado para substituir certos arquivos no original. Não há uma verdadeira razão para a distribuição de pacotes pequenos exceto para economizar espaço no meio de distribuição. Você também pode distribuir o pacote original completo com poucos arquivos alterados, ou fornecer acesso ao pacote modificado em uma rede. Contanto que somente estes novos arquivos sejam realmente diferentes (os outros arquivos não foram recompilados), o comando pkgadd instala as diferenças. Observe as seguintes diretrizes em relação a atualização com patches dos pacotes.

É vital que o número de versão do pacote de patch seja o mesmo do pacote original. Você deve rastrear o status do patch do pacote usando uma entrada diferente do arquivo pkginfo com a forma.


PATCH=patch_number

Se a versão do pacote for alterada em um patch, você cria outra instância do pacote e fica extremamente difícil gerenciar o produto com patch. Este método de patch de instância progressiva oferecia certas vantagens nas primeiras versões do sistema operacional Solaris, mas torna chato o gerenciamento de sistemas mais complexos.

Todos os parâmetros de zona do patch devem corresponder aos parâmetros de zona do pacote.

No que diz respeito aos pacotes que formam o sistema operacional Solaris, deveria haver somente uma cópia do pacote no banco de dados do pacote, embora possa haver várias instâncias com patches. Para remover um objeto de um pacote instalado (usando o comando removef), você precisa saber que instâncias possuem tal arquivo.

Entretanto, se seu pacote (que não faz parte do sistema operacional Solaris) precisar determinar o nível do patch de um determinado pacote que faz parte do sistema operacional Solaris, isso se torna um problema que será resolvido aqui. Os scripts de instalação podem ser um pouco grandes sem causar impacto importante desde que não sejam armazenados no sistema de destino. Com o uso de scripts de ação de classe e vários outros scripts de procedimento, você pode salvar os arquivos alterados usando a variável de ambiente PKGSAV (ou em outro diretório mais permanente) a fim de possibilitar a devolução dos patches instalados. Você pode monitorar o histórico do patch definindo as variáveis de ambiente adequadas através de scripts request. Os scripts das seções seguintes supõem que pode haver vários patches cujo esquema de numeração tem um significado quando aplicado a um único pacote. Neste caso, os números de patches individuais representam um subconjunto de funcionalidades relacionado aos arquivos do pacote. Dois números diferentes de patch não podem alterar o mesmo arquivo.

Para criar um pacote pequeno regular em um pacote de patch, os scripts descritos nas seções seguintes podem ser simplesmente colocados no pacote. Todos eles podem ser reconhecidos como componentes de pacote padrão com exceção dos dois últimos denominados patch_checkinstall e patch_postinstall. Estes dois scripts podem ser incorporados no pacote de devolução se você quiser incluir a capacidade de devolver o patch. Os scripts são bastante simples e as suas tarefas são fáceis.


Observação –

Este método de atualizar com patches pode ser usado para colocar patches nos sistemas clientes, mas os diretórios-raiz do cliente no servidor deve ter as permissões corretas para que o usuário install ou nobody possa ler.


O script checkinstall

O script checkinstall verifica se tal patch é apropriado para este pacote em particular. Uma vez confirmado, ele constrói a lista de patches e a lista de informações do patch e, em seguida, insere-as no arquivo de resposta para que sejam incorporadas no banco de dados do pacote.

Uma lista de patches é a lista de patches que afetam o pacote atual. Esta lista de patches está registrada no arquivo pkginfo do pacote instalado com uma linha que se assemelha a:

PATCHLIST=patch_id patch_id ...

Uma lista de informações do patch é a lista de patches da qual o patch atual é dependente. Esta lista de patches também está registrada no arquivo pkginfo com uma linha que se assemelha a:

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

Observação –

Estas linhas (e seus formatos) são declaradas como interface pública. Qualquer empresa que distribua patches para pacotes Solaris deve atualizar esta lista adequadamente. Quando um patch é entregue, cada pacote dentro do patch contém um script checkinstall que realiza esta tarefa. Este mesmo script checkinstall também atualiza alguns parâmetros específicos do patch. Esta é a nova arquitetura do patch, que é denominada Direct Instance Patching


Neste exemplo, os pacotes originais e seus patches existem no mesmo diretório. Os dois pacotes originais são denominados SUNWstuf.v1 e SUNWstuf.v2, e seus patches são denominados SUNWstuf.p1 e SUNWstuf.p2. Isso significa que poderia ser muito difícil para um script de procedimento saber de que diretório vêm esses arquivos, visto que tudo no nome do pacote após o ponto (“.”) é extraído para o parâmetro PKG, e a variável de ambiente PKGINST faz referência à instância instalada, não à instância de origem. Para que os scripts de procedimento possam encontrar o diretório de origem, o script checkinstall (que é executado sempre a partir do diretório de origem) faz a pesquisa e repassa o local como a variável SCRIPTS_DIR. Se houvesse somente um pacote no diretório de origem denominado SUNWstuf, então os scripts de procedimento poderiam tê-lo encontrado usando $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

O script preinstall

O script preinstall inicializa o arquivo prototype, os arquivos de informação e os scripts de instalação para que o pacote de devolução seja construído. Este script é muito simples e os scripts restantes deste exemplo permitem somente que um pacote de devolução descreva arquivos regulares.

Se quiser restaurar os links simbólicos, os links de disco rígido, os dispositivos e os pipes nomeados em um pacote de devolução, você pode modificar o script preinstall para que use o comando pkgproto para comparar o arquivo pkgmap entregue aos arquivos instalados e, então, criar uma entrada do arquivo prototype para cada não-arquivo a ser alterado no pacote de devolução. O método que você deve usar é semelhante ao método do script de ação de classe.

Os scripts patch_checkinstall e patch_postinstall são inseridos na árvore de origem do pacote do script preinstall. Estes dois scripts desfazem as ações do 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

O script de ação de classe

O script de ação de classe cria uma cópia de cada arquivo que substitui um arquivo existente e adiciona uma linha correspondente ao arquivo prototype do pacote de devolução. Tudo isso é feito com scripts nawk muito simples. O script de ação de classe recebe uma lista de pares origem/destino composta de arquivos comuns que não combinam com os arquivos instalados correspondentes. Os links simbólicos e outros não-arquivos devem ser tratados no 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

O script postinstall

O script postinstall cria o pacote de devolução usando as informações fornecidas pelos outros scripts. Visto que os comandos pkgmk e pkgtrans não requerem o banco de dados do pacote, eles podem ser executados na instalação de um pacote.

No exemplo, é permitido desfazer o patch construindo um pacote em formato de fluxo no diretório salvo (usando a variável de ambiente PKGSAV). Não é óbvio, mas este pacote não deve estar em formato de fluxo, porque o diretório salvo se desloca durante uma operação com pkgadd. Se o comando pkgadd for aplicado em um pacote no seu próprio diretório salvo, é muito arriscado supor onde a origem do pacote está em um dado momento. Um pacote em formato de fluxo é desempacotado em um diretório temporário e é instalado a partir de tal diretório. (Um pacote em formato de fluxo poderia começar a instalação a partir do diretório salvo e descobrir inesperadamente que foi relocado durante uma operação com pkgadd à prova de falha.)

Para determinar quais patches se aplicam a um pacote, use este comando:


$ pkgparam SUNWstuf PATCHLIST

Com exceção de PATCHLIST, que é uma interface pública da Sun, não há nada significativo nos nomes de parâmetro deste exemplo. Em vez de PATCH, você pode usar o SUNW_PATCHID tradicional, e as outras listas, tais como PATCH_EXCL e PATCH_REQD, podem ser renomeadas do devido modo.

Se determinados pacotes de patches dependerem de outros pacotes de patches que estão disponíveis no mesmo meio, o script checkinstall pode determinar tal dependência e criar um script que será executado pelo script postinstall da mesma forma que no exemplo de atualização (consulte Atualizando pacotes).

# 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

O script patch_checkinstall

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

O script patch_postinstall

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

Atualizando pacotes

O processo de atualização de um pacote é muito diferente do processo de substituição de um pacote. Ao mesmo tempo em que há ferramentas especiais que oferecem suporte à atualização de pacotes padrão entregues como parte do sistema operacional Solaris, um pacote não incorporado pode estar destinado a oferecer suporte a sua própria atualização — vários exemplos anteriores descreveram os pacotes pensados para o futuro e que controlam o método exato de instalação sob a direção do administrador. Você também pode criar um script request para oferecer suporte à atualização direta de um pacote. Se o administrador optar por instalar um pacote de modo a substituir completamente o outro, sem deixar rastro de arquivos obsoletos, os scripts de pacote podem fazê-lo.

O script request e o script postinstall deste exemplo oferecem um pacote atualizável simples. O script request se comunica com o administrador e configura um arquivo simples no diretório /tmp para remover a instância de pacote antiga. (Embora o script request crie um arquivo (que é proibido), não há problema porque todos têm acesso ao /tmp).

O script postinstall executa, então, o script shell em /tmp, que executa o comando pkgrm necessário contra o pacote antigo e, em seguida, se auto-exclui.

Este exemplo ilustra uma atualização básica. Tem menos de cinqüenta linhas de código incluindo algumas mensagens bastante longas. Pode ser estendido para que devolva a atualização ou realize outras transformações principais no pacote conforme requerido pelo criador.

O design de uma opção de atualização da interface de usuário deve estar absolutamente segura de que o administrador está totalmente ciente do processo e solicitou ativamente a atualização em vez da instalação paralela. Não há nada de errado em realizar uma operação complexa como a atualização contanto que a interface de usuário permita que a operação seja realizada com clareza.

O script request

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

O script postinstall

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

Criando pacotes de arquivo de classe

Um pacote de arquivo de classe, que é um aperfeiçoamento da ABI (Application Binary Interface), é aquele no qual certos conjuntos de arquivos são combinados em arquivos simples, ou arquivos de dados, e são opcionalmente compactados ou criptografados. Os formatos de arquivo de classe aumentam a velocidade da instalação inicial em até 30% e melhoram a confiabilidade durante a instalação de pacotes e patches em sistemas de arquivos potencialmente ativos.

As seções seguintes oferecem informações sobre a estrutura do diretório, as palavras-chave e o utilitário faspac do pacote de arquivo.

Estrutura do diretório do pacote de arquivo

A entrada do pacote mostrada na ilustração abaixo representa o diretório que contém os arquivos de pacote. Este diretório deve ser o mesmo do pacote.

Figura 6–1 Estrutura do diretório do pacote

O diagrama mostra cinco subdiretórios abaixo do diretório do pacote: pkginfo, pkgmap, reloc, root e install. Também mostra seus subdiretórios.

O quadro abaixo lista as funções dos arquivos e diretórios contidos no diretório do pacote.

Item 

Descrição 

pkginfo

Arquivo que descreve o pacote como um todo incluindo as variáveis de ambiente especiais e as diretivas de instalação 

pkgmap

Arquivo que descreve cada objeto que será instalado , como um arquivo, diretório ou pipe 

reloc

Diretório opcional que contém os arquivos a serem instalados em relação ao diretório base (os objetos relocáveis) 

root

Diretório opcional que contém os arquivos a serem instalados em relação ao diretório root (os objetos-raiz)

install

Diretório opcional que contém os scripts e outros arquivos auxiliares (exceto para pkginfo e pkgmap, todos os arquivos ftype i até aqui)

O formato de arquivo de classe permite que o construtor do pacote combine arquivos dos diretórios reloc e root em arquivos de dados que podem ser compactados, criptografados ou, senão, processados de outra maneira a fim de aumentar a velocidade da instalação, diminuir o tamanho do pacote ou aumentar a segurança deste.

A ABI permite que os arquivos dentro de um pacote sejam atribuídos a uma classe. Todos os arquivos de uma classe específica podem ser instalados no disco usando um método personalizado definido por um script de ação de classe. Este método personalizado pode usar programas disponíveis no sistema de destino ou programas entregues com o pacote. A formato resultante se parece muito ao formato padrão da ABI. Como mostrado na ilustração seguinte, outro diretório é adicionado. Qualquer tipo de arquivos destinado ao arquivo de dados é simplesmente combinado em um arquivo único e colocado no diretório archive. Todos os arquivos arquivados são removidos dos diretórios reloc e root e um script de ação de classe de instalação é colocado no diretório install.

Figura 6–2 Estrutura do diretório do pacote de arquivo

O diagrama mostra a mesma estrutura do diretório do pacote da Figura 6-1 com a adição do subdiretório archive.

Palavras-chave para oferecer suporte aos pacotes de arquivo de classe

Para oferecer suporte a este novo formato de arquivo de classe, três novas interfaces em forma de palavras-chave têm especial significado no arquivo pkginfo. Estas palavras-chave são usadas para designar as classes que requerem tratamento especial. A instrução do formato de cada palavra-chave é: keyword=class1[class2 class3 ...]. Cada valor da palavra-chave está definido na tabela seguinte.

Palavra-chave 

Descrição 

PKG_SRC_NOVERIFY

Esta palavra-chave diz a pkgadd para não verificar a existência e as propriedades dos arquivos nos diretórios reloc ou root do pacote entregue se eles pertencerem à classe nomeada. É requerido por todas as classes arquivadas, porque tais arquivos não estão mais em um diretório reloc ou root. São um arquivo de formato privado do diretório archive.

PKG_DST_QKVERIFY

Os arquivos nessas classes são verificados após a instalação usando um algoritmo rápido com pouca ou nenhuma saída de texto. A verificação rápida primeiro define os atributos de cada arquivo corretamente e, então, realiza a verificação para comprovar se a operação foi bem-sucedida. Em seguida, há um teste do tamanho do arquivo e do tempo de modificação em comparação ao pkgmap. Não é realizada nenhuma verificação com checksum e a recuperação de erros é bem pior comparada com a oferecida pelo mecanismo padrão. No caso de blecaute ou de falha do disco durante a instalação, o arquivo do conteúdo pode ficar incompatível com os arquivos instalados. Esta incompatibilidade pode ser resolvida sempre com um comando pkgrm.

PKG_CAS_PASSRELATIVE

Normalmente o script de ação de classe recebe do stdin uma lista de pares de origem e destino constando quais arquivos instalar. As classes atribuídas a PKG_CAS_PASSRELATIVE não obtêm os pares de origem e destino. Em vez disso, elas recebem uma única lista, na qual a primeira entrada é a localização do pacote de origem e o restante são os caminhos de destino. Isso serve especificamente para simplificar a extração de um arquivo de dados. Da localização do pacote de origem, você pode encontrar o arquivo de dados no diretório archive. Os caminhos de destino são, então, passados para a função responsável pela extração do conteúdo do arquivo de dados. Cada caminho de destino fornecido é absoluto ou relativo do diretório base dependendo se o caminho estiver localizado originalmente em root ou reloc. Se esta opção for escolhida, pode ser difícil combinar caminhos absoluto e relativo em uma única classe.

Para cada classe arquivada é necessário um script de ação de classe. É um arquivo que contém comandos do shell Bourne que é executado por pkgadd para realmente instalar os arquivos a partir do arquivo de dados. Se o script de ação de classe for encontrado no diretório install do pacote, o pkgadd passa toda a responsabilidade da instalação para este script. O script de ação de classe é executado com permissões de raiz e pode colocar seus arquivos em quase todos os locais do sistema de destino.


Observação –

A única palavra-chave que é absolutamente necessária para implementar um pacote de arquivo de classe é PKG_SRC_NOVERIFY. As outras podem ser usadas para melhorar a velocidade da instalação ou conservar o código.


O utilitário faspac

O utilitário faspac converte um pacote de ABI padrão em um formato de arquivo de classe usado em pacotes incorporados. Este utilitário arquiva usando cpio e compacta usando compress. O pacote resultante tem um diretório adicional na parte superior do diretório denominada archive. Neste diretório todos os arquivos de dados terão o nome de classe. O diretório install conterá os scripts de ação de classe necessários para desempacotar cada arquivo de dados. Os caminhos absolutos não são arquivados.

O utilitário faspac tem o seguinte formato:


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

Cada opção do comando faspac está descrita na tabela seguinte.

Opção 

Descrição 

-m Archive Method

 

Indica um método para arquivar ou compactar. bzip2 é o utilitário de compactação padrão usado. Para passar para o método zip ou unzip use -m zip ou para cpio ou compress use - m cpio.

-a

Fixa atributos (deve ser raiz para fazê-lo). 

-s

Indica a tradução do pacote do tipo ABI padrão. Esta opção toma o cpio ou o pacote compactado e o transforma em um formato de pacote compatível com a ABI padrão. 

-q

Indica o modo silencioso. 

-d Base Directory

Indica o diretório no qual todos os pacotes presentes agirão de acordo com o requerido pela linha de comando. É mutuamente exclusivo em relação à entrada List of Packages.

-x Exclude List

Indica uma lista de pacotes separados por vírgulas, espaços ou entre aspas que serão excluídos do processo. 

List of Packages

Indica a lista de pacotes que serão processados.