On Mon, Jan 30, 2017 at 06:38:16PM +0000, Robie Basak wrote:
> > So how about this, just a sketch at the moment rather than a full
> > patch?
>
> Your sketch seems good to me, assuming that "dpkg-query --search" is
> permitted from maintainer scripts (I know there are some re-entrancy
> problems with some particular types of dpkg-related invocations?)
> [...]
>
> I wondered this too. But without thinking it through in more detail,
> it'd certainly be better than what we have now.
Please find attached a patch against the current
mysql-5.7/debian/master branch on alioth. I have also updated the
github branch for mariadb-10.1 to address the same issue (the one with
a pull request to otto/mariadb-10.1).
It's been tested for upgrades, clean install, remove and purge.
Best wishes,
Julian
diff --git a/debian/mysql-server-5.7.lintian-overrides b/debian/mysql-server-5.7.lintian-overrides
index f1672c49..c5732994 100644
--- a/debian/mysql-server-5.7.lintian-overrides
+++ b/debian/mysql-server-5.7.lintian-overrides
@@ -1,3 +1,5 @@
# These long lines reproduce actual output and to reformat them
# would damage the integrity of the man page.
manpage-has-errors-from-man usr/share/man/man1/mysqlbinlog.1.gz 1893: warning [p 13, 5.3i, div `3tbd3,2', 0.8i]: can't break line
+# the second update-rc.d is informational only: see postrm for details
+mysql-server-5.7: duplicate-updaterc.d-calls-in-postrm mysql
diff --git a/debian/mysql-server-5.7.postinst b/debian/mysql-server-5.7.postinst
index 54adbd09..e7e7f823 100755
--- a/debian/mysql-server-5.7.postinst
+++ b/debian/mysql-server-5.7.postinst
@@ -22,27 +22,8 @@ run_init_sql() {
return $result
}
-# To avoid having hardcoded paths in the script, we do a search on the path, as suggested at:
-# https://www.debian.org/doc/manuals/developers-reference/ch06.en.html#bpp-debian-maint-scripts
-pathfind() {
- OLDIFS="$IFS"
- IFS=:
- for p in $PATH; do
- if [ -x "$p/$*" ]; then
- IFS="$OLDIFS"
- return 0
- fi
- done
- IFS="$OLDIFS"
- return 1
-}
-
invoke() {
- if pathfind invoke-rc.d; then
- invoke-rc.d mysql $1
- else
- /etc/init.d/mysql $1
- fi
+ invoke-rc.d mysql $1
}
# Check if server is able to start. If it fails we abort early and refer
@@ -315,6 +296,27 @@ if [ "$1" = "configure" ]; then
invoke start
fi
fi
+
+ # Fix broken postrms in mysql-server-5.[1-6] and mariadb-server-10.[01]
+ # packages to prevent purging these packages from breaking our package.
+ # (See #852495) It is unlikely that a user would have mariadb-server
+ # postrm files lying around, but we aim to be safe.
+
+ # We comment out all of the commands which assume that there is no other
+ # mysql server installed.
+ # (Because of the Conflicts in the control file for this package, they can
+ # only possibly be in a configuration-only state at this point. And this
+ # cannot harm even if the system is in a very broken state and we are being
+ # configured in spite of those packages being in a different state.)
+ olds=$(ls /var/lib/dpkg/info/mysql-server-5.[1-6].postrm /var/lib/dpkg/info/mariadb-server-10.0.postrm 2>/dev/null || true)
+ if [ -f /var/lib/dpkg/info/mariadb-server-10.1.postrm ]; then
+ if ! grep -q fullpurge /var/lib/dpkg/info/mariadb-server-10.1.postrm; then
+ olds="$olds /var/lib/dpkg/info/mariadb-server-10.1.postrm"
+ fi
+ fi
+ if [ -n "$olds" ]; then
+ perl -i -pe 's/stop_server(?=\s|$)/# stop_server/; s/^(\s*)((?:update|invoke)-rc\.d.*$)/$1# $2\n$1true/; s/^(\s*)(deb-systemd-helper.*$)/$1# $2\n$1true/; s%rm -f "/etc/apparmor.d%# rm -f "/etc/apparmor.d%' $olds
+ fi
fi
# forget we ever saw the password. don't use reset to keep the seen status
diff --git a/debian/mysql-server-5.7.postrm b/debian/mysql-server-5.7.postrm
index 49d45f1b..a106ec29 100755
--- a/debian/mysql-server-5.7.postrm
+++ b/debian/mysql-server-5.7.postrm
@@ -11,49 +11,33 @@ if [ -n "$DEBIAN_SCRIPT_DEBUG" ]; then set -v -x; DEBIAN_SCRIPT_TRACE=1; fi
${DEBIAN_SCRIPT_TRACE:+ echo "#42#DEBUG# RUNNING $0 $*" 1>&2 }
mysql_cfgdir=/etc/mysql
-MYADMIN="/usr/bin/mysqladmin --defaults-file=/etc/mysql/debian.cnf"
-
-# To avoid having hardcoded paths in the script, we do a search on the path, as suggested at:
-# https://www.debian.org/doc/manuals/developers-reference/ch06.en.html#bpp-debian-maint-scripts
-pathfind() {
- OLDIFS="$IFS"
- IFS=:
- for p in $PATH; do
- if [ -x "$p/$*" ]; then
- IFS="$OLDIFS"
- return 0
- fi
- done
- IFS="$OLDIFS"
- return 1
-}
-
-# Try to stop the server in a sane way. If it does not success let the admin
-# do it himself. No database directories should be removed while the server
-# is running!
-stop_server() {
- set +e
- if pathfind invoke-rc.d; then
- invoke-rc.d mysql stop
- else
- /etc/init.d/mysql stop
- fi
- errno=$?
- set -e
- if [ "$?" != 0 ]; then
- echo "Trying to stop the MySQL server resulted in exitcode $?." 1>&2
- echo "Stop it yourself and try again!" 1>&2
- exit 1
+# Do we (offer to) do a full purge, or is there another mysql server
+# present? This includes within it a check for "$1" = purge.
+fullpurge=no
+if [ "$1" = purge ]; then
+ if [ ! \( -x /usr/sbin/mysqld -o -L /usr/sbin/mysqld \) ]; then
+ fullpurge=yes
+ elif [ -x /usr/sbin/mysqld ]; then
+ # Does this /usr/sbin/mysqld belong to our server-core package?
+ # If so, we can offer to do a full purge, otherwise we do not.
+
+ # Use the DPKG_MAINTSCRIPT_PACKAGE to avoid hardcoding the package
+ # name; this reduces the chances of future errors creeping in.
+ # If we're being run outside of a dpkg run, then this is safe.
+ package=${DPKG_MAINTSCRIPT_PACKAGE}
+ corepackage=$(echo "$package" | sed -e 's/server-/server-core-/')
+ daemonpackage=$(dpkg-query -S /usr/sbin/mysqld 2>/dev/null | cut -d: -f1)
+ if [ "$corepackage" = "$daemonpackage" -a -n "$corepackage" ]; then
+ fullpurge=yes
+ fi
fi
-}
+fi
case "$1" in
purge|remove|upgrade|failed-upgrade|abort-install|abort-upgrade|disappear)
- if [ -n "`$MYADMIN ping 2>/dev/null`" ]; then
- stop_server
- sleep 2
- fi
+ # We handle purge actions below. The server has already been stopped
+ # if necessary by the prerm.
;;
*)
echo "postrm called with unknown argument '$1'" 1>&2
@@ -72,7 +56,7 @@ esac
#
# - When purging, ask if data files should also be removed
#
-if [ "$1" = "purge" ]; then
+if [ $fullpurge = yes ]; then
# we remove the mysql user only after all his owned files are purged
rm -f /var/log/mysql.{log,err}{,.0,.[1234567].gz}
rm -rf /var/log/mysql
@@ -84,13 +68,84 @@ if [ "$1" = "purge" ]; then
# never remove the debian.cnf when the databases are still existing
# else we ran into big trouble on the next install!
rm -f /etc/mysql/debian.cnf
- rm -rf /var/lib/mysql
+ # Remove all contents from /var/lib/mysql except if it's a
+ # directory with file system data. See #829491 for details and
+ # #608938 for potential mysql-server leftovers which erroneously
+ # had been renamed.
+ # Attempt removal only if the directory hasn't already been removed
+ # by dpkg to avoid failing on "No such file or directory" errors.
+ if [ -d /var/lib/mysql ]
+ then
+ find /var/lib/mysql -mindepth 1 \
+ -not -path '*/lost+found/*' -not -name 'lost+found' \
+ -not -path '*/lost@002bfound/*' -not -name 'lost@002bfound' \
+ -delete
+
+ # "|| true" still needed as rmdir still exits with non-zero if
+ # /var/lib/mysql is a mount point
+ rmdir --ignore-fail-on-non-empty /var/lib/mysql || true
+ fi
+ rm -rf /var/run/mysqld # this directory is created by the init script, don't leave behind
rm -rf /var/lib/mysql-files
rm -rf /var/lib/mysql-keyring
userdel mysql || true
fi
fi
-#DEBHELPER#
+# We manually add the debhelper snippets here to ensure that when purging,
+# only safe-to-run snippets are run if another mysql-server or mariadb-server
+# package is installed.
+
+# Automatically added by dh_installinit
+# modified to protect against another mysql server package being installed
+if [ $fullpurge = yes ]; then
+ update-rc.d mysql remove >/dev/null
+fi
+
+
+# In case this system is running systemd, we make systemd reload the unit files
+# to pick up changes.
+if [ -d /run/systemd/system ] ; then
+ systemctl --system daemon-reload >/dev/null || true
+fi
+# End automatically added section
+# Automatically added by dh_systemd_enable
+if [ "$1" = "remove" ]; then
+ if [ -x "/usr/bin/deb-systemd-helper" ]; then
+ deb-systemd-helper mask mysql.service >/dev/null
+ fi
+fi
+
+# modified to protect against another mysql server package being installed
+if [ $fullpurge = yes ]; then
+ if [ -x "/usr/bin/deb-systemd-helper" ]; then
+ deb-systemd-helper purge mysql.service >/dev/null
+ deb-systemd-helper unmask mysql.service >/dev/null
+ fi
+fi
+# End automatically added section
+# Automatically added by dh_installdebconf
+if [ "$1" = purge ] && [ -e /usr/share/debconf/confmodule ]; then
+ . /usr/share/debconf/confmodule
+ db_purge
+fi
+# End automatically added section
+# Automatically added by dh_apparmor
+# modified to protect against another mysql server package being installed
+if [ $fullpurge = yes ] && ! [ -e "/etc/apparmor.d/usr.sbin.mysqld" ] ; then
+ rm -f "/etc/apparmor.d/disable/usr.sbin.mysqld" || true
+ rm -f "/etc/apparmor.d/force-complain/usr.sbin.mysqld" || true
+ rm -f "/etc/apparmor.d/local/usr.sbin.mysqld" || true
+ rmdir /etc/apparmor.d/disable 2>/dev/null || true
+ rmdir /etc/apparmor.d/local 2>/dev/null || true
+ rmdir /etc/apparmor.d 2>/dev/null || true
+fi
+# End automatically added section
exit 0
+
+# We add the debhelper snippets here, after the exit 0, so that they can
+# be visually checked in the future to ensure that nothing has been left
+# out above.
+
+#DEBHELPER#
diff --git a/debian/mysql-server-5.7.preinst b/debian/mysql-server-5.7.preinst
index 4ac328cc..143cf61d 100755
--- a/debian/mysql-server-5.7.preinst
+++ b/debian/mysql-server-5.7.preinst
@@ -20,21 +20,6 @@ DATADIR=/var/lib/mysql
LOGDIR=/var/log/mysql
UPGRADEDIR=/var/lib/mysql-upgrade
-# To avoid having hardcoded paths in the script, we do a search on the path, as suggested at:
-# https://www.debian.org/doc/manuals/developers-reference/ch06.en.html#bpp-debian-maint-scripts
-pathfind() {
- OLDIFS="$IFS"
- IFS=:
- for p in $PATH; do
- if [ -x "$p/$*" ]; then
- IFS="$OLDIFS"
- return 0
- fi
- done
- IFS="$OLDIFS"
- return 1
-}
-
# Try to stop the server in a sane way. If it does not success let the admin
# do it himself. No database directories should be removed while the server
# is running! Another mysqld in e.g. a different chroot is fine for us.
@@ -42,12 +27,7 @@ stop_server() {
if [ ! -x /etc/init.d/mysql ]; then return; fi
set +e
- if pathfind invoke-rc.d; then
- cmd="invoke-rc.d mysql stop"
- else
- cmd="/etc/init.d/mysql stop"
- fi
- $cmd
+ invoke-rc.d mysql stop
errno=$?
set -e