1# ex:ts=8 sw=4: 2# $OpenBSD: CollisionReport.pm,v 1.48 2019/09/04 12:27:38 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 # XXX in -n mode, some stuff is not really there 61 # avoid warnings 62 next unless -d installed_info($pkg); 63 my $plist = OpenBSD::PackingList->from_installation($pkg, 64 \&OpenBSD::PackingList::FilesOnly); 65 next if !defined $plist; 66 $plist->handle_collisions($todo, $pkg, $bypkg); 67 } 68 return $bypkg; 69} 70 71sub collision_report 72{ 73 my ($list, $state, $set) = @_; 74 75 my $destdir = $state->{destdir}; 76 77 if ($state->defines('removecollisions')) { 78 require OpenBSD::Error; 79 for my $f (@$list) { 80 $state->unlink(1, $destdir.$f->fullname); 81 } 82 return; 83 } 84 my %todo = map {($_->fullname, $_->{d})} @$list; 85 my %extra = map {($_->fullname, $_->{newly_found})} @$list; 86 my $clueless_bat; 87 my $clueless_bat2; 88 my $found = 0; 89 90 $state->errsay("Collision in #1: the following files already exist", 91 $set->print); 92 if (!$state->defines('dontfindcollisions')) { 93 my $bypkg = find_collisions(\%todo, $state); 94 for my $pkg (sort keys %$bypkg) { 95 for my $item (sort @{$bypkg->{$pkg}}) { 96 $found++; 97 $state->errsay("\t#1 (#2 and #3)", $item, $pkg, 98 $extra{$item}); 99 } 100 if ($pkg =~ m/^(?:partial\-|borked\.\d+$)/o) { 101 $clueless_bat = $pkg; 102 } 103 if ($pkg =~ m/^\.libs\d*-*$/o) { 104 $clueless_bat2 = $pkg; 105 } 106 } 107 } 108 if (%todo) { 109 110 for my $item (sort keys %todo) { 111 my $old = $todo{$item}; 112 $state->errprint("\t#1 from #2", $item, $extra{$item}); 113 if (defined $old && -f $destdir.$item) { 114 my $d = $old->new($destdir.$item); 115 116 if ($d->equals($old)) { 117 $state->errsay(" (same checksum)"); 118 } else { 119 $state->errsay(" (different checksum)"); 120 } 121 } else { 122 $state->errsay; 123 } 124 } 125 } 126 if (defined $clueless_bat) { 127 $state->errprint("The package name #1 suggests that a former installation\n". 128 "of a similar package got interrupted. It is likely that\n". 129 "\tpkg_delete #1\n". 130 "will solve the problem\n", $clueless_bat); 131 } 132 if (defined $clueless_bat2) { 133 $state->errprint("The package name #1 suggests remaining libraries\n". 134 "from a former package update. It is likely that\n". 135 "\tpkg_delete #1\n". 136 "will solve the problem\n", $clueless_bat2); 137 } 138 my $dorepair = 0; 139 if ($found == 0) { 140 $dorepair = $state->defines('repair') || 141 $state->confirm_defaults_to_no( 142 "It seems to be a missing package registration\nRepair"); 143 } 144 if ($dorepair == 1) { 145 for my $f (@$list) { 146 147 if ($state->unlink($state->verbose >= 2, 148 $destdir.$f->fullname)) { 149 $state->{problems}--; 150 } else { 151 return; 152 } 153 } 154 $state->{repairdependencies} = 1; 155 } 156} 157 1581; 159