1# ex:ts=8 sw=4: 2# $OpenBSD: CollisionReport.pm,v 1.33 2010/05/10 09:17:55 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::CollisionReport; 22use OpenBSD::PackingList; 23use OpenBSD::PackageInfo; 24 25sub find_collisions 26{ 27 my ($todo, $state) = @_; 28 my $verbose = $state->verbose >= 3; 29 my $bypkg = {}; 30 for my $name (keys %$todo) { 31 my $pkg = $state->vstat->value($state->{destdir}.$name); 32 if (defined $pkg) { 33 push(@{$bypkg->{$pkg}}, $name); 34 delete $todo->{$name}; 35 } 36 } 37 38 39 if (!%$todo) { 40 return $bypkg; 41 } 42 for my $pkg (installed_packages()) { 43 $state->say("Looking for collisions in $pkg") if $verbose; 44 my $plist = OpenBSD::PackingList->from_installation($pkg, 45 \&OpenBSD::PackingList::FilesOnly); 46 next if !defined $plist; 47 for my $item (@{$plist->{items}}) { 48 next unless $item->IsFile; 49 my $name = $item->fullname; 50 if (defined $todo->{$name}) { 51 push(@{$bypkg->{$pkg}}, $name); 52 delete $todo->{$name}; 53 } 54 } 55 } 56 return $bypkg; 57} 58 59sub collision_report($$) 60{ 61 my ($list, $state) = @_; 62 63 my $destdir = $state->{destdir}; 64 65 if ($state->{defines}->{removecollisions}) { 66 require OpenBSD::Error; 67 for my $f (@$list) { 68 $state->unlink(1, $destdir.$f->fullname); 69 } 70 return; 71 } 72 my %todo = map {($_->fullname, $_->{d})} @$list; 73 my $clueless_bat; 74 my $clueless_bat2; 75 my $found = 0; 76 77 $state->errsay("Collision: the following files already exist"); 78 if (!$state->{defines}->{dontfindcollisions}) { 79 my $bypkg = find_collisions(\%todo, $state); 80 for my $pkg (sort keys %$bypkg) { 81 for my $item (sort @{$bypkg->{$pkg}}) { 82 $found++; 83 $state->errsay("\t$item ($pkg)"); 84 } 85 if ($pkg =~ m/^(?:partial\-|borked\.\d+$)/o) { 86 $clueless_bat = $pkg; 87 } 88 if ($pkg =~ m/^\.libs\d*-*$/o) { 89 $clueless_bat2 = $pkg; 90 } 91 } 92 } 93 if (%todo) { 94 95 for my $item (sort keys %todo) { 96 my $old = $todo{$item}; 97 $state->errprint("\t$item"); 98 if (defined $old && -f $destdir.$item) { 99 my $d = $old->new($destdir.$item); 100 101 if ($d->equals($old)) { 102 $state->errsay(" (same checksum)"); 103 } else { 104 $state->errsay(" (different checksum)"); 105 } 106 } else { 107 $state->errsay(""); 108 } 109 } 110 } 111 if (defined $clueless_bat) { 112 $state->errprint("The package name $clueless_bat suggests that a former installation\n", 113 "of a similar package got interrupted. It is likely that\n", 114 "\tpkg_delete $clueless_bat\n", 115 "will solve the problem\n"); 116 } 117 if (defined $clueless_bat2) { 118 $state->errprint("The package name $clueless_bat2 suggests remaining libraries\n", 119 "from a former package update. It is likely that\n", 120 "\tpkg_delete $clueless_bat2\n". 121 "will solve the problem\n"); 122 } 123 my $dorepair = 0; 124 if ($found == 0) { 125 if ($state->{defines}->{repair}) { 126 $dorepair = 1; 127 } elsif ($state->{interactive}) { 128 if ($state->confirm("It seems to be a missing package registration\nRepair", 0)) { 129 $dorepair = 1; 130 } 131 } 132 } 133 if ($dorepair == 1) { 134 for my $f (@$list) { 135 136 if ($state->unlink($state->verbose >= 2, 137 $destdir.$f->fullname)) { 138 $state->{problems}--; 139 } else { 140 return; 141 } 142 } 143 $state->{repairdependencies} = 1; 144 } 145} 146 1471; 148