DOKK / manpages / debian 11 / debconf-doc / debconf-devel.7.pt
DEBCONF-DEVEL(7) Miscellaneous Information Manual DEBCONF-DEVEL(7)

debconf - guia de programadores

Isto é um guia para desenvolver pacotes que usam debconf.

Este manual assume que você está familiarizado com o debconf como utilizador, e está familiarizado com as bases de construção de pacotes debian.

Este manual começa por explicar dois novos ficheiros que foram adicionados aos pacotes debian que usam debconf. Depois explica como funciona o protocolo debconf, e indica-lhe algumas bibliotecas que permitem que os seus programas falem o protocolo. Discute outros scripts de maintainer onde o debconf é tipicamente usado: os scripts postinst e postrm. Depois avança para tópicos mais avançados como templates debconf partilhados, depuração, e algumas técnicas comuns e armadilhas de programar com debconf. Termina com uma discussão das deficiências actuais do debconf.

Debconf adiciona um script de maintainer adicional, o script config, ao conjunto de scripts do maintainer que podem existir nos pacotes debian (o postinst, preinst, postrm, e prerm). O script config é responsável por perguntar quaisquer questões necessárias à configuração do pacote.

Nota: É um pouco confuso que o dpkg refira a correr o script postinst de um pacote como "a configurar" o pacote, porque o pacote que usa debconf é geralmente totalmente pré-configurado, pelo seu script config, antes do postinst correr. Pois é.

Como o postinst, ao script config são passados dois parâmetros quando é executado. O primeiro diz que acção é executada, e o segundo é a versão do pacote que está actualmente instalada. Portanto, como num postinst, você pode usar dpkg --compare-versions em $2 para fazer com que certo comportamento apenas aconteça na actualização de uma versão particular de um pacote, e coisas desse género.

O script config pode ser executado em um de três modos:

1
Se um pacote é pré-configurado com o dpkg-preconfigure, o seu script config é executado, e é lhe passado os parâmetros "configure" e installed-version.
2
Quando o postinst de um pacote é executado, o debconf irá tentar executar também o script config, e serão passados os mesmos parâmetros que foram passados quando foi pré-configurado. Isto é necessário porque o pacote pode não ter sido pré-configurado, e o script config ainda precise de uma chance para funcionar. Veja TRUQUES para mais detalhes.
3
Se um pacote é reconfigurado com o dpkg-reconfigure, o seu script config é executado, e é lhe passado os parâmetros "reconfigure" e installed-version.

Note que como uma instalação típica ou actualização de pacote usando apt corre em passos 1 e 2, tipicamente o script config será executado duas vezes. Não deverá fazer nada na segunda vez (fazer as mesmas perguntas duas vezes é aborrecido), e deverá definitivamente ser idempotente. Felizmente, o debconf evita repetir questões por predefinição, então isto é geralmente fácil de conseguir.

Note que o script config é executado antes do pacote ser desempacotado. Deverá apenas usar comandos que estão em pacotes essenciais. A única dependência do seu pacote que é garantido estar satisfeita quando o seu script config é executado é uma dependência do próprio debconf (possivelmente com uma versão específica).

O script config não deve necessitar de modificar o sistema de ficheiros. Apenas examina o estado do sistema, e faz perguntas, e o debconf armazena as respostas para serem actuadas mais tarde pelo script postinst. Reciprocamente, o script postinst não deve quase nunca usar o debconf para fazer perguntas, mas em vez disso deve actuar com as respostas às questões feitas pelo script config.

Um pacote que usa debconf provavelmente vai querer perguntar algumas questões. Estas questões estão armazenadas, num formato de template, no ficheiro de templates.

Tal como o script config, o ficheiros templates é colocado na secção control.tar.gz de um deb. O seu formato é semelhante a um ficheiro de controle debian; um conjunto de estrofes separadas por linhas vazias, com cada estrofe a ter um formato tipo RFC822:


Template: foo/bar
Type: string
Default: foo
Description: Isto é um exemplo de string de questão.
Isto é a sua descrição extensa.
.
Note que:
- Tal como na descrição dum pacote debian, um ponto
isolado define um novo parágrafo.
- A maioria do texto é arrumado por palavras, mas o texto
duplamente indentado é deixado como está, portanto pode usá-lo para
listas de itens, como esta. Tenha cuidado, como não
é arrumado por palavras, se for muito longo
vai ficar mal. É melhor usá-lo para itens curtos
(portanto isto é um mau exemplo).


Template: foo/baz
Type: boolean
Description: Suficientemente claro, não?
Isto é outra questão, de tipo booleano.

Para alguns exemplos reais de ficheiros templates, veja /var/lib/dpkg/info/debconf.templates, e outros ficheiros templates nesse directório.

Vamos observar cada um dos campos um de cada vez...

O nome do template, no campo 'Template', é geralmente prefixado com nome do pacote. Após isso o espaço do nome é totalmente aberto; você pode usar uma disposição plana e simples como a que está em cima, ou configurar "sub-directórios" que contêm questões relacionadas.
O tipo de template determina que tipo de widget é mostrado ao utilizador. Os tipos actualmente suportados são:
Resulta num campo de entrada de formato livre onde o utilizador pode escrever qualquer string.
Pede ao utilizador uma palavra-passe. Use isto com cuidado; esteja ciente que a palavra-passe que o utilizador inserir será escrita na base de dados do debconf. Você deve provavelmente limpar esse valor da base de dados o mais cedo possível.
Uma escolha verdadeiro/falso.
Uma escolha entre um de um número de valores. As escolhas devem ser especificadas num campo chamado 'Choices'. Separe os valores possíveis com vírgulas e espaços, como isto:

Choices: yes, no, maybe
Tal como o tipo de dados select, excepto que o utilizador pode escolher qualquer número de itens da lista de escolhas (ou não escolher nenhum deles).
Em vez de ser uma questão em si, este tipo de dados indica uma nota que pode ser mostrada ao utilizador. Deve ser usado apenas para notas importantes que o utilizador realmente precisa de ver, pois o debconf irá ter trabalho a certificar-se que o utilizador a vê; parando a instalação para que ele carregue numa tecla. É melhor usar estas apenas avisos sobre problemas muito sérios, e o tipo de dados error é geralmente mais apropriado.
Este tipo de dados é usado para mensagens de erro, tais como erros de validação de entrada. O Debconf irá mostrar uma questão deste tipo mesmo que a prioridade seja muito alta ou que o utilizador já a tenha visto.
Este tipo de dados é usado para títulos, para ser definido com o comando SETTITLE.
Este tipo de dados pode ser usado para fragmentos de texto, tais como etiquetas, que podem ser usadas por questões cosméticas nos mostradores de alguns frontends. Outros frontends nem as vão usar de todo. Não existe razão para usar este tipo de dados ainda, já que nenhum frontend o suporta bem, e pode até ser removido no futuro.
O campo 'Default' diz ao debconf qual deve ser o valor predefinido. Para multi-selecção, pode ser uma lista escolhas, separadas por vírgulas e espaços, semelhante ao campo 'Choices'. Para selecção, deve ser uma das opções. Para booleano, é "true" ou "false", enquanto que pode ser qualquer coisa para uma string, e é ignorado para palavras-passe.

Não cometa o erro de pensar que o campo default contém o "valor" da questão, ou que pode ser usado para alterar o valor da questão. Não o faz, nem pode fazer, apenas disponibiliza um valor predefinido para a primeira vez que a questão é mostrada. Para disponibilizar uma predefinição que muda na hora, você terá de usar o comando SET para alterar o valor de uma questão.

O campo 'Description', como a descrição de um pacote Debia, tem duas partes: Uma descrição curta e uma descrição extensa. Note que alguns frontends não mostram a descrição longa, ou podem apenas mostrá-la se o utilizador pedir ajuda. Portanto a descrição curta deverá ser suficiente sozinha.

Se você não consegue pensar numa descrição longa, então primeiro pense mais um pouco. Poste em debian-devel. Peça ajuda. Tire um curso de escrita! Essa descrição extensa é importante. Se após isso tudo ainda não conseguir imaginar nada, deixe em branco. Não vale a pena duplicar a descrição curta.

O texto na descrição extensa será arrumado por palavras, a menos que seja prefixado com um espaço em branco adicional (para além do espaço necessário). Você pode parti-lo em parágrafos separados ao colocar um "." sozinho numa linha entre eles.

Uma questão é um template instanciado. Ao pedir ao debconf para mostrar uma questão, o seu script config pode interagir com o utilizador. Quando o debconf carrega um ficheiro templates (isto acontece quer um script config ou postinst seja executado), instancia automaticamente uma questão para cada template. Na realidade é possível instanciar várias questões independentes do mesmo template (usando o comando REGISTER), mas isso é raramente necessário. Templates são dados estáticos que vêm do ficheiro templates, enquanto as questões são usadas para armazenar dados dinâmicos, tal como o valor actual de uma questão, se um utilizador já viu a questão, e etc. Mantenha em mente a distinção entre um template e uma questão, mas não se preocupe muito com isso.

É possível ter um template e uma questão que é partilhada entre um conjunto de pacotes. Todos os pacotes têm que disponibilizar uma cópia idêntica do template nos seus ficheiros templates. Isto pode ser útil num grupo de pacotes que precisam de perguntar a mesma pergunta, e você apenas deseja aborrecer o utilizador com ela uma vez. Os templates partilhados são geralmente colocados no pseudo-directório shared/ no espaço de nomes de template do debconf.

Os scripts de configuração comunicam com o debconf usando o protocolo debconf. Isto é um protocolo orientado a linhas simples, semelhante a protocolos de internet comuns como o SMTP. O script config envia um comando ao debconf ao escrever o comando na saída (output) standard. Depois pode ler a resposta do debconf a partir da entrada (input) standard.

A resposta do debconf pode ser partida em duas partes: Um código de resultado numérico (a primeira palavra da resposta), e um código de resultado extensivo opcional (o restante da resposta). O código numérico usa 0 para indicar sucesso, e outros números para indicar vários tipos de falhas. Para os detalhes completos, veja a tabela no documento de especificação do debconf da política Debian.

o código de retorno extensivo é geralmente de formato livre e não especificado, portanto você geralmente ignorá-lo, e não deve tentar analisá-lo com um programa para inspeccionar o que o debconf está a fazer. As excepções são comandos como o GET, que causa o retorno de um valor no código de retorno extensivo.

Geralmente você vai querer usar uma biblioteca específica para a linguagem que lida com os 'parafusos e porcas' da configuração destas ligações ao debconf e da comunicação com ele.

Por agora, aqui estão os comandos no protocolo. Isto não é a definição definitiva, veja o documento de especificação debconf da política Debian para isso.

Geralmente você não precisa de usar este comando. Ele troca com o debconf o número de versão do protocolo que está a ser usado. A versão actual do protocolo é 2.0, e versões na série 2.x serão compatíveis para trás. Você pode especificar o número da versão de protocolo que está a falar e o debconf irá responder com a versão do protocolo que ele fala no código de resultados extenso. Se a versão que você especificar for muito baixa, o debconf irá responder com o código numérico 30.
Geralmente você não precisa de usar este comando. Ele troca com o debconf uma lista das capacidades suportadas (separadas por espaços). As capacidades que ambos você e o debconf suportam serão usadas, e o debconf irá responder com todas as capacidades que suporta.

Se o 'escape' for encontrado entre as suas capacidades, o debconf irá esperar que os comandos que você envia tenha barras invertidas e escapes de novas linhas (como \\ e \n respectivamente) e irá por sua vez escapar as barras invertidas e novas linhas nas suas respostas. Isto pode ser usado, por exemplo, para substituir strings de múltiplas linhas em templates, ou para obter descrições extensas de múltiplas linhas com segurança usando METAGET. Neste modo, você tem que dar escape você próprio no texto de entrada (pode usar debconf-escape(1) para o ajudar com isto se desejar), mas as bibliotecas confmodule irá retirar o espace das respostas para si.

Isto define o título que o debconf mostra ao utilizador, usando a descrição curta do template para a questão específica. O template deve ser do tipo 'title'. Você raramente precisa de usar este comando porque o debconf pode automaticamente gerar um título baseado no nome do seu pacote.

Definir o título a partir de um template significa que eles são armazenados no mesmo local que o resto das questões do debconf, e permite-lhes serem traduzidos.

Isto define o título que o debconf mostra ao utilizador para a string especificada. Normalmente é preferido o uso do comando SETTITLE pois este permite a tradução do título.
Pede ao debconf para preparar a amostragem de uma questão ao utilizador. A questão não é realmente mostrada até que seja emitido um comando GO; isto permite que sejam dados vários comandos INPUT em série, para preparar um conjunto de questões, que as quais podem ser todas respondidas num único écran.

O campo de prioridade diz ao debconf qual a importância de mostrar esta questão ao utilizador. Os valores de prioridade são:

Itens muito triviais que têm predefinições que irão trabalhar ma vasta maioria dos casos, apenas os viciados no controle vêm estes.
Itens normais que têm predefinições razoáveis.
Itens que não têm uma predefinição razoável.
Itens que provavelmente irão danificar o sistema sem a intervenção do utilizador.

O debconf decide se uma questão é mesmo mostrada, baseando-se na sua prioridade, e se o utilizador já a viu antes, e qual o frontend está a ser usado. Se a questão não é para ser mostrada, o debconf responde com o código 30.

Diz ao debconf para mostrar o conjunto de questões acumuladas (a partir de comandos INPUT) ao utilizador.

Se a capacidade de backup for suportada e o utilizador indicar que quer fazer backup de um passo, o debconf responde com código 30.

Limpa o conjunto de questões acumulado (de comandos INPUT) sem os mostrar.
Alguns frontends do debconf podem mostrar ao utilizador um número de questões de uma vez. Talvez no futuro um frontend seja até capaz de agrupar estas questões em blocos no écran. BEGINBLOCK e ENDBLOCK podem ser colocados em redor de um conjunto de comandos INPUT para indicar blocos de questões (e os blocos podem até ser aninhados). Como ainda não há nenhum frontend do debconf tão sofisticado, este comandos são ignorados, por agora.
Este comando diz ao debconf que já terminou de falar com ele. Geralmente o debconf consegue determinar o terminar do seu programa e este comando é desnecessário.
Após usar INPUT e GO para mostrar uma questão, você pode usar este comando para obter o valor que o utilizador inseriu. O valor é retornado no código de resultado extensivo.
Isto define o valor de uma questão, e pode ser usado para sobrepor o valor predefinido com algo que o seu programa calcula na hora.
Isto re-define (reset) a questão ao seu valor predefinido (tal como especificado no campo 'Default' do seu template).
As questões podem ter substituições embebidas nos seus campos "Description" e "Choices" (apesar do uso de substituições nos campos "Choices" ser um pouco de truque; será eventualmente desenvolvido um mecanismo melhor). Estas substituições parecem-se como "${key}". Quando a questão é mostrada, as substituições trocam de lugar com os seus valores. Este comando pode ser usado para definir o valor de uma substituição. Isto é útil caso você precise de mostrar alguma questão ao utilizador que não a pode codificar no ficheiro templates.
Não tente usar o SUBST para alterar o valor predefinido de uma questão, não vai funcionar porque existe um comando SET explícito para esse trabalho.
As questões podem ter bandeiras associadas a elas. As bandeiras pode ter um valor de "true" ou "false". Este comando devolve o valor de uma bandeira.
Isto define o valor da bandeira de uma questão. O valor tem de ser "true" ou " false".

Uma bandeira comum é a bandeira "seen" (visto). Normalmente apenas é definida se um utilizador já viu uma pergunta. Normalmente o debconf apenas mostra questões aos utilizadores se estas tiverem a bandeira seen definida para "false" (ou se estiver e reconfigurar um pacote). Por vezes você quer que o utilizador volte a ver a pergunta de novo -- nestes casos você pode definir a bandeira seen para false para forçar o debconf a mostrá-la.

Isto devolve o valor de qualquer campo de um template associado a uma questão (a Descrição, por exemplo).
Isto cria uma nova questão que está ligada a um template. Por predefinição cada template tem uma questão associada com o mesmo nome. No entanto, qualquer número de questões pode ser realmente associado com um template, e isto permite-lhe criar mais dessas tais questões.
Isto remove uma questão da base de dados.
Chame isto no seu pós-remoção (postrm) quando o seu pacote é purgado. Remove todas as suas questões do pacote da base de dados do debconf.
Esta extensão carrega o ficheiro template específico na base de dados do debconf. O dono muda por predefinição para o pacote que está a ser configurado com o debconf.

Aqui está um exemplo simples do protocolo debconf em acção.


INPUT medium debconf/frontend
30 question skipped
FSET debconf/frontend seen false
0 false
INPUT high debconf/frontend
0 question will be asked
GO
[ Here debconf displays a question to the user. ]
0 ok
GET no/such/question
10 no/such/question doesn't exist
GET debconf/frontend
0 Dialog

Configurar as coisas para que possa falar com o debconf, e falar o protocolo debconf manualmente é demasiado trabalhoso, então existem algumas pequenas bibliotecas para aliviar esta pequena trabalheira.

Para programação em shell, existe a biblioteca /usr/share/debconf/confmodule, a qual você pode usar no topo de um script shell, e falar com o debconf dum modo bastante natural, usando versões em minúsculas dos comandos do protocolo debconf, que estão prefixados com "db_" (ie, "db_input" e "db_go"). Para detalhes veja confmodule(3).

Programadores de Perl podem usar o módulo Debconf::Client::ConfModule(3pm), e programadores de python podem usar o módulo python do debconf.

O resto deste manual irá usar a biblioteca /usr/share/debconf/confmodule em exemplos de scripts de shell. Aqui está um exemplo de script config que usa essa biblioteca, que apenas faz uma pergunta:


#!/bin/sh
set -e
. /usr/share/debconf/confmodule
db_set mypackage/reboot-now false
db_input high mypackage/reboot-now || true
db_go || true

Repare na utilização de "|| true" para prevenir que o script morra se o debconf decidir que não pode mostrar uma pergunta, ou o utilizador tente voltar atrás. Nessas situações, o debconf devolve um código de erro diferente de zero, e como este script de shell está definido com -e, um código de saída não previsto irá fazê-lo abortar.

E aqui está o script postinst correspondente, que usa a resposta do utilizador para a questão para ver se o sistema deve ser reiniciado (um exemplo bastante absurdo...):


#!/bin/sh
set -e
. /usr/share/debconf/confmodule
db_get mypackage/reboot-now
if [ "$RET" = true ]; then
shutdown -r now
fi

Repare na utilização da variável $RET para obter um código de retorno extenso do comando GET, o qual detém a resposta do utilizador para a questão.

A última secção tinha um exemplo de um script postinst que usa debconf para obter um valor de uma questão, e actuar nela. Aqui estão algumas coisas a ter em mente quando escrever scripts postinst que usam debconf:

*
Evite fazer as questões no pós-instalação. Em vez disso, o script config deve fazer as questões usando debconf, para que a pré-configuração funcione.
*
Use sempre a fonte /usr/share/debconf/confmodule no topo do seu postinst, mesmo que não vá correr nenhuns comandos db_* nele. Isto é necessário para certificar que o script config tem uma hipótese de correr (veja TRUQUES para mais detalhes).
*
Evite escrever algo para o stdout no seu postinst, pois isso pode confundir o debconf, e o postinst não deve ser detalhado de qualquer modo. A escrita para o stderr é boa ideia, se tiver mesmo que ser.
*
Se o seu postinst lançar um daemon, certifique-se de dizer ao debconf para parar (STOP) no fim, pois caso contrário o debconf pode ficar um pouco confuso acerca de quando o seu postinst terminou.
*
Faça o seu script postinst aceitar um primeiro parâmetro de "reconfigure". Ele pode tratá-lo tal como "configure". Isto será usado numa versão posterior do debconf para permitir aos postinsts saberem quando são reconfigurados.

À parte dos scripts config e postinst, você pode usar o debconf em qualquer dos outros scripts do maintainer. Mais geralmente, você vai usar debconf no seu postrm, para chamar o comando PURGE quando o seu pacote é purgado, para limpar as suas entradas na base de dados debconf. (Já agora, isto é definido automaticamente para si por dh_installdebconf(1),.)

Uma utilização mais envolvida do debconf seria se desejasse usá-lo no postrm quando o seu pacote é purgado, para fazer uma pergunta acerca de apagar algo. Ou talvez você descubra que precisa de usá-lo no preinst ou prerm or alguma razão. Todas estas utilizações irão funcionar, irá provavelmente envolver o fazer perguntas e actuar nas respostas no mesmo programa, em vez de separar as duas actividades como é feito pelos scripts config e postinst.

Note que se a única utilização do debconf do seu pacote é o postrm, você deve fazer o postinst do seu pacote usar a fonte /usr/share/debconf/confmodule, para dar uma chance ao debconf de carregar o seu ficheiro templates na base de dados. Então o templates estará disponível quando o seu pacote for purgado.

Você também pode usar o debconf em outros programas standalone. O problema a observar aqui é que o debconf não se destina a ser, e não deve ser usado como um registo. No fim de contas isto é unix, e os programas são configurados por ficheiros em /etc, e não por alguma base de dados debconf nebulosa (de qualquer modo é apenas uma cache e pode ser derrubada). Portanto pense bem antes de usar o debconf num programa standalone.

Existem alturas em que isso faz sentido, com no programa apt-setup que usa debconf para perguntar ao utilizador num modo consistente com o resto do processo de instalação debian, e actua imediatamente nas suas respostas para configurar o sources.list do apt.

Debconf suporta a localização de ficheiros templates. Isto é conseguido ao adicionar mais campos, com texto traduzido neles. Qualquer dos campos pode ser traduzido. Por exemplo, você pode querer traduzir a descrição em Espanhol. Apenas crie um campo chamado 'Description-es' que mantém a tradução. Se um campo traduzido não estiver disponível, o debconf regressa ao campo de Inglês normal.

Além do campo 'Description', você deve traduzir o campo 'Choices' de um template de selecção ou multi-selecção. Certifique-se de listar as escolhas traduzidas na mesma ordem que elas aparecem no campo 'Choices' principal. Você não precisa de traduzir o campo 'Default' de uma questão de selecção ou multi-selecção, e o valor da questão será automaticamente devolvido em Inglês.

Você vai descobrir que é mais fácil de gerir traduções se as manter em ficheiros separados; um ficheiro por cada tradução. No passado, os programas debconf-getlang(1) e debconf-mergetemplate(1) eram usados para gerir ficheiros debian/template.ll. Isto foi substituído pelo pacote po-debconf(7)l, o qual permite-lhe lidar com as traduções de debconf em ficheiros .po, tal como quaisquer outras traduções. Os seus tradutores vão agradecer-lhe por usar este mecanismo novo e melhorado.

Para detalhes sobre o po-debconf, veja o seu manual. Se você está a usar debhelper, converter para po-debconf é tão simples como correr o comando debconf-gettextize(1) uma vez, e adicionar uma Dependência de Compilação (Build-Dependency) ao po-debconf e ao debhelper (>= 4.1.13).

Então você tem um script config, um ficheiro templates, um script postinst que usa debconf, e etc. Juntar estas peças num pacote debian não é difícil. Pode fazê-lo manualmente, ou pode usar dh_installdebconf(1) o qual irá fundir os seus templates traduzidos, copiar os ficheiros para os lugares correctos para si. e pode até gerar a chamada ao PURGE que deve ir para o seu script postrm. Certifique-se que o seu pacote depende do debconf (>= 0.5), pois as versões anteriores não eram compatíveis com tudo o que é descrito neste manual. E está feito.

Bem, excepto para testar, depurar, e realmente usar o debconf para coisas mais interessantes do que fazer algumas perguntas básicas. Para isso continue a ler...

Se você tem um pacote que é suposto usar debconf, mas não funciona, talvez o debconf não esteja a perguntar a questão que você definiu. Ou talvez não esteja a acontecer nada de esquisito: ela ficou presa eternamente num tipo de ciclo vicioso, ou pior. Felizmente, o debconf tem bastantes funcionalidades de depuração.

A primeira coisa a pegar é na variável de ambiente DEBCONF_DEBUG. Se você definir e export DEBCONF_DEBUG=developer, o debconf irá escrever no stderr uma descarga do protocolo debconf quando o seu programa corre. Irá parecer algo como isto -- o erro de escrita é tornado claro:


debconf (developer): <-- input high debconf/frontand
debconf (developer): --> 10 "debconf/frontand" doesn't exist
debconf (developer): <-- go
debconf (developer): --> 0 ok

É bastante útil usar o frontend readline do debconf quando está a depurar (na opinião do autor), porque as perguntas não interrompem, e toda a informação de depuração é facilmente preservada e registada em log.

Se esta variável de ambiente for definida para 'true', o frontend irá mostrar os valores nos campos Choices-C (se presentes) de templates de selecção e multi-selecção em vez dos valores descritivos.
Outra ferramenta útil é o programa debconf-communicate(1).Execute-o e você pode falar o protocolo debconf em cru com o debconf interactivamente, Este é um bom modo de experimentar coisas na hora.
Se um utilizador está a reportar um problema, o debconf-show(1) pode ser usado para despejar todas as questões possuídas pelo seu pacote, mostrando todos os valores e se o utilizador as viu.
.debconfrc
Para evitar o ciclo tedioso de compilar/instalar/depurar, pode ser útil para carregar o seu templates com debconf-loadtemplate(1) e correr o seu script config manualmente com o comando debconf(1). No entanto, você ainda vai precisar de fazer isso como root, certo? Não é muito bom. E o ideal seria você ser capaz de ver como é que uma instalação fresca do seu pacote fica, com uma base de dados debconf limpa.

Acontece que você definiu um ficheiro ~/.debconfrc para um utilizador normal, apontando para um config.dat e template.dat pessoal para o utilizador, você pode carregar os templates e correr os scripts config que quiser, sem nenhum acesso de root. Se deseja começar com uma base de dados limpa, apenas livre-se dos ficheiros *.dat.

Para detalhes de como definir isto, veja debconf.conf(5), e note que /etc/debconf.conf faz um bom modelo para um ficheiro ~/.debconfrc pessoal.

Muita gente parece querer usar o debconf para ajudar a gerir ficheiros de configuração que fazem parte do seu pacote. Talvez não haja uma boa predefinição para lançar um ficheiro de configuração, e assim desejam usar o debconf para questionar o utilizador, e escrever um ficheiro de configuração baseado nas suas respostas. Isso parece bastante fácil de fazer, mas depois considere as actualizações, e o que fazer quando alguém modifica o ficheiro de configuração que você gerou, e o dpkg-reconfigure, e...

Existem muitas maneiras de fazer isto, e a maioria delas estão erradas, e irão geralmente dar-lhe relatórios aborrecidos de bugs. Aqui está uma maneira certa de o fazer. Assume que o seu ficheiro de configuração é realmente apenas uma série de variáveis shell a serem definidas, com comentários pelo meio, e então você pode simplesmente usar a fonte do ficheiro para "carregá-lo". Se você tem um formato mais complicado, ler (e escrever) fica mais complicado.

O seu script config irá parecer algo como isto:


#!/bin/sh
CONFIGFILE=/etc/foo.conf
set -e
. /usr/share/debconf/confmodule


# Carrega ficheiro de configuração, se existir.
if [ -e $CONFIGFILE ]; then
. $CONFIGFILE || true


# Armazena valores do ficheiro de configuração na
# base de dados debconf.
db_set mypackage/foo "$FOO"
db_set mypackage/bar "$BAR"
fi


# Faz perguntas.
db_input medium mypackage/foo || true
db_input medium mypackage/bar || true
db_go || true

E o postinst irá parecer algo como isto:


#!/bin/sh
CONFIGFILE=/etc/foo.conf
set -e
. /usr/share/debconf/confmodule


# Gera ficheiro de configuração, se este não existir.
# Uma alternativa é copiar um ficheiro template
# de outro sítio.
if [ ! -e $CONFIGFILE ]; then
echo "# Config file for my package" > $CONFIGFILE
echo "FOO=" >> $CONFIGFILE
echo "BAR=" >> $CONFIGFILE
fi


# Substituto nos valores de debconf db.
# Existem optimizações óbvias possíveis aqui.
# O cp antes do sed assegura que não estragamos as
# permissões e dono do ficheiro de configuração.
db_get mypackage/foo
FOO="$RET"
db_get mypackage/bar
BAR="$RET"
cp -a -f $CONFIGFILE $CONFIGFILE.tmp


# Se o administrador apagou o comentou algumas variáveis mas depois
# definiu-as via debconf, (re-)adiciona-as ao ficheiro de configuração.
test -z "$FOO" || grep -Eq '^ *FOO=' $CONFIGFILE || \
echo "FOO=" >> $CONFIGFILE
test -z "$BAR" || grep -Eq '^ *BAR=' $CONFIGFILE || \
echo "BAR=" >> $CONFIGFILE


sed -e "s/^ *FOO=.*/FOO=\"$FOO\"/" \
-e "s/^ *BAR=.*/BAR=\"$BAR\"/" \
< $CONFIGFILE > $CONFIGFILE.tmp
mv -f $CONFIGFILE.tmp $CONFIGFILE

Considere como estes dois scripts lidam com todos os casos. Em instalações novas as perguntas são feitas pelo script config, e um novo ficheiro de configuração é gerado pelo postinst. Nas actualizações e reconfigurações, o ficheiro de configuração é lido, e os valores nele são usados para alterar os valores na base de dados debconf, portanto as modificações manuais do administrador não são perdidas. As questões são feitas de novo (e podem ser ou não ser mostradas). Depois o postinst substitui os valores de volta ao ficheiro de configuração, deixando o resto inalterado.

Poucas coisas são mais frustrantes que quando se usa um sistema como o debconf onde é-lhe feita uma pergunta, respondida, depois avança-se para outro écran com uma nova pergunta, e depois percebe-se que cometeu um erro na última pergunta, e você quer voltar atrás e descobre que já não pode.

Como o debconf é conduzido pelo seu script config, ele não pode saltar para uma questão anterior por si só, mas com alguma ajuda da sua parte, ele pode conseguir isso. O primeiro passo é fazer com que o seu script config faça o debconf saber que é capaz de lidar com um utilizador a carregar no botão de retroceder. Você usa o comando CAPB para fazer isto, passando backup como parâmetro.

Então após cada comando GO, você tem de testar para ver se o utilizador pediu para recuar (o debconf devolve um código de 30), e se sim, saltar de volta para a questão anterior.

Existem várias maneiras de escrever as estruturas de controle do seu programa para que possa saltar para questões anteriores caso necessário. Você pode escrever código goto-laden spaghetti. Ou pode criar várias funções e usar a recursão. Mas talvez o modo mais simples e limpo seja construir uma máquina de estado. Aqui está um exemplo de uma máquina de estado que você pode preencher e expandir.


#!/bin/sh
set -e
. /usr/share/debconf/confmodule
db_capb backup


STATE=1
while true; do
case "$STATE" in
1)
# Duas questões não relacionadas.
db_input medium my/question || true
db_input medium my/other_question || true
;;
2)
# Apenas faz esta pergunta se a
# primeira questão foi respondida em
# afirmativo.
db_get my/question
if [ "$RET" = "true" ]; then
db_input medium my/dep_question || true
fi
;;
*)
# O caso predefinido é capturado quando $STATE é maior que o
# último estado implementado, e sai fora do ciclo. Isto
# requer que os estados sejam numerados consecutivamente a partir de 1
# sem falhas, pois o caso predefinido também irá ser inserido
# se houver uma falha na numeração
break # sai do delimitador "enquanto" em ciclo
;;
esac


if db_go; then
STATE=$(($STATE + 1))
else
STATE=$(($STATE - 1))
fi
done


if [ $STATE -eq 0 ]; then
# O utilizador pediu para voltar atrás a partir da primeira
# questão. Este caso é problemático. Uma instalação
# de pacote regular do dpkg e apt não é capaz de
# andar para trás nas questões entre pacotes quando estas
# são escritas, portanto isto vai terminar deixando o pacote
# por configurar - provavelmente a melhor maneira de lidar com
# esta situação.
exit 10
fi

Note que se tudo o que o seu script config faz é perguntar algumas questões não relacionadas, então não há necessidade duma máquina de estado. Apenas pergunte-as todas e, GO; o debconf fará o seu melhor para apresentá-las todas no mesmo écran, e o utilizador não precisa de voltar a trás.

Acontece um problema com o debconf se você tem um ciclo no seu script config. Suponha que está a perguntar por uma entrada e a validá-la, e a usar um looping caso não seja válida:


ok=”
do while [ ! "$ok" ];
db_input low foo/bar || true
db_go || true
db_get foo/bar
if [ "$RET" ]; then
ok=1
fi
done

isto parece ok à primeira vista. Mas considere o que acontece se o valor de /foo/bar for "" quando se entra neste ciclo, e o utilizador tem a sua prioridade definida para alta, ou está a usar um frontend não-interactivo, e então não lhe é realmente pedido uma entrada. O valor de foo/bar não é alterado pelo db_input, e então falha ao testar e volta a repetir o ciclo vicioso...

Uma correcção para isto é certificar-se que antes de entrar no ciclo, o valor de foo/bar é definido para algo que passe no teste no ciclo. Então por exemplo se o valor predefinido de foo/bar for "1", você pode fazer RESET a foo/bar antes de entrar no ciclo.

Outra correcção é verifica o código de retorno do comando INPUT. Se for 30 então não está a ser mostrada ao utilizador a pergunta que pediu, e deve sair do ciclo.

Por vezes pode ser instalado um conjunto de pacotes relacionados, e você quer perguntar ao utilizador qual dos conjuntos deve ser usado por predefinição. Exemplos de tais conjuntos são os gestores de janelas, ou ficheiros do dicionário ispell.

Enquanto seria possível para cada pacote no conjunto simplesmente perguntar "Deve este pacote ser predefinido?", isto levaria a um monte de perguntas repetidas se estiverem a ser instalados vários pacotes. É possível com o debconf apresentar uma lista de todos os pacotes no conjunto e permitir ao utilizador escolher entre eles. Aqui está como.

Faz com que todos os pacotes no conjunto usem um template partilhado. Algo como isto:


Template: shared/window-manager
Type: select
Choices: ${choices}
Description: Selecciona o gestor de janelas predefinido.
Selecciona o gestor de janelas que será iniciado por
predefinição quando o X arranca.

Cada pacote deve incluir uma cópia do template. Depois deve incluir algum código como este no seu script config:


db_metaget shared/window-manager owners
OWNERS=$RET
db_metaget shared/window-manager choices
CHOICES=$RET


if [ "$OWNERS" != "$CHOICES" ]; then
db_subst shared/window-manager choices $OWNERS
db_fset shared/window-manager seen false
fi


db_input medium shared/window-manager || true
db_go || true

É preciso um pouco de explicação. Pela altura em que o seu script config corre, o debconf já leu todos os templates para os pacotes que estão a ser instalados. Como um conjunto de pacotes partilha uma questão, o debconf regista esse facto no campo owners. Por estranha coincidência, o formato do campo owners é o mesmo que aquele do campo choices (uma lista de valores delimitada por vírgulas e espaços).

O comando METAGET pode ser usado para obter a lista de donos e a lista de escolhas. Se forem diferentes, então foi instalado um novo pacote. Então use o comando SUBST para alterar a lista de escolhas para ser o mesmo que a lista de donos, e fazer a pergunta.

Quando um pacote é removido, provavelmente você quer ver se esse pacote é a escolha actualmente seleccionada, e se for, avisar o utilizado para seleccionar um pacote diferente para o substituir.

Isto pode ser conseguido ao adicionar algo como isto aos scripts prerm de todos os pacotes relacionados (substituindo <package> pelo nome do pacote):


if [ -e /usr/share/debconf/confmodule ]; then
. /usr/share/debconf/confmodule
# I no longer claim this question.
db_unregister shared/window-manager


# Vê se a questão partilhada ainda existe.
if db_get shared/window-manager; then
db_metaget shared/window-manager owners
db_subst shared/window-manager choices $RET
db_metaget shared/window-manager value
if [ "<package>" = "$RET" ] ; then
db_fset shared/window-manager seen false
db_input high shared/window-manager || true
db_go || true
fi


# Agora faz o que o script postinst fez
# para actualizar o link simbólico do gestor de janelas.
fi
fi

O debconf não está presentemente totalmente integrado com o dpkg (mas queremos mudar isto no futuro), e então actualmente são precisos alguns truques feiosos.

O pior destes involve meter o script config a correr. O modo como funciona agora é que o script config será executado quando o pacote é pré-configurado. Depois, quando o script postinst corre, arranca o debconf outra vez. O debconf percebe que está a ser usado pelo script postinst, e então desliga-se e corre corre o script config. Isto apenas funciona se o seu postinst carregar uma das bibliotecas do debconf, então os postinsts têm sempre que tratar disso. Nós esperamos dirigir-nos a isto mais tarde ao adicionar suporte explícito ao dpkg para debconf. O programa debconf(1) é um passo nesta direcção.

Um truque relacionado e fazer o debconf correr quando um script config, postinst, ou outro programa que o usa, arranque. Afinal de contas, eles esperam poder falar com o debconf imediatamente. A maneira que isto é conseguido por agora é que quanto um tal script carrega uma biblioteca do debconf (como /usr/share/debconf/confmodule), e o debconf não está já a correr, é arrancado, e uma nova cópia do script é re-executada. O único resultado apreciável é que você precisa de colocar a linha que carrega a biblioteca do debconf no topo do script, ou vão acontecer coisas esquisitas. Nós esperamos dirigir-nos a isto mais tarde ao alterar o modo como o debconf é invocado, e transformá-lo em algo como um daemon de transição.

É também um truque o modo como o debconf percebe que ficheiros templates deve carregar, e quando os carrega. Quando os scripts config, preinst e postinst invocam o debconf, ele descobre automaticamente onde está o ficheiro templates, e carrega-o. Os programas standalone que usam debconf irão fazer com que o debconf procure os ficheiro templates em /usr/share/debconf/templates/nome-do-programa.templates. E se um postrm quer usar debconf durante uma purga, os templates não estarão disponíveis a menos que o debconf tenha uma chance de carregá-los no seu postinst. Isto é uma trapalhada, mas inevitável. No futuro alguns destes programas poderão ser capazes de usar debconf-loadtemplate manualmente.

O comportamento histórico de /usr/share/debconf/confmodule de jogar com descritores de ficheiros e definindo um fd #3 que fala com debconf, pode causar todo o tipo de problemas quando um postinst corre em daemon, pois o daemon começa a falar com o debconf,e o debconf não consegue perceber quando o script termina. O comando STOP pode contornar isto. No futuro, estamos a considerar fazer com que a comunicação com o debconf aconteça por um socket ou outro mecanismo que não seja o stdio.

Debconf define DEBCONF_RECONFIGURE=1 antes de correr scripts postinst, então um script postinst que precise de evitar alguma operação cara quando reconfigurado pode olhar para essa variável. Isto é um truque porque o correcto seria passar $1 = "reconfigure", mas fazê-lo sem quebrar todos os postinsts que usam debconf é difícil. O plano de migração para fugir a este truque é encorajar as pessoas a escrever postinsts que aceitem "reconfigure", e quanto todos o fizerem, começar a passar esse parâmetro.

debconf(7) é o guia do utilizador do debconf.

A especificação debconf na política debian é a definição canónica do protocolo debconf. /usr/share/doc/debian-policy/debconf_specification.txt.gz

debconf.conf(5) tem muita informação útil, incluindo alguma informação acerca da base de dados backend.

Joey Hess <joeyh@debian.org>

Américo Monteiro <a_monteiro@netcabo.pt>, 2010,2012

Por favor comunique quaisquer erros de tradução para a_monteiro@netcabo.pt, l10n@debianpt.org, ou submeta um relatório de bug contra o pacote debconf.