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