1# ex:ts=8 sw=4: 2# $OpenBSD: Add.pm,v 1.184 2020/05/17 14:34:47 espie Exp $ 3# 4# Copyright (c) 2003-2014 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::Add; 22use OpenBSD::Error; 23use OpenBSD::PackageInfo; 24use OpenBSD::ArcCheck; 25use OpenBSD::Paths; 26use File::Copy; 27 28sub manpages_index 29{ 30 my ($state) = @_; 31 return unless defined $state->{addman}; 32 my $destdir = $state->{destdir}; 33 34 # fudge verbose for API differences 35 while (my ($k, $v) = each %{$state->{addman}}) { 36 my @l = map { "$destdir$k/$_" } @$v; 37 if ($state->{not}) { 38 $state->say("Merging manpages in #1: #2", 39 $destdir.$k, join(' ', @l)) if $state->verbose; 40 } else { 41 $state->run_makewhatis(['-d', $destdir.$k], \@l); 42 } 43 } 44 delete $state->{addman}; 45} 46 47sub register_installation 48{ 49 my ($plist, $state) = @_; 50 if ($state->{not}) { 51 $plist->to_cache; 52 } else { 53 my $dest = installed_info($plist->pkgname); 54 mkdir($dest); 55 $plist->copy_info($dest, $state); 56 $plist->set_infodir($dest); 57 $plist->to_installation; 58 } 59} 60 61sub validate_plist 62{ 63 my ($plist, $state, $set) = @_; 64 65 $plist->prepare_for_addition($state, $plist->pkgname, $set); 66} 67 68sub record_partial_installation 69{ 70 my ($plist, $state, $h) = @_; 71 72 use OpenBSD::PackingElement; 73 74 my $n = $plist->make_shallow_copy($h); 75 my $borked = borked_package($plist->pkgname); 76 $n->set_pkgname($borked); 77 78 # last file may have not copied correctly 79 my $last = $n->{state}->{lastfile}; 80 if (defined $last && defined($last->{d})) { 81 82 my $old = $last->{d}; 83 my $lastname = $last->realname($state); 84 if (-f $lastname) { 85 $last->{d} = $last->compute_digest($lastname, $old); 86 if (!$old->equals($last->{d})) { 87 $state->say("Adjusting #1 for #2 from #3 to #4", 88 $old->keyword, $lastname, $old->stringize, 89 $last->{d}->stringize); 90 } 91 } else { 92 delete $last->{d}; 93 } 94 } 95 register_installation($n, $state); 96 return $borked; 97} 98 99sub perform_installation 100{ 101 my ($handle, $state) = @_; 102 103 return if $state->defines('stub'); 104 105 $state->{partial} = $handle->{partial}; 106 $state->progress->visit_with_size($handle->{plist}, 'install'); 107 if ($handle->{location}{early_close}) { 108 $handle->{location}->close_now; 109 } else { 110 $handle->{location}->finish_and_close; 111 } 112} 113 114sub perform_extraction 115{ 116 my ($handle, $state) = @_; 117 118 return if $state->defines('stub'); 119 120 $handle->{partial} = {}; 121 $state->{partial} = $handle->{partial}; 122 $state->{archive} = $handle->{location}; 123 $state->{check_digest} = $handle->{plist}{check_digest}; 124 my ($wanted, $tied) = ({}, {}); 125 $handle->{plist}->find_extractible($state, $wanted, $tied); 126 my $p = $state->progress->new_sizer($handle->{plist}, $state); 127 while (my $file = $state->{archive}->next) { 128 if (keys %$wanted == 0) { 129 $state->tweak_header("skipping"); 130 for my $e (values %$tied) { 131 $e->tie($state); 132 $p->advance($e); 133 } 134 if (keys %$tied > 0) { 135 # skipped entries should still be read in CACHE mode 136 if (defined $state->cache_directory) { 137 while (my $e = $state->{archive}->next) { 138 } 139 } else { 140 $handle->{location}{early_close} = 1; 141 } 142 } 143 last; 144 } 145 my $e = $tied->{$file->name}; 146 if (defined $e) { 147 delete $tied->{$file->name}; 148 $e->prepare_to_extract($state, $file); 149 $e->tie($state); 150 $state->{archive}->skip; 151 $p->advance($e); 152 # skip to next; 153 next; 154 } 155 $e = $wanted->{$file->name}; 156 if (!defined $e) { 157 $state->fatal("archive member not found #1", 158 $file->name); 159 } 160 delete $wanted->{$file->name}; 161 my $fullname = $e->fullname; 162 if ($fullname =~ m,^$state->{localbase}/share/doc/pkg-readmes/,) { 163 push(@{$state->{readmes}}, $fullname); 164 } 165 166 $e->prepare_to_extract($state, $file); 167 $e->extract($state, $file); 168 $p->advance($e); 169 } 170 if (keys %$wanted > 0) { 171 $state->fatal("Truncated archive"); 172 } 173 $p->saved; 174} 175 176my $user_tagged = {}; 177 178sub extract_pkgname 179{ 180 my $pkgname = shift; 181 $pkgname =~ s/^.*\///; 182 $pkgname =~ s/\.tgz$//; 183 return $pkgname; 184} 185 186sub tweak_package_status 187{ 188 my ($pkgname, $state) = @_; 189 190 $pkgname = extract_pkgname($pkgname); 191 return 0 unless is_installed($pkgname); 192 return 0 unless $user_tagged->{$pkgname}; 193 return 1 if $state->{not}; 194 my $plist = OpenBSD::PackingList->from_installation($pkgname); 195 if ($plist->has('manual-installation') && $state->{automatic} > 1) { 196 delete $plist->{'manual-installation'}; 197 $plist->to_installation; 198 return 1; 199 } elsif (!$plist->has('manual-installation') && !$state->{automatic}) { 200 OpenBSD::PackingElement::ManualInstallation->add($plist); 201 $plist->to_installation; 202 return 1; 203 } 204 return 0; 205} 206 207sub tweak_plist_status 208{ 209 my ($plist, $state) = @_; 210 211 my $pkgname = $plist->pkgname; 212 if ($state->defines('FW_UPDATE')) { 213 $plist->has('firmware') or 214 OpenBSD::PackingElement::Firmware->add($plist); 215 } 216 return 0 unless $user_tagged->{$pkgname}; 217 if (!$plist->has('manual-installation') && !$state->{automatic}) { 218 OpenBSD::PackingElement::ManualInstallation->add($plist); 219 } 220} 221 222sub tag_user_packages 223{ 224 for my $set (@_) { 225 for my $n ($set->newer_names) { 226 $user_tagged->{OpenBSD::PackageName::url2pkgname($n)} = 1; 227 } 228 } 229} 230 231# used by newuser/newgroup to deal with options. 232package OpenBSD::PackingElement; 233use OpenBSD::Error; 234 235my ($uidcache, $gidcache); 236 237sub prepare_for_addition 238{ 239} 240 241sub find_extractible 242{ 243} 244 245sub extract 246{ 247 my ($self, $state) = @_; 248 $state->{partial}{$self} = 1; 249 if ($state->{interrupted}) { 250 die "Interrupted"; 251 } 252} 253 254sub install 255{ 256 my ($self, $state) = @_; 257 # XXX "normal" items are already in partial, but NOT stuff 258 # that's install-only, like symlinks and dirs... 259 $state->{partial}{$self} = 1; 260 if ($state->{interrupted}) { 261 die "Interrupted"; 262 } 263} 264 265sub copy_info 266{ 267} 268 269sub set_modes 270{ 271 my ($self, $state, $name) = @_; 272 273 if (defined $self->{owner} || defined $self->{group}) { 274 require OpenBSD::IdCache; 275 276 if (!defined $uidcache) { 277 $uidcache = OpenBSD::UidCache->new; 278 $gidcache = OpenBSD::GidCache->new; 279 } 280 my ($uid, $gid) = (-1, -1); 281 if (defined $self->{owner}) { 282 $uid = $uidcache->lookup($self->{owner}, $uid); 283 } 284 if (defined $self->{group}) { 285 $gid = $gidcache->lookup($self->{group}, $gid); 286 } 287 chown $uid, $gid, $name; 288 } 289 if (defined $self->{mode}) { 290 my $v = $self->{mode}; 291 if ($v =~ m/^\d+$/o) { 292 chmod oct($v), $name; 293 } else { 294 $state->system(OpenBSD::Paths->chmod, 295 $self->{mode}, $name); 296 } 297 } 298 if (defined $self->{ts}) { 299 utime $self->{ts}, $self->{ts}, $name; 300 } 301} 302 303package OpenBSD::PackingElement::Meta; 304 305# XXX stuff that's invisible to find_extractible should be considered extracted 306# for the most part, otherwise we create broken partial packages 307sub find_extractible 308{ 309 my ($self, $state, $wanted, $tied) = @_; 310 $state->{partial}{$self} = 1; 311} 312 313package OpenBSD::PackingElement::ExtraInfo; 314use OpenBSD::Error; 315 316sub prepare_for_addition 317{ 318 my ($self, $state, $pkgname) = @_; 319 320 if ($state->{ftp_only} && $self->{ftp} ne 'yes') { 321 $state->errsay("Package #1 is not for ftp", $pkgname); 322 $state->{problems}++; 323 } 324} 325 326package OpenBSD::PackingElement::NewAuth; 327use OpenBSD::Error; 328 329sub add_entry 330{ 331 shift; # get rid of self 332 my $l = shift; 333 while (@_ >= 2) { 334 my $f = shift; 335 my $v = shift; 336 next if !defined $v or $v eq ''; 337 if ($v =~ m/^\!(.*)$/o) { 338 push(@$l, $f, $1); 339 } else { 340 push(@$l, $f, $v); 341 } 342 } 343} 344 345sub prepare_for_addition 346{ 347 my ($self, $state, $pkgname) = @_; 348 my $ok = $self->check; 349 if (defined $ok) { 350 if ($ok == 0) { 351 $state->errsay("#1 #2 does not match", 352 $self->type, $self->name); 353 $state->{problems}++; 354 } 355 } 356 $self->{okay} = $ok; 357} 358 359sub install 360{ 361 my ($self, $state) = @_; 362 $self->SUPER::install($state); 363 my $auth = $self->name; 364 $state->say("adding #1 #2", $self->type, $auth) if $state->verbose >= 2; 365 return if $state->{not}; 366 return if defined $self->{okay}; 367 my $l=[]; 368 push(@$l, "-v") if $state->verbose >= 2; 369 $self->build_args($l); 370 $state->vsystem($self->command,, @$l, '--', $auth); 371} 372 373package OpenBSD::PackingElement::NewUser; 374 375sub command { OpenBSD::Paths->useradd } 376 377sub build_args 378{ 379 my ($self, $l) = @_; 380 381 $self->add_entry($l, 382 '-u', $self->{uid}, 383 '-g', $self->{group}, 384 '-L', $self->{class}, 385 '-c', $self->{comment}, 386 '-d', $self->{home}, 387 '-s', $self->{shell}); 388} 389 390package OpenBSD::PackingElement::NewGroup; 391 392sub command { OpenBSD::Paths->groupadd } 393 394sub build_args 395{ 396 my ($self, $l) = @_; 397 398 $self->add_entry($l, '-g', $self->{gid}); 399} 400 401package OpenBSD::PackingElement::FileBase; 402use OpenBSD::Error; 403use File::Basename; 404use File::Path; 405use OpenBSD::Temp; 406 407sub find_extractible 408{ 409 my ($self, $state, $wanted, $tied) = @_; 410 if ($self->{tieto} || $self->{link} || $self->{symlink}) { 411 $tied->{$self->name} = $self; 412 } else { 413 $wanted->{$self->name} = $self; 414 } 415} 416 417sub prepare_for_addition 418{ 419 my ($self, $state, $pkgname) = @_; 420 my $fname = $self->retrieve_fullname($state, $pkgname); 421 # check for collisions with existing stuff 422 if ($state->vstat->exists($fname)) { 423 push(@{$state->{colliding}}, $self); 424 $self->{newly_found} = $pkgname; 425 $state->{problems}++; 426 return; 427 } 428 return if $state->defines('stub'); 429 my $s = $state->vstat->add($fname, 430 $self->{tieto} ? 0 : $self->retrieve_size, $pkgname); 431 return unless defined $s; 432 if ($s->ro) { 433 $s->report_ro($state, $fname); 434 } 435 if ($s->avail < 0) { 436 $s->report_overflow($state, $fname); 437 } 438} 439 440sub prepare_to_extract 441{ 442 my ($self, $state, $file) = @_; 443 my $fullname = $self->fullname; 444 my $destdir = $state->{destdir}; 445 446 $file->{cwd} = $self->cwd; 447 if (!$file->validate_meta($self)) { 448 $state->fatal("can't continue"); 449 } 450 451 $file->set_name($fullname); 452 $file->{destdir} = $destdir; 453} 454 455sub find_safe_dir 456{ 457 my ($self, $filename) = @_; 458 # figure out a safe directory where to put the temp file 459 my $d = dirname($filename); 460 461 # we go back up until we find an existing directory. 462 # hopefully this will be on the same file system. 463 my @candidates = (); 464 while (!-d $d) { 465 push(@candidates, $d); 466 $d = dirname($d); 467 } 468 # and now we try to go back down, creating the best path we can 469 while (@candidates > 0) { 470 my $c = pop @candidates; 471 last if -e $c; # okay this exists, but is not a directory 472 $d = $c; 473 } 474 return $d; 475} 476 477sub create_temp 478{ 479 my ($self, $d, $state, $fullname) = @_; 480 # XXX this takes over right after find_safe_dir 481 if (!-e _) { 482 $state->make_path($d, $fullname); 483 } 484 my ($fh, $tempname) = OpenBSD::Temp::permanent_file($d, "pkg"); 485 $self->{tempname} = $tempname; 486 if (!defined $tempname) { 487 if ($state->allow_nonroot($fullname)) { 488 $state->errsay("Can't create temp file outside localbase for #1", $fullname); 489 $state->errsay(OpenBSD::Temp->last_error); 490 return undef; 491 } 492 $state->fatal(OpenBSD::Temp->last_error); 493 } 494 return ($fh, $tempname); 495} 496 497sub tie 498{ 499 my ($self, $state) = @_; 500 if (defined $self->{link} || defined $self->{symlink}) { 501 return; 502 } 503 504 $self->SUPER::extract($state); 505 506 my $d = $self->find_safe_dir($state->{destdir}.$self->fullname); 507 if ($state->{not}) { 508 $state->say("link #1 -> #2", 509 $self->name, $d) if $state->verbose >= 3; 510 } else { 511 my ($fh, $tempname) = $self->create_temp($d, $state, 512 $self->fullname); 513 514 return if !defined $tempname; 515 my $src = $self->{tieto}->realname($state); 516 unlink($tempname); 517 $state->say("link #1 -> #2", $src, $tempname) 518 if $state->verbose >= 3; 519 link($src, $tempname) || $state->copy_file($src, $tempname); 520 } 521} 522 523sub extract 524{ 525 my ($self, $state, $file) = @_; 526 527 $self->SUPER::extract($state); 528 529 my $d = $self->find_safe_dir($file->{destdir}.$file->name); 530 if ($state->{not}) { 531 $state->say("extract #1 -> #2", 532 $self->name, $d) if $state->verbose >= 3; 533 $state->{archive}->skip; 534 } else { 535 my ($fh, $tempname) = $self->create_temp($d, $state, 536 $file->name); 537 if (!defined $tempname) { 538 $state->{archive}->skip; 539 return; 540 } 541 542 # XXX don't apply destdir twice 543 $file->{destdir} = ''; 544 $file->set_name($tempname); 545 546 $state->say("extract #1 -> #2", $self->name, $tempname) 547 if $state->verbose >= 3; 548 549 550 if (!$file->isFile) { 551 $state->fatal("can't extract #1, it's not a file", 552 $self->stringize); 553 } 554 $file->create; 555 $self->may_check_digest($file, $state); 556 } 557} 558 559sub install 560{ 561 my ($self, $state) = @_; 562 $self->SUPER::install($state); 563 my $fullname = $self->fullname; 564 my $destdir = $state->{destdir}; 565 if ($state->{not}) { 566 $state->say("moving tempfile -> #1", 567 $destdir.$fullname) if $state->verbose >= 5; 568 return; 569 } 570 $state->make_path(dirname($destdir.$fullname), $fullname); 571 if (defined $self->{link}) { 572 link($destdir.$self->{link}, $destdir.$fullname); 573 } elsif (defined $self->{symlink}) { 574 symlink($self->{symlink}, $destdir.$fullname); 575 } else { 576 if (!defined $self->{tempname}) { 577 return if $state->allow_nonroot($fullname); 578 $state->fatal("No tempname for #1", $fullname); 579 } 580 rename($self->{tempname}, $destdir.$fullname) or 581 $state->fatal("can't move #1 to #2: #3", 582 $self->{tempname}, $fullname, $!); 583 $state->say("moving #1 -> #2", 584 $self->{tempname}, $destdir.$fullname) 585 if $state->verbose >= 5; 586 delete $self->{tempname}; 587 } 588 $self->set_modes($state, $destdir.$fullname); 589} 590 591package OpenBSD::PackingElement::RcScript; 592sub install 593{ 594 my ($self, $state) = @_; 595 $state->{add_rcscripts}{$self->fullname} = 1; 596 $self->SUPER::install($state); 597} 598 599package OpenBSD::PackingElement::Sample; 600use OpenBSD::Error; 601use File::Copy; 602 603sub prepare_for_addition 604{ 605 my ($self, $state, $pkgname) = @_; 606 if (!defined $self->{copyfrom}) { 607 $state->errsay("\@sample element #1 does not reference a valid file", 608 $self->fullname); 609 $state->{problems}++; 610 } 611 my $fname = $state->{destdir}.$self->fullname; 612 # If file already exists, we won't change it 613 if ($state->vstat->exists($fname)) { 614 return; 615 } 616 my $size = $self->{copyfrom}->{size}; 617 my $s = $state->vstat->add($fname, $size, $pkgname); 618 return unless defined $s; 619 if ($s->ro) { 620 $s->report_ro($state, $fname); 621 } 622 if ($s->avail < 0) { 623 $s->report_overflow($state, $fname); 624 } 625} 626 627sub find_extractible 628{ 629} 630 631sub extract 632{ 633} 634 635sub install 636{ 637 my ($self, $state) = @_; 638 639 $self->SUPER::install($state); 640 my $destdir = $state->{destdir}; 641 my $filename = $destdir.$self->fullname; 642 my $orig = $self->{copyfrom}; 643 my $origname = $destdir.$orig->fullname; 644 if (-e $filename) { 645 if ($state->verbose) { 646 $state->say("The existing file #1 has NOT been changed", 647 $filename); 648 if (defined $orig->{d}) { 649 650 # XXX assume this would be the same type of file 651 my $d = $self->compute_digest($filename, $orig->{d}); 652 if ($d->equals($orig->{d})) { 653 $state->say("(but it seems to match the sample file #1)", $origname); 654 } else { 655 $state->say("It does NOT match the sample file #1", 656 $origname); 657 $state->say("You may wish to update it manually"); 658 } 659 } 660 } 661 } else { 662 if ($state->{not}) { 663 $state->say("The file #1 would be installed from #2", 664 $filename, $origname) if $state->verbose >= 2; 665 } else { 666 if (!copy($origname, $filename)) { 667 $state->errsay("File #1 could not be installed:\n\t#2", $filename, $!); 668 } 669 $self->set_modes($state, $filename); 670 if ($state->verbose >= 2) { 671 $state->say("installed #1 from #2", 672 $filename, $origname); 673 } 674 } 675 } 676} 677 678package OpenBSD::PackingElement::Sampledir; 679sub extract 680{ 681} 682 683sub install 684{ 685 &OpenBSD::PackingElement::Dir::install; 686} 687 688package OpenBSD::PackingElement::Mandir; 689 690sub install 691{ 692 my ($self, $state) = @_; 693 $self->SUPER::install($state); 694 if (!$state->{current_set}{known_mandirs}{$self->fullname}) { 695 $state->log("You may wish to add #1 to /etc/man.conf", 696 $self->fullname); 697 } 698} 699 700package OpenBSD::PackingElement::Manpage; 701 702sub install 703{ 704 my ($self, $state) = @_; 705 $self->SUPER::install($state); 706 $self->register_manpage($state, 'addman'); 707} 708 709package OpenBSD::PackingElement::InfoFile; 710use File::Basename; 711use OpenBSD::Error; 712 713sub install 714{ 715 my ($self, $state) = @_; 716 $self->SUPER::install($state); 717 return if $state->{not}; 718 my $fullname = $state->{destdir}.$self->fullname; 719 $state->vsystem(OpenBSD::Paths->install_info, 720 "--info-dir=".dirname($fullname), '--', $fullname); 721} 722 723package OpenBSD::PackingElement::Shell; 724sub install 725{ 726 my ($self, $state) = @_; 727 $self->SUPER::install($state); 728 return if $state->{not}; 729 my $fullname = $self->fullname; 730 my $destdir = $state->{destdir}; 731 # go append to /etc/shells if needed 732 open(my $shells, '<', $destdir.OpenBSD::Paths->shells) or return; 733 while(<$shells>) { 734 s/^\#.*//o; 735 return if m/^\Q$fullname\E\s*$/; 736 } 737 close($shells); 738 open(my $shells2, '>>', $destdir.OpenBSD::Paths->shells) or return; 739 print $shells2 $fullname, "\n"; 740 close $shells2; 741 $state->say("Shell #1 appended to #2", $fullname, 742 $destdir.OpenBSD::Paths->shells) if $state->verbose; 743} 744 745package OpenBSD::PackingElement::Dir; 746sub extract 747{ 748 my ($self, $state) = @_; 749 my $fullname = $self->fullname; 750 my $destdir = $state->{destdir}; 751 752 return if -e $destdir.$fullname; 753 $self->SUPER::extract($state); 754 $state->say("new directory #1", $destdir.$fullname) 755 if $state->verbose >= 3; 756 return if $state->{not}; 757 $state->make_path($destdir.$fullname, $fullname); 758} 759 760sub install 761{ 762 my ($self, $state) = @_; 763 $self->SUPER::install($state); 764 my $fullname = $self->fullname; 765 my $destdir = $state->{destdir}; 766 767 $state->say("new directory #1", $destdir.$fullname) 768 if $state->verbose >= 5; 769 return if $state->{not}; 770 $state->make_path($destdir.$fullname, $fullname); 771 $self->set_modes($state, $destdir.$fullname); 772} 773 774package OpenBSD::PackingElement::Exec; 775use OpenBSD::Error; 776 777sub install 778{ 779 my ($self, $state) = @_; 780 781 $self->SUPER::install($state); 782 if ($self->should_run($state)) { 783 $self->run($state); 784 } 785} 786 787sub should_run() { 1 } 788 789package OpenBSD::PackingElement::ExecAdd; 790sub should_run 791{ 792 my ($self, $state) = @_; 793 return !$state->replacing; 794} 795 796package OpenBSD::PackingElement::ExecUpdate; 797sub should_run 798{ 799 my ($self, $state) = @_; 800 return $state->replacing; 801} 802 803package OpenBSD::PackingElement::Tag; 804 805sub install 806{ 807 my ($self, $state) = @_; 808 809 for my $d (@{$self->{definition_list}}) { 810 $d->add_tag($self, "install", $state); 811 } 812} 813 814package OpenBSD::PackingElement::Lib; 815 816sub install 817{ 818 my ($self, $state) = @_; 819 $self->SUPER::install($state); 820 $self->mark_ldconfig_directory($state); 821} 822 823package OpenBSD::PackingElement::SpecialFile; 824use OpenBSD::PackageInfo; 825use OpenBSD::Error; 826 827sub copy_info 828{ 829 my ($self, $dest, $state) = @_; 830 require File::Copy; 831 832 File::Copy::move($self->fullname, $dest) or 833 $state->errsay("Problem while moving #1 into #2: #3", 834 $self->fullname, $dest, $!); 835} 836 837sub extract 838{ 839 my ($self, $state) = @_; 840 $self->may_verify_digest($state); 841} 842 843sub find_extractible 844{ 845 my ($self, $state) = @_; 846 $self->may_verify_digest($state); 847} 848 849package OpenBSD::PackingElement::FCONTENTS; 850sub copy_info 851{ 852} 853 854package OpenBSD::PackingElement::AskUpdate; 855sub prepare_for_addition 856{ 857 my ($self, $state, $pkgname, $set) = @_; 858 my @old = $set->older_names; 859 if ($self->spec->match_ref(\@old) > 0) { 860 my $key = "update_".OpenBSD::PackageName::splitstem($pkgname); 861 return if $state->defines($key); 862 if ($state->is_interactive) { 863 if ($state->confirm_defaults_to_no( 864 "#1: #2.\nDo you want to update now", 865 $pkgname, $self->{message})) { 866 return; 867 } 868 } else { 869 $state->errsay("Can't update #1 now: #2", 870 $pkgname, $self->{message}); 871 } 872 $state->{problems}++; 873 } 874} 875 876package OpenBSD::PackingElement::FDISPLAY; 877sub install 878{ 879 my ($self, $state) = @_; 880 my $d = $self->{d}; 881 if (!$state->{current_set}{known_displays}{$self->{d}->key}) { 882 $self->prepare($state); 883 } 884 $self->SUPER::install($state); 885} 886 887package OpenBSD::PackingElement::FUNDISPLAY; 888sub find_extractible 889{ 890 my ($self, $state, $wanted, $tied) = @_; 891 $state->{current_set}{known_displays}{$self->{d}->key} = 1; 892 $self->SUPER::find_extractible($state, $wanted, $tied); 893} 894 8951; 896