Control: tags -1 + patch On 2018-08-24 08:55 +0200, Sven Joachim wrote:
> Package: dash > Version: 0.5.8-2.10 > > If /bin/sh points to dash (the default for some nine years now), dash > fails to crossgrade, say from i386 to amd64. This is a regression from > Stretch where that worked flawlessly. > > ,---- > | # export LC_ALL=C > | # dpkg --print-architecture > | amd64 > | # dpkg --print-foreign-architectures > | i386 > | # dpkg-query -W dash > | dash:i386 0.5.8-2.10 > | # readlink -f /bin/sh > | /bin/dash > | # dpkg -i /var/cache/apt/archives/dash_0.5.8-2.10_amd64.deb > | (Reading database ... 10104 files and directories currently installed.) > | Preparing to unpack .../dash_0.5.8-2.10_amd64.deb ... > | Ignoring request to remove shared diversion 'diversion of /bin/sh to > /bin/sh.distrib by dash'. > | dpkg-divert: error: 'diversion of /bin/sh to /bin/sh.distrib by > | bash' clashes with 'diversion of /bin/sh to /bin/sh.distrib by dash' > | dash.preinst: dpkg-divert exited with status 2 > | dpkg: error processing archive > /var/cache/apt/archives/dash_0.5.8-2.10_amd64.deb (--install): > | new dash:i386 package pre-installation script subprocess returned error > exit status 1 > | Errors were encountered while processing: > | /var/cache/apt/archives/dash_0.5.8-2.10_amd64.deb > `---- I think the solution is to get rid of dash's preinst entirely[1]. It had been necessary when /bin/sh was shipped in the bash package and the diversions had to be set up before unpacking dash to avoid file conflicts, but bash has not shipped /bin/sh for over six years, so the dash preinst is not needed anymore. Getting rid of dash's preinst solves the crossgrade problem as well as stopping the noise during upgrades (#890073). Cheers, Sven 1. Originally proposed in May 2013 by yours truly, see https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=604873#172.
>From 4fd330b62c1ab8d1674e0478bdce83bc285f5859 Mon Sep 17 00:00:00 2001 From: Sven Joachim <svenj...@gmx.de> Date: Thu, 6 Sep 2018 19:34:26 +0200 Subject: [PATCH] Remove dash.preinst The preinst had been necessary to unpack dash when /bin/sh was also included in the bash package, but bash stopped shipping /bin/sh over six years ago. Nowadays the preinst seems entirely superfluous and prevents crossgrades, as well as spitting out noise on upgrades. Closes: #907132, #890073 Signed-off-by: Sven Joachim <svenj...@gmx.de> --- debian/clean | 3 - debian/dash.preinst-lib.c | 131 -------------------------------------- debian/dash.preinst.c | 107 ------------------------------- debian/dash.preinst.h | 37 ----------- debian/rules | 11 +--- 5 files changed, 1 insertion(+), 288 deletions(-) delete mode 100644 debian/dash.preinst-lib.c delete mode 100644 debian/dash.preinst.c delete mode 100644 debian/dash.preinst.h diff --git a/debian/clean b/debian/clean index 13ac127..4586283 100644 --- a/debian/clean +++ b/debian/clean @@ -1,4 +1 @@ debian/dash.templates -debian/dash.preinst -debian/dash.preinst-lib.o -debian/dash.preinst.o diff --git a/debian/dash.preinst-lib.c b/debian/dash.preinst-lib.c deleted file mode 100644 index ef87e18..0000000 --- a/debian/dash.preinst-lib.c +++ /dev/null @@ -1,131 +0,0 @@ -/* - * This file is in the public domain. - * You may freely use, modify, distribute, and relicense it. - */ - -#include "dash.preinst.h" -#include <stdio.h> -#include <stdlib.h> -#include <stdarg.h> -#include <string.h> -#include <errno.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <sys/wait.h> -#include <unistd.h> -#include <fcntl.h> -#include <spawn.h> - -extern char **environ; - -__attribute__((format(printf, 1, 0))) -static void vreportf(const char *err, va_list params, int errnum) -{ - fprintf(stderr, "dash.preinst: "); - vfprintf(stderr, err, params); - if (errnum) - fprintf(stderr, ": %s", strerror(errnum)); - fprintf(stderr, "\n"); -} - -__attribute__((format(printf, 1, 2))) -NORETURN void die_errno(const char *fmt, ...) -{ - va_list params; - va_start(params, fmt); - vreportf(fmt, params, errno); - va_end(params); - exit(1); -} - -__attribute__((format(printf, 1, 2))) -NORETURN void die(const char *fmt, ...) -{ - va_list params; - va_start(params, fmt); - vreportf(fmt, params, 0); - va_end(params); - exit(1); -} - -int exists(const char *file) -{ - struct stat sb; - if (!lstat(file, &sb)) - return 1; - if (errno == ENOENT) - return 0; - die_errno("cannot get status of %s", file); -} - -void set_cloexec(int fd) -{ - int flags = fcntl(fd, F_GETFL); - if (flags < 0 || fcntl(fd, F_SETFL, 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) -{ - 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)) - return; - - if (WIFEXITED(status)) - die("%s exited with status %d", name, WEXITSTATUS(status)); - if (WIFSIGNALED(status)) - die("%s killed by signal %d", name, WTERMSIG(status)); - if (WIFSTOPPED(status)) - die("%s stopped by signal %d", name, WSTOPSIG(status)); - die("waitpid is confused (status=%d)", status); -} - -pid_t spawn(const char * const cmd[], int out, int err) -{ - pid_t child; - posix_spawn_file_actions_t redir; - - if (posix_spawn_file_actions_init(&redir) || - (out >= 0 && posix_spawn_file_actions_adddup2(&redir, out, 1)) || - (err >= 0 && posix_spawn_file_actions_adddup2(&redir, err, 2)) || - posix_spawnp(&child, cmd[0], &redir, NULL, - (char **) cmd, environ) || - posix_spawn_file_actions_destroy(&redir)) - die_errno("cannot run %s", cmd[0]); - return child; -} - -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; -} diff --git a/debian/dash.preinst.c b/debian/dash.preinst.c deleted file mode 100644 index 966b65d..0000000 --- a/debian/dash.preinst.c +++ /dev/null @@ -1,107 +0,0 @@ -/* - * This file is in the public domain. - * You may freely use, modify, distribute, and relicense it. - */ - -#include "dash.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 copy(const char *file, const char *dest) -{ - const char * const cmd[] = {"cp", "-dp", file, dest, NULL}; - - if (exists(file)) - run(cmd); - else if (unlink(dest)) - die_errno("cannot remove %s", dest); -} - -static void force_symlink(const char *target, const char *link, - const char *temp) -{ - /* - * Forcibly create a symlink to "target" from "link". - * This is performed in two stages with an - * intermediate temporary file because symlink(2) cannot - * atomically replace an existing file. - */ - if ((unlink(temp) && errno != ENOENT) || - symlink(target, temp) || - rename(temp, link)) - 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", "dash", "--remove", file, NULL}; - const char * const new_diversion[] = - {"dpkg-divert", "--package", package, - "--divert", distrib, "--add", file, NULL}; - run(remove_old_diversion); - run(new_diversion); - copy(file, distrib); -} - -static int undiverted(const char *path) -{ - const char * const cmd[] = - {"dpkg-divert", "--listpackage", path, NULL}; - pid_t child; - char packagename[sizeof("dash\n")]; - size_t len; - FILE *in = spawn_pipe(&child, cmd, -1); - int diverted = 1; - - /* Is $path diverted by someone other than dash? */ - - 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("dash\n") && !memcmp(packagename, "dash\n", len)) - diverted = 0; /* Diverted by dash. */ - - 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[]) -{ - /* - * To help with bootstrapping Debian, the dash package includes - * symlinks for /bin/sh and the sh(1) manpage in its data.tar. - * - * Unless we are careful, unpacking the new version of dash - * can overwrite them. So we tell dpkg that the files from dash - * 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("bash", "/bin/sh", "/bin/sh.distrib"); - if (undiverted("/usr/share/man/man1/sh.1.gz")) - reset_diversion("bash", "/usr/share/man/man1/sh.1.gz", - "/usr/share/man/man1/sh.distrib.1.gz"); - - /* /bin/sh needs to point to a valid target. */ - if (access("/bin/sh", X_OK)) { - force_symlink("dash", "/bin/sh", "/bin/sh.temp"); - force_symlink("dash.1.gz", "/usr/share/man/man1/sh.1.gz", - "/usr/share/man/man1/sh.1.gz.temp"); - } - - return 0; -} diff --git a/debian/dash.preinst.h b/debian/dash.preinst.h deleted file mode 100644 index 066c4b4..0000000 --- a/debian/dash.preinst.h +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef DASH_PREINST_H -#define DASH_PREINST_H - -/* - * This file is in the public domain. - * You may freely use, modify, distribute, and relicense it. - */ - -#define _XOPEN_SOURCE 700 -#include <stdio.h> -#include <stdarg.h> -#include <sys/types.h> - -#if !defined(__GNUC__) && !defined(__attribute__) -# define __attribute__(x) -#endif -#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 --git a/debian/rules b/debian/rules index 251f31f..4f9d9d4 100755 --- a/debian/rules +++ b/debian/rules @@ -38,16 +38,7 @@ DIRA =$(shell pwd)/debian/ash override_dh_auto_configure: dh_auto_configure -- --enable-fnmatch --disable-lineno -PREINST_OBJECTS = debian/dash.preinst.o debian/dash.preinst-lib.o - -$(PREINST_OBJECTS): %.o: %.c debian/dash.preinst.h - $(CC) -c -o $@ $(CFLAGS) $< - -debian/dash.preinst: $(PREINST_OBJECTS) - $(CC) -o debian/dash.preinst $(CFLAGS) $(PREINST_OBJECTS) - $(STRIP) -R .comment -R .note debian/dash.preinst - -override_dh_auto_build: debian/dash.preinst po-templates +override_dh_auto_build: po-templates dh_auto_build po-templates: -- 2.19.0.rc2