summaryrefslogtreecommitdiff
path: root/usr.sbin/pkg_add
diff options
context:
space:
mode:
authorMarc Espie <espie@cvs.openbsd.org>2003-12-21 18:41:24 +0000
committerMarc Espie <espie@cvs.openbsd.org>2003-12-21 18:41:24 +0000
commite4f77a8787305c794f97b808b09e12679092c052 (patch)
tree4fe08ad7a9de73c56c594d6eb13d97eb843d914f /usr.sbin/pkg_add
parentea056ddbeaa034e795d4767e2705c140eb0686c1 (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/Makefile5
-rw-r--r--usr.sbin/pkg_add/OpenBSD/Vstat.pm176
-rw-r--r--usr.sbin/pkg_add/pkg_add32
-rw-r--r--usr.sbin/pkg_add/pkg_delete17
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) {