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