The following commit has been merged in the master branch:
commit a7cc8e2eb39c36b8456fdf6b9abbb3eb32dfbcd0
Author: Raphael Hertzog <[email protected]>
Date: Sun Feb 22 20:31:10 2009 +0100
update-alternatives: don't replace real files by alternative links without
--force
update-alternatives should not replace real files by symlinks. When
--install is called, the alternative link should either not exist
or already be a link. It that's not the case, it will simply skip
installing that link and display a warning. However if --force is given,
it will (try to) replace the file.
Ensure that behaviour within the test suite.
diff --git a/ChangeLog b/ChangeLog
index 9f37ceb..4e8749e 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,17 @@
2009-02-22 Raphael Hertzog <[email protected]>
+ * scripts/update-alternatives.pl: update-alternatives should not
+ replace real files by symlinks. When --install is called, the
+ alternative link should either not exist or already be a link. It
+ that's not the case, it will simply skip installing that link and
+ display a warning. However if --force is given, it will (try to)
+ replace the file.
+ * man/update-alternatives.8: Document this behaviour.
+ * scripts/t/900_update_alternatives.t: Add corresponding tests in
+ the test suite.
+
+2009-02-22 Raphael Hertzog <[email protected]>
+
* man/update-alternatives.8: Document how --all can be used to
repair all alternatives on the system in a single command.
* scripts/update-alternatives.pl: Ensure the above explanation
diff --git a/man/update-alternatives.8 b/man/update-alternatives.8
index daba7f7..c21edc0 100644
--- a/man/update-alternatives.8
+++ b/man/update-alternatives.8
@@ -218,7 +218,8 @@ options, each followed by three arguments,
may be specified. Note that the master alternative must exist or the call
will fail. However if a slave alternative doesn't exist, the corresponding
slave alternative link will simply not be installed (a warning will still
-be displayed).
+be displayed). If some real file is installed where an alternative link
+has to be installed, it is kept unless \fB\-\-force\fR is used.
.IP
If the alternative name specified exists already
in the alternatives system's records,
@@ -330,6 +331,10 @@ different from the default.
Specifies the administrative directory, when this is to be
different from the default.
.TP
+.TP
+.BI \-\-force
+Let \fBupdate-alternatives\fR replace any real file that is installed
+where an alternative link has to be installed.
.BI \-\-skip\-auto
Skip configuration prompt for alternatives which are properly configured
in automatic mode. This option is only relevant with \fB\-\-config\fR or
diff --git a/scripts/t/900_update_alternatives.t
b/scripts/t/900_update_alternatives.t
index b9d2908..21618c5 100644
--- a/scripts/t/900_update_alternatives.t
+++ b/scripts/t/900_update_alternatives.t
@@ -30,7 +30,7 @@ my @choices = (
{
"link" => "$bindir/slave1",
name => "slave1",
- path => "/bin/yes",
+ path => "/usr/bin/yes",
},
],
},
@@ -52,8 +52,8 @@ my @choices = (
},
);
my $nb_slaves = 2;
-plan tests => (4 * ($nb_slaves + 1) + 2) * 23 # number of check_choices
- + 56; # rest
+plan tests => (4 * ($nb_slaves + 1) + 2) * 24 # number of check_choices
+ + 60; # rest
sub cleanup {
system("rm -rf $srcdir/t.tmp/ua && mkdir -p $admindir && mkdir -p
$altdir");
@@ -74,8 +74,10 @@ sub call_ua {
sub install_choice {
my ($id, %opts) = @_;
my $alt = $choices[$id];
- my @params = ("--install", "$main_link", "$main_name",
- $alt->{path}, $alt->{priority});
+ my @params;
+ push @params, @{$opts{params}} if exists $opts{params};
+ push @params, "--install", "$main_link", "$main_name",
+ $alt->{path}, $alt->{priority};
foreach my $slave (@{ $alt->{slaves} }) {
push @params, "--slave", $slave->{"link"}, $slave->{"name"},
$slave->{"path"};
}
@@ -266,6 +268,7 @@ $choices[0]{"slaves"}[0]{"link"} =
"$bindir/generic-slave-bis";
install_choice(0);
check_choice(0, "auto", "rename lost file");
check_no_link($old_slave, "rename lost file");
+$choices[0]{"slaves"}[0]{"link"} = "$bindir/slave2";
# test install with empty admin file (#457863)
cleanup();
system("touch $admindir/generic-test");
@@ -328,12 +331,19 @@ check_choice(0, "auto", "optional renamed slave2 in
non-existing dir");
cleanup();
install_choice(0);
check_choice(0, "auto", "optional slave2 in non-existing dir");
-$choices[0]{"slaves"}[0]{"link"} = $old_link;
+$choices[0]{"slaves"}[0]{"link"} = $old_slave;
# test fresh install with a non-existing slave file
cleanup();
install_choice(0);
check_choice(0, "auto", "optional slave2");
$choices[0]{"slaves"}[0]{"path"} = $old_path;
+# test management of pre-existing files
+cleanup();
+system("touch $main_link $bindir/slave1");
+install_choice(0);
+ok(!-l $main_link, "install preserves files that should be links");
+ok(!-l "$bindir/slave1", "install preserves files that should be slave links");
+install_choice(0, params => ["--force"]);
+check_choice(0, "auto", "install --force replaces files with links");
-# TODO: handle of pre-existing files in place of alternative links
diff --git a/scripts/update-alternatives.pl b/scripts/update-alternatives.pl
index c6c30d8..387b790 100755
--- a/scripts/update-alternatives.pl
+++ b/scripts/update-alternatives.pl
@@ -19,12 +19,13 @@ my $altdir = '/etc/alternatives';
my $admdir = $admindir . '/alternatives';
my $action = ''; # Action to perform (display / query / install / remove
/ auto / config)
-my $skip_auto = ''; # Skip alternatives properly configured in auto mode
(for --config)
my $alternative; # Alternative worked on
my $inst_alt; # Alternative to install
my $fileset; # Set of files to install in the alternative
my $path; # Path of alternative we are offering
+my $skip_auto = 0; # Skip alternatives properly configured in auto mode
(for --config)
my $verbosemode = 0;
+my $force = 0;
my @pass_opts;
$| = 1;
@@ -106,6 +107,9 @@ while (@ARGV) {
} elsif (m/^--skip-auto$/) {
$skip_auto = 1;
push @pass_opts, $_;
+ } elsif (m/^--force$/) {
+ $force = 1;
+ push @pass_opts, $_;
} else {
badusage(_g("unknown option \`%s'"), $_);
}
@@ -572,6 +576,7 @@ sub slave {
package Alternative;
use Dpkg::Gettext;
+use POSIX qw(:errno_h);
sub pr { main::pr(@_) }
sub quit { main::quit(@_) }
@@ -951,32 +956,44 @@ sub prepare_install {
my ($self, $choice) = @_;
my ($link, $name) = ($self->link(), $self->name());
my $fileset = $self->fileset($choice);
- # Setup main link
- main::checked_rm("$link.dpkg-tmp");
- main::checked_symlink("$altdir/$name", "$link.dpkg-tmp");
- # Setup main alternative link
+ # Create link in /etc/alternatives
main::checked_rm("$altdir/$name.dpkg-tmp");
main::checked_symlink($choice, "$altdir/$name.dpkg-tmp");
- # Add commit operations
$self->add_commit_op(sub {
- main::checked_mv("$link.dpkg-tmp", $link);
main::checked_mv("$altdir/$name.dpkg-tmp", "$altdir/$name");
});
+ $! = 0; lstat($link);
+ if (-l _ or $! == ENOENT or $force) {
+ # Create alternative link
+ main::checked_rm("$link.dpkg-tmp");
+ main::checked_symlink("$altdir/$name", "$link.dpkg-tmp");
+ $self->add_commit_op(sub {
+ main::checked_mv("$link.dpkg-tmp", $link);
+ });
+ } else {
+ pr(_g("Not replacing %s with a link."), $link) if $verbosemode >= 0;
+ }
# Take care of slaves links
foreach my $slave ($self->slaves()) {
my ($slink, $spath) = ($self->slave_link($slave),
$fileset->slave($slave));
if ($fileset->has_slave($slave) and -e $spath) {
- # Setup slave link
- main::checked_rm("$slink.dpkg-tmp");
- main::checked_symlink("$altdir/$slave", "$slink.dpkg-tmp");
- # Setup slave alternative link
+ # Create link in /etc/alternatives
main::checked_rm("$altdir/$slave.dpkg-tmp");
main::checked_symlink($spath, "$altdir/$slave.dpkg-tmp");
- # Add commit operations
$self->add_commit_op(sub {
- main::checked_mv("$slink.dpkg-tmp", $slink);
main::checked_mv("$altdir/$slave.dpkg-tmp", "$altdir/$slave");
});
+ $! = 0; lstat($slink);
+ if (-l _ or $! == ENOENT or $force) {
+ # Create alternative link
+ main::checked_rm("$slink.dpkg-tmp");
+ main::checked_symlink("$altdir/$slave", "$slink.dpkg-tmp");
+ $self->add_commit_op(sub {
+ main::checked_mv("$slink.dpkg-tmp", $slink);
+ });
+ } else {
+ pr(_g("Not replacing %s with a link."), $link) if $verbosemode
>= 0;
+ }
} else {
main::pr(_g("skip creation of %s because associated file %s (of" .
"link group %s) doesn't exist"), $slink, $spath,
--
dpkg's main repository
--
To UNSUBSCRIBE, email to [email protected]
with a subject of "unsubscribe". Trouble? Contact [email protected]