It is possible to supply scripts as part of a package which dpkg
will run for you when your package is installed, upgraded or removed.
These scripts should be the files preinst, postinst, prerm and postrm in the control area of the package. They must be proper exectuable files; if they are scripts (which is recommended) they must start with the usual #! convention. They should be readable and executable to anyone, and not world-writeable.
dpkg
looks at the exit status from these scripts. It is important
that they exit with a non-zero status if there is an error, so that
dpkg
can stop its processing. For shell scripts this means that
you almost always need to use set -e (this is usually
true when writing shell scripts, in fact). It is also important, of course,
that they don't exit with a non-zero status if everything went well.
It is necessary for the error recovery procedures that the scripts be idempotent: ie, invoking the same script several times in the same situation should do no harm. If the first call failed, or aborted half way through for some reason, the second call should merely do the things that were left undone the first time, if any, and exit with a success status.
When a package is upgraded a combination of the scripts from the old and new packages is called in amongst the other steps of the upgrade procedure. If your scripts are going to be at all complicated you need to be aware of this, and may need to check the arguments to your scripts.
Broadly speaking the preinst
is called before (a particular
version of) a package is installed, and the postinst
afterwards;
the prerm
before (a version of) a package is removed and the
postrm
afterwards.
Programs called from maintainer scripts should not normally have a path
prepended to them. Before installation is started dpkg
checks to
see if the programs ldconfig
, start-stop-daemon
,
install-info
, and update-rc.d
can be found via the
PATH environment variable. Those programs, and any other program
that one would expect to on the PATH, should thus be invoked
without an absolute pathname. Maintainer scripts should also not reset the
PATH, though they might choose to modify it by pre- or appending
package-specific directories. These considerations really apply to all shell
scripts.
The procedure on installation/upgrade/overwrite/disappear (ie, when running dpkg --unpack, or the unpack stage of dpkg --install) is as follows. In each case if an error occurs the actions in are general run backwards - this means that the maintainer scripts are run with different arguments in reverse order. These are the `error unwind' calls listed below.
old-prerm upgrade new-version
new-prerm failed-upgrade old-version
Error unwind, for both the above cases:
old-postinst abort-upgrade new-version
deconfigured's-prerm deconfigure \ in-favour package-being-installed version \ removing conflicting-package version
Error unwind:
deconfigured's-postinst abort-deconfigure \ in-favour package-being-installed-but-failed version \ removing conflicting-package version
The deconfigured packages are marked as requiring configuration, so that if --install is used they will be configured again if possible.
conflictor's-prerm remove in-favour package new-version
Error unwind:
conflictor's-postinst abort-remove \ in-favour package new-version
new-preinst upgrade old-version
new-preinst install old-version
new-preinst install
Error unwind versions, respectively:
new-postrm abort-upgrade old-version new-postrm abort-install old-version new-postrm abort-install
It is an error for a package to contains files which are on the system in another package, unless Replaces is used (see Replaces - overwriting files and replacing packages, Section 8.5). Currently the --force-overwrite flag is enabled, downgrading it to a warning, but this may not always be the case.
It is a more serious error for a package to contain a plain file or other kind of nondirectory where another package has a directory (again, unless Replaces is used). This error can be overridden if desired using --force-overwrite-dir, but this is not advisable.
Packages which overwrite each other's files produce behaviour which though deterministic is hard for the system administrator to understand. It can easily lead to `missing' programs if, for example, a package is installed which overwrites a file from another package, and is then removed again. [19]
A directory will never be replaced by a symbolic links to a directory or vice
versa; instead, the existing state (symlink or not) will be left alone and
dpkg
will follow the symlink if there is one.
old-postrm upgrade new-version
dpkg
will attempt:
new-postrm failed-upgrade old-version
Error unwind, for both cases:
old-preinst abort-upgrade new-version
This is the point of no return - if dpkg
gets this far, it won't
back off past this point if an error occurs. This will leave the package in a
fairly bad state, which will require a successful reinstallation to clear up,
but it's when dpkg
starts doing things that are irreversible.
dpkg
calls:
disappearer's-postrm disappear \ overwriter overwriter-version
dpkg
). Note that disappearing packages do not have their prerm
called, because dpkg
doesn't know in advance that the package is
going to vanish.
When we configure a package (this happens with dpkg --install, or with --configure), we first update the conffiles and then call:
postinst configure most-recently-configured-version
No attempt is made to unwind after errors during configuration.
If there is no most recently configured version dpkg
will pass a
null argument; older versions of dpkg may pass <unknown>
(including the angle brackets) in this case. Even older ones do not pass a
second argument at all, under any circumstances.
prerm remove
postrm remove
If we aren't purging the package we stop here. Note that packages which have
no postrm and no conffiles are automatically purged when removed, as there is
no difference except for the dpkg
status.
postrm purge
No attempt is made to unwind after errors during removal.
ijackson@gnu.ai.mit.edu
bweaver@debian.org
schwarz@debian.org
srivasta@debian.org
debian-policy@lists.debian.org