# ex:ts=8 sw=4: # $OpenBSD: Replace.pm,v 1.85 2014/01/07 13:26:18 espie Exp $ # # Copyright (c) 2004-2010 Marc Espie # # Permission to use, copy, modify, and distribute this software for any # purpose with or without fee is hereby granted, provided that the above # copyright notice and this permission notice appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF use strict; use warnings; use OpenBSD::Delete; package OpenBSD::PackingElement; sub can_update { my ($self, $installing, $state) = @_; my $issue = $self->update_issue($installing); if (defined $issue) { push(@{$state->{journal}}, $issue); } } sub update_issue { undef } sub extract { my ($self, $state) = @_; $state->{partial}->{$self} = 1; if ($state->{interrupted}) { die "Interrupted"; } } package OpenBSD::PackingElement::FileBase; use OpenBSD::Temp; sub extract { my ($self, $state) = @_; my $file = $self->prepare_to_extract($state); if (defined $self->{link} || defined $self->{symlink}) { $state->{archive}->skip; return; } $self->SUPER::extract($state); # figure out a safe directory where to put the temp file my $d = dirname($file->{destdir}.$file->name); # we go back up until we find an existing directory. # hopefully this will be on the same file system. while (!-d $d && -e _ || defined $state->{noshadow}->{$d}) { $d = dirname($d); } if ($state->{not}) { $state->say("extracting tempfile under #1", $d) if $state->verbose >= 3; $state->{archive}->skip; } else { if (!-e _) { File::Path::mkpath($d); } my ($fh, $tempname) = OpenBSD::Temp::permanent_file($d, "pkg"); $self->{tempname} = $tempname; # XXX don't apply destdir twice $file->{destdir} = ''; $file->set_name($tempname); if ($self->{tieto}) { my $src = $self->{tieto}->realname($state); unlink($tempname); $state->say("linking #1 to #2", $src, $tempname) if $state->verbose >= 3; if (link($src, $tempname) || $state->copy_file($src, $tempname)) { # we still need to adjust properties $file->set_modes; $state->{archive}->skip; return; } # okay, it didn't work. recreate tempname. open $fh, ">", $tempname; } $state->say("extracting #1", $tempname) if $state->verbose >= 3; $file->create; $self->may_check_digest($file, $state); } } package OpenBSD::PackingElement::Dir; sub extract { my ($self, $state) = @_; my $fullname = $self->fullname; my $destdir = $state->{destdir}; return if -e $destdir.$fullname; $self->SUPER::extract($state); $state->say("new directory #1", $destdir.$fullname) if $state->verbose >= 3; return if $state->{not}; File::Path::mkpath($destdir.$fullname); } package OpenBSD::PackingElement::Sample; sub extract { } package OpenBSD::PackingElement::Sampledir; sub extract { } package OpenBSD::PackingElement::SpecialFile; sub extract { my ($self, $state) = @_; $self->may_verify_digest($state); } package OpenBSD::PackingElement::Exec; sub update_issue { my ($self, $installing) = @_; return if !$installing; return '@'.$self->keyword.' '.$self->{expanded}; } package OpenBSD::PackingElement::ExecAdd; sub update_issue { undef } package OpenBSD::PackingElement::Unexec; sub update_issue { my ($self, $installing) = @_; return if $installing; return '@'.$self->keyword.' '.$self->{expanded}; } package OpenBSD::PackingElement::UnexecDelete; sub update_issue { undef } package OpenBSD::Replace; sub perform_extraction { my ($handle, $state) = @_; $handle->{partial} = {}; $state->{partial} = $handle->{partial}; $state->{archive} = $handle->{location}; $state->progress->visit_with_size($handle->{plist}, 'extract', $state); } sub check_plist_exec { my ($plist, $state, $new) = @_; $state->{journal} = []; $plist->can_update($new, $state); return 1 if @{$state->{journal}} == 0; $state->errsay(($new ? "New": "Old"). " package #1 will run the following commands", $plist->pkgname); for my $i (@{$state->{journal}}) { if ($new) { $state->errsay("+ #1", $i); } else { $state->errsay("- #1", $i); } } return 0; } sub can_old_package_be_replaced { my ($plist, $state) = @_; return check_plist_exec($plist, $state, 0); } sub is_new_package_safe { my ($plist, $state) = @_; return check_plist_exec($plist, $state, 1); } sub is_set_safe { my ($set, $state) = @_; if (!$state->defines('paranoid') && !$state->verbose) { return 1; } my $ok = 1; for my $pkg ($set->older) { $ok = 0 unless can_old_package_be_replaced($pkg->plist, $state); } for my $pkg ($set->newer) { $ok = 0 unless is_new_package_safe($pkg->plist, $state); } return 1 if $ok; if (!$state->defines('paranoid')) { $state->errsay("Running update"); return 1; } elsif ($state->{interactive}) { if ($state->confirm("proceed with update anyways", 0)) { return 1; } else { return 0; } } else { $state->errsay("Cannot install #1", $set->print); return 0; } } 1;