7. Conectando um script ao framework rc.d

Depois que um script foi escrito, ele precisa ser integrado em rc.d>. O passo crucial é instalar o script em /etc/rc.d (para o sistema base) ou /usr/local/etc/rc.d (para ports). Ambos <bsd.prog.mk > e < bsd.port.mk > fornecer ganchos convenientes para isso, e geralmente você não precisa se preocupar com a propriedade e o modo adequado. Os scripts do sistema devem ser instalados a partir do src /etc/rc.d através do Makefile encontrado lá. Os scripts de porta podem ser instalados usando USE_RC_SUBR conforme descrito em no Manual do Porter.

No entanto, devemos considerar antecipadamente o local do nosso script na sequência de inicialização do sistema. O serviço manipulado pelo nosso script provavelmente depende de outros serviços. Por exemplo, um daemon de rede não pode funcionar sem as interfaces de rede e o roteamento em funcionamento. Mesmo que um serviço pareça não exigir nada, dificilmente pode ser iniciado antes que os sistemas de arquivos básicos tenham sido verificados e montados.

Nós já mencionamos o rcorder(8). Agora é hora de dar uma olhada de perto. Em poucas palavras, o rcorder(8) pega um conjunto de arquivos, examina seu conteúdo e imprime uma lista ordenada por dependência de arquivos do conjunto para stdout. O objetivo é manter as informações de dependência dentro dos arquivos para que cada arquivo possa falar por si só. Um arquivo pode especificar as seguintes informações:

Não é surpresa que rcorder(8) possa manipular apenas arquivos de texto com uma sintaxe próxima a de sh(1). Ou seja, linhas especiais compreendidas por rcorder(8) se parecem com comentários sh(1). A sintaxe de tais linhas especiais é bastante rígida para simplificar seu processamento. Veja rcorder(8) para detalhes.

Além de usar linhas especiais do rcorder(8), um script pode insistir em sua dependência de outro serviço apenas iniciando-o forçadamente. Isso pode ser necessário quando o outro serviço é opcional e não será iniciado automaticamente porque o administrador do sistema o desativou por engano no rc.conf(5).

Com este conhecimento geral em mente, vamos considerar o simples script daemon aprimorado com coisas de dependência:

#!/bin/sh

# PROVIDE: mumbled oldmumble 1
# REQUIRE: DAEMON cleanvar frotz2
# BEFORE:  LOGIN3
# KEYWORD: nojail shutdown4

. /etc/rc.subr

name=mumbled
rcvar=mumbled_enable

command="/usr/sbin/${name}"
start_precmd="${name}_prestart"

mumbled_prestart()
{
	if ! checkyesno frotz_enable && \
	    ! /etc/rc.d/frotz forcestatus 1>/dev/null 2>&1; then
		force_depend frotz || return 15
	fi
	return 0
}

load_rc_config $name
run_rc_command "$1"

Como antes, a análise detalhada segue:

1

Esta linha declara os nomes das condições que nosso script fornece. Agora, outros scripts podem registrar uma dependência em nosso script por estes nomes.

Nota:

Geralmente, um script especifica uma única condição fornecida. No entanto, nada nos impede de listar várias condições, por exemplo, por razões de compatibilidade.

Em qualquer caso, o nome da condição principal, ou a única, PROVIDE: deve ser o mesmo que ${name}.

2 3

Portanto, nosso script indica quais condições são fornecidas por outros scripts dos quais depende. De acordo com as linhas, nosso script pede ao rcorder(8) para colocá-lo após o(s) script(s) fornecendo DAEMON e cleanvar, mas antes disso prover LOGIN.

Nota:

A linha BEFORE: não deve ser abusada para contornar uma lista de dependências incompleta no outro script. O caso apropriado para usar o BEFORE: é quando o outro script não se importa com o nosso, mas nosso script pode fazer sua tarefa melhor se for executado antes do outro. Um típico exemplo da vida real são as interfaces de rede versus o firewall: embora as interfaces não dependam do firewall em realizar seu trabalho, a segurança do sistema se beneficiará do firewall estar pronto antes que haja qualquer tráfego de rede.

Além das condições correspondentes a um único serviço, existem meta-condições e seus scripts placeholder usados para garantir que determinados grupos de operações sejam executados antes dos outros. Estes são denotados pelos nomes UPPERCASE. Sua lista e finalidades podem ser encontradas em rc(8).

Tenha em mente que colocar um nome de serviço na linha REQUIRE: não garante que o serviço estará realmente em execução no momento em que nosso script for iniciado. O serviço necessário pode falhar ao iniciar ou simplesmente ser desativado em rc.conf(5). Obviamente, o rcorder(8) não pode controlar tais detalhes, e o rc(8) também não fará isso. Consequentemente, o aplicativo iniciado por nosso script deve ser capaz de lidar com quaisquer serviços necessários indisponíveis. Em certos casos, podemos ajudá-lo conforme discutido abaixo.

4

Como lembramos do texto acima, as palavras-chave do rcorder(8) podem ser usadas para selecionar ou deixar alguns scripts. Ou seja, qualquer consumidor rcorder(8) pode especificar através das opções -k e -s que as palavras-chave estão na keep list e na skip list, respectivamente. De todos os arquivos a serem classificados, o rcorder(8) selecionará apenas aqueles que tiverem uma palavra-chave da lista de manutenção (a menos que vazia) e não uma palavra-chave da lista de itens ignorados.

No FreeBSD, o rcorder(8) é usado por /etc/rc e /etc/rc.shutdown. Esses dois scripts definem a lista padrão de palavras-chave do rc.d do FreeBSD e seus significados da seguinte forma:

nojail

O serviço não é para o ambiente jail(8). Os procedimentos automáticos de inicialização e encerramento ignoram o script se estiverem executando dentro de uma jail.

nostart

O serviço deve ser iniciado manualmente ou não iniciado. O procedimento de inicialização automática irá ignorar o script. Em conjunto com a palavra-chave shutdown, isso pode ser usado para escrever scripts que fazem algo apenas no desligamento do sistema.

shutdown

Esta palavra-chave deve ser listada explicitamente se o serviço precisar ser interrompido antes do desligamento do sistema.

Nota:

Quando o sistema for desligado, o /etc/rc.shutdown será executado. Ele assume que a maioria dos scripts rc.d não tem nada a fazer naquele momento. Portanto, /etc/rc.shutdown invoca seletivamente os scripts rc.d com a palavra-chave shutdown, efetivamente ignorando o restante dos scripts. Para um desligamento ainda mais rápido, o /etc/rc.shutdown passa o comando faststop para os scripts que executa, para que eles ignorem as verificações preliminares, por exemplo, a verificação do pidfile. Como os serviços dependentes devem ser parados antes de seus pré-requisitos, /etc/rc.shutdown executa os scripts na ordem de dependência inversa.

Se estiver escrevendo um script rc.d real, você deve considerar se é relevante no momento do desligamento do sistema. Por exemplo, se o seu script funcionar apenas em resposta ao comando start, não será necessário incluir essa palavra-chave. No entanto, se o seu script gerenciar um serviço, provavelmente será uma boa ideia pará-lo antes que o sistema prossiga para o estágio final de sua seqüência de desligamento descrita em halt(8). Em particular, um serviço deve ser interrompido explicitamente se precisar de tempo considerável ou ações especiais para encerrar de forma limpa. Um exemplo típico de tal serviço é um mecanismo de banco de dados.

5

Para começar, force_depend deve ser usado com muito cuidado. Geralmente é melhor revisar a hierarquia de variáveis de configuração para seus scripts rc. se eles forem interdependentes.

Se você ainda não pode fazer sem force_depend, o exemplo oferece uma expressão de como invocá-lo condicionalmente. No exemplo, nosso daemon mumbled requer que outro, frotz, seja iniciado antecipadamente. No entanto, frotz é opcional também; e rcorder(8) não sabe nada sobre esses detalhes. Felizmente, nosso script tem acesso a todas as variáveis rc.conf(5). Se frotz_enable estiver como true, esperamos pelo melhor e dependemos de rc.d para iniciar frotz. Caso contrário, nós forçadamente verificaremos o status de frotz. Finalmente, impomos nossa dependência ao frotz se ele não estiver sendo executado. Uma mensagem de aviso será emitida por force_depend porque ele deve ser chamado apenas se um erro de configuração for detectado.

All FreeBSD documents are available for download at https://download.freebsd.org/ftp/doc/

Questions that are not answered by the documentation may be sent to <freebsd-questions@FreeBSD.org>.
Send questions about this document to <freebsd-doc@FreeBSD.org>.