1# ex:ts=8 sw=4:
2# $OpenBSD: Handle.pm,v 1.44 2023/06/13 09:07:17 espie Exp $
3#
4# Copyright (c) 2007-2009 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
18# fairly non-descriptive name. Used to store various package information
19# during installs and updates.
20
21use v5.36;
22
23package OpenBSD::Handle;
24
25use OpenBSD::PackageInfo;
26use OpenBSD::Error;
27
28use constant {
29	BAD_PACKAGE => 1,
30	CANT_INSTALL => 2,
31	ALREADY_INSTALLED => 3,
32	NOT_FOUND => 4,
33	CANT_DELETE => 5,
34};
35
36sub is_real($) { return 1; }
37
38sub cleanup($self, $error = undef, $errorinfo = undef)
39{
40	if (defined $error) {
41		$self->{error} //= $error;
42		$self->{errorinfo} //= $errorinfo;
43	}
44	if (defined $self->location) {
45		if (defined $self->{error} && $self->{error} == BAD_PACKAGE) {
46			$self->location->close_with_client_error;
47		} else {
48			$self->location->close_now;
49		}
50		$self->location->wipe_info;
51	}
52	delete $self->{plist};
53	delete $self->{db};
54	delete $self->{conflict_list};
55}
56
57sub new($class)
58{
59	return bless {}, $class;
60}
61
62sub system($class)
63{
64	return OpenBSD::Handle::BaseSystem->new;
65}
66
67sub pkgname($self)
68{
69	if (!defined $self->{pkgname}) {
70		if (defined $self->{plist}) {
71			$self->{pkgname} = $self->{plist}->pkgname;
72		} elsif (defined $self->{location}) {
73			$self->{pkgname} = $self->{location}->name;
74		} elsif (defined $self->{name}) {
75			require OpenBSD::PackageName;
76
77			$self->{pkgname} =
78			    OpenBSD::PackageName::url2pkgname($self->{name});
79		}
80	}
81
82	return $self->{pkgname};
83}
84
85sub location($self)
86{
87	return $self->{location};
88}
89
90sub plist($self)
91{
92	return $self->{plist};
93}
94
95sub dependency_info($self)
96{
97	if (defined $self->{plist}) {
98		return $self->{plist};
99	} elsif (defined $self->{location} &&
100	    defined $self->{location}{update_info}) {
101		return $self->{location}{update_info};
102	} else {
103		return undef;
104	}
105}
106
107OpenBSD::Auto::cache(conflict_list,
108    sub($self) {
109    	require OpenBSD::PkgCfl;
110	return OpenBSD::PkgCfl->make_conflict_list($self->dependency_info);
111    });
112
113sub set_error($self, $error)
114{
115	$self->{error} = $error;
116}
117
118sub has_error($self, $error = undef)
119{
120	if (!defined $self->{error}) {
121		return undef;
122	}
123	if (defined $error) {
124		return $self->{error} eq $error;
125	}
126	return $self->{error};
127}
128
129sub has_reported_error($self)
130{
131	return $self->{error_reported};
132}
133
134sub error_message($self)
135{
136	my $error = $self->{error};
137	if ($error == BAD_PACKAGE) {
138		return "bad package";
139	} elsif ($error == CANT_INSTALL) {
140		if ($self->{errorinfo}) {
141			return "$self->{errorinfo}";
142		} else {
143			return "can't install";
144		}
145	} elsif ($error == NOT_FOUND) {
146		return "not found";
147	} elsif ($error == ALREADY_INSTALLED) {
148		return "already installed";
149	} else {
150		return "no error";
151	}
152}
153
154sub complete_old($self)
155{
156	my $location = $self->{location};
157
158	if (!defined $location) {
159		$self->set_error(NOT_FOUND);
160    	} else {
161		my $plist = $location->plist;
162		if (!defined $plist) {
163			$self->set_error(BAD_PACKAGE);
164		} else {
165			$self->{plist} = $plist;
166			delete $location->{contents};
167			delete $location->{update_info};
168		}
169	}
170}
171
172sub complete_dependency_info($self)
173{
174	my $location = $self->{location};
175
176	if (!defined $location) {
177		$self->set_error(NOT_FOUND);
178	} else {
179		if (!defined $self->{plist}) {
180			# trigger build
181			$location->update_info;
182		}
183	}
184}
185
186sub create_old($class, $pkgname, $state)
187{
188	my $self= $class->new;
189	$self->{name} = $pkgname;
190
191	my $location = $state->repo->installed->find($pkgname);
192	if (defined $location) {
193		$self->{location} = $location;
194	}
195	$self->complete_dependency_info;
196
197	return $self;
198}
199
200sub create_new($class, $pkg)
201{
202	my $handle = $class->new;
203	$handle->{name} = $pkg;
204	$handle->{tweaked} = 0;
205	return $handle;
206}
207
208sub from_location($class, $location)
209{
210	my $handle = $class->new;
211	$handle->{location} = $location;
212	$handle->{tweaked} = 0;
213	return $handle;
214}
215
216sub get_plist($handle, $state)
217{
218	my $location = $handle->{location};
219	my $pkg = $handle->pkgname;
220
221	if ($state->verbose >= 2) {
222		$state->say("#1parsing #2", $state->deptree_header($pkg), $pkg);
223	}
224	my $plist = $location->plist;
225	unless (defined $plist) {
226		$state->say("Can't find CONTENTS from #1", $location->url)
227		    unless $location->{error_reported};
228		$location->close_with_client_error;
229		$location->wipe_info;
230		$handle->set_error(BAD_PACKAGE);
231		$handle->{error_reported} = 1;
232		return;
233	}
234	delete $location->{update_info};
235	$location->decorate($plist);
236	if ($plist->localbase ne $state->{localbase}) {
237		$state->say("Localbase mismatch: package has: #1, user wants: #2",
238		    $plist->localbase, $state->{localbase});
239		$location->close_with_client_error;
240		$location->wipe_info;
241		$handle->set_error(BAD_PACKAGE);
242		return;
243	}
244	my $pkgname = $handle->{pkgname} = $plist->pkgname;
245
246	if ($pkg ne '-') {
247		if (!defined $pkgname or $pkg ne $pkgname) {
248			$state->say("Package name is not consistent ???");
249			$location->close_with_client_error;
250			$location->wipe_info;
251			$handle->set_error(BAD_PACKAGE);
252			return;
253		}
254	}
255	$handle->{plist} = $plist;
256}
257
258sub get_location($handle, $state)
259{
260	my $name = $handle->{name};
261
262	my $location = $state->repo->find($name);
263	if (!$location) {
264		$state->print("#1", $state->deptree_header($name));
265		$handle->set_error(NOT_FOUND);
266		$handle->{tweaked} =
267		    OpenBSD::Add::tweak_package_status($handle->pkgname,
268			$state);
269		if (!$handle->{tweaked}) {
270			$state->say("Can't find #1", $name);
271			$handle->{error_reported} = 1;
272			eval {
273				my $r = [$name];
274				$state->quirks->filter_obsolete($r, $state);
275			}
276		}
277		return;
278	}
279	$handle->{location} = $location;
280	$handle->{pkgname} = $location->name;
281}
282
283sub complete($handle, $state)
284{
285	return if $handle->has_error;
286
287	if (!defined $handle->{location}) {
288		$handle->get_location($state);
289	}
290	return if $handle->has_error;
291	if (!defined $handle->{plist}) {
292		$handle->get_plist($state);
293	}
294}
295
296package OpenBSD::Handle::BaseSystem;
297our @ISA = qw(OpenBSD::Handle);
298sub pkgname($) { return "BaseSystem"; }
299
300sub is_real($) { return 0; }
301
3021;
303