diff options
Diffstat (limited to 'src/dpkg-maintscript-helper.sh')
-rwxr-xr-x | src/dpkg-maintscript-helper.sh | 667 |
1 files changed, 667 insertions, 0 deletions
diff --git a/src/dpkg-maintscript-helper.sh b/src/dpkg-maintscript-helper.sh new file mode 100755 index 0000000..d799aa8 --- /dev/null +++ b/src/dpkg-maintscript-helper.sh @@ -0,0 +1,667 @@ +#!/bin/sh +# +# Copyright © 2007, 2011-2015 Guillem Jover <guillem@debian.org> +# Copyright © 2010 Raphaël Hertzog <hertzog@debian.org> +# Copyright © 2008 Joey Hess <joeyh@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 <https://www.gnu.org/licenses/>. + +# The conffile related functions are inspired by +# https://wiki.debian.org/DpkgConffileHandling + +# This script is documented in dpkg-maintscript-helper(1) + +## +## Functions to remove an obsolete conffile during upgrade +## +rm_conffile() { + local CONFFILE="$1" + local LASTVERSION="$2" + local PACKAGE="$3" + + 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 "$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" + [ -n "$DPKG_MAINTSCRIPT_PACKAGE" ] || \ + error "environment variable DPKG_MAINTSCRIPT_PACKAGE is required" + [ "${CONFFILE}" != "${CONFFILE#/}" ] || \ + error "conffile '$CONFFILE' is not an absolute path" + validate_optional_version "$LASTVERSION" + + 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" ] && [ -n "$2" ] && + dpkg --compare-versions -- "$2" le-nl "$LASTVERSION"; then + prepare_rm_conffile "$CONFFILE" "$PACKAGE" + fi + ;; + postinst) + if [ "$1" = "configure" ] && [ -n "$2" ] && + dpkg --compare-versions -- "$2" le-nl "$LASTVERSION"; then + finish_rm_conffile "$CONFFILE" + fi + ;; + postrm) + if [ "$1" = "purge" ]; then + rm -f "$DPKG_ROOT$CONFFILE.dpkg-bak" \ + "$DPKG_ROOT$CONFFILE.dpkg-remove" \ + "$DPKG_ROOT$CONFFILE.dpkg-backup" + fi + if [ "$1" = "abort-install" -o "$1" = "abort-upgrade" ] && + [ -n "$2" ] && + dpkg --compare-versions -- "$2" le-nl "$LASTVERSION"; then + abort_rm_conffile "$CONFFILE" "$PACKAGE" + fi + ;; + *) + debug "$0 rm_conffile not required in $DPKG_MAINTSCRIPT_NAME" + ;; + esac +} + +prepare_rm_conffile() { + local CONFFILE="$1" + local PACKAGE="$2" + + [ -e "$DPKG_ROOT$CONFFILE" ] || return 0 + ensure_package_owns_file "$PACKAGE" "$CONFFILE" || return 0 + + local md5sum old_md5sum + md5sum="$(md5sum "$DPKG_ROOT$CONFFILE" | sed -e 's/ .*//')" + old_md5sum="$(dpkg-query -W -f='${Conffiles}' "$PACKAGE" | \ + sed -n -e "\\'^ $CONFFILE ' { s/ obsolete$//; s/.* //; p }")" + if [ "$md5sum" != "$old_md5sum" ]; then + mv -f "$DPKG_ROOT$CONFFILE" "$DPKG_ROOT$CONFFILE.dpkg-backup" + else + mv -f "$DPKG_ROOT$CONFFILE" "$DPKG_ROOT$CONFFILE.dpkg-remove" + fi +} + +finish_rm_conffile() { + local CONFFILE="$1" + + if [ -e "$DPKG_ROOT$CONFFILE.dpkg-backup" ]; then + echo "Obsolete conffile $DPKG_ROOT$CONFFILE has been modified by you." + echo "Saving as $DPKG_ROOT$CONFFILE.dpkg-bak ..." + mv -f "$DPKG_ROOT$CONFFILE.dpkg-backup" "$DPKG_ROOT$CONFFILE.dpkg-bak" + fi + if [ -e "$DPKG_ROOT$CONFFILE.dpkg-remove" ]; then + echo "Removing obsolete conffile $DPKG_ROOT$CONFFILE ..." + rm -f "$DPKG_ROOT$CONFFILE.dpkg-remove" + fi +} + +abort_rm_conffile() { + local CONFFILE="$1" + local PACKAGE="$2" + + ensure_package_owns_file "$PACKAGE" "$CONFFILE" || return 0 + + if [ -e "$DPKG_ROOT$CONFFILE.dpkg-remove" ]; then + echo "Reinstalling $DPKG_ROOT$CONFFILE that was moved away" + mv "$DPKG_ROOT$CONFFILE.dpkg-remove" "$DPKG_ROOT$CONFFILE" + fi + if [ -e "$DPKG_ROOT$CONFFILE.dpkg-backup" ]; then + echo "Reinstalling $DPKG_ROOT$CONFFILE that was backed-up" + mv "$DPKG_ROOT$CONFFILE.dpkg-backup" "$DPKG_ROOT$CONFFILE" + fi +} + +## +## Functions to rename a conffile during upgrade +## +mv_conffile() { + local OLDCONFFILE="$1" + local NEWCONFFILE="$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 "$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" + [ -n "$DPKG_MAINTSCRIPT_PACKAGE" ] || \ + error "environment variable DPKG_MAINTSCRIPT_PACKAGE is required" + [ "${OLDCONFFILE}" != "${OLDCONFFILE#/}" ] || \ + error "old-conffile '$OLDCONFFILE' is not an absolute path" + [ "${NEWCONFFILE}" != "${NEWCONFFILE#/}" ] || \ + error "new-conffile '$NEWCONFFILE' is not an absolute path" + validate_optional_version "$LASTVERSION" + + 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" ] && [ -n "$2" ] && + dpkg --compare-versions -- "$2" le-nl "$LASTVERSION"; then + prepare_mv_conffile "$OLDCONFFILE" "$PACKAGE" + fi + ;; + postinst) + if [ "$1" = "configure" ] && [ -n "$2" ] && + dpkg --compare-versions -- "$2" le-nl "$LASTVERSION"; then + finish_mv_conffile "$OLDCONFFILE" "$NEWCONFFILE" "$PACKAGE" + fi + ;; + postrm) + if [ "$1" = "abort-install" -o "$1" = "abort-upgrade" ] && + [ -n "$2" ] && + dpkg --compare-versions -- "$2" le-nl "$LASTVERSION"; then + abort_mv_conffile "$OLDCONFFILE" "$PACKAGE" + fi + ;; + *) + debug "$0 mv_conffile not required in $DPKG_MAINTSCRIPT_NAME" + ;; + esac +} + +prepare_mv_conffile() { + local CONFFILE="$1" + local PACKAGE="$2" + + [ -e "$DPKG_ROOT$CONFFILE" ] || return 0 + + ensure_package_owns_file "$PACKAGE" "$CONFFILE" || return 0 + + local md5sum old_md5sum + md5sum="$(md5sum "$DPKG_ROOT$CONFFILE" | sed -e 's/ .*//')" + old_md5sum="$(dpkg-query -W -f='${Conffiles}' "$PACKAGE" | \ + sed -n -e "\\'^ $CONFFILE ' { s/ obsolete$//; s/.* //; p }")" + if [ "$md5sum" = "$old_md5sum" ]; then + mv -f "$DPKG_ROOT$CONFFILE" "$DPKG_ROOT$CONFFILE.dpkg-remove" + fi +} + +finish_mv_conffile() { + local OLDCONFFILE="$1" + local NEWCONFFILE="$2" + local PACKAGE="$3" + + rm -f "$DPKG_ROOT$OLDCONFFILE.dpkg-remove" + + [ -e "$DPKG_ROOT$OLDCONFFILE" ] || return 0 + ensure_package_owns_file "$PACKAGE" "$OLDCONFFILE" || return 0 + + echo "Preserving user changes to $DPKG_ROOT$NEWCONFFILE (renamed from $DPKG_ROOT$OLDCONFFILE)..." + if [ -e "$DPKG_ROOT$NEWCONFFILE" ]; then + mv -f "$DPKG_ROOT$NEWCONFFILE" "$DPKG_ROOT$NEWCONFFILE.dpkg-new" + fi + mv -f "$DPKG_ROOT$OLDCONFFILE" "$DPKG_ROOT$NEWCONFFILE" +} + +abort_mv_conffile() { + local CONFFILE="$1" + local PACKAGE="$2" + + ensure_package_owns_file "$PACKAGE" "$CONFFILE" || return 0 + + if [ -e "$DPKG_ROOT$CONFFILE.dpkg-remove" ]; then + echo "Reinstalling $DPKG_ROOT$CONFFILE that was moved away" + mv "$DPKG_ROOT$CONFFILE.dpkg-remove" "$DPKG_ROOT$CONFFILE" + 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 "$DPKG_MAINTSCRIPT_PACKAGE" ] || \ + error "environment variable DPKG_MAINTSCRIPT_PACKAGE is required" + [ -n "$PACKAGE" ] || error "cannot identify the package" + [ -n "$SYMLINK" ] || error "symlink parameter is missing" + [ "${SYMLINK#/}" = "$SYMLINK" ] && \ + error "symlink pathname is not an absolute path" + [ "${SYMLINK%/}" = "$SYMLINK" ] || \ + error "symlink pathname ends with a slash" + [ -n "$SYMLINK_TARGET" ] || error "original symlink target is missing" + [ -n "$1" ] || error "maintainer script parameters are missing" + validate_optional_version "$LASTVERSION" + + 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 "$DPKG_ROOT$SYMLINK" ] && + symlink_match "$SYMLINK" "$SYMLINK_TARGET" && + dpkg --compare-versions -- "$2" le-nl "$LASTVERSION"; then + mv -f "$DPKG_ROOT$SYMLINK" "$DPKG_ROOT${SYMLINK}.dpkg-backup" + fi + ;; + postinst) + # We cannot bail depending on the version, as here we only + # know what was the last configured version, and we might + # have been unpacked, then upgraded with an unpack and thus + # never been configured before. + if [ "$1" = "configure" ] && + [ -h "$DPKG_ROOT${SYMLINK}.dpkg-backup" ] && + symlink_match "${SYMLINK}.dpkg-backup" "$SYMLINK_TARGET" + then + rm -f "$DPKG_ROOT${SYMLINK}.dpkg-backup" + fi + ;; + postrm) + if [ "$1" = "purge" ] && [ -h "$DPKG_ROOT${SYMLINK}.dpkg-backup" ]; then + rm -f "$DPKG_ROOT${SYMLINK}.dpkg-backup" + fi + if [ "$1" = "abort-install" -o "$1" = "abort-upgrade" ] && + [ -n "$2" ] && + [ ! -e "$DPKG_ROOT$SYMLINK" ] && + [ -h "$DPKG_ROOT${SYMLINK}.dpkg-backup" ] && + symlink_match "${SYMLINK}.dpkg-backup" "$SYMLINK_TARGET" && + dpkg --compare-versions -- "$2" le-nl "$LASTVERSION"; then + echo "Restoring backup of $DPKG_ROOT$SYMLINK ..." + mv "$DPKG_ROOT${SYMLINK}.dpkg-backup" "$DPKG_ROOT$SYMLINK" + fi + ;; + *) + debug "$0 symlink_to_dir not required in $DPKG_MAINTSCRIPT_NAME" + ;; + esac +} + +## +## Functions to replace a directory with a symlink +## +dir_to_symlink() { + local PATHNAME="${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 "$DPKG_MAINTSCRIPT_PACKAGE" ] || \ + error "environment variable DPKG_MAINTSCRIPT_PACKAGE is required" + [ -n "$PACKAGE" ] || error "cannot identify the package" + [ -n "$PATHNAME" ] || error "directory parameter is missing" + [ "${PATHNAME#/}" = "$PATHNAME" ] && \ + error "directory parameter is not an absolute path" + [ -n "$SYMLINK_TARGET" ] || error "new symlink target is missing" + [ -n "$1" ] || error "maintainer script parameters are missing" + validate_optional_version "$LASTVERSION" + + debug "Executing $0 dir_to_symlink in $DPKG_MAINTSCRIPT_NAME" \ + "of $DPKG_MAINTSCRIPT_PACKAGE" + debug "PATHNAME=$PATHNAME SYMLINK_TARGET=$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 "$DPKG_ROOT$PATHNAME" ] && + [ -d "$DPKG_ROOT$PATHNAME" ] && + dpkg --compare-versions -- "$2" le-nl "$LASTVERSION"; then + prepare_dir_to_symlink "$PACKAGE" "$PATHNAME" + fi + ;; + postinst) + # We cannot bail depending on the version, as here we only + # know what was the last configured version, and we might + # have been unpacked, then upgraded with an unpack and thus + # never been configured before. + if [ "$1" = "configure" ] && + [ -d "$DPKG_ROOT${PATHNAME}.dpkg-backup" ] && + [ ! -h "$DPKG_ROOT$PATHNAME" ] && + [ -d "$DPKG_ROOT$PATHNAME" ] && + [ -f "$DPKG_ROOT$PATHNAME/.dpkg-staging-dir" ]; then + finish_dir_to_symlink "$PATHNAME" "$SYMLINK_TARGET" + fi + ;; + postrm) + if [ "$1" = "purge" ] && + [ -d "$DPKG_ROOT${PATHNAME}.dpkg-backup" ]; then + rm -rf "$DPKG_ROOT${PATHNAME}.dpkg-backup" + fi + if [ "$1" = "abort-install" -o "$1" = "abort-upgrade" ] && + [ -n "$2" ] && + [ -d "$DPKG_ROOT${PATHNAME}.dpkg-backup" ] && + [ \( ! -h "$DPKG_ROOT$PATHNAME" -a \ + -d "$DPKG_ROOT$PATHNAME" -a \ + -f "$DPKG_ROOT$PATHNAME/.dpkg-staging-dir" \) -o \ + \( -h "$DPKG_ROOT$PATHNAME" -a \ + \( "$(readlink "$DPKG_ROOT$PATHNAME")" = "$SYMLINK_TARGET" -o \ + "$(dpkg-realpath "$PATHNAME")" = "$SYMLINK_TARGET" \) \) ] && + dpkg --compare-versions -- "$2" le-nl "$LASTVERSION"; then + abort_dir_to_symlink "$PATHNAME" + fi + ;; + *) + debug "$0 dir_to_symlink not required in $DPKG_MAINTSCRIPT_NAME" + ;; + esac +} + +prepare_dir_to_symlink() +{ + local PACKAGE="$1" + local PATHNAME="$2" + + local LINE + # If there are conffiles we should not perform the switch. + dpkg-query -W -f='${Conffiles}\n' "$PACKAGE" | while read -r LINE; do + case "$LINE" in + "$PATHNAME"/*) + error "directory '$PATHNAME' contains conffiles," \ + "cannot switch to symlink" + ;; + esac + done + + # If there are locally created files or files owned by another package + # we should not perform the switch. + export DPKG_MAINTSCRIPT_HELPER_INTERNAL_API="$version" + find "$DPKG_ROOT$PATHNAME" -print0 | \ + xargs -0 -n1 "$0" _internal_pkg_must_own_file "$PACKAGE" || \ + error "directory '$PATHNAME' contains files not owned by" \ + "package $PACKAGE, cannot switch to symlink" + unset DPKG_MAINTSCRIPT_HELPER_INTERNAL_API + + # At this point, we know that the directory either contains no files, + # or only non-conffiles owned by the package. + # + # To do the switch we cannot simply replace it with the final symlink + # just yet, because dpkg needs to remove any file present in the old + # package that have disappeared in the new one, and we do not want to + # lose files resolving to the same pathname in the symlink target. + # + # We cannot replace the directory with a staging symlink either, + # because dpkg will update symlinks to their new target. + # + # So we need to create a staging directory, to avoid removing files + # from other packages, and to trap any new files in the directory + # to move them to their correct place later on. + mv -f "$DPKG_ROOT$PATHNAME" "$DPKG_ROOT${PATHNAME}.dpkg-backup" + mkdir "$DPKG_ROOT$PATHNAME" + + # Mark it as a staging directory, so that we can track things. + touch "$DPKG_ROOT$PATHNAME/.dpkg-staging-dir" +} + +finish_dir_to_symlink() +{ + local PATHNAME="$1" + local SYMLINK_TARGET="$2" + + # Move the contents of the staging directory to the symlink target, + # as those are all new files installed between this package being + # unpacked and configured. + local ABS_SYMLINK_TARGET + if [ "${SYMLINK_TARGET#/}" = "$SYMLINK_TARGET" ]; then + ABS_SYMLINK_TARGET="$(dirname "$PATHNAME")/$SYMLINK_TARGET" + else + ABS_SYMLINK_TARGET="$SYMLINK_TARGET" + fi + rm "$DPKG_ROOT$PATHNAME/.dpkg-staging-dir" + find "$DPKG_ROOT$PATHNAME" -mindepth 1 -maxdepth 1 -print0 | \ + xargs -0 -I% mv -f "%" "$DPKG_ROOT$ABS_SYMLINK_TARGET/" + + # Remove the staging directory. + rmdir "$DPKG_ROOT$PATHNAME" + + # Do the actual switch. + ln -s "$SYMLINK_TARGET" "$DPKG_ROOT$PATHNAME" + + # We are left behind the old files owned by this package in the backup + # directory, just remove it. + rm -rf "$DPKG_ROOT${PATHNAME}.dpkg-backup" +} + +abort_dir_to_symlink() +{ + local PATHNAME="$1" + + echo "Restoring backup of $DPKG_ROOT$PATHNAME ..." + if [ -h "$DPKG_ROOT$PATHNAME" ]; then + rm -f "$DPKG_ROOT$PATHNAME" + else + # The staging directory must be empty, as no other package + # should have been unpacked in between. + rm -f "$DPKG_ROOT$PATHNAME/.dpkg-staging-dir" + rmdir "$DPKG_ROOT$PATHNAME" + fi + + mv "$DPKG_ROOT${PATHNAME}.dpkg-backup" "$DPKG_ROOT$PATHNAME" +} + +# Common functions +validate_optional_version() { + local VERSION="$1" + + if [ -z "$VERSION" ]; then + return + fi + + if ! VERSIONCHECK=$(dpkg --validate-version -- "$VERSION" 2>&1); then + error "$VERSIONCHECK" + fi +} + +ensure_package_owns_file() { + local PACKAGE="$1" + local FILE="$2" + + if ! dpkg-query -L "$PACKAGE" | grep -F -q -x "$FILE"; then + debug "File '$FILE' not owned by package " \ + "'$PACKAGE', skipping $command" + return 1 + fi + return 0 +} + +internal_pkg_must_own_file() +{ + local PACKAGE="$1" + local FILE="${2##"$DPKG_ROOT"}" + + if [ "$DPKG_MAINTSCRIPT_HELPER_INTERNAL_API" != "$version" ]; then + error "internal API used by external command" + fi + + if ! ensure_package_owns_file "$PACKAGE" "$FILE"; then + error "file '$FILE' not owned by package '$PACKAGE'" + fi + return 0 +} + +symlink_match() +{ + local SYMLINK="$1" + local SYMLINK_TARGET="$2" + + [ "$(readlink "$DPKG_ROOT$SYMLINK")" = "$SYMLINK_TARGET" ] || \ + [ "$(dpkg-realpath "$SYMLINK")" = "$SYMLINK_TARGET" ] +} + +usage() { + cat <<END +Usage: $PROGNAME <command> <parameter>... -- <maintainer-script-parameter>... + +Commands: + supports <command> + Returns 0 (success) if the given command is supported, 1 otherwise. + 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. + symlink_to_dir <pathname> <old-symlink-target> [<last-version> [<package>]] + Replace a symlink with a directory. Must be called in preinst, + postinst and postrm. + dir_to_symlink <pathname> <new-symlink-target> [<last-version> [<package>]] + Replace a directory with a symlink. Must be called in preinst, + postinst and postrm. + help + -?, --help + Show this help message. + --version + Show the version. +END +} + +# Main code +set -e + +PROGNAME=$(basename "$0") +version="unknown" +DPKG_ROOT=${DPKG_ROOT:+$(realpath "$DPKG_ROOT")} +# Remove default root dir. +if [ "$DPKG_ROOT" = "/" ]; then + DPKG_ROOT="" +fi +export DPKG_ROOT + +PKGDATADIR_DEFAULT=src +PKGDATADIR="${DPKG_DATADIR:-$PKGDATADIR_DEFAULT}" + +# shellcheck source=src/sh/dpkg-error.sh +. "$PKGDATADIR/sh/dpkg-error.sh" + +setup_colors + +command="$1" +[ $# -gt 0 ] || badusage "missing command" +shift + +case "$command" in +supports) + case "$1" in + rm_conffile|mv_conffile|symlink_to_dir|dir_to_symlink) + code=0 + ;; + *) + code=1 + ;; + esac + if [ -z "$DPKG_MAINTSCRIPT_NAME" ]; then + warning "environment variable DPKG_MAINTSCRIPT_NAME missing" + code=1 + fi + if [ -z "$DPKG_MAINTSCRIPT_PACKAGE" ]; then + warning "environment variable DPKG_MAINTSCRIPT_PACKAGE missing" + code=1 + fi + exit $code + ;; +rm_conffile) + rm_conffile "$@" + ;; +mv_conffile) + mv_conffile "$@" + ;; +symlink_to_dir) + symlink_to_dir "$@" + ;; +dir_to_symlink) + dir_to_symlink "$@" + ;; +_internal_pkg_must_own_file) + # This is an internal command, must not be used outside this program. + internal_pkg_must_own_file "$@" + ;; +--help|help|-?) + usage + ;; +--version) + cat <<END +Debian $PROGNAME version $version. + +This is free software; see the GNU General Public License version 2 or +later for copying conditions. There is NO warranty. +END + ;; +*) + badusage "command $command is unknown +Hint: upgrading dpkg to a newer version might help." +esac + +exit 0 |