tag 633627 + patch
thanks

On Fri, 15 Jul 2011, Raphael Hertzog wrote:
> In the mean time, I will look into fixing this regression.

Here's a patch, can you tell me if it works for you?

Cheers,
-- 
Raphaël Hertzog ◈ Debian Developer

Follow my Debian News ▶ http://RaphaelHertzog.com (English)
                      ▶ http://RaphaelHertzog.fr (Français)
commit c34fe91e6679c2a41944e30df83e6a9684f4da81
Author: Raphaël Hertzog <[email protected]>
Date:   Fri Jul 15 22:06:38 2011 +0200

    update-alternatives: fix regression when dropping slave alternatives
    
    When the alternative is changed, it might have to drop a slave alternative
    that's no longer provide by the new choice. This must only remove the slave
    link if it's actually a link. If it's a file, it must be kept except if
    --force is given.
    
    Reported-by: Andreas Beckmann <[email protected]>

diff --git a/debian/changelog b/debian/changelog
index 20b149a..ac9d3fb 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -74,6 +74,9 @@ dpkg (1.16.1) UNRELEASED; urgency=low
   * dpkg-mergechangelogs now checks the return value of the close() call.
     Thanks to Niels Thykier <[email protected]> for the patch. Closes: #633539
   * Similar changes to dpkg-shlibdeps and dpkg-gencontrol, also by Niels.
+  * Fix update-alternatives to not remove a real file when dropping a
+    symlink for a slave that's not provided by the new current choice.
+    Closes: #633627
 
   [ Guillem Jover ]
   * Install deb-src-control(5) man pages in dpkg-dev. Closes: #620520
diff --git a/utils/update-alternatives.c b/utils/update-alternatives.c
index 0ad55a6..f35f5db 100644
--- a/utils/update-alternatives.c
+++ b/utils/update-alternatives.c
@@ -1623,13 +1623,29 @@ alternative_commit(struct alternative *a)
        alternative_commit_operations_free(a);
 }
 
+static bool
+alternative_can_replace_link(const char *linkname)
+{
+       struct stat st;
+       bool replace_link;
+
+       errno = 0;
+       if (lstat(linkname, &st) == -1) {
+               if (errno != ENOENT)
+                       syserr(_("cannot stat file '%s'"), linkname);
+               replace_link = true;
+       } else {
+               replace_link = S_ISLNK(st.st_mode);
+       }
+
+       return (replace_link || opt_force);
+}
+
 static void
 alternative_prepare_install_single(struct alternative *a, const char *name,
                                   const char *linkname, const char *file)
 {
        char *fntmp, *fn;
-       struct stat st;
-       bool create_link;
 
        /* Create link in /etc/alternatives. */
        xasprintf(&fntmp, "%s/%s" DPKG_TMP_EXT, altdir, name);
@@ -1639,15 +1655,7 @@ alternative_prepare_install_single(struct alternative 
*a, const char *name,
        alternative_add_commit_op(a, opcode_mv, fntmp, fn);
        free(fntmp);
 
-       errno = 0;
-       if (lstat(linkname, &st) == -1) {
-               if (errno != ENOENT)
-                       syserr(_("cannot stat file '%s'"), linkname);
-               create_link = true;
-       } else {
-               create_link = S_ISLNK(st.st_mode);
-       }
-       if (create_link || opt_force) {
+       if (alternative_can_replace_link(linkname)) {
                /* Create alternative link. */
                xasprintf(&fntmp, "%s" DPKG_TMP_EXT, linkname);
                checked_rm(fntmp);
@@ -1693,7 +1701,11 @@ alternative_prepare_install(struct alternative *a, const 
char *choice)
 
                /* Drop unused slave. */
                xasprintf(&fn, "%s/%s", altdir, sl->name);
-               alternative_add_commit_op(a, opcode_rm, sl->link, NULL);
+               if (alternative_can_replace_link(sl->link))
+                       alternative_add_commit_op(a, opcode_rm, sl->link, NULL);
+               else
+                       warning(_("not removing %s since it's not a symlink."),
+                               sl->link);
                alternative_add_commit_op(a, opcode_rm, fn, NULL);
                free(fn);
        }

Reply via email to