18968f6aaSespie# ex:ts=8 sw=4: 2*d6425245Sespie# $OpenBSD: Add.pm,v 1.196 2023/10/11 13:54:43 espie Exp $ 38968f6aaSespie# 445019a4aSespie# Copyright (c) 2003-2014 Marc Espie <espie@openbsd.org> 58968f6aaSespie# 68968f6aaSespie# Permission to use, copy, modify, and distribute this software for any 78968f6aaSespie# purpose with or without fee is hereby granted, provided that the above 88968f6aaSespie# copyright notice and this permission notice appear in all copies. 98968f6aaSespie# 108968f6aaSespie# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 118968f6aaSespie# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 128968f6aaSespie# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 138968f6aaSespie# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 148968f6aaSespie# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 158968f6aaSespie# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 168968f6aaSespie# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 170fbefeddSespie 18039cbdaaSespieuse v5.36; 198968f6aaSespie 208968f6aaSespiepackage OpenBSD::Add; 219e4de79fSespieuse OpenBSD::Error; 22ebc3e79eSespieuse OpenBSD::PackageInfo; 23cddc17abSespieuse OpenBSD::ArcCheck; 2473c16894Sespieuse OpenBSD::Paths; 257f105815Sespieuse File::Copy; 268968f6aaSespie 27039cbdaaSespiesub manpages_index($state) 289e4de79fSespie{ 29005e7d56Sespie return unless defined $state->{addman}; 309e4de79fSespie my $destdir = $state->{destdir}; 319e4de79fSespie 325f30bd74Sespie # fudge verbose for API differences 33005e7d56Sespie while (my ($k, $v) = each %{$state->{addman}}) { 34005e7d56Sespie my @l = map { "$destdir$k/$_" } @$v; 359e4de79fSespie if ($state->{not}) { 367e83eca3Sespie $state->say("Merging manpages in #1: #2", 375f30bd74Sespie $destdir.$k, join(' ', @l)) if $state->verbose; 389e4de79fSespie } else { 39101180a9Sespie $state->run_makewhatis(['-d', $destdir.$k], \@l); 409e4de79fSespie } 419e4de79fSespie } 42005e7d56Sespie delete $state->{addman}; 439e4de79fSespie} 449e4de79fSespie 45039cbdaaSespiesub register_installation($plist, $state) 469e4de79fSespie{ 4709ca648fSespie if ($state->{not}) { 4809ca648fSespie $plist->to_cache; 4909ca648fSespie } else { 50c2569c13Sespie my $dest = installed_info($plist->pkgname); 519e4de79fSespie mkdir($dest); 528d5333baSespie $plist->copy_info($dest, $state); 53c2569c13Sespie $plist->set_infodir($dest); 54f04afe28Sespie $plist->to_installation; 559e4de79fSespie } 5609ca648fSespie} 579e4de79fSespie 58039cbdaaSespiesub validate_plist($plist, $state, $set) 599e4de79fSespie{ 60062c25acSespie $plist->prepare_for_addition($state, $plist->pkgname, $set); 619e4de79fSespie} 62ebc3e79eSespie 63039cbdaaSespiesub record_partial_installation($plist, $state, $h) 64c767db06Sespie{ 65c767db06Sespie use OpenBSD::PackingElement; 66c767db06Sespie 676a5fab34Sespie my $n = $plist->make_shallow_copy($h); 68f04afe28Sespie my $borked = borked_package($plist->pkgname); 693f7a0022Sespie $n->set_pkgname($borked); 70c767db06Sespie 71c767db06Sespie # last file may have not copied correctly 725c5127c1Sespie my $last = $n->{state}{lastfile}; 73700d29cbSespie if (defined $last && defined($last->{d})) { 74c767db06Sespie 75700d29cbSespie my $old = $last->{d}; 761f6201e6Sespie my $lastname = $last->realname($state); 778cf6695bSespie if (-f $lastname) { 78700d29cbSespie $last->{d} = $last->compute_digest($lastname, $old); 79700d29cbSespie if (!$old->equals($last->{d})) { 807e83eca3Sespie $state->say("Adjusting #1 for #2 from #3 to #4", 817e83eca3Sespie $old->keyword, $lastname, $old->stringize, 827e83eca3Sespie $last->{d}->stringize); 83c767db06Sespie } 848cf6695bSespie } else { 8595a49439Sespie delete $last->{d}; 868cf6695bSespie } 87c767db06Sespie } 886428b005Sespie register_installation($n, $state); 893f2ef483Sespie return $borked; 903f2ef483Sespie} 913f2ef483Sespie 92039cbdaaSespiesub perform_installation($handle, $state) 939a36c239Sespie{ 94*d6425245Sespie return if $state->{regression}{stub} && $handle->pkgname !~ /^quirks\-/; 950c61d0f0Sespie 9695a49439Sespie $state->{partial} = $handle->{partial}; 9723b5e034Sespie $state->progress->visit_with_size($handle->{plist}, 'install'); 98cdd4712cSespie if ($handle->{location}{early_close}) { 99cdd4712cSespie $handle->{location}->close_now; 100cdd4712cSespie } else { 1019a36c239Sespie $handle->{location}->finish_and_close; 1029a36c239Sespie } 103cdd4712cSespie} 1049a36c239Sespie 105039cbdaaSespiesub skip_to_the_end($handle, $state, $tied, $p) 1062eca3cddSespie{ 1078faa7e80Sespie $state->tweak_header("skipping"); 108cdd4712cSespie for my $e (values %$tied) { 109cdd4712cSespie $e->tie($state); 110d4147c99Sespie $p->advance($e); 111cdd4712cSespie } 112cdd4712cSespie if (keys %$tied > 0) { 11314093141Sespie # skipped entries should still be read in CACHE mode 11414093141Sespie if (defined $state->cache_directory) { 11514093141Sespie while (my $e = $state->{archive}->next) { 11614093141Sespie } 11714093141Sespie } else { 118cdd4712cSespie $handle->{location}{early_close} = 1; 119cdd4712cSespie } 12014093141Sespie } 121ffa43a13Sespie} 122ffa43a13Sespie 123039cbdaaSespiesub perform_extraction($handle, $state) 124ffa43a13Sespie{ 125*d6425245Sespie return if $state->{regression}{stub} && $handle->pkgname !~ /^quirks\-/; 126ffa43a13Sespie 127ffa43a13Sespie $handle->{partial} = {}; 128ffa43a13Sespie $state->{partial} = $handle->{partial}; 129ffa43a13Sespie $state->{archive} = $handle->{location}; 130ffa43a13Sespie $state->{check_digest} = $handle->{plist}{check_digest}; 131ffa43a13Sespie 132ffa43a13Sespie # archives are actually stored out of order, find_extractible 133ffa43a13Sespie # will dispatch the packing-list entries into hashes keyed by names. 134ffa43a13Sespie # For "tied" entries, also see tie_files in OpenBSD::PkgAdd. 135ffa43a13Sespie my ($wanted, $tied) = ({}, {}); 136ffa43a13Sespie $handle->{plist}->find_extractible($state, $wanted, $tied); 137c3b72fabSespie my $p = $state->progress->new_sizer($handle->{plist}); 138ffa43a13Sespie 139ffa43a13Sespie # so iterate over the archive, and "consume" hashes entry as we go 140ffa43a13Sespie # it's necessary to delete them so that skip_to_the_end will work 141ffa43a13Sespie # correctly (relies on wanted being empty to trigger, and requires 142ffa43a13Sespie # tied to be correct for the progress meter). 143ffa43a13Sespie if (keys %$wanted == 0) { 144ffa43a13Sespie skip_to_the_end($handle, $state, $tied, $p); 14588e129ceSespie return; 146cdd4712cSespie } 14788e129ceSespie while (my $file = $state->{archive}->next) { 148cdd4712cSespie my $e = $tied->{$file->name}; 149cdd4712cSespie if (defined $e) { 150cdd4712cSespie delete $tied->{$file->name}; 151cdd4712cSespie $e->prepare_to_extract($state, $file); 152cdd4712cSespie $e->tie($state); 153cdd4712cSespie $state->{archive}->skip; 154cdd4712cSespie $p->advance($e); 155cdd4712cSespie # skip to next; 156cdd4712cSespie next; 157cdd4712cSespie } 158cdd4712cSespie $e = $wanted->{$file->name}; 159cdd4712cSespie if (!defined $e) { 160cdd4712cSespie $state->fatal("archive member not found #1", 161cdd4712cSespie $file->name); 162cdd4712cSespie } 163cdd4712cSespie delete $wanted->{$file->name}; 164ffa43a13Sespie # note that readmes are only recorded when !tied, since 165ffa43a13Sespie # we only care if they changed 1662cac224bSespie my $fullname = $e->fullname; 1672cac224bSespie if ($fullname =~ m,^$state->{localbase}/share/doc/pkg-readmes/,) { 1682cac224bSespie push(@{$state->{readmes}}, $fullname); 1692cac224bSespie } 1702cac224bSespie 171cdd4712cSespie $e->prepare_to_extract($state, $file); 172cdd4712cSespie $e->extract($state, $file); 173cdd4712cSespie $p->advance($e); 17488e129ceSespie if (keys %$wanted == 0) { 17588e129ceSespie skip_to_the_end($handle, $state, $tied, $p); 17688e129ceSespie last; 17788e129ceSespie } 178cdd4712cSespie } 179cdd4712cSespie if (keys %$wanted > 0) { 180cdd4712cSespie $state->fatal("Truncated archive"); 181cdd4712cSespie } 1822eca3cddSespie} 1832eca3cddSespie 1842735aeecSespiemy $user_tagged = {}; 1852735aeecSespie 186039cbdaaSespiesub extract_pkgname($pkgname) 1872735aeecSespie{ 1882735aeecSespie $pkgname =~ s/^.*\///; 1892735aeecSespie $pkgname =~ s/\.tgz$//; 1902735aeecSespie return $pkgname; 1912735aeecSespie} 1922735aeecSespie 193039cbdaaSespiesub tweak_package_status($pkgname, $state) 1942735aeecSespie{ 1952735aeecSespie $pkgname = extract_pkgname($pkgname); 1962735aeecSespie return 0 unless is_installed($pkgname); 1972735aeecSespie return 0 unless $user_tagged->{$pkgname}; 19864d38bd3Sespie return 1 if $state->{not}; 1992735aeecSespie my $plist = OpenBSD::PackingList->from_installation($pkgname); 20031a74889Sespie if ($plist->has('manual-installation') && $state->{automatic} > 1) { 2012735aeecSespie delete $plist->{'manual-installation'}; 2022735aeecSespie $plist->to_installation; 2032735aeecSespie return 1; 2042735aeecSespie } elsif (!$plist->has('manual-installation') && !$state->{automatic}) { 2052735aeecSespie OpenBSD::PackingElement::ManualInstallation->add($plist); 2062735aeecSespie $plist->to_installation; 2072735aeecSespie return 1; 2082735aeecSespie } 2092735aeecSespie return 0; 2102735aeecSespie} 2112735aeecSespie 212039cbdaaSespiesub tweak_plist_status($plist, $state) 2132735aeecSespie{ 2142735aeecSespie my $pkgname = $plist->pkgname; 2153f7ff4b1Sespie if ($state->defines('FW_UPDATE')) { 2163f7ff4b1Sespie $plist->has('firmware') or 2173f7ff4b1Sespie OpenBSD::PackingElement::Firmware->add($plist); 2183f7ff4b1Sespie } 2192735aeecSespie return 0 unless $user_tagged->{$pkgname}; 2202735aeecSespie if (!$plist->has('manual-installation') && !$state->{automatic}) { 2212735aeecSespie OpenBSD::PackingElement::ManualInstallation->add($plist); 2222735aeecSespie } 2232735aeecSespie} 2242735aeecSespie 225039cbdaaSespiesub tag_user_packages(@p) 2262735aeecSespie{ 227039cbdaaSespie for my $set (@p) { 228d4d7cbccSespie for my $n ($set->newer_names) { 229d4d7cbccSespie $user_tagged->{OpenBSD::PackageName::url2pkgname($n)} = 1; 230fa7d327fSespie } 2312735aeecSespie } 2322735aeecSespie} 2332735aeecSespie 234ffa43a13Sespie# The whole package addition/replacecement works like this: 235ffa43a13Sespie# first we run tie_files in PkgAdd to figure out tieto 236ffa43a13Sespie# then "find_extractible" figures out the element of the plist that 237ffa43a13Sespie# belong in the archive (thus find_extractible is the hook that always 238ffa43a13Sespie# gets run on every plist entry just prior to extraction/skipping) 239ffa43a13Sespie# 240ffa43a13Sespie# Then the actual extraction proceeds through "prepare_to_extract" and 241ffa43a13Sespie# either "tie' OR "extract" depending on the element status. 242ffa43a13Sespie# Then later on, we run "install". 243ffa43a13Sespie# 244ffa43a13Sespie# Actual file system entries may get a tempname, or avoid temp altogether 245ffa43a13Sespie# 246ffa43a13Sespie# In case of replacement, tempname will get used if the name is the same 247ffa43a13Sespie# but the file content is different. 248ffa43a13Sespie# 249ffa43a13Sespie# If pkg_add can figure out the name is the same, it will set avoidtemp 250ffa43a13Sespie# 251ffa43a13Sespie# Note that directories, hardlinks and symlinks are purely plist objects 252ffa43a13Sespie# with no archive existence: 253ffa43a13Sespie# Links always get deleted/re-added even in replacement mode, while directory 254ffa43a13Sespie# deletion is delayed into OpenBSD::SharedItems, since several packages 255ffa43a13Sespie# may mention the same directory. 256ffa43a13Sespie# 2578968f6aaSespiepackage OpenBSD::PackingElement; 2588968f6aaSespieuse OpenBSD::Error; 2598968f6aaSespie 260ffa43a13Sespie# used by newuser/newgroup to deal with options. 2618968f6aaSespiemy ($uidcache, $gidcache); 2628968f6aaSespie 2637c22bbb7Sespie# $self->prepare_for_addition($state, $pkgname, $set) 264039cbdaaSespiesub prepare_for_addition($, $, $, $) 2653511fba3Sespie{ 2663511fba3Sespie} 2673511fba3Sespie 2687c22bbb7Sespie# $self->find_extractible($state, $wanted, $tied): 2697c22bbb7Sespie# sort item into wanted (needed from archive) / tied (already there) 270039cbdaaSespiesub find_extractible($, $, $, $) 271cdd4712cSespie{ 272cdd4712cSespie} 273cdd4712cSespie 274039cbdaaSespiesub extract($self, $state) 2758968f6aaSespie{ 27695a49439Sespie $state->{partial}{$self} = 1; 27733efc49fSespie if ($state->{interrupted}) { 27833efc49fSespie die "Interrupted"; 27933efc49fSespie } 2802eca3cddSespie} 2812eca3cddSespie 282039cbdaaSespiesub install($self, $state) 2832eca3cddSespie{ 28495a49439Sespie # XXX "normal" items are already in partial, but NOT stuff 28595a49439Sespie # that's install-only, like symlinks and dirs... 28695a49439Sespie $state->{partial}{$self} = 1; 2872eca3cddSespie if ($state->{interrupted}) { 2882eca3cddSespie die "Interrupted"; 2892eca3cddSespie } 2908968f6aaSespie} 2918968f6aaSespie 292039cbdaaSespie# $self->copy_info($dest, $state) 293039cbdaaSespiesub copy_info($, $, $) 294c2569c13Sespie{ 295c2569c13Sespie} 296c2569c13Sespie 297039cbdaaSespiesub set_modes($self, $state, $name) 2988968f6aaSespie{ 2998968f6aaSespie if (defined $self->{owner} || defined $self->{group}) { 3008968f6aaSespie require OpenBSD::IdCache; 3018968f6aaSespie 3028968f6aaSespie if (!defined $uidcache) { 303f04afe28Sespie $uidcache = OpenBSD::UidCache->new; 304f04afe28Sespie $gidcache = OpenBSD::GidCache->new; 3058968f6aaSespie } 306178c9266Sespie my ($uid, $gid) = (-1, -1); 3078968f6aaSespie if (defined $self->{owner}) { 3088968f6aaSespie $uid = $uidcache->lookup($self->{owner}, $uid); 3098968f6aaSespie } 3108968f6aaSespie if (defined $self->{group}) { 3118968f6aaSespie $gid = $gidcache->lookup($self->{group}, $gid); 3128968f6aaSespie } 3138968f6aaSespie chown $uid, $gid, $name; 3148968f6aaSespie } 3158968f6aaSespie if (defined $self->{mode}) { 3168968f6aaSespie my $v = $self->{mode}; 317cc24e6f2Sespie if ($v =~ m/^\d+$/o) { 3188968f6aaSespie chmod oct($v), $name; 3198968f6aaSespie } else { 320178c9266Sespie $state->system(OpenBSD::Paths->chmod, 321178c9266Sespie $self->{mode}, $name); 3228968f6aaSespie } 3238968f6aaSespie } 32431374c36Sespie if (defined $self->{ts}) { 32531374c36Sespie utime $self->{ts}, $self->{ts}, $name; 32631374c36Sespie } 3278968f6aaSespie} 3288968f6aaSespie 329cdd4712cSespiepackage OpenBSD::PackingElement::Meta; 330cdd4712cSespie 331cdd4712cSespie# XXX stuff that's invisible to find_extractible should be considered extracted 332cdd4712cSespie# for the most part, otherwise we create broken partial packages 333039cbdaaSespiesub find_extractible($self, $state, $wanted, $tied) 334cdd4712cSespie{ 335cdd4712cSespie $state->{partial}{$self} = 1; 336cdd4712cSespie} 337cdd4712cSespie 3385c5127c1Sespiepackage OpenBSD::PackingElement::Cwd; 339039cbdaaSespiesub find_extractible # forwarder 3405c5127c1Sespie{ 3415c5127c1Sespie &OpenBSD::PackingElement::Meta::find_extractible; 3425c5127c1Sespie} 3435c5127c1Sespie 3443511fba3Sespiepackage OpenBSD::PackingElement::ExtraInfo; 3453511fba3Sespieuse OpenBSD::Error; 3463511fba3Sespie 347039cbdaaSespiesub prepare_for_addition($self, $state, $pkgname, $) 3483511fba3Sespie{ 3493511fba3Sespie if ($state->{ftp_only} && $self->{ftp} ne 'yes') { 3507e83eca3Sespie $state->errsay("Package #1 is not for ftp", $pkgname); 35185a4d1f9Sespie $state->{problems}++; 3523511fba3Sespie } 3533511fba3Sespie} 3543511fba3Sespie 3553511fba3Sespiepackage OpenBSD::PackingElement::NewAuth; 3563511fba3Sespieuse OpenBSD::Error; 3573511fba3Sespie 358039cbdaaSespiesub add_entry($, $l, @p) 3598968f6aaSespie{ 360039cbdaaSespie while (@p >= 2) { 361039cbdaaSespie my $f = shift @p; 362039cbdaaSespie my $v = shift @p; 3638968f6aaSespie next if !defined $v or $v eq ''; 364a00f6995Sespie if ($v =~ m/^\!(.*)$/o) { 365a00f6995Sespie push(@$l, $f, $1); 3668968f6aaSespie } else { 3678968f6aaSespie push(@$l, $f, $v); 3688968f6aaSespie } 3698968f6aaSespie } 3708968f6aaSespie} 3718968f6aaSespie 372039cbdaaSespiesub prepare_for_addition($self, $state, $pkgname, $) 3733511fba3Sespie{ 37485a4d1f9Sespie my $ok = $self->check; 3753511fba3Sespie if (defined $ok) { 3763511fba3Sespie if ($ok == 0) { 3777e83eca3Sespie $state->errsay("#1 #2 does not match", 3787e83eca3Sespie $self->type, $self->name); 37985a4d1f9Sespie $state->{problems}++; 3803511fba3Sespie } 3813511fba3Sespie } 3823511fba3Sespie $self->{okay} = $ok; 3833511fba3Sespie} 3848968f6aaSespie 385039cbdaaSespiesub install($self, $state) 3868968f6aaSespie{ 387ab64361eSespie $self->SUPER::install($state); 388e451b54dSespie my $auth = $self->name; 3897e83eca3Sespie $state->say("adding #1 #2", $self->type, $auth) if $state->verbose >= 2; 3908968f6aaSespie return if $state->{not}; 3913511fba3Sespie return if defined $self->{okay}; 3928968f6aaSespie my $l=[]; 393e74b30b0Sespie push(@$l, "-v") if $state->verbose >= 2; 3943511fba3Sespie $self->build_args($l); 395dfdce8c8Sespie $state->vsystem($self->command,, @$l, '--', $auth); 3963511fba3Sespie} 3973511fba3Sespie 3983511fba3Sespiepackage OpenBSD::PackingElement::NewUser; 3993511fba3Sespie 400039cbdaaSespiesub command($) { OpenBSD::Paths->useradd } 4013511fba3Sespie 402039cbdaaSespiesub build_args($self, $l) 4033511fba3Sespie{ 4048968f6aaSespie $self->add_entry($l, 4058968f6aaSespie '-u', $self->{uid}, 4068968f6aaSespie '-g', $self->{group}, 4078968f6aaSespie '-L', $self->{class}, 4088968f6aaSespie '-c', $self->{comment}, 4098968f6aaSespie '-d', $self->{home}, 4108968f6aaSespie '-s', $self->{shell}); 4118968f6aaSespie} 4128968f6aaSespie 4138968f6aaSespiepackage OpenBSD::PackingElement::NewGroup; 4148968f6aaSespie 415039cbdaaSespiesub command($) { OpenBSD::Paths->groupadd } 4163511fba3Sespie 417039cbdaaSespiesub build_args($self, $l) 4188968f6aaSespie{ 4198968f6aaSespie $self->add_entry($l, '-g', $self->{gid}); 4208968f6aaSespie} 4218968f6aaSespie 4228968f6aaSespiepackage OpenBSD::PackingElement::FileBase; 4238968f6aaSespieuse OpenBSD::Error; 4248968f6aaSespieuse File::Basename; 4258968f6aaSespieuse File::Path; 4262eca3cddSespieuse OpenBSD::Temp; 4278968f6aaSespie 428039cbdaaSespiesub find_extractible($self, $state, $wanted, $tied) 429cdd4712cSespie{ 43002254ccdSespie if ($self->{tieto} || $self->{link} || $self->{symlink}) { 431cdd4712cSespie $tied->{$self->name} = $self; 432cdd4712cSespie } else { 433cdd4712cSespie $wanted->{$self->name} = $self; 434cdd4712cSespie } 435cdd4712cSespie} 436cdd4712cSespie 437039cbdaaSespiesub prepare_for_addition($self, $state, $pkgname, $) 4383511fba3Sespie{ 43935135148Sespie my $fname = $self->retrieve_fullname($state, $pkgname); 4403511fba3Sespie # check for collisions with existing stuff 4414c82e4b5Sespie if ($state->vstat->exists($fname)) { 44285a4d1f9Sespie push(@{$state->{colliding}}, $self); 44345571e80Sespie $self->{newly_found} = $pkgname; 44485a4d1f9Sespie $state->{problems}++; 4453511fba3Sespie return; 4463511fba3Sespie } 447*d6425245Sespie return if $state->{regression}{stub} && $pkgname !~ /^quirks\-/; 44835135148Sespie my $s = $state->vstat->add($fname, 44935135148Sespie $self->{tieto} ? 0 : $self->retrieve_size, $pkgname); 4503511fba3Sespie return unless defined $s; 451645ff4e3Sespie if ($s->ro) { 452268e18bfSespie $s->report_ro($state, $fname); 4533511fba3Sespie } 454f04afe28Sespie if ($s->avail < 0) { 455268e18bfSespie $s->report_overflow($state, $fname); 4563511fba3Sespie } 4573511fba3Sespie} 4583511fba3Sespie 459039cbdaaSespiesub prepare_to_extract($self, $state, $file) 46021b58429Sespie{ 461f04afe28Sespie my $fullname = $self->fullname; 46221b58429Sespie my $destdir = $state->{destdir}; 46321b58429Sespie 464f04afe28Sespie $file->{cwd} = $self->cwd; 465033b1a08Sespie if (!$file->validate_meta($self)) { 4667e83eca3Sespie $state->fatal("can't continue"); 4671ce85c68Sespie } 4688968f6aaSespie 469e451b54dSespie $file->set_name($fullname); 4708968f6aaSespie $file->{destdir} = $destdir; 471cdd4712cSespie} 472cdd4712cSespie 473039cbdaaSespiesub find_safe_dir($self, $state) 474674fe0a0Sespie{ 475674fe0a0Sespie # figure out a safe directory where to put the temp file 476948d0681Sespie 477948d0681Sespie my $fullname = $self->fullname; 478948d0681Sespie my $filename = $state->{destdir}.$fullname; 479674fe0a0Sespie my $d = dirname($filename); 480d66db768Sespie my $orig = $d; 481674fe0a0Sespie 482674fe0a0Sespie # we go back up until we find an existing directory. 483674fe0a0Sespie # hopefully this will be on the same file system. 484674fe0a0Sespie my @candidates = (); 485674fe0a0Sespie while (!-d $d) { 486674fe0a0Sespie push(@candidates, $d); 487674fe0a0Sespie $d = dirname($d); 488674fe0a0Sespie } 489674fe0a0Sespie # and now we try to go back down, creating the best path we can 490674fe0a0Sespie while (@candidates > 0) { 491674fe0a0Sespie my $c = pop @candidates; 492674fe0a0Sespie last if -e $c; # okay this exists, but is not a directory 493674fe0a0Sespie $d = $c; 494674fe0a0Sespie } 495948d0681Sespie if (!-e _ && !$state->{not}) { 496948d0681Sespie $state->make_path($d, $fullname); 497948d0681Sespie } 498d66db768Sespie if ($state->{current_set}{simple_update} && 499d66db768Sespie $d eq $orig && 500d66db768Sespie !-e $filename) { 501d66db768Sespie $self->{avoid_temp} = $filename; 502d66db768Sespie } 503d66db768Sespie 504674fe0a0Sespie return $d; 505674fe0a0Sespie} 506674fe0a0Sespie 507039cbdaaSespiesub create_temp($self, $d, $state) 508023a8480Sespie{ 509948d0681Sespie my $fullname = $self->fullname; 510023a8480Sespie my ($fh, $tempname) = OpenBSD::Temp::permanent_file($d, "pkg"); 511023a8480Sespie $self->{tempname} = $tempname; 512ddd2e461Sespie if (!defined $tempname) { 513ddd2e461Sespie if ($state->allow_nonroot($fullname)) { 514ddd2e461Sespie $state->errsay("Can't create temp file outside localbase for #1", $fullname); 51580bdda31Sespie $state->errsay(OpenBSD::Temp->last_error); 516ddd2e461Sespie return undef; 517ddd2e461Sespie } 51880bdda31Sespie $state->fatal(OpenBSD::Temp->last_error); 519ddd2e461Sespie } 520023a8480Sespie return ($fh, $tempname); 521023a8480Sespie} 522023a8480Sespie 523039cbdaaSespiesub may_create_temp($self, $d, $state) 524d66db768Sespie{ 525d66db768Sespie if ($self->{avoid_temp}) { 526d66db768Sespie if (open(my $fh, '>', $self->{avoid_temp})) { 527d66db768Sespie return ($fh, $self->{avoid_temp}); 528d66db768Sespie } 529d66db768Sespie } 530d66db768Sespie delete $self->{avoid_temp}; 531d66db768Sespie return $self->create_temp($d, $state); 532d66db768Sespie} 533d66db768Sespie 534039cbdaaSespiesub tie($self, $state) 535cdd4712cSespie{ 536cdd4712cSespie if (defined $self->{link} || defined $self->{symlink}) { 537cdd4712cSespie return; 538cdd4712cSespie } 539cdd4712cSespie 540cdd4712cSespie $self->SUPER::extract($state); 541cdd4712cSespie 542948d0681Sespie my $d = $self->find_safe_dir($state); 543d66db768Sespie my $src = $self->{tieto}->realname($state); 544d66db768Sespie my $dest = $self->realname($state); 545d66db768Sespie if ($state->{current_set}{simple_update} && $src eq $dest) { 546d66db768Sespie $state->say("No name change on tied file #1", $src) 547d66db768Sespie if $state->verbose >= 3; 548d66db768Sespie $state->{current_set}{dont_delete}{$dest} = 1; 549d66db768Sespie $self->{avoid_temp} = 1; 550d66db768Sespie return; 551d66db768Sespie } 552cdd4712cSespie if ($state->{not}) { 5535fe97cfdSespie $state->say("link #1 -> #2", 5545fe97cfdSespie $self->name, $d) if $state->verbose >= 3; 555cdd4712cSespie } else { 556d66db768Sespie my ($fh, $tempname) = $self->may_create_temp($d, $state); 557cdd4712cSespie 558ddd2e461Sespie return if !defined $tempname; 559cdd4712cSespie unlink($tempname); 5605fe97cfdSespie $state->say("link #1 -> #2", $src, $tempname) 561cdd4712cSespie if $state->verbose >= 3; 562cdd4712cSespie link($src, $tempname) || $state->copy_file($src, $tempname); 563cdd4712cSespie } 5648968f6aaSespie} 5658968f6aaSespie 566d66db768Sespie 567039cbdaaSespiesub extract($self, $state, $file) 5682eca3cddSespie{ 5692eca3cddSespie $self->SUPER::extract($state); 5702eca3cddSespie 571948d0681Sespie my $d = $self->find_safe_dir($state); 5722eca3cddSespie if ($state->{not}) { 5735fe97cfdSespie $state->say("extract #1 -> #2", 5745fe97cfdSespie $self->name, $d) if $state->verbose >= 3; 5752eca3cddSespie $state->{archive}->skip; 5762eca3cddSespie } else { 577d66db768Sespie my ($fh, $filename) = $self->may_create_temp($d, $state); 578d66db768Sespie if (!defined $filename) { 579ddd2e461Sespie $state->{archive}->skip; 580ddd2e461Sespie return; 581ddd2e461Sespie } 5822eca3cddSespie 583d66db768Sespie if ($self->{avoid_temp}) { 584d66db768Sespie $state->{current_set}{dont_delete}{$filename} = 1; 585d66db768Sespie } 586d66db768Sespie $state->say("extract #1 -> #2", $self->name, $filename) 5875fe97cfdSespie if $state->verbose >= 3; 5882eca3cddSespie 589cdd4712cSespie 5902eca3cddSespie if (!$file->isFile) { 5912eca3cddSespie $state->fatal("can't extract #1, it's not a file", 5922eca3cddSespie $self->stringize); 5932eca3cddSespie } 594b8f783bdSespie $file->extract_to_fh($fh); 595d66db768Sespie $self->may_check_digest($filename, $state); 5962eca3cddSespie } 5972eca3cddSespie} 5982eca3cddSespie 599039cbdaaSespiesub install($self, $state) 6002eca3cddSespie{ 6012eca3cddSespie $self->SUPER::install($state); 6022eca3cddSespie my $fullname = $self->fullname; 6032eca3cddSespie my $destdir = $state->{destdir}; 6042eca3cddSespie if ($state->{not}) { 6052eca3cddSespie $state->say("moving tempfile -> #1", 6062eca3cddSespie $destdir.$fullname) if $state->verbose >= 5; 6072eca3cddSespie return; 6082eca3cddSespie } 609ddd2e461Sespie $state->make_path(dirname($destdir.$fullname), $fullname); 6102eca3cddSespie if (defined $self->{link}) { 6112eca3cddSespie link($destdir.$self->{link}, $destdir.$fullname); 6125406d593Sespie $state->say("link #1 -> #2", $destdir.$self->{link}, 6135406d593Sespie $destdir.$fullname) if $state->verbose >= 5; 6142eca3cddSespie } elsif (defined $self->{symlink}) { 6152eca3cddSespie symlink($self->{symlink}, $destdir.$fullname); 6165406d593Sespie $state->say("symlink #1 -> #2", $self->{symlink}, 6175406d593Sespie $destdir.$fullname) if $state->verbose >= 5; 6182eca3cddSespie } else { 619d66db768Sespie if (defined $self->{avoid_temp}) { 620d66db768Sespie delete $self->{avoid_temp}; 621d66db768Sespie } else { 622ddd2e461Sespie if (!defined $self->{tempname}) { 623ddd2e461Sespie return if $state->allow_nonroot($fullname); 624ddd2e461Sespie $state->fatal("No tempname for #1", $fullname); 625ddd2e461Sespie } 6262eca3cddSespie rename($self->{tempname}, $destdir.$fullname) or 6272eca3cddSespie $state->fatal("can't move #1 to #2: #3", 6282eca3cddSespie $self->{tempname}, $fullname, $!); 6292eca3cddSespie $state->say("moving #1 -> #2", 6302eca3cddSespie $self->{tempname}, $destdir.$fullname) 6312eca3cddSespie if $state->verbose >= 5; 63295a49439Sespie delete $self->{tempname}; 6332eca3cddSespie } 634d66db768Sespie } 6352eca3cddSespie $self->set_modes($state, $destdir.$fullname); 6362eca3cddSespie} 6372eca3cddSespie 6382fcee420Sespiepackage OpenBSD::PackingElement::Extra; 639039cbdaaSespiesub find_extractible($self, $state, $wanted, $tied) 6402fcee420Sespie{ 6412fcee420Sespie $state->{current_set}{known_extra}{$self->fullname} = 1; 6422fcee420Sespie} 6432fcee420Sespie 644df8a9707Sespiepackage OpenBSD::PackingElement::RcScript; 645039cbdaaSespiesub install($self, $state) 646df8a9707Sespie{ 647df8a9707Sespie $state->{add_rcscripts}{$self->fullname} = 1; 648df8a9707Sespie $self->SUPER::install($state); 649df8a9707Sespie} 650df8a9707Sespie 6518968f6aaSespiepackage OpenBSD::PackingElement::Sample; 6528968f6aaSespieuse OpenBSD::Error; 6538968f6aaSespieuse File::Copy; 6548968f6aaSespie 655039cbdaaSespiesub prepare_for_addition($self, $state, $pkgname, $) 6563511fba3Sespie{ 6573511fba3Sespie if (!defined $self->{copyfrom}) { 6587e83eca3Sespie $state->errsay("\@sample element #1 does not reference a valid file", 6597e83eca3Sespie $self->fullname); 6607a5146e9Sespie $state->{problems}++; 6613511fba3Sespie } 66285a4d1f9Sespie my $fname = $state->{destdir}.$self->fullname; 663a2706d2aSespie # If file already exists, we won't change it 6644c82e4b5Sespie if ($state->vstat->exists($fname)) { 665a2706d2aSespie return; 666a2706d2aSespie } 667a2706d2aSespie my $size = $self->{copyfrom}->{size}; 668b6ce8483Sespie my $s = $state->vstat->add($fname, $size, $pkgname); 669a2706d2aSespie return unless defined $s; 670645ff4e3Sespie if ($s->ro) { 671268e18bfSespie $s->report_ro($state, $fname); 672a2706d2aSespie } 673f04afe28Sespie if ($s->avail < 0) { 674268e18bfSespie $s->report_overflow($state, $fname); 675a2706d2aSespie } 6763511fba3Sespie} 6773511fba3Sespie 678039cbdaaSespiesub find_extractible($self, $state, $wanted, $tied) 679cdd4712cSespie{ 6802fcee420Sespie $state->{current_set}{known_sample}{$self->fullname} = 1; 681cdd4712cSespie} 682cdd4712cSespie 6837c22bbb7Sespie# $self->extract($state) 684039cbdaaSespiesub extract($, $) 6852eca3cddSespie{ 6862eca3cddSespie} 6872eca3cddSespie 688039cbdaaSespiesub install($self, $state) 6898968f6aaSespie{ 690ab64361eSespie $self->SUPER::install($state); 6918968f6aaSespie my $destdir = $state->{destdir}; 692f04afe28Sespie my $filename = $destdir.$self->fullname; 6938968f6aaSespie my $orig = $self->{copyfrom}; 694f04afe28Sespie my $origname = $destdir.$orig->fullname; 6958968f6aaSespie if (-e $filename) { 696e74b30b0Sespie if ($state->verbose) { 6977e83eca3Sespie $state->say("The existing file #1 has NOT been changed", 6987e83eca3Sespie $filename); 699700d29cbSespie if (defined $orig->{d}) { 7008968f6aaSespie 701c742d81aSespie # XXX assume this would be the same type of file 702700d29cbSespie my $d = $self->compute_digest($filename, $orig->{d}); 703700d29cbSespie if ($d->equals($orig->{d})) { 7047e83eca3Sespie $state->say("(but it seems to match the sample file #1)", $origname); 7058968f6aaSespie } else { 7067e83eca3Sespie $state->say("It does NOT match the sample file #1", 7077e83eca3Sespie $origname); 708662ab648Sespie $state->say("You may wish to update it manually"); 7098968f6aaSespie } 7108968f6aaSespie } 7118968f6aaSespie } 7128968f6aaSespie } else { 7138968f6aaSespie if ($state->{not}) { 7147e83eca3Sespie $state->say("The file #1 would be installed from #2", 7157e83eca3Sespie $filename, $origname) if $state->verbose >= 2; 7168968f6aaSespie } else { 7178968f6aaSespie if (!copy($origname, $filename)) { 7187e83eca3Sespie $state->errsay("File #1 could not be installed:\n\t#2", $filename, $!); 7198968f6aaSespie } 7205f05097cSespie $self->set_modes($state, $filename); 721e74b30b0Sespie if ($state->verbose >= 2) { 7227e83eca3Sespie $state->say("installed #1 from #2", 7237e83eca3Sespie $filename, $origname); 7248968f6aaSespie } 7258968f6aaSespie } 7268968f6aaSespie } 7278968f6aaSespie} 7288968f6aaSespie 7298968f6aaSespiepackage OpenBSD::PackingElement::Sampledir; 730039cbdaaSespiesub extract($, $) 7312eca3cddSespie{ 7322eca3cddSespie} 7338968f6aaSespie 734039cbdaaSespiesub install # forwarder 7358968f6aaSespie{ 7368968f6aaSespie &OpenBSD::PackingElement::Dir::install; 7378968f6aaSespie} 7388968f6aaSespie 7398968f6aaSespiepackage OpenBSD::PackingElement::Mandir; 7408968f6aaSespie 741039cbdaaSespiesub install($self, $state) 7428968f6aaSespie{ 7438968f6aaSespie $self->SUPER::install($state); 744d957d6edSespie if (!$state->{current_set}{known_mandirs}{$self->fullname}) { 745c9c651ecSespie $state->log("You may wish to add #1 to /etc/man.conf", 746c9c651ecSespie $self->fullname); 747c9c651ecSespie } 7488968f6aaSespie} 7498968f6aaSespie 7508968f6aaSespiepackage OpenBSD::PackingElement::Manpage; 7518968f6aaSespie 752039cbdaaSespiesub install($self, $state) 7538968f6aaSespie{ 7548968f6aaSespie $self->SUPER::install($state); 755005e7d56Sespie $self->register_manpage($state, 'addman'); 7568968f6aaSespie} 7578968f6aaSespie 7588968f6aaSespiepackage OpenBSD::PackingElement::InfoFile; 7598968f6aaSespieuse File::Basename; 7608968f6aaSespieuse OpenBSD::Error; 7618968f6aaSespie 762039cbdaaSespiesub install($self, $state) 7638968f6aaSespie{ 7648968f6aaSespie $self->SUPER::install($state); 7658968f6aaSespie return if $state->{not}; 766f04afe28Sespie my $fullname = $state->{destdir}.$self->fullname; 767b5458979Sespie $state->vsystem(OpenBSD::Paths->install_info, 768dfdce8c8Sespie "--info-dir=".dirname($fullname), '--', $fullname); 7698968f6aaSespie} 7708968f6aaSespie 7718968f6aaSespiepackage OpenBSD::PackingElement::Shell; 772039cbdaaSespiesub install($self, $state) 7738968f6aaSespie{ 7748968f6aaSespie $self->SUPER::install($state); 7758968f6aaSespie return if $state->{not}; 776f04afe28Sespie my $fullname = $self->fullname; 7778968f6aaSespie my $destdir = $state->{destdir}; 7788968f6aaSespie # go append to /etc/shells if needed 77973c16894Sespie open(my $shells, '<', $destdir.OpenBSD::Paths->shells) or return; 7808968f6aaSespie while(<$shells>) { 781cc24e6f2Sespie s/^\#.*//o; 782b62674ebSespie return if m/^\Q$fullname\E\s*$/; 7838968f6aaSespie } 7848968f6aaSespie close($shells); 78573c16894Sespie open(my $shells2, '>>', $destdir.OpenBSD::Paths->shells) or return; 7868968f6aaSespie print $shells2 $fullname, "\n"; 7878968f6aaSespie close $shells2; 7887e83eca3Sespie $state->say("Shell #1 appended to #2", $fullname, 7897e83eca3Sespie $destdir.OpenBSD::Paths->shells) if $state->verbose; 7908968f6aaSespie} 7918968f6aaSespie 7928968f6aaSespiepackage OpenBSD::PackingElement::Dir; 793039cbdaaSespiesub extract($self, $state) 7942eca3cddSespie{ 7952eca3cddSespie my $fullname = $self->fullname; 7962eca3cddSespie my $destdir = $state->{destdir}; 7972eca3cddSespie 7982eca3cddSespie return if -e $destdir.$fullname; 7992eca3cddSespie $self->SUPER::extract($state); 8002eca3cddSespie $state->say("new directory #1", $destdir.$fullname) 8012eca3cddSespie if $state->verbose >= 3; 8022eca3cddSespie return if $state->{not}; 803ddd2e461Sespie $state->make_path($destdir.$fullname, $fullname); 8042eca3cddSespie} 8052eca3cddSespie 806039cbdaaSespiesub install($self, $state) 8078968f6aaSespie{ 808ab64361eSespie $self->SUPER::install($state); 809f04afe28Sespie my $fullname = $self->fullname; 8108968f6aaSespie my $destdir = $state->{destdir}; 8118968f6aaSespie 8122eca3cddSespie $state->say("new directory #1", $destdir.$fullname) 8132eca3cddSespie if $state->verbose >= 5; 8148968f6aaSespie return if $state->{not}; 815ddd2e461Sespie $state->make_path($destdir.$fullname, $fullname); 8165f05097cSespie $self->set_modes($state, $destdir.$fullname); 8178968f6aaSespie} 8188968f6aaSespie 8198968f6aaSespiepackage OpenBSD::PackingElement::Exec; 8208968f6aaSespieuse OpenBSD::Error; 8218968f6aaSespie 822039cbdaaSespiesub install($self, $state) 8238968f6aaSespie{ 824ab64361eSespie $self->SUPER::install($state); 8257947b3f2Sespie if ($self->should_run($state)) { 8268968f6aaSespie $self->run($state); 8278968f6aaSespie } 8287947b3f2Sespie} 8297947b3f2Sespie 830039cbdaaSespiesub should_run($, $) { 1 } 8317947b3f2Sespie 8327947b3f2Sespiepackage OpenBSD::PackingElement::ExecAdd; 833039cbdaaSespiesub should_run($self, $state) 8347947b3f2Sespie{ 83564061489Sespie return !$state->replacing; 8367947b3f2Sespie} 8377947b3f2Sespie 8387947b3f2Sespiepackage OpenBSD::PackingElement::ExecUpdate; 839039cbdaaSespiesub should_run($self, $state) 8407947b3f2Sespie{ 84164061489Sespie return $state->replacing; 8427947b3f2Sespie} 8438968f6aaSespie 844eb082087Sespiepackage OpenBSD::PackingElement::Tag; 845eb082087Sespie 846039cbdaaSespiesub install($self, $state) 847eb082087Sespie{ 848eb082087Sespie for my $d (@{$self->{definition_list}}) { 849eb082087Sespie $d->add_tag($self, "install", $state); 850eb082087Sespie } 851eb082087Sespie} 852eb082087Sespie 8538968f6aaSespiepackage OpenBSD::PackingElement::Lib; 8548968f6aaSespie 855039cbdaaSespiesub install($self, $state) 8568968f6aaSespie{ 8578968f6aaSespie $self->SUPER::install($state); 858a6526ca6Sespie $self->mark_ldconfig_directory($state); 8598968f6aaSespie} 8608968f6aaSespie 8613511fba3Sespiepackage OpenBSD::PackingElement::SpecialFile; 8623511fba3Sespieuse OpenBSD::PackageInfo; 8633511fba3Sespieuse OpenBSD::Error; 8643511fba3Sespie 865039cbdaaSespiesub copy_info($self, $dest, $state) 866c2569c13Sespie{ 867c2569c13Sespie require File::Copy; 868c2569c13Sespie 8698e2dcc0dSespie File::Copy::move($self->fullname, $dest) or 8708d5333baSespie $state->errsay("Problem while moving #1 into #2: #3", 8718d5333baSespie $self->fullname, $dest, $!); 872c2569c13Sespie} 873c2569c13Sespie 874039cbdaaSespiesub extract($self, $state) 8754119eea1Sespie{ 8764119eea1Sespie $self->may_verify_digest($state); 8774119eea1Sespie} 8784119eea1Sespie 879039cbdaaSespiesub find_extractible($self, $state, $, $) 8800c7be895Sespie{ 8810c7be895Sespie $self->may_verify_digest($state); 8820c7be895Sespie} 8830c7be895Sespie 884c2569c13Sespiepackage OpenBSD::PackingElement::FCONTENTS; 885039cbdaaSespiesub copy_info($, $, $) 886c2569c13Sespie{ 887c2569c13Sespie} 888c2569c13Sespie 889062c25acSespiepackage OpenBSD::PackingElement::AskUpdate; 890039cbdaaSespiesub prepare_for_addition($self, $state, $pkgname, $set) 891062c25acSespie{ 892062c25acSespie my @old = $set->older_names; 893062c25acSespie if ($self->spec->match_ref(\@old) > 0) { 894062c25acSespie my $key = "update_".OpenBSD::PackageName::splitstem($pkgname); 895a409537dSespie return if $state->defines($key); 896e8cdaf99Sespie if ($state->is_interactive) { 897fb75580aSespie if ($state->confirm_defaults_to_no( 898fb75580aSespie "#1: #2.\nDo you want to update now", 899fb75580aSespie $pkgname, $self->{message})) { 900062c25acSespie return; 901062c25acSespie } 902062c25acSespie } else { 9037e83eca3Sespie $state->errsay("Can't update #1 now: #2", 9047e83eca3Sespie $pkgname, $self->{message}); 905062c25acSespie } 906062c25acSespie $state->{problems}++; 907062c25acSespie } 908062c25acSespie} 909062c25acSespie 910c9c651ecSespiepackage OpenBSD::PackingElement::FDISPLAY; 911039cbdaaSespiesub install($self, $state) 912c9c651ecSespie{ 913c9c651ecSespie my $d = $self->{d}; 914d957d6edSespie if (!$state->{current_set}{known_displays}{$self->{d}->key}) { 915c9c651ecSespie $self->prepare($state); 916c9c651ecSespie } 917c9c651ecSespie $self->SUPER::install($state); 918c9c651ecSespie} 919c9c651ecSespie 920c9c651ecSespiepackage OpenBSD::PackingElement::FUNDISPLAY; 921039cbdaaSespiesub find_extractible($self, $state, $wanted, $tied) 922c9c651ecSespie{ 923d957d6edSespie $state->{current_set}{known_displays}{$self->{d}->key} = 1; 924c9c651ecSespie $self->SUPER::find_extractible($state, $wanted, $tied); 925c9c651ecSespie} 926c9c651ecSespie 9278968f6aaSespie1; 928