1# ex:ts=8 sw=4: 2# $OpenBSD: PackingElement.pm,v 1.244 2016/06/25 18:02:59 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 21use OpenBSD::PackageInfo; 22use OpenBSD::Paths; 23 24# perl ipc 25require 5.008_000; 26 27# This is the basic class, which is mostly abstract, except for 28# create and register_with_factory. 29# It does provide base methods for stuff under it, though. 30package OpenBSD::PackingElement; 31our %keyword; 32 33sub create 34{ 35 my ($class, $line, $plist) = @_; 36 if ($line =~ m/^\@(\S+)\s*(.*)$/o) { 37 if (defined $keyword{$1}) { 38 $keyword{$1}->add($plist, $2); 39 } else { 40 die "Unknown element: $line"; 41 } 42 } else { 43 chomp $line; 44 OpenBSD::PackingElement::File->add($plist, $line); 45 } 46} 47 48sub register_with_factory 49{ 50 my ($class, $k, $o) = @_; 51 if (!defined $k) { 52 $k = $class->keyword; 53 } 54 if (!defined $o) { 55 $o = $class; 56 } 57 $keyword{$k} = $o; 58} 59 60sub category() { 'items' } 61 62sub new 63{ 64 my ($class, $args) = @_; 65 bless { name => $args }, $class; 66} 67 68sub remove 69{ 70 my ($self, $plist) = @_; 71 $self->{deleted} = 1; 72} 73 74sub clone 75{ 76 my $object = shift; 77 # shallow copy 78 my %h = %$object; 79 bless \%h, ref($object); 80} 81 82 83sub register_manpage 84{ 85} 86 87sub destate 88{ 89} 90 91sub add_object 92{ 93 my ($self, $plist) = @_; 94 $self->destate($plist->{state}); 95 $plist->add2list($self); 96 return $self; 97} 98 99sub add 100{ 101 my ($class, $plist, @args) = @_; 102 103 my $self = $class->new(@args); 104 return $self->add_object($plist); 105} 106 107sub needs_keyword() { 1 } 108 109sub write 110{ 111 my ($self, $fh) = @_; 112 my $s = $self->stringize; 113 if ($self->needs_keyword) { 114 $s = " $s" unless $s eq ''; 115 print $fh "\@", $self->keyword, "$s\n"; 116 } else { 117 print $fh "$s\n"; 118 } 119} 120 121sub write_no_sig 122{ 123 my ($self, $fh) = @_; 124 $self->write($fh); 125} 126 127sub write_without_variation 128{ 129 my ($self, $fh) = @_; 130 $self->write_no_sig($fh); 131} 132 133# needed for comment checking 134sub fullstring 135{ 136 my ($self, $fh) = @_; 137 my $s = $self->stringize; 138 if ($self->needs_keyword) { 139 $s = " $s" unless $s eq ''; 140 return "\@".$self->keyword.$s; 141 } else { 142 return $s; 143 } 144} 145 146sub name 147{ 148 my $self = shift; 149 return $self->{name}; 150} 151 152sub set_name 153{ 154 my ($self, $v) = @_; 155 $self->{name} = $v; 156} 157sub stringize 158{ 159 my $self = shift; 160 return $self->name; 161} 162 163sub IsFile() { 0 } 164 165sub is_a_library() { 0 } 166sub NoDuplicateNames() { 0 } 167 168 169sub copy_shallow_if 170{ 171 my ($self, $copy, $h) = @_; 172 $self->add_object($copy) if defined $h->{$self}; 173} 174 175sub copy_deep_if 176{ 177 my ($self, $copy, $h) = @_; 178 $self->clone->add_object($copy) if defined $h->{$self}; 179} 180 181sub finish 182{ 183 my ($class, $state) = @_; 184 OpenBSD::PackingElement::Fontdir->finish($state); 185 OpenBSD::PackingElement::RcScript->report($state); 186 if ($state->{readmes}) { 187 $state->say("Look in #1/share/doc/pkg-readmes for extra documentation.", $state->{localbase}); 188 } 189} 190 191# Basic class hierarchy 192 193# various stuff that's only linked to objects before/after them 194# this class doesn't have real objects: no valid new nor clone... 195package OpenBSD::PackingElement::Annotation; 196our @ISA=qw(OpenBSD::PackingElement); 197sub new { die "Can't create annotation objects" } 198 199# concrete objects 200package OpenBSD::PackingElement::Object; 201our @ISA=qw(OpenBSD::PackingElement); 202 203sub cwd 204{ 205 return ${$_[0]->{cwd}}; 206} 207 208sub absolute_okay() { 0 } 209sub compute_fullname 210{ 211 my ($self, $state) = @_; 212 213 $self->{cwd} = $state->{cwd}; 214 $self->set_name(File::Spec->canonpath($self->name)); 215 if ($self->name =~ m|^/|) { 216 unless ($self->absolute_okay) { 217 die "Absolute name forbidden: ", $self->name; 218 } 219 } 220} 221 222sub make_full 223{ 224 my ($self, $path) = @_; 225 if ($path !~ m|^/|o && $self->cwd ne '.') { 226 $path = $self->cwd."/".$path; 227 $path =~ s,^//,/,; 228 } 229 return $path; 230} 231 232sub fullname 233{ 234 my $self = shift; 235 return $self->make_full($self->name); 236} 237 238sub compute_modes 239{ 240 my ($self, $state) = @_; 241 if (defined $state->{mode}) { 242 $self->{mode} = $state->{mode}; 243 } 244 if (defined $state->{owner}) { 245 $self->{owner} = $state->{owner}; 246 if (defined $state->{uid}) { 247 $self->{uid} = $state->{uid}; 248 } 249 } 250 if (defined $state->{group}) { 251 $self->{group} = $state->{group}; 252 if (defined $state->{gid}) { 253 $self->{gid} = $state->{gid}; 254 } 255 } 256} 257 258# concrete objects with file-like behavior 259package OpenBSD::PackingElement::FileObject; 260our @ISA=qw(OpenBSD::PackingElement::Object); 261 262sub NoDuplicateNames() { 1 } 263 264sub dirclass() { undef } 265 266sub new 267{ 268 my ($class, $args) = @_; 269 if ($args =~ m/^(.*?)\/+$/o and defined $class->dirclass) { 270 bless { name => $1 }, $class->dirclass; 271 } else { 272 bless { name => $args }, $class; 273 } 274} 275 276sub destate 277{ 278 my ($self, $state) = @_; 279 $state->{lastfileobject} = $self; 280 $self->compute_fullname($state); 281} 282 283sub set_tempname 284{ 285 my ($self, $tempname) = @_; 286 $self->{tempname} = $tempname; 287} 288 289sub realname 290{ 291 my ($self, $state) = @_; 292 293 my $name = $self->fullname; 294 if (defined $self->{tempname}) { 295 $name = $self->{tempname}; 296 } 297 return $state->{destdir}.$name; 298} 299 300sub compute_digest 301{ 302 my ($self, $filename, $class) = @_; 303 require OpenBSD::md5; 304 $class = 'OpenBSD::sha' if !defined $class; 305 return $class->new($filename); 306} 307 308sub write 309{ 310 my ($self, $fh) = @_; 311 312 $self->SUPER::write($fh); 313 if (defined $self->{tags}) { 314 for my $tag (sort keys %{$self->{tags}}) { 315 print $fh "\@tag ", $tag, "\n"; 316 } 317 } 318} 319 320# exec/unexec and friends 321package OpenBSD::PackingElement::Action; 322our @ISA=qw(OpenBSD::PackingElement::Object); 323 324# persistent state for following objects 325package OpenBSD::PackingElement::State; 326our @ISA=qw(OpenBSD::PackingElement::Object); 327 328# meta information, stored elsewhere 329package OpenBSD::PackingElement::Meta; 330our @ISA=qw(OpenBSD::PackingElement); 331 332package OpenBSD::PackingElement::Unique; 333our @ISA=qw(OpenBSD::PackingElement::Meta); 334 335sub add_object 336{ 337 my ($self, $plist) = @_; 338 339 $self->destate($plist->{state}); 340 $plist->addunique($self); 341 return $self; 342} 343 344sub remove 345{ 346 my ($self, $plist) = @_; 347 delete $plist->{$self->category}; 348} 349 350sub category 351{ 352 return ref(shift); 353} 354 355# all dependency information 356package OpenBSD::PackingElement::Depend; 357our @ISA=qw(OpenBSD::PackingElement::Meta); 358 359# Abstract class for all file-like elements 360package OpenBSD::PackingElement::FileBase; 361our @ISA=qw(OpenBSD::PackingElement::FileObject); 362 363use File::Basename; 364 365sub write 366{ 367 my ($self, $fh) = @_; 368 print $fh "\@comment no checksum\n" if defined $self->{nochecksum}; 369 $self->SUPER::write($fh); 370 if (defined $self->{d}) { 371 $self->{d}->write($fh); 372 } 373 if (defined $self->{size}) { 374 print $fh "\@size ", $self->{size}, "\n"; 375 } 376 if (defined $self->{ts}) { 377 print $fh "\@ts ", $self->{ts}, "\n"; 378 } 379 if (defined $self->{symlink}) { 380 print $fh "\@symlink ", $self->{symlink}, "\n"; 381 } 382 if (defined $self->{link}) { 383 print $fh "\@link ", $self->{link}, "\n"; 384 } 385 if (defined $self->{tempname}) { 386 print $fh "\@temp ", $self->{tempname}, "\n"; 387 } 388} 389 390sub destate 391{ 392 my ($self, $state) = @_; 393 $self->SUPER::destate($state); 394 $state->{lastfile} = $self; 395 $state->{lastchecksummable} = $self; 396 $self->compute_modes($state); 397 if (defined $state->{nochecksum}) { 398 $self->{nochecksum} = 1; 399 undef $state->{nochecksum}; 400 } 401} 402 403sub add_digest 404{ 405 my ($self, $d) = @_; 406 $self->{d} = $d; 407} 408sub add_size 409{ 410 my ($self, $sz) = @_; 411 $self->{size} = $sz; 412} 413 414sub add_timestamp 415{ 416 my ($self, $ts) = @_; 417 $self->{ts} = $ts; 418} 419 420# XXX symlink/hardlinks are properties of File, 421# because we want to use inheritance for other stuff. 422 423sub make_symlink 424{ 425 my ($self, $linkname) = @_; 426 $self->{symlink} = $linkname; 427} 428 429sub make_hardlink 430{ 431 my ($self, $linkname) = @_; 432 $self->{link} = $linkname; 433} 434 435sub may_check_digest 436{ 437 my ($self, $file, $state) = @_; 438 if ($state->{check_digest}) { 439 $self->check_digest($file, $state); 440 } 441} 442 443sub check_digest 444{ 445 my ($self, $file, $state) = @_; 446 return if $self->{link} or $self->{symlink}; 447 if (!defined $self->{d}) { 448 $state->log->fatal($state->f("#1 does not have a signature", 449 $self->fullname)); 450 } 451 my $d = $self->compute_digest($file->{destdir}.$file->name); 452 if (!$d->equals($self->{d})) { 453 $state->log->fatal($state->f("checksum for #1 does not match", 454 $self->fullname)); 455 } 456 if ($state->verbose >= 3) { 457 $state->say("Checksum match for #1", $self->fullname); 458 } 459} 460 461sub IsFile() { 1 } 462 463package OpenBSD::PackingElement::File; 464our @ISA=qw(OpenBSD::PackingElement::FileBase); 465 466use OpenBSD::PackageInfo qw(is_info_name); 467sub keyword() { "file" } 468__PACKAGE__->register_with_factory; 469 470sub dirclass() { "OpenBSD::PackingElement::Dir" } 471 472sub needs_keyword 473{ 474 my $self = shift; 475 return $self->stringize =~ m/\^@/; 476} 477 478sub add_object 479{ 480 my ($self, $plist) = @_; 481 482 $self->destate($plist->{state}); 483 my $j = is_info_name($self->fullname); 484 if ($j) { 485 bless $self, "OpenBSD::PackingElement::$j"; 486 $self->add_object($plist); 487 } else { 488 $plist->add2list($self); 489 } 490 return $self; 491} 492 493package OpenBSD::PackingElement::Sample; 494our @ISA=qw(OpenBSD::PackingElement::FileObject); 495 496sub keyword() { "sample" } 497sub absolute_okay() { 1 } 498__PACKAGE__->register_with_factory; 499 500sub destate 501{ 502 my ($self, $state) = @_; 503 if ($state->{lastfile}->isa("OpenBSD::PackingElement::SpecialFile")) { 504 die "Can't \@sample a specialfile: ". 505 $state->{lastfile}->stringize. "\n"; 506 } 507 $self->{copyfrom} = $state->{lastfile}; 508 $self->compute_fullname($state); 509 $self->compute_modes($state); 510} 511 512sub dirclass() { "OpenBSD::PackingElement::Sampledir" } 513 514package OpenBSD::PackingElement::Ghost; 515our @ISA = qw(OpenBSD::PackingElement::FileObject); 516 517sub keyword() { "ghost" } 518sub absolute_okay() { 1 } 519__PACKAGE__->register_with_factory; 520 521sub destate 522{ 523 my ($self, $state) = @_; 524 $self->compute_fullname($state); 525 $self->compute_modes($state); 526} 527 528package OpenBSD::PackingElement::Sampledir; 529our @ISA=qw(OpenBSD::PackingElement::DirBase OpenBSD::PackingElement::Sample); 530 531sub absolute_okay() { 1 } 532 533sub destate 534{ 535 my ($self, $state) = @_; 536 $self->compute_fullname($state); 537 $self->compute_modes($state); 538} 539 540package OpenBSD::PackingElement::RcScript; 541use File::Basename; 542our @ISA = qw(OpenBSD::PackingElement::FileBase); 543 544sub keyword() { "rcscript" } 545sub absolute_okay() { 1 } 546__PACKAGE__->register_with_factory; 547 548sub destate 549{ 550 my ($self, $state) = @_; 551 $self->compute_fullname($state); 552 if ($self->name =~ m/^\//) { 553 $state->set_cwd(dirname($self->name)); 554 } 555 $state->{lastfile} = $self; 556 $state->{lastchecksummable} = $self; 557 $self->compute_modes($state); 558} 559 560sub report 561{ 562 my ($class, $state) = @_; 563 564 my @l; 565 for my $script (sort keys %{$state->{add_rcscripts}}) { 566 next if $state->{delete_rcscripts}{$script}; 567 push(@l, $script); 568 } 569 if (@l > 0) { 570 $state->say("The following new rcscripts were installed: #1", 571 join(' ', @l)); 572 $state->say("See rcctl(8) for details."); 573 } 574} 575 576package OpenBSD::PackingElement::InfoFile; 577our @ISA=qw(OpenBSD::PackingElement::FileBase); 578 579sub keyword() { "info" } 580__PACKAGE__->register_with_factory; 581sub dirclass() { "OpenBSD::PackingElement::Infodir" } 582 583package OpenBSD::PackingElement::Shell; 584our @ISA=qw(OpenBSD::PackingElement::FileBase); 585 586sub keyword() { "shell" } 587__PACKAGE__->register_with_factory; 588 589package OpenBSD::PackingElement::Manpage; 590use File::Basename; 591our @ISA=qw(OpenBSD::PackingElement::FileBase); 592 593sub keyword() { "man" } 594__PACKAGE__->register_with_factory; 595 596sub register_manpage 597{ 598 my ($self, $state, $key) = @_; 599 # XXX don't bother register stuff from partial packages 600 return if defined $self->{tempname}; 601 my $fname = $self->fullname; 602 if ($fname =~ m,^(.*/man)/((?:man|cat).*),) { 603 push(@{$state->{$key}{$1}}, $2); 604 } 605} 606 607sub is_source 608{ 609 my $self = shift; 610 return $self->name =~ m/man\/man[^\/]+\/[^\/]+\.[\dln][^\/]?$/o; 611} 612 613sub source_to_dest 614{ 615 my $self = shift; 616 my $v = $self->name; 617 $v =~ s/(man\/)man([^\/]+\/[^\/]+)\.[\dln][^\/]?$/$1cat$2.0/; 618 return $v; 619} 620 621# assumes the source is nroff, launches nroff 622sub format 623{ 624 my ($self, $state, $dest, $destfh) = @_; 625 626 my $base = $state->{base}; 627 my $fname = $base.$self->fullname; 628 if (-z $fname) { 629 $state->error("empty source manpage: #1", $fname); 630 return; 631 } 632 open(my $fh, '<', $fname) or die "Can't read $fname"; 633 my $line = <$fh>; 634 close $fh; 635 my @extra = (); 636 # extra preprocessors as described in man. 637 if ($line =~ m/^\'\\\"\s+(.*)$/o) { 638 for my $letter (split '', $1) { 639 if ($letter =~ m/[ept]/o) { 640 push(@extra, "-$letter"); 641 } elsif ($letter eq 'r') { 642 push(@extra, "-R"); 643 } 644 } 645 } 646 my $d = dirname($dest); 647 unless (-d $d) { 648 mkdir($d); 649 } 650 if (my ($dir, $file) = $fname =~ m/^(.*)\/([^\/]+\/[^\/]+)$/) { 651 $state->system(sub { 652 open STDOUT, '>&', $destfh or 653 die "Can't write to $dest"; 654 close $destfh; 655 chdir($dir) or die "Can't chdir to $dir"; 656 }, 657 OpenBSD::Paths->groff, 658 qw(-mandoc -mtty-char -E -Ww -Tascii -P -c), 659 @extra, '--', $file); 660 } else { 661 die "Can't parse source name $fname"; 662 } 663 return 1; 664} 665 666package OpenBSD::PackingElement::Mandoc; 667our @ISA=qw(OpenBSD::PackingElement::Manpage); 668 669sub keyword() { "mandoc" } 670__PACKAGE__->register_with_factory; 671 672package OpenBSD::PackingElement::Lib; 673our @ISA=qw(OpenBSD::PackingElement::FileBase); 674 675our $todo = 0; 676 677sub keyword() { "lib" } 678__PACKAGE__->register_with_factory; 679 680sub mark_ldconfig_directory 681{ 682 my ($self, $state) = @_; 683 $state->ldconfig->mark_directory($self->fullname); 684} 685 686sub parse 687{ 688 my ($self, $filename) = @_; 689 if ($filename =~ m/^(.*?)\/?lib([^\/]+)\.so\.(\d+)\.(\d+)$/o) { 690 return ($2, $3, $4, $1); 691 } else { 692 return undef; 693 } 694} 695 696sub is_a_library() { 1 } 697 698package OpenBSD::PackingElement::PkgConfig; 699our @ISA=qw(OpenBSD::PackingElement::FileBase); 700 701sub keyword() { "pkgconfig" } 702__PACKAGE__->register_with_factory; 703 704package OpenBSD::PackingElement::LibtoolLib; 705our @ISA=qw(OpenBSD::PackingElement::FileBase); 706 707sub keyword() { "ltlib" } 708__PACKAGE__->register_with_factory; 709 710package OpenBSD::PackingElement::Binary; 711our @ISA=qw(OpenBSD::PackingElement::FileBase); 712 713sub keyword() { "bin" } 714__PACKAGE__->register_with_factory; 715 716# Comment is very special 717package OpenBSD::PackingElement::Comment; 718our @ISA=qw(OpenBSD::PackingElement::Meta); 719 720sub keyword() { "comment" } 721__PACKAGE__->register_with_factory; 722 723sub destate 724{ 725 my ($self, $state) = @_; 726 $self->{cwd} = $state->{cwd}; 727} 728 729sub add 730{ 731 my ($class, $plist, $args) = @_; 732 733 if ($args =~ m/^\$OpenBSD.*\$\s*$/o) { 734 return OpenBSD::PackingElement::CVSTag->add($plist, $args); 735 } elsif ($args =~ m/^(?:subdir|pkgpath)\=(.*?)\s+cdrom\=(.*?)\s+ftp\=(.*?)\s*$/o) { 736 return OpenBSD::PackingElement::ExtraInfo->add($plist, $1, $2, $3); 737 } elsif ($args eq 'no checksum') { 738 $plist->{state}->{nochecksum} = 1; 739 return; 740 } else { 741 return $class->SUPER::add($plist, $args); 742 } 743} 744 745package OpenBSD::PackingElement::CVSTag; 746our @ISA=qw(OpenBSD::PackingElement::Meta); 747 748sub keyword() { 'comment' } 749 750sub category() { 'cvstags'} 751 752# don't incorporate this into compared signatures 753sub write_without_variation 754{ 755} 756 757package OpenBSD::PackingElement::sha; 758our @ISA=qw(OpenBSD::PackingElement::Annotation); 759 760__PACKAGE__->register_with_factory('sha'); 761 762sub add 763{ 764 my ($class, $plist, $args) = @_; 765 766 require OpenBSD::md5; 767 768 $plist->{state}->{lastchecksummable}->add_digest(OpenBSD::sha->fromstring($args)); 769 return; 770} 771 772package OpenBSD::PackingElement::tag; 773our @ISA=qw(OpenBSD::PackingElement::Annotation); 774 775__PACKAGE__->register_with_factory('tag'); 776 777sub add 778{ 779 my ($class, $plist, $args) = @_; 780 781 if ($args eq 'no checksum') { 782 $plist->{state}{lastfile}{nochecksum} = 1; 783 } else { 784 my $object = $plist->{state}{lastfileobject}; 785 $object->{tags}{$args} = 1; 786 push(@{$plist->{tags}{$args}}, $object); 787 } 788 return undef; 789} 790 791package OpenBSD::PackingElement::DefineTag; 792our @ISA=qw(OpenBSD::PackingElement::Meta); 793 794sub category() { 'define-tag' } 795sub keyword() { 'define-tag' } 796__PACKAGE__->register_with_factory; 797 798sub new 799{ 800 my ($class, $args) = @_; 801 my ($tag, $condition, @command) = split(/\s+/, $args); 802 bless { 803 name => $tag, 804 when => $condition, 805 command => join(' ', @command) 806 }, $class; 807} 808 809sub stringize 810{ 811 my $self = shift; 812 return join(' ', map { $self->{$_}} 813 (qw(name when command))); 814} 815 816package OpenBSD::PackingElement::symlink; 817our @ISA=qw(OpenBSD::PackingElement::Annotation); 818 819__PACKAGE__->register_with_factory('symlink'); 820 821sub add 822{ 823 my ($class, $plist, $args) = @_; 824 825 $plist->{state}->{lastfile}->make_symlink($args); 826 return; 827} 828 829package OpenBSD::PackingElement::hardlink; 830our @ISA=qw(OpenBSD::PackingElement::Annotation); 831 832__PACKAGE__->register_with_factory('link'); 833 834sub add 835{ 836 my ($class, $plist, $args) = @_; 837 838 $plist->{state}->{lastfile}->make_hardlink($args); 839 return; 840} 841 842package OpenBSD::PackingElement::temp; 843our @ISA=qw(OpenBSD::PackingElement::Annotation); 844 845__PACKAGE__->register_with_factory('temp'); 846 847sub add 848{ 849 my ($class, $plist, $args) = @_; 850 $plist->{state}->{lastfile}->set_tempname($args); 851 return; 852} 853 854package OpenBSD::PackingElement::size; 855our @ISA=qw(OpenBSD::PackingElement::Annotation); 856 857__PACKAGE__->register_with_factory('size'); 858 859sub add 860{ 861 my ($class, $plist, $args) = @_; 862 863 $plist->{state}->{lastfile}->add_size($args); 864 return; 865} 866 867package OpenBSD::PackingElement::ts; 868our @ISA=qw(OpenBSD::PackingElement::Annotation); 869 870__PACKAGE__->register_with_factory('ts'); 871 872sub add 873{ 874 my ($class, $plist, $args) = @_; 875 876 $plist->{state}->{lastfile}->add_timestamp($args); 877 return; 878} 879 880package OpenBSD::PackingElement::Option; 881our @ISA=qw(OpenBSD::PackingElement::Meta); 882 883sub keyword() { 'option' } 884__PACKAGE__->register_with_factory; 885 886sub new 887{ 888 my ($class, $args) = @_; 889 if ($args eq 'no-default-conflict') { 890 return OpenBSD::PackingElement::NoDefaultConflict->new; 891 } elsif ($args eq 'manual-installation') { 892 return OpenBSD::PackingElement::ManualInstallation->new; 893 } elsif ($args eq 'firmware') { 894 return OpenBSD::PackingElement::Firmware->new; 895 } elsif ($args eq 'always-update') { 896 return OpenBSD::PackingElement::AlwaysUpdate->new; 897 } elsif ($args eq 'is-branch') { 898 return OpenBSD::PackingElement::IsBranch->new; 899 } else { 900 die "Unknown option: $args"; 901 } 902} 903 904package OpenBSD::PackingElement::UniqueOption; 905our @ISA=qw(OpenBSD::PackingElement::Unique OpenBSD::PackingElement::Option); 906 907sub stringize 908{ 909 my $self = shift; 910 return $self->category; 911} 912 913sub new 914{ 915 my ($class, @args) = @_; 916 bless {}, $class; 917} 918 919package OpenBSD::PackingElement::NoDefaultConflict; 920our @ISA=qw(OpenBSD::PackingElement::UniqueOption); 921 922sub category() { 'no-default-conflict' } 923 924package OpenBSD::PackingElement::ManualInstallation; 925our @ISA=qw(OpenBSD::PackingElement::UniqueOption); 926 927sub category() { 'manual-installation' } 928 929# XXX don't incorporate this in signatures. 930sub write_no_sig() 931{ 932} 933 934package OpenBSD::PackingElement::Firmware; 935our @ISA=qw(OpenBSD::PackingElement::ManualInstallation); 936sub category() { 'firmware' } 937 938package OpenBSD::PackingElement::AlwaysUpdate; 939our @ISA=qw(OpenBSD::PackingElement::UniqueOption); 940 941sub category() 942{ 943 'always-update'; 944} 945 946package OpenBSD::PackingElement::IsBranch; 947our @ISA=qw(OpenBSD::PackingElement::UniqueOption); 948 949sub category() 950{ 951 'is-branch'; 952} 953# The special elements that don't end in the right place 954package OpenBSD::PackingElement::ExtraInfo; 955our @ISA=qw(OpenBSD::PackingElement::Unique OpenBSD::PackingElement::Comment); 956 957sub category() { 'extrainfo' } 958 959sub new 960{ 961 my ($class, $subdir, $cdrom, $ftp) = @_; 962 963 $cdrom =~ s/^\"(.*)\"$/$1/; 964 $cdrom =~ s/^\'(.*)\'$/$1/; 965 $ftp =~ s/^\"(.*)\"$/$1/; 966 $ftp =~ s/^\'(.*)\'$/$1/; 967 bless { subdir => $subdir, 968 path => OpenBSD::PkgPath->new($subdir), 969 cdrom => $cdrom, 970 ftp => $ftp}, $class; 971} 972 973sub subdir 974{ 975 return shift->{subdir}; 976} 977 978sub may_quote 979{ 980 my $s = shift; 981 if ($s =~ m/\s/) { 982 return '"'.$s.'"'; 983 } else { 984 return $s; 985 } 986} 987 988sub stringize 989{ 990 my $self = shift; 991 return join(' ', 992 "pkgpath=".$self->{subdir}, 993 "cdrom=".may_quote($self->{cdrom}), 994 "ftp=".may_quote($self->{ftp})); 995} 996 997package OpenBSD::PackingElement::Name; 998use File::Spec; 999our @ISA=qw(OpenBSD::PackingElement::Unique); 1000 1001sub keyword() { "name" } 1002__PACKAGE__->register_with_factory; 1003sub category() { "name" } 1004 1005package OpenBSD::PackingElement::LocalBase; 1006our @ISA=qw(OpenBSD::PackingElement::Unique); 1007 1008sub keyword() { "localbase" } 1009__PACKAGE__->register_with_factory; 1010sub category() { "localbase" } 1011 1012package OpenBSD::PackingElement::Url; 1013our @ISA=qw(OpenBSD::PackingElement::Unique); 1014 1015sub keyword() { "url" } 1016__PACKAGE__->register_with_factory; 1017sub category() { "url" } 1018 1019# XXX don't incorporate this in signatures. 1020sub write_no_sig() 1021{ 1022} 1023 1024package OpenBSD::PackingElement::Conflict; 1025our @ISA=qw(OpenBSD::PackingElement::Meta); 1026 1027sub keyword() { "conflict" } 1028__PACKAGE__->register_with_factory; 1029sub category() { "conflict" } 1030 1031sub spec 1032{ 1033 my $self =shift; 1034 1035 require OpenBSD::Search; 1036 return OpenBSD::Search::PkgSpec->new($self->name); 1037} 1038 1039package OpenBSD::PackingElement::Dependency; 1040our @ISA=qw(OpenBSD::PackingElement::Depend); 1041use OpenBSD::Error; 1042 1043sub keyword() { "depend" } 1044__PACKAGE__->register_with_factory; 1045sub category() { "depend" } 1046 1047sub new 1048{ 1049 my ($class, $args) = @_; 1050 my ($pkgpath, $pattern, $def) = split /\:/o, $args; 1051 bless { name => $def, pkgpath => $pkgpath, pattern => $pattern, 1052 def => $def }, $class; 1053} 1054 1055sub stringize 1056{ 1057 my $self = shift; 1058 return join(':', map { $self->{$_}} 1059 (qw(pkgpath pattern def))); 1060} 1061 1062OpenBSD::Auto::cache(spec, 1063 sub { 1064 require OpenBSD::Search; 1065 1066 my $self = shift; 1067 return OpenBSD::Search::PkgSpec->new($self->{pattern}) 1068 ->add_pkgpath_hint($self->{pkgpath}); 1069 }); 1070 1071package OpenBSD::PackingElement::Wantlib; 1072our @ISA=qw(OpenBSD::PackingElement::Depend); 1073 1074sub category() { "wantlib" } 1075sub keyword() { "wantlib" } 1076__PACKAGE__->register_with_factory; 1077 1078OpenBSD::Auto::cache(spec, 1079 sub { 1080 my $self = shift; 1081 1082 require OpenBSD::LibSpec; 1083 return OpenBSD::LibSpec->from_string($self->name); 1084 }); 1085package OpenBSD::PackingElement::PkgPath; 1086our @ISA=qw(OpenBSD::PackingElement::Meta); 1087 1088sub keyword() { "pkgpath" } 1089__PACKAGE__->register_with_factory; 1090sub category() { "pkgpath" } 1091 1092sub new 1093{ 1094 my ($class, $fullpkgpath) = @_; 1095 bless {name => $fullpkgpath, 1096 path => OpenBSD::PkgPath::WithOpts->new($fullpkgpath)}, $class; 1097} 1098 1099sub subdir 1100{ 1101 return shift->{name}; 1102} 1103 1104package OpenBSD::PackingElement::AskUpdate; 1105our @ISA=qw(OpenBSD::PackingElement::Meta); 1106 1107sub new 1108{ 1109 my ($class, $args) = @_; 1110 my ($pattern, $message) = split /\s+/o, $args, 2; 1111 bless { pattern => $pattern, message => $message}, $class; 1112} 1113 1114sub stringize 1115{ 1116 my $self = shift; 1117 return join(' ', map { $self->{$_}} 1118 (qw(pattern message))); 1119} 1120 1121sub keyword() { "ask-update" } 1122__PACKAGE__->register_with_factory; 1123sub category() { "ask-update" } 1124 1125OpenBSD::Auto::cache(spec, 1126 sub { 1127 require OpenBSD::PkgSpec; 1128 1129 my $self = shift; 1130 return OpenBSD::PkgSpec->new($self->{pattern}) 1131 }); 1132 1133package OpenBSD::PackingElement::NewAuth; 1134our @ISA=qw(OpenBSD::PackingElement::Action); 1135 1136package OpenBSD::PackingElement::NewUser; 1137our @ISA=qw(OpenBSD::PackingElement::NewAuth); 1138 1139sub type() { "user" } 1140sub category() { "users" } 1141sub keyword() { "newuser" } 1142__PACKAGE__->register_with_factory; 1143 1144sub new 1145{ 1146 my ($class, $args) = @_; 1147 my ($name, $uid, $group, $loginclass, $comment, $home, $shell) = 1148 split /\:/o, $args; 1149 bless { name => $name, uid => $uid, group => $group, 1150 class => $loginclass, 1151 comment => $comment, home => $home, shell => $shell }, $class; 1152} 1153 1154sub destate 1155{ 1156 my ($self, $state) = @_; 1157 my $uid = $self->{uid}; 1158 $uid =~ s/^\!//; 1159 $state->{owners}{$self->{name}} = $uid; 1160} 1161 1162sub check 1163{ 1164 my $self = shift; 1165 my ($name, $passwd, $uid, $gid, $quota, $class, $gcos, $dir, $shell, 1166 $expire) = getpwnam($self->name); 1167 return unless defined $name; 1168 if ($self->{uid} =~ m/^\!(.*)$/o) { 1169 return 0 unless $uid == $1; 1170 } 1171 if ($self->{group} =~ m/^\!(.*)$/o) { 1172 my $g = $1; 1173 unless ($g =~ m/^\d+$/o) { 1174 $g = getgrnam($g); 1175 return 0 unless defined $g; 1176 } 1177 return 0 unless $gid eq $g; 1178 } 1179 if ($self->{class} =~ m/^\!(.*)$/o) { 1180 return 0 unless $class eq $1; 1181 } 1182 if ($self->{comment} =~ m/^\!(.*)$/o) { 1183 return 0 unless $gcos eq $1; 1184 } 1185 if ($self->{home} =~ m/^\!(.*)$/o) { 1186 return 0 unless $dir eq $1; 1187 } 1188 if ($self->{shell} =~ m/^\!(.*)$/o) { 1189 return 0 unless $shell eq $1; 1190 } 1191 return 1; 1192} 1193 1194sub stringize 1195{ 1196 my $self = shift; 1197 return join(':', map { $self->{$_}} 1198 (qw(name uid group class comment home shell))); 1199} 1200 1201package OpenBSD::PackingElement::NewGroup; 1202our @ISA=qw(OpenBSD::PackingElement::NewAuth); 1203 1204 1205sub type() { "group" } 1206sub category() { "groups" } 1207sub keyword() { "newgroup" } 1208__PACKAGE__->register_with_factory; 1209 1210sub new 1211{ 1212 my ($class, $args) = @_; 1213 my ($name, $gid) = split /\:/o, $args; 1214 bless { name => $name, gid => $gid }, $class; 1215} 1216 1217sub destate 1218{ 1219 my ($self, $state) = @_; 1220 my $gid = $self->{gid}; 1221 $gid =~ s/^\!//; 1222 $state->{groups}{$self->{name}} = $gid; 1223} 1224 1225sub check 1226{ 1227 my $self = shift; 1228 my ($name, $passwd, $gid, $members) = getgrnam($self->name); 1229 return unless defined $name; 1230 if ($self->{gid} =~ m/^\!(.*)$/o) { 1231 return 0 unless $gid == $1; 1232 } 1233 return 1; 1234} 1235 1236sub stringize($) 1237{ 1238 my $self = $_[0]; 1239 return join(':', map { $self->{$_}} 1240 (qw(name gid))); 1241} 1242 1243package OpenBSD::PackingElement::Cwd; 1244use File::Spec; 1245our @ISA=qw(OpenBSD::PackingElement::State); 1246 1247 1248sub keyword() { 'cwd' } 1249__PACKAGE__->register_with_factory; 1250 1251sub destate 1252{ 1253 my ($self, $state) = @_; 1254 $state->set_cwd($self->name); 1255} 1256 1257package OpenBSD::PackingElement::Owner; 1258our @ISA=qw(OpenBSD::PackingElement::State); 1259 1260sub keyword() { 'owner' } 1261__PACKAGE__->register_with_factory; 1262 1263sub destate 1264{ 1265 my ($self, $state) = @_; 1266 1267 delete $state->{uid}; 1268 if ($self->name eq '') { 1269 undef $state->{owner}; 1270 } else { 1271 $state->{owner} = $self->name; 1272 if (defined $state->{owners}{$self->name}) { 1273 $state->{uid} = $state->{owners}{$self->name}; 1274 } 1275 } 1276} 1277 1278package OpenBSD::PackingElement::Group; 1279our @ISA=qw(OpenBSD::PackingElement::State); 1280 1281sub keyword() { 'group' } 1282__PACKAGE__->register_with_factory; 1283 1284sub destate 1285{ 1286 my ($self, $state) = @_; 1287 1288 delete $state->{gid}; 1289 if ($self->name eq '') { 1290 undef $state->{group}; 1291 } else { 1292 $state->{group} = $self->name; 1293 if (defined $state->{groups}{$self->name}) { 1294 $state->{gid} = $state->{groups}{$self->name}; 1295 } 1296 } 1297} 1298 1299package OpenBSD::PackingElement::Mode; 1300our @ISA=qw(OpenBSD::PackingElement::State); 1301 1302sub keyword() { 'mode' } 1303__PACKAGE__->register_with_factory; 1304 1305sub destate 1306{ 1307 my ($self, $state) = @_; 1308 1309 if ($self->name eq '') { 1310 undef $state->{mode}; 1311 } else { 1312 $state->{mode} = $self->name; 1313 } 1314} 1315 1316package OpenBSD::PackingElement::Sysctl; 1317our @ISA=qw(OpenBSD::PackingElement::Action); 1318 1319sub keyword() { 'sysctl' } 1320__PACKAGE__->register_with_factory; 1321 1322sub new 1323 1324{ 1325 my ($class, $args) = @_; 1326 if ($args =~ m/^\s*(.*)\s*(\=|\>=)\s*(.*)\s*$/o) { 1327 bless { name => $1, mode => $2, value => $3}, $class; 1328 } else { 1329 die "Bad syntax for \@sysctl"; 1330 } 1331} 1332 1333sub stringize 1334{ 1335 my $self = shift; 1336 return $self->{name}.$self->{mode}.$self->{value}; 1337} 1338 1339package OpenBSD::PackingElement::ExeclikeAction; 1340use File::Basename; 1341use OpenBSD::Error; 1342our @ISA=qw(OpenBSD::PackingElement::Action); 1343 1344sub expand 1345{ 1346 my ($self, $state) = @_; 1347 my $e = $self->name; 1348 if ($e =~ m/\%F/o) { 1349 die "Bad expand" unless defined $state->{lastfile}; 1350 $e =~ s/\%F/$state->{lastfile}->{name}/g; 1351 } 1352 if ($e =~ m/\%D/o) { 1353 die "Bad expand" unless defined $state->{cwd}; 1354 $e =~ s/\%D/$state->cwd/ge; 1355 } 1356 if ($e =~ m/\%B/o) { 1357 die "Bad expand" unless defined $state->{lastfile}; 1358 $e =~ s/\%B/dirname($state->{lastfile}->fullname)/ge; 1359 } 1360 if ($e =~ m/\%f/o) { 1361 die "Bad expand" unless defined $state->{lastfile}; 1362 $e =~ s/\%f/basename($state->{lastfile}->fullname)/ge; 1363 } 1364 return $e; 1365} 1366 1367sub destate 1368{ 1369 my ($self, $state) = @_; 1370 $self->{expanded} = $self->expand($state); 1371} 1372 1373sub run 1374{ 1375 my ($self, $state) = @_; 1376 1377 $state->ldconfig->ensure; 1378 $state->say("#1 #2", $self->keyword, $self->{expanded}) 1379 if $state->verbose >= 2; 1380 $state->log->system(OpenBSD::Paths->sh, '-c', $self->{expanded}) 1381 unless $state->{not}; 1382} 1383 1384package OpenBSD::PackingElement::Exec; 1385our @ISA=qw(OpenBSD::PackingElement::ExeclikeAction); 1386 1387sub keyword() { "exec" } 1388__PACKAGE__->register_with_factory; 1389 1390package OpenBSD::PackingElement::ExecAlways; 1391our @ISA=qw(OpenBSD::PackingElement::Exec); 1392 1393sub keyword() { "exec-always" } 1394__PACKAGE__->register_with_factory; 1395 1396package OpenBSD::PackingElement::ExecAdd; 1397our @ISA=qw(OpenBSD::PackingElement::Exec); 1398 1399sub keyword() { "exec-add" } 1400__PACKAGE__->register_with_factory; 1401 1402package OpenBSD::PackingElement::ExecUpdate; 1403our @ISA=qw(OpenBSD::PackingElement::Exec); 1404 1405sub keyword() { "exec-update" } 1406__PACKAGE__->register_with_factory; 1407 1408package OpenBSD::PackingElement::Unexec; 1409our @ISA=qw(OpenBSD::PackingElement::ExeclikeAction); 1410 1411sub keyword() { "unexec" } 1412__PACKAGE__->register_with_factory; 1413 1414package OpenBSD::PackingElement::UnexecAlways; 1415our @ISA=qw(OpenBSD::PackingElement::Unexec); 1416 1417sub keyword() { "unexec-always" } 1418__PACKAGE__->register_with_factory; 1419 1420package OpenBSD::PackingElement::UnexecUpdate; 1421our @ISA=qw(OpenBSD::PackingElement::Unexec); 1422 1423sub keyword() { "unexec-update" } 1424__PACKAGE__->register_with_factory; 1425 1426package OpenBSD::PackingElement::UnexecDelete; 1427our @ISA=qw(OpenBSD::PackingElement::Unexec); 1428 1429sub keyword() { "unexec-delete" } 1430__PACKAGE__->register_with_factory; 1431 1432package OpenBSD::PackingElement::ExtraUnexec; 1433our @ISA=qw(OpenBSD::PackingElement::ExeclikeAction); 1434 1435sub keyword() { "extraunexec" } 1436__PACKAGE__->register_with_factory; 1437 1438package OpenBSD::PackingElement::DirlikeObject; 1439our @ISA=qw(OpenBSD::PackingElement::FileObject); 1440 1441package OpenBSD::PackingElement::DirBase; 1442our @ISA=qw(OpenBSD::PackingElement::DirlikeObject); 1443 1444sub destate 1445{ 1446 my ($self, $state) = @_; 1447 $state->{lastdir} = $self; 1448 $self->SUPER::destate($state); 1449} 1450 1451 1452sub stringize 1453{ 1454 my $self = shift; 1455 return $self->name."/"; 1456} 1457 1458sub write 1459{ 1460 my ($self, $fh) = @_; 1461 $self->SUPER::write($fh); 1462} 1463 1464package OpenBSD::PackingElement::Dir; 1465our @ISA=qw(OpenBSD::PackingElement::DirBase); 1466 1467sub keyword() { "dir" } 1468__PACKAGE__->register_with_factory; 1469 1470sub destate 1471{ 1472 my ($self, $state) = @_; 1473 $self->SUPER::destate($state); 1474 $self->compute_modes($state); 1475} 1476 1477sub needs_keyword 1478{ 1479 my $self = shift; 1480 return $self->stringize =~ m/\^@/o; 1481} 1482 1483package OpenBSD::PackingElement::Infodir; 1484our @ISA=qw(OpenBSD::PackingElement::Dir); 1485sub keyword() { "info" } 1486sub needs_keyword() { 1 } 1487 1488package OpenBSD::PackingElement::Fontdir; 1489our @ISA=qw(OpenBSD::PackingElement::Dir); 1490sub keyword() { "fontdir" } 1491__PACKAGE__->register_with_factory; 1492sub needs_keyword() { 1 } 1493sub dirclass() { "OpenBSD::PackingElement::Fontdir" } 1494 1495sub install 1496{ 1497 my ($self, $state) = @_; 1498 $self->SUPER::install($state); 1499 $state->log("You may wish to update your font path for #1", $self->fullname); 1500 $state->{recorder}{fonts_todo}{$state->{destdir}.$self->fullname} = 1; 1501} 1502 1503sub reload 1504{ 1505 my ($self, $state) = @_; 1506 $state->{recorder}{fonts_todo}{$state->{destdir}.$self->fullname} = 1; 1507} 1508 1509sub update_fontalias 1510{ 1511 my $dirname = shift; 1512 my @aliases; 1513 1514 if (-d "$dirname") { 1515 for my $alias (glob "$dirname/fonts.alias-*") { 1516 open my $f ,'<', $alias or next; 1517 push(@aliases, <$f>); 1518 close $f; 1519 } 1520 open my $f, '>', "$dirname/fonts.alias"; 1521 print $f @aliases; 1522 close $f; 1523 } 1524} 1525 1526sub restore_fontdir 1527{ 1528 my ($dirname, $state) = @_; 1529 if (-f "$dirname/fonts.dir.dist") { 1530 1531 unlink("$dirname/fonts.dir"); 1532 $state->copy_file("$dirname/fonts.dir.dist", 1533 "$dirname/fonts.dir"); 1534 } 1535} 1536 1537sub run_if_exists 1538{ 1539 my ($state, $cmd, @l) = @_; 1540 1541 if (-x $cmd) { 1542 $state->vsystem($cmd, @l); 1543 } else { 1544 $state->errsay("#1 not found", $cmd); 1545 } 1546} 1547 1548sub finish 1549{ 1550 my ($class, $state) = @_; 1551 my @l = keys %{$state->{recorder}->{fonts_todo}}; 1552 1553 if (@l != 0) { 1554 require OpenBSD::Error; 1555 1556 return if $state->{not}; 1557 map { update_fontalias($_) } @l; 1558 if (-d "@l") { 1559 run_if_exists($state, OpenBSD::Paths->mkfontscale, '--', @l); 1560 run_if_exists($state, OpenBSD::Paths->mkfontdir, '--', @l); 1561 map { restore_fontdir($_, $state) } @l; 1562 } 1563 1564 run_if_exists($state, OpenBSD::Paths->fc_cache, '--', @l); 1565 } 1566} 1567 1568 1569package OpenBSD::PackingElement::Mandir; 1570our @ISA=qw(OpenBSD::PackingElement::Dir); 1571 1572sub keyword() { "mandir" } 1573__PACKAGE__->register_with_factory; 1574sub needs_keyword() { 1 } 1575sub dirclass() { "OpenBSD::PackingElement::Mandir" } 1576 1577package OpenBSD::PackingElement::Extra; 1578our @ISA=qw(OpenBSD::PackingElement::FileObject); 1579 1580sub keyword() { 'extra' } 1581sub absolute_okay() { 1 } 1582__PACKAGE__->register_with_factory; 1583 1584sub destate 1585{ 1586 my ($self, $state) = @_; 1587 $self->compute_fullname($state); 1588} 1589 1590sub dirclass() { "OpenBSD::PackingElement::Extradir" } 1591 1592package OpenBSD::PackingElement::Extradir; 1593our @ISA=qw(OpenBSD::PackingElement::DirBase OpenBSD::PackingElement::Extra); 1594sub absolute_okay() { 1 } 1595 1596sub destate 1597{ 1598 &OpenBSD::PackingElement::Extra::destate; 1599} 1600 1601package OpenBSD::PackingElement::SpecialFile; 1602our @ISA=qw(OpenBSD::PackingElement::Unique); 1603 1604sub add_digest 1605{ 1606 &OpenBSD::PackingElement::FileBase::add_digest; 1607} 1608 1609sub add_size 1610{ 1611 &OpenBSD::PackingElement::FileBase::add_size; 1612} 1613 1614sub add_timestamp 1615{ 1616 # just don't 1617} 1618 1619sub compute_digest 1620{ 1621 &OpenBSD::PackingElement::FileObject::compute_digest; 1622} 1623 1624sub write 1625{ 1626 &OpenBSD::PackingElement::FileBase::write; 1627} 1628 1629sub needs_keyword { 0 } 1630 1631sub add_object 1632{ 1633 my ($self, $plist) = @_; 1634 $self->{infodir} = $plist->{infodir}; 1635 $self->SUPER::add_object($plist); 1636} 1637 1638sub infodir 1639{ 1640 my $self = shift; 1641 return ${$self->{infodir}}; 1642} 1643 1644sub stringize 1645{ 1646 my $self = shift; 1647 return $self->category; 1648} 1649 1650sub fullname 1651{ 1652 my $self = shift; 1653 my $d = $self->infodir; 1654 if (defined $d) { 1655 return $d.$self->name; 1656 } else { 1657 return undef; 1658 } 1659} 1660 1661sub category 1662{ 1663 my $self = shift; 1664 1665 return $self->name; 1666} 1667 1668sub new 1669{ 1670 &OpenBSD::PackingElement::UniqueOption::new; 1671} 1672 1673sub may_verify_digest 1674{ 1675 my ($self, $state) = @_; 1676 if (!$state->{check_digest}) { 1677 return; 1678 } 1679 if (!defined $self->{d}) { 1680 $state->log->fatal($state->f("#1 does not have a signature", 1681 $self->fullname)); 1682 } 1683 my $d = $self->compute_digest($self->fullname); 1684 if (!$d->equals($self->{d})) { 1685 $state->log->fatal($state->f("checksum for #1 does not match", 1686 $self->fullname)); 1687 } 1688 if ($state->verbose >= 3) { 1689 $state->say("Checksum match for #1", $self->fullname); 1690 } 1691} 1692 1693package OpenBSD::PackingElement::FCONTENTS; 1694our @ISA=qw(OpenBSD::PackingElement::SpecialFile); 1695sub name() { OpenBSD::PackageInfo::CONTENTS } 1696# XXX we don't write `self' 1697sub write 1698{} 1699 1700sub copy_shallow_if 1701{ 1702} 1703 1704sub copy_deep_if 1705{ 1706} 1707 1708# CONTENTS doesn't have a checksum 1709sub may_verify_digest 1710{ 1711} 1712 1713package OpenBSD::PackingElement::FDESC; 1714our @ISA=qw(OpenBSD::PackingElement::SpecialFile); 1715sub name() { OpenBSD::PackageInfo::DESC } 1716 1717package OpenBSD::PackingElement::DisplayFile; 1718our @ISA=qw(OpenBSD::PackingElement::SpecialFile); 1719use OpenBSD::Error; 1720 1721sub prepare 1722{ 1723 my ($self, $state) = @_; 1724 my $fname = $self->fullname; 1725 if (open(my $src, '<', $fname)) { 1726 while (<$src>) { 1727 chomp; 1728 next if m/^\+\-+\s*$/o; 1729 s/^[+-] //o; 1730 $state->log("#1", $_); 1731 } 1732 } else { 1733 $state->errsay("Can't open #1: #2", $fname, $!); 1734 } 1735} 1736 1737package OpenBSD::PackingElement::FDISPLAY; 1738our @ISA=qw(OpenBSD::PackingElement::DisplayFile); 1739sub name() { OpenBSD::PackageInfo::DISPLAY } 1740 1741package OpenBSD::PackingElement::FUNDISPLAY; 1742our @ISA=qw(OpenBSD::PackingElement::DisplayFile); 1743sub name() { OpenBSD::PackageInfo::UNDISPLAY } 1744 1745package OpenBSD::PackingElement::Arch; 1746our @ISA=qw(OpenBSD::PackingElement::Unique); 1747 1748sub category() { 'arch' } 1749sub keyword() { 'arch' } 1750__PACKAGE__->register_with_factory; 1751 1752sub new 1753{ 1754 my ($class, $args) = @_; 1755 my @arches= split(/\,/o, $args); 1756 bless { arches => \@arches }, $class; 1757} 1758 1759sub stringize($) 1760{ 1761 my $self = $_[0]; 1762 return join(',', @{$self->{arches}}); 1763} 1764 1765sub check 1766{ 1767 my ($self, $forced_arch) = @_; 1768 1769 for my $ok (@{$self->{arches}}) { 1770 return 1 if $ok eq '*'; 1771 if (defined $forced_arch) { 1772 if ($ok eq $forced_arch) { 1773 return 1; 1774 } else { 1775 next; 1776 } 1777 } 1778 return 1 if $ok eq OpenBSD::Paths->machine_architecture; 1779 return 1 if $ok eq OpenBSD::Paths->architecture; 1780 } 1781 return; 1782} 1783 1784package OpenBSD::PackingElement::Signer; 1785our @ISA=qw(OpenBSD::PackingElement::Unique); 1786sub keyword() { 'signer' } 1787__PACKAGE__->register_with_factory; 1788sub category() { "signer" } 1789sub new 1790{ 1791 my ($class, $args) = @_; 1792 unless ($args =~ m/^[\w\d\.\-\+\@]+$/) { 1793 die "Invalid characters in signer $args\n"; 1794 } 1795 $class->SUPER::new($args); 1796} 1797 1798# don't incorporate this into compared signatures 1799sub write_without_variation 1800{ 1801} 1802 1803# XXX digital-signatures have to be unique, since they are a part 1804# of the unsigned packing-list, with only the b64sig part removed 1805# (likewise for signer) 1806package OpenBSD::PackingElement::DigitalSignature; 1807our @ISA=qw(OpenBSD::PackingElement::Unique); 1808 1809sub keyword() { 'digital-signature' } 1810__PACKAGE__->register_with_factory; 1811sub category() { "digital-signature" } 1812 1813# parse to and from a subset of iso8601 1814# 1815# allows us to represent timestamps in a human readable format without 1816# any ambiguity 1817sub time_to_iso8601 1818{ 1819 my $time = shift; 1820 my ($sec, $min, $hour, $day, $month, $year, @rest) = gmtime($time); 1821 return sprintf("%04d-%02d-%02dT%02d:%02d:%02dZ", 1822 $year+1900, $month+1, $day, $hour, $min, $sec); 1823} 1824 1825sub iso8601 1826{ 1827 my $self = shift; 1828 return time_to_iso8601($self->{timestamp}); 1829} 1830 1831sub iso8601_to_time 1832{ 1833 if ($_[0] =~ m/^(\d{4})\-(\d{2})\-(\d{2})T(\d{2})\:(\d{2})\:(\d{2})Z$/) { 1834 my ($year, $month, $day, $hour, $min, $sec) = 1835 ($1 - 1900, $2-1, $3, $4, $5, $6); 1836 require POSIX; 1837 my $oldtz = $ENV{TZ}; 1838 $ENV{TZ} = 'UTC'; 1839 my $t = POSIX::mktime($sec, $min, $hour, $day, $month, $year); 1840 if (defined $oldtz) { 1841 $ENV{TZ} = $oldtz; 1842 } else { 1843 delete $ENV{TZ}; 1844 } 1845 return $t; 1846 } else { 1847 die "Incorrect ISO8601 timestamp: $_[0]"; 1848 } 1849} 1850 1851sub new 1852{ 1853 my ($class, $args) = @_; 1854 my ($key, $tsbase, $tsmin, $tssec, $signature) = split(/\:/, $args); 1855 my $timestamp = iso8601_to_time("$tsbase:$tsmin:$tssec"); 1856 bless { key => $key, timestamp => $timestamp, b64sig => $signature }, 1857 $class; 1858} 1859 1860sub blank 1861{ 1862 my ($class, $type) = @_; 1863 bless { key => $type, timestamp => time, b64sig => '' }, $class; 1864} 1865 1866sub stringize 1867{ 1868 my $self = shift; 1869 return join(':', $self->{key}, time_to_iso8601($self->{timestamp}), 1870 $self->{b64sig}); 1871} 1872 1873sub write_no_sig 1874{ 1875 my ($self, $fh) = @_; 1876 print $fh "\@", $self->keyword, " ", $self->{key}, ":", 1877 time_to_iso8601($self->{timestamp}), "\n"; 1878} 1879 1880# don't incorporate this into compared signatures 1881sub write_without_variation 1882{ 1883} 1884 1885package OpenBSD::PackingElement::Old; 1886our @ISA=qw(OpenBSD::PackingElement); 1887 1888my $warned; 1889 1890sub new 1891{ 1892 my ($class, $k, $args) = @_; 1893 bless { keyword => $k, name => $args }, $class; 1894} 1895 1896sub add 1897{ 1898 my ($o, $plist, $args) = @_; 1899 my $keyword = $$o; 1900 if (!$warned->{$keyword}) { 1901 print STDERR "Warning: obsolete construct: \@$keyword $args\n"; 1902 $warned->{$keyword} = 1; 1903 } 1904 my $o2 = OpenBSD::PackingElement::Old->new($keyword, $args); 1905 $o2->add_object($plist); 1906 $plist->{deprecated} = 1; 1907 return undef; 1908} 1909 1910sub keyword 1911{ 1912 my $self = shift; 1913 return $self->{keyword}; 1914} 1915 1916sub register_old_keyword 1917{ 1918 my ($class, $k) = @_; 1919 $class->register_with_factory($k, bless \$k, $class); 1920} 1921 1922for my $k (qw(src display mtree ignore_inst dirrm pkgcfl pkgdep newdepend 1923 libdepend endfake ignore vendor incompatibility md5)) { 1924 __PACKAGE__->register_old_keyword($k); 1925} 1926 1927# Real pkgpath objects, with matching properties 1928package OpenBSD::PkgPath; 1929sub new 1930{ 1931 my ($class, $fullpkgpath) = @_; 1932 my ($dir, @mandatory) = split(/\,/, $fullpkgpath); 1933 return bless {dir => $dir, 1934 mandatory => {map {($_, 1)} @mandatory}, 1935 }, $class; 1936} 1937 1938sub fullpkgpath 1939{ 1940 my ($self) = @_; 1941 if(%{$self->{mandatory}}) { 1942 my $m = join(",", keys %{$self->{mandatory}}); 1943 return "$self->{dir},$m"; 1944 } else { 1945 return $self->{dir}; 1946 } 1947} 1948 1949# a pkgpath has a dir, and some flavors/multi parts. To match, we must 1950# remove them all. So, keep a full hash of everything we have (has), and 1951# when stuff $to_rm matches, remove them from $from. 1952# We match when we're left with nothing. 1953sub trim 1954{ 1955 my ($self, $has, $from, $to_rm) = @_; 1956 for my $f (keys %$to_rm) { 1957 if ($has->{$f}) { 1958 delete $from->{$f}; 1959 } else { 1960 return 0; 1961 } 1962 } 1963 return 1; 1964} 1965 1966# basic match: after mandatory, nothing left 1967sub match2 1968{ 1969 my ($self, $has, $h) = @_; 1970 if (keys %$h) { 1971 return 0; 1972 } else { 1973 return 1; 1974 } 1975} 1976 1977# zap mandatory, check that what's left is okay. 1978sub match 1979{ 1980 my ($self, $other) = @_; 1981 # make a copy of options 1982 my %h = %{$other->{mandatory}}; 1983 if (!$self->trim($other->{mandatory}, \%h, $self->{mandatory})) { 1984 return 0; 1985 } 1986 if ($self->match2($other->{mandatory}, \%h)) { 1987 return 1; 1988 } else { 1989 return 0; 1990 } 1991} 1992 1993package OpenBSD::PkgPath::WithOpts; 1994our @ISA = qw(OpenBSD::PkgPath); 1995 1996sub new 1997{ 1998 my ($class, $fullpkgpath) = @_; 1999 my @opts = (); 2000 while ($fullpkgpath =~ s/\[\,(.*?)\]//) { 2001 push(@opts, {map {($_, 1)} split(/\,/, $1) }); 2002 }; 2003 my $o = $class->SUPER::new($fullpkgpath); 2004 if (@opts == 0) { 2005 bless $o, "OpenBSD::PkgPath"; 2006 } else { 2007 $o->{opts} = \@opts; 2008 } 2009 return $o; 2010} 2011 2012# match with options: systematically trim any optional part that fully 2013# matches, until we're left with nothing, or some options keep happening. 2014sub match2 2015{ 2016 my ($self, $has, $h) = @_; 2017 if (!keys %$h) { 2018 return 1; 2019 } 2020 for my $opts (@{$self->{opts}}) { 2021 my %h2 = %$h; 2022 if ($self->trim($has, \%h2, $opts)) { 2023 $h = \%h2; 2024 if (!keys %$h) { 2025 return 1; 2026 } 2027 } 2028 } 2029 return 0; 2030} 2031 20321; 2033