DEBCONF-DEVELSection: Maintenance Commands (8)
Return to Main Contents
NAMEdebconf - developers guide
DESCRIPTIONThis is a guide for developing packages that use debconf. This manual assumes that you are familiar with debconf as a user, and are familiar with the basics of debian package construction. This manual begins by explaining two new files that are added to debian packages that use debconf. Then it explains how the debconf protocol works, and points you at some libraries that will let your programs speak the protocol. It discusses other maintainer scripts that debconf is typically used in: the postinst and postrm scripts. Then moves on to more advanced topics like shared debconf templates, debugging, and some common techniques and pitfalls of programming with debconf. It closes with a discussion of debconf's current shortcomings.
THE CONFIG SCRIPTDebconf adds an additional maintainer script, the config script, to the set of maintainer scripts that can be in debian packages (the postinst, preinst, postrm, and prerm). The config script is responsible for asking any questions necessary to configure the package. Note: It is a little confusing that dpkg refers to running a package's postinst script as "configuring" the package, since a package that uses debconf is often fully pre-configured, by its config script, before the postinst ever runs. Oh well. Like the postinst, the config script is passed two parameters when it is run. The first tells what action is being performed, and the second is the version of the package that is currently installed. So, like in a postinst, you can use dpkg --compare-versions on $2 to make some behavior happen only on upgrade from a particular version of a package, and things like that. The config script can be run in one of three ways:
THE TEMPLATES FILEA package that uses debconf probably wants to ask some questions. These questions are stored, in template form, in the templates file. Like the config script, the templates file is put in the control.tar.gz section of a deb. Its format is similar to a debian control file; a set of stanzas separated by blank lines, with each stanza having a RFC822-like form:
Description: This is a sample string question.
This is its extended description.
- Like in a debian package description, a dot
on its own line sets off a new paragraph.
- Most text is word-wrapped, but doubly-indented
text is left alone, so you can use it for lists
of items, like this list.
QUESTIONSA question is an instantiated template. By asking debconf to display a question, your config script can interact with the user. When debconf loads a templates file (this happens whenever a config or postinst script is run), it automatically instantiates a question from each template. It is actually possible to instantiate several independent questions from the same template (using the REGISTER command), but that is rarely necessary. Templates are static data that comes from the templates file, while questions are used to store dynamic data, like the current value of the question, whether a user has seen a question, and so on. Keep the distinction between a template and a question in mind, but don't worry too much about it.
SHARED TEMPLATESIt's actually possible to have a template and a question that are shared among a set of packages. All the packages have to provide an identical copy of the template in their templates files. This can be useful if a bunch of packages need to ask the same question, and you only want to bother the user with it once. Shared templates are generally put in the shared/ pseudo-directory in the debconf template namespace.
THE DEBCONF PROTOCOLConfig scripts communicate with debconf using the debconf protocol. This is a simple line-oriented protocol, similar to common internet protocols such as SMTP. The config script sends debconf a command by writing the command to standard output. Then it can read debconf's reply from standard input. Debconf's reply can be broken down into two parts: A numeric result code (the first word of the reply), and an optional extended result code (the remainder of the reply). The numeric code uses 0 to indicate success, and other numbers to indicate various kinds of failure. For full details, see the table in Debian policy's debconf specification document. Generally you'll want to use a language-specific library that handles the nuts and bolts of setting up these connections to debconf and communicating with it. For now, here are the commands in the protocol. This is not the definitive definition, see Debian policy's debconf specification document for that.
LIBRARIESSetting things up so you can talk to debconf, and speaking the debconf protocol by hand is a little too much work, so some thin libraries exist to relieve this minor drudgery. For shell programming, there is the /usr/share/debconf/confmodule library, which you can source at the top of a shell script, and talk to debconf in a fairly natural way, using lower-case versions of the debconf protocol commands, that are prefixed with "db_" (ie, "db_input" and "db_go"). For details, see confmodule(3). Perl programmers can use the Debconf::Client::ConfModule(3) perl module. The rest of this manual will use the /usr/share/debconf/confmodule library in example shell scripts. Here is an example config script using that library, that just asks a question:
db_set mypackage/reboot-now false
db_input high mypackage/reboot-now || true
db_go || true Notice the uses of "|| true" to prevent the script from dying if debconf decides it can't display a question, or the user tries to back up. In those situations, debconf returns a non-zero exit code, and since this shell script is set -e, an untrapped exit code would make it abort. And here is a corresponding postinst script, that uses the user's answer to the question to see if the system should be rebooted (a rather absurd example..):
if [ "$RET" = true ]; then
shutdown -r now
fi Notice the use of the $RET variable to get at the extended return code from the GET command, which holds the user's answer to the question.
THE POSTINST SCRIPTThe last section had an example of a postinst script that uses debconf to get the value of a question, and act on it. Here are some things to keep in mind when writing postinst scripts that use debconf:
OTHER SCRIPTSBesides the config script and postinst, you can use debconf in any of the other maintainer scripts. Most commonly, you'll be using debconf in your postrm, to call the PURGE command when your package is removed, to clean out its entries in the debconf database. (This is automatically set up for you by dh_installdebconf(1), by the way. A more involved use of debconf would be if you want to use it in the postrm when your package is purged, to ask a question about deleting something. Or maybe you find you need to use it in the preinst or prerm for some reason. All of these uses will work, though they'll probably involve asking questions and acting on the answers in the same program, rather than separating the two activities as is done in the config and postinst scripts. Note that if your package's sole use of debconf is in the postrm, you should make your package's postinst sources /usr/share/debconf/confmodule, to give debconf a chance to load up your templates file into its database. Then the templates will be available when your package is being pourged. You can also use debconf in other, stand alone programs. The issue to watch out for here is that debconf is not intended to be, and must not be used as a registry. This is unix after all, and programs are configured by files in /etc, not by some nebulous debconf database (that is only a cache anyway and might get blown away). So think long and hard before using debconf in a standalone program. There are times when it can make sense, as in the apt-setup program which uses debconf to prompt the user in a manner consistent with the rest of the debian install process, and immediately acts on their answers to set up apt's sources.list.
LOCALIZATIONDebconf supports localization of templates files. This is accomplished by adding more fields, with translated text in them. Any of the fields can be translated. For example, you might want to translate the description into Spanish. Just make a field named 'Description-es' that holds the translation. If a translated field is not available, debconf falls back to the normal English field. Besides the 'Description' field, you should translate the 'Choices' field of a select or multiselect template. Be sure to list the translated choices in the same order as they appear in the main 'Choices' field. You do not need to translate the 'Default' field of a select of multiselect question, and the value of the question will be automatically returned in English. You will find it easier to manage translations if you keep them in separate files; one file per translation. The debconf-getlang(1) program can generate and update such files, and the debconf-mergetemplate(1) program can merge several such templates files together to produce a combined file to put in your binary package. For more details on maintaining translations, see their man pages.
PUTTING IT ALL TOGETHERSo you have a config script, a templates file, a postinst script that uses debconf, and so on. Putting these pieces together into a debian package isn't hard. You can do it by hand, or use can use dh_installdebconf(1) which will merge your translated templates, copy the files into the right places for you, and can even generate the call to PURGE that should go in your postrm script. Make sure that your package depends on debconf (>= 0.5), since earlier versions were not compatible with everything described in this manual. And you're done. Well, except for testing, debugging, and actually using debconf for more interesting things than asking a few basic questions. For that, read on..
DEBUGGINGSo you have a package that's supposed to use debconf, but it doesn't quite work. Maybe debconf is just not asking that question you set up. Or maybe something weirder is happening; it spins forever in some kind of loop, or worse. Luckily, debconf has plenty of debugging facilities.
ADVANCED PROGRAMING WITH DEBCONF
Config file handlingMany of you seem to want to use debconf to help manage config files that are part of your package. Perhaps there is no good default to ship in a conffile, and so you want to use debconf to prompt the user, and write out a config file based on their answers. That seems easy enough to do, but then you consider upgrades, and what to do when someone modifies the config file you generate, and dpkg-reconfigure, and ... There are a lot of ways to do this, and most of them are wrong, and will often earn you annoyed bug reports. Here is one right way to do it. It assumes that your config file is really just a series of shell variables being set, with comments in between, and so you can just source the file to "load" it. If you have a more complicated format, reading (and writing) it becomes a bit trickier. Your config script will look something like this:
Letting the user back upFew things are more frustrating when using a system like debconf than being asked a question, and answering it, then moving on to another screen with a new question on it, and realizing that hey, you made a mistake, with that last question, and you want to go back to it, and discovering that you can't. Since debconf is driven by your config script, it can't jump back to a previous question on its own but with a little help from you, it can accomplish this feat. The first step is to make your config script let debconf know it is capable of handling the user pressing a back button. You use the CAPB command to do this, passing backup as a parameter. Then after each GO command, you must test to see if the user asked to back up (debconf returns a code of 30), and if so jump back to the previous question. There are several ways to write the control structures of your program so it can jump back to previous questions when necessary. You can write goto-laden spaghetti code. Or you can create several functions and use recursion. But perhaps the cleanest and easiest way is to construct a state machine. Here is a skeleton of a state machine that you can fill out and expand.
while [ "$STATE" != 0 -a "$STATE" -le "$LASTSTATE" ]; do
case "$STATE" in
# Two unrelated questions.
db_input medium my/question || true
db_input medium my/other_question || true
# Only ask this question if the
# first question was answered in
# the affirmative.
if [ "$RET" = "false" ]; then
db_input medium my/dep_question || true
# Add additional states here, making sure to
# increment LASTSTATE.
Preventing infinite loopsOne gotcha with debconf comes up if you have a loop in your config script. Suppose you're asking for input and validating it, and looping if it's not valid:
do while [ ! "$ok" ];
db_input low foo/bar || true
db_go || true
if [ "$RET" ]; then
done This looks ok at first glance. But consider what happens if the value of foo/bar is "" when this loop is entered, and the user has their priority set high, or is using a non-interactive frontend, and so they are not really asked for input. The value of foo/bar is not changed by the db_input, and so it fails the test and loops. And loops ... One fix for this is to make sure that before the loop is entered, the value of foo/bar is set to something that will pass the test in the loop. So for example if the default value of foo/bar is "1", then you could RESET foo/bar just before entering the loop. Another fix is to check the return code of the INPUT command. If it is 30 then the user is not being shown the question you asked them, and you should break out of the loop.
Choosing among related packagesSometimes a set of related packages can be installed, and you want to prompt the user which of the set should be used by default. Examples of such sets are window managers, or ispell dictionary files. While it would be possible for each package in the set to simply prompt, "Should this package be default?", this leads to a lot of repetitive questions if several of the packages are installed. It's possible with debconf to present a list of all the packages in the set and allow the user to choose between them. Here's how. Make all the packages in the set use a shared template. Something like this:
Description: Select the default window manager.
Select the window manager that will be started by
default when X starts. Each package should include a copy of the template. Then it should include some code like this in its config script:
db_metaget shared/window-manager owners
db_metaget shared/window-manager choices
if [ "$OWNERS" != "$CHOICES" ]; then
db_subst shared/window-manager choices $OWNERS
db_fset shared/window-manager seen false
db_input medium shared/window-manager || true
db_go || true A bit of an explanation is called for. By the time your config script runs, debconf has already read in all the templates for the packages that are being installed. Since the set of packages share a question, debconf records that fact in the owners field. By a strange coincidence, the format of the owners field is the same as that of the choices field (a comma and space delimited list of values). The METAGET command can be used to get the list of owners and the list of choices. If they are different, then a new package has been installed. So use the SUBST command to change the list of choices to be the same as the list of owners, and ask the question. When a package is removed, you probably want to see if that package is the currently selected choice, and if so, prompt the user to select a different package to replace it. This can be accomplished by adding something like this to the prerm scripts of all related packages (replacing <package> with the package name):
if [ -e /usr/share/debconf/confmodule ]; then
# I no longer claim this question.
# See if the shared question still exists.
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-manage seen false
db_input high shared/window-manager || true
db_go || true
# Now do whatever the postinst script did
# to update the window manager symlink.
HACKSDebconf is currently not fully integrated into dpkg (but I want to change this in the future), and so some messy hacks are currently called for. The worst of these involves getting the config script to run. The way that works now is the config script will be run when the package is pre-configured. Then, when the postinst script runs, it starts up debconf again. Debconf notices it is being used by the postinst script, and so it goes off and runs the config script. This can only work if your postinst loads up one of the debconf libraries though, so postinsts always have to take care to do that. We hope to address this later by adding explicit support to dpkg for debconf. A related hack is getting debconf running when a config script, postinst, or other program that uses it starts up. After all, they expect to be able to talk to debconf right away. The way this is accomplished for now is that when such a script loads a debconf library (like /usr/share/debconf/confmodule), and debconf is not already running, it is started up, and a new copy of the script is re-execed. The only noticeable result is that you need to put the line that loads a debconf library at the very top of the script, or weird things will happen. We hope to address this later by changing how debconf is invoked, and turning it into something more like a transient daemon. It's rather hackish how debconf figures out what templates files to load, and when it loads them. When the config, preinst, and postinst scripts invoke debconf, it will automatically figure out where the templates file is, and load it. Standalone programs that use debconf will cause debconf to look for templates files in /usr/share/debconf/progname.templates. And if a postrm wants to use debconf at purge time, the templates won't be available unless debconf had a chance to load them in its postinst. This is messy, but rather unavoidable. In the future some of these programs may be able to use debconf-loadtemplate by hand though. Finally, /usr/share/debconf/confmodule's historic behavior of playing with file descriptions and setting up a fd #3 that talks to debconf, can cause all sorts of trouble when a postinst runs a daemon, since the daemon ends up talking to debconf, and debconf can't figure out when the script terminates. The STOP command can work around this. In the future, we are considering making debconf communication happen over a socket or some other mechanism than stdio.
SEE ALSOdebconf(1) is the debconf user's guide. The debconf specification in debian policy is the canonical definition of the debconf protocol. /usr/doc/debian-policy/debconf_specification.txt.gz debconf.conf(5) has much useful information, including some info about the backend database. The debconf tutorial walks you through converting an existing package to use debconf. /usr/doc/debconf-doc/tutorial.txt.gz
AUTHORJoey Hess <email@example.com>
This document was created by man2html, using the manual pages.
Time: 19:39:26 GMT, December 08, 2021