#!/usr/bin/perl # ex:ts=8 sw=4: # $OpenBSD: pkg_delete,v 1.111 2007/12/18 10:58:46 espie Exp $ # # Copyright (c) 2003-2007 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 # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. use strict; use warnings; use OpenBSD::Getopt; use OpenBSD::PackingList; use OpenBSD::RequiredBy; use OpenBSD::Error; use OpenBSD::Interactive; use OpenBSD::Delete; use OpenBSD::PackageInfo; use OpenBSD::Vstat; use OpenBSD::Paths; use OpenBSD::UpdateSet; our %forced = (); our $not; package OpenBSD::pkg_delete::State; our @ISA=(qw(OpenBSD::pkg_foo::State)); package main; set_usage('pkg_delete [-cIinqvx] [-B pkg-destdir] [-F keywords] pkg-name [...]'); our ($opt_v, $opt_D, $opt_d, $opt_n, $opt_q, $opt_p, $opt_c, $opt_L, $opt_B, $opt_I, $opt_i, $opt_x); $opt_v = 0; try { getopts('vchixDdnf:F:qpS:L:B:I', {'v' => sub {++$opt_v;}, 'h' => sub { Usage(); }, 'F' => sub { for my $o (split /\,/o, shift) { $forced{$o} = 1; } }, 'f' => sub { for my $o (split /\,/o, shift) { $forced{$o} = 1; } }}); } catchall { Usage($_); }; if ($opt_D) { $opt_I = 1; } $opt_B = $ENV{'PKG_DESTDIR'} unless defined $opt_B; $opt_B = '' unless defined $opt_B; if ($opt_B ne '') { $opt_B.='/' unless $opt_B =~ m/\/$/o; } $ENV{'PKG_DESTDIR'} = $opt_B; $opt_L = OpenBSD::Paths->localbase unless defined $opt_L; if (defined $opt_p) { Usage "Option p is obsolete"; } if (defined $opt_d) { Usage "Option d is obsolete"; } my %done; my $removed; try { my $state = OpenBSD::pkg_delete::State->new; $state->{recorder} = OpenBSD::SharedItemsRecorder->new; $state->{not} = $opt_n; # XXX RequiredBy $not = $opt_n; $state->{quick} = $opt_q; $state->{very_verbose} = $opt_v >=2; $state->{verbose} = $opt_v; $state->{beverbose} = $opt_n || ($opt_v >= 2); $state->{extra} = $opt_c; $state->{dont_run_scripts} = $opt_I; $state->{forced} = \%forced; $state->{destdir} = $opt_B; $state->{interactive} = $opt_i; if ($opt_B eq '') { $state->{destdirname} = ''; } else { $state->{destdirname} = '${PKG_DESTDIR}'; } $ENV{'PKG_DELETE_EXTRA'} = $state->{extra} ? "Yes" : "No"; lock_db($opt_n) unless $state->{forced}->{nolock}; $state->setup_progressmeter($opt_x); $state->check_root; # First, resolve pkg names my @realnames; my $bad; OpenBSD::PackageInfo::solve_installed_names(\@ARGV, \@realnames, "(removing them all)", $state); my @todo = OpenBSD::RequiredBy->compute_closure(@realnames); if (@todo > @realnames) { my $details = $state->{very_verbose} || $forced{verbosedeps}; my $show = sub { my ($p, $d) = @_; print "Can't remove ".join(' ', @$p)." without also removing:\n" .join(' ', @$d)."\n"; }; if ($state->{interactive} || !$details) { my %deps = map {($_, 1)} @todo; for my $p (@realnames) { delete $deps{$p}; } &$show([@realnames], [keys %deps]); if ((keys %deps) > 1 && OpenBSD::Interactive::confirm( "Do you want details", $state->{interactive}, 1)) { $details = 1; } } if ($details) { for my $pkg (@realnames) { my @deps = OpenBSD::RequiredBy->compute_closure($pkg); next unless @deps > 1; @deps = grep {$_ ne $pkg} @deps; &$show([$pkg], [@deps]); } } my $them = @todo > 1 ? 'them' : 'it'; if ($forced{dependencies} or OpenBSD::Interactive::confirm("Do you want to remove $them as well", $state->{interactive}, 0)) { print "(removing $them as well)\n"; } else { $bad = 1; } } if ($bad) { exit(1); } eval { # and finally, handle the removal { do { $removed = 0; DELETE: for my $pkgname (@todo) { next if $done{$pkgname}; unless (is_installed($pkgname)) { print "$pkgname was not installed\n"; $done{$pkgname} = 1; $removed++; next; } my $r = OpenBSD::RequiredBy->new($pkgname); if ($r->list > 0) { if ($forced{baddepend}) { for my $p ($r->list) { if ($done{$p}) { $r->delete($p); } else { next DELETE; } } } else { next; } } if (!$state->progress->set_header($pkgname)) { print $opt_n ? "Pretending to delete " : "Deleting ", "$pkgname\n"; } $state->set_pkgname($pkgname); OpenBSD::Delete::delete_package($pkgname, $state); $done{$pkgname} = 1; $removed++; } } while ($removed); } }; my $dielater = $@; $state->{recorder}->cleanup($state); OpenBSD::PackingElement::Lib::ensure_ldconfig($state); OpenBSD::PackingElement::Fontdir::finish_fontdirs($state); if ($state->{beverbose}) { OpenBSD::Vstat::tally(); } $state->delayed_output; rethrow $dielater; } catch { print STDERR "$0: $_\n"; exit(1); };