Package: bash
Version: 5.1-3
Severity: wishlist
Tags: patch
X-Debbugs-Cc: Niels Thykier <ni...@thykier.net>, Guillem Jover 
<guil...@debian.org>
Control: block 958083 by -1

While #958083 asks for removing bash.preinst, this bug asks for even
less: The bash.preinst contains code for upgrading a bash that did
contain /bin/sh to a current one. Since at least wheezy, bash did not
contain /bin/sh, so this code can quite surely go away without trouble.

I'm attaching a patch to makes just this code go away. The deleted code
is practically dead for years. Removing it should be uncontroversial and
after it is removed, it becomes easier to reason about #958083 which
asks to remove the rest of the preinst.

Essentially, this bug splits #958083 into a removing the majority of
code that should be uncontroversial to remove.

Helmut
diff --minimal -Nru bash-5.1/debian/bash.preinst-lib.c 
bash-5.1/debian/bash.preinst-lib.c
--- bash-5.1/debian/bash.preinst-lib.c  2013-10-23 14:41:22.000000000 +0200
+++ bash-5.1/debian/bash.preinst-lib.c  2021-05-31 14:29:20.000000000 +0200
@@ -13,7 +13,6 @@
 #include <sys/stat.h>
 #include <sys/wait.h>
 #include <unistd.h>
-#include <fcntl.h>
 #include <spawn.h>
 
 extern char **environ;
@@ -58,30 +57,12 @@
        die_errno("cannot get status of %s", file);
 }
 
-void set_cloexec(int fd)
-{
-       int flags = fcntl(fd, F_GETFD);
-       if (flags < 0 || fcntl(fd, F_SETFD, flags | FD_CLOEXEC))
-               die_errno("cannot set close-on-exec flag");
-}
-
-void xpipe(int pipefd[2])
-{
-       if (pipe(pipefd))
-               die_errno("cannot create pipe");
-       set_cloexec(pipefd[0]);
-       set_cloexec(pipefd[1]);
-}
-
-void wait_or_die(pid_t child, const char *name, int flags)
+static void wait_or_die(pid_t child, const char *name)
 {
        int status;
        if (waitpid(child, &status, 0) != child)
                die_errno("cannot wait for %s", name);
-       if ((WIFEXITED(status) && WEXITSTATUS(status) == 0) ||
-           ((flags & ERROR_OK) && WIFEXITED(status)) ||
-           ((flags & SIGPIPE_OK) &&
-            WIFSIGNALED(status) && WTERMSIG(status) == SIGPIPE))
+       if (WIFEXITED(status) && WEXITSTATUS(status) == 0)
                return;
 
        if (WIFEXITED(status))
@@ -93,7 +74,7 @@
        die("waitpid is confused (status=%d)", status);
 }
 
-pid_t spawn(const char * const cmd[], int out, int err)
+static pid_t spawn(const char * const cmd[], int out, int err)
 {
        pid_t child;
        posix_spawn_file_actions_t redir;
@@ -111,21 +92,5 @@
 void run(const char * const cmd[])
 {
        pid_t child = spawn(cmd, -1, -1);
-       wait_or_die(child, cmd[0], 0);
-}
-
-FILE *spawn_pipe(pid_t *pid, const char * const cmd[], int errfd)
-{
-       int pipefd[2];
-       FILE *f;
-
-       xpipe(pipefd);
-       *pid = spawn(cmd, pipefd[1], errfd);
-       if (close(pipefd[1]) || (errfd != -1 && close(errfd)))
-               die_errno("cannot close unneeded fd");
-
-       f = fdopen(pipefd[0], "r");
-       if (!f)
-               die_errno("cannot stream read end of pipe");
-       return f;
+       wait_or_die(child, cmd[0]);
 }
diff --minimal -Nru bash-5.1/debian/bash.preinst.c 
bash-5.1/debian/bash.preinst.c
--- bash-5.1/debian/bash.preinst.c      2013-10-23 14:41:22.000000000 +0200
+++ bash-5.1/debian/bash.preinst.c      2021-05-31 14:29:20.000000000 +0200
@@ -4,13 +4,8 @@
  */
 
 #include "bash.preinst.h"
-#include <stdio.h>
-#include <string.h>
 #include <errno.h>
-#include <sys/types.h>
-#include <sys/stat.h>
 #include <unistd.h>
-#include <fcntl.h>
 
 static void backup(const char *file, const char *dest)
 {
@@ -34,103 +29,6 @@
                die_errno("cannot create symlink %s -> %s", link, target);
 }
 
-static void reset_diversion(const char *package, const char *file,
-                                               const char *distrib)
-{
-       const char * const remove_old_diversion[] =
-               {"dpkg-divert", "--package", "bash", "--remove", file, NULL};
-       const char * const new_diversion[] =
-               {"dpkg-divert", "--package", package,
-               "--divert", distrib, "--add", file, NULL};
-       run(remove_old_diversion);
-       run(new_diversion);
-}
-
-static int has_binsh_line(FILE *file)
-{
-       char item[sizeof("/bin/sh\n")];
-
-       while (fgets(item, sizeof(item), file)) {
-               int ch;
-
-               if (!memcmp(item, "/bin/sh\n", strlen("/bin/sh\n") + 1))
-                       return 1;
-               if (strchr(item, '\n'))
-                       continue;
-
-               /* Finish the line. */
-               for (ch = 0; ch != '\n' && ch != EOF; ch = fgetc(file))
-                       ; /* just reading */
-               if (ch == EOF)
-                       break;
-       }
-       if (ferror(file))
-               die_errno("cannot read pipe");
-       return 0;
-}
-
-static int binsh_in_filelist(const char *package)
-{
-       const char * const cmd[] = {"dpkg-query", "-L", package, NULL};
-       pid_t child;
-       int sink;
-       FILE *in;
-       int found;
-
-       /*
-        * dpkg -L $package 2>/dev/null | ...
-        *
-        * Redirection of stderr is for quieter output
-        * when $package is not installed.  If opening /dev/null
-        * fails, no problem; leave stderr alone in that case.
-        */
-       sink = open("/dev/null", O_WRONLY);
-       if (sink >= 0)
-               set_cloexec(sink);
-       in = spawn_pipe(&child, cmd, sink);
-
-       /* ... | grep "^/bin/sh\$" */
-       found = has_binsh_line(in);
-       if (fclose(in))
-               die_errno("cannot close read end of pipe");
-
-       /*
-        * dpkg -L will error out if $package is not already installed.
-        *
-        * We stopped reading early if we found a match, so
-        * tolerate SIGPIPE in that case.
-        */
-       wait_or_die(child, "dpkg-query -L", ERROR_OK |
-                                               (found ? SIGPIPE_OK : 0));
-       return found;
-}
-
-static int undiverted(const char *path)
-{
-       const char * const cmd[] =
-               {"dpkg-divert", "--listpackage", path, NULL};
-       pid_t child;
-       char packagename[sizeof("bash\n")];
-       size_t len;
-       FILE *in = spawn_pipe(&child, cmd, -1);
-       int diverted = 1;
-
-       /* Is $path diverted by someone other than bash? */
-
-       len = fread(packagename, 1, sizeof(packagename), in);
-       if (ferror(in))
-               die_errno("cannot read from dpkg-divert");
-       if (len == 0)
-               diverted = 0;   /* No diversion. */
-       if (len == strlen("bash\n") && !memcmp(packagename, "bash\n", len))
-               diverted = 0;   /* Diverted by bash. */
-
-       if (fclose(in))
-               die_errno("cannot close read end of pipe");
-       wait_or_die(child, "dpkg-divert", ERROR_OK | SIGPIPE_OK);
-       return !diverted;
-}
-
 int main(int argc, char *argv[])
 {
        /* /bin/sh needs to point to a valid target. */
@@ -144,27 +42,5 @@
                force_symlink("bash.1.gz", "/usr/share/man/man1/sh.1.gz",
                        "/usr/share/man/man1/sh.1.gz.temp");
        }
-       if (!binsh_in_filelist("bash"))
-               /* Ready. */
-               return 0;
-
-       /*
-        * In bash (<= 4.1-3), the bash package included symlinks for
-        * /bin/sh and the sh(1) manpage in its data.tar.
-        *
-        * Unless we are careful, unpacking the new version of bash
-        * will remove them.  So we tell dpkg that the files from bash
-        * to be removed are elsewhere, using a diversion on behalf of
-        * another package.
-        *
-        * Based on an idea by Michael Stone.
-        * “You're one sick individual.” -- Anthony Towns
-        * http://bugs.debian.org/cgi-bin/bugreport.cgi?msg=85;bug=34717
-        */
-       if (undiverted("/bin/sh"))
-               reset_diversion("dash", "/bin/sh", "/bin/sh.distrib");
-       if (undiverted("/usr/share/man/man1/sh.1.gz"))
-               reset_diversion("dash", "/usr/share/man/man1/sh.1.gz",
-                               "/usr/share/man/man1/sh.distrib.1.gz");
        return 0;
 }
diff --minimal -Nru bash-5.1/debian/bash.preinst.h 
bash-5.1/debian/bash.preinst.h
--- bash-5.1/debian/bash.preinst.h      2013-10-23 14:41:22.000000000 +0200
+++ bash-5.1/debian/bash.preinst.h      2021-05-31 14:28:21.000000000 +0200
@@ -17,21 +17,11 @@
 #define NORETURN __attribute__((__noreturn__))
 #define PRINTFLIKE __attribute__((format(printf, 1, 2)))
 
-enum wait_or_die_flags {
-       ERROR_OK = 1,
-       SIGPIPE_OK = 2
-};
-
 extern NORETURN PRINTFLIKE void die_errno(const char *fmt, ...);
 extern NORETURN PRINTFLIKE void die(const char *fmt, ...);
 
 extern int exists(const char *path);
-extern void set_cloexec(int fd);
-extern void xpipe(int pipefd[2]);
 
-extern void wait_or_die(pid_t child, const char *desc, int flags);
-extern pid_t spawn(const char * const cmd[], int outfd, int errfd);
 extern void run(const char * const cmd[]);     /* spawn and wait */
-extern FILE *spawn_pipe(pid_t *pid, const char * const cmd[], int errfd);
 
 #endif
diff --minimal -Nru bash-5.1/debian/changelog bash-5.1/debian/changelog
--- bash-5.1/debian/changelog   2021-05-10 08:52:10.000000000 +0200
+++ bash-5.1/debian/changelog   2021-05-31 14:29:20.000000000 +0200
@@ -1,3 +1,10 @@
+bash (5.1-3.1) UNRELEASED; urgency=medium
+
+  * Non-maintainer upload.
+  * preinst: Remove obsolete upgrade path from pre-wheezy. (Closes: #-1)
+
+ -- Helmut Grohne <hel...@subdivi.de>  Mon, 31 May 2021 14:29:20 +0200
+
 bash (5.1-3) unstable; urgency=medium
 
   * Apply upstream patches 005 - 008.

Reply via email to