1# ex:ts=8 sw=4: 2# $OpenBSD: Add.pm,v 1.186 2021/08/09 16:41:21 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, $state) = @_; 458 # figure out a safe directory where to put the temp file 459 460 my $fullname = $self->fullname; 461 my $filename = $state->{destdir}.$fullname; 462 my $d = dirname($filename); 463 464 # we go back up until we find an existing directory. 465 # hopefully this will be on the same file system. 466 my @candidates = (); 467 while (!-d $d) { 468 push(@candidates, $d); 469 $d = dirname($d); 470 } 471 # and now we try to go back down, creating the best path we can 472 while (@candidates > 0) { 473 my $c = pop @candidates; 474 last if -e $c; # okay this exists, but is not a directory 475 $d = $c; 476 } 477 if (!-e _ && !$state->{not}) { 478 $state->make_path($d, $fullname); 479 } 480 return $d; 481} 482 483sub create_temp 484{ 485 my ($self, $d, $state) = @_; 486 my $fullname = $self->fullname; 487 my ($fh, $tempname) = OpenBSD::Temp::permanent_file($d, "pkg"); 488 $self->{tempname} = $tempname; 489 if (!defined $tempname) { 490 if ($state->allow_nonroot($fullname)) { 491 $state->errsay("Can't create temp file outside localbase for #1", $fullname); 492 $state->errsay(OpenBSD::Temp->last_error); 493 return undef; 494 } 495 $state->fatal(OpenBSD::Temp->last_error); 496 } 497 return ($fh, $tempname); 498} 499 500sub tie 501{ 502 my ($self, $state) = @_; 503 if (defined $self->{link} || defined $self->{symlink}) { 504 return; 505 } 506 507 $self->SUPER::extract($state); 508 509 my $d = $self->find_safe_dir($state); 510 if ($state->{not}) { 511 $state->say("link #1 -> #2", 512 $self->name, $d) if $state->verbose >= 3; 513 } else { 514 my ($fh, $tempname) = $self->create_temp($d, $state); 515 516 return if !defined $tempname; 517 my $src = $self->{tieto}->realname($state); 518 unlink($tempname); 519 $state->say("link #1 -> #2", $src, $tempname) 520 if $state->verbose >= 3; 521 link($src, $tempname) || $state->copy_file($src, $tempname); 522 } 523} 524 525sub extract 526{ 527 my ($self, $state, $file) = @_; 528 529 $self->SUPER::extract($state); 530 531 my $d = $self->find_safe_dir($state); 532 if ($state->{not}) { 533 $state->say("extract #1 -> #2", 534 $self->name, $d) if $state->verbose >= 3; 535 $state->{archive}->skip; 536 } else { 537 my ($fh, $tempname) = $self->create_temp($d, $state); 538 if (!defined $tempname) { 539 $state->{archive}->skip; 540 return; 541 } 542 543 $state->say("extract #1 -> #2", $self->name, $tempname) 544 if $state->verbose >= 3; 545 546 547 if (!$file->isFile) { 548 $state->fatal("can't extract #1, it's not a file", 549 $self->stringize); 550 } 551 $file->extract_to_fh($fh); 552 $self->may_check_digest($tempname, $state); 553 } 554} 555 556sub install 557{ 558 my ($self, $state) = @_; 559 $self->SUPER::install($state); 560 my $fullname = $self->fullname; 561 my $destdir = $state->{destdir}; 562 if ($state->{not}) { 563 $state->say("moving tempfile -> #1", 564 $destdir.$fullname) if $state->verbose >= 5; 565 return; 566 } 567 $state->make_path(dirname($destdir.$fullname), $fullname); 568 if (defined $self->{link}) { 569 link($destdir.$self->{link}, $destdir.$fullname); 570 } elsif (defined $self->{symlink}) { 571 symlink($self->{symlink}, $destdir.$fullname); 572 } else { 573 if (!defined $self->{tempname}) { 574 return if $state->allow_nonroot($fullname); 575 $state->fatal("No tempname for #1", $fullname); 576 } 577 rename($self->{tempname}, $destdir.$fullname) or 578 $state->fatal("can't move #1 to #2: #3", 579 $self->{tempname}, $fullname, $!); 580 $state->say("moving #1 -> #2", 581 $self->{tempname}, $destdir.$fullname) 582 if $state->verbose >= 5; 583 delete $self->{tempname}; 584 } 585 $self->set_modes($state, $destdir.$fullname); 586} 587 588package OpenBSD::PackingElement::RcScript; 589sub install 590{ 591 my ($self, $state) = @_; 592 $state->{add_rcscripts}{$self->fullname} = 1; 593 $self->SUPER::install($state); 594} 595 596package OpenBSD::PackingElement::Sample; 597use OpenBSD::Error; 598use File::Copy; 599 600sub prepare_for_addition 601{ 602 my ($self, $state, $pkgname) = @_; 603 if (!defined $self->{copyfrom}) { 604 $state->errsay("\@sample element #1 does not reference a valid file", 605 $self->fullname); 606 $state->{problems}++; 607 } 608 my $fname = $state->{destdir}.$self->fullname; 609 # If file already exists, we won't change it 610 if ($state->vstat->exists($fname)) { 611 return; 612 } 613 my $size = $self->{copyfrom}->{size}; 614 my $s = $state->vstat->add($fname, $size, $pkgname); 615 return unless defined $s; 616 if ($s->ro) { 617 $s->report_ro($state, $fname); 618 } 619 if ($s->avail < 0) { 620 $s->report_overflow($state, $fname); 621 } 622} 623 624sub find_extractible 625{ 626} 627 628sub extract 629{ 630} 631 632sub install 633{ 634 my ($self, $state) = @_; 635 636 $self->SUPER::install($state); 637 my $destdir = $state->{destdir}; 638 my $filename = $destdir.$self->fullname; 639 my $orig = $self->{copyfrom}; 640 my $origname = $destdir.$orig->fullname; 641 if (-e $filename) { 642 if ($state->verbose) { 643 $state->say("The existing file #1 has NOT been changed", 644 $filename); 645 if (defined $orig->{d}) { 646 647 # XXX assume this would be the same type of file 648 my $d = $self->compute_digest($filename, $orig->{d}); 649 if ($d->equals($orig->{d})) { 650 $state->say("(but it seems to match the sample file #1)", $origname); 651 } else { 652 $state->say("It does NOT match the sample file #1", 653 $origname); 654 $state->say("You may wish to update it manually"); 655 } 656 } 657 } 658 } else { 659 if ($state->{not}) { 660 $state->say("The file #1 would be installed from #2", 661 $filename, $origname) if $state->verbose >= 2; 662 } else { 663 if (!copy($origname, $filename)) { 664 $state->errsay("File #1 could not be installed:\n\t#2", $filename, $!); 665 } 666 $self->set_modes($state, $filename); 667 if ($state->verbose >= 2) { 668 $state->say("installed #1 from #2", 669 $filename, $origname); 670 } 671 } 672 } 673} 674 675package OpenBSD::PackingElement::Sampledir; 676sub extract 677{ 678} 679 680sub install 681{ 682 &OpenBSD::PackingElement::Dir::install; 683} 684 685package OpenBSD::PackingElement::Mandir; 686 687sub install 688{ 689 my ($self, $state) = @_; 690 $self->SUPER::install($state); 691 if (!$state->{current_set}{known_mandirs}{$self->fullname}) { 692 $state->log("You may wish to add #1 to /etc/man.conf", 693 $self->fullname); 694 } 695} 696 697package OpenBSD::PackingElement::Manpage; 698 699sub install 700{ 701 my ($self, $state) = @_; 702 $self->SUPER::install($state); 703 $self->register_manpage($state, 'addman'); 704} 705 706package OpenBSD::PackingElement::InfoFile; 707use File::Basename; 708use OpenBSD::Error; 709 710sub install 711{ 712 my ($self, $state) = @_; 713 $self->SUPER::install($state); 714 return if $state->{not}; 715 my $fullname = $state->{destdir}.$self->fullname; 716 $state->vsystem(OpenBSD::Paths->install_info, 717 "--info-dir=".dirname($fullname), '--', $fullname); 718} 719 720package OpenBSD::PackingElement::Shell; 721sub install 722{ 723 my ($self, $state) = @_; 724 $self->SUPER::install($state); 725 return if $state->{not}; 726 my $fullname = $self->fullname; 727 my $destdir = $state->{destdir}; 728 # go append to /etc/shells if needed 729 open(my $shells, '<', $destdir.OpenBSD::Paths->shells) or return; 730 while(<$shells>) { 731 s/^\#.*//o; 732 return if m/^\Q$fullname\E\s*$/; 733 } 734 close($shells); 735 open(my $shells2, '>>', $destdir.OpenBSD::Paths->shells) or return; 736 print $shells2 $fullname, "\n"; 737 close $shells2; 738 $state->say("Shell #1 appended to #2", $fullname, 739 $destdir.OpenBSD::Paths->shells) if $state->verbose; 740} 741 742package OpenBSD::PackingElement::Dir; 743sub extract 744{ 745 my ($self, $state) = @_; 746 my $fullname = $self->fullname; 747 my $destdir = $state->{destdir}; 748 749 return if -e $destdir.$fullname; 750 $self->SUPER::extract($state); 751 $state->say("new directory #1", $destdir.$fullname) 752 if $state->verbose >= 3; 753 return if $state->{not}; 754 $state->make_path($destdir.$fullname, $fullname); 755} 756 757sub install 758{ 759 my ($self, $state) = @_; 760 $self->SUPER::install($state); 761 my $fullname = $self->fullname; 762 my $destdir = $state->{destdir}; 763 764 $state->say("new directory #1", $destdir.$fullname) 765 if $state->verbose >= 5; 766 return if $state->{not}; 767 $state->make_path($destdir.$fullname, $fullname); 768 $self->set_modes($state, $destdir.$fullname); 769} 770 771package OpenBSD::PackingElement::Exec; 772use OpenBSD::Error; 773 774sub install 775{ 776 my ($self, $state) = @_; 777 778 $self->SUPER::install($state); 779 if ($self->should_run($state)) { 780 $self->run($state); 781 } 782} 783 784sub should_run() { 1 } 785 786package OpenBSD::PackingElement::ExecAdd; 787sub should_run 788{ 789 my ($self, $state) = @_; 790 return !$state->replacing; 791} 792 793package OpenBSD::PackingElement::ExecUpdate; 794sub should_run 795{ 796 my ($self, $state) = @_; 797 return $state->replacing; 798} 799 800package OpenBSD::PackingElement::Tag; 801 802sub install 803{ 804 my ($self, $state) = @_; 805 806 for my $d (@{$self->{definition_list}}) { 807 $d->add_tag($self, "install", $state); 808 } 809} 810 811package OpenBSD::PackingElement::Lib; 812 813sub install 814{ 815 my ($self, $state) = @_; 816 $self->SUPER::install($state); 817 $self->mark_ldconfig_directory($state); 818} 819 820package OpenBSD::PackingElement::SpecialFile; 821use OpenBSD::PackageInfo; 822use OpenBSD::Error; 823 824sub copy_info 825{ 826 my ($self, $dest, $state) = @_; 827 require File::Copy; 828 829 File::Copy::move($self->fullname, $dest) or 830 $state->errsay("Problem while moving #1 into #2: #3", 831 $self->fullname, $dest, $!); 832} 833 834sub extract 835{ 836 my ($self, $state) = @_; 837 $self->may_verify_digest($state); 838} 839 840sub find_extractible 841{ 842 my ($self, $state) = @_; 843 $self->may_verify_digest($state); 844} 845 846package OpenBSD::PackingElement::FCONTENTS; 847sub copy_info 848{ 849} 850 851package OpenBSD::PackingElement::AskUpdate; 852sub prepare_for_addition 853{ 854 my ($self, $state, $pkgname, $set) = @_; 855 my @old = $set->older_names; 856 if ($self->spec->match_ref(\@old) > 0) { 857 my $key = "update_".OpenBSD::PackageName::splitstem($pkgname); 858 return if $state->defines($key); 859 if ($state->is_interactive) { 860 if ($state->confirm_defaults_to_no( 861 "#1: #2.\nDo you want to update now", 862 $pkgname, $self->{message})) { 863 return; 864 } 865 } else { 866 $state->errsay("Can't update #1 now: #2", 867 $pkgname, $self->{message}); 868 } 869 $state->{problems}++; 870 } 871} 872 873package OpenBSD::PackingElement::FDISPLAY; 874sub install 875{ 876 my ($self, $state) = @_; 877 my $d = $self->{d}; 878 if (!$state->{current_set}{known_displays}{$self->{d}->key}) { 879 $self->prepare($state); 880 } 881 $self->SUPER::install($state); 882} 883 884package OpenBSD::PackingElement::FUNDISPLAY; 885sub find_extractible 886{ 887 my ($self, $state, $wanted, $tied) = @_; 888 $state->{current_set}{known_displays}{$self->{d}->key} = 1; 889 $self->SUPER::find_extractible($state, $wanted, $tied); 890} 891 8921; 893