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/OpenBSD | |
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/OpenBSD')
-rw-r--r-- | usr.sbin/pkg_add/OpenBSD/Vstat.pm | 176 |
1 files changed, 176 insertions, 0 deletions
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; |