Przeglądaj źródła

update-alternatives: better handle missing files

* scripts/update-alternatives.pl (rename_mv): Integrate logic to
not fail if ENOENT is the reason why the rename failed.

The underlying problem in the previous implementation is not
immediately obvious but rename() can fail for multiple reasons
at the same time. In #99870 we have a case where rename() fails
with EXDEV and the system("mv",…) call fails due to ENOENT. In that
case, rename_mv() fails but the check $! == ENOENT also fails
when in fact it should not because ENOENT is really the reason
why rename_mv() failed.

Verifying the existence of the source file first is a sanity check
that avoids running mv when we know that it's going to fail and clutter
the screen with an undesired error message.
Raphael Hertzog 17 lat temu
rodzic
commit
0f861ca7c1
3 zmienionych plików z 25 dodań i 5 usunięć
  1. 5 0
      ChangeLog
  2. 6 0
      debian/changelog
  3. 14 5
      scripts/update-alternatives.pl

+ 5 - 0
ChangeLog

@@ -1,3 +1,8 @@
+2009-02-05  Raphael Hertzog  <hertzog@debian.org>
+
+	* scripts/update-alternatives.pl (rename_mv): Integrate logic to
+	not fail if ENOENT is the reason why the rename failed.
+
 2009-02-05  Raphael Hertzog  <hertzog@debian.org>
 
 	* scripts/update-alternatives.pl: Ensure that a broken link

+ 6 - 0
debian/changelog

@@ -118,6 +118,12 @@ dpkg (1.15.0) UNRELEASED; urgency=low
     with a broken symlink (instead let the current action fix it).
     Also ensure that a message is displayed by default when such a switch is
     made. Closes: #141325, #87677
+  * Fix update-alternatives' logic to rename files. It failed to ignore errors
+    in some cases where it wanted to when the source file didn't exist.
+    Closes: #99870
+    This also makes update-alternatives less noisy when this happens since we
+    don't call mv when we know that it's going to fail.
+    Closes: #98822
 
   [ Pierre Habouzit ]
   * Add a --query option to update-alternatives. Closes: #336091, #441904

+ 14 - 5
scripts/update-alternatives.pl

@@ -497,8 +497,8 @@ if ($action eq 'install') {
     if (defined($link) && $link ne $alink) {
         pr(sprintf(_g("Renaming %s link from %s to %s."), $name, $link, $alink))
           if $verbosemode > 0;
-        rename_mv($link,$alink) || $! == ENOENT ||
-            quit(sprintf(_g("unable to rename %s to %s: %s"), $link, $alink, $!));
+        rename_mv($link, $alink, 1) ||
+            quit(sprintf(_g("unable to rename %s to %s: see error above"), $link, $alink));
     }
     $link= $alink;
     my $i;
@@ -521,8 +521,8 @@ if ($action eq 'install') {
 	if (defined($oldslavelink) && $newslavelink ne $oldslavelink) {
             pr(sprintf(_g("Renaming %s slave link from %s to %s."), $sname, $oldslavelink, $newslavelink))
               if $verbosemode > 0;
-            rename_mv($oldslavelink,$newslavelink) || $! == ENOENT ||
-                quit(sprintf(_g("unable to rename %s to %s: %s"), $oldslavelink, $newslavelink, $!));
+            rename_mv($oldslavelink, $newslavelink, 1) ||
+                quit(sprintf(_g("unable to rename %s to %s: see error above"), $oldslavelink, $newslavelink));
         }
         $slavelinks[$j]= $newslavelink;
     }
@@ -769,7 +769,16 @@ sub badfmt {
     quit(sprintf(_g("internal error: %s corrupt: %s"), "$admindir/$name", $_[0]));
 }
 sub rename_mv {
-    return (rename($_[0], $_[1]) || (system(("mv", $_[0], $_[1])) == 0));
+    my ($source, $dest, $ignore_enoent) = @_;
+    $ignore_enoent = 0 unless defined($ignore_enoent);
+    return 1 if ($ignore_enoent and not -e $source);
+    if (not rename($source, $dest)) {
+        if (system("mv", $source, $dest) != 0) {
+            return $ignore_enoent if $! == ENOENT;
+            return 0;
+        }
+    }
+    return 1;
 }
 sub checked_symlink {
     my ($filename, $linkname) = @_;