Hi Gerrit,

Ken Bloom wrote:

> I can report on the broken scenario, since I made this change just a
> few days ago to have dash provide /bin/sh on its own.
> 
> The following instructions are given in
> /usr/share/doc/bash/README.Debian.gz for making /bin/sh point to
> something else.
> 
>    Type
> 
>         dpkg-divert --add /bin/sh
> 
>    and then point it to whatever you want. Upgrades to bash  won't upgrade
>    the /bin/sh symlink. To put /bin/sh under dpkg control again, type
> 
>         dpkg-divert --remove /bin/sh

Here's a patch implementing (II) from
<http://bugs.debian.org/cgi-bin/bugreport.cgi?msg=97;bug=546528>:

-- 8< --
Subject: debian/dash.preinst: Cope better with local diversions

Before dash was essential, local sysadmins and various packages
like dash, pdksh, posh, and mksh would use dpkg-divert to redirect
bash's /bin/sh elsewhere before installing their own /bin/sh
symlink.

Unfortunately now that dash is essential, that method means
trouble: any diversion by a package other than dash and bash will
divert both /bin/sh symlinks to the same destination, resulting
in a file conflict between essential packages (ouch).

The fix depends on the specific case:

A.  Local diversions to make room for bash or dash can be
replaced by package-specific diversions.

B.  Diversions making room for other shells will have to wait
until bash or dash loses its /bin/sh symlink.

This patch handles case A, by treating the target of the
/bin/sh symlink as sacred and using that to decide which
package should divert /bin/sh.

Caveats:

 - Without this patch, dash would set up its /bin/sh symlink
   immediately when first installed.  With it, it leaves /bin/sh
   as is until postinst (which I consider to be better behavior
   anyway).

 - set_diversions () could be interrupted between removing an
   old diversion and adding a new one, with unpleasant
   consequences.

   The old preinst has that problem, too.  dpkg-divert probably
   needs to learn a new option to transfer diversions between
   packages before we can fix it properly.

Case B is not handled by this patch; it would still be reported
as a file conflict.
---
Thoughts?

 debian/changelog    |    2 +
 debian/dash.preinst |   97 ++++++++++++++++++++++++++++++++++++++++-----------
 2 files changed, 78 insertions(+), 21 deletions(-)

diff --git a/debian/changelog b/debian/changelog
index 808edf0..18ba498 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -2,6 +2,8 @@ dash (0.5.5.1-7.1) unstable; urgency=low
 
   * debian/dash.preinst: change shebang line to use /bin/bash
     (closes: #546528).
+  * debian/dash.preinst: reset diversion for /bin/sh on behalf of
+    the current /bin/sh link target (closes: #538822).
 
  -- Jonathan Nieder <jrnie...@gmail.com>  Sun, 17 Oct 2010 01:58:20 -0500
 
diff --git a/debian/dash.preinst b/debian/dash.preinst
index 4fdbb0d..6287cdd 100644
--- a/debian/dash.preinst
+++ b/debian/dash.preinst
@@ -1,27 +1,82 @@
 #!/bin/bash
+# Examples:
+#
+# A. New install.
+#     1. /bin/sh is already a symlink to dash from bootstrapping.
+#     2. Add diversion by dash of sh.
+#     3. Add diversion by bash of sh.1.gz.
+#
+# B. Upgrade from lenny with bash but dash not installed.
+#     1. /bin/sh is already a symlink to bash.
+#     2. Add diversion by bash of sh.
+#     3. Add diversion by bash of sh.1.gz.
+#
+# C. Upgrade from lenny with mksh configured as /bin/sh.
+#     1. /bin/sh is already a symlink to mksh.
+#     2. Keep diversion by mksh of sh.
+#     3. Keep diversion by mksh of sh.1.gz.
+#
+# D. Upgrade from lenny with dash configured via a local diversion
+#    as /bin/sh <http://bugs.debian.org/538822>.
+#     1. /bin/sh is already a symlink to dash.
+#     2. Replace local diversion with diversion by dash.
+#     3. Add diversion by dash of sh.1.gz.
+#
 set -e
 
-divert() {
-       dfile=$1
-       ltarget=$2
-       div=$(dpkg-divert --list $dfile)
-       distrib=${3:-$dfile.distrib}
-       if [ -z "$div" ]; then
-               dpkg-divert --package dash --divert $distrib --add $dfile
-               # This differs from dpkg-divert's --rename because we
-               # first make a copy of $dfile (the file being diverted)
-               # in $distrib. Then, a symlink to $ltarget is forcibly created
-               # from $dfile.
-               # dpkg-divert's --rename direct equivalent would be:
-               # mv $dfile $distrib -- but we could end up without a symlink
-               cp -dp $dfile $distrib
-               ln -sf $ltarget $dfile
+set_diversions () {
+       if test "$(dpkg-divert --listpackage /bin/sh)" != "$1"
+       then
+               dpkg-divert --quiet --remove /bin/sh
+               dpkg-divert --package "$1" --divert /bin/sh.distrib --add 
/bin/sh
        fi
+       if test "$(dpkg-divert --listpackage /usr/share/man/man1/sh.1.gz)" != 
"$1"
+       then
+               dpkg-divert --remove /usr/share/man/man1/sh.1.gz
+               dpkg-divert --package "$1" \
+                       --divert /usr/share/man/man1/sh.distrib.1.gz \
+                       --add /usr/share/man/man1/sh.1.gz
+       fi
+}
+
+divert_sh () {
+       shell=$(readlink /bin/sh)
+       shell=${shell#/bin/}
+
+       case "$shell" in
+       dash|bash|mksh|ksh|posh|pdksh|zsh)
+               set_diversions "$shell"
+               ;;
+       ksh93)
+               set_diversions ksh
+               ;;
+       mksh-static)
+               set_diversions mksh
+               ;;
+       zsh4|/usr/bin/zsh)
+               set_diversions zsh
+               ;;
+       *)
+               # Unknown shell.  Trust the existing diversion.
+               case "$(dpkg-divert --listpackage /bin/sh)" in
+               dash)
+                       echo >&2 \
+ "dash.preinst: Overwriting /bin/sh -> $shell link as requested by diversion"
+                       ;;
+               "")
+                       echo >&2 "dash.preinst: Overwriting /bin/sh -> $shell 
link."
+               esac
+       esac
 }
 
-# Divert the following files if no diversion exists already
-# It is currently used to prevent the files collision between bash and
-# dash: they both provide the files in the package.
-divert /bin/sh dash
-divert /usr/share/man/man1/sh.1.gz dash.1.gz \
-       /usr/share/man/man1/sh.distrib.1.gz
+# 1. Ensure /bin/sh is a symlink.
+if ! test -h /bin/sh
+then
+       echo >&2 'dash.preinst: No /bin/sh symlink found.  Aborting.'
+       exit 1
+fi
+# 2. Ensure /bin/sh is diverted by the package corresponding to
+#    the symlink target.
+# 3. Set /usr/share/man/man1/sh.1.gz diversion to match /bin/sh
+#    diversion.
+divert_sh
-- 
1.7.2.3.557.gab647.dirty




-- 
To UNSUBSCRIBE, email to debian-bugs-dist-requ...@lists.debian.org
with a subject of "unsubscribe". Trouble? Contact listmas...@lists.debian.org

Reply via email to