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