The following commit has been merged in the master branch:
commit 20f33fd89e06a214c861733c2cc28754eda58bfa
Author: Raphaël Hertzog <[email protected]>
Date:   Mon Apr 12 12:32:18 2010 +0200

    maintscript-helper: new program to simplify some maintainer scripts
    
    This program is designed to be run within maintainer scripts to achieve
    some tasks that dpkg can't (yet) handle natively either because of design
    decisions or due to current limitations.
    
    Many of those tasks require coordinated actions from several maintainer
    scripts (preinst, postinst, prerm, postrm). To avoid mistakes the same
    call simply needs to be put in all scripts and the program will 
automatically
    adapt its behaviour based on the environment variable DPKG_MAINTSCRIPT_NAME
    and on the maintainer scripts arguments that you have to forward after
    a double dash.

diff --git a/debian/changelog b/debian/changelog
index 06757d7..30440e6 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -37,6 +37,10 @@ dpkg (1.15.6.2) UNRELEASED; urgency=low
   * dpkg now exports DPKG_LIBDIR to maintainer scripts pointing to the
     private directory containing internal programs like the upcoming
     maintscript-helper.
+  * Add $DPKG_LIBDIR/maintscript-helper program that can be used in
+    maintainer scripts to perform common operations working around
+    current dpkg limitations: first version supports removing obsolete
+    conffiles and renaming conffiles. Closes: #514316
 
   [ Colin Watson ]
   * Modern tar files typically use NormalFile1 rather than NormalFile0 for
diff --git a/debian/dpkg.install b/debian/dpkg.install
index 30bf847..fd86914 100644
--- a/debian/dpkg.install
+++ b/debian/dpkg.install
@@ -11,6 +11,7 @@ usr/bin/dpkg-split
 usr/bin/dpkg-statoverride
 usr/bin/dpkg-trigger
 usr/bin/update-alternatives
+usr/lib/dpkg/maintscript-helper
 usr/lib/dpkg/mksplit
 usr/sbin
 usr/share/dpkg
@@ -23,6 +24,7 @@ usr/share/man/{*/*,*}/dpkg-statoverride.8
 usr/share/man/{*/*,*}/dpkg-trigger.1
 usr/share/man/{*/*,*}/dpkg.cfg.5
 usr/share/man/{*/*,*}/dpkg.1
+usr/share/man/{*/*,*}/maintscript-helper.1
 usr/share/man/{*/*,*}/start-stop-daemon.8
 usr/share/man/{*/*,*}/update-alternatives.8
 usr/share/perl5/Dpkg.pm
diff --git a/lib/Makefile.am b/lib/Makefile.am
index 40c2a6b..deb9b9b 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -4,3 +4,4 @@ SUBDIRS = \
        compat \
        dpkg
 
+pkglib_SCRIPTS = maintscript-helper
diff --git a/lib/maintscript-helper b/lib/maintscript-helper
new file mode 100755
index 0000000..d8f81bb
--- /dev/null
+++ b/lib/maintscript-helper
@@ -0,0 +1,256 @@
+#!/bin/sh
+#
+# Copyright © 2010 Raphaël Hertzog <[email protected]>
+# Copyright © 2008 Joey Hess <[email protected]>
+# Copyright © 2007 Guillem Jover (modifications on wiki.debian.org)
+# Copyright © 2005 Scott James Remnant (original implementation on 
www.dpkg.org)
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# The conffile related functions are inspired by
+# http://wiki.debian.org/DpkgConffileHandling
+
+# This script is documented in maintscript-helper(1)
+
+##
+## Functions to remove an obsolete conffile during upgrade
+##
+rm_conffile() {
+       local CONFFILE="$1"
+       local LASTVERSION="$2"
+       local PACKAGE="$3"
+       if [ "$PACKAGE" = "--" -o -z "$PACKAGE" ]; then
+               PACKAGE="$DPKG_MAINTSCRIPT_PACKAGE"
+       fi
+       # Skip remaining parameters up to --
+       while [ "$1" != "--" -a "$1" != "" ]; do shift; done
+       shift
+
+       [ -n "$PACKAGE" ] || error "couldn't identify the package"
+       [ -n "$1" ] || error "maintainer script parameters are missing"
+       [ -n "$DPKG_MAINTSCRIPT_NAME" ] || \
+               error "environment variable DPKG_MAINTSCRIPT_NAME is required"
+
+       debug "Executing $0 rm_conffile in $DPKG_MAINTSCRIPT_NAME "\
+             "of $DPKG_MAINTSCRIPT_PACKAGE"
+       debug "CONFFILE=$CONFFILE PACKAGE=$PACKAGE "\
+             "LASTVERSION=$LASTVERSION ACTION=$1 PARAM=$2"
+       case "$DPKG_MAINTSCRIPT_NAME" in
+       preinst)
+               if [ "$1" = "install" -o "$1" = "upgrade" ] &&
+                  dpkg --compare-versions "$2" le-nl "$LASTVERSION"; then
+                       prepare_rm_conffile "$CONFFILE" "$PACKAGE"
+               fi
+               ;;
+       postinst)
+               if [ "$1" = "configure" ] &&
+                  dpkg --compare-versions "$2" le-nl "$LASTVERSION"; then
+                       finish_rm_conffile $CONFFILE
+               fi
+               ;;
+       postrm)
+               if [ "$1" = "purge" ]; then
+                       rm -f "$CONFFILE.dpkg-bak" "$CONFFILE.dpkg-remove"
+               fi
+               if [ "$1" = "abort-install" -o "$1" = "abort-upgrade" ] &&
+                  dpkg --compare-versions "$2" le-nl "$LASTVERSION"; then
+                       abort_rm_conffile "$CONFFILE"
+               fi
+               ;;
+       *)
+               debug "$0 rm_conffile not required in $DPKG_MAINTSCRIPT_NAME"
+               ;;
+       esac
+}
+
+prepare_rm_conffile() {
+       local CONFFILE="$1"
+       local PACKAGE="$2"
+
+       [ -e "$CONFFILE" ] || return 0
+
+       local md5sum="$(md5sum $CONFFILE | sed -e 's/ .*//')"
+       local old_md5sum="$(dpkg-query -W -f='${Conffiles}' $PACKAGE | \
+               sed -n -e "\' $CONFFILE ' { s/ obsolete$//; s/.* //; p }")"
+       if [ "$md5sum" != "$old_md5sum" ]; then
+               echo "Obsolete conffile $CONFFILE has been modified by you."
+               echo "Saving as $CONFFILE.dpkg-bak ..."
+               mv -f "$CONFFILE" "$CONFFILE.dpkg-bak"
+       else
+               echo "Moving obsolete conffile $CONFFILE out of the way..."
+               mv -f "$CONFFILE" "$CONFFILE.dpkg-remove"
+       fi
+}
+
+finish_rm_conffile() {
+       local CONFFILE="$1"
+
+       if [ -e "$CONFFILE.dpkg-remove" ]; then
+               echo "Removing obsolete conffile $CONFFILE ..."
+               rm -f "$CONFFILE.dpkg-remove"
+       fi
+}
+
+abort_rm_conffile() {
+       local CONFFILE="$1"
+
+       if [ -e "$CONFFILE.dpkg-remove" ]; then
+               echo "Reinstalling $CONFFILE that was moved away"
+               mv "$CONFFILE.dpkg-remove" "$CONFFILE"
+       fi
+       if [ -e "$CONFFILE.dpkg-bak" ]; then
+               echo "Reinstalling $CONFFILE that was backupped"
+               mv "$CONFFILE.dpkg-bak" "$CONFFILE"
+       fi
+}
+
+##
+## Functions to rename a conffile during upgrade
+##
+mv_conffile() {
+       local OLDCONFFILE="$1"
+       local NEWCONFFILE="$2"
+       local LASTVERSION="$3"
+       local PACKAGE="$4"
+       if [ "$PACKAGE" = "--" -o -z "$PACKAGE" ]; then
+               PACKAGE="$DPKG_MAINTSCRIPT_PACKAGE"
+       fi
+       # Skip remaining parameters up to --
+       while [ "$1" != "--" -a "$1" != "" ]; do shift; done
+       shift
+
+       [ -n "$PACKAGE" ] || error "couldn't identify the package"
+       [ -n "$1" ] || error "maintainer script parameters are missing"
+       [ -n "$DPKG_MAINTSCRIPT_NAME" ] || \
+               error "environment variable DPKG_MAINTSCRIPT_NAME is required"
+
+       debug "Executing $0 mv_conffile in $DPKG_MAINTSCRIPT_NAME "\
+             "of $DPKG_MAINTSCRIPT_PACKAGE"
+       debug "CONFFILE=$OLDCONFFILE -> $NEWCONFFILE PACKAGE=$PACKAGE "\
+             "LASTVERSION=$LASTVERSION ACTION=$1 PARAM=$2"
+       case "$DPKG_MAINTSCRIPT_NAME" in
+       preinst)
+               if [ "$1" = "install" -o "$1" = "upgrade" ] &&
+                  dpkg --compare-versions "$2" le-nl "$LASTVERSION"; then
+                       prepare_mv_conffile "$OLDCONFFILE" "$PACKAGE"
+               fi
+               ;;
+       postinst)
+               if [ "$1" = "configure" ] &&
+                  dpkg --compare-versions "$2" le-nl "$LASTVERSION"; then
+                       finish_mv_conffile "$OLDCONFFILE" "$NEWCONFFILE"
+               fi
+               ;;
+       postrm)
+               if [ "$1" = "abort-install" -o "$1" = "abort-upgrade" ] &&
+                  dpkg --compare-versions "$2" le-nl "$LASTVERSION"; then
+                       abort_rm_conffile "$OLDCONFFILE"
+               fi
+               ;;
+       *)
+               debug "$0 mv_conffile not required in $DPKG_MAINTSCRIPT_NAME"
+               ;;
+       esac
+}
+
+prepare_mv_conffile() {
+       local CONFFILE="$1"
+       local PACKAGE="$2"
+
+       [ -e "$CONFFILE" ] || return 0
+
+       local md5sum="$(md5sum $CONFFILE | sed -e 's/ .*//')"
+       local old_md5sum="$(dpkg-query -W -f='${Conffiles}' $PACKAGE | \
+               sed -n -e "\' $CONFFILE ' { s/ obsolete$//; s/.* //; p }")"
+       if [ "$md5sum" = "$old_md5sum" ]; then
+               mv -f "$CONFFILE" "$CONFFILE.dpkg-remove"
+       fi
+}
+
+finish_mv_conffile() {
+       local OLDCONFFILE="$1"
+       local NEWCONFFILE="$2"
+
+       rm -f $OLDCONFFILE.dpkg-remove
+
+       [ -e "$OLDCONFFILE" ] || return 0
+
+       echo "Preserving user changes to $NEWCONFFILE (renamed from 
$OLDCONFFILE)..."
+       mv -f "$NEWCONFFILE" "$NEWCONFFILE.dpkg-new"
+       mv -f "$OLDCONFFILE" "$NEWCONFFILE"
+}
+
+abort_mv_conffile() {
+       local CONFFILE="$1"
+
+       if [ -e "$CONFFILE.dpkg-remove" ]; then
+               echo "Reinstalling $CONFFILE that was moved away"
+               mv "$CONFFILE.dpkg-remove" "$CONFFILE"
+       fi
+}
+
+# Common functions
+debug() {
+       if [ -n "$DPKG_DEBUG" ]; then
+               echo "DEBUG: $PROGNAME: $1" >&2
+       fi
+}
+
+error() {
+       echo "ERROR: $PROGNAME: $1" >&2
+       exit 1
+}
+
+usage() {
+       cat <<END
+Syntax: $0 <command> [<parameters>] -- <maintainer script parameters>
+
+Commands and parameters:
+
+  rm_conffile <conffile> <last-version> [<package>]
+       Remove obsolete conffile.
+       Must be called in preinst, postinst and postrm.
+
+  mv_conffile <old-conf> <new-conf> <last-version> [<package>]
+       Rename a conffile.
+       Must be called in preinst, postinst and postrm.
+
+  help
+       Display this usage information.
+END
+}
+
+# Main code
+set -e
+
+PROGNAME=$(basename $0)
+command="$1"
+shift
+
+case "$command" in
+rm_conffile)
+       rm_conffile "$@"
+       ;;
+mv_conffile)
+       mv_conffile "$@"
+       ;;
+--help|help|-?|-h)
+       usage
+       ;;
+*)
+       usage
+       exit 1
+esac
+
+exit 0
diff --git a/man/Makefile.am b/man/Makefile.am
index 8348832..1dcb2dd 100644
--- a/man/Makefile.am
+++ b/man/Makefile.am
@@ -118,7 +118,8 @@ dist_man_MANS = \
        dpkg-trigger.1 \
        dpkg-vendor.1 \
        dpkg.1 \
-       dpkg.cfg.5
+       dpkg.cfg.5 \
+       maintscript-helper.1
 
 if WITH_DSELECT
 dist_man_MANS += \
diff --git a/man/maintscript-helper.1 b/man/maintscript-helper.1
new file mode 100644
index 0000000..f1ead94
--- /dev/null
+++ b/man/maintscript-helper.1
@@ -0,0 +1,117 @@
+.TH maintscript\-helper 1 "2010-04-16" "Debian Project" "dpkg suite"
+.SH NAME
+maintscript\-helper \- works around known dpkg limitations in maintainer 
scripts
+.
+.SH SYNOPSIS
+.B $DPKG_LIBDIR/maintscript\-helper
+.IR command " [" parameters "...] \-\- " maint-script-parameters
+.
+.SH COMMANDS AND PARAMETERS
+.P
+\fBrm_conffile\fP \fIconffile\fP \fIlastversion\fP [\fIpackage\fP]
+.P
+\fBmv_conffile\fP \fIoldconffile\fP \fInewconffile\fP \fIlastversion\fP 
[\fIpackage\fP]
+.
+.SH DESCRIPTION
+.P
+This program is designed to be run within maintainer scripts to achieve
+some tasks that dpkg can't (yet) handle natively either because of design
+decisions or due to current limitations.
+.P
+Many of those tasks require coordinated actions from several maintainer
+scripts (\fBpreinst\fP, \fBpostinst\fP, \fBprerm\fP, \fBpostrm\fP). To
+avoid mistakes the same call simply needs to be put in all scripts and the
+program will automatically adapt its behaviour based on the environment
+variable DPKG_MAINTSCRIPT_NAME and on the maintainer scripts arguments
+that you have to forward after a double dash.
+.
+.SH CONFFILE RELATED TASKS
+.P
+When upgrading a package, dpkg will not automatically remove a conffile (a
+configuration file for which dpkg should preserve user changes) if it is
+not present in the newer version. There are two principal reasons for
+this; the first is that the conffile could've been dropped by accident and
+the next version could restore it, users wouldn't want their changes
+thrown away. The second is to allow packages to transition files from a
+dpkg\-maintained conffile to a file maintained by the package's maintainer
+scripts, usually with a tool like debconf or ucf.
+.P
+This means that if a package is intended to rename or remove a conffile,
+it must explicitly do so and \fBmaintscript\-helper\fP can be used to implement
+graceful deletion and moving of conffiles within maintainer scripts.
+.
+.SS REMOVING A CONFFILE
+.P
+If a conffile is completely removed, it should be removed from disk,
+unless the user has modified it. If there are local modifications, they
+should be preserved. If the package upgrades aborts, the newly obsolete
+conffile should not disappear.
+.P
+All of this is implemented by putting the following shell snippet in the
+\fBpreinst\fP, \fBpostinst\fP and \fBpostrm\fP maintainer scripts:
+.P
+    if [ \-x $DPKG_LIBDIR/maintscript\-helper ]; then
+        $DPKG_LIBDIR/maintscript\-helper rm_conffile \\
+            \fIconffile\fP \fIlastversion\fP \fIpackage\fP \-\- "$@"
+    fi
+.P
+\fIconffile\fP is the filename of the conffile to remove.
+\fIlastversion\fP is the last version of the package that contained the
+conffile. \fIpackage\fP is the package name, it's optional as it will
+default to $DPKG_MAINTSCRIPT_PACKAGE (this variable is set by dpkg to the
+name of the package acted upon). All the parameters of the maintainer
+scripts have to be forwarded to the program after "\-\-".
+.P
+Current implementation: in the \fBpreinst\fP, it checks if the conffile
+was modified and renames it either to \fIconffile\fP\fB.dpkg\-remove\fP (if not
+modified) or to \fIconffile\fP\fB.dpkg\-bak\fP (if modified). The latter file 
is
+kept for reference as it contains user modifications but the former will
+be removed in the \fBpostinst\fP. If the package upgrade aborts, the
+\fBpostrm\fP reinstalls the original conffile. During purge, the
+\fBpostrm\fP will also delete the \fB.dpkg\-bak\fP file kept up to now.
+.
+.SS RENAMING A CONFFILE
+.P
+If a conffile is moved from one location to another, you need to make sure
+you move across any changes the user has made. This may seem a simple
+change to the \fBpreinst\fP script at first, however that will result in
+the user being prompted by dpkg to approve the conffile edits even though
+they are not responsible of them.
+.P
+Graceful renaming can be implemented by putting the following shell
+snippet in the \fBpreinst\fP, \fBpostinst\fP and \fBpostrm\fP maintainer
+scripts:
+.P
+    if [ \-x $DPKG_LIBDIR/maintscript\-helper ]; then
+        $DPKG_LIBDIR/maintscript\-helper mv_conffile \\
+            \fIoldconffile\fP \fInewconffile\fP \fIlastversion\fP 
\fIpackage\fP \-\- "$@"
+    fi
+.P
+\fIoldconffile\fP and \fInewconffile\fP are the old and new name of the
+conffile to rename. \fIlastversion\fP is the last version of the package
+that contained the conffile with the old name. \fIpackage\fP is the
+package name, it's optional as it will default to
+$DPKG_MAINTSCRIPT_PACKAGE (this variable is set by dpkg to the name of the
+package acted upon). All the parameters of the maintainer scripts have to
+be forwarded to the program after "\-\-".
+.P
+Current implementation: the \fBpreinst\fP checks if the conffile has been
+modified, if yes it's left on place otherwise it's renamed to
+\fIoldconffile\fP\fB.dpkg\-remove\fP. On configuration, the \fBpostinst\fP
+removes \fIoldconffile\fP\fB.dpkg\-remove\fP and renames \fIoldconffile\fP
+to \fInewconffile\fP if \fIoldconffile\fP is still available. On
+abort\-ugrade/abort\-install, the \fBpostrm\fP renames
+\fIoldconffile\fP\fB.dpkg\-remove\fP back to \fIoldconffile\fP if required.
+.
+.SH AUTHORS
+Copyright \(co 2010 Rapha\[:e]l Hertzog
+.br
+Copyright \(co 2008 Joey Hess
+.br
+Copyright \(co 2007 Guillem Jover
+.br
+Copyright \(co 2005 Scott James Remnant
+.sp
+This is free software; see the GNU General Public Licence version 2 or
+later for copying conditions. There is NO WARRANTY.
+
diff --git a/man/po/po4a.cfg b/man/po/po4a.cfg
index 80089ae..92e52a1 100644
--- a/man/po/po4a.cfg
+++ b/man/po/po4a.cfg
@@ -193,6 +193,11 @@
            add_$lang:po/$lang.add
 
 
+[type:man] maintscript-helper.1       \
+           $lang:$(builddir)/$lang/maintscript-helper.1     \
+           add_$lang:po/$lang.add
+
+
 [type:man] start-stop-daemon.8        \
            $lang:$(builddir)/$lang/start-stop-daemon.8      \
            add_$lang:po/$lang.add

-- 
dpkg's main repository


-- 
To UNSUBSCRIBE, email to [email protected]
with a subject of "unsubscribe". Trouble? Contact [email protected]

Reply via email to