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