Scroll to navigation

DEBCONF-DEVEL(7) Miscellaneous Information Manual DEBCONF-DEVEL(7)

НАЗВАНИЕ

debconf - руководство разработчика

ОПИСАНИЕ

Данное руководство помогает при разработке пакетов, использующих debconf.

Предполагается, что вы знакомы с debconf как пользователь, а также знакомы сосновами создания пакетов debian.

Это руководство начинается с описания двух новых файлов, которые добавляютсяв пакеты debian, если они используют debconf. Затем объясняется работапротокола debconf и описываются некоторые библиотеки, которые позволят вашимпрограммам работать с ним. В частности обсуждаются другие сценарии длясопровождения, которые обычно используются с debconf: сценарии postinst иpostrm. Далее рассматриваются более сложные темы, например, общие шаблоныdebconf, отладка и некоторые основные приёмы и ловушки при программированиис debconf. Завершает руководство описание имеющихся недостатков debconf.

СЦЕНАРИЙ НАСТРОЙКИ

Debconf добавляет дополнительный сценарий сопровождения, сценарий config,который служит для настройки сопровождающих сценариев, имеющихся в пакетахdebian (postinst, preinst, postrm и prerm). Сценарий config отвечает завыдачу всех вопросов настройки пакета.

Замечание: часто смущает тот факт, что dpkg ссылается на запущенный сценарийпакета postinst как на «настроечный», хотя пакет, который использует debconfчасто полностью настроен своим сценарием config ещё до того как postinstдаже будет запущен. Такие дела.

Как и postinst, сценарию config передаётся два параметра при запуске. Впервом задаётся действие, которое нужно выполнить, а во втором — версияустановленного в данный момент пакета. Как и в postinst, вы можете применитьdpkg --compare-versions к $2, чтобы выполнить данную команду только приобновлении с определённой версии пакета и тому подобных операций.

Сценарий config может быть запущен в трёх случаях:

1
Во время предварительной настройки пакета из dpkg-preconfigure, которыйзапускает сценарий config с параметрами «configure» и номером установленнойверсии.
2
При запуске postinst из пакета, debconf также попытается запустить сценарийconfig и передать те же параметры, что и в случае с предварительнойнастройкой пакета. Это необходимо, так как пакет может не бытьпредварительно настроен, и сценарию config даётся ещё одна попыткаотработать. Подробней смотрите в разделе ХАКИ.
3
При повторной настройке пакета с помощью dpkg-reconfigure, где сценарийconfig запускается с параметрами «reconfigure» и номером установленнойверсии.

Заметим, что так как типичная установка или обновление с помощью aptпопадают под случаи 1 и 2, сценарий config обычно запускается дважды. Онничего не должен делать во второй раз (отвечать на вопросы второй раз подрядраздражает), и определённо должен быть идемпотентен. К счастью, debconfизбегает повторения вопросов по умолчанию, поэтому это легко достигается.

Заметим, что сценарий config запускается перед распаковкой пакета. В нёмдолжны использоваться только команды из пакетов первойнеобходимости. Единственная зависимость пакета, которая будет удовлетворенадо запуска сценария config — это сам debconf (возможно указать версию).

Сценарию config ничего не нужно изменять в файловой системе. Он долженпросто проверить состояние системы и задать вопросы, а debconf сохранитответы, которые требуют действий позже из сценария postinst. И наоборот,сценарий postinst не должен использовать debconf для задания вопросов, авместо этого должен полагаться на ответы, полученные при работе сценарияconfig.

ФАЙЛ TEMPLATES

Пакету, использующему debconf, вероятно требуется задать некоторыевопросы. Эти вопросы хранятся в форме шаблона в файле templates.

Как и сценарий config, файл templates находится в секции control.tar.gz debфайла. Его формат похож на формат debian файла control; секции строк,разделённые символами новой строки, каждая строка задана в RFC822-подобнойформе:


Template: foo/bar
Type: string
Default: foo
Description: Это пример строки вопроса.
Это её дополнительное описание.
.
Заметим что:
- как и в описании пакета debian точка
в отдельной строке начинает новый параграф.
- для большого текста выполняется перенос на новую строку, но текст
с двойным отступом выводится как есть,
вы можете использовать это для показа списков
как сделано здесь. Осторожно, так как
перенос не выполняется, это очень плохо сказывается на слишком
длинных строках. Используйте это для коротких элементов
(поэтому это плохой пример).


Template: foo/baz
Type: boolean
Description: Вроде всё просто?
Это другой вопрос, логического типа.

Несколько рабочих примеров для файлов templates можно найти в/var/lib/dpkg/info/debconf.templates и других файлах .templates в этомкаталоге.

Давайте рассмотрим каждое из полей по очереди..

Название шаблона в поле «Template» обычно начинается с названияпакета. Далее можно использовать что угодно; вы можете использовать простуюсхему как в предыдущем примере или настроить «подкаталоги», содержащиепохожие вопросы.
Тип шаблона, который определяет какого вида будет показанэлемент. Поддерживаются:
Поле ввода произвольных данных, в которое пользователь может ввести любуюстроку.
Предлагает пользователю ввести пароль. Используйте с осторожностью; этотпароль будет сохранён в базу данных debconf. Вероятно, вы должны удалить этозначение из базы как можно быстрее.
Выбор true/false.
Выбор одного из указанных значений. Значения должны быть заданы в поле«Choices». Разделителями значений могут быть запятые и пробелы:

Choices: да, нет, может_быть
Как и в типе данных select, выбор из списка, кроме того, что пользовательможет выбрать сразу несколько значений из списка (или ни одного из них).
Вместо вопроса как такового, этот тип данных задаёт примечание, котороеможет быть показано пользователю. Данный тип должен использоваться толькодля важных сообщений, которые пользователи обязательно должны увидеть, таккак debconf обязательно сделает так, чтобы пользователь увидел это;установка остановится, пока не будет нажата клавиша. Данный тип лучшеиспользовать только для предупреждений о серьёзных проблемах.
Этот тип данных используется для сообщений об ошибках, таких как ошибкиввода данных. Debconf покажет вопрос этого типа даже если приоритет самыйвысокий и пользователь уже видел этот вопрос.
Этот тип данных используется для заголовков, которые устанавливаютсякомандой SETTITLE.
Данный тип данных может быть использован для показа частей текста, напримерярлыков, которые могут использоваться в косметических целях отображениянекоторыми интерфейсами. Некоторые интерфейсы вообще не используют этоттип. Пока нет общих принципов по использованию его, так как нет интерфейсов,которые поддерживают его хорошо. Может в будущем он будет вообще удалён.
Поле «Default» указывает debconf, какое должно быть значение поумолчанию. Для multiselect это может быть список значений, разделённыхзапятыми или пробелами, как в поле «Choices». Для select — это одно значениеиз списка. Для boolean — это «true» или «false», хотя может использоватьсялюбая строка, и она игнорируется для паролей.

Не подумайте, что поле значения по умолчанию содержит «ответ» на вопрос, иличто он может быть использован для замены ответа на вопрос. Это не так, и неможет быть так, он только предоставляет ответ по умолчанию при первом показевопроса. Чтобы изменить значение по умолчанию на лету, используйте командуSET.

Поле «Description» подобно полю описания в пакете Debian, имеет две части:короткое описание и расширенное описание. Заметим, что некоторые интерфейсык debconf не отображают длинное описание, или могут показать его, толькоесли пользователь попросит показать помощь. Поэтому короткое описание должноотображать всю суть вопроса.

Если вы не можете придумать длинного описания, то сначала подумайте ещёнемного. Напишите в debian-devel. Попросите помочь. Возьмите урок понаписанию! Длинное описание очень важно. Если после всего этого ничего неприходит в голову, оставьте поле пустым. Нет смысла дублировать то, что уженаписано в коротком описании.

Текст в расширенном описании будет переноситься по словам, если он неначинается с дополнительного пробельного символа (после первогообязательного пробела). Вы можете разбить его на параграфы поместив « .» впустой строке между параграфами.

ВОПРОСЫ

Вопрос — это проиллюстрированный шаблон. Прося debconf показать вопрос,таким образом ваш сценарий config может взаимодействовать спользователем. Когда debconf загружает файл templates (это происходит призапуске сценария config или postinst), он автоматически показывает вопроскаждого шаблона. На самом деле можно показать несколько независимых вопросовиз одного шаблона (с помощью команды REGISTER), но это требуетсяредко. Шаблоны — это статические данные из файла templates, а вопросыиспользуются для хранения динамических данных, таких как имеющийся ответ навопрос, видел ли пользователь уже этот вопрос и тому подобное. Помните обэтом различии между шаблоном и вопросом, но не стоит сильно забивать этимголову.

ОБЩИЕ ШАБЛОНЫ

Фактически, есть возможность иметь один шаблон и вопрос сразу для несколькихпакетов. Все пакеты могут предоставлять идентичную копию шаблона в своихфайлах templates. Это может быть полезно, если набору пакетов требуетсязадать один и тот же вопрос, а вы хотите побеспокоить пользователя толькоодин раз. Общие шаблоны обычно помещаются в псевдокаталог shared/ впространстве имён шаблонов debconf.

ПРОТОКОЛ DEBCONF

Сценарии config взаимодействуют с debconf по протоколу debconf. Это простойоднострочный протокол, похожий на основные протоколы интернета, типаSMTP. Сценарий config посылает debconf команду, записывая эту команду встандартный вывод. Затем, он может прочитать ответ debconf со стандартноговвода.

Ответы debconf можно разделить на две части: числовой код результата (первоеслово в ответе) и необязательный расширенный код результата (оставшаясячасть ответа). В числовом коде значение 0 соответствует успешномувыполнению, а другие числа указывают на различного вида неудачи. Подробнейсмотрите таблицу в политике Debian, раздел спецификации debconf.

Расширенный код результата имеет любой вид и никак не стандартизован,поэтому нужно игнорировать его и не пытаться использовать в своей программедля выяснения что делает debconf. Исключение составляют команды типа GET,которая создаёт значение для возврата в расширенном коде результата.

Обычно вы будете использовать библиотеку, которая работает на низком уровнедля установления связи с debconf и взаимодействия с ним.

А теперь обсудим команды протокола. Это не полное описание, за нимобращайтесь к документу о политике Debian, раздел спецификации debconf.

Обычно не нужно использовать эту команду. Она позволяет договориться сdebconf о том, какая версия протокола должна быть использована. Текущаяверсия протокола — 2.0, а версии ветки 2.x обратно совместимы. Вы можетеуказать номер версии протокола и debconf вернёт версию протокола врасширенном коде результата. Если указанная вами версия слишком стара,debconf вернёт числовой код 30.
Обычно не нужно использовать эту команду. Она позволяет обменяться с debconfсписком поддерживаемых возможностей (разделяются пробелами). Будутиспользованы возможности, которые поддерживаются вами и debconf, а debconfвернёт список всех поддерживаемых им возможностей.

Если среди ваших возможностей будет «escape», то debconf будет ожидать, чтов посылаемых вами командах символы обратный слеш и новой строки экранированы(\\ и \n соответственно), а в своих ответах будет также это делать. Этоможет быть использовано, например, для подстановки многострочных строк вшаблонах, или для получения многострочных расширенных описаний,использующихся в METAGET. В этом режиме вы должны сами экранировать входнойтекст (для этого вы можете использовать команду debconf-escape(1), если хотите), а библиотеки confmodule будут снимать экранирования в ответах за вас.

Устанавливает заголовок, который debconf показывает пользователю, используякороткое описание шаблона указанного вопроса. Шаблон должен быть типаtitle. Обычно редко используется, так как debconf может автоматическигенерировать заголовок на основе имени пакета.

Установка заголовка из шаблона означает, что они хранятся в том же месте чтои все вопросы debconf, и их можно переводить на другие языки.

Устанавливает заголовок, который debconf показывает пользователю, используязаданную строку. Использование команды SETTITLE предпочтительно, так какпозволяет переводить заголовок на другие языки.
Просит debconf подготовить к показу вопрос пользователю. Вопрос непоказывается до тех пор пока не будет дана команда GO; это позволяетпоследовательно задать несколько команд INPUT для накопления наборавопросов, которые могут быть заданы все разом на одном экране.

Поле приоритета говорит debconf насколько важен вопрос, который будетпоказан пользователю. Значения приоритета:

Очень простые элементы со значениями по умолчанию, которые работают вподавляющем большинстве случаев; только параноики увидят их.
Обычные элементы с корректными значениями по умолчанию.
Элементы, у которых нет приемлемых значений по умолчанию.
Элементы, которые вероятно сломают систему, если не будет вмешательствапользователя.

Debconf сам решает нужно ли вообще показывать вопрос, основываясь на этомприоритете и том, видел ли уже пользователь этот вопрос и какой интерфейсиспользуется для показа. Если вопрос не будет показан, debconf возвращаеткод 30.

Указывает debconf показать накопленные вопросы (переданные ранее командамиINPUT) пользователю.

Если поддерживается возможность backup и пользователь потребовал вернутьсяна шаг назад, то debconf возвратит код 30.

Очистить накопленные вопросы (из команд INPUT) и не показывать их.
Некоторые интерфейсы debconf могут показывать пользователю сразу нескольковопросов одновременно. Может быть в будущем интерфейсы даже смогутгруппировать такие вопросы по блокам на экране. BEGINBLOCK и ENDBLOCK могутуказываться вокруг набора команд INPUT, чтобы обозначить блоки вопросов (иблоки могут быть вложенными). Так как пока ни один интерфейс к debconf неподдерживает их, в данный момент эти команды игнорируются.
Эта команда указывает debconf на завершения взаимодействия с ним. Частоdebconf может сам обнаружить завершение вашей программы и эта команда необязательна.
После отработки INPUT и GO для показа вопроса, вы можете использовать этукоманду для получения значения введённого пользователем. Значениевозвращается в виде расширенного кода результата.
Задаёт ответ на вопрос; это можно использовать для замены ответа поумолчанию чем-то, что ваша программа вычислила во время работы.
Сбрасывает ответ на вопрос в значение по умолчанию (как указано в поле«Default» в шаблоне).
Вопросы могут содержать подстановки в полях «Description» и «Choices» (хотяиспользование подстановок в полях «Choices» считается хаком; со временембудет разработан лучший способ). Эти подстановки выглядят как"${ключ}". Когда вопрос отображается, подстановки заменяются на нужныезначения. Эта команда может быть использована для задания значенияподстановки. Это полезно, если вам требуется показать какое-то сообщениепользователю, которое нельзя однозначно записать в файл templates.
Не пытайтесь использовать SUBST для замены ответа по умолчанию на вопрос;это не сработает, так как для этого служит команда SET.
Вопросы могут иметь связанные с ними флаги. Флаги могут иметь значение«true» или «false». Эта команда возвращает значение флага.
Устанавливает значение флага вопроса. Значение должно быть или «true» или«false».

Распространённым флагом является флаг «seen». Обычно он устанавливаетсятолько если пользователь уже видел вопрос. Debconf обычно показывает толькоте вопросы пользователю, у которых флаг seen установлен в «false» (или еслипроисходит процесс перенастройки пакета). Иногда вам нужно чтобыпользователь увидел вопрос снова — в этом случае вы можете установить флагseen в значение «false», чтобы заставить debconf показать вопрос ещё раз.

Возвращает значение любого поля вопроса из соответствующего шаблона(например, Description).
Создаёт новый вопрос, который привязывается к шаблону. По умолчанию, каждыйшаблон имеет соответствующий вопрос с тем же именем. Однако, с шаблономможно связать любое число вопросов, и это позволяет создать много такихвопросов.
Удаляет вопрос из базы данных.
Вызывайте эту команду из сценария postrm при вычистке пакета. Она удалит всевопросы пакета из базы данных debconf.
Это расширение загружает указанный файл template в базу данных debconf. Поумолчанию, владельцем считается пакет, который в данный момент настраиваетсяdebconf.

Вот простой пример протокола debconf в действии.


INPUT medium debconf/frontend
30 question skipped
FSET debconf/frontend seen false
0 false
INPUT high debconf/frontend
0 question will be asked
GO
[ Здесь debconf показывает вопрос пользователю. ]
0 ok
GET no/such/question
10 no/such/question doesn't exist
GET debconf/frontend
0 Dialog

БИБЛИОТЕКИ

Настройка окружения для работы с debconf и общение с debconf по протоколувручную требует слишком больших затрат, поэтому для этого существуютпромежуточные библиотеки, которые освобождают человека от этой монотоннойработы.

Для программирования на языке оболочки командной строки существуетбиблиотека /usr/share/debconf/confmodule, которую вы можете указать в началесценария оболочки, и общаться с debconf в довольно естественной манере,используя команды debconf протокола записанные строчными буквами, которыеначинаются с «db_» (то есть, «db_input» и «db_go»). Подробней смотрите вconfmodule(3).

Программисты на perl могут использовать модульDebconf::Client::ConfModule(3pm), а программисты на python могут использовать модуль debconf.

В последующих примерах сценариев оболочки руководства будет использованабиблиотека /usr/share/debconf/confmodule. Вот пример сценария config,который задаёт вопрос с помощью этой библиотеки:


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

Заметим, что использование "|| true" предотвращает сценарий от завершенияработы, если debconf решит, что не может показать вопрос, или когдапользователь решит вернуться к предыдущему вопросу. В таких ситуацияхdebconf возвращает ненулевой код возврата, и так как в сценарии оболочкиуказана set -e, неотловленный код выхода прервёт его работу.

А вот соответствующий сценарий postinst, который использует пользовательскийответ на вопрос, должна ли система быть перезагружена (слегка абсурдныйпример..):


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

Заметим, что используемая переменная $RET получает расширенный код возвратаот команды GET, который содержит ответ пользователя на вопрос.

СЦЕНАРИЙ POSTINST

В последнем разделе был приведён пример сценария postinst, которыйиспользует debconf для получения ответа на вопрос и выполняетсоответствующие действия. Есть несколько вещей о которых нужно помнить принаписании сценариев postinst, использующих debconf:

*
Не задавайте вопросов из сценария postinst. Вопросы должен задавать сценарийconfig с помощью debconf, для того чтобы работал механизм предварительнойнастройки.
*
Всегда включайте /usr/share/debconf/confmodule в самом начале сценарияpostinst, даже если не будет использоваться никаких команд db_*. Это нужнодля того, чтобы дать шанс запуститься сценарию config (подробней смотрите вразделе ХАКИ).
*
Избегайте вывода чего-либо в stdout из сценария postinst, так как этоdebconf может неправильно понять и вообще, сценарий postinst не должен бытьслишком разговорчивым. Если очень нужно — выводите в stderr.
*
Если сценарий postinst запускается в режиме демона, убедитесь, что выпослали debconf команду STOP в конце работы, так как debconf не сможетотловить момент когда postinst закончил с ним работать.
*
Пишите сценарий postinst так, чтобы он принимал первым параметром«reconfigure». Он может трактовать его как «configure». Это будетиспользовано в следующих версиях debconf, чтобы указать сценариям postinstкогда они должны выполнять перенастройку.

ДРУГИЕ СЦЕНАРИИ

Кроме сценариев config и postinst, вы можете использовать debconf в любомсценарии сопровождения пакета. Наиболее часто вы будете использовать debconfв сценарии postrm, чтобы вызвать команду PURGE при удалении пакета дляудаления всех записей о пакете из базы данных debconf (кстати, этонастраивается автоматически с помощью dh_installdebconf(1)).

Также debconf может быть использован в сценарии postrm при вычистке пакетачтобы задать вопрос об удалении чего-либо. Или может быть по какой-топричине вам может потребоваться использовать его в preinst или prerm. Вездеон будет работать, хотя это вероятно приведёт к выдаче одинаковых вопросов иреакции на ответы в программе, а не к двум разным действиям, как этопроисходит со сценариями config и postinst.

Заметим, что если ваш пакет использует debconf только в сценарии postrm, выдолжны добавить вызов /usr/share/debconf/confmodule в начало сценарияpostinst, чтобы дать debconf шанс загрузить файл templates в свою базуданных. Затем templates будет доступен во время вычистке пакета.

Также вы можете использовать debconf просто в работе программ. Но незабывайте, что debconf не предназначен для этого, и не должен использоватьсякак своеобразный реестр. Это всё-таки unix, и настройки программ хранятся вфайлах в каталоге /etc, а не в какой-то мутной базе данных debconf (котораяв конечном счёте просто кэш и может сломаться). Так что тридцать разподумайте перед тем как использовать debconf в простых программах.

Есть ситуации когда это имеет смысл, например в программе apt-setup, котораяиспользует debconf для того чтобы пользователь завершил процесс установкиdebian в похожем интерфейсе, и сразу же применяет эти ответы для настройкифайла sources.list программы apt.

ЛОКАЛИЗАЦИЯ

Debconf поддерживает локализацию файлов templates. Это достигаетсядобавлением дополнительных полей с переведённым текстом. Любые поля можнопереводить. Например, есть желание перевести описание на испанский. Простосоздайте поле с именем «Description-es», в котором есть перевод. Еслипереведённое поле недоступно, debconf использует обычный английский вариант.

Помимо поля «Description», вы можете перевести поле «Choices» из шаблонаselect или multiselect. Убедитесь, что переведённые значения в спискерасположены в том же порядке что и в основном поле «Choices». Вам не нужнопереводить поле «Default» из вопроса select или multiselect, ответ на вопросбудет автоматически возвращён на английский.

Вы обнаружите, что для облегчения управления переводами лучше хранить их вотдельных файлах; один файл на перевод. Раньше для управления файламиdebian/template.ll использовались программы debconf-getlang(1) и debconf-mergetemplate(1). Теперь эту функцию выполняет пакет po-debconf(7), который позволяет работать с переводами debconf в .po файлах как с любыми другими переводами. Ваши переводчики будут благодарны вам за использование этого нового усовершенствованного механизма.

Подробней о po-debconf смотрите в его справочной странице. Если выиспользуете debhelper, переведите его в po-debconf просто запустив один разкоманду debconf-gettextize(1) и добавьте зависимость в Build-Dependency от po-debconf и от debhelper (>= 4.1.13).

СОБЕРЁМ ВСЁ ВМЕСТЕ

Итак, у вас есть сценарий config, файл templates, сценарий postinst,использующие debconf и так далее. Поместить все эти части в пакет debianнесложно. Вы можете сделать это вручную или с помощьюdh_installdebconf(1), которая объединяет переведённые шаблоны, копирует файлы в нужные места, и даже генерирует вызов PURGE, который должен быть в сценарии postrm. Убедитесь, что ваш пакет зависит от debconf (>= 0.5), так как более ранние версии несовместимы с всем описанным в руководстве. Всё.

Да, за исключением тестирования, отладки и реального использования debconfдля более интересных вещей чем простое задание вопросов. Об этом читайтедалее..

ОТЛАДКА

Итак, у вас есть пакет, который предположительно использует debconf, но онне совсем работает. Может быть debconf не только задаёт вопросы принастройке. Или может быть что-то странное случается; он крутится в каком-товечном цикле или хуже. К счастью, debconf обладает множеством средствотладки.

Наипервейшая вещь — это переменная окружения DEBCONF_DEBUG. Если вы сделаетеexport DEBCONF_DEBUG=developer, то debconf будет выводить в stderr дамппротокола debconf при работе. Это выглядит как-то так(сразу видно опечатку):


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

Для отладки довольно полезно использовать интерфейс debconf readline(помнению автора), поскольку вопросы не мешают и весь отладочный вывод легкосохранить.

Если значение данной переменной окружения равно «true», то интерфейснаяпрограмма будет показывать значения шаблонов Choices-C (если есть) выбора имножественного выбора, вместо описательных значений.
Другим полезным инструментом является программаdebconf-communicate(1). Просто запустите её и вы сможете интерактивно вводить команды протокола debconf непосредственно в debconf. Это отличный способ попробовать команды на лету.
Если пользователь сообщил о проблеме, можно использовать debconf-show(1), чтобы скопировать все вопросы пакета, показать их ответы и узнать какие из них видел пользователь.
.debconfrc
Чтобы избежать утомительного цикла сборка/установка/отладка, можно загрузитьфайл templates с помощью debconf-loadtemplate(1) и запустить сценарий config вручную с помощью команды debconf(1). Однако, вам по прежнему требуются права суперпользователя? Не очень здорово. И в идеале вы хотели бы увидеть как проходит новая установка, с чистой базой данных debconf.

Оказывается, если вы настроите файл ~/.debconfrc для обычного пользователя,указав в нём личный config.dat и template.dat, то сможете загружать файлыtemplates и запускать сценарий config как хочется, без полномочийсуперпользователя. Если нужно ещё раз запуститься с чистой базой данных,просто удалите файлы *.dat.

Подробности настройки смотрите в debconf.conf(5), и заметим, что файл /etc/debconf.conf отлично подойдёт как шаблон для личного файла ~/.debconfrc.

УГЛУБЛЁННОЕ ПРОГРАММИРОВАНИЕ С DEBCONF

Работа с файлами настройки

Многие из вас хотели бы использовать debconf для управления файламинастройки пакета. Возможно в файлах настройки недостаточно настроек поумолчанию и поэтому вы бы хотели использовать debconf для опросапользователя и основываясь на его ответах создавать файл настройки. Кажется,что этого легко достичь, но когда вы задумаетесь об обновлении, или когдакто-то ещё изменит файл настройки, созданный вами и про dpkg-reconfigure и...

Есть много способов сделать это и большинство из них неправильные, а выбудете получать раздражающие отчёты об ошибках. Есть один правильный путьдостижения этого. В нём предполагается, что ваш файл настройки состоит изпростого набора устанавливаемых переменных оболочки с комментариями, ипоэтому вы можете просто выполнить файл для его «загрузки». Если у вас болеесложный формат, чтение (и запись) становятся более сложными.

Ваш сценарий config будет выглядеть так:


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


# Загрузить файл настройки, если он существует.
if [ -e $CONFIGFILE ]; then
. $CONFIGFILE || true


# Сохранить значения из файла настройки в
# базу данных debconf.
db_set mypackage/foo "$FOO"
db_set mypackage/bar "$BAR"
fi


# Задать вопросы.
db_input medium mypackage/foo || true
db_input medium mypackage/bar || true
db_go || true

А сценарий postinst будет выглядеть так:


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


# Сгенерировать файл настройки, если он не существует.
# Или скопировать из файла шаблона
# откуда-то ещё.
if [ ! -e $CONFIGFILE ]; then
echo "# Config file for my package" > $CONFIGFILE
echo "FOO=" >> $CONFIGFILE
echo "BAR=" >> $CONFIGFILE
fi


# Выполнить подстановку значений из базы данных debconf.
# Здесь явно возможна оптимизация.
# Команда cp перед sed проверяет, что мы не испортили
# права доступа и владельца файла настройки.
db_get mypackage/foo
FOO="$RET"
db_get mypackage/bar
BAR="$RET"
cp -a -f $CONFIGFILE $CONFIGFILE.tmp


# Если администратор удалил или закомментировал какие-то переменные, но
# после задал их через debconf, добавим(пересоздадим) их в файле
# настройки.
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

Рассмотрим как эти два сценария обрабатывают все возможные ситуации. Приначальной установке сценарий config задаёт вопросы и новый файл настройкигенерируется сценарием postinst. При обновлении или перенастройке файлнастройки читается и его значения используются для изменения значений в базеданных debconf, поэтому значения, изменённые администратором, нетеряются. Вопросы задаются снова (могут показываться, а могут и нет). Затемсценарий postinst выполняет подстановку значений обратно в файл настройки,не изменяя всего остального.

Позволить пользователю возвращаться назад

Некоторые вещи ещё сильнее разочаровывают при использовании систем типаdebconf: после заданного вопроса и ответа на него, переходишь к другомуэкрану с новым вопросом, и отвечая понимаешь, что совершил ошибку впоследнем вопросе и хочешь вернуться обратно и обнаруживаешь, что не можешьсделать этого.

Так как debconf управляется вашим сценарием config, он не может прыгнутьобратно на предыдущий вопрос сам, но с небольшой вашей помощью, он сможетвыполнить этот подвиг. Первый шаг — в сценарии config дать понять debconf,что сценарий config способен обрабатывать нажатие кнопки назадпользователем. Для этого используйте команду CAPB, передав backup в качествепараметра.

Затем, после каждой команды GO вы должны выполнять тест, чтобы увидетьпросил ли пользователь вернуться назад (debconf возвратит код 30), и, еслиэто произошло, возвратиться к предыдущему вопросу.

Есть несколько способов написания управляющих структур в вашей программе длявозвращения к предыдущему вопросу при необходимости. Вы можете написать код,использующий кучу команд перехода goto. Или вы можете создать несколькофункций и использовать рекурсию. Но возможно самым понятным и простымявляется создание конечного автомата. Вот скелет конечного автомата, которыйможно заполнить и расширить.


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


STATE=1
while true; do
case "$STATE" in
1)
# Два несвязных вопроса.
db_input medium my/question || true
db_input medium my/other_question || true
;;
2)
# Задавать этот вопрос, только если
# на первый был получен
# положительный ответ.
db_get my/question
if [ "$RET" = "true" ]; then
db_input medium my/dep_question || true
fi
;;
*)
# Действие по умолчанию возникает, когда $STATE больше чем последнее
# введённое состояние и прерывает цикл. Для
# этого требуется, чтобы состояния были пронумерованы последовательно с 1
# без перерывов, так как в этом случае возникает событие по умолчанию
break # выход из обёртывающего цикла "while"
;;
esac


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


if [ $STATE -eq 0 ]; then
# Пользователь хочет выйти из первого вопроса.
# Это проблематичный случай. Обычная установка
# пакетов с помощью dpkg и apt не даёт
# вернуться к вопросам между пакетами как здесь написано,
# поэтому завершить работу, оставив пакет ненастроенным,
# вероятно, лучший путь обработки этой ситуации.
exit 10
fi

Заметим, что если ваш сценарий config задаёт несколько несвязных между собойвопросов, то конечный автомат не нужен. Просто задайте их все и GO; debconfпокажет их все на одном экране, и пользователю не нужно возвращаться назад.

Предотвращение бесконечных циклов

Это может произойти с debconf, если в сценарии config естьцикл. Предположим, вы задаёте вопрос и проверяете ответ, и всё это в циклепока ответ не станет правильным:


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

На первый взгляд всё выглядит хорошо. Но посмотрим что произойдёт, еслизначение foo/bar будет "" в начале цикла, а пользователь установил приоритетна высокий, или использует не интерактивный интерфейс, и поэтому вопрос насамом деле задан не будет. Значение foo/bar не изменяется в db_input, и тестне проходит и повторяется. И всё зацикливается …

Одним вариантом исправления является задание значения foo/bar перед входом вцикл. Например, если значение по умолчанию foo/bar равно «1», то вы можетевыполнить RESET foo/bar перед входом в цикл.

В другом варианте можно проверить код завершения команды INPUT. Если онравен 30, то пользователю вопрос показан не был, и вы должны прервать цикл.

Выбор из похожих пакетов

Иногда может выполняться установка похожих по функциональности пакетов, и выхотели бы предложить пользователю выбрать пакет, который должениспользоваться по умолчанию. Примером таких наборов могут быть оконныеменеджеры или файлы словарей ispell.

Хотя можно для каждого пакета задавать простой вопрос «Использовать этотпакет по умолчанию?», но это приведёт к большому числу повторяющихсявопросов, если устанавливается несколько пакетов. С помощью debconf возможносоздать список всех пакетов и позволить пользователю сделать из неговыбор. Посмотрим как это делается.

Сделайте так, чтобы все пакеты в наборе использовали общий шаблон. Например:


Template: shared/window-manager
Type: select
Choices: ${choices}
Description: Выбор оконного менеджера по умолчанию.
Определяет выбранный оконный менеджер, который запускается
по умолчанию при запуске X.

Каждый пакет должен содержать копию этого шаблона. Также нужно включить кодв свой сценарий 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

Объяснение. Во время запуска сценария config, debconf уже прочитал всешаблоны для устанавливаемых пакетов. Так как эти пакеты используют общийвопрос, debconf записывает этот факт в поле владельцев. По странномусовпадению формат поля владельцев такой же как и у поля выбора (запятая ипробел являются разделителями в списке значений).

Команда METAGET может использоваться для получения списка владельцев исписка выбора. Если они различаются, то это значит, что был установлен новыйпакет. Поэтому используется команда SUBST для замены списка выбора на списоквладельцев и задаётся вопрос.

При удалении пакета вы вероятно хотите проверить не является этот пакетвыбранным в списке, и если так, то попросить пользователя выбрать другойпакет по умолчанию на замену.

Это можно выполнить добавив следующее в сценарии prerm всех похожих пакетов(заменив <package> именем пакета):


if [ -e /usr/share/debconf/confmodule ]; then
. /usr/share/debconf/confmodule
# больше не задавать этот вопрос.
db_unregister shared/window-manager


# Проверить, что общий вопрос ещё существует.
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


# Теперь сделать тоже что делает сценарий postinst
# для обновления символической ссылки оконного менеджера.
fi
fi

ХАКИ

В настоящее время debconf не полностью интегрирован с dpkg (но я хочуизменить это в будущем), и поэтому сейчас вызывается для некоторыхнеприятных хаков.

Худшие из них требуют запуска сценария config. Для этого в настоящий моментприходится запускать сценарий config во время предварительной настройкипакета. Также, при запуске сценария postinst, снова запускаетсяdebconf. Debconf понимает, что запускается из сценария postinst и поэтомуостанавливается и запускает сценарий config. Это работает, только если вашpostinst загружает хотя бы одну из библиотек debconf, поэтому postinstвсегда делает это. Мы надеемся вернуться к этому позже добавив явнуюподдержку в dpkg для debconf. Программа debconf(1) — это шаг в данном направлении.

Похожий хак — запуск debconf когда сценарии config, postinst или другиепрограммы используют его при запуске. Не смотря ни на что, они ожидают чтобудут сразу общаться с debconf. Сейчас это выполняется, так что когда такойсценарий загружает библиотеку debconf (типа /usr/share/debconf/confmodule),а debconf ещё не запущен, он запускается, и новая копия сценария выполняетсязаново. Заметный результат в том, что вам нужно указывать строку загрузкибиблиотеки debconf как можно ближе к началу сценария, или могут случитьсянепонятные вещи. Мы надеемся вернуться к этой проблеме позже изменив вызовdebconf, и превратить его в что-то подобное отдельного демона.

Сравнимо с хаком и то, как debconf выясняет какие файл шаблонов загружены икогда их загружать. Когда сценарии config, preinst и postinst вызываютdebconf, он автоматически выясняет где файл templates и загружаетего. Отдельные программы, использующие debconf, заставляют debconf искатьфайл шаблонов в /usr/share/debconf/templates/имя_программы.templates. И еслиpostrm хочет использовать debconf при вычистке, шаблоны будут недоступныесли только у debconf не будет шанса загрузить их в postinst. Не неприятно,но неизбежно. Хотя в будущем некоторые из таких программ смогут использоватьdebconf-loadtemplate вручную.

Исторически сложившееся поведение /usr/share/debconf/confmodule играть сфайловыми дескрипторами и устанавливать fd #3 через который происходитобщение с debconf, может вызывать весь набор проблем при запуске из postinstдемона, так как демон завершает общение с debconf, а debconf не можетопределить когда завершился сценарий. Команда STOP помогает обойти это. Вбудущем, мы рассмотрим создание связи с debconf через сокет или другоймеханизм отличный от stdio.

Debconf устанавливает DEBCONF_RECONFIGURE=1 перед запуском сценариевpostinst, поэтому сценарий postinst, которому требуется избежать некоторойзатратной операции перед перенастройкой, может проверить наличие этойпеременной. Это хак, так как правильно сделать это — передать $1 =«reconfigure», но этого делать нельзя, так как будут работать неправильновсе сценарии postinst, использующие debconf. Разработан план перехода наприём сценариями postinst значения «reconfigure», и как только все сделаютэто, начнётся передача этого параметра.

СМОТРИТЕ ТАКЖЕ

В debconf(7) содержится руководство пользователя debconf.

Описание debconf в политике debian является спецификацией протоколаdebconf. /usr/share/doc/debian-policy/debconf_specification.txt.gz

debconf.conf(5) содержит много полезной информации, включая описание среды хранения базы данных.

АВТОР

Joey Hess <joeyh@debian.org>