diff options
author | Marc Espie <espie@cvs.openbsd.org> | 2003-12-21 18:41:24 +0000 |
---|---|---|
committer | Marc Espie <espie@cvs.openbsd.org> | 2003-12-21 18:41:24 +0000 |
commit | e4f77a8787305c794f97b808b09e12679092c052 (patch) | |
tree | 4fe08ad7a9de73c56c594d6eb13d97eb843d914f /usr.sbin/pkg_add | |
parent | ea056ddbeaa034e795d4767e2705c140eb0686c1 (diff) |
Add virtual file system, so that pkg_add and pkg_delete can check for
read-only status, or size concerns, before even beginning to add/remove
files.
Allows pkg_add -n and pkg_delete -n to be more thorough as well.
Some testing by Todd Millert, comments by Greg Steuck and Sam Smith.
Diffstat (limited to 'usr.sbin/pkg_add')
-rw-r--r-- | usr.sbin/pkg_add/Makefile | 5 | ||||
-rw-r--r-- | usr.sbin/pkg_add/OpenBSD/Vstat.pm | 176 | ||||
-rw-r--r-- | usr.sbin/pkg_add/pkg_add | 32 | ||||
-rw-r--r-- | usr.sbin/pkg_add/pkg_delete | 17 |
4 files changed, 213 insertions, 17 deletions
diff --git a/usr.sbin/pkg_add/Makefile b/usr.sbin/pkg_add/Makefile index 967494d4401..13bf5aef39e 100644 --- a/usr.sbin/pkg_add/Makefile +++ b/usr.sbin/pkg_add/Makefile @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile,v 1.4 2003/12/11 15:03:48 espie Exp $ +# $OpenBSD: Makefile,v 1.5 2003/12/21 18:41:23 espie Exp $ MAN=pkg_add.1 pkg_info.1 pkg_create.1 pkg_delete.1 pkg.1 @@ -13,7 +13,8 @@ PACKAGES= \ OpenBSD/RequiredBy.pm \ OpenBSD/Temp.pm \ OpenBSD/Ustar.pm \ - OpenBSD/md5.pm + OpenBSD/md5.pm \ + OpenBSD/Vstat.pm SCRIPTS= \ pkg_add \ diff --git a/usr.sbin/pkg_add/OpenBSD/Vstat.pm b/usr.sbin/pkg_add/OpenBSD/Vstat.pm new file mode 100644 index 00000000000..500dca1b799 --- /dev/null +++ b/usr.sbin/pkg_add/OpenBSD/Vstat.pm @@ -0,0 +1,176 @@ +# $OpenBSD: Vstat.pm,v 1.1 2003/12/21 18:41:23 espie Exp $ +# +# Copyright (c) 2003 Marc Espie. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE OPENBSD PROJECT AND CONTRIBUTORS +# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OPENBSD +# PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +# Provides stat and statfs-like functions for package handling. + +# allows user to add/remove files. + +# uses mount and df directly for now. + +use strict; +use warnings; + +package OpenBSD::Vstat; +use File::Basename; +use Symbol; + +my $dirinfo = {}; +my $virtual = {}; +my $virtual_dir = {}; + +sub init_dirinfo() +{ + open(my $cmd1, "/sbin/mount|") or print STDERR "Can't run mount\n"; + while (<$cmd1>) { + chomp; + if (m/^.*?\s+on\s+(.*?)\s+type\s+.*?\s+\((.*?)\)$/) { + my ($mntpoint, $opts) = ($1, $2); + $dirinfo->{"$mntpoint"} = { mnt => $mntpoint } + unless defined $dirinfo->{"$mntpoint"}; + my $i = $dirinfo->{"$mntpoint"}; + for my $o (split /,\s*/, $opts) { + if ($o eq 'read-only') { + $i->{ro} = 1; + } elsif ($o eq 'nodev') { + $i->{nodev} = 1; + } elsif ($o eq 'nosuid') { + $i->{nosuid} = 1; + } + } + } else { + print STDERR "Can't parse mount line: $_\n"; + } + } + close($cmd1); + + delete $ENV{'BLOCKSIZE'}; + open(my $cmd2, "/bin/df|") or print STDERR "Can't run df\n"; + my $bs; + while (<$cmd2>) { + chomp; + if (m/^Filesystem\s+(\d+)\-blocks/) { + $bs = $1; + } elsif (m/^.*?\s+\d+\s+\d+\s+(\d+)\s+\d+\%\s+(.*?)$/) { + my ($mntpoint, $avail) = ($2, $1); + $dirinfo->{"$mntpoint"} = { mnt => $mntpoint } + unless defined $dirinfo->{"$mntpoint"}; + my $i = $dirinfo->{"$mntpoint"}; + $i->{blocksize} = $bs; + $i->{avail} = $avail; + } + } + close($cmd2); +} + +init_dirinfo(); + +sub _dirstat($); + +sub _dirstat($) +{ + my $dname = shift; + + if (!defined $dirinfo->{"$dname"}) { + return $dirinfo->{"$dname"} = _dirstat(dirname($dname)); + } else { + return $dirinfo->{"$dname"}; + } +} + +sub filestat($) +{ + my $fname = shift; + if (!defined $dirinfo->{"$fname"}) { + return _dirstat(dirname($fname)); + } else { + return $dirinfo->{"$fname"}; + } +} + +sub vexists($) +{ + my $name = shift; + if (defined $virtual->{"$name"}) { + return $virtual->{"$name"}; + } else { + return -e $name; + } +} + +sub vreaddir($) +{ + my $dirname = shift; + my %l; + my $d = gensym; + opendir($d, $dirname); + %l = map { $_ => 1 } readdir($d); + closedir($d); + if (defined $virtual_dir->{"$dirname"}) { + for my $e (@{$virtual_dir->{"$dirname"}}) { + my $n = basename($e); + if (vexists $e) { + $l{"$n"} = 1; + } else { + undef $l{"$n"}; + } + } + } + return keys(%l); +} + +sub add($$) +{ + my ($name, $size) = @_; + $virtual->{$name} = 1; + my $d = dirname($name); + $virtual_dir->{$d} = [] unless defined $virtual_dir->{$d}; + push(@{$virtual_dir->{$d}}, $name); + if (defined $size) { + my $e = filestat($name); + if (defined $e->{avail} && defined $e->{blocksize}) { + $e->{avail} -= $size / $e->{blocksize}; + return $e; + } + } + return undef; +} + +sub remove($$) +{ + my ($name, $size) = @_; + $virtual->{$name} = 0; + my $d = dirname($name); + $virtual_dir->{$d} = [] unless defined $virtual_dir->{$d}; + push(@{$virtual_dir->{$d}}, $name); + if (defined $size) { + my $e = filestat($name); + $e->{avail} += $size / $e->{blocksize}; + return $e; + } else { + return undef; + } +} + +1; diff --git a/usr.sbin/pkg_add/pkg_add b/usr.sbin/pkg_add/pkg_add index 9bc28c40acc..810e57bd395 100644 --- a/usr.sbin/pkg_add/pkg_add +++ b/usr.sbin/pkg_add/pkg_add @@ -1,7 +1,7 @@ #! /usr/bin/perl # ex:ts=8 sw=4: -# $OpenBSD: pkg_add,v 1.18 2003/12/19 00:29:20 espie Exp $ +# $OpenBSD: pkg_add,v 1.19 2003/12/21 18:41:23 espie Exp $ # # Copyright (c) 2003 Marc Espie. # @@ -34,6 +34,7 @@ use OpenBSD::PackageInfo; use OpenBSD::PackageLocator; use OpenBSD::PackageName; use OpenBSD::PkgCfl; +use OpenBSD::Vstat; use Getopt::Std; use File::Copy; @@ -284,15 +285,10 @@ sub check_lib_specs } if ($spec =~ m/^(.*)\.(\d+)\.(\d+)$/) { my ($libname, $major, $minor) = ($1, $2, $3); - unless (opendir(DIRECTORY, $dir)) { - print "base directory not found\n" if $opt_v; - return undef; - } my @candidates = grep { /^lib\Q$libname\E\.so\.$major\.(\d+)$/ && $1 >= $minor } - readdir(DIRECTORY); - close(DIRECTORY); + OpenBSD::Vstat::vreaddir($dir); if (@candidates == 0) { print "not found\n" if $opt_v; return undef; @@ -315,15 +311,26 @@ sub really_add($) my $pkgname = $plist->pkgname(); $ENV{'PKG_PREFIX'} = '/usr/local'; # check for collisions with existing stuff - my $collisions = 0; + my $problems = 0; for my $item (@{$plist->{items}}) { next unless $item->IsFile(); - if (-e $item->fullname()) { - print "Collision: ",$item->fullname()," already exists\n"; - $collisions++; + my $fname = $item->fullname(); + if (OpenBSD::Vstat::vexists($fname)) { + print "Collision: $fname already exists\n"; + $problems++; + } + my $s = OpenBSD::Vstat::add($fname, $item->{size}); + next unless defined $s; + if ($s->{ro}) { + print "Error: ", $s->{mnt}, " is read-only ($fname)\n"; + $problems++; + } + if ($s->{avail} < 0) { + print "Error: ", $s->{mnt}, " is not large enough ($fname)\n"; + $problems++; } } - die if $collisions; + die if $problems; my $interrupted; local $SIG{'INT'} = sub { @@ -420,7 +427,6 @@ while (my $pkg = shift @todo) { } for my $dep (@{$plist->{libdepend}}) { # can't check libspecs yet - next if $opt_n; next if $dep->{name} ne $plist->pkgname(); if (!check_lib_specs('/usr/local', $dep->{libspec})) { print "Can't install $pkg: incorrect libspec: ", diff --git a/usr.sbin/pkg_add/pkg_delete b/usr.sbin/pkg_add/pkg_delete index 8fdca93dbba..e12a164c3df 100644 --- a/usr.sbin/pkg_add/pkg_delete +++ b/usr.sbin/pkg_add/pkg_delete @@ -1,6 +1,6 @@ #!/usr/bin/perl # ex:ts=8 sw=4: -# $OpenBSD: pkg_delete,v 1.15 2003/12/10 11:43:52 espie Exp $ +# $OpenBSD: pkg_delete,v 1.16 2003/12/21 18:41:23 espie Exp $ # # Copyright (c) 2003 Marc Espie. # @@ -32,6 +32,7 @@ use OpenBSD::PackingList; use OpenBSD::PackageInfo; use OpenBSD::RequiredBy; use OpenBSD::Logger; +use OpenBSD::Vstat; package OpenBSD::PackingElement; sub delete @@ -272,6 +273,19 @@ sub delete_package die "Package $pkgname real name does not match"; } + my $problems = 0; + for my $item (@{$plist->{items}}) { + next unless $item->IsFile(); + my $fname = $item->fullname(); + my $s = OpenBSD::Vstat::remove($fname, $item->{size}); + next unless defined $s; + if ($s->{ro}) { + print "Error: ", $s->{mnt}, " is read-only ($fname)\n"; + $problems++; + } + } + die if $problems; + $ENV{'PKG_PREFIX'} = '/usr/local'; if ($plist->has(REQUIRE)) { $plist->get(REQUIRE)->delete($state); @@ -294,7 +308,6 @@ sub delete_package remove_packing_info($dir) unless $opt_n; } - getopts('vcDdnfqpS:'); if (defined $opt_p) { |