severity 34717 wishlist thanks Severity rationale: the current behaviour is bug free, and works. Having /bin/sh point to ash is not a release critical feature. A workaround exists: use: # dpkg-divert --rename --add /bin/sh # ln -sf ash /bin/sh to get the desired behaviour without changing bash.
But read on anyway... On Sat, Aug 28, 1999 at 09:18:17AM -0400, Michael Stone wrote: > On Sat, Aug 28, 1999 at 02:10:01PM +1000, Anthony Towns wrote: > > Note that the first maintainer script after "remove /bin/sh" is the > > postinst -- adding the link in the preinst doesn't do us any good on > > upgrades. > Ok. I stand corrected. How's this for a nasty hack: what if the preinst > diverts /bin/sh before cretaing the symlink? You're one sick individual. The following seems to work: (consider it pseudocode, however) preinst: #!/bin/sh set -e dpkg --assert-support-predepends || (echo "new dpkg"; exit 1) # are we upgrading from a version of bash that includes /bin/sh in # the package? If so, divert it so it doesn't get removed when # unpacking. # # NB: dpkg-divert seems to get confused if a package diverts one of its # own files, so we use a pseudo package of "bash-preinst" here. Note # that this diversion gets removed in the postinst. if [ "$1" = "upgrade" ]; then if dpkg --compare-versions "$2" lt 2.02.1-1.7; then /usr/sbin/dpkg-divert --package bash-preinst \ --add --rename --divert /bin/sh.bash-old \ --quiet /bin/sh || ( echo "couldn't divert."; exit 1 ) fi fi # We've ensured any /bin/sh link won't be rm'ed after unpacking -- so # we can make a link here to ensure /bin/sh exists even if bash is only # unpacked and not configured. if [ -e /bin/sh ]; then true else echo "Adding symlink" ln -s bash /bin/sh fi postinst: #!/bin/bash set -e # if the diversion still exists, get rid of it -- it's only necessary # while bash is unconfigured dpkg-divert --quiet --package bash-preinst --remove /bin/sh install-info --quiet --description="GNU Bourne-Again SHell Features." \ --section "General Commands" "General Commands" /usr/info/bash.info.gz Now for the longer version. First, the preinst in C: ----bash.preinst.c---- /* Copyright (c) 1999 Anthony Towns * * You may freely use, distribute, and modify this program. */ #include <stdio.h> #include <stdlib.h> #include <stdarg.h> #include <errno.h> #include <unistd.h> #include <sys/stat.h> #include <sys/types.h> #include <sys/wait.h> int mysystem(char *filename, ...) { char *args[100]; int i = 0; va_list ap; pid_t child; args[0] = filename; va_start(ap, filename); while(++i < 100 && (args[i] = va_arg(ap, char*))) ; args[99] = NULL; switch(child = fork()) { case -1: /* fork failed */ return 127; case 0: /* i'm the child */ { execv(filename, args); return 127; } default: /* i'm the parent */ { int status; pid_t pid; pid = wait(&status); if (pid == child) { if (WIFEXITED(status)) { return WEXITSTATUS(status); } } return 127; } } } int dpkg_ver(char *left, char *right) { int result; if (strcmp(left, right) == 0) return 0; result = mysystem("/usr/bin/dpkg", "--compare-versions", left, "lt", right, NULL); if (result == 0) return -1; if (result == 1) return 1; /* otherwise there's been a problem. */ return 0; } int main(int argc, char **argv) { struct stat stat_buf; if (mysystem("/usr/bin/dpkg", "--assert-support-predepends", NULL) != 0) { printf("\nPlease upgrade to a new version of dpkg\n\n"); return EXIT_FAILURE; } /* are we upgrading from a version of bash that includes /bin/sh in * the package? If so, divert it so it doesn't get removed when unpacking. * * NB: dpkg-divert seems to get confused if a package diverts one of its * own files, so we use a pseudo package of "bash-preinst" here. Note that * this diversion gets removed in the postinst. */ if (argc >= 2 && strcmp(argv[1],"upgrade") == 0) { if (argc == 2 || dpkg_ver(argv[2], "2.02.1-1.7") < 0) { if (mysystem("/usr/sbin/dpkg-divert", "--package", "bash-preinst", "--add", "--rename", "--divert", "/bin/sh.bash-old", "--quiet", "/bin/sh", NULL) != 0) { printf("/bin/sh: Couldn't ensure /bin/sh won't be lost " "during upgrade; aborting\n"); return EXIT_FAILURE; } } } /* /bin/sh link won't be rm'ed after unpacking -- so we can make a link * to ensure /bin/sh exists even if bash is only unpacked and not * configured. */ if (lstat("/bin/sh", &stat_buf) == 0 || errno != ENOENT) { /* /bin/sh already exists; presume the admin knows what ey's doing, * and leave it as is. */ } else { printf("Adding symlink /bin/sh to /bin/bash.\n"); if (symlink("/bin/bash", "/bin/sh") < 0) { perror("/bin/sh"); return EXIT_FAILURE; } } return EXIT_SUCCESS; } ----bash.preinst.c---- Next, some demonstration that it actually works. First, when Apt decides to remove and reinstall bash: ====REMOVAL AND REINSTALLATION==== Script started on Mon Aug 30 16:03:06 1999 Stand-alone shell (version 2.1) > ls -l /bin/sh /bin/bash; dpkg -S /bin/sh; dpkg -l | grep bash -rwxr-xr-x 1 root root 447760 Aug 16 05:37 /bin/bash lrwxrwxrwx 1 root root 4 Aug 30 16:03 /bin/sh -> bash bash: /bin/sh ii bash 2.02.1-1.6 The GNU Bourne Again SHell > dpkg --force-depends --force-remove-essential --remove bash dpkg - warning, overriding problem because --force enabled: This is an essential package - it should not be removed. dpkg - warning, overriding problem because --force enabled: This is an essential package - it should not be removed. dpkg - warning, overriding problem because --force enabled: This is an essential package - it should not be removed. dpkg - warning, overriding problem because --force enabled: This is an essential package - it should not be removed. dpkg - warning, overriding problem because --force enabled: This is an essential package - it should not be removed. dpkg - warning, overriding problem because --force enabled: This is an essential package - it should not be removed. dpkg - warning, overriding problem because --force enabled: This is an essential package - it should not be removed. dpkg - warning, overriding problem because --force enabled: This is an essential package - it should not be removed. dpkg - warning, overriding problem because --force enabled: This is an essential package - it should not be removed. dpkg - warning, overriding problem because --force enabled: This is an essential package - it should not be removed. dpkg - warning, overriding problem because --force enabled: This is an essential package - it should not be removed. dpkg - warning, overriding problem because --force enabled: This is an essential package - it should not be removed. dpkg - warning, overriding problem because --force enabled: This is an essential package - it should not be removed. dpkg - warning, overriding problem because --force enabled: This is an essential package - it should not be removed. dpkg - warning, overriding problem because --force enabled: This is an essential package - it should not be removed. dpkg - warning, overriding problem because --force enabled: This is an essential package - it should not be removed. dpkg: bash: dependency problems, but removing anyway as you request: bug depends on bash (>= 2.01.1-1). (Reading database ... 44579 files and directories currently installed.) Removing bash ... > ls -l /bin/sh /bin/bash; dpkg -S /bin/sh; dpkg -l | grep bash > dpkg --unpack bash_2.02.1-1.7_i386.deb Selecting previously deselected package bash. (Reading database ... 44440 files and directories currently installed.) Unpacking bash (from bash_2.02.1-1.7_i386.deb) ... Adding symlink /bin/sh to /bin/bash. > ls -l /bin/sh /bin/bash; dpkg -S /bin/sh; dpkg -l | grep bash -rwxr-xr-x 1 root root 447760 Aug 30 15:44 /bin/bash lrwxrwxrwx 1 root root 9 Aug 30 16:03 /bin/sh -> /bin/bash dpkg: /bin/sh not found. iU bash 2.02.1-1.7 The GNU Bourne Again SHell > dpkg --configure bash Setting up bash (2.02.1-1.7) ... > ls -l /bin/sh /bin/bash; dpkg -S /bin/sh; dpkg -l | grep bash -rwxr-xr-x 1 root root 447760 Aug 30 15:44 /bin/bash lrwxrwxrwx 1 root root 9 Aug 30 16:03 /bin/sh -> /bin/bash dpkg: /bin/sh not found. ii bash 2.02.1-1.7 The GNU Bourne Again SHell > Script done on Mon Aug 30 16:04:21 1999 ====REMOVAL AND REINSTALLATION==== Next, when Joe Average decides to upgrade bash from one release to the next: ====UPGRADE==== Script started on Mon Aug 30 16:04:30 1999 Stand-alone shell (version 2.1) > ls -l /bin/sh /bin/bash; dpkg -S /bin/sh; dpkg -l | grep bash -rwxr-xr-x 1 root root 447760 Aug 16 05:37 /bin/bash lrwxrwxrwx 1 root root 4 Aug 30 16:04 /bin/sh -> bash bash: /bin/sh ii bash 2.02.1-1.6 The GNU Bourne Again SHell > dpkg --unpack bash_2.02.1-1.7_i386.deb (Reading database ... 44579 files and directories currently installed.) Preparing to replace bash 2.02.1-1.6 (using bash_2.02.1-1.7_i386.deb) ... Adding symlink /bin/sh to /bin/bash. Unpacking replacement bash ... > ls -l /bin/sh /bin/bash; dpkg -S /bin/sh; dpkg -l | grep bash -rwxr-xr-x 1 root root 447760 Aug 30 15:44 /bin/bash lrwxrwxrwx 1 root root 9 Aug 30 16:04 /bin/sh -> /bin/bash diversion by bash-preinst from: /bin/sh diversion by bash-preinst to: /bin/sh.bash-old iU bash 2.02.1-1.7 The GNU Bourne Again SHell > dpkg --configure bash Setting up bash (2.02.1-1.7) ... > ls -l /bin/sh /bin/bash; dpkg -S /bin/sh; dpkg -l | grep bash -rwxr-xr-x 1 root root 447760 Aug 30 15:44 /bin/bash lrwxrwxrwx 1 root root 9 Aug 30 16:04 /bin/sh -> /bin/bash dpkg: /bin/sh not found. ii bash 2.02.1-1.7 The GNU Bourne Again SHell > Script done on Mon Aug 30 16:05:23 1999 ====UPGRADE==== Finally, when Jill Not-so-average, who's followed the aforementioned advice about diverting /bin/sh tries the upgrade: (the main problem being that she has to remove the diversion before the upgrade will go ahead. It's the preinst that's failing however, so no actual damage is done. It'd probably be a good idea to make the error message a little bit more helpful in this case, actually) ====UPGRADE WITH DIVERSION==== Script started on Mon Aug 30 16:07:31 1999 Stand-alone shell (version 2.1) > dpkg-divert --rename --add /bin/sh Adding `local diversion of /bin/sh to /bin/sh.distrib' > ln -s ash /bin/sh > ls -l /bin/sh /bin/bash; dpkg -S /bin/sh; dpkg -l | grep bash -rwxr-xr-x 1 root root 447760 Aug 16 05:37 /bin/bash lrwxrwxrwx 1 root root 3 Aug 30 16:07 /bin/sh -> ash local diversion from: /bin/sh local diversion to: /bin/sh.distrib bash: /bin/sh ii bash 2.02.1-1.6 The GNU Bourne Again SHell > dpkg --install bash_2.02.1-1.6_i386.deb (Reading database ... 44580 files and directories currently installed.) Preparing to replace bash 2.02.1-1.6 (using bash_2.02.1-1.6_i386.deb) ... Unpacking replacement bash ... Setting up bash (2.02.1-1.6) ... > ls -l /bin/sh /bin/bash; dpkg -S /bin/sh; dpkg -l | grep bash -rwxr-xr-x 1 root root 447760 Aug 16 05:37 /bin/bash lrwxrwxrwx 1 root root 3 Aug 30 16:07 /bin/sh -> ash local diversion from: /bin/sh local diversion to: /bin/sh.distrib bash: /bin/sh ii bash 2.02.1-1.6 The GNU Bourne Again SHell > dpkg --unpack bash_2.02.1-1.7_i386.deb (Reading database ... 44580 files and directories currently installed.) Preparing to replace bash 2.02.1-1.6 (using bash_2.02.1-1.7_i386.deb) ... dpkg-divert: `diversion of /bin/sh to /bin/sh.bash-old by bash-preinst' clashes with `local diversion of /bin/sh to /bin/sh.distrib' /bin/sh: Couldn't ensure /bin/sh won't be lost during upgrade; aborting dpkg: error processing bash_2.02.1-1.7_i386.deb (--unpack): subprocess pre-installation script returned error exit status 1 Errors were encountered while processing: bash_2.02.1-1.7_i386.deb > dpkg-divert --remove /bin/sh Removing `local diversion of /bin/sh to /bin/sh.distrib' > dpkg --install bash_2.02.1-1.7_i386.deb (Reading database ... 44579 files and directories currently installed.) Preparing to replace bash 2.02.1-1.6 (using bash_2.02.1-1.7_i386.deb) ... Adding symlink /bin/sh to /bin/bash. Unpacking replacement bash ... Setting up bash (2.02.1-1.7) ... > ls -l /bin/sh /bin/bash; dpkg -S /bin/sh; dpkg -l | grep bash -rwxr-xr-x 1 root root 447760 Aug 30 15:44 /bin/bash lrwxrwxrwx 1 root root 9 Aug 30 16:09 /bin/sh -> /bin/bash dpkg: /bin/sh not found. ii bash 2.02.1-1.7 The GNU Bourne Again SHell > ln -sf ash /bin/sh > dpkg --install bash_2.02.1-1.7_i386.deb (Reading database ... 44578 files and directories currently installed.) Preparing to replace bash 2.02.1-1.7 (using bash_2.02.1-1.7_i386.deb) ... Unpacking replacement bash ... Setting up bash (2.02.1-1.7) ... > ls -l /bin/sh /bin/bash; dpkg -S /bin/sh; dpkg -l | grep bash -rwxr-xr-x 1 root root 447760 Aug 30 15:44 /bin/bash lrwxrwxrwx 1 root root 3 Aug 30 16:09 /bin/sh -> ash dpkg: /bin/sh not found. ii bash 2.02.1-1.7 The GNU Bourne Again SHell > Script done on Mon Aug 30 16:10:29 1999 ====UPGRADE WITH DIVERSION==== Cheers, aj -- Anthony Towns <[EMAIL PROTECTED]> <http://azure.humbug.org.au/~aj/> I don't speak for anyone save myself. PGP encrypted mail preferred. ``The thing is: trying to be too generic is EVIL. It's stupid, it results in slower code, and it results in more bugs.'' -- Linus Torvalds