Parcourir la source

dpkg-maintscript-helper: Add new symlink_to_dir command

Closes: #720712

Based-on-patch-by: Bastien ROUCARIÈS <roucaries.bastien@gmail.com>
Guillem Jover il y a 13 ans
Parent
commit
bfc1044bee
3 fichiers modifiés avec 113 ajouts et 3 suppressions
  1. 2 0
      debian/changelog
  2. 36 2
      man/dpkg-maintscript-helper.1
  3. 75 1
      scripts/dpkg-maintscript-helper.sh

+ 2 - 0
debian/changelog

@@ -79,6 +79,8 @@ dpkg (1.17.2) UNRELEASED; urgency=low
     cause a segfault in case the function returns 0 entries.
     cause a segfault in case the function returns 0 entries.
   * Always return from ensure_statoverrides() if file is NULL, otherwise
   * Always return from ensure_statoverrides() if file is NULL, otherwise
     we might get us to read garbage from memory or segfault.
     we might get us to read garbage from memory or segfault.
+  * Add new symlink_to_dir command to dpkg-maintscript-helper. Closes: #720712
+    Based on a patch by Bastien ROUCARIÈS <roucaries.bastien@gmail.com>.
 
 
   [ Updated programs translations ]
   [ Updated programs translations ]
   * German (Sven Joachim).
   * German (Sven Joachim).

+ 36 - 2
man/dpkg-maintscript-helper.1

@@ -28,6 +28,8 @@ dpkg\-maintscript\-helper \- works around known dpkg limitations in maintainer s
 \fBrm_conffile\fP \fIconffile\fP [\fIprior-version\fP [\fIpackage\fP]]
 \fBrm_conffile\fP \fIconffile\fP [\fIprior-version\fP [\fIpackage\fP]]
 .P
 .P
 \fBmv_conffile\fP \fIold-conffile\fP \fInew-conffile\fP [\fIprior-version\fP [\fIpackage\fP]]
 \fBmv_conffile\fP \fIold-conffile\fP \fInew-conffile\fP [\fIprior-version\fP [\fIpackage\fP]]
+.P
+\fBsymlink_to_dir\fP \fIpathname\fP \fIold-target\fP [\fIprior-version\fP [\fIpackage\fP]]
 .
 .
 .SH DESCRIPTION
 .SH DESCRIPTION
 .P
 .P
@@ -138,15 +140,47 @@ to \fInew-conffile\fP if \fIold-conffile\fP is still available. On
 abort\-upgrade/abort\-install, the \fBpostrm\fP renames
 abort\-upgrade/abort\-install, the \fBpostrm\fP renames
 \fIold-conffile\fP\fB.dpkg\-remove\fP back to \fIold-conffile\fP if required.
 \fIold-conffile\fP\fB.dpkg\-remove\fP back to \fIold-conffile\fP if required.
 .
 .
+.SH SYMLINK AND DIRECTORY SWITCHES
+.
+When upgrading a package, \fBdpkg\fP will not automatically switch a symlink
+to a directory or vice-versa.
+.
+.SS Switching a symlink to directory
+.
+If a symlink is converted to a real directory, you need to make sure
+before unpacking that the symlink is removed. This may seem a simple
+change to the \fBpreinst\fP script at first, however that will result
+in some problems in case of admin local customization of the symlink
+or when downgrading the package.
+.P
+Graceful renaming can be implemented by putting the following shell
+snippet in the \fBpreinst\fP, \fBpostinst\fP and \fBpostrm\fP maintainer
+scripts:
+.P
+    dpkg\-maintscript\-helper symlink_to_dir \\
+        \fIpathname\fP \fIold-target\fP \fIprior-version\fP \fIpackage\fP \-\- "$@"
+.P
+\fIpathname\fP is the name of the old symlink (the path will be a
+directory at the end of the installation) and \fIold-target\fP the
+target of the former symlink at \fIpathname\fP.
+.P
+Current implementation: the \fBpreinst\fP checks if the symlink exists
+and points to \fIold-target\fP, if not then it's left in place, otherwise
+it's renamed to \fIpathname\fP\fB.dpkg\-backup\fP. On configuration,
+the \fBpostinst\fP removes \fIpathname\fP\fB.dpkg\-backup\fP if
+\fIpathname\fP\fB.dpkg\-backup\fP is still a symlink. On
+abort\-upgrade/abort\-install, the \fBpostrm\fP renames
+\fIpathname\fP\fB.dpkg\-backup\fP back to \fIpathname\fP if required.
+.
 .SH INTEGRATION IN PACKAGES
 .SH INTEGRATION IN PACKAGES
 .P
 .P
 Given that \fBdpkg\-maintscript\-helper\fP is used in the \fBpreinst\fP,
 Given that \fBdpkg\-maintscript\-helper\fP is used in the \fBpreinst\fP,
 using it unconditionally requires a pre-dependency to ensure that the
 using it unconditionally requires a pre-dependency to ensure that the
 required version of \fBdpkg\fP has been unpacked before. The required version
 required version of \fBdpkg\fP has been unpacked before. The required version
 depends on the command used, for \fBrm_conffile\fP and \fBmv_conffile\fP
 depends on the command used, for \fBrm_conffile\fP and \fBmv_conffile\fP
-it is 1.15.7.2:
+it is 1.15.7.2, for \fBsymlink_to_dir\fP it is 1.17.2:
 .P
 .P
-    \fBPre\-Depends:\fP dpkg (>= 1.15.7.2)
+    \fBPre\-Depends:\fP dpkg (>= 1.17.2)
 .P
 .P
 But in many cases the operation done by the program is not critical for
 But in many cases the operation done by the program is not critical for
 the package, and instead of using a pre-dependency we can call the
 the package, and instead of using a pre-dependency we can call the

+ 75 - 1
scripts/dpkg-maintscript-helper.sh

@@ -227,6 +227,74 @@ abort_mv_conffile() {
 	fi
 	fi
 }
 }
 
 
+##
+## Functions to replace a symlink with a directory
+##
+symlink_to_dir() {
+	local SYMLINK="$1"
+	local SYMLINK_TARGET="$2"
+	local LASTVERSION="$3"
+	local PACKAGE="$4"
+
+	if [ "$LASTVERSION" = "--" ]; then
+		LASTVERSION=""
+		PACKAGE="$DPKG_MAINTSCRIPT_PACKAGE${DPKG_MAINTSCRIPT_ARCH:+:$DPKG_MAINTSCRIPT_ARCH}"
+	fi
+	if [ "$PACKAGE" = "--" -o -z "$PACKAGE" ]; then
+		PACKAGE="$DPKG_MAINTSCRIPT_PACKAGE${DPKG_MAINTSCRIPT_ARCH:+:$DPKG_MAINTSCRIPT_ARCH}"
+	fi
+
+	# Skip remaining parameters up to --
+	while [ "$1" != "--" -a $# -gt 0 ]; do shift; done
+	[ $# -gt 0 ] || badusage "missing arguments after --"
+	shift
+
+	[ -n "$DPKG_MAINTSCRIPT_NAME" ] || \
+		error "environment variable DPKG_MAINTSCRIPT_NAME is required"
+	[ -n "$PACKAGE" ] || error "cannot identify the package"
+	[ -n "$SYMLINK" ] || error "symlink parameter is missing"
+	[ -n "$SYMLINK_TARGET" ] || error "original symlink target is missing"
+	[ -n "$LASTVERSION" ] || error "last version is missing"
+	[ -n "$1" ] || error "maintainer script parameters are missing"
+
+	debug "Executing $0 symlink_to_dir in $DPKG_MAINTSCRIPT_NAME" \
+	      "of $DPKG_MAINTSCRIPT_PACKAGE"
+	debug "SYMLINK=$SYMLINK -> $SYMLINK_TARGET PACKAGE=$PACKAGE" \
+	      "LASTVERSION=$LASTVERSION ACTION=$1 PARAM=$2"
+
+	case "$DPKG_MAINTSCRIPT_NAME" in
+	preinst)
+		if [ "$1" = "install" -o "$1" = "upgrade" ] &&
+		   [ -n "$2" ] && [ -h "$SYMLINK" ] &&
+		   [ "$(readlink -f $SYMLINK)" = "$SYMLINK_TARGET" ] &&
+		   dpkg --compare-versions "$2" le-nl "$LASTVERSION"; then
+			mv -f "$SYMLINK" "${SYMLINK}.dpkg-backup"
+		fi
+		;;
+	postinst)
+		if [ "$1" = "configure" ] && [ -h "${SYMLINK}.dpkg-backup" ] &&
+		    dpkg --compare-versions "$2" le-nl "$LASTVERSION"; then
+			rm -f "${SYMLINK}.dpkg-backup"
+		fi
+		;;
+	postrm)
+		if [ "$1" = "purge" ] && [ -h "${SYMLINK}.dpkg-backup" ]; then
+		    rm -f "${SYMLINK}.dpkg-backup"
+		fi
+		if [ "$1" = "abort-install" -o "$1" = "abort-upgrade" ] &&
+		   [ -n "$2" ] &&
+		   [ -h "${SYMLINK}.dpkg-backup" ] && [ ! -e "$SYMLINK" ] &&
+		   dpkg --compare-versions "$2" le-nl "$LASTVERSION"; then
+			echo "Restoring backup of $SYMLINK ..."
+			mv "${SYMLINK}.dpkg-backup" "$SYMLINK"
+		fi
+		;;
+	*)
+		debug "$0 symlink_to_dir not required in $DPKG_MAINTSCRIPT_NAME"
+		;;
+	esac
+}
+
 # Common functions
 # Common functions
 ensure_package_owns_file() {
 ensure_package_owns_file() {
 	local PACKAGE="$1"
 	local PACKAGE="$1"
@@ -267,6 +335,9 @@ Commands:
 	postrm.
 	postrm.
   mv_conffile <old-conf> <new-conf> [<last-version> [<package>]]
   mv_conffile <old-conf> <new-conf> [<last-version> [<package>]]
 	Rename a conffile. Must be called in preinst, postinst and postrm.
 	Rename a conffile. Must be called in preinst, postinst and postrm.
+  symlink_to_dir <pathname> <old-symlink-target> [<last-version> [<package>]]
+	Replace a symlink with a directory. Must be called in preinst,
+	postinst and postrm.
   help
   help
 	Display this usage information.
 	Display this usage information.
 END
 END
@@ -291,7 +362,7 @@ shift
 case "$command" in
 case "$command" in
 supports)
 supports)
 	case "$1" in
 	case "$1" in
-	rm_conffile|mv_conffile)
+	rm_conffile|mv_conffile|symlink_to_dir)
 		code=0
 		code=0
 		;;
 		;;
 	*)
 	*)
@@ -314,6 +385,9 @@ rm_conffile)
 mv_conffile)
 mv_conffile)
 	mv_conffile "$@"
 	mv_conffile "$@"
 	;;
 	;;
+symlink_to_dir)
+	symlink_to_dir "$@"
+	;;
 --help|help|-?)
 --help|help|-?)
 	usage
 	usage
 	;;
 	;;