svn commit: r185304 - head/tools/regression/acltools

Edward Tomasz Napierala trasz at FreeBSD.org
Tue Nov 25 10:29:34 PST 2008


Author: trasz
Date: Tue Nov 25 18:29:33 2008
New Revision: 185304
URL: http://svn.freebsd.org/changeset/base/185304

Log:
  Add tools-level test for POSIX.1e functionality.
  
  Approved by:	rwatson (mentor)

Added:
  head/tools/regression/acltools/
  head/tools/regression/acltools/00.t   (contents, props changed)
  head/tools/regression/acltools/run   (contents, props changed)
  head/tools/regression/acltools/tools-posix.test   (contents, props changed)

Added: head/tools/regression/acltools/00.t
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/tools/regression/acltools/00.t	Tue Nov 25 18:29:33 2008	(r185304)
@@ -0,0 +1,62 @@
+#!/bin/sh
+#
+# This is a wrapper script to run tools-posix.test.
+#
+# If any of the tests fails, here is how to debug it: go to
+# the directory with problematic filesystem mounted on it,
+# and do /path/to/test run /path/to/test tools-posix.test, e.g.
+#
+# /usr/src/tools/regression/acltools/run /usr/src/tools/regression/acltools/tools-posix.test
+#
+# Output should be obvious.
+#
+# $FreeBSD$
+#
+
+echo "1..4"
+
+if [ `whoami` != "root" ]; then
+	echo "not ok 1 - you need to be root to run this test."
+	exit 1
+fi
+
+TESTDIR=`dirname $0`
+
+# Set up the test filesystem.
+MD=`mdconfig -at swap -s 10m`
+MNT=`mktemp -dt acltools`
+newfs /dev/$MD > /dev/null
+mount -o acls /dev/$MD $MNT
+if [ $? -ne 0 ]; then
+	echo "not ok 1 - mount failed."
+	exit 1
+fi
+
+echo "ok 1"
+
+cd $MNT
+
+# First, check whether we can crash the kernel by creating too many
+# entries.  For some reason this won't work in the test file.
+touch xxx
+i=0;
+while :; do i=$(($i+1)); setfacl -m u:$i:rwx xxx 2> /dev/null; if [ $? -ne 0 ]; then break; fi; done
+chmod 600 xxx
+rm xxx
+echo "ok 2"
+
+perl $TESTDIR/run $TESTDIR/tools-posix.test > /dev/null
+
+if [ $? -eq 0 ]; then
+	echo "ok 3"
+else
+	echo "not ok 3"
+fi
+
+cd /
+umount -f $MNT
+rmdir $MNT
+mdconfig -du $MD
+
+echo "ok 4"
+

Added: head/tools/regression/acltools/run
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/tools/regression/acltools/run	Tue Nov 25 18:29:33 2008	(r185304)
@@ -0,0 +1,327 @@
+#!/usr/bin/perl -w -U
+
+# Copyright (c) 2007, 2008 Andreas Gruenbacher.
+# All rights reserved.
+#
+# 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,
+#    without modification, immediately at the beginning of the file.
+# 2. The name of the author may not be used to endorse or promote products
+#    derived from this software without specific prior written permission.
+#
+# Alternatively, this software may be distributed under the terms of the
+# GNU Public License ("GPL").
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+#
+# $FreeBSD$
+#
+
+#
+# Possible improvements:
+#
+# - distinguish stdout and stderr output
+# - add environment variable like assignments
+# - run up to a specific line
+# - resume at a specific line
+#
+
+use strict;
+use FileHandle;
+use Getopt::Std;
+use POSIX qw(isatty setuid getcwd);
+use vars qw($opt_l $opt_v);
+
+no warnings qw(taint);
+
+$opt_l = ~0;  # a really huge number
+getopts('l:v');
+
+my ($OK, $FAILED) = ("ok", "failed");
+if (isatty(fileno(STDOUT))) {
+	$OK = "\033[32m" . $OK . "\033[m";
+	$FAILED = "\033[31m\033[1m" . $FAILED . "\033[m";
+}
+
+sub exec_test($$);
+sub process_test($$$$);
+
+my ($prog, $in, $out) = ([], [], []);
+my $prog_line = 0;
+my ($tests, $failed) = (0,0);
+my $lineno;
+my $width = ($ENV{COLUMNS} || 80) >> 1;
+
+for (;;) {
+  my $line = <>; $lineno++;
+  if (defined $line) {
+    # Substitute %VAR and %{VAR} with environment variables.
+    $line =~ s[%(\w+)][$ENV{$1}]eg;
+    $line =~ s[%{(\w+)}][$ENV{$1}]eg;
+  }
+  if (defined $line) {
+    if ($line =~ s/^\s*< ?//) {
+      push @$in, $line;
+    } elsif ($line =~ s/^\s*> ?//) {
+      push @$out, $line;
+    } else {
+      process_test($prog, $prog_line, $in, $out);
+      last if $prog_line >= $opt_l;
+
+      $prog = [];
+      $prog_line = 0;
+    }
+    if ($line =~ s/^\s*\$ ?//) {
+      $prog = [ map { s/\\(.)/$1/g; $_ } split /(?<!\\)\s+/, $line ];
+      $prog_line = $lineno;
+      $in = [];
+      $out = [];
+    }
+  } else {
+    process_test($prog, $prog_line, $in, $out);
+    last;
+  }
+}
+
+my $status = sprintf("%d commands (%d passed, %d failed)",
+	$tests, $tests-$failed, $failed);
+if (isatty(fileno(STDOUT))) {
+	if ($failed) {
+		$status = "\033[31m\033[1m" . $status . "\033[m";
+	} else {
+		$status = "\033[32m" . $status . "\033[m";
+	}
+}
+print $status, "\n";
+exit $failed ? 1 : 0;
+
+
+sub process_test($$$$) {
+  my ($prog, $prog_line, $in, $out) = @_;
+
+  return unless @$prog;
+
+       my $p = [ @$prog ];
+       print "[$prog_line] \$ ", join(' ',
+             map { s/\s/\\$&/g; $_ } @$p), " -- ";
+       my $result = exec_test($prog, $in);
+       my @good = ();
+       my $nmax = (@$out > @$result) ? @$out : @$result;
+       for (my $n=0; $n < $nmax; $n++) {
+	   my $use_re;
+	   if (defined $out->[$n] && $out->[$n] =~ /^~ /) {
+		$use_re = 1;
+		$out->[$n] =~ s/^~ //g;
+	   }
+
+           if (!defined($out->[$n]) || !defined($result->[$n]) ||
+               (!$use_re && $result->[$n] ne $out->[$n]) ||
+               ( $use_re && $result->[$n] !~ /^$out->[$n]/)) {
+               push @good, ($use_re ? '!~' : '!=');
+	   }
+	   else {
+               push @good, ($use_re ? '=~' : '==');
+           }
+       }
+       my $good = !(grep /!/, @good);
+       $tests++;
+       $failed++ unless $good;
+       print $good ? $OK : $FAILED, "\n";
+       if (!$good || $opt_v) {
+         for (my $n=0; $n < $nmax; $n++) {
+	   my $l = defined($out->[$n]) ? $out->[$n] : "~";
+	   chomp $l;
+	   my $r = defined($result->[$n]) ? $result->[$n] : "~";
+	   chomp $r;
+	   print sprintf("%-" . ($width-3) . "s %s %s\n",
+			 $r, $good[$n], $l);
+         }
+       }
+}
+
+
+sub su($) {
+  my ($user) = @_;
+
+  $user ||= "root";
+
+  my ($login, $pass, $uid, $gid) = getpwnam($user)
+    or return [ "su: user $user does not exist\n" ];
+  my @groups = ();
+  my $fh = new FileHandle("/etc/group")
+    or return [ "opening /etc/group: $!\n" ];
+  while (<$fh>) {
+    chomp;
+    my ($group, $passwd, $gid, $users) = split /:/;
+    foreach my $u (split /,/, $users) {
+      push @groups, $gid
+	if ($user eq $u);
+    }
+  }
+  $fh->close;
+
+  my $groups = join(" ", ($gid, $gid, @groups));
+  #print STDERR "[[$groups]]\n";
+  $! = 0;  # reset errno
+  $> = 0;
+  $( = $gid;
+  $) = $groups;
+  if ($!) {
+    return [ "su: $!\n" ];
+  }
+  if ($uid != 0) {
+    $> = $uid;
+    #$< = $uid;
+    if ($!) {
+      return [ "su: $prog->[1]: $!\n" ];
+    }
+  }
+  #print STDERR "[($>,$<)($(,$))]";
+  return [];
+}
+
+
+sub sg($) {
+  my ($group) = @_;
+
+  my $gid = getgrnam($group)
+    or return [ "sg: group $group does not exist\n" ];
+  my %groups = map { $_ eq $gid ? () : ($_ => 1) } (split /\s/, $));
+  
+  #print STDERR "<<", join("/", keys %groups), ">>\n";
+  my $groups = join(" ", ($gid, $gid, keys %groups));
+  #print STDERR "[[$groups]]\n";
+  $! = 0;  # reset errno
+  if ($> != 0) {
+	  my $uid = $>;
+	  $> = 0;
+	  $( = $gid;
+	  $) = $groups;
+	  $> = $uid;
+  } else {
+	  $( = $gid;
+	  $) = $groups;
+  }
+  if ($!) {
+    return [ "sg: $!\n" ];
+  }
+  print STDERR "[($>,$<)($(,$))]";
+  return [];
+}
+
+
+sub exec_test($$) {
+  my ($prog, $in) = @_;
+  local (*IN, *IN_DUP, *IN2, *OUT_DUP, *OUT, *OUT2);
+  my $needs_shell = (join('', @$prog) =~ /[][|<>"'`\$\*\?]/);
+
+  if ($prog->[0] eq "umask") {
+    umask oct $prog->[1];
+    return [];
+  } elsif ($prog->[0] eq "cd") {
+    if (!chdir $prog->[1]) {
+      return [ "chdir: $prog->[1]: $!\n" ];
+    }
+    $ENV{PWD} = getcwd;
+    return [];
+  } elsif ($prog->[0] eq "su") {
+    return su($prog->[1]);
+  } elsif ($prog->[0] eq "sg") {
+    return sg($prog->[1]);
+  } elsif ($prog->[0] eq "export") {
+    my ($name, $value) = split /=/, $prog->[1];
+    # FIXME: need to evaluate $value, so that things like this will work:
+    # export dir=$PWD/dir
+    $ENV{$name} = $value;
+    return [];
+  } elsif ($prog->[0] eq "unset") {
+    delete $ENV{$prog->[1]};
+    return [];
+  }
+
+  pipe *IN2, *OUT
+    or die "Can't create pipe for reading: $!";
+  open *IN_DUP, "<&STDIN"
+    or *IN_DUP = undef;
+  open *STDIN, "<&IN2"
+    or die "Can't duplicate pipe for reading: $!";
+  close *IN2;
+
+  open *OUT_DUP, ">&STDOUT"
+    or die "Can't duplicate STDOUT: $!";
+  pipe *IN, *OUT2
+    or die "Can't create pipe for writing: $!";
+  open *STDOUT, ">&OUT2"
+    or die "Can't duplicate pipe for writing: $!";
+  close *OUT2;
+
+  *STDOUT->autoflush();
+  *OUT->autoflush();
+
+  if (fork()) {
+    # Server
+    if (*IN_DUP) {
+      open *STDIN, "<&IN_DUP"
+        or die "Can't duplicate STDIN: $!";
+      close *IN_DUP
+        or die "Can't close STDIN duplicate: $!";
+    }
+    open *STDOUT, ">&OUT_DUP"
+      or die "Can't duplicate STDOUT: $!";
+    close *OUT_DUP
+      or die "Can't close STDOUT duplicate: $!";
+
+    foreach my $line (@$in) {
+      #print "> $line";
+      print OUT $line;
+    }
+    close *OUT
+      or die "Can't close pipe for writing: $!";
+
+    my $result = [];
+    while (<IN>) {
+      #print "< $_";
+      if ($needs_shell) {
+	s#^/bin/sh: line \d+: ##;
+      }
+      push @$result, $_;
+    }
+    return $result;
+  } else {
+    # Client
+    $< = $>;
+    close IN
+      or die "Can't close read end for input pipe: $!";
+    close OUT
+      or die "Can't close write end for output pipe: $!";
+    close OUT_DUP
+      or die "Can't close STDOUT duplicate: $!";
+    local *ERR_DUP;
+    open ERR_DUP, ">&STDERR"
+      or die "Can't duplicate STDERR: $!";
+    open STDERR, ">&STDOUT"
+      or die "Can't join STDOUT and STDERR: $!";
+
+    if ($needs_shell) {
+      exec ('/bin/sh', '-c', join(" ", @$prog));
+    } else {
+      exec @$prog;
+    }
+    print STDERR $prog->[0], ": $!\n";
+    exit;
+  }
+}
+

Added: head/tools/regression/acltools/tools-posix.test
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/tools/regression/acltools/tools-posix.test	Tue Nov 25 18:29:33 2008	(r185304)
@@ -0,0 +1,243 @@
+# This is a tools-level test for POSIX.1e ACL functionality.  Run it as root
+# using ACL-enabled kernel:
+#
+# /usr/src/tools/regression/acltools/run /usr/src/tools/regression/acltools/tools-posix.test
+#
+# WARNING: Creates files in unsafe way.
+#
+# $FreeBSD$
+
+$ whoami
+> root
+$ umask 022
+
+# Smoke test for getfacl(1).
+$ touch xxx
+$ getfacl xxx
+> # file: xxx
+> # owner: root
+> # group: wheel
+> user::rw-
+> group::r--
+> other::r--
+
+$ getfacl -q xxx
+> user::rw-
+> group::r--
+> other::r--
+
+$ setfacl -m u:42:r,g:43:w xxx
+$ getfacl xxx
+> # file: xxx
+> # owner: root
+> # group: wheel
+> user::rw-
+> user:42:r--
+> group::r--
+> group:43:-w-
+> mask::rw-
+> other::r--
+
+# Check whether ls correctly marks files with "+".
+$ ls -l xxx | cut -d' ' -f1
+> -rw-rw-r--+
+
+# Test removing entries.
+$ setfacl -x user:42: xxx
+$ getfacl xxx
+> # file: xxx
+> # owner: root
+> # group: wheel
+> user::rw-
+> group::r--
+> group:43:-w-
+> mask::rw-
+> other::r--
+
+$ setfacl -m g:43:r xxx
+$ getfacl xxx
+> # file: xxx
+> # owner: root
+> # group: wheel
+> user::rw-
+> group::r--
+> group:43:r--
+> mask::r--
+> other::r--
+
+# Make sure cp without any flags does not copy the ACL.
+$ cp xxx yyy
+$ ls -l yyy | cut -d' ' -f1
+> -rw-r--r--
+
+# Make sure it does with the "-p" flag.
+$ rm yyy
+$ cp -p xxx yyy
+$ getfacl yyy
+> # file: yyy
+> # owner: root
+> # group: wheel
+> user::rw-
+> group::r--
+> group:43:r--
+> mask::r--
+> other::r--
+
+$ rm yyy
+
+# Test removing entries by...  by example?
+$ setfacl -m u:42:r,g:43:w xxx
+$ setfacl -x u:42: xxx
+$ getfacl xxx
+> # file: xxx
+> # owner: root
+> # group: wheel
+> user::rw-
+> group::r--
+> group:43:-w-
+> mask::rw-
+> other::r--
+
+# Test setfacl -b.
+$ setfacl -b xxx
+$ getfacl xxx
+> # file: xxx
+> # owner: root
+> # group: wheel
+> user::rw-
+> group::r--
+> mask::r--
+> other::r--
+
+$ ls -l xxx | cut -d' ' -f1
+> -rw-r--r--+
+
+$ setfacl -nb xxx
+$ getfacl xxx
+> # file: xxx
+> # owner: root
+> # group: wheel
+> user::rw-
+> group::r--
+> other::r--
+
+$ ls -l xxx | cut -d' ' -f1
+> -rw-r--r--
+
+# Check setfacl(1) and getfacl(1) with multiple files.
+$ touch xxx yyy zzz
+
+$ ls -l xxx yyy zzz | cut -d' ' -f1
+> -rw-r--r--
+> -rw-r--r--
+> -rw-r--r--
+
+$ setfacl -m u:42:x,g:43:w nnn xxx yyy zzz
+> setfacl: stat() of nnn failed: No such file or directory
+
+$ ls -l nnn xxx yyy zzz | cut -d' ' -f1
+> ls: nnn: No such file or directory
+> -rw-rwxr--+
+> -rw-rwxr--+
+> -rw-rwxr--+
+
+$ getfacl -q nnn xxx yyy zzz
+> getfacl: nnn: No such file or directory
+> user::rw-
+> user:42:--x
+> group::r--
+> group:43:-w-
+> mask::rwx
+> other::r--
+> 
+> user::rw-
+> user:42:--x
+> group::r--
+> group:43:-w-
+> mask::rwx
+> other::r--
+> 
+> user::rw-
+> user:42:--x
+> group::r--
+> group:43:-w-
+> mask::rwx
+> other::r--
+
+$ setfacl -b nnn xxx yyy zzz
+> setfacl: stat() of nnn failed: No such file or directory
+
+$ ls -l nnn xxx yyy zzz | cut -d' ' -f1
+> ls: nnn: No such file or directory
+> -rw-r--r--+
+> -rw-r--r--+
+> -rw-r--r--+
+
+$ rm xxx yyy zzz
+
+# Check whether chmod actually does what it should do.
+$ touch xxx
+$ setfacl -m u:42:rwx,g:43:rwx xxx
+$ chmod 600 xxx
+$ getfacl xxx
+> # file: xxx
+> # owner: root
+> # group: wheel
+> user::rw-
+> user:42:rwx		# effective: ---
+> group::r--		# effective: ---
+> group:43:rwx		# effective: ---
+> mask::---
+> other::---
+
+$ chmod 060 xxx
+$ getfacl xxx
+> # file: xxx
+> # owner: root
+> # group: wheel
+> user::---
+> user:42:rwx		# effective: rw-
+> group::r--
+> group:43:rwx		# effective: rw-
+> mask::rw-
+> other::---
+
+# Test default ACLs.
+$ umask 022
+$ mkdir ddd
+$ getfacl -q ddd
+> user::rwx
+> group::r-x
+> other::r-x
+
+$ getfacl -dq ddd
+$ setfacl -d -m u::rwx,g::rx,o::rx,mask::rwx ddd
+$ getfacl -dq ddd
+> user::rwx
+> group::r-x
+> mask::rwx
+> other::r-x
+
+$ setfacl -dm g:42:rwx,u:42:r ddd
+$ setfacl -dm g::w ddd
+$ getfacl -dq ddd
+> user::rwx
+> user:42:r--
+> group::-w-
+> group:42:rwx
+> mask::rwx
+> other::r-x
+
+$ setfacl -dx group:42: ddd
+$ getfacl -dq ddd
+> user::rwx
+> user:42:r--
+> group::-w-
+> mask::rw-
+> other::r-x
+
+> # XXX: Test inheritance.
+
+$ rmdir ddd
+$ rm xxx
+


More information about the svn-src-all mailing list