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