1# ex:ts=8 sw=4: 2# $OpenBSD: CollisionReport.pm,v 1.44 2012/04/28 12:00:10 espie Exp $ 3# 4# Copyright (c) 2003-2006 Marc Espie <espie@openbsd.org> 5# 6# Permission to use, copy, modify, and distribute this software for any 7# purpose with or without fee is hereby granted, provided that the above 8# copyright notice and this permission notice appear in all copies. 9# 10# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 18use strict; 19use warnings; 20 21package OpenBSD::PackingElement; 22sub handle_collisions 23{ 24} 25 26package OpenBSD::PackingElement::FileBase; 27sub handle_collisions 28{ 29 my ($self, $todo, $pkg, $bypkg) = @_; 30 my $name = $self->fullname; 31 if (defined $todo->{$name}) { 32 push(@{$bypkg->{$pkg}}, $name); 33 delete $todo->{$name}; 34 } 35} 36 37package OpenBSD::CollisionReport; 38use OpenBSD::PackingList; 39use OpenBSD::PackageInfo; 40 41sub find_collisions 42{ 43 my ($todo, $state) = @_; 44 my $verbose = $state->verbose >= 3; 45 my $bypkg = {}; 46 for my $name (keys %$todo) { 47 my $pkg = $state->vstat->value($state->{destdir}.$name); 48 if (defined $pkg) { 49 push(@{$bypkg->{$pkg}}, $name); 50 delete $todo->{$name}; 51 } 52 } 53 54 55 if (!%$todo) { 56 return $bypkg; 57 } 58 for my $pkg (installed_packages()) { 59 $state->say("Looking for collisions in #1", $pkg) if $verbose; 60 my $plist = OpenBSD::PackingList->from_installation($pkg, 61 \&OpenBSD::PackingList::FilesOnly); 62 next if !defined $plist; 63 $plist->handle_collisions($todo, $pkg, $bypkg); 64 } 65 return $bypkg; 66} 67 68sub collision_report 69{ 70 my ($list, $state, $set) = @_; 71 72 my $destdir = $state->{destdir}; 73 74 if ($state->defines('removecollisions')) { 75 require OpenBSD::Error; 76 for my $f (@$list) { 77 $state->unlink(1, $destdir.$f->fullname); 78 } 79 return; 80 } 81 my %todo = map {($_->fullname, $_->{d})} @$list; 82 my %extra = map {($_->fullname, $_->{newly_found})} @$list; 83 my $clueless_bat; 84 my $clueless_bat2; 85 my $found = 0; 86 87 $state->errsay("Collision in #1: the following files already exist", 88 $set->print); 89 if (!$state->defines('dontfindcollisions')) { 90 my $bypkg = find_collisions(\%todo, $state); 91 for my $pkg (sort keys %$bypkg) { 92 for my $item (sort @{$bypkg->{$pkg}}) { 93 $found++; 94 $state->errsay("\t#1 (#2 and #3)", $item, $pkg, 95 $extra{$item}); 96 } 97 if ($pkg =~ m/^(?:partial\-|borked\.\d+$)/o) { 98 $clueless_bat = $pkg; 99 } 100 if ($pkg =~ m/^\.libs\d*-*$/o) { 101 $clueless_bat2 = $pkg; 102 } 103 } 104 } 105 if (%todo) { 106 107 for my $item (sort keys %todo) { 108 my $old = $todo{$item}; 109 $state->errprint("\t#1 from #2", $item, $extra{$item}); 110 if (defined $old && -f $destdir.$item) { 111 my $d = $old->new($destdir.$item); 112 113 if ($d->equals($old)) { 114 $state->errsay(" (same checksum)"); 115 } else { 116 $state->errsay(" (different checksum)"); 117 } 118 } else { 119 $state->errsay; 120 } 121 } 122 } 123 if (defined $clueless_bat) { 124 $state->errprint("The package name #1 suggests that a former installation\n". 125 "of a similar package got interrupted. It is likely that\n". 126 "\tpkg_delete #1\n". 127 "will solve the problem\n", $clueless_bat); 128 } 129 if (defined $clueless_bat2) { 130 $state->errprint("The package name #1 suggests remaining libraries\n". 131 "from a former package update. It is likely that\n". 132 "\tpkg_delete #1\n". 133 "will solve the problem\n", $clueless_bat2); 134 } 135 my $dorepair = 0; 136 if ($found == 0) { 137 if ($state->defines('repair')) { 138 $dorepair = 1; 139 } elsif ($state->{interactive}) { 140 if ($state->confirm("It seems to be a missing package registration\nRepair", 0)) { 141 $dorepair = 1; 142 } 143 } 144 } 145 if ($dorepair == 1) { 146 for my $f (@$list) { 147 148 if ($state->unlink($state->verbose >= 2, 149 $destdir.$f->fullname)) { 150 $state->{problems}--; 151 } else { 152 return; 153 } 154 } 155 $state->{repairdependencies} = 1; 156 } 157} 158 1591; 160